Author Topic: [Examples] More Y-Script examples  (Read 11188 times)

Offline memmaker

  • Captain
  • ***
  • Posts: 96
    • View Profile
[Examples] More Y-Script examples
« on: January 07, 2020, 07:52:42 pm »
So, I've been working on some ModScripts for OXCE+ and wanted to share what I have so far.

I am actually aiming for some documentation of the various scripting possibilities but did not yet find the time to write something meaningful. So examples will have to do for know.

I will start of with two of my debug scripts which I used for some damage scaling and understanding how XCOM applies damage. (See attached file debug.rul)

I am using two hooks which are part of the hit and damage calculations: hitUnit and damageUnit.

Both are called in quick succession after each other, every time a unit will potentially receive damage.

The first hook (hitUnit) receives power, part and side and is expected to also return these values. So we have the opportunity to change the power of an attack, the body part which was hit or the side of the armor where the hit connected.

The second hook (damageUnit) has variables for all the damage that is applied after a succesful hit (like to_health, to_armor, to_stun, etc.). Here you can change the amount of damage that is applied to the respective type.

One potential use of this would be a weapon which enables for body part targeting. I have included such an example as bodypart_targeting.rul.

We define three new Tags: AUTO_IS_KNEESHOT, AUTO_IS_ARMSHOT & AUTO_IS_HEADSHOT. When applied to a gun, the scripts will check for that tag on the weapon and apply fatal wounds to the bodypart which has been targeted.

(My meal is getting cold, so I will add more information later..;)
« Last Edit: February 12, 2023, 02:54:56 pm by Meridian »

Offline memmaker

  • Captain
  • ***
  • Posts: 96
    • View Profile
Re: More ModScript examples
« Reply #1 on: January 16, 2020, 11:04:11 pm »
So, I guess this is the right place to continue posting about my various modscripting examples that fit nowhere else. Let's start off with a XCOM2 style mimic beacon:

Code: [Select]
items:
  - type: STR_MIMIC_BEACON
    size: 0.1
    costBuy: 10000 # cannot buy
    costSell: 8000
    weight: 3
    bigSprite: 55
    floorSprite: 72
    power: 0
    damageType: 0
    damageAlter:
      FixRadius: 0
    battleType: 4
    accuracyThrow: 100
    costPrime:
      time: 45
    costUnprime:
      time: 5
    costThrow:
      time: 5
    primeActionName: STR_MIMIC_PRIME_ACTION
    primeActionMessage: STR_MIMIC_PRIME_MESSAGE
    unprimeActionName: STR_MIMIC_UNPRIME_ACTION
    unprimeActionMessage: STR_MIMIC_UNPRIME_MESSAGE
    recover: true
    spawnUnit: STR_SOLDIER_MIMIC # Default empty meaning don't spawn a unit, when a valid unit (defined in the units: ruleset) is defined here it will be spawned by this item.
    spawnUnitFaction: 2 # Default -1 meaning the spawned unit will be the same faction as the unit using/firing the item, this defines which faction gets the new unit:
                         #   -1: Same faction as item user
                         #    0: Player faction
                         #    1: Enemy faction
                         #    2: Civilian faction

units:
  - type: STR_SOLDIER_MIMIC
    race: STR_SOLDIER_MIMIC
    stats:
      tu: 0
      stamina: 0
      health: 45
      bravery: 110
      reactions: 0
      firing: 0
      throwing: 0
      strength: 0
      psiStrength: 100
      psiSkill: 0
      melee: 0
    armor: MIMIC_ARMOR
    standHeight: 16
    kneelHeight: 16
    value: 0
    deathSound: 23
    moveSound: 14
    energyRecovery: 50
    aggression: 0
    capturable: false
    moraleLossWhenKilled: 0
   

extended:
  tags:
    BattleUnit:
      MIMIC_COUNTER: int
    RuleArmor:
      IS_MIMIC: int

