0 votes
by (150 points)
edited by

I'm working with Twine 2.1.1 and SugarCube 2.14.0 at the moment, for reference. 

Here's what I'm trying to do: let's assume I have an object created with various keys and values. Like so:

<<set $clothes = {
  shirt: "red",
  pants: "blue",
  socks: "red",
  gloves: "green",
  jacket: "yellow",
                }>>

Then an event happens in the story to change the color of a piece of clothing to "red" if it isn't already.

What I'm looking for is something (probably a loop, yes?) that will randomly choose one of the keys from $clothes and check the following:

  • If the key selected doesn't have a value of "red" (like $clothes.pants), it will change its value to "red" and end the function and move on
  • If the key selected does have a value of "red" (like $clothes.shirt), it will randomly select a different key and perform the check again

By reading a playing around with code I've found ways to do the different parts of all of this on their own, but not working together as a whole unit. Any suggestions or help would be very welcome. Or, if there's a better way besides using an Object like that, I'd gladly do that too.Thanks.

2 Answers

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

Your best bet is probably to do something like the following:

<<silently>>
	<<set _clothingNames to Object.keys($clothes)>>
	<<for _clothingNames.length gt 0>>
		<<set _name to _clothingNames.pluck()>>
		<<if $clothes[_name] isnot "red">>
			<<set $clothes[_name] to "red">>
			<<break>>
		<</if>>
	<</for>>
<</silently>>

SEE: <<silently>>, <<set>>, Object.keys(), <<for>>, <Array>.pluck(), <<if>>.

by (150 points)
Thank you for the fast and easy answer! This solution works perfectly for my needs.
0 votes
by (159k points)

Please don't include information about the version of Twine and the Story Format within the Title of your question, using the questions tags to provide this information (like you did) is the correct way to do that.

There are a number of ways using either TwineScript or Javascript you can achieve the result you require.

1. The following TwineScript uses the Javascript Object.keys() function to obtain generate an Array containing the names of each of pieces of clothing in your $clothes object, it then uses SugarCube's <Array>.shuffle() function to randomly sort that list. Looping through the list until the condition you're looking for is handled via a <<for>> macro combined with a <<if>> macro, and the <<for>> macro's child <<break>> macro is used to stop the looping once the condition is true.

<<set $clothes = {
  shirt: "red",
  pants: "blue",
  socks: "red",
  gloves: "green",
  jacket: "yellow"
}>>

<<set _keys to Object.keys($clothes).shuffle()>>
<<for _i to 0; _i lt _keys.length; _i++>>
	<<if $clothes[_keys[_i]] isnot "red">>
		<<set $clothes[_keys[_i]] to "red">>
		<<break>>
	<</if>>
<</for>>

2. The follow (embedded) Javascript uses the same method as example 1 to obtain a random list of clothes names. It uses <Array>.some() function to loop through the list until the condition you're looking for is met then does the assignment you want and stops the looping.

<<set $clothes = {
  shirt: "red",
  pants: "blue",
  socks: "red",
  gloves: "green",
  jacket: "yellow"
}>>

<<run Object.keys($clothes).shuffle().some(
	function (element, index, array) {
		console.log(`element: ${element}`);
		var clothes = State.variables["clothes"];
  		if (clothes[element] != "red") {
			clothes[element] = "red";
			return true;
		} else {
			return false;
		}
	}
)>>

WARNING: The <Array>.some() function used above is a recent addition to Javascript and may not be supported in the web-browser being used by the Reader, if you are planing on using the above Javascript example then I strongly suggests you include the Polyfill included on the linked page within your story's Story Javascript area so that the above example will work for people using older web-browsers.

by (68.6k points)

WARNING: The <Array>.some() function used above is a recent addition to Javascript and may not be supported in the web-browser being used by the Reader, if you are planing on using the above Javascript example then I strongly suggests you include the Polyfill included on the linked page within your story's Story Javascript area so that the above example will work for people using older web-browsers.

Being part of ES5, I don't think it's really accurate to describe <Array>.some() as recent.  It's probably natively supported in every browser supported by SugarCube itself.  Even in the case that it wasn't, SugarCube includes a set of ES5 polyfills which cover it, so the polyfill from MDN is absolutely unnecessary.

by (150 points)
Thank you for the fast and thorough response! The additional information regarding a pure JavaScript method was also very helpful and informative.
...