I7: How Temporary are Temporary Variables?

While using Inform 7, I am often a bit frustrated by temporary variables that don’t seem to be very temporary. I’m wondering if I am not properly comprehending the nature of these variables (and if not, whether someone could explain the matter) or if this is a bug in the program.

I’ll apologize in advance for posting tediously long sections of code without any context, but I’ve only ever noticed the trouble in complex rules (and posting the full context would probably be beyond the abilities of the forum to record). Fortunately I’m fairly certain it won’t be necessary for anyone to understand what the following code does or what the many cryptic variables utilized mean in order to see the phenomenon to which I’m referring.

The following bits of code are from parts of a highly-randomized combat system I’m developing. I have replaced the standard “attacking” action with a new action called “attacking it with” to deal with hand-to-hand combat between characters. I have a second action, “shooting it with,” to handle combat with ranged weapons.

First therefore I define some action variables for the “attacking it with” action. Although it’s not relevant to the issue at the heart of my post, the following code determines whether an attack is successful, and if successful what damage is done to the target:

[code]The attacking it with action has a number called hit-or-miss. The attacking it with action has a number called damage-inflicted.

Destructioncheck is a number that varies. Destructioncheck is usually 0.

Setting action variables for an actor attacking something (called the target) with something (called the means) (this is the pre-attacking-variables rule):
now destructioncheck is 0;
if the target is notbroke:
change destructioncheck to 1;
if the target is evasive:
let vaxie be a random number from 1 to 100;
if the means is a weapon:
let rivuto be melee-hit-chance of the actor plus accuracy-bonus of the means minus evasion-rating of the target;
if rivuto >= 100:
change rivuto to 99;
if vaxie is less than rivuto or vaxie is rivuto:
change hit-or-miss to 2;
otherwise:
change hit-or-miss to 1;
otherwise:
let rivuto be melee-hit-chance of the actor minus evasion-rating of the target;
if rivuto >= 100:
change rivuto to 99;
if vaxie is less than rivuto or vaxie is rivuto:
change hit-or-miss to 2;
otherwise:
change hit-or-miss to 1;
if the target is not evasive:
if a random chance of 95 in 100 succeeds:
change hit-or-miss to 2;
otherwise:
change hit-or-miss to 1;
if the target provides currenthp:
let elveto be the object-damage of the means;
let critchance be luck of the actor;
if the means is a weapon:
change elveto to elveto minus damage-reduction of the target;
let fenril be (elveto multiplied by ten) multiplied by damage-resistance of the target;
change fenril to (elveto multiplied by 1000) minus fenril;
change the damage-inflicted to a random number between (fenril divided by 2000) and (fenril divided by 1000);
increase the damage-inflicted by the melee-damage of the actor;
if the accuracy-bonus of the means is greater than 0:
change critchance to (accuracy-bonus of the means divided by 3) plus critchance;
if the means is not a weapon:
change elveto to elveto minus damage-reduction of the target;
let fenril be (elveto multiplied by ten) multiplied by damage-resistance of the target;
change fenril to (elveto multiplied by 1000) minus fenril;
change the damage-inflicted to a random number between (fenril divided by 2000) and (fenril divided by 1000);
increase the damage-inflicted by the melee-damage of the actor;
let gawil be a random number from 1 to 100;
if a random chance of critchance in 100 succeeds:
if hit-or-miss is 2:
say “Critical hit!”;
if gawil is greater than 0 and gawil is less than 46:
change the damage-inflicted to (damage-inflicted multiplied by 15) divided by 10;
if gawil is greater than 45 and gawil is less than 86:
change the damage-inflicted to damage-inflicted multiplied by 3;
if gawil is greater than 85:
change the damage-inflicted to (damage-inflicted multiplied by 45) divided by 10.[/code]

When combined with all the other rules in the game, everything works great. I then proceed to define the “shooting it with action,” and define action variables for it to determine, among other things, if the attack was successful and how much damage is done by a successful attack:

[code]The shooting it with action has a number called hit-or-miss. The shooting it with action has a number called total-hits. The shooting it with action has a number called damage-inflicted.

Setting action variables for an actor shooting something (called the target) with something (called the means) (this is the pre-shooting-variables rule):
now destructioncheck is 0;
if the target is notbroke:
change destructioncheck to 1;
let vaxie be a random number from 1 to 100;
if the target is evasive:
if the means is a weapon:
change hit-or-miss to 1;
let rivuto be ranged-hit-chance of the actor plus accuracy-bonus of the means minus evasion-rating of the target;
if rivuto >= 96:
change rivuto to 95;
if the means is a mechstylegun:
if the rateoffire of the means is less than the currentammo of a random ammaclip enclosed by the means or the rateoffire of the means is the currentammo of a random ammaclip enclosed by the means:
repeat with multishot running from 1 to rateoffire of the means:
change vaxie to a random number from 1 to 100;
if vaxie is less than rivuto or vaxie is rivuto:
now hit-or-miss is 2;
increase total-hits by 1;
otherwise if the rateoffire of the means is greater than the currentammo of a random ammaclip enclosed by the means:
repeat with multishot running from 1 to currentammo of a random ammaclip enclosed by the means:
change vaxie to a random number from 1 to 100;
if vaxie is less than rivuto or vaxie is rivuto:
now hit-or-miss is 2;
increase total-hits by 1;
if the means is a manualgun:
if the rateoffire of the means is less than the currentammo of a random ammochamber enclosed by the means or the rateoffire of the means is the currentammo of a random ammochamber enclosed by the means:
repeat with multishot running from 1 to rateoffire of the means:
change vaxie to a random number from 1 to 100;
if vaxie is less than rivuto or vaxie is rivuto:
now hit-or-miss is 2;
increase total-hits by 1;
otherwise if the rateoffire of the means is greater than the currentammo of a random ammochamber enclosed by the means:
repeat with multishot running from 1 to currentammo of a random ammochamber enclosed by the means:
change vaxie to a random number from 1 to 100;
if vaxie is less than rivuto or vaxie is rivuto:
now hit-or-miss is 2;
increase total-hits by 1;
otherwise if the means is not a weapon:
let rivuto be ranged-hit-chance of the actor minus evasion-rating of the target;
if rivuto >= 91:
change rivuto to 90;
if vaxie is less than rivuto or vaxie is rivuto:
change hit-or-miss to 2;
otherwise:
change hit-or-miss to 1;
if the target is not evasive:
if the means is a weapon:
change hit-or-miss to 1;
let rivuto be ranged-hit-chance of the actor plus accuracy-bonus of the means;
change rivuto to rivuto plus rivuto;
if rivuto >= 96:
change rivuto to 95;
if the means is a mechstylegun:
if the rateoffire of the means is less than the currentammo of a random ammaclip enclosed by the means or the rateoffire of the means is the currentammo of a random ammaclip enclosed by the means:
repeat with multishot running from 1 to rateoffire of the means:
change vaxie to a random number from 1 to 100;
if vaxie is less than rivuto or vaxie is rivuto:
now hit-or-miss is 2;
increase total-hits by 1;
otherwise if the rateoffire of the means is greater than the currentammo of a random ammaclip enclosed by the means:
repeat with multishot running from 1 to currentammo of a random ammaclip enclosed by the means:
change vaxie to a random number from 1 to 100;
if vaxie is less than rivuto or vaxie is rivuto:
now hit-or-miss is 2;
increase total-hits by 1;
if the means is a manualgun:
if the rateoffire of the means is less than the currentammo of a random ammochamber enclosed by the means or the rateoffire of the means is the currentammo of a random ammochamber enclosed by the means:
repeat with multishot running from 1 to rateoffire of the means:
change vaxie to a random number from 1 to 100;
if vaxie is less than rivuto or vaxie is rivuto:
now hit-or-miss is 2;
increase total-hits by 1;
otherwise if the rateoffire of the means is greater than the currentammo of a random ammochamber enclosed by the means:
repeat with multishot running from 1 to currentammo of a random ammochamber enclosed by the means:
change vaxie to a random number from 1 to 100;
if vaxie is less than rivuto or vaxie is rivuto:
now hit-or-miss is 2;
increase total-hits by 1;
otherwise if the means is not a weapon:
let rivuto be ranged-hit-chance of the actor plus ranged-hit-chance of the actor;
if rivuto >= 96:
change rivuto to 95;
if vaxie is less than rivuto or vaxie is rivuto:
change hit-or-miss to 2;
otherwise:
change hit-or-miss to 1;
if the target provides currenthp:
let elveto be the object-damage of the means;
let critchance be the luck of the actor;
if the means is a weapon:
change elveto to elveto minus damage-reduction of the target;
let fenril be (elveto multiplied by ten) multiplied by damage-resistance of the target;
change fenril to (elveto multiplied by 1000) minus fenril;
if total-hits is at least 1:
change damage-inflicted to 0;
repeat with burstcheck running from 1 to total-hits:
increase the damage-inflicted by a random number between (fenril divided by 2000) and (fenril divided by 1000);
if damage-inflicted is less than 1:
change damage-inflicted to 1;
if the accuracy-bonus of the means is greater than 0:
change critchance to (accuracy-bonus of the means divided by 3) plus critchance;
if the means is not a weapon:
change elveto to elveto minus damage-reduction of the target;
let fenril be (elveto multiplied by ten) multiplied by damage-resistance of the target;
change fenril to (elveto multiplied by 1000) minus fenril;
change the damage-inflicted to a random number between (fenril divided by 2000) and (fenril divided by 1000);
if damage-inflicted is less than 1:
change damage-inflicted to 1;
let gawil be a random number from 1 to 100;
if a random chance of critchance in 100 succeeds:
if hit-or-miss is 2:
say “Critical hit!”;
if gawil is greater than 0 and gawil is less than 46:
change the damage-inflicted to (damage-inflicted multiplied by 15) divided by 10;
if gawil is greater than 45 and gawil is less than 86:
change the damage-inflicted to damage-inflicted multiplied by 3;
if gawil is greater than 85:
change the damage-inflicted to (damage-inflicted multiplied by 45) divided by 10.
[/code]