armors:
  - type: MIMIC_ARMOR
    tags:
      IS_MIMIC: 1
    units: [STR_SOLDIER_MIMIC]
    corpseBattle:
      - STR_CORPSE
    allowsMoving: false
    createsMeleeThreat: false
    spriteSheet: XCOM_0.PCK
    spriteInv: MAN_0
    spriteFaceGroup: 6
    spriteFaceColor: [96, 96, 96, 96, 160, 160, 163, 163] #M0 F0 M1 F1 M2 F2 M3 F3
    spriteHairGroup: 9
    spriteHairColor: [144, 144, 164, 164, 245, 245, 166, 166] #M0 F0 M1 F1 M2 F2 M3 F3
    storeItem: STR_NONE
    frontArmor: 12
    sideArmor: 12
    rearArmor: 12
    underArmor: 12
    damageModifier:
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
      - 1.0
    loftempsSet: [ 3 ]
    scripts:
      createUnit: |
        var ptr RuleArmor armor_rule;
        var int is_mimic;
        debug_log "Mimic Beacon Code running";
        unit.getRuleArmor armor_rule; 
        armor_rule.getTag is_mimic Tag.IS_MIMIC;

        if gt is_mimic 0;  # we have a mimic
          debug_log "Mimic Beacon Spawned";
          unit.setTag Tag.MIMIC_COUNTER 2;
        end;
        return;
      recolorUnitSprite: |
        var int color;
        var int temp;
        get_color color new_pixel;
       
        set temp anim_frame;
        wavegen_tri temp 16 16 15;
        mul temp -1;
        add temp 8;
        add_shade new_pixel temp;

        return new_pixel;
      newTurnUnit: |
        var ptr RuleArmor armor_rule;
        var int counter;
        var int is_mimic;

        debug_log "Mimic Beacon Code On New Turn";
        if eq side 1; # on the alien turns
          unit.getRuleArmor armor_rule; 
          armor_rule.getTag is_mimic Tag.IS_MIMIC;

          if gt is_mimic 0;  # we have a mimic
            unit.getTag counter Tag.MIMIC_COUNTER;

            sub counter 1;
            debug_log "Mimic Counter: " counter;

            if gt counter 0;
              unit.setTag Tag.MIMIC_COUNTER counter;
            end;
            if eq counter 0; # mimic beacon timer is over
              unit.setHealth 0;      # kill the mimic
              debug_log "Mimic removed";
            end;
          end;
        end;
        return;

extraStrings:
  - type: en-US
    strings:
      STR_MIMIC_BEACON: Mimic Beacon
      STR_MIMIC_ARMOR: Mimic Armor
      STR_SOLDIER_MIMIC: Deployed Mimic Beacon
      STR_MIMIC_PRIME_ACTION: Activate Beacon
      STR_MIMIC_PRIME_MESSAGE: Mimic Beacon activated
      STR_MIMIC_UNPRIME_ACTION: Deactivate Beacon
      STR_MIMIC_UNPRIME_MESSAGE: Mimic Beacon deactivated

Offline memmaker

  • Captain
  • ***
  • Posts: 96
    • View Profile
Re: More ModScript examples
« Reply #2 on: January 16, 2020, 11:12:15 pm »
Here I will post some scripts I use to fine-tune the game experience to my liking
1. Alien Exposer
This one negates the vision advantage of the aliens and makes XCOM units see as good as them.
2. Accuracy Nerfer (Adjuster ;)
Allows global changes to the accuracy of all alien units. I use this if I think the aliens are aiming a bit too good  ;D Of course it can be used to make the Game even harder by just globally increasing the accuracy of your foes.
3. Power Nerfer
Same as the above. Allows global attack power adjustment of the enemies. Could also be used to make them hit harder..
4. Critical hits. Code for simple critical hits. Might still be a bit finicky. I use this because I play with with a very low damageRange.

Code: [Select]
extended:
  tags:
    BattleUnit:
      CRITICAL_STATE: int
    RuleItem:
      CRIT_CHANCE: int
      CRIT_DAMAGE: int
  scripts:
    visibilityUnit:
      - offset: -1 # alien exposer
        code: |
          var ptr RuleArmor armor_rule;
          var ptr RuleSoldier soldier_rule;
         
          observer_unit.getRuleSoldier soldier_rule; 

          if neq soldier_rule null;  # we have an xcom unit as observer
            if le distance distance_max;
              set current_visibility 100; # expose enemy unit if in max viewing dist (like the aliens..)
            end;
          end;
          return current_visibility visibility_mode;
    createUnit:
      - offset: -1 # accuracy nerfer
        code: |
          var ptr RuleSoldier soldier_rule;
          var int id;
          var int firing;
          var int adjustment;
         
          set adjustment 90; # 90% accuracy

          unit.getId id;
          unit.getRuleSoldier soldier_rule; 

          if eq soldier_rule null;  # we have an alien unit
            debug_log "Adjusting accuracy of unit" id;
            unit.Stats.getFiring firing;
            debug_log " - from" firing;
            muldiv firing adjustment 100;
            unit.Stats.setFiring firing;
            debug_log " - to" firing;
          end;
          return;
    hitUnit:
      - offset: -1 # power nerfer
        code: |
          var ptr RuleSoldier soldier_rule;
          var int id;
          var int firing;
          var int adjustment;
         
          set adjustment 70; # 70% power

          unit.getId id;
          unit.getRuleSoldier soldier_rule; 

          if neq soldier_rule null;  # we have an xcom unit
            debug_log "Adjusting power of hit against xcom unit" id;
            debug_log " - from" power;
            muldiv power adjustment 100;
            debug_log " - to" power;
          end;
          return power part side;
    damageUnit:
      - offset: -1 # critical hits (balancing for lower damageRange)
        code: |
          var ptr RuleItem item_rule;
          var int weapon_chance;
          var int unit_chance;
          var int chance;
          var int crit_factor;  # 100 = 100% additional damage of original power
          var int crit_damage;

          weapon_item.getRuleItem item_rule;

          unit.getTag unit_chance Tag.CRITICAL_STATE;
          item_rule.getTag weapon_chance Tag.CRIT_CHANCE;
          item_rule.getTag crit_factor Tag.CRIT_DAMAGE;

          add unit_chance weapon_chance;

          if eq unit_chance 0;
            set unit_chance 5;  # base chance of 5% for everybody
          end;

          if eq crit_factor 0;
            set crit_factor 20; # 20% additional damage as baseline for everybody on crit
          end;

          battle_game.randomChance unit_chance; # will set unit_chance to 1 on success
          if gt unit_chance 0;
            set crit_damage orig_power;
            muldiv crit_damage crit_factor 100;
            add to_health crit_damage;
            debug_log "CRITICAL HIT:" crit_damage;
          end;
          return;

