Author Topic: [Solved] Script - Limbs hits not inmediately fatal  (Read 4199 times)

Offline cevaralien

  • Captain
  • ***
  • Posts: 96
    • View Profile
[Solved] Script - Limbs hits not inmediately fatal
« on: August 23, 2020, 11:32:29 pm »
I was thinking that limbs hits must not be absolutely fatal. In the real life, a hit in an arm doesn't kill the person inmediately.

So, i begun to do a script, based on this one https://openxcom.org/forum/index.php?topic=7310.0 of Kzer-Za. Credits to him for the base. I also modified the code to do more easy to read, for me.

Well... this is the code:

Quote
extended:
  tags:
    RuleItem:
      SPECIAL_WOUND: int
      WOUND_FACTOR: int

  scripts:
    damageUnit:
      - offset: -41
        code: |
          var int wounds;
          var int special;
          var int woundFactor;
          var ptr RuleItem itemRuleset;
          var int woundfac;
         
          damaging_item.getRuleItem itemRuleset;
          itemRuleset.getTag special Tag.SPECIAL_WOUND; 
          body_part get part; First, i need to know which part of the body has been hit. I think that this line is not good, but i don't found how to get the body part hitted.                    

          if neq to_health 0;       
            if or eq body_part 0 eq body_part 1; This is the standard of the original script.  It is working well.
              div to_health 1
              set woundfac 5
              return;         
            else or eq body_part 3 eq body_part 2; Here i want to define a factor to multiplies the wounds but reducing health damage, so, the soldier wouldn't be killed inmediately. I also increase the stun, to guaranties that the soldier will be out of combat.
              set to_stun to_health
              div to_health 4 
              set woundfac 3 
              return;
            else or eq body_part 4 eq body_part 5; Here i want to define a factor to multiplies the wounds but reducing health damage, so, the soldier wouldn't be killed inmediately. I also increase the stun, to guaranties that the soldier will be out of combat.
              set to_stun to_health
              div to_health 3
              set woundfac 2 
              return;
            end;           
            if eq special 1;
              return;     
            else eq special 2;
              itemRuleset.getTag woundFactor Tag.WOUND_FACTOR;
              set wounds to_health;
              div wounds woundFactor;
              set to_wound wounds;
              return;
            else and neq special 1 neq special 2;         
              set wounds to_health;
              div wounds woundfac;
              set to_wound wounds;
              return;
            end;
          end;


I think that this procedure of divide to_health is not good. I want to divide the damage received, but i don't know how to define it.
« Last Edit: February 12, 2023, 02:58:02 pm by Meridian »

Offline Yankes

  • Global Moderator
  • Commander
  • *****
  • Posts: 3347
    • View Profile
Re: Script - Limbs hits not inmediately fatal
« Reply #1 on: August 24, 2020, 03:17:01 am »
You can try `hitUnit` hook that is call before `damageUnit`, if I recall correct it can change damage that hit unit.


btw when you add comments to script use `#` before it, because if someone would like copy-paste your example will have invalid script.

Offline cevaralien

  • Captain
  • ***
  • Posts: 96
    • View Profile
Re: Script - Limbs hits not inmediately fatal
« Reply #2 on: August 25, 2020, 03:30:38 am »
Ok, i will take in mind the next time.

This is the script with HitUnit:
Quote
extended:
  tags:
    RuleItem:
      SPECIAL_WOUND: int
      WOUND_FACTOR: int
      WEAPON_POWER: int
      WEAPON_POWER2: int

  scripts:
    hitUnit:
      - offset: -41
        code:
          var int powr
          var ptr BattleUnit unit_battle;
          var ptr RuleItem item_rule;
         
          item_rule.GetTag powr Tag.WEAPON_POWER;
         #I have doubts about the following line. Does it well defined? Can i get the body part using "get part"? I think that this is my real problem.
          body_part get part;
         
          if or eq body_part 0 eq body_part 1;
            div powr 1
            item_rule.SetTag Tag.WEAPON_POWER2 powr;   
            return;
          end;
         
          if or eq body_part 3 eq body_part 2;
            div powr 4
            item_rule.SetTag Tag.WEAPON_POWER2 powr;       
            return;
          end;

          if or eq body_part 4 eq body_part 5;
            div powr 3
            item_rule.SetTag Tag.WEAPON_POWER2 powr;
            return;
          end;                   
         
    damageUnit:
      - offset: -41
        code: |
          var int wounds;
          var int special;
          var int woundFactor;
          var ptr RuleItem itemRuleset;
          var int hitpower;
          var int damagepower;
          var int woundfact;
         
          if eq to_health 0;
            return;
          end;
         
          damaging_item.getRuleItem itemRuleset;
          itemRuleset.getTag special Tag.SPECIAL_WOUND;
          itemRuleset.getTag hitpower Tag.WEAPON_POWER;
          itemRuleset.getTag damagepower Tag.WEAPON_POWER2;         

