Folks, I was grokking the handcuffs scripts and I think I found up to three possible problems, or I don't get the intent behind the logic. Can you help me understand?
I am talking about these handcuffs scripts:
https://github.com/SolariusScorch/XComFiles/blob/4f8e083df57eeca3a3a1b2dcd455a8ddc30b0cfa/Ruleset/scripts_XCOMFILES.rul#L2150-L2167 else gt RandomValue StrengthLevel;
unit.getStun CurrStun;
unit.getStunMax NewStun;
unit.Stats.getHealth UnitStatHealth;
unit.getHealth UnitHealth;
muldiv NewStun UnitHealth UnitStatHealth;
# debug_log "newTurnUnit: unit.Stats.getHealth = " UnitStatHealth ", unit.getHealth = " UnitHealth ", NewStun = " NewStun;
sub CurrStun NewStun;
add PrevStun CurrStun;
if lt PrevStun 0;
set PrevStun 0;
end;
unit.setTag Tag.VIRTUAL_STUN_LEVEL PrevStun;
unit.setStun NewStun;
# debug_log "newTurnUnit: if RandomValue (" RandomValue ") > StrengthLevel (" StrengthLevel ") then unit.setTag.VIRTUAL_STUN_LEVEL: " PrevStun ", unit.setStun: " NewStun;
end;The first possible issue I see is that the NewStun, aka "stun-with-handcuffs" aka "stun as understood by the game", is not capped at 200, the same way it is done here:
https://github.com/SolariusScorch/XComFiles/blob/4f8e083df57eeca3a3a1b2dcd455a8ddc30b0cfa/Ruleset/scripts_XCOMFILES.rul#L1860-L1863This might cause problems for units that have more than 50 base health, because maxStun is base health * 4, as can be seen here:
https://github.com/MeridianOXC/OpenXcom/blob/19449159c806c9e3e57e6907e3580812ff9bacf9/src/Savegame/BattleUnit.cpp#L5224Thus, for example, if a unit with 100 base health loses 20 hit points, this script will compute its new stun to be (100*4) * (100-20) / 100 = 400 * 0.8 = 360. Ouch.
The second potential problem I see is that the "stun-without-handcuffs" aka "virtual stun" gets set to 4 * (baseHealth - health). Meaning: the more badly wounded the unit, the larger the virtual stun.
This virtual stun is used to compute if the unit will even try to escape the handcuffs. If it is > 0 it won't. This can be seen here:
https://github.com/SolariusScorch/XComFiles/blob/4f8e083df57eeca3a3a1b2dcd455a8ddc30b0cfa/Ruleset/scripts_XCOMFILES.rul#L2134-L2139For the third problem: this virtual stun sometimes will end up dropping by 1 or 2 by turn, or not at all. Not sure why, but I think these are some rounding errors, as sometimes maxStun is 4*baseHealth-1 or -2.
Thus, some units will never try to escape the handcuffs while some of them will when the stun gets to 0. This is dependent on rounding error.
I deduced the formula for virtual stun from this code fragment:
sub CurrStun NewStun;
add PrevStun CurrStun;
if lt PrevStun 0;
set PrevStun 0;Here CurrStun is initially set to the "stun-including-handcuffs" which is at first MIN(maxStun, 200) which is MIN(baseHealth * 4, 200)
NewStun is maxStun * health / baseHealth
So CurrStun becomes, ignoring he MIN function:
CurrStun = CurrStun - NewStun
which is
maxStun - (maxStun * health/baseHealth)
which is
baseHealth * 4 - (baseHealth * 4 * health/baseHealth)
which is
baseHealth * 4 - (health * 4)
which is
4 * (baseHealth - health)
This now ends up being added to PrevStun which is the "stun-without-handcuffs" a.k.a. virtual stun.
Note that the numbers stabilize in repeated computations in following turns.
Next turn CurrStun will have the value of previous turns' NewStun
Applying to the formula above we get:
CurrStun = CurrStun - NewStun
=>
CurrStun = NewStun - NewStun
=>
CurrStun = 0
As I mentioned, sometimes there are rounding errors and instead CurrStun is -1 or even -2, decreasing the virtual stun by 1 or 2 each turn. But not the "stun-with-handcuffs" aka "stun as understood by the game".