Offline memmaker

  • Captain
  • ***
  • Posts: 96
    • View Profile
Re: More ModScript examples
« Reply #3 on: February 16, 2020, 12:37:22 am »
I will put this here, since I do not know where to put this otherwise ;)

Code: [Select]
# weapon proficicency system - by memmaker
#
# how to use: flag weapons with WEAPON_TYPE tags
# eg. You decide all shotguns are weapon type 3
# Then you would have something like this:
# items:
#   - type: STR_SHOTGUN
#     tags:
#       WEAPON_TYPE: 4 # shotguns
#   - type: STR_ALLOY_SHOTGUN
#     tags:
#       WEAPON_TYPE: 4 # shotguns
#
# You can decide which WEAPON_TYPE entry to use by using this table:
#
# Type 1 -> WEAPON_TYPE: 1
# Type 2 -> WEAPON_TYPE: 2
# Type 3 -> WEAPON_TYPE: 4
# Type 4 -> WEAPON_TYPE: 8
# Type 5 -> WEAPON_TYPE: 16
# Type 6 -> WEAPON_TYPE: 32
# Type 7 -> WEAPON_TYPE: 64
# Type 8 -> WEAPON_TYPE: 128
#
# NOTE1: The current script only allows for a maximum of 8 different weapon types. Could be expanded.
#
# All hits with weapons which are tagged with WEAPON_TYPE will be tracked.
# After the hit_limit is reached (search for "set hit_limit" if you want change it),
# the soldier is awarded the proficiency with this weapon type.
#
# A soldier's accuracy with a proficient weapon is increased (defined at "set accuracy_bonus").
# IMPORTANT: If a soldier has weapons in both hands the bonus of the right hand weapon is applied.
#            The technical reason for this is, that we do not know for which item an accuracy bonus is being calculated.
#            Also, having a proficient weapon equipped also boosts PSI accuracy, since the bonus is not bound
#            to a specific action.

extraStrings:
  - type: en-US
    strings:
      STR_PROFICIENT_MESSAGE_TYPE1: "Soldier became proficient with TYPE1"
      STR_PROFICIENT_MESSAGE_TYPE2: "Soldier became proficient with TYPE2"
      STR_PROFICIENT_MESSAGE_TYPE3: "Soldier became proficient with TYPE3"
      STR_PROFICIENT_MESSAGE_TYPE4: "Soldier became proficient with TYPE4"
      STR_PROFICIENT_MESSAGE_TYPE5: "Soldier became proficient with TYPE5"
      STR_PROFICIENT_MESSAGE_TYPE6: "Soldier became proficient with TYPE6"
      STR_PROFICIENT_MESSAGE_TYPE7: "Soldier became proficient with TYPE7"
      STR_PROFICIENT_MESSAGE_TYPE8: "Soldier became proficient with TYPE8"
   
