Twine Version: 2.9.1.0
SugarCube: 2.37.0
So, I built a fight system that rewards experience points for having completed the fight. One can level up, find gold, yadda yadda. Now I want to have item drops added.
So, I made some arrays for StoryInit:
<<set $Inventory to []>>
<<set $Inventory.Gold to 0>>
<<set $Inventory.Item01 to []>>
<<set $Inventory.Item01.Name to "Wolf Pelt">>
<<set $Inventory.Item01.Count to 0>>
<<set $Inventory.Item02 to []>>
<<set $Inventory.Item02.Name to "Wolf Fang">>
<<set $Inventory.Item02.Count to 0>>
<<set $Inventory.Item03 to []>>
<<set $Inventory.Item03.Name to "Raw Meat">>
<<set $Inventory.Item03.Count to 0>>
<<set $Inventory.Item04 to []>>
<<set $Inventory.Item04.Name to "Silver Fang">>
<<set $Inventory.Item04.Count to 0>>
<<set $Temp to []>>
<<set $Temp.Gold to 0>>
<<set $Temp.Item01 to []>>
<<set $Temp.Item01.Name to "Wolf Pelt">>
<<set $Temp.Item01.Count to 0>>
<<set $Temp.Item02 to []>>
<<set $Temp.Item02.Name to "Wolf Fang">>
<<set $Temp.Item02.Count to 0>>
<<set $Temp.Item03 to []>>
<<set $Temp.Item03.Name to "Raw Meat">>
<<set $Temp.Item03.Count to 0>>
<<set $Temp.Item04 to []>>
<<set $Temp.Item04.Name to "Silver Fang">>
<<set $Temp.Item04.Count to 0>>
This is just the first four items and some gold. The reason I have two is that $Temp is just what you gain at the end of this particular fight, whereas $Inventory is your total in your bag. At the end of the fight, there’s this:
<<set $Inventory.Item01.Count += $Temp.Item01.Count>>\
<<set $Inventory.Item02.Count += $Temp.Item02.Count>>\
<<set $Inventory.Item03.Count += $Temp.Item03.Count>>\
<<set $Inventory.Item04.Count += $Temp.Item04.Count>>\
And more items to come. Side note, if you know how to add all of the counts from one to the other, that’d be great. I’m still an amateur, especially when it comes to arrays.
So, anyway, leading out of the battle to a passage where your winnings are decided, I have this:
<<set _DropCount to random(3, 5)>>
<<set $Temp.Item01.Count to 0>>
<<set $Temp.Item02.Count to 0>>
<<set $Temp.Item03.Count to 0>>
<<set $Temp.Item04.Count to 0>>
<<for _DropCount gt 0>>
<<set _D20 to random(1, 20)>>
<<if _D20 gte 1 and _D20 lt 4>>wolf pelt - 15%
<<set $Temp.Item01.Count += 1>>
<<elseif _D20 gte 4 and _D20 lt 8>>wolf fang - 20%
<<set $Temp.Item02.Count += 1>>
<<elseif _D20 gte 8 and _D20 lt 20>>raw meat - 60%
<<set $Temp.Item03.Count += 1>>
<<elseif _D20 is 20>>silver fang - 5%
<<set $Temp.Item04.Count += 1>>
<</if>>
<<set _DropCount -= 1>>
<</for>>
I’ve done a bit of looking around, and I know I could clean that up a little bit, but I’m still an amateur, so even if it’s a bit messy, at least I know this is working as intended. This is all meant to go silently, of course. The text it’s going to print is only so that I can watch what’s going on, and when I’m done, I’ll change the link that takes me to the next screen to just a goto command so that it executes the code and moves automatically to where I want it to go, where the text that the player will see is displayed. Also, I’ve left the gold out of this, because it was working as intended.
Now, the next bit looks like this:
<<set $Drops to ["Temp.Item01", "Temp.Item02", "Temp.Item03", "Temp.Item04"]>>
<<set $Drops to $Drops.filter( (id) => State.variables[id].Count !== 0 )>>
<<set $Drops to $Drops.map( (id) => State.variables[id].Name )>>
From what I understand, this is supposed to make an array of all of the items that I may have gained (first line), filter out anything that I gained none of (second line), and map it to the name of the item (third line).
The issue is that it wouldn’t return what I want it to, even if it worked. It’s throwing error messages at me.
Error: <<set>>: bad evaluation: Cannot read properties of undefined (reading 'Count')
<<set _Drops to _Drops.filter( (id) => State.variables[id].Count !== 0 )>>
I know I haven’t told it to actually print anything yet, but if I had gained two raw meat, a fang and a pelt, then this javascript:
setup.toCommaString = function(array) {
// 0 or 1 entries, nothing to join, just convert to string
return array.length < 2 ? array.join('')
// exactly 2, join with "and"
: array.length === 2 ? array.join(' and ')
// join most of them with commas, use "and" for the last
: array.slice(0, array.length-1).join(', ')
// add the serial comma here if you want it
+ ' and ' + array[array.length-1];
}
followed by this code:
You received the following:
<<= setup.toCommaString($Drops)>>
<<set $Inventory.Item01.Count += $Temp.Item01.Count>>\
<<set $Inventory.Item02.Count += $Temp.Item02.Count>>\
<<set $Inventory.Item03.Count += $Temp.Item03.Count>>\
<<set $Inventory.Item04.Count += $Temp.Item04.Count>>\
would tell me that I gained (wolf pelt, wolf fang and raw meat), but not how many of each. I want the player to know how many of each.
That javascript is strictly reused; I haven’t made it around to fiddling with it yet, but I was going to add in a statement for if you happened to gain no items, such as a small creature that dropped 0-2 items instead of 3-5. I do want to keep that javascript, I just want to have a second, separate one, because this one is doing something else that I need it to keep doing. I just wanted to make the array work, first.
That javascript and the sorting code, I learned here, thanks to the two users that helped me figure that one out. And sorry for the wall of text.