How to make Timed Status Effects variable based on [Time] Variable Changing?

Twine Version: 2.8.1
[SugarCube 2.36.1]

Hi all,

So I’m trying to make a [Status Effect] last a certain amount of time, based on the number of [Days] that pass in my project. E.g. if you get the [Injured] status, it lasts 3 days, so if you get it on [Day 10] it’ll last till [Day 13], or [Day 15] till [Day 18].

I’m trying to figure out a simpler way to do this. I’m not quite sure if there is a method to have the [Status Effect] trigger some sort of countdown and for that countdown to change based on the days changing.

Right now my working theory, my probably more work than I need to do, I’m still learning basic programming and I’m using Twine as a fun way to practice and learn things, please don’t hurt me process, is that when the [Status Effect] triggers, it sets a variable (let’s say $injured) = 3, with 3 being the number of days it’ll last. Then, I’d have to add to any trigger that caused a day to pass something like:

<<if $injured == 3>>
set $injured = $injured - 1>>
<<if $injured == 2>>
set $injured = $injured -1>>
...

etc. So and so forth, until $injured = 0, in which the [Status Effect] would go away, until the next time it was triggered.

Now, that all sounds like a lot of work and lot of excessive code, especially if I have a bunch of different timed variables, to add to every single trigger that would change the [Day]. So I’m hoping that there is a simpler solution to this, perhaps involving some sort of Javascript function or something like that.

Thanks for any replies!
~VN

note: I’m going to assume you have a variable that tracks the current Day number. In my examples that will be a variable named $day, which will be initialised to a numerical value of 1 in the project’s StoryInit special Passage like so…

<<set $day to 1>>

…and this variable gets incremented each time the current Day has ended.

Instead of using individual variables to represent each of the “Status Effects” you want to track I would use a single variable that contains an Generic Object, whose properties represent each of the effects that are currently active.
eg. Initialise the variable in StoryInit

<<set $effects to {}>>

Then when an Effect becomes active I would add the related property to the $effects variable, assigning that property a numerical value equal to today’s $day plus the duration of the effect.
eg. If the “injured” effect lasts three days then the assignment would look like…

<<set $effects["injured"] to $day + 3>>

Because the value being tracked is the day the effect ends, instead of its remaining duration, there is no need to decrease the value being tracked.

And when an effect becomes inactive (which I will discuss later) the related property would be removed from the $effects variable like so…

<<run delete $effects["injured"]>>

Now comes the slightly more complex parts. Which I personally would handle using custom widgets (or custom macros), as they allow the abstraction of the related functionality.

1: Determining if an effect should be made inactive.

This is done by looping through each of the existing properties of the $effects object and comparing there value to that of $day. If the value is the same then the property is removed.

<<for _effect range Object.keys($effects)>>
	<<if $effects[_effect] is $day>>
		<<run delete $effects["injured"]>>
	<</if>>
<</for>>

A custom widget definition that can be used to do the above check would look something like…

<<widget "CheckEffects">>
	<<for _effect range Object.keys($effects)>>
		<<if $effects[_effect] is $day>>
			<<run delete $effects["injured"]>>
		<</if>>
	<</for>>
<</widget>>

…which would be called like so…

<<CheckEffects>>

2: Activating an Effect

I already gave an example of how to add a new property to the $effects variable, the following is a custom widget definition that abstracts that process…

<<widget "ApplyEffect">>
	/* 1st argument is effect being applied; 2nd the effect's duration */
	<<set $effects[_args[0]] to $day + _args[1]>>
<</widget>>

…which would be used like so…

<<ApplyEffect "injured" 3>>

3: When to check for inactive effects.

Somewhere in your own code you increment the current day number, possibly when the Main Character “sleeps”, but there may be other reasons. Again I would use a custom widget to abstract that day incrementation, so other things can also occur at the same time.

The following widget definition is a very basic example of such an abstraction…

<<widget "IncressDay">>
	<<set $day += 1>>
	<<CheckEffects>>
<</widget>>

…which could be used like so when needed…

<<IncressDay>>

I hope the above has given you some ideas about one way to achieve an outcome like you described.