extended:
  tags:
    GeoscapeSoldier:
      WEAPON_PROFICIENCY_FLAGS: int # 8 bits of flags, one for each weapon type
      EXP_WITH_TYPE1: int   # tracks the hits a soldier made with these weapon types
      EXP_WITH_TYPE2: int
      EXP_WITH_TYPE3: int
      EXP_WITH_TYPE4: int
      EXP_WITH_TYPE5: int
      EXP_WITH_TYPE6: int
      EXP_WITH_TYPE7: int
      EXP_WITH_TYPE8: int
    BattleUnit:
      HITS_WITH_TYPE1: int   # tracks the hits a unit makes with the specific weapon type during a mission
      HITS_WITH_TYPE2: int
      HITS_WITH_TYPE3: int
      HITS_WITH_TYPE4: int
      HITS_WITH_TYPE5: int
      HITS_WITH_TYPE6: int
      HITS_WITH_TYPE7: int
      HITS_WITH_TYPE8: int
    RuleItem:
      WEAPON_TYPE: int # one of, 0 = none, 1 = type 1, 2 = type 2, 4 = type 3, 8 = type 4, 16, 32, 64, 128
  scripts:
    hitUnit:
      - offset: 66   # get weapon type, track hit for that weapon type on unit
        code: |
          var ptr RuleItem item_rule;
          var int weapon_type;
          var int temp;
          var int hit_limit;
          var int exp;
          var int wp_flags;
          var ptre GeoscapeSoldier soldier;
          var ptr RuleSoldier soldier_rule; # replace with getFaction code, when available
         
          unit.getRuleSoldier soldier_rule;

          set hit_limit 30; # award weapon proficiency after this number of hits..

          if neq soldier_rule null; # is xcom unit
            unit.getGeoscapeSoldier soldier;
           
            damaging_item.getRuleItem item_rule;
            item_rule.getTag weapon_type Tag.WEAPON_TYPE;

            if eq weapon_type 1;
              soldier.getTag exp Tag.EXP_WITH_TYPE1;
              unit.getTag temp Tag.HITS_WITH_TYPE1;
              add temp 1;
              unit.setTag Tag.HITS_WITH_TYPE1 temp;
              add exp temp;
              if ge exp hit_limit;
                soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;
                bit_or wp_flags weapon_type;
                soldier.setTag Tag.WEAPON_PROFICIENCY_FLAGS wp_flags;
                battle_game.flashMessage "STR_PROFICIENT_MESSAGE_TYPE1";
              end;
            else eq weapon_type 2;
              soldier.getTag exp Tag.EXP_WITH_TYPE2;
              unit.getTag temp Tag.HITS_WITH_TYPE2;
              add temp 1;
              unit.setTag Tag.HITS_WITH_TYPE2 temp;
              add exp temp;
              if ge exp hit_limit;
                soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;
                bit_or wp_flags weapon_type;
                soldier.setTag Tag.WEAPON_PROFICIENCY_FLAGS wp_flags;
                battle_game.flashMessage "STR_PROFICIENT_MESSAGE_TYPE2";
              end;
            else eq weapon_type 4;
              soldier.getTag exp Tag.EXP_WITH_TYPE3;
              unit.getTag temp Tag.HITS_WITH_TYPE3;
              add temp 1;
              unit.setTag Tag.HITS_WITH_TYPE3 temp;
              add exp temp;
              if ge exp hit_limit;
                soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;
                bit_or wp_flags weapon_type;
                soldier.setTag Tag.WEAPON_PROFICIENCY_FLAGS wp_flags;
                battle_game.flashMessage "STR_PROFICIENT_MESSAGE_TYPE3";
              end;
            else eq weapon_type 8;
              soldier.getTag exp Tag.EXP_WITH_TYPE4;
              unit.getTag temp Tag.HITS_WITH_TYPE4;
              add temp 1;
              unit.setTag Tag.HITS_WITH_TYPE4 temp;
              add exp temp;
              if ge exp hit_limit;
                soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;
                bit_or wp_flags weapon_type;
                soldier.setTag Tag.WEAPON_PROFICIENCY_FLAGS wp_flags;
                battle_game.flashMessage "STR_PROFICIENT_MESSAGE_TYPE4";
              end;
            else eq weapon_type 16;
              soldier.getTag exp Tag.EXP_WITH_TYPE5;
              unit.getTag temp Tag.HITS_WITH_TYPE5;
              add temp 1;
              unit.setTag Tag.HITS_WITH_TYPE5 temp;
              add exp temp;
              if ge exp hit_limit;
                soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;
                bit_or wp_flags weapon_type;
                soldier.setTag Tag.WEAPON_PROFICIENCY_FLAGS wp_flags;
                battle_game.flashMessage "STR_PROFICIENT_MESSAGE_TYPE5";
              end;
            else eq weapon_type 32;
              soldier.getTag exp Tag.EXP_WITH_TYPE6;
              unit.getTag temp Tag.HITS_WITH_TYPE6;
              add temp 1;
              unit.setTag Tag.HITS_WITH_TYPE6 temp;
              add exp temp;
              if ge exp hit_limit;
                soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;
                bit_or wp_flags weapon_type;
                soldier.setTag Tag.WEAPON_PROFICIENCY_FLAGS wp_flags;
                battle_game.flashMessage "STR_PROFICIENT_MESSAGE_TYPE6";
              end;
            else eq weapon_type 64;
              soldier.getTag exp Tag.EXP_WITH_TYPE7;
              unit.getTag temp Tag.HITS_WITH_TYPE7;
              add temp 1;
              unit.setTag Tag.HITS_WITH_TYPE7 temp;
              add exp temp;
              if ge exp hit_limit;
                soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;
                bit_or wp_flags weapon_type;
                soldier.setTag Tag.WEAPON_PROFICIENCY_FLAGS wp_flags;
                battle_game.flashMessage "STR_PROFICIENT_MESSAGE_TYPE7";
              end;
            else eq weapon_type 128;
              soldier.getTag exp Tag.EXP_WITH_TYPE8;
              unit.getTag temp Tag.HITS_WITH_TYPE8;
              add temp 1;
              unit.setTag Tag.HITS_WITH_TYPE8 temp;
              add exp temp;
              if ge exp hit_limit;
                soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;
                bit_or wp_flags weapon_type;
                soldier.setTag Tag.WEAPON_PROFICIENCY_FLAGS wp_flags;
                battle_game.flashMessage "STR_PROFICIENT_MESSAGE_TYPE8";
              end;
            end;
          end;
          return power part side;
    accuracyMultiplierBonusStats:
      - offset: 66   # check if unit is proficient with current weapon type, boost accuracy
        code: |
          var ptr RuleItem item_rule;
          var ptr BattleItem weapon;
          var int weapon_type;
          var int temp;
          var int wp_flags;
          var ptr GeoscapeSoldier soldier;
          var int accuracy_bonus;
          var ptr RuleSoldier soldier_rule; # replace with getFaction code, when available

          set accuracy_bonus 10; # adjusts the bonus accuracy for handling proficient weapons

          unit.getRuleSoldier soldier_rule;

          if neq soldier_rule null; # is xcom unit
            unit.getGeoscapeSoldier soldier;
            soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;

            unit.getRightHandWeapon weapon;
            if eq weapon null;
              unit.getLeftHandWeapon weapon;
            end;
            if neq weapon null;
              weapon.getRuleItem item_rule;
              item_rule.getTag weapon_type Tag.WEAPON_TYPE;

              bit_and wp_flags weapon_type;

              if neq wp_flags 0;
                # soldier is proficient in this weapon type
                add bonus accuracy_bonus;
                debug_log "Weapon proficiency bonus added: " unit weapon;
              end;
            end;
          end;
          return bonus;
    meleeMultiplierBonusStats:
      - offset: 66   # check if unit is proficient with current weapon type, boost accuracy
        code: |
          var ptr RuleItem item_rule;
          var ptr BattleItem weapon;
          var int weapon_type;
          var int temp;
          var int wp_flags;
          var ptr GeoscapeSoldier soldier;
          var int accuracy_bonus;
          var ptr RuleSoldier soldier_rule; # replace with getFaction code, when available

          set accuracy_bonus 10; # adjusts the bonus accuracy for handling proficient weapons

          unit.getRuleSoldier soldier_rule;

          if neq soldier_rule null; # is xcom unit
            unit.getGeoscapeSoldier soldier;
            soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;

            unit.getRightHandWeapon weapon;
            if eq weapon null;
              unit.getLeftHandWeapon weapon;
            end;
            if neq weapon null;
              weapon.getRuleItem item_rule;
              item_rule.getTag weapon_type Tag.WEAPON_TYPE;

              bit_and wp_flags weapon_type;

              if neq wp_flags 0;
                # soldier is proficient in this weapon type
                add bonus accuracy_bonus;
                debug_log "Weapon proficiency bonus added: " unit weapon;
              end;
            end;
          end;
          return bonus;   
    throwMultiplierBonusStats:
      - offset: 66   # check if unit is proficient with current weapon type, boost accuracy
        code: |
          var ptr RuleItem item_rule;
          var ptr BattleItem weapon;
          var int weapon_type;
          var int temp;
          var int wp_flags;
          var ptr GeoscapeSoldier soldier;
          var int accuracy_bonus;
          var ptr RuleSoldier soldier_rule; # replace with getFaction code, when available

          set accuracy_bonus 10; # adjusts the bonus accuracy for handling proficient weapons

          unit.getRuleSoldier soldier_rule;

          if neq soldier_rule null; # is xcom unit
            unit.getGeoscapeSoldier soldier;
            soldier.getTag wp_flags Tag.WEAPON_PROFICIENCY_FLAGS;

            unit.getRightHandWeapon weapon;
            if eq weapon null;
              unit.getLeftHandWeapon weapon;
            end;
            if neq weapon null;
              weapon.getRuleItem item_rule;
              item_rule.getTag weapon_type Tag.WEAPON_TYPE;

              bit_and wp_flags weapon_type;

              if neq wp_flags 0;
                # soldier is proficient in this weapon type
                add bonus accuracy_bonus;
                debug_log "Weapon proficiency bonus added: " unit weapon;
              end;
            end;
          end;
          return bonus;
    returnFromMissionUnit:
      - offset: 66   # transfer hits from battlescape unit to geoscape soldier, award weapon proficiency when limit is hit
        code: |
          var int hits;
          var int exp;

          unit.getTag hits Tag.HITS_WITH_TYPE1;
          soldier.getTag exp Tag.EXP_WITH_TYPE1;
          add exp hits;
          soldier.setTag Tag.EXP_WITH_TYPE1 exp;

          unit.getTag hits Tag.HITS_WITH_TYPE2;
          soldier.getTag exp Tag.EXP_WITH_TYPE2;
          add exp hits;
          soldier.setTag Tag.EXP_WITH_TYPE2 exp;

          unit.getTag hits Tag.HITS_WITH_TYPE3;
          soldier.getTag exp Tag.EXP_WITH_TYPE3;
          add exp hits;
          soldier.setTag Tag.EXP_WITH_TYPE3 exp;

          unit.getTag hits Tag.HITS_WITH_TYPE4;
          soldier.getTag exp Tag.EXP_WITH_TYPE4;
          add exp hits;
          soldier.setTag Tag.EXP_WITH_TYPE4 exp;

          unit.getTag hits Tag.HITS_WITH_TYPE5;
          soldier.getTag exp Tag.EXP_WITH_TYPE5;
          add exp hits;
          soldier.setTag Tag.EXP_WITH_TYPE5 exp;

          unit.getTag hits Tag.HITS_WITH_TYPE6;
          soldier.getTag exp Tag.EXP_WITH_TYPE6;
          add exp hits;
          soldier.setTag Tag.EXP_WITH_TYPE6 exp;

          unit.getTag hits Tag.HITS_WITH_TYPE7;
          soldier.getTag exp Tag.EXP_WITH_TYPE7;
          add exp hits;
          soldier.setTag Tag.EXP_WITH_TYPE7 exp;

          unit.getTag hits Tag.HITS_WITH_TYPE8;
          soldier.getTag exp Tag.EXP_WITH_TYPE8;
          add exp hits;
          soldier.setTag Tag.EXP_WITH_TYPE8 exp;

          return;

