Arrays, moving and identifying objects and List boxes

Twine: 2.92, Sugarcube 2.37

Hi all,

Slowly transitioning my story from Harlowe to Sugarcube and I’m having some trouble with .includes and moving objects between arrays and List boxes.

Could someone clarify the syntax for what I’m trying to do below. Which is move stuff between arrays and at some point have an if statement to see whether an array contains a specific object by name. I could do all this stuff in Harlowe but now I’m struggling a bit.
Thank you so much.

<<set $desk to []>>
<<set $inventory to []>>

<<set $inventory to [
{ name: "Saw", itemType: "Tool", weight: 2, cost: 5},
{ name: "Ruler", itemType: "Stationery", weight: 1, cost: 1},
{ name: "House key", itemType: "Key", weight: 1, cost: 1}
]>>

<<set $desk to [ 
{ name: "Pencil", itemType: "Stationery", weight: 1, cost: 1},
{ name: "Eraser", itemType: "Stationery", weight: 1, cost: 1},
{ name: "Hammer", itemType: "Tool", weight: 3, cost: 1}
]>>
<br>
On desk:
<br><<print $desk[0].name>>
<br><<print $desk[1].name>>
<br><<print $desk[2].name>>
<br>
<br>Carrying:
<br><<print $inventory[0].name>>
<br><<print $inventory[1].name>>
<br><<print $inventory[2].name>>

<br>
<<link "<br>>Choose item from desk">>
<<set $desk.delete($itemChoice)>>
<<set $inventory.push($itemChoice)>>
<</link>>
<<listbox "$itemChoice" autoselect>>
`<<optionsfrom $desk>>`
<</listbox>>

<<link "<br>>Place item on desk">>
<<set $inventory.delete($itemChoice)>>
<<set $desk.push($itemChoice)>>
<</link>>
<<listbox "$itemChoice" autoselect>>
`<<optionsfrom $inventory>>`
<</listbox>>
<br>
<<if $desk.includes ("Pencil")>>
<br>The pencil is on the desk.
<</if>>

I’ve found the answer to the listboxes!
But I still can’t get the If/include test or the moving the object in and out of an array.

Updated code below:

<<set $desk to []>>
<<set $inventory to []>>

<<set $inventory to [
{ name: "Saw", itemType: "Tool", weight: 2, cost: 5},
{ name: "Ruler", itemType: "Stationery", weight: 1, cost: 1},
{ name: "House key", itemType: "Key", weight: 1, cost: 1}
]>>

<<set $desk to [ 
{ name: "Pencil", itemType: "Stationery", weight: 1, cost: 1},
{ name: "Eraser", itemType: "Stationery", weight: 1, cost: 1},
{ name: "Hammer", itemType: "Tool", weight: 3, cost: 1}
]>>
<br>
On desk:
<br><<print $desk[0].name>>
<br><<print $desk[1].name>>
<br><<print $desk[2].name>>
<br>
<br>Carrying:
<br><<print $inventory[0].name>>
<br><<print $inventory[1].name>>
<br><<print $inventory[2].name>>

<br>
<<link "<br>>Choose item from desk" "INVENTORY TEST">>
<<set $desk.delete($itemChoice)>>
<<set $inventory.push($itemChoice)>>
<</link>>
<<set _collection = new Map()>>
<<for _idx, _obj range $desk>>
	<<set _collection.set(_obj.name, _idx)>>
<</for>>
<<listbox "$itemChoice" autoselect>>
	`<<optionsfrom _collection>>`
<</listbox>>

<<link "<br>>Place item on desk" "INVENTORY TEST">>
<<set $inventory.delete($itemChoice)>>
<<set $desk.push($itemChoice)>>
<</link>>

<<set _collection = new Map()>>
<<for _idx, _obj range $inventory>>
	<<set _collection.set(_obj.name, _idx)>>
<</for>>

<<listbox "$itemChoice" autoselect>>
	`<<optionsfrom _collection>>`
<</listbox>>

<br>
<<if $desk.includes ("Pencil")>>
<br>The saw is on the desk
<</if>>

I have no idea what the backquotes around the <<optionsfrom _collection>> are meant to be doing, but I’m pretty sure it’s not what you think :slight_smile: I can see that you are transforming your item list into a temporary variable to give the listbox something to display, which does make sense, but then the values from the <<listbox>> don’t match the values in your $inventory which is why the moving things doesn’t work at all.

Here’s how I’d do it.

Assuming that the properties of the items themselves don’t change during play, I’d have the $inventory just be ["saw","ruler","house_key"] and store the properties of those objects elsewhere, ideally on setup, which is where static data would live.

So something like this:
StoryInit

<<set setup.items to {
  saw: { id: "saw", name: "Saw", itemType: "Tool", weight: 2, cost: 5},
  ruler: { id: "ruler", name: "Ruler", itemType: "Stationery", weight: 1, cost: 1},
  house_key: { id: "house_key", name: "House key", itemType: "Key", weight: 1, cost: 1},
  pencil: { id: "pencil", name: "Pencil", itemType: "Stationery", weight: 1, cost: 1},
  eraser: { id: "eraser", name: "Eraser", itemType: "Stationery", weight: 1, cost: 1},
  hammer: { id: "hammer", name: "Hammer", itemType: "Tool", weight: 3, cost: 1}
}>>
<<set $inventory to []>>

Then for the actual passage you turn those lists of ID’s into something for the <<listbox>> to display that looks like {id: "name", id: "name"} e.g. {saw: "Saw", house_key: "House key"}. In the example below I do that with an Array.map() call, but you can do it with a <<for>> loop like you did before if you prefer.

This example also uses <<do>>/<<redo>> to make the changes immediately visible.

Passage

<<set $inventory to ["saw","ruler","house_key"]>>
<<set $desk to ["pencil","eraser","hammer"]>>

<<do>>
On desk:
<<for _item range $desk>>
   <<print setup.items[_item].name>>
<</for>>

Carrying:
<<for _item range $inventory>>
   <<print setup.items[_item].name>>
<</for>>

<<if $desk.length>>
  <<link "<br>>Choose item from desk">>
    <<set $desk.delete($pickupChoice)>>
    <<set $inventory.push($pickupChoice)>>
    <<redo>>
  <</link>>
  <<listbox "$pickupChoice" autoselect>>
      <<optionsfrom Object.fromEntries($desk.map((i) => [setup.items[i].name, i]))>>
  <</listbox>>
<</if>>

<<if $inventory.length>>
  <<link "<br>>Put item on desk">>
    <<set $inventory.delete($dropChoice)>>
    <<set $desk.push($dropChoice)>>
    <<redo>>
  <</link>>
  <<listbox "$dropChoice" autoselect>>
      <<optionsfrom Object.fromEntries($inventory.map((i) => [setup.items[i].name, i]))>>
  <</listbox>>
<</if>>
<</do>>

Thank you so much. It’s starting to make sense now. That Do/redo macro is going to be really useful!