+1 vote
by (8.9k 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
by (68.6k points)
selected by
 
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">>

 

by (8.9k points)
Thanks, Exile!  You're really good at this.  :-)
0 votes
by (8.6k points)
edited by

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 */
});

 

...