Offline KingMob4313

  • Commander
  • *****
  • Posts: 543
  • Never let me down again.
    • View Profile
    • Mod Hub for Equal Terms 2.0
Re: More ModScript examples
« Reply #4 on: June 10, 2020, 05:54:07 am »
I will put this here, since I do not know where to put this otherwise ;)


This is blowing my mind, thanks for posting this.

Offline KingMob4313

  • Commander
  • *****
  • Posts: 543
  • Never let me down again.
    • View Profile
    • Mod Hub for Equal Terms 2.0
Re: More ModScript examples
« Reply #5 on: June 23, 2020, 11:19:54 pm »
Here I will post some scripts I use to fine-tune the game experience to my liking
1. Alien Exposer
This one negates the vision advantage of the aliens and makes XCOM units see as good as them.
2. Accuracy Nerfer (Adjuster ;)
Allows global changes to the accuracy of all alien units. I use this if I think the aliens are aiming a bit too good  ;D Of course it can be used to make the Game even harder by just globally increasing the accuracy of your foes.
3. Power Nerfer
Same as the above. Allows global attack power adjustment of the enemies. Could also be used to make them hit harder..
4. Critical hits. Code for simple critical hits. Might still be a bit finicky. I use this because I play with with a very low damageRange.

Code: [Select]
extended:
  tags:
    BattleUnit:
      CRITICAL_STATE: int
    RuleItem:
      CRIT_CHANCE: int
      CRIT_DAMAGE: int
  scripts:
    visibilityUnit:
      - offset: -1 # alien exposer
        code: |
          var ptr RuleArmor armor_rule;
          var ptr RuleSoldier soldier_rule;
         
          observer_unit.getRuleSoldier soldier_rule; 

          if neq soldier_rule null;  # we have an xcom unit as observer
            if le distance distance_max;
              set current_visibility 100; # expose enemy unit if in max viewing dist (like the aliens..)
            end;
          end;
          return current_visibility visibility_mode;
    createUnit:
      - offset: -1 # accuracy nerfer
        code: |
          var ptr RuleSoldier soldier_rule;
          var int id;
          var int firing;
          var int adjustment;
         
          set adjustment 90; # 90% accuracy

          unit.getId id;
          unit.getRuleSoldier soldier_rule; 

          if eq soldier_rule null;  # we have an alien unit
            debug_log "Adjusting accuracy of unit" id;
            unit.Stats.getFiring firing;
            debug_log " - from" firing;
            muldiv firing adjustment 100;
            unit.Stats.setFiring firing;
            debug_log " - to" firing;
          end;
          return;
    hitUnit:
      - offset: -1 # power nerfer
        code: |
          var ptr RuleSoldier soldier_rule;
          var int id;
          var int firing;
          var int adjustment;
         
          set adjustment 70; # 70% power

          unit.getId id;
          unit.getRuleSoldier soldier_rule; 

          if neq soldier_rule null;  # we have an xcom unit
            debug_log "Adjusting power of hit against xcom unit" id;
            debug_log " - from" power;
            muldiv power adjustment 100;
            debug_log " - to" power;
          end;
          return power part side;
    damageUnit:
      - offset: -1 # critical hits (balancing for lower damageRange)
        code: |
          var ptr RuleItem item_rule;
          var int weapon_chance;
          var int unit_chance;
          var int chance;
          var int crit_factor;  # 100 = 100% additional damage of original power
          var int crit_damage;

          weapon_item.getRuleItem item_rule;

          unit.getTag unit_chance Tag.CRITICAL_STATE;
          item_rule.getTag weapon_chance Tag.CRIT_CHANCE;
          item_rule.getTag crit_factor Tag.CRIT_DAMAGE;

          add unit_chance weapon_chance;

          if eq unit_chance 0;
            set unit_chance 5;  # base chance of 5% for everybody
          end;

          if eq crit_factor 0;
            set crit_factor 20; # 20% additional damage as baseline for everybody on crit
          end;

          battle_game.randomChance unit_chance; # will set unit_chance to 1 on success
          if gt unit_chance 0;
            set crit_damage orig_power;
            muldiv crit_damage crit_factor 100;
            add to_health crit_damage;
            debug_log "CRITICAL HIT:" crit_damage;
          end;
          return;

 Curiously, is there a way to make critical hits negate a portion of armor instead?

