Author Topic: [Solved] Trying to change Yankes "Poison Script" Round 2!  (Read 3110 times)

Offline The Martian

  • Commander
  • *****
  • Posts: 754
  • "It implores you to listen to its arguments..."
    • View Profile
[Solved] Trying to change Yankes "Poison Script" Round 2!
« on: September 24, 2021, 01:57:36 am »
(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)
Spoiler:
Code: [Select]
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

(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:
Code: [Select]
            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)

Code: [Select]
extended:
  tags:
    RuleItem:
      POISON_STRENGTH: int
    RuleArmor:
      POISON_SUSCEPTIBILITY: int
    BattleUnit:
      POISON_LEVEL: int

This script runs when a unit is damaged.

Code: [Select]
  scripts:
    damageUnit:

offset: 1 means this script will run before any script with offset: 2 or greater.

Code: [Select]
      - 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: [Select]
        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.
         
Code: [Select]
          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.

Code: [Select]
          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.

Code: [Select]
    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.

Code: [Select]
    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.

Code: [Select]
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.
Code: [Select]
          var int duration 0;
The item also now passes the Tag.POISON_DURATION value to the scripts duration variable:
Code: [Select]
          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:
Code: [Select]
            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:
Code: [Select]
            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:
Code: [Select]
          var int duration 0;
and has the value held by the unit's POISON_REMAINING tag assigned to it.
Code: [Select]
          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:
Code: [Select]
            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:
Code: [Select]
          if le duration 0;
            unit.setTag Tag.POISON_LEVEL 0;


When the mod is loaded, the following error is displayed

Code: [Select]
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
« Last Edit: February 12, 2023, 03:17:59 pm by Meridian »

Offline The Martian

  • Commander
  • *****
  • Posts: 754
  • "It implores you to listen to its arguments..."
    • View Profile
Re: Trying to change Yankes "Poison Script" Round 2!
« Reply #1 on: September 24, 2021, 02:20:44 am »
I tried removing these lines and it stopped the mod's loading error:
Code: [Select]
          debug_log 3 3;
#            mul strength susceptibility;
#            div strength 10;

Is 'comment' # text not allowed inside a script's code: | sections?

Unfortunately the poison effect does not appear to be being applied when an x-com soldier wearing the poisonable armor is struck by the poison weapon, so I'm still missing something.


Here's the new version of the mod:
TestModPoison V0-2.zip
« Last Edit: September 24, 2021, 02:35:25 am by The Martian »

Offline Nord

  • Commander
  • *****
  • Posts: 1625
  • The Gate is open.
    • View Profile
Re: Trying to change Yankes "Poison Script" Round 2!
« Reply #2 on: September 24, 2021, 10:48:14 am »
You have missing "end;" in some cases. here is fixed script.

Offline The Martian

  • Commander
  • *****
  • Posts: 754
  • "It implores you to listen to its arguments..."
    • View Profile
Re: Trying to change Yankes "Poison Script" Round 2!
« Reply #3 on: September 30, 2021, 02:10:02 pm »
Thank you!

I just went through the .rul file you posted and I think I see what you mean.

All IF statements need to have their code block closed with an end; command.

Offline Ethereal

  • Commander
  • *****
  • Posts: 619
    • View Profile
Re: Trying to change Yankes "Poison Script" Round 2!
« Reply #4 on: June 17, 2022, 07:57:14 am »
The translator does not speak English well, but... I did not find anything about reducing the level poisoning with the help of a first aid kit. And that should have been the first thing to think about.

I was just thinking about using poison in the modification, but no, without the ability to remove the poison with a first-aid kit, this is not applicable.