(UPDATE)I think that I've solved the mod loading error... but now the script's poison effect isn't working when the unit is struck. Here is the new example Mod from 2nd post in this thread:
TestModPoison V0-2.zip
(Goal). Edit
Yankes "
Simple poison bullets that do damage over time" script so that it no longer decreases the amount of health lost as the duration reduces.
. Control the duration of the poison via a tag on the weapon item.
. Change the armors:
POISON_SUSCEPTIBILITY tag to a 0-1 true-false switch that determines if an armor can be poisoned.
(Problem). Poison effect does not apply when a unit wearing the poisonable armor is struck.
.
My current attempt is throwing the following error: (Solved, see 2nd post)(Example Mod)For convenience I've attached the mod I'm working with that contains the modified script to this post:
TestModPoison V0-1.zip
I've been reading up on how
OpenXcom's scripting works and I thought I was finally ready to make the edits I attempted a year ago back in this thread "
A few questions about this "Poison Script" (OXCE)".
Unfortunately the code is throwing an error so I've missed something.
I think the error is being triggered by the removal of these lines of code, but I'm not sure why:
mul strength susceptibility;
div strength 10;
I'm going to break down my understanding of Yankes's original code, if anyone spots my mistake or anything odd I'm doing please let me know.
This part creates the variables that the script keeps information on the effected item, armor and unit.
POISON_STRENGTH is the amount of damage the poison does.
POISON_SUSCEPTIBILITY is the armor's resistance to the poison.
POISON_LEVEL stores the amount of poison left on the unit.
This code needs to be in the
items.rul armors.rul &
units.rul files.
(If you have the armors: items: units: code sections split between different .rul files)extended:
tags:
RuleItem:
POISON_STRENGTH: int
RuleArmor:
POISON_SUSCEPTIBILITY: int
BattleUnit:
POISON_LEVEL: int
This script runs when a unit is damaged.
scripts:
damageUnit:
offset: 1 means this script will run before any script with
offset: 2 or greater.
- offset: 1
This code block creates temporary variables to handle the values the poison scripts works with.
The
var int definitions are creating variables that can hold an integer.
I'm not sure exactly how the
var ptr part works but I'm guessing it is loading the entire
items: and
armors: section for the script to access.
code: |
var int susceptibility 0;
var int strength 0;
var int temp 0;
var ptr RuleArmor armor_rule;
var ptr RuleItem item_rule;
the
armor_rule variable is being assigned the value found on the unit being damaged's armor's
POISON_SUSCEPTIBILITY tag.
This value is then being stored in the scripts
susceptibility variable to make it easier to work with.
Similarly the item being used to damage the unit has the value of its
POISON_STRENGTH assigned to the scripts
strength variable.
unit.getRuleArmor armor_rule;
armor_rule.getTag susceptibility Tag.POISON_SUSCEPTIBILITY;
damaging_item.getRuleItem item_rule;
item_rule.getTag strength Tag.POISON_STRENGTH;
I'm not sure how the
debug_log commands work but I'm guessing that both
strength &
susceptibility variables are written in the
openxcom.log file by these commands.
Then if both
strength &
susceptibility are
gt(Greater Than) 0 the item's poison
strength is multiplied by the armor's
susceptibility value.
After which
strength is divided by 10.
The unit being damaged's
POISON_LEVEL tag variable is then stored in the
temp variable.
Then if
temp is
lt(Less than)
strength the unit's
POISON_LEVEL tag is given the value of
strength.
If I'm reading it correctly what this section of code has done is check to see if incoming poison damage is of a higher value than any poison currently on the unit, and if it is the new higher poison value is given to the unit's tag.
I think that
return; is used to end the script and return the flow of code back to the rest of the game engine loop.
debug_log 1 strength;
debug_log 2 susceptibility;
if and gt strength 0 gt susceptibility 0;
debug_log 3 3;
mul strength susceptibility;
div strength 10;
unit.getTag temp Tag.POISON_LEVEL;
if lt temp strength;
unit.setTag Tag.POISON_LEVEL strength;
end;
end;
return;
This code block is separate from the above one and is only run for each unit at the beginning of a new turn.
New temporary variables are declared called
poison &
hp.
The
poison variable is assigned the value of the unit's
POISON_LEVEL tag.
If the
poison value is greater than 0
(The unit is currently poisoned) then the unit's health is assigned to the
hp variable.
The value of
poison is subtracted from
hp and then the unit has its actual health value changed to match the
hp variable.
The
poison value is subtracted by 1 and then the unit's
POISON_LEVEL is assigned the resulting new value.
newTurnUnit:
- offset: 1
code: |
var int poison;
var int hp;
unit.getTag poison Tag.POISON_LEVEL;
if gt poison 0;
unit.getHealth hp;
sub hp poison;
unit.setHealth hp;
sub poison 1;
unit.setTag Tag.POISON_LEVEL poison;
end;
return;
This code block changes the colour of a unit that is currently poisoned.
The 4 on the line:
set_color new_pixel 4; #green color
controls what the new colour is.
If I'm understanding it correctly the number indicates the row used in the X-Com palette.
When using the
TFTD palette a value of 5 gives a similar green shade to the one expected in
X-COM: UFO Defense.
recolorUnitSprite:
- offset: 4
code: |
var int poison;
unit.getTag poison Tag.POISON_LEVEL;
if gt poison 0;
set_color new_pixel 4; #green color
end;
return new_pixel;
That is my understanding of how the code works, and now here is the way I've tried to alter the script.
extended:
tags:
RuleItem:
POISON_STRENGTH: int
POISON_DURATION: int
RuleArmor:
POISON_SUSCEPTIBILITY: int
BattleUnit:
POISON_REMAINING: int
POISON_LEVEL: int
scripts:
damageUnit:
- offset: 1
code: |
var int susceptibility 0;
var int strength 0;
var int duration 0;
var int temp 0;
var ptr RuleArmor armor_rule;
var ptr RuleItem item_rule;
unit.getRuleArmor armor_rule;
armor_rule.getTag susceptibility Tag.POISON_SUSCEPTIBILITY;
damaging_item.getRuleItem item_rule;
item_rule.getTag strength Tag.POISON_STRENGTH;
item_rule.getTag duration Tag.POISON_DURATION;
debug_log 1 strength;
debug_log 2 susceptibility;
if and gt strength 0 gt susceptibility 0;
debug_log 3 3;
# mul strength susceptibility;
# div strength 10;
unit.getTag temp Tag.POISON_LEVEL;
if lt temp strength;
unit.setTag Tag.POISON_LEVEL strength;
unit.getTag temp Tag.POISON_REMAINING;
if lt temp duration;
unit.setTag Tag.POISON_REMAINING duration;
end;
end;
return;
newTurnUnit:
- offset: 1
code: |
var int poison;
var int hp;
var int duration 0;
unit.getTag poison Tag.POISON_LEVEL;
unit.getTag duration Tag.POISON_REMAINING;
if gt poison 0;
unit.getHealth hp;
sub hp poison;
unit.setHealth hp;
sub duration 1;
unit.setTag Tag.POISON_REMAINING duration;
if le duration 0;
unit.setTag Tag.POISON_LEVEL 0;
end;
return;
recolorUnitSprite:
- offset: 4
code: |
var int poison;
unit.getTag poison Tag.POISON_LEVEL;
if gt poison 0;
set_color new_pixel 5; # 4 green color
end;
return new_pixel;
I've tried to changed the tags used by the script a bit.
(Items:)
POISON_STRENGTH = How strong the weapon's poison is.
POISON_DURATION = How long the weapon's poison lasts when applied.
(Armors:)
POISON_SUSCEPTIBILITY = Can this unit be poisoned? 0 = false. 1 = true.
(Units:)
POISON_REMAINING = Tag for storing
POISON_DURATION when a unit is poisoned.
POISON_LEVEL = Tag for storing
POISON_STRENGTH when a unit is poisoned.
A new variable is declared at the start of the script to store the amount of time the inflicted poison will last.
var int duration 0;
The item also now passes the
Tag.POISON_DURATION value to the scripts duration variable:
item_rule.getTag duration Tag.POISON_DURATION;
As susceptibility now is used only to check if the armor can be poisoned or not these two lines of code are removed:
mul strength susceptibility;
div strength 10;
If the
tag.POISON_DURATION of the weapon is higher than the
tag.POISON_REMAINING value on the unit then the unit's
POISON_REMAINING value is assigned the weapons poison
duration value:
unit.getTag temp Tag.POISON_REMAINING;
if lt temp duration;
unit.setTag Tag.POISON_REMAINING duration;
in the
newTurnUnit: code block the temporary variable
duration is created again:
var int duration 0;
and has the value held by the unit's
POISON_REMAINING tag assigned to it.
unit.getTag duration Tag.POISON_REMAINING;
As
POISON_LEVEL is no longer linked to the time a unit spends poisoned the
duration variable is subtracted from instead of
poison:
sub duration 1;
unit.setTag Tag.POISON_REMAINING duration;
An additional
if statement is checked to see if the
duration is 0 and then zero the
POISON_LEVEL tag on the unit if it is:
if le duration 0;
unit.setTag Tag.POISON_LEVEL 0;
When the mod is loaded, the following error is displayed
ERROR:
[23-09-2021_15-36-06] [FATAL] Error loading file './user/mods/TestModPoison/Ruleset/scriptPoison.rul'
[23-09-2021_15-36-06] [WARN] disabling mod with invalid ruleset: TESTPOISON
[23-09-2021_15-36-06] [ERROR] failed to load 'Testing Mod: Poison Script'; mod disabled
./user/mods/TestModPoison/Ruleset/scriptPoison.rul: yaml-cpp: error at line 34, column 13: end of map not found