0 votes
by (870 points)

I want stats displayed in a character's info pane to be highlighted different colors if they've been temporarily lowered or raised due to a status effect.

Currently I am doing that like this:

ATTACK: 
<<if $actor[0].get("Attack") < $actor[0].getBase("Attack")>>
<font color=#FF0000><<print $actor[0].get("Attack")>></font><br />
<<elseif $actor[0].get("Attack") > $actor[0].getBase("Attack")>>
<font color=#0000FF><<print $actor[0].get("Attack")>></font><br />
<<else>>
<<print $actor[0].get("Attack")>><br />
<</if>>

This works, but is obviously pretty cumbersome, especially as I wish to make my engine available to other Twine users and therefore ease of use is important.

I figure I want something that algorithmically looks like this:

function applied to all <span> elements with class "statvalue":

if (text of element) > $actor[0].getBase(stat), then add class "blue"
elseif (text of element) < $actor[0].getBase(stat), then add class "red"
else, do nothing

That would enable all stats to be easily displayed with a simple for loop.

I believe this can be done in jQuery, but I'm not familiar with its syntax or how to call its functions, or if it's compatible with Twine variables. If someone could explain how to translate this pseudocode into JavaScript, that would be much appreciated.

1 Answer

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

You can use a custom <<widget>>  or a custom Macro to abstract a block of code that you need to use repeatably, and CSS rules to do the same for styling.

Add the following two CSS rules to your project's Story Storysheet area, they define a rule to be used when the relevant stat has been raised or lowered.

.stat-raised {
	color: blue;
}
.stat-lowered {
	color: red;
}


In this particular use-case you could use either a custom Widget (TwineScript based) or a custom Macro (JavaScript based), which you would use depends on which programming language you feel comfortable using.

1. How to create a <<stat "stat-name">> widget.

The following code should be place within a Passage that has been assigned a widget passage tag. The code first checks if a "stat-name" has been passed to the widget, it uses that stat name to obtain the current and base values for that stat, and then compares those values to determine how to display the current value.

<<widget "stat">><<nobr>>
	/* Check that a Stat Name was passed to the widget. */
	<<if $args.length is 0>>
		ERROR
	<<else>>
		<<set _current to $actor[0].get($args[0]) >>
		<<set _base to $actor[0].getBase($args[0]) >>

		/* Check if the Stat has been raised. */
		<<if _current > _base >>
			@@.stat-raised;_current@@

		/* Check if the Stat has been lowered. */
		<<elseif _current < _base >>
			@@.stat-lowered;_current@@

		/* The Stat has not changed. */
		<<else>>
			_current
		<</if>>
	
	<</if>>
<</nobr>><</widget>>


2. How to create a <<stat "stat-name">> macro.

The following code should be placed within your project's Story Javascript area, it basically does the same thing as the custom widget using JavaScript.

Macro.add('stat', {
	skipArgs : false,
	handler  : function () {
		/* Check that a Stat Name was passed to the macro. */
		if (this.args.length < 1) {
			return this.error('no stat name argument.');
		}

		const actor = State.variables.actor[0];
		const current = actor.get(this.args[0]);
		const base = actor.getBase(this.args[0]);

		const $span = jQuery(document.createElement('span'))
			.text(current);

		/* Check if the Stat has been raised. */
		if (current > base) {
			$span.addClass('stat-raised');

		/* Check if the Stat has been lowered. */
		} else if (current < base) {
			$span.addClass('stat-lowered');
		}

		$span.appendTo(this.output);
	}
});


3. Usage of either the widget or macro is the same.

ATTACK: <<stat "Attack">>

 

by (870 points)
That works, thank you! I will credit you in the documentation.
...