Setting a variable name, not its value, as a _variable

+1 vote
asked Oct 11 by Charlie (4,430 points)

I'm working on a widget that reduces the energy shield strength of a spaceship.  In this example, both the Millennium Falcon and Slave I have energy shields, thus:

<<set
   $milleniumFalcon.shields to 100,
   $slavei.shields to 100>>

The ships are in combat.  If the Falcon is hit, I'd like to tell the game that, then run a widget that calculates the damage.

<<set _target to $millenniumFalcon.shields>>
<<shieldDamage>>

The shieldDamage widget:

<<widget "shieldDamage">>
  <<set _d10 to random(1,10)>>
  <<set _target -= _d10>>
<</widget>>

However, this doesn't adjust $millenniumFalcon.shields.  It does work if I set the widget up so:

<<widget "shieldDamage">>
  <<set _d10 to random(1,10)>>
  <<set $millenniumFalcon.shields -= _d10>>
<</widget>>

...which makes me think that the problem is that I'm setting _target to 100 (i.e. the value of $millenniumFalcon.shields) instead of to the variable name.

Is there a better way to go about this?

2 Answers

+1 vote
answered Oct 11 by TheMadExile (20,310 points)
selected Oct 11 by Charlie
 
Best answer

You could easily do something like the following, which uses the State.variables property:

<<widget "shieldDamage">>
	\<<set _d10 to random(1,10)>>
	\<<set State.variables[$args[0]].shields -= _d10>>
\<</widget>>

Further, if you aren't using the temporary variable outside of the widget, then you don't need it and could simplify that to:

<<widget "shieldDamage">>
	\<<set State.variables[$args[0]].shields -= random(1,10)>>
\<</widget>>

 

Usage:

<<shieldDamage "millenniumFalcon">>

 

commented Oct 11 by Charlie (4,430 points)
Thanks, Exile!  You're really good at this.  :-)
0 votes
answered Oct 12 by Akjosch (3,950 points)
edited Oct 12 by Akjosch

You can pass the ship object itself to the widget, like this.

<<shielddamage $milleniumFalcon>>

The widget itself has access to it via its $args argument array and (after a few sanity checks) can modify all the properties of the object. A version with some simple error reporting would look like this.

<<widget "shielddamage">>
	<<if $args[0] && Number.isFinite($args[0].shields)>>
		<<set $args[0].shields -= random(1, 10)>>
	<<else>>
		@@.error;invalid arguments <<- $args.raw>>@@
	<</if>>
<</widget>>

The advantage here is that you have easy access to other variables of the ship. For example, let's assume you want to expand the widget to do the following in the future:

  • When the shields are damaged, trigger all ":shieldsdamaged" event handlers and when they are fully depleted, all ":shieldsgone" event handlers additionally to it, with both getting full access to the damaged ship's JS object.
  • If the ship has indestructible shields (they need to be bypassed or shut down from the inside), don't damage them at all.
  • Have a 20% chance of overloading the shields if the damage exceeds 33% of their current strength.

You can do all of this without changing how the widget is called, just by changing its code.

<<widget "shielddamage">>
	<<if $args[0] && Number.isFinite($args[0].shields)>>
		<<if !$args[0].indestructibleShields>>
			<<set _damage = random(1, 10)>>
			<<if _damage * 3 > $args[0].shields && random(1, 5) === 1>>
				<<set _damage = $args[0].shields>>
			<</if>>
			<<set $args[0].shields -= Math.min($args[0].shields, _damage)>>
			<<run jQuery.event.trigger({
				type: ":shieldsdamaged",
				ship: $args[0],
				damage: _damage,
			})>>
			<<if $args[0].shields <= 0>>
			  <<run jQuery.event.trigger({
				  type: ":shieldsgone",
				  ship: $args[0],
			  })>>
			<</if>>
		<</if>>
	<<else>>
		@@.error;invalid arguments <<- $args.raw>>@@
	<</if>>
<</widget>>

(Relatively) easy extensibility, pretty easy usage. Event handlers can be added in your story's JavaScript section, like this.

jQuery(document).on(":shieldsdamaged", function(event) {
	/* get your ship from event.ship and the damage from event.damage */
});

 

Welcome to Twine Q&A, where you can ask questions and receive answers from other members of the community.

You can also find hints and information on Twine on the official wiki and the old forums archive.

See a spam question? Flag it instead of downvoting. A question flagged enough times will automatically be hidden while moderators review it.
...