0 votes
by (130 points)
Hello! So I have an inventory which is an array:

<<set $inventory = []>>

I then create objects to populate the inventory:

<<set $book to { name: "Book", value: 70, description: "Text here" }>>

<<set $inventory.push($book)>>

Everything works fine, except when I check if the player has the item in the inventory:

<<if $inventory.includes($book)>>
[[show book]]
<</if>>

The only time it works is when I place <<set $inventory.push($book)>> in the same passage as the check.

I checked in the old forum and came across this thread with the same problem: https://twinery.org/forum/discussion/comment/23380/

So now I know the reason why it doesn't work.

What I want to know now is one of the solutions proposed:

"You could give each object you wish to use in this way a unique property and check for that"

Let's say I give $book a unique ID

<<set $book to { name: "Book", value: 70, description: "Text here", ID: 001 }>>

How do I check for the property of an object inside an array?

Thanks

1 Answer

+1 vote
by (159k points)

Each time the Reader transitions between passages a 'copy' of the current state of all known variables is made, the original state is associated with the previous passage and stored in the History sub-system, and the 'copy' is made available to the passage about to be shown. This 'copy' breaks all object references which basically means that the copy of the 'Book' object referenced in the $book variables and the copy of the 'Book' object stored in the $inventory are no longer the same object, but both 'Book objects current have a same 'value'.

Because of this effect it is generally recommended to use a key value rather than object reference when associating two things.

<<set $items to {}>>
<<set $items["Book"] to { name: "Book", value: 70, description: "Text here" }>>
<<set $items["Lamp"] to { name: "Lamp", value: 50, description: "Text here" }>>

<<set $inventory = []>>

<<set $inventory.push("Book")>>

<<if $inventory.includes("Book")>>
[[show book]]
<</if>>

warning: The above code was written from memory and has not been tested, it may contain syntax errors.

But if you want to continue using object references then I suggest you read the entirety of the Inventory System (Sugarcube 2.0 / Twine 2) thread on the Forums, I suggest reading the whole thread because it contains noth corrections to earlier posted code examples as well as explanations on many of the pitfalls of using object references.

by (130 points)
edited by
Thanks for the answer greyelf! I think I'll go with your system instead then. One last question though.

On my StoryMenu passage I got an inventory, displaying all the items in the $inventory array with a description. Like this:

You are holding:
<<for $i = 0; $i < $inventory.length; $i++>>
<<set $item = $inventory[$i]>>
<<print $item.name>> - <<print $item.description>>
<</for>>

However now $item.name and $item.description don't print anything. Any ideas?

 

EDIT: Okay, I see now that I can show the item name by simply printing $item. It's just the description that's missing.
by (159k points)

This comment in the Array contains object - problem thread on the Forum shows how to loop through the items in my original $items collection variable, it also shows how to access/display a property (in that case cost) associated with an item.

So to show the name and description of your $inventory collection just do something like the following:

<<for _i to 0; _i < $inventory.length; _i++>>
<<set _item to $inventory[_i]>>
<<print _item + " - " + $items[_item].description>>
<</for>>

note: The above code assumes you are storing the list of item objects within the $items variable defined in my previous example, it also uses temporary variables for the loop index and the item variables. The above code was written from memory and has not been tested, it may contain syntax errors. 

...