Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Inventory & Dataset

edited March 2015 in Help! with 2.0
I would love to add an inventory natively in Twine 2 Harlowe.

I can add an item to an inventory dataset -
(set: $inventory to (dataset:))
(put: "knife" into $inventory)
I can test if an item is in my inventory dataset
(if: "knife" is in $inventory)[You have the knife!]
What I can't do is -
  • Remove something from the dataset
  • Check to see if nothing is in the dataset
I'd be happy to do this in an array if I can get that to work like it does in Twine 1.

Comments

  • There is a small issue with your example, your (put:) macro is not actually adding "knife" to the dataset object contained within the $inventory variable, instead it is replacing the dataset object with the "knife" string.

    The following code demonstrates the differences and how to dynamically add an item to a dataset.
    As you can see, the $set1 variable (like your $inventory) changes from a dataset object to a string, $set2 starts off containing "dummy" and ends up containing both "dummy" and "knife", and $array starts and end similar to $set2.

    {
    (set: $set1 to (dataset: "dummy"))
    (set: $set2 to (dataset: "dummy"))
    (set: $array to (array: "dummy"))
    }
    <b>Initial values</b>
    dataset 1: [(print: $set1.size)] (print: $set1)
    dataset 2: [(print: $set2.size)] (print: $set2)
    array: [(print: $array.length)] (print: $array)

    <b>Assign "knife" to the each of the three variables.</b>
    {
    (put: "knife" into $set1)
    (set: $set2 += (dataset: "knife"))
    (set: $array += (array: "knife"))
    }
    dataset 1: (print: $set1)
    note: Now a string variable and 5 is the number of characters in the string.

    dataset 2: [(print: $set2.size)] (print: $set2)
    contains dummy? (if: $set2 contains "dummy")[Yes](else:)[No]
    contains knife? (if: $set2 contains "knife")[Yes](else:)[No]
    or contains knife? (if: "knife" is in $set2)[Yes](else:)[No]
    note: still contains a dataset object.

    array: [(print: $array.length)] (print: $array)
    contains dummy? (if: $array contains "dummy")[Yes](else:)[No]
    contains knife? (if: $array contains "knife")[Yes](else:)[No]
    The (move:) macro is meant to be used to delete items from collections (like (array:) and (dataset:)) but I am not sure of the syntax required to make it work with a dataset object

    P.S. You can use the dataset size property to check how many elements are contained within it:

    (print: $set1.size)
    (if: $set1.size > 0)[Not Empty](else:)[empty]
  • Thank you so much GreyElf - this explained everything I was getting wrong.

    For any of those using Snowman below is how you might do the same in JavaScript:
    // create inventory
    var inv = [];
    // add items
    inv.push("item2");
    inv.push("item1");
    // show items
    console.log(inv);
    // sort items
    inv.sort();
    console.log(inv);
    // remove item
    inv.splice(inv.indexOf("item2"),1);
    // check if item is in inventory
    if (inv.indexOf("item1") > -1) {
    console.log("you have it!")
    }
    // check if item isn't in inventory
    if (inv.indexOf("item2") === -1) {
    console.log("you don't have it!")
    }
    // check if nothing is in inventory
    if (inv.length === 0) {
    console.log("nothing in the inventory");
    }
  • greyelf wrote:

    There is a small issue with your example, your (put:) macro is not actually adding "knife" to the dataset object contained within the $inventory variable, instead it is replacing the dataset object with the "knife" string.
    Honestly I hadn't anticipated this UI issue when I added (put:), but now that you've encountered it, I'm feeling a bit cross with myself.
  • I went back to using arrays and this is how I remove an item:
    (set: $blank to $inv.splice($inv.indexOf("itemName"),1))
    So that covers everything - adding items, listing the inventory, and a testing if an item is held.
  • So there is a way to add and remove things with datasets using "set", which is a little ugly-looking but works.
    Create inventory as a dataset
    (set: $inventory to (dataset:))
    Add knife
    (set: $inventory to it + (dataset: "knife"))
    Remove knife
    (set: $inventory to it - (dataset: "knife"))
    You have to make sure the thing you're adding or removing is defined as the same kind of variable as your inventory variable or it won't work, which is the ugly part.

    You can use the same method with arrays, too, which at least looks a little nicer in the code.
    (set: $inventory to it + (a: "knife")
    eta: Oh, shoot. Those are both covered in greyelf's post, I feel dumb now.
  • Now I'm just trying to figure out how to take an object if you don't already have it.

    This will show the key if you aren't already holding it:
    (if: $inv contains "key")[](else:)[You see a key here.]
    <!-- Show inventory -->
    (if: $inv.length is 0)[You aren't carrying anything.](else:)[You are carrying: $inv]
    This will give you the option to take it:
    [Take the key.]<keyTaken|
    (click: ?keyTaken)[ (replace: ?keyTaken)[(set: $inv += (array: "key"))You take the Key.] ]
    That lets you know you've taken the key, but it gives you the option to take it again if you ever revisit this passage (even though you already have it!)

    So I try to test to see if you have the key before asking if you want to pick it up:
    (if: $inv contains "key")[](else:)[Take the key.]<keyTaken|
    (click: ?keyTaken)[ (replace: ?keyTaken)[(set: $inv += (array: "key"))You take the Key.] ]
    However that doesn't work at all. Am I missing something?

    BTW, Inspector Caracal you are far from dumb - you worked out what I couldn't without help.
  • By Jove I've got it!  This works:
    (if: $inv contains "key")[](else:)[[A small key rests within the branches.]<keyS|]
    (click: ?keyS)[You take the key.(set: $inv += (array: "key"))]
    Not exactly how I hoped to implement this - but it'll do for now.
  • Although having an empty code block (the []'s) after an (if:) macro is not invalid coding as such it is considered wrong or ugly:
    eg. your example:  (I added spaces to emphasized the point)

    (if: $inv contains "key") [] (else:)[[A small key rests within the branches.]<keyS|]
    Instead you should test to see that $inv does not contain "key" like the following, that way you dont need both an (if:) and (else:), note the extra parentheses around the contains conditional.

    (if: not ($inv contains "key"))[[A small key rests within the branches.]<keyS|]
  • Thanks again Grey Elf. Now I know the right way to do this.

    I kept trying not contains and not is in (& is not in) and every other variation I could think of.
  • nate wrote:

    I kept trying not contains and not is in (& is not in) and every other variation I could think of.

    So did I at first, I just kept at it a little longer than you did because I knew that it was possible! lol
  • edited August 2015
    $inv.length
    no longer seems to work -
    $inv's length
    does work however
Sign In or Register to comment.