0 votes
by (120 points)
I'm writing a game with a lot of locations and characters. Each of the characters moves depending on the day and so on. I already have a time system in my game, so I came to the conclusion it would be easiest to have one widget to check if there's someone in a particular location at the current time. So that I'll just write <<DisplayCharacters Forest>> and it'll return what characters are currently in this location.

To do it I've built a huge array, that looks like this:

<<set $CharacterLocations =
[
    ["John", "Forest", "workdays", "Noon"],
    ["John", "City", "weekend", "Morning, Night"],
    ["Albert", "Mountains", "workdays", "Morning"],
    ["Albert", "Forest", "Friday, Saturday", "Noon"],
    ["Cindy", "Moon", "weekend", "Evening"]
]
>>

And so on.

So my question is - how should I write a widget that will search this array and return me the name of the character? Could someone point me to a tutorial or something? Sorry if it's a noob question, but I'm new to programming, and it's my first Twine experience.

1 Answer

0 votes
by (44.7k points)
edited by

Well, if you modify your arrays just a little bit, then it's not too difficult to do what you want.

Basically you need to change items in arrays like these, where you have multiple conditions in a single string:

    ["John", "City", "weekend", "Morning, Night"],
    ["Albert", "Forest", "Friday, Saturday", "Noon"],

into arrays where each item is a separate string, like this:

    ["John", "City", "weekend", "Morning", "Night"],
    ["Albert", "Forest", "Friday", "Saturday", "Noon"],

(Note how "Morning" and "Night" are now separate items, as are "Friday" and "Saturday".)

Once you've done that, then it's fairly easy to search through.  Just create a new passage, add "widget" and "nobr" tags to the passage, and then include some code like this:

<<widget "DisplayCharacters">>
	<<set _Location = $args.raw>>
	<<set _Chars = []>>
	<<for _i = 0; _i < $CharacterLocations.length; _i++>>
		<<set _cl = $CharacterLocations[_i]>>
		<<if ["Saturday", "Sunday"].includes($CurrentDay)>>
			<<set _dayType = "weekend">>
		<<else>>
			<<set _dayType = "workdays">>
		<</if>>
		<<if _cl.includes(_Location) && _cl.includes($DayPart) && (_cl.includes($CurrentDay) || _cl.includes(_dayType))>>
			<<set _Chars.pushUnique(_cl[0])>>
		<</if>>
	<</for>>
	<<if _Chars.length > 0>>
		People here: _Chars<br>
	<<else>>
		There's nobody here currently.<br>
	<</if>>
<</widget>>

The code above assumes that $CurrentDay holds the name of the current day of the week, that $DayPart holds the current part of the day ("Noon", etc.), that the capitalization will always match (because "noon" isn't the same as "Noon"), and that the character's name will always be the first item in each array within the $CharacterLocations array.  You can change those two variable names ($CurrentDay and $DayPart) in the code above to whatever you called those variables.

Now when you call "<<DisplayCharacters Forest>>" (remember that proper capitalization matters) it will either display "There's nobody here currently." or something like "People here: John, Albert".  It will also set the temporary variable _Chars to an array of all of those character names, so you can use that variable after you call the <<DisplayCharacters>> widget.

It does that by using a <<for>> loop to go through the $CharacterLocations array, and then checks to see if each sub-array includes the correct location, day part, and either the correct day of the week or correct day type ("weekend" or "workdays") using the .includes() method.  I think everything else above is explained in the SugarCube documentation.

Hopefully that's clear enough that you understand how it works and can edit it to how you'd prefer.

Have fun!  :-)

...