#The reason of hitpower and damagepower is to get the constant that will be used in damageUnit to reduce the amount of damage.         
          div hitpower damagepower                 
          if eq special 2;
            if eq hitpower 4;
              div to_health 4;
              return;
            else eq hitpower 3;
              div to_health 4;
              return;
            end;
            itemRuleset.getTag woundFactor Tag.WOUND_FACTOR;
            set wounds to_health;
            div wounds woundFactor;
            set to_wound wounds;
            return;       
          else neq special 2;
            if eq hitpower 4;
              div to_health 4;
              set woundfact 2;
              set to_stun hitpower;
              return;
            else eq hitpower 3;
              div to_health 4;
              set woundfact 3;
              set to_stun hitpower;
              return;
            else eq hitpower 1;
              set woundfact 5;
              return;                   
            set wounds to_health;
            div wounds woundfact;
            set to_wound wounds;
            return;
          end;

This script was a previously version of the first script posted, so there is some differences.

I defined two tags with names WEAPON_POWER and WEAPON_POWER2. Both will get the value of the weapon power, but the second one will be changed in HitUnit. I defined this because i don't know the exact mechanics of the scripting procces in OXCE. For example, in Python, i can use the final value of a function (return) in the next function, but i don't know if the damageUnit script would get the result of HitUnit.

Offline Yankes

  • Global Moderator
  • Commander
  • *****
  • Posts: 3347
    • View Profile
Re: Script - Limbs hits not inmediately fatal
« Reply #3 on: August 25, 2020, 07:13:18 pm »
First of all, I see you did not try run this script because it would throw errors, `RuleItem` is readonly object in script, you cannot set its tags.
Second thing is looking on verbose log where I dump all script hooks data, aka all parameters passed to script and all functions available to it.

Thing you want change is `BattleItem` or `BattleUnit`, probably best would be add tags to `BattleUnit` that is hit.
`part` is `int` value that have curret body part that is hitted. You do not need do any thing to use it, only change you could do not to use values like `1` but named ones like:
Code: [Select]
if or eq part BODYPART_LEFTARM eq part BODYPART_RIGHTARM;
Another thing is you can alter real damage that unit will get by altering variable `power`.

Finally `hitUnit` script hook require you to return multiple values like:
Code: [Select]
return power part side;

`damageUnit` do not do this because it would need 7+ values that would be very hard to handle correctly.


Offline cevaralien

  • Captain
  • ***
  • Posts: 96
    • View Profile
Re: Script - Limbs hits not inmediately fatal
« Reply #4 on: August 28, 2020, 03:17:59 pm »
Yes, you are right. I haven't run this script yet.

I will try to do it with your code for bodyparts. That is what i was looking for.

I will inform here about my progress.

Offline cevaralien

  • Captain
  • ***
  • Posts: 96
    • View Profile
Re: Script - Limbs hits not inmediately fatal
« Reply #5 on: September 06, 2020, 05:30:36 pm »
Ok. I tried that i understand. I think that my problem is setting the body part when i am in damageUnit script. I want to set a random number to the damage (after armor), not to power. In fact, i want a flat power hitting the armor, but the resulting damage will be modified for a random modifier that increase or decrease the to_health.

For example, if any of the arms are hitted, the to_healt amount will be a random number from 0.1 to 0.5 of the resulting damage after armor. But, if the hit is at the head, the random number will be from 1 to 2.

That is the spirit of this script. 

Quote
extended:
  tags:
    RuleItem:
      SPECIAL_WOUND: int
      WOUND_FACTOR: int

  scripts:     
    hitUnit: #Here i tried to set the part, but i don't know if it ok
      - offset: -41
        code: |
          var ptr RuleItem rule;
          damaging_item.getRuleItem rule;
          return power part side;
    damageUnit:
      - offset: -41
        code: |
          var int wounds;
          var int special;
          var int woundFactor;
          var int ranhealth;
          var int health;
          var int lowv;
          var int higv;
          var ptr RuleItem itemRuleset;
         
          damaging_item.getRuleItem itemRuleset;
          itemRuleset.getTag special Tag.SPECIAL_WOUND; 
         
          if or eq part BODYPART_LEFTARM eq part BODYPART_RIGHTARM;
            set lowv 1;
            set higv 5;
            return;
          else or eq part BODYPART_LEFTLEG eq part BODYPART_RIGHTLEG;
            set lowv 5;
            set higv 10;
            return;
          else eq part BODYPART_TORSO;
            set lowv 5;
            set higv 20;
            return; 
          else eq part BODYPART_HEAD;
            set lowv 10;
            set higv 20;
            return;
          end; 
     
          battle_game.randomRange ranhealth lowv higv; #Here i'm changing the RandomHealth, because i don't like the 0 - X range. It is working when the range is defined with a number. I tested it.
          set health to_health;
          mul health ranhealth;
          div health 10;
          set to_health health;
                                       
          if ge to_health 5;         
            if eq special 1;
              return;     
            else eq special 2;
              itemRuleset.getTag woundFactor Tag.WOUND_FACTOR;
              set wounds to_health;
              div wounds woundFactor;
              set to_wound wounds;
              return;
            else and neq special 1 neq special 2;         
              set wounds to_health;
              div wounds 5;
              set to_wound wounds;
              return;
            end;
          end;

