As a precursor, I have been spending hours researching this, scouring the Twine forums, w3schools for Javascript, the Twine 2 wiki, and SugarCube 2 docs, so this is kinda my last resort.
Firstly, I have found next to no documentation on creating custom Javascript functions and using them. Everything I have learned is through looking at examples, and with my own knowledge of JS.
I set out trying to learn how to take an array of objects, such as:
[ { name: "Gold", value: 100 }, { name: "Silver", value: 10 }, { name: "Copper", value: 1 } ]
And pass it into a custom JS function to get the sum of all of "value" properties.
I created a function and attached it to "window" (a trick that doesn't seem to be explain anywhere) which looked like this:
window.SumValue = function (list) {
var v=0;
for(var i=0; i<=list.length; i++) {
v+=list[i].value;
}
return v;
}
(I put this in my "Edit Story Javascript" area of my Twine project.)
Then, in attempted to use the function as follows:
<<set $list to [ { name: "Gold", value: 100 }, { name: "Silver", value: 10 }, { name: "Copper", value: 1 } ]>>
<<print SumValue($list)>>
The intended result was to print the number: 111 to the screen when the passage loaded (100 + 10 + 1), instead I get an error that reads, "Error: <<print>>: bad evaluation: Cannot read property 'value' of undefined".
If anyone has some answers for me, even if it's just pointing me in the direction of the documentation on how work with JS and Twine/Sugarcube, I would most appreciate it.
I am using
Twine 2 (offline),
SugarCube 2.12.1 (local/offline).
Lastly, I would prefer to not have to use widgets to accomplish this, as they are bulky, do not provide a return method, and generally aren't good for internal workings.
Comments
Any help is greatly appreciated.
That trick—including the reason it's necessary: scoping issues—has been explained on these forums countless times. That's not a shot at you, BTW, just an observation.
The environment/scope within which author/developer JavaScript is normally executed inside most story formats is localized. Meaning, if you want a function you define to be accessible outside of its own localized scope, you need to attach it to a scope which is already accessible to the rest of the story format.
In all story formats you may use the global scope for this purpose, which you accomplish by attaching the function to the window object—as you've already discovered. As a special property of the window object, all of its members are also what's known as auto-globals—meaning you can access them without have to prefix them with window.
In SugarCube, you have an additional option in the setup object.
I see an error and have a couple of suggestions:
EXTRA CREDIT ALTERNATIVE
You're not leveraging the native JavaScript library. The native Array object has methods which may be used to help you out here. For example, here's your summing function rewritten to use the <Array>.reduce() method:
Thank you again for all the help. I didn't realize how well Twine and SugarCube interfaced with native JavaScript. And thanks for explaining everything so thoroughly! I hope that I can help people on the forum even half as much as you helped me!