When combined with all the other “shooting it with” rules, everything compiles fine. However in the course of the test game when a) the “defining action variables for an actor shooting it with” rule is present at the same time as the “defining action variables for an actor attacking it with” rule, and b) I have one character shoot another character, I always see some variaton of the following jibba-jabba:

Whenever situations like this occur, changing the relevant code simply by changing the names of what should be temporary variables solves the problem. For example, when I change the “shooting it with” rules as follows:

[code][Note: the only changes made were prefacing some variable names with an “SW,” and enclosing other variable names with a capital “A”]

The shooting it with action has a number called SWhit-or-miss. The shooting it with action has a number called total-hits. The shooting it with action has a number called SWdamage-inflicted.

Setting action variables for an actor shooting something (called the target) with something (called the means) (this is the pre-shooting-variables rule):
now destructioncheck is 0;
if the target is notbroke:
change destructioncheck to 1;
let AvaxieA be a random number from 1 to 100;
if the target is evasive:
if the means is a weapon:
change SWhit-or-miss to 1;
let ArivutoA be ranged-hit-chance of the actor plus accuracy-bonus of the means minus evasion-rating of the target;
if ArivutoA >= 96:
change ArivutoA to 95;
if the means is a mechstylegun:
if the rateoffire of the means is less than the currentammo of a random ammaclip enclosed by the means or the rateoffire of the means is the currentammo of a random ammaclip enclosed by the means:
repeat with multishot running from 1 to rateoffire of the means:
change AvaxieA to a random number from 1 to 100;
if AvaxieA is less than ArivutoA or AvaxieA is ArivutoA:
now SWhit-or-miss is 2;
increase total-hits by 1;
otherwise if the rateoffire of the means is greater than the currentammo of a random ammaclip enclosed by the means:
repeat with multishot running from 1 to currentammo of a random ammaclip enclosed by the means:
change AvaxieA to a random number from 1 to 100;
if AvaxieA is less than ArivutoA or AvaxieA is ArivutoA:
now SWhit-or-miss is 2;
increase total-hits by 1;
if the means is a manualgun:
if the rateoffire of the means is less than the currentammo of a random ammochamber enclosed by the means or the rateoffire of the means is the currentammo of a random ammochamber enclosed by the means:
repeat with multishot running from 1 to rateoffire of the means:
change AvaxieA to a random number from 1 to 100;
if AvaxieA is less than ArivutoA or AvaxieA is ArivutoA:
now SWhit-or-miss is 2;
increase total-hits by 1;
otherwise if the rateoffire of the means is greater than the currentammo of a random ammochamber enclosed by the means:
repeat with multishot running from 1 to currentammo of a random ammochamber enclosed by the means:
change AvaxieA to a random number from 1 to 100;
if AvaxieA is less than ArivutoA or AvaxieA is ArivutoA:
now SWhit-or-miss is 2;
increase total-hits by 1;
otherwise if the means is not a weapon:
let ArivutoA be ranged-hit-chance of the actor minus evasion-rating of the target;
if ArivutoA >= 91:
change ArivutoA to 90;
if AvaxieA is less than ArivutoA or AvaxieA is ArivutoA:
change SWhit-or-miss to 2;
otherwise:
change SWhit-or-miss to 1;
if the target is not evasive:
if the means is a weapon:
change SWhit-or-miss to 1;
let ArivutoA be ranged-hit-chance of the actor plus accuracy-bonus of the means;
change ArivutoA to ArivutoA plus ArivutoA;
if ArivutoA >= 96:
change ArivutoA to 95;
if the means is a mechstylegun:
if the rateoffire of the means is less than the currentammo of a random ammaclip enclosed by the means or the rateoffire of the means is the currentammo of a random ammaclip enclosed by the means:
repeat with multishot running from 1 to rateoffire of the means:
change AvaxieA to a random number from 1 to 100;
if AvaxieA is less than ArivutoA or AvaxieA is ArivutoA:
now SWhit-or-miss is 2;
increase total-hits by 1;
otherwise if the rateoffire of the means is greater than the currentammo of a random ammaclip enclosed by the means:
repeat with multishot running from 1 to currentammo of a random ammaclip enclosed by the means:
change AvaxieA to a random number from 1 to 100;
if AvaxieA is less than ArivutoA or AvaxieA is ArivutoA:
now SWhit-or-miss is 2;
increase total-hits by 1;
if the means is a manualgun:
if the rateoffire of the means is less than the currentammo of a random ammochamber enclosed by the means or the rateoffire of the means is the currentammo of a random ammochamber enclosed by the means:
repeat with multishot running from 1 to rateoffire of the means:
change AvaxieA to a random number from 1 to 100;
if AvaxieA is less than ArivutoA or AvaxieA is ArivutoA:
now SWhit-or-miss is 2;
increase total-hits by 1;
otherwise if the rateoffire of the means is greater than the currentammo of a random ammochamber enclosed by the means:
repeat with multishot running from 1 to currentammo of a random ammochamber enclosed by the means:
change AvaxieA to a random number from 1 to 100;
if AvaxieA is less than ArivutoA or AvaxieA is ArivutoA:
now SWhit-or-miss is 2;
increase total-hits by 1;
otherwise if the means is not a weapon:
let ArivutoA be ranged-hit-chance of the actor plus ranged-hit-chance of the actor;
if ArivutoA >= 96:
change ArivutoA to 95;
if AvaxieA is less than ArivutoA or AvaxieA is ArivutoA:
change SWhit-or-miss to 2;
otherwise:
change SWhit-or-miss to 1;
if the target provides currenthp:
let AelvetoA be the object-damage of the means;
let AcritchanceA be the luck of the actor;
if the means is a weapon:
change AelvetoA to AelvetoA minus damage-reduction of the target;
let AfenrilA be (AelvetoA multiplied by ten) multiplied by damage-resistance of the target;
change AfenrilA to (AelvetoA multiplied by 1000) minus AfenrilA;
if total-hits is at least 1:
change SWdamage-inflicted to 0;
repeat with burstcheck running from 1 to total-hits:
increase the SWdamage-inflicted by a random number between (AfenrilA divided by 2000) and (AfenrilA divided by 1000);
if SWdamage-inflicted is less than 1:
change SWdamage-inflicted to 1;
if the accuracy-bonus of the means is greater than 0:
change AcritchanceA to (accuracy-bonus of the means divided by 3) plus AcritchanceA;
if the means is not a weapon:
change AelvetoA to AelvetoA minus damage-reduction of the target;
let AfenrilA be (AelvetoA multiplied by ten) multiplied by damage-resistance of the target;
change AfenrilA to (AelvetoA multiplied by 1000) minus AfenrilA;
change the SWdamage-inflicted to a random number between (AfenrilA divided by 2000) and (AfenrilA divided by 1000);
if SWdamage-inflicted is less than 1:
change SWdamage-inflicted to 1;
let AgawilA be a random number from 1 to 100;
if a random chance of AcritchanceA in 100 succeeds:
if SWhit-or-miss is 2:
say “Critical hit!”;
if AgawilA is greater than 0 and AgawilA is less than 46:
change the SWdamage-inflicted to (SWdamage-inflicted multiplied by 15) divided by 10;
if AgawilA is greater than 45 and AgawilA is less than 86:
change the SWdamage-inflicted to SWdamage-inflicted multiplied by 3;
if AgawilA is greater than 85:
change the SWdamage-inflicted to (SWdamage-inflicted multiplied by 45) divided by 10.[/code]