Online Meridian

  • Global Moderator
  • Commander
  • *****
  • Posts: 9078
    • View Profile
Re: Script - Limbs hits not inmediately fatal
« Reply #6 on: September 06, 2020, 06:55:52 pm »
Response by Yankes, moved from the other thread: https://openxcom.org/forum/index.php/topic,5245.msg131426.html#msg131426

Code: [Select]
            set lowv 1;
            set higv 5;
            return;
This will quit your script, you need to drop this return otherwise rest of the script will be skipped.
Remember to add `debug_log "I am here!";` to see what exactly the script is doing when you hit something. With this you can debug its behavior.
« Last Edit: September 06, 2020, 07:02:14 pm by Meridian »

Offline cevaralien

  • Captain
  • ***
  • Posts: 96
    • View Profile
Re: Script - Limbs hits not inmediately fatal
« Reply #7 on: September 13, 2020, 04:25:43 pm »
Thanks all! It's is working! I will post the mod soon to share it.

Offline cevaralien

  • Captain
  • ***
  • Posts: 96
    • View Profile
Re: Script - Limbs hits not inmediately fatal
« Reply #8 on: September 18, 2020, 02:42:48 am »
Well... i was testing it and it is working. I want to share it.

First, thanks to Yankees and Meridian for the help, and credits to Kzer-Za for the base script.

The objective of this mod is to enhance the random damage received by the units. By default, we can do "damageAlter" to define a random multiplier from 0 to X percent. I don't like the zero damage.

Another think that i don't like is the range of weapon power (default 0 -200). Why change the raw power of a weapon every shot? To enhance this, i used a fixed power and i changed the random damage after armor. This is equivalent to critical hits.

Now, if the unit receive a headshot, the damage could be a random percentage from 100% of the power after armor to 200%, but if the hit is at torso, the damage could be from 50% to 200%.

The limbs. No one dies imediately if loses a leg or an arm, right? well, in xcom is a reality. With this script, all damage to limbs is reduced, but the wounds are more critical than torso wounds or even head. When the unit receive damage equal or more than 20% of the max health, it will stun and bleed to death, if no one is near with a medikit to save the day, but the health damage would be not so heavy at all.

Feel free to use or enhance it if you like it.

Notice that i have a health cap for humans at 45. You can increase the value of wounds if you are using the base ruleset for soldiers. The use of tags it's better explained at https://openxcom.org/forum/index.php?topic=7310.0

Quote
extended:
  tags:
    RuleItem:
      SPECIAL_WOUND: int
      WOUND_FACTOR: int

  scripts:
    damageUnit:
      - offset: -41
        code: |
          var int wounds;
          var int special;
          var int woundFactor;
          var int ranhealth;
          var int health;
          var int lowv;
          var int higv;
          var ptr RuleItem itemRuleset;
         
          damaging_item.getRuleItem itemRuleset;
          itemRuleset.getTag special Tag.SPECIAL_WOUND; 
                                       
          if ge to_health 5;         
            if eq special 1;
              return;     
            else eq special 2;
              itemRuleset.getTag woundFactor Tag.WOUND_FACTOR;
              set wounds to_health;
              div wounds woundFactor;
              set to_wound wounds;
            else and neq special 1 neq special 2;         
              set wounds to_health;
              div wounds 5;
              set to_wound wounds;
            end;
          end;

          if or eq part BODYPART_LEFTARM eq part BODYPART_RIGHTARM;
            set lowv 1;
            set higv 2;
          else or eq part BODYPART_LEFTLEG eq part BODYPART_RIGHTLEG;
            set lowv 1;
            set higv 2;
          else eq part BODYPART_TORSO;
            set lowv 5;
            set higv 20;
          else eq part BODYPART_HEAD;
            set lowv 10;
            set higv 20;
          end;     
               
          battle_game.randomRange ranhealth lowv higv;
         
          set health to_health;
          mul health ranhealth;
          div health 10;
          set to_health health;
         
armors:
  - &HUMAN_ARMOR
    type: HUMAN_ARMOR
    scripts:
      damageUnit: |
        var int wounds;
        var int health;
        unit.getFatalwoundsTotal wounds;
        unit.getHealthMax health;
        add wounds to_wound;
        if gt wounds 9;
          unit.setStun health;
        end;
        return;

# Civilians
  - type: CIVM_ARMOR
    refNode: *HUMAN_ARMOR
  - type: CIVF_ARMOR
    refNode: *HUMAN_ARMOR

# Soldiers
  - type: STR_NONE_UC
    refNode: *HUMAN_ARMOR
  - type: STR_PERSONAL_ARMOR_UC
    refNode: *HUMAN_ARMOR
  - type: STR_POWER_SUIT_UC
    refNode: *HUMAN_ARMOR
  - type: STR_FLYING_SUIT_UC
    refNode: *HUMAN_ARMOR