Using the same variable in a nested widget

Twine Version: 2.8.1 Story Format: Sugarcube 2.36.1
[also choose a Story Format tag above]

Hello! I am writing a widget which determines the nature of enemy to determine if weapon does any damage. For example, non-silver does not damage undead. And this widget is called inside the sword attack widget. Can we use _args[0] again inside such nested widget?
But I think that maybe I should do it somehow simpler.
Thanks in advance!

<<set $enmNature=1; $enmGiant=1; $enmElem=1; $enmMod=1>>
/*max enmNature=1, max enmGiant=1.5, max enmElem=1.5*/

/*set weapon*/
<<set $sword={type: "weapon1h", wtype: "sword", name:"железный меч", atk: 70, cost:25, ench: 0, enchType: "water", material: "iron"}>>
/*set enemy*/
<<set $enm to {   
name: "скелет-воин", lvl: 4, sp: 4,
streng: 6,  dex: 0.3, intel: 4, wisd: 2, 
hp: 340, maxhp: 340, mp: 100, maxmp: 100, stam: 100, maxstam: 100, def: 190, atk: 250, atkMax: 250, atkname: "наносит удар мечом", atkrange: 3,
exper: 400, slash: 1.2, pierce: 1, smash: 0.9, hack: 1.1, effect: "none", effDur: 0, water: 0.95, earth: 0.8, fire: 1.1, 
nature: "undead", giant: false, elem: "none"

/*Widget passage*/
/*calculate enemy modificator enmMod*/
<<widget "EnmWeak">>
<<if _args[0] and _args[1]>>/*if defined temporary variables (elements of array) _args[0] - weapon, _args[1] - enemy*/
<<capture _args[0], _args[1]>>/*keep temporary variables in memory*/
<<if _args[0].material=="silver">>
<<if _args[1].nature=="undead">><<set $enmNature=1>><</if>>
<<elseif _args[0].material!="silver">>
	<<if _args[1].nature=="undead">><<set $enmNature=0>><</if>>
<<if (_args[0].wtype=="spear") and (_args[1].giant==true)>>
	<<set $enmGiant=1.5>>
<<if _args[1].elem!= _args[0].enchType>><<set $enmElem=1.5>><</if>>
<<set $enmMod=$enmNature*$enmGiant*$enmElem>>
<</if>>/*end all ifs*/

/*sword attack widget*/
<<widget "SwordAtkYourHack">>
<<if $singleE is true>><<if _args[0]>>
<<capture _args[0]>>
    <<AtkPr $you.swordSkill>>
    <<EnmWeak $sword $enm>>/*pass enemy and weapon to widget to calculate enmMod*/
    <<set $you.currAtk=Math.trunc($enm.hack*($you.swordSkill+$you.meleeSkill)*(_args[0].atk+_args[0].ench)*(1-$enm.dex)*$atk_prob*$enmMod)>>/*calculate attack of sword with modificator enmMod*/
    <<set $you.currHit=$you.currAtk-$enm.def>>
    <<if $you.currHit gt 0>><<set $enm.hp-=$you.currHit>>
    <<else>><<set $enm.hp-=$you.streng>>
    <<set $turn to "enemy">><<set $nturn+=1>>
    <<set $log to "attack">><<addmins 5>>


If your question is “Does my second widget inherit arguments from my first?” the question is no. Each widget must get it’s own arguments listed when called.
However I’m pretty sure, but no time right now to try, that you can call a widget inside another widget and take arguments from the first widget to the second. :

<<mysecondwidget _args[1]>>
1 Like

I tried the <<EnmWeak $sword $enm>> alone and it works. But when used with sword widget in combat it does not work, attack on skeleton enemy is not 0. I will be testing further.

StoryInit does not update if you use the F5 key. You need to restart each time the game when you change the StoryInit page.

With regards to the visibility of variables, widget invocations work very much like JavaScript function invocations—if you’re familiar with those.

Each widget invocation receives its own copies of the _args and _contents special variables—the latter only if it’s a container widget. Any preexisting instances of those variables are shadowed during the invocation—i.e., they’re backed up during the call, then restored afterward.

This means that separate widget invocations cannot see the special variables of another invocation, since each gets their own copies. That said, you can pass the values of one invocation’s special variables to another when invoking it.

For example. The following won’t print fnord because the <<bar>> invocation has its own separate copy of _args:

:: Widgets [widget]
<<widget "foo">>foo: <<bar>><</widget>>
<<widget "bar">>bar: <<= _args[0]>><</widget>>

:: Test
<<foo "fnord">> /* foo: bar: [undefined] */

This, on the other hand, will print fnord because <<foo>> passes the value of its _args[0] to its invocation of <<bar>>:

:: Widgets [widget]
<<widget "foo">>foo: <<bar _args[0]>><</widget>>
<<widget "bar">>bar: <<= _args[0]>><</widget>>

:: Test
<<foo "fnord">> /* foo: bar: fnord */


A few notes on <<capture>>

That is not how you use <<capture>>. It captures entire variables—e.g., _args and $char. It does not capture property accesses—e.g., _args[0] and $ Thus, for example, the following:

<<capture _args[0], _args[1]>>

Is actually doing:

<<capture _args>>

Additionally. Its use is only necessary when you need to use the current value of an existing variable within an asynchronous context. Neither of your example widgets shown above contain any asynchronous code.

1 Like

Big thanks to you and souppilouliouma!
Now I understand args a bit better.
I also forgot old $sword variable, which does not exist now and passed it to <<EnmWeak>>. So I fixed this by passing the same variable to the widget inside widget:

<<widget "SwordAtkYourHack">>
<<if $singleE is true>><<if _args[0]>>
    <<AtkPr $you.swordSkill>>
    <<EnmWeak _args[0] $enm>>/*pass weapon and enemy to widget to calculate enmMod*/
1 Like