Simplest way to do an Inventory in Twine 2?

So, how do you all handle inventories in Twine? I can imagine using (history: ) and just sending the user to passages when they take an item. But then you can't easily remove/re-add items. Do you use the (dataset: ) array? Can you append or concatenate dataset arrays?

Comments

  • P.S. Harlowe
  • I do it via variables. I.e., if someone gets a shield, you can set the variable $shield to true. Then, I use if/else statements to check those variables.

    Datasets might be more efficient (and, yes, you can append to them, etc.), but I always found variables easier to track.

    If you need actual code examples, let us know.
  • Ah. Of course. That is a simple and easy way to do it. I think I just got caught up in trying to do it a more complicated way. Now that I think about it, it was so I could print out a player's inventory in one go instead of a bunch of statements to check for everything the player could have. But really, it's not a bad idea to keep a passage with all list of all your variables anyway, so...
  • edited May 2015
    ... and the nice thing about variables is they have some flexibility. Like you could set $matches to 6, and then $matches = $matches-1 anytime a player uses one.
  • edited May 2015
    You can do a basic inventory via the (dataset:) macro.

    I've used a combination of the dataset and count macros and the contains operator. Did what I needed at the time. Might be something you could use as well.

    From @L's Twine 2.0 Harlowe Guide

    (dataset:) This macro produces a Javascript Set, which is a more limited form of array that does not have numeric properties - you can only query whether it contains a value using contains or is in. It can be used for simplifying (if:) statements - instead of writing (if: $a is "sword" or $a is "axe" or $a is "dagger") dozens of times, you can write (set: $weapons to (dataset: "sword", "axe", "dagger")) and then simply write (if: $a is in $weapons).

    contains: This operator is used to check if a string or some text contains another substring. For instance, "Red" contains "R" evaluates to true. (It can also be used with arrays to check for inclusion: (array: 1,4,5) contains 4 evaluates to true.)

    (count:): This macro takes an array and a value, and returns the number of times the value appears within the array. (count: $a, "Egg") returns the number of times the string "Egg" is a value in $a. It's like the contains operator, but it produces a number rather than just true or false.

  • @rayotus

    I found this, I think on glorious trainwreck... but it works great:
    <<set $inv = ["Dagger", "Shield", "Potion"] >>
    <<if $inv.length is 0>>You have nothing.
    <<else>>
    Your inventory contains:
    <<print $inv.join("\n")>>
    <<endif>>
    
    
    You decide to [[drop your potion]]
    
    ―> (new room)
    
    <<script>>
    // Removes an element from an array.
    // String value: the value to search and remove.
    // return: an array with the removed element; false otherwise.
    Array.prototype.remove = function(value) {
    var idx = this.indexOf(value);
    if (idx != -1) {
    return this.splice(idx, 1); // The second parameter is the number of elements to remove.
    }
    return false;
    }
    <</script>>
    
    It breaks on the ground and just in front of you, and you see....
    
    <<set $inv.remove('Potion')>>
    Your inventory now only contains:
    <<print $inv.join("\n")>>
    

    If I miscredited it, let me know... but I think I saw it there.

    —Sage.
  • It works great for SugarCube, probably doesn't work for Harlowe.
  • @AvaJarvis
    Missed that, above, thanks.
  • The following is a Harlowe version of @Sage's post:

    1. Place the following in your story's Story Javascript area:
    // Removes an element from an array.
    // String value: the value to search and remove.
    // return: an array with the removed element; false otherwise.
    Array.prototype.remove = function(value) {
    	var idx = this.indexOf(value);
    	if (idx != -1) {
    		// The second parameter is the number of elements to remove.
    		return this.splice(idx, 1); 
    	}
    	return false;
    };
    
    2. Copy the following In your start passage:
    (set: $inv to (array: "Dagger", "Shield", "Potion"))
    (if: $inv.length is 0)[You have nothing.]
    (else:)[Your inventory contains:
    (print: $inv.join("\n"))
    ]
    
    You decide to [[drop your potion]]
    
    3. Create a new passage titled drop your potion and copy the following into it:
    It breaks on the ground and just in front of you, and you see....
    
    (set: $dummy to $inv.remove("Potion"))
    Your inventory now only contains:
    (print: $inv.join("\n"))
    
    4. Dance around with your hands in the air like you just don't care...
  • But I wanted to dance around… :(
Sign In or Register to comment.