Offline Yankes

  • Global Moderator
  • Commander
  • *****
  • Posts: 3350
    • View Profile
Re: More ModScript examples
« Reply #6 on: June 24, 2020, 02:30:34 am »
It should be possible, it would need some code to "revert" part done in engine, but most needed variables are avaialbe in scripts.

[ps]
One big drawback I find, `ArmorEffectiveness` is not exposed to scripts, this mean you need guess what values was.
Probably easiest way would be ignore complete current behavior of engine and write your own damage mechanism :D
I will look in this week if I can add details of damage type to scripts.
« Last Edit: June 24, 2020, 02:38:31 am by Yankes »

Offline KingMob4313

  • Commander
  • *****
  • Posts: 543
  • Never let me down again.
    • View Profile
    • Mod Hub for Equal Terms 2.0
Re: More ModScript examples
« Reply #7 on: June 24, 2020, 05:30:25 am »
It should be possible, it would need some code to "revert" part done in engine, but most needed variables are avaialbe in scripts.

[ps]
One big drawback I find, `ArmorEffectiveness` is not exposed to scripts, this mean you need guess what values was.
Probably easiest way would be ignore complete current behavior of engine and write your own damage mechanism :D
I will look in this week if I can add details of damage type to scripts.

While it's not exposed, can you still set the armor or armor effectiveness to 0?