My code works fine, so I’m not looking for any pointers on the particulars (unless of course someone cares to offer such). My questions are simply:

a) am I failing to understanding these variables properly when I understand them as “temporary variables,” as in

or,

b) is this some kind of bug, or

c) none of the above.

I realize this is a very long post for anyone to read through, so thank you in advance for any responses.

As you’ve discovered, all action variable names must be unique:

I guess they are talking about general action rules such as “Instead of loud behaviour” or “After doing something with the bomb in the presence of the guard dog”. The variables can be accessed here as well, but you’d have to be careful only to refer to them inside clauses that check the specific action, or you’ll get those “variable unavailable” errors.

Well, they are not the same thing exactly. Those created with “let” become “regular” temporary variables that only exist inside a certain routine, like “i” in the following:

[ CountToTen i; for (i=1: i<11: i++) print i; ];
But the action variables have to be available throughout the duration of an action and all of its rulebooks. Have a look at the chapter on the MStack Template in Appendix B to see how they’re implemented.

I’m wondering though why the compiler doesn’t give an error when you try to create several action variables with the same name?

Also, the following part sounds strange to me:

because that first error message is the one you get when you try to refer to an action variable that belongs to another action. So why does it say it’s impossible to produce? Am I reading that wrong?

Thanks for the answers, SJ_43. I definitely was not understanding the issue, but it makes sense now that you pointed out the need for action variables to be named uniquely. I had briefly thought about the possiblity that some Instead rules related to combat actions (such as “Instead of attacking someone with a gun, try shooting the noun with the second noun”) were causing the trouble because they grabbed the setting action variables rules for both actions at once, but when I commented out all those pre-emptive rules and there was no difference I set the idea aside without going further and realizing all the other very generic check rules that had nothing to do with the combat ruleset were also doing the same thing.

I took a look at the document you mentioned. Although I don’t understand I6 code, the comments before each bit of code were pretty clear about what each section of code does. I don’t think you’re reading anything wrongly, because the word “impossible” prefacing the bit of code you quoted is a pretty strong word, and I read the whole thing the same way you did.

Thanks again for your help on this issue.