0 votes
by (2.4k points)

Hi everybody! Sorry for the long question that follows...

I'm using this inventory system (with a couple of modifications) where items are declared like:

<<set $anItem to {
  id: "anItem",
  name: "An Item"
}>>

And an array is used to store the ids of the items the player has in his inventory. I've added to the items variables an array called tags which I use to mark certain characteristics of the item (such as if the item is a weapon, clothes, shoes, if itn is considered an elegant or magical item, etc...). So finally my item variables looks something like this:

<<set $anItem to {
  id: "anItem",
  name: "An Item",
  tags: ["chest", "elegant"],
  description: "A generic item that counts as an elegant dress"
}>>

Now for choosing what the player has equiped in each slot (head, chest, pants...) I'm using a passage where I declare a series of <<listbox>> (one for each slot) with only one option for the "none" item (as in the player has nothing equiped in that slot). Since obviously the inventory can change each time the player visits the equipement passage, I'm using a javascript code in PassageDone that goes through the inventory array reading the ids of the items owned by the player and checks their tags so it could be added to the correct <<listbox>>.

My idea here is that whe I detect an item that can be added to a <<listbox>> I would build an option element in javascript and add it to the <<listbox>>. Currently I'm trying to do this like this:

var listbox_chest = document.getElementById("listbox-equipmentchest");

State.variables.inventory.forEach(function (item) {
  var opt = document.createElement("option");
  opt.text = item.name;
  opt.value = item.id;  //Here is where I think the error is going to be

  if(window.hasTag(item, "chest")){ //Returns true/false if the item has the tag
    listbox_chest.options.add(opt);
  }
  //More similar code here for each listbox
  
});

When running the equipment passage, the <<listbox>> seems to form properly as I see the correct item names in each one, but when choosing one of the new options the variable related to the <<listbox>> is not properly updated and its value changes from "none" (the empty item) to undefined. Here is when I noticed I was using Sugarcube2.27 so I updated to 2.28.2 but now I get an uglier error wich prompts an alert saying:

Apologies! An error has occurred. You may be able to continue, but some parts may not work properly.

Error: i[Number(...)] is undefined.

Stack Trace:

Inspecting the generated html code from the browser I've noticed that the options generated by Sugarcube when doing it properly from a passage code have the "value" property assigned to numbers (0, 1, 2...) and I supose that somewhere in the code Sugarcube translate those numbers to the proper variable value, while adding the option using javascript adds the string value of item.id to it so I'm sure that is here where Sugarcube explodes trying to string value to an integer or something like that.

So I supose that using javascript is not the correct way of doing all this in Sugarcube, but I have no idea of how to do this other than declaring each possible option in the passage and enclosing them with an <<if>> where I check if the item is in the inventory, but that would be hard to maintain once I have more items declared or I decide to change tags or something.

Does anybody have any idea about what to do? Thanks!

1 Answer

0 votes
by (68.6k points)
selected by
 
Best answer

Attempting an end run around a macro is never a good idea.  In many cases, there is internal state that you do not have access to.

 

You'll likely want to use the <<listbox>> macro's <<optionsfrom>> tag with some kind of filtering and mapping.

Since you have an array of objects, I'd probably make a function, similar to the getInv() function from the linked thread, to filter and map the inventory down into a form acceptible to <<optionsfrom>> and simply call it with that, since it's an expression receiving tag.  For example, say you named the function getOptionsFromInvByTag():

<<optionsfrom getOptionsFromInvByTag("chest")>>

Alternatively, you could also filter/map the inventory directly within the tag invocation or you could build the list beforehand and store it in a temporary variable, if necessary or desired.  I'd probably just go with the function(s) though.

by (2.4k points)
Thanks, it worked!

I did try to build an <<optionsfrom>> map before, but I did it in PassageDone and it failed too, so I suposed that maybe the <<listbox>> was trying to read it before it was ready. I didn't realized it could be called in a function.
...