Thanks for peeking into it. I really need to look into the code deeper and see about if I can create more hooks. An inventory iterator would be nice like getInventoryArray()

Offline Yankes

  • Global Moderator
  • Commander
  • *****
  • Posts: 3350
    • View Profile
Re: More ModScript examples
« Reply #8 on: June 24, 2020, 11:21:05 am »
While it's not exposed, can you still set the armor or armor effectiveness to 0?

Thanks for peeking into it. I really need to look into the code deeper and see about if I can create more hooks. An inventory iterator would be nice like getInventoryArray()

Yes, this is one option, and then in script (`hitUnit`) manually subtract armor value using your own logic. Probaby better is alter effectiveness  as is not avaiable to scripts right now (unit armor is).

Loops are on my TODO, this is bit tricky because I need made some refactors to make them easy to use and safe (I would prefer that scripts can't hang whole game).

Online Finnik

  • Commander
  • *****
  • Posts: 508
  • Finnik#0257
    • View Profile
Re: More ModScript examples
« Reply #9 on: July 07, 2020, 05:11:53 pm »
I've always wondered how noticeably y-scripts can affect game performance? After all, some are called quite often (each frame). Are there any recommendations about this, restrictions? Say, if my y-script will consist of 5 thousand lines of calculation code? Or 10? Could there be a difference between hooks?

Offline Yankes

  • Global Moderator
  • Commander
  • *****
  • Posts: 3350
    • View Profile
Re: More ModScript examples
« Reply #10 on: July 07, 2020, 07:04:20 pm »
y-scripts was designed to DRAW graphic (or at least alter pixels it in arbitrarily way).
Last time I check budget was around 100M script operations per second or something this magnitude.
More important question is what you script do exactly, because some functions could do lot of things (like getting rules by name or finding item in inventory).

Online Finnik

  • Commander
  • *****
  • Posts: 508
  • Finnik#0257
    • View Profile
Re: More ModScript examples
« Reply #11 on: July 07, 2020, 07:15:56 pm »
For now, I was only using tag loads, things like getting an attacker unit or damaging item. Now sure how expensive those operations are.

Offline Yankes

  • Global Moderator
  • Commander
  • *****
  • Posts: 3350
    • View Profile
Re: More ModScript examples
« Reply #12 on: July 07, 2020, 08:03:10 pm »
Most of them are relative cheap. And for overall performance, check how often given hook is call, if you do not fill up debug output limit then you should not worry about performance even if you have complex script.

Offline KingMob4313

  • Commander
  • *****
  • Posts: 543
  • Never let me down again.
    • View Profile
    • Mod Hub for Equal Terms 2.0
Re: More ModScript examples
« Reply #13 on: July 07, 2020, 09:33:12 pm »

Yes, this is one option, and then in script (`hitUnit`) manually subtract armor value using your own logic. Probaby better is alter effectiveness  as is not avaiable to scripts right now (unit armor is).

Loops are on my TODO, this is bit tricky because I need made some refactors to make them easy to use and safe (I would prefer that scripts can't hang whole game).

Set Armor effectiveness to 0 or .25 or whatever fits. Got ya.

Offline KingMob4313

  • Commander
  • *****
  • Posts: 543
  • Never let me down again.
    • View Profile
    • Mod Hub for Equal Terms 2.0
Re: More ModScript examples
« Reply #14 on: July 14, 2020, 12:56:52 am »
Here I will post some scripts I use to fine-tune the game experience to my liking

4. Critical hits. Code for simple critical hits. Might still be a bit finicky. I use this because I play with with a very low damageRange.

I've been playing around with the critical hit code, combining it to the "turn red for one frame" code and a message to show critical hits.
Code: [Select]
extraStrings:
  - type: en-US
    strings:
      STR_CRITICAL_HIT_MESSAGE: "Critical hit!"
extended:
  tags:
    BattleUnit:
      CRITICAL_STATE: int
      LAST_HIT_FRAME: int
    RuleItem:
      CRIT_CHANCE: int
      CRIT_DAMAGE: int
  scripts:
    # Future Script for luck
    #
    # Script for Criticals
    damageUnit:
      - offset: -1 # critical hits (balancing for lower damageRange)
        code: |
          var ptr RuleItem item_rule;
          var int weapon_chance;
          var int unit_chance;
          var int chance;
          var int crit_factor;  # 100 = 100% additional damage of original power
          var int crit_damage;
          var int temp;

          weapon_item.getRuleItem item_rule;

          unit.getTag unit_chance Tag.CRITICAL_STATE;
          item_rule.getTag weapon_chance Tag.CRIT_CHANCE;
          item_rule.getTag crit_factor Tag.CRIT_DAMAGE;

          add unit_chance weapon_chance;

          if eq unit_chance 0;
            set unit_chance 5;  # base chance of 5% for everybody
          end;

          if eq crit_factor 0;
            set crit_factor 100; # 100% additional damage as baseline for everybody on crit
          end;

          battle_game.randomChance unit_chance; # will set unit_chance to 1 on success
          if gt unit_chance 0;
            set crit_damage orig_power;
            muldiv crit_damage crit_factor 100;
            add to_health crit_damage;
            # Flash RED when crit hit
            # NEED TO BUILD IN A CHECK TO SEE IF ITS WEAPON DAMAGE FFS
            battle_game.flashMessage "STR_CRITICAL_HIT_MESSAGE";
            battle_game.getAnimFrame temp;
            unit.setTag Tag.LAST_HIT_FRAME temp;
            debug_log "CRITICAL HIT:" crit_damage;
          end;
          return;

    recolorUnitSprite:
      - offset: 10
        code: |
          var int temp;
         
          unit.getTag temp Tag.LAST_HIT_FRAME;
          if neq temp 0;
            sub temp anim_frame;
            if gt temp -3; #only 3 frames after hit have changed color
              set_color new_pixel 2; #red color
            end;
          end;
         
          return new_pixel;

I need to figure out
1) How to connect it to shoot script, since I'd love to have it as 5% for snap shots, 1% for auto shots and 10% for aimed shots.
   a) Also I need it to stop declaring critical hits for smoke
2) How to change the code so that it leaves off a damage roll and just gives the base damage number (100%) and then reduces armor effectiveness to 0.25

But I haven't been playing with it all that much yet. Too busy streaming.

Thanks for posting this up.