OpenXcom Forum

Modding => OXCE Support => OpenXcom Extended => OXCE Support Y-scripts => Topic started by: Yankes on January 29, 2017, 05:11:23 pm

Title: [Documentation] OXCE Y-Script examples
Post by: Yankes on January 29, 2017, 05:11:23 pm
Parrot animation:
Code: [Select]
armors:
  - type: PARROT_ARMOR
    drawingRoutine: 4
    scripts:
      selectUnitSprite: |
        #this script will always run move animation of unit.
        var int temp;
        var int walking;
        unit.isWalking walking;
        if eq walking 0;
          unit.getId temp;
          offsetmod temp 11 0 8; #desync animation of different units
          add temp anim_frame;
          wavegen_saw temp 8 8 7;
          mul sprite_offset 8;
          add sprite_offset 8;
          add sprite_offset temp;
          set sprite_index sprite_offset;
        else;
          add sprite_index sprite_offset;
        end;
        return sprite_index;

2x2 unit animation:
Code: [Select]
armors:
  - type: TANK_ARMOR
    drawingRoutine: 20
    movementType: 1
    spriteSheet: FDEAMON.PCK
    scripts:
      selectUnitSprite: |
        var int temp;
        var int walking;
        var int floating;
        unit.isWalking walking;
        unit.isFloating floating;
        if and eq walking 0 eq floating 1;
          unit.getId temp;
          offsetmod temp 11 0 8; #desync animation of different units
          add temp anim_frame;
          wavegen_saw temp 4 4 4;
          add sprite_offset 1;
          add sprite_offset temp;
          add sprite_index sprite_offset;
        else;
          add sprite_index sprite_offset;
        end;
        return sprite_index;

Animation for Floater
Code: [Select]
  - type: FLOATER_ARMOR0
    drawingRoutine: 1
    scripts:
      selectUnitSprite: |
        var int temp;
        var int walking;
        unit.isWalking walking;
        if and eq walking 0 eq blit_part BODYPART_TORSO;
          unit.getId temp;
          offsetmod temp 11 0 8; #desync animation of different units
          add temp anim_frame;
          wavegen_saw temp 5 5 5;
         
         
          mul sprite_offset 5; # `drawingRoutine: 1` have blocks of 5 frames per direction, we convert `0,1,2,...` to `0,5,10,...` offsets
          add sprite_offset temp;
         
          add sprite_index 8; #moving animations frames starts after 8 standing one
          add sprite_index sprite_offset;
        else;
          add sprite_index sprite_offset;
        end;
        return sprite_index;

Hit confirm by red "flash":
Code: [Select]
extended:
  tags:
    BattleUnit:
      LAST_HIT_FRAME: int

  scripts:
    damageUnit:
      - offset: 10
        code: |
          var int temp;
          battle_game.getAnimFrame temp;
          unit.setTag Tag.LAST_HIT_FRAME temp;
          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;
         
Title: Re: OXCE Script examples
Post by: ohartenstein23 on January 31, 2017, 08:17:14 pm
Changing a weapon's sprites based on the ammunition loaded:
Code: [Select]
extended:
  tags: # Remember to add these tags to the same file as items ruleset
    RuleItem:
      ALLOW_AMMO_TO_RESPRITE: int
      NEW_BIGOB_FOR_WEAPON: int
      NEW_FLOOROB_FOR_WEAPON: int
      NEW_HANDOB_FOR_WEAPON: int
      CURRENT_MOD_OFFSET: RuleList

  scripts:
    selectItemSprite:
# Select weapon bigSprite based on ammo item
      - offset: 1
        code: |
          var ptr BattleItem ammoItem;
          var ptr RuleItem weaponRuleset;
          var ptr RuleItem ammoRuleset;
          var int doResprite;
          var int newSprite;
          var int modOffset;

          if eq blit_part blit_item_big;
            item.getRuleItem weaponRuleset;
            weaponRuleset.getTag doResprite Tag.ALLOW_AMMO_TO_RESPRITE;

            if eq doResprite 1;
              item.getAmmoItem ammoItem;
              ammoItem.getRuleItem ammoRuleset;
              ammoRuleset.getTag newSprite Tag.NEW_BIGOB_FOR_WEAPON;

              if neq newSprite 0;
                ammoRuleset.getTag sprite_index Tag.NEW_BIGOB_FOR_WEAPON;
                ammoRuleset.getTag modOffset Tag.CURRENT_MOD_OFFSET;
                rules.getSpriteOffsetBigobs sprite_index modOffset;
                return sprite_index;

              end;

            end;

          end;

          return sprite_index;

# Select weapon floorSprite based on ammo item
      - offset: 2
        code: |
          var ptr BattleItem ammoItem;
          var ptr RuleItem weaponRuleset;
          var ptr RuleItem ammoRuleset;
          var int doResprite;
          var int newSprite;
          var int modOffset;

          if eq blit_part blit_item_floor;
            item.getRuleItem weaponRuleset;
            weaponRuleset.getTag doResprite Tag.ALLOW_AMMO_TO_RESPRITE;

            if eq doResprite 1;
              item.getAmmoItem ammoItem;
              ammoItem.getRuleItem ammoRuleset;
              ammoRuleset.getTag newSprite Tag.NEW_FLOOROB_FOR_WEAPON;

              if neq newSprite 0;
                ammoRuleset.getTag sprite_index Tag.NEW_FLOOROB_FOR_WEAPON;
                ammoRuleset.getTag modOffset Tag.CURRENT_MOD_OFFSET;
                rules.getSpriteOffsetFloorob sprite_index modOffset;
                return sprite_index;

              end;

            end;

          end;

          return sprite_index;

# Select weapon handSprite based on ammo item
      - offset: 3
        code: |
          var ptr BattleItem ammoItem;
          var ptr RuleItem weaponRuleset;
          var ptr RuleItem ammoRuleset;
          var int doResprite;
          var int newSprite;
          var int modOffset;

          if or eq blit_part blit_item_lefthand eq blit_part blit_item_righthand;
            item.getRuleItem weaponRuleset;
            weaponRuleset.getTag doResprite Tag.ALLOW_AMMO_TO_RESPRITE;

            if eq doResprite 1;
              item.getAmmoItem ammoItem;
              ammoItem.getRuleItem ammoRuleset;
              ammoRuleset.getTag newSprite Tag.NEW_HANDOB_FOR_WEAPON;

              if neq newSprite 0;
                add newSprite sprite_offset;
                set sprite_index newSprite;

                ammoRuleset.getTag modOffset Tag.CURRENT_MOD_OFFSET;
                rules.getSpriteOffsetBigobs sprite_index modOffset;
                return sprite_index;

              end;

            end;

          end;

          return sprite_index;

Set the tag ALLOW_AMMO_TO_RESPRITE: 1 on the weapon you wish to change sprites, then on the ammunition you wish to do the change for, set NEW_BIGOB_FOR_WEAPON, NEW_FLOOROB_FOR_WEAPON, and NEW_HANDOB_FOR_WEAPON tags to the sprites you want, and add CURRENT_MOD_OFFSET: current to the tags as well.

Note: with the way tags are handled, this will not change sprites if you choose a sprite index of 0.  Also, since Handobs are lacking a proper function for getting the mod offset (coming in OXCE 3.7), this may not work if you have mods with different index offsets for handobs and bigobs - you can check your verbose log to see if the offsets are the same or not.

Also, this may not be useful if you want to have multiple weapons changing sprites but all share the same types of ammunition - I'll probably work fixing that at some point.
Title: Re: OXCE Script examples
Post by: Yankes on February 01, 2017, 12:31:34 am
Simple poison bullets that do damage over time:

Code: [Select]
extended:
  tags:
    RuleItem:
      POISON_STRENGTH: int
    RuleArmor:
      POISON_SUSCEPTIBILITY: int
    BattleUnit:
      POISON_LEVEL: int
  scripts:
    damageUnit:
      - offset: 1
        code: |
          var int susceptibility 0;
          var int strength 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;
         
          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;
    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;
    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;
items:
  - type: STR_PISTOL_CLIP
    tags:
      POISON_STRENGTH: 6
     

armors:
  - type: STR_SOME_MARTIAN
    tags:
      POISON_SUSCEPTIBILITY: 20


Laser rifle with overcharge, be careful it last only limited time and weapon is destroyed after that. But during this time you will melt all enemies.
Code: [Select]
extended:
  tags:
    RuleItem:
      OVERCHARGE_WEAPON: int
     
  scripts:
    hitUnit:
      - offset: 1
        code: |
          var int temp;
          var int primed;
          var ptr RuleItem rule;
          damaging_item.getRuleItem rule;
          damaging_item.getFuseTimer primed;
          rule.getTag temp Tag.OVERCHARGE_WEAPON;
          if and gt temp 0 gt primed 0;
            unit.reduceByResistance temp 4; #4 - laser damage type
            add power temp;
          end;
          return power part side; #part - body part, side - armor side
items:
  - type: STR_LASER_RIFLE
    fuseType: 3
    isExplodingInHands: true
    isConsumable: true #when primed is not recoverable anymore
    primeActionName: STR_LASER_RIFLE_OVERCHARGE
    primeActionMessage: STR_LASER_RIFLE_OVERCHARGE_MESSAGE
    tags:
      OVERCHARGE_WEAPON: 50
    scripts:
      recolorItemSprite: |
        var int color;
        var int temp;
        get_color color new_pixel;
        if eq color 2;
          item.getFuseTimer temp;
          if gt temp 0;
            set temp anim_frame;
            wavegen_tri temp 16 16 15;
            mul temp -1;
            add temp 8;
            add_shade new_pixel temp;
          else;
            set_shade new_pixel 15;
          end;
        end;
        return new_pixel;

extraStrings:
  - type: en-US
    strings:
      STR_LASER_RIFLE_OVERCHARGE: "Overcharge"
      STR_LASER_RIFLE_OVERCHARGE_MESSAGE: "Rifle is Overcharged"
   
Title: Re: OXCE Script examples
Post by: ohartenstein23 on February 01, 2017, 05:17:06 pm
'Vampiric' weapons, items, and armor:
Code: [Select]
extended:
  tags: # Remember to add tag definitions to same file as item/armor rulesets!
    RuleItem:
      DAMAGE_RETURNED_AS_HP: int
      DAMAGE_RETURNED_RESIST_TYPE: int
    RuleArmor:
      DAMAGE_RETURNED_AS_HP_BUFF: int
      DAMAGE_RETURNED_RESIST_TYPE_ARMOR: int

  scripts:
    damageUnit:
      - offset: 3
        code: |
          var ptre BattleUnit attackingUnit;
          var ptre BattleItem attackingItem;
          var ptr RuleItem itemRuleset;
          var ptr RuleArmor attackerArmor;
          var int hpReturnedCoefficient;
          var int hpReturnedResistType;
          var int hpDamageDone;
          var int hpTarget;
          var int hpAttacker;
          var int hpMaxAttacker;
          var int hpReturned;
          var int temp;

          damaging_item.getRuleItem itemRuleset;
          itemRuleset.getTag hpReturnedCoefficient Tag.DAMAGE_RETURNED_AS_HP;

          damaging_item.getOwner attackingUnit;
          attackingUnit.getLeftHandWeapon attackingItem;
          if and neq attackingItem null neq attackingItem damaging_item;
            attackingItem.getRuleItem itemRuleset;
            itemRuleset.getTag temp Tag.DAMAGE_RETURNED_AS_HP;
            add hpReturnedCoefficient temp;
          end;
          attackingUnit.getRightHandWeapon attackingItem;
          if and neq attackingItem null neq attackingItem damaging_item;
            attackingItem.getRuleItem itemRuleset;
            itemRuleset.getTag temp Tag.DAMAGE_RETURNED_AS_HP;
            add hpReturnedCoefficient temp;
          end;

          attackingUnit.getRuleArmor attackerArmor;
          attackerArmor.getTag temp Tag.DAMAGE_RETURNED_AS_HP_BUFF;
          add hpReturnedCoefficient temp;

          if eq hpReturnedCoefficient 0;
            return;
          else;
            unit.getHealth hpTarget;
            set hpDamageDone to_health;
            if gt hpDamageDone hpTarget;
              set hpReturned hpTarget;
            else;
              set hpReturned hpDamageDone;
            end;

            mul hpReturned hpReturnedCoefficient;
            div hpReturned 100;

            itemRuleset.getTag hpReturnedResistType Tag.DAMAGE_RETURNED_RESIST_TYPE;
            if eq hpReturnedResistType 0;
              attackerArmor.getTag hpReturnedResistType Tag.DAMAGE_RETURNED_RESIST_TYPE_ARMOR;
            end;
            unit.reduceByResistance hpReturned hpReturnedResistType;

            attackingUnit.getHealth hpAttacker;
            attackingUnit.getHealthMax hpMaxAttacker;
            add hpReturned hpAttacker;

            if gt hpReturned hpMaxAttacker;
              attackingUnit.setHealth hpMaxAttacker;
            else;
              attackingUnit.setHealth hpReturned;
            end;
          end;

          return;

items:
   - type: STR_SOME_WEAPON_OR_HELD_ITEM
     tags:
       DAMAGE_RETURNED_AS_HP: 10
       DAMAGE_RETURNED_RESIST_TYPE: 6
armors:
   - type: STR_SOME_ARMOR
     tags:
       DAMAGE_RETURNED_AS_HP_BUFF: 20

When you deal damage to a target, the items in your soldier's hands and their armor is checked for these tags, so the vampirism is an additive percent of damage done (e.g. item1: 10 + item2: 5 + armor: 15 = 30% of health damage done is returned), and modified by the chosen resist type on the enemy, so you can choose which enemies from which you suck blood by resistances.
Title: Re: OXCE Script examples
Post by: crutchmaster on February 02, 2017, 10:41:50 am
Code: [Select]

if and eq walking 0 eq floating 1;
...
offsetmod temp 11 0 8;
...
if and neq attackingItem null neq attackingItem damaging_item;
I require ECMA support.
Title: Re: OXCE Script examples
Post by: ohartenstein23 on February 03, 2017, 07:51:17 pm
Inspired by the example of the overcharged laser using priming as a mechanic, I present single-use personal energy shields!

Code: [Select]
extended:
  tags:
    RuleItem:
      ENERGY_SHIELD_CAPACITY: int
      ENERGY_SHIELD_PER_TURN: int
    BattleItem:
      ENERGY_SHIELD_HP: int
      ENERGY_SHIELD_IS_PRIMED: int
    BattleUnit:
      UNIT_RECOLOR_COLOR: int
      UNIT_RECOLOR_START_FRAME: int
      UNIT_RECOLOR_FRAME_LENGTH: int

  scripts:
    hitUnit:
      - offset: 1
        code: |
          var ptre BattleItem shieldItem;
          var ptr RuleItem shieldRule;
          var int shieldCapacity;
          var int shieldTimer;
          var int shieldHp;
          var int temp;

          # Script to handle consumable (primed) energy shields on hit
          # Check for item in left hand
          unit.getLeftHandWeapon shieldItem;

          if neq shieldItem null;
            # Check to see if the item has a shield capacity tag
            shieldItem.getRuleItem shieldRule;
            shieldRule.getTag shieldCapacity Tag.ENERGY_SHIELD_CAPACITY;

            if neq shieldCapacity 0;
              shieldItem.getFuseTimer shieldTimer;

              if gt shieldTimer 0; # Primed consumable shields have positive timer
                shieldItem.getTag temp Tag.ENERGY_SHIELD_IS_PRIMED;

                if eq temp 0; # If we just primed and haven't been hit yet, need to set shield HP
                  shieldItem.setTag Tag.ENERGY_SHIELD_IS_PRIMED 1;
                  shieldItem.setTag Tag.ENERGY_SHIELD_HP shieldCapacity;
                end;

                # Get the item's HP value and reduce damage by it
                # Resistance consideration goes here when Yankes gets to it
                shieldItem.getTag shieldHp Tag.ENERGY_SHIELD_HP;
                set temp shieldHp;
                sub temp power; # get shield value leftover after hit
                sub power shieldHp; # reduce hit by hp

                # Apply limits to make sure no negative power/HP
                limit_lower power 0;
                limit_lower temp 0;

                # Set the shield's new HP value
                shieldItem.setTag Tag.ENERGY_SHIELD_HP temp;

                # Make the unit flash a color to denote shield was hit
                if and gt temp 0 eq power 0; # But only if shield is left over
                  battle_game.getAnimFrame temp;
                  unit.setTag Tag.UNIT_RECOLOR_START_FRAME temp;
                  unit.setTag Tag.UNIT_RECOLOR_FRAME_LENGTH 3;
                  unit.setTag Tag.UNIT_RECOLOR_COLOR COLOR_X1_BLUE1; # add tag to configure?
                end;
              end;
            end;
          end;

          # Now do it for a right hand shield
          unit.getRightHandWeapon shieldItem;

          if neq shieldItem null;
            # Check to see if the item has a shield capacity tag
            shieldItem.getRuleItem shieldRule;
            shieldRule.getTag shieldCapacity Tag.ENERGY_SHIELD_CAPACITY;

            if neq shieldCapacity 0;
              shieldItem.getFuseTimer shieldTimer;

              if gt shieldTimer 0; # Primed consumable shields have positive timer
                shieldItem.getTag temp Tag.ENERGY_SHIELD_IS_PRIMED;

                if eq temp 0; # If we just primed and haven't been hit yet, need to set shield HP
                  shieldItem.setTag Tag.ENERGY_SHIELD_IS_PRIMED 1;
                  shieldItem.setTag Tag.ENERGY_SHIELD_HP shieldCapacity;
                end;

                # Get the item's HP value and reduce damage by it
                # Resistance consideration goes here when Yankes gets to it
                shieldItem.getTag shieldHp Tag.ENERGY_SHIELD_HP;
                set temp shieldHp;
                sub temp power; # get shield value leftover after hit
                sub power shieldHp; # reduce hit by hp

                # Apply limits to make sure no negative power/HP
                limit_lower power 0;
                limit_lower temp 0;

                # Set the shield's new HP value
                shieldItem.setTag Tag.ENERGY_SHIELD_HP temp;

                # Make the unit flash a color to denote shield was hit
                if and gt temp 0 eq power 0; # But only if shield is left over
                  battle_game.getAnimFrame temp;
                  unit.setTag Tag.UNIT_RECOLOR_START_FRAME temp;
                  unit.setTag Tag.UNIT_RECOLOR_FRAME_LENGTH 3;
                  unit.setTag Tag.UNIT_RECOLOR_COLOR COLOR_X1_BLUE1; # add tag to configure?
                end;
              end;
            end;
          end;

          # return modified power
          return power part side;

    recolorUnitSprite:
      - offset: 10
        code: |
          var int frame;
          var int frameLength;
          var int color;
          var int temp;

          unit.getTag frame Tag.UNIT_RECOLOR_START_FRAME;
          unit.getTag frameLength Tag.UNIT_RECOLOR_FRAME_LENGTH;

          if neq frame 0;
            set temp anim_frame;
            sub temp frame;

            if lt temp frameLength;
              unit.getTag color Tag.UNIT_RECOLOR_COLOR;
              set_color new_pixel color;
            end;
          end;

          return new_pixel;

    recolorItemSprite:
      - offset: 10
        code: |
          var ptr RuleItem shieldItem;
          var int shieldCapacity;
          var int shieldTimer;
          var int shieldHp;
          var int shieldPercent;
          var int shieldIsPrimed;
          var int color;
          var int shadeIndex;
          var int temp;

          item.getRuleItem shieldItem;
          shieldItem.getTag shieldCapacity Tag.ENERGY_SHIELD_CAPACITY;

          if eq shieldCapacity 0;
            return new_pixel;
          else;
            item.getFuseTimer shieldTimer;

            if gt shieldTimer 0;
              item.getTag shieldHp Tag.ENERGY_SHIELD_HP;
              set shieldPercent shieldHp;
              muldiv shieldPercent 100 shieldCapacity;

              item.getTag shieldIsPrimed Tag.ENERGY_SHIELD_IS_PRIMED;
              if eq shieldIsPrimed 0; # Haven't been hit yet, but should show shield
                set shieldPercent 100;
              end;

              # Choose color to replace on sprite
              get_color color new_pixel;

              if eq color COLOR_X1_YELLOW;
                get_shade shadeIndex new_pixel;

                if gt shieldPercent 20; # Choose critical shields at 20%, make tag later?
                  set color COLOR_X1_BLUE1;
                else;
                  set color COLOR_X1_RED;
                end;

                set temp shieldPercent;
                sub temp 100;
                abs temp;
                muldiv temp 15 100;
                add shadeIndex temp;
                limit shadeIndex 0 15;
                set_color new_pixel color;
                set_shade new_pixel shadeIndex;
              end;
            end;
          end;

          return new_pixel;

    newTurnItem:
      - offset: 2
        code: |
          var ptr RuleItem shieldRule;
          var int shieldCapacity;
          var int shieldTimer;
          var int shieldIsPrimed;
          var int shieldPerTurn;
          var int shieldHp;
          var int temp;

          # Recharge/decay handling for consumable shield items
          item.getRuleItem shieldRule;
          shieldRule.getTag shieldCapacity Tag.ENERGY_SHIELD_CAPACITY;

          if eq shieldCapacity 0;
            return;
          else;
            item.getFuseTimer shieldTimer;

            if gt shieldTimer 0; # Consumable shields have positive timers when on
              # Make sure it's primed, if not, do so now
              item.getTag shieldIsPrimed Tag.ENERGY_SHIELD_IS_PRIMED;

              if eq shieldIsPrimed 0;
                item.setTag Tag.ENERGY_SHIELD_IS_PRIMED 1;
                item.setTag Tag.ENERGY_SHIELD_HP shieldCapacity;
              end;

              shieldRule.getTag shieldPerTurn Tag.ENERGY_SHIELD_PER_TURN;
              item.getTag shieldHp Tag.ENERGY_SHIELD_HP;

              # Recharge/decay shield, respecting capacity and 0
              add shieldHp shieldPerTurn;
              limit shieldHp 0 shieldCapacity;
              item.setTag Tag.ENERGY_SHIELD_HP shieldHp;
            end;
          end;

          return;

items:
  - type: STR_PERSONAL_SHIELD
    battleType: 10
    tags:
      ENERGY_SHIELD_CAPACITY: 50
      ENERGY_SHIELD_PER_TURN: -5
    bigSprite: 55
    floorSprite: 72
    costBuy: 5000
    power: 20
    fuseType: 5
    costPrime:
      time: 25
    primeActionName: STR_PRIME_ENERGY_SHIELD
    primeActionMessage: STR_ENERGY_SHIELD_ACTIVE
    unprimeActionMessage: STR_ENERGY_SHIELD_INACTIVE
    isConsumable: true
    isExplodingInHands: true

extraStrings:
  - type: en-US
    strings:
      STR_PERSONAL_SHIELD: "Personal Shield"
      STR_PRIME_ENERGY_SHIELD: "Activate Shield"
      STR_ENERGY_SHIELD_ACTIVE: "Shield is Active"
      STR_ENERGY_SHIELD_INACTIVE: "Shield is Inactive"

Prime before battle and that rookie can (mostly) safely run down the Skyranger ramp!

Edit:  Needed to tweak a bit after testing.  Also, I should tell you it only works if you're holding it in your hand when you're hit!
Title: Re: OXCE Script examples
Post by: Yankes on February 10, 2017, 09:30:45 pm
Script for OXCE+ where is more than 10 damage types, instead of using them as separate damage types you can use them as sub-resistances:
Code: [Select]
extended:
  scripts:
    damageUnit:
      - offset: 50
        code: |
          unit.reduceByResistance to_health 10;
          unit.reduceByResistance to_stun 11;
          unit.reduceByResistance to_time 12;
          unit.reduceByResistance to_wound 13;
          unit.reduceByResistance to_energy 14;
          unit.reduceByResistance to_morale 15;
          return;
extraStrings:
  - type: en-US
    strings:
      STR_DAMAGE_10: "Health damage multipler"
      STR_DAMAGE_11: "Stun damage multipler"
      STR_DAMAGE_12: "Time damage multipler"
      STR_DAMAGE_13: "Wound damage multipler"
      STR_DAMAGE_14: "Energy damage multipler"
      STR_DAMAGE_15: "Morale damage multipler"
Title: Re: [Documentation] OXCE Script examples
Post by: KingMob4313 on July 10, 2020, 07:33:16 am
My first script

A script I am using for my stream to keep soldiers from being wounded more than 13 days.

Code: [Select]
    returnFromMissionUnit:
      - offset: -2 # Changing injured time to less than 13
        code: |
          var int currentRecoveryDays 0;
          var int maxRecoveryDays 13;
          var int newRecoveryDays 0;
          debug_log "Original Recovery Time:" recovery_time;
          set currentRecoveryDays recovery_time;
          div currentRecoveryDays 5;
          debug_log "Changed Recovery Time:" currentRecoveryDays;
          if gt currentRecoveryDays 13;
            debug_log "Changed MAX Days Recovery from" currentRecoveryDays;
            set currentRecoveryDays 13;
          end;
          set recovery_time currentRecoveryDays;
          return;
Title: Re: [Documentation] OXCE Script examples
Post by: cevaralien on September 06, 2020, 05:30:03 pm
Post edited/removed by Meridian, please use this thread only to post working scripts you want to share with others.

Original post here: https://openxcom.org/forum/index.php/topic,8476.msg131427.html#msg131427
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Yankes on February 19, 2021, 09:15:08 pm
Code what find all units that are 2 tile way from `unit`
Code: [Select]

          begin;
            var int range 2;
            var int l 0;
            var int rangeVoxel;
            var int sx;
            var int sy;
            var int sz;
            var ptr Tile st;
           
            unit.getPosition.getX sx;
            unit.getPosition.getY sy;
            unit.getPosition.getZ sz;
            battle_game.getTile st sx sy sz;
           
            set l range;
            mul l 2;
            add l 1;
           
            set rangeVoxel range;
            mul rangeVoxel 16;
            add rangeVoxel 8; #half tile buffer for max distance
           
            loop var x l;
              add x sx;
              sub x range;
             
              loop var y l;
                add y sy;
                sub y range;
               
                loop var z l;
                  add z sz;
                  sub z range;
                 
                  begin;
                    var ptr Tile t;
                    var int tileDistance;
                    var ptr BattleUnit bu;
                   
                    battle_game.getTile t x y z;
                    t.getUnit bu;
                    st.getDistanceVoxel tileDistance t;
                    if and neq bu null gt tileDistance 0 lt tileDistance rangeVoxel;
                     
                      #check other close units
                      debug_log "unit" bu "at" t;
                    end;
                  end;
                end;
              end;
            end;
           
          end;
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Yankes on February 21, 2021, 06:07:47 pm
Iterate whole inventory of unit and special weapons (like buildin alien PSI attack)
Code: [Select]
          begin;
            var int size;
            unit.getInventoryItem.size size;
            loop var i size;
              var ptre BattleItem item;
              unit.getInventoryItem item i;
             
              debug_log "unit" unit "have in inv" item;
            end;
          end;
         
          begin;
            var int size;
            unit.getSpecialItem.size size;
            loop var i size;
              var ptre BattleItem item;
              unit.getSpecialItem item i;
             
              debug_log "unit" unit "have in spec" item;
            end;
          end;

result:

Code: [Select]
[21-02-2021_17-04-09] [DEBUG] Script debug log: unit BattleUnit(type: "STR_ETHEREAL_SOLDIER" race: "STR_ETHEREAL" id: 1000017 faction: Hostile hp: 1/100) have in inv BattleItem(name: "STR_HEAVY_PLASMA" id: 117)
[21-02-2021_17-04-09] [DEBUG] Script debug log: unit BattleUnit(type: "STR_ETHEREAL_SOLDIER" race: "STR_ETHEREAL" id: 1000017 faction: Hostile hp: 1/100) have in inv BattleItem(name: "STR_ALIEN_GRENADE" id: 119)
[21-02-2021_17-04-09] [DEBUG] Script debug log: unit BattleUnit(type: "STR_ETHEREAL_SOLDIER" race: "STR_ETHEREAL" id: 1000017 faction: Hostile hp: 1/100) have in inv BattleItem(name: "STR_HEAVY_PLASMA_CLIP" id: 120 ammo: 35/35)
[21-02-2021_17-04-09] [DEBUG] Script debug log: unit BattleUnit(type: "STR_ETHEREAL_SOLDIER" race: "STR_ETHEREAL" id: 1000017 faction: Hostile hp: 1/100) have in spec BattleItem(name: "ALIEN_PSI_WEAPON" id: 116)
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Finnik on February 23, 2021, 11:55:47 pm
That is overcool! Last argument like bah, YS is not so cool as Lua or Python has fallen in my eyes. Great job!
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: scarf on April 20, 2021, 01:23:04 pm
1. Environmental Damages
script that deals additional environmental damage (smoke & fire) to units every turn. also getSmoke gets the intensity of EITHER FIRE or SMOKE (thanks meridian)

Code: [Select]

extended:
  scripts:
    newTurnUnit:
      - offset: 2
        code: |
          var int LOG 0; # 0: none; 1: simple 2: detailed


          var ptr Tile tile_info;


          var int x;
          var int y;
          var int z;


          var int Hazard_Intensity;
          var int Fire_Duration;


          unit.getPosition.getX x;
          unit.getPosition.getY y;
          unit.getPosition.getZ z;


          battle_game.getTile tile_info x y z;


          tile_info.getSmoke Hazard_Intensity;
          tile_info.getFire Fire_Duration;
          #debug_log "hazard intensity:" Hazard_Intensity "fire duration:" Fire_Duration;


          if and gt Fire_Duration 0 gt Hazard_Intensity 0;
            begin;
              var int Fire_Damage 0;
              var int Total_Fire_Damage 0;


              var ptr RuleArmor Unit_Armor;
              var int Unit_Size; # 1 for small, 2 for big
              var int Unit_Armor_Under;
              var int Resist_Under 70;


              unit.getRuleArmor Unit_Armor;
              Unit_Armor.getSize Unit_Size;
              Unit_Armor.getArmor Unit_Armor_Under 4;
              sub Resist_Under Unit_Armor_Under;




              if ge LOG 1;debug_log "trauma report for:" unit;end;
              if ge LOG 1;debug_log "original hazard intensity:" Hazard_Intensity;end;
              if ge LOG 2;debug_log " armor size" Unit_Size;end;


              #normalizing
              # from 01 02 03 04 05 06 07 08 09 10 11 12
              # to   06 06 06 06 07 07 07 07 08 08 08 08
              if gt Hazard_Intensity 8;
                set Hazard_Intensity 8;
              else gt Hazard_Intensity 4;
                set Hazard_Intensity 7;
              else gt Hazard_Intensity 0;
                set Hazard_Intensity 6;
              end;
              if gt Unit_Size 1;
                div Hazard_Intensity 4;
              end;
              if ge LOG 2;debug_log "normalized hazard intensity:" Hazard_Intensity;end;
              loop var i Hazard_Intensity;
                #set Fire_Damage Hazard_Intensity;
                battle_game.randomRange Fire_Damage 0 Hazard_Intensity;
                unit.reduceByResistance Fire_Damage 2;
                mul Fire_Damage Resist_Under;
                div Fire_Damage 70; # under armor over 70 completely negates fire damage
                mul Fire_Damage -1;
                if ge LOG 2;debug_log "   fire damage for loop" i ":" Fire_Damage;end;
                if lt Fire_Damage 0;
                  unit.addHealth Fire_Damage;
                  unit.addMorale Fire_Damage;
                  add Total_Fire_Damage Fire_Damage;
                end;
              end;
              if ge LOG 1;debug_log "total fire damage [" Total_Fire_Damage "]";end;
              #adds fatal damage (2x2 units are immune)
              if and le Total_Fire_Damage -10 eq Unit_Size 1;
                # START WOUNDED_PART
                # TORSO 1 RL 4 LL 5
                var int Wounded_Part;
                battle_game.randomRange Wounded_Part 3 5;
                if eq Wounded_Part 3; sub Wounded_Part 2; end;
                # FINISH WOUNDED PART
                mul Total_Fire_Damage -1;
                div Total_Fire_Damage 2;
                battle_game.randomRange Total_Fire_Damage 1 Total_Fire_Damage;
                unit.addFatalwounds Wounded_Part Total_Fire_Damage;
                if ge LOG 1;debug_log Total_Fire_Damage "wound to" Wounded_Part;end;
              end;
            end;
          else gt Hazard_Intensity 0;
            div Hazard_Intensity 4;
            battle_game.randomRange Hazard_Intensity 0 Hazard_Intensity;
            unit.reduceByResistance Hazard_Intensity 9;
            if gt Hazard_Intensity 0;
              if ge LOG 1;debug_log "total smoke damage:" Hazard_Intensity;end;
              unit.addStun Hazard_Intensity;
            end;
          end;
          return;



2. More Fatal Wounds
this script overrides vanilla fatal wound limit of 1 to 3. code below deals roughly 1/4 inflicted damage to fatal wounds.
Code: [Select]

extended:
  scripts:
    damageUnit:
      - offset: 1
        code: |
          var int LOG 2; # 0: none; 1: simple 2: detailed


          var int Temp 0;


          if ge LOG 2;debug_log "start:" to_health to_wound unit;end;


          set to_wound 0;


          loop var i to_health;
            battle_game.randomRange Temp 0 3; #25% chance
            if eq Temp 0; add to_wound 1;end;
          end;


          if ge LOG 1;debug_log "end:" to_health to_wound;end;
          return;
3. Fatal Wounds inflict Moral Loss
Code: [Select]

extended:
  scripts:
    newTurnUnit:
      - offset: 1
        code: |
          var int Fatal_Wounds;
          var int Moral_Damage;


          unit.getFatalwoundsTotal Fatal_Wounds;


          if gt Fatal_Wounds 0;
            begin;
              loop var i 4;
                unit.reduceByBravery Fatal_Wounds;
                battle_game.randomRange Moral_Damage 0 Fatal_Wounds;
                mul Moral_Damage -1;
                unit.addMorale Moral_Damage;
                #debug_log "moral dmg:" Moral_Damage;
              end;
            end;
          end;
          return;
4. Automatic Priming
script that automatically primes grenades tagged as START_PRIMED. newTurnItem methods are preferred as it does not prime grenades on floor.

Code: [Select]
extended:
  tags:
    RuleItem:
      START_PRIMED: int
  scripts:
    newTurnItem:
      - offset: 52
        code: |
          var int Current_Turn;
          battle_game.getTurn Current_Turn;


          if eq Current_Turn 1;
            var ptr RuleInventory Items_Inventory;
            var int Inventory_Slot;
            item.getSlot Items_Inventory;
            Items_Inventory.getType Inventory_Slot;


            if neq Inventory_Slot INV_GROUND;
              var int Start_Primed;
              item.getTag Start_Primed Tag.START_PRIMED;


              if eq Start_Primed 1;
                item.setFuseTimer 0;
                return;
              end;
            end;
          end;
          return;

5. change ammo sprite by rounds left
Code: [Select]
extended:
  tags:
    RuleItem:
      ALLOW_AMMO_TO_RESPRITE: int # 0: NO, 1 ~ 4: how many ammos to compute, recommended max 3
      PAEDIA_OFFSET: int # on ufopaedia weapon on max loadout is shown; negates that offset. usu. sum of ommo offsets
      OFFSET_BIGOB_WEAPON: int # 0: empty, 1 ~ 4: ammo type 1 ~ 4
  scripts:
    selectItemSprite:
      - offset: 1
        code: |
          var int Ammo_Types;


          if eq blit_part blit_item_big; # if blit_part == blit_item_big; -> on bliting big item
            item.getTag Ammo_Types Tag.ALLOW_AMMO_TO_RESPRITE; # find matching tag: ALLOW_AMMO_TO_RESPRITE


            if gt Ammo_Types 0; # if Ammo_Types > 0; -> tagged as resprite
              var int Paedia_Offset;
              var int Ammo_Offset;
              var ptr BattleItem Loaded_Ammo;


              # NEGATES PEDIA OFFSET
              item.getTag Paedia_Offset Tag.PAEDIA_OFFSET;
              sub sprite_index Paedia_Offset;


              # LOOP THROUGH AMMO SLOTS
              loop var i Ammo_Types;
                item.getAmmoForSlot Loaded_Ammo i; # get ammo item as Loaded_Ammo
                Loaded_Ammo.getTag Ammo_Offset Tag.OFFSET_BIGOB_WEAPON; # find offset value as Ammo_Offset
                add sprite_index Ammo_Offset; # ammo offset applied to sprite_index
              end;
            end;
          end;
          return sprite_index;
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Meridian on April 20, 2021, 02:00:01 pm
`getFire` is not fire intensity, it's fire duration

fire intensity is in `getSmoke`
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: scarf on April 20, 2021, 02:38:38 pm
`getFire` is not fire intensity, it's fire duration

fire intensity is in `getSmoke`


oh, I've misunderstood, changed it to more suitable one. thank you!
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Yankes on March 25, 2022, 10:38:17 am
Global fix for soldiers armors that have more than 3 death frames, assumes that all armors with more death frames shifted all surfaces graphic too.
Fix for problem: https://openxcom.org/forum/index.php/topic,10392.0.html

Code: [Select]
extended:
  scripts:
    selectUnitSprite:
      - offset: -2
        code: |
          var int drawingRoutine;
          var int deathFrames;
         
          if or
            eq blit_part blit_torso
            eq blit_part blit_legs
          ;
            var ptr RuleArmor armor;
            unit.getRuleArmor armor;
            armor.getDrawingRoutine drawingRoutine;
            armor.getDeathFrames deathFrames;
            if and
              eq drawingRoutine 0
              gt sprite_index 264  #bigger than first death frame
              gt deathFrames 3
            ;
              sub deathFrames 3;
              add sprite_index deathFrames;
            end;
          end;
          return sprite_index;
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Yankes on April 09, 2022, 03:40:05 pm
More idea than implementation:

In recent OXCE nighty I added option for blocking item move (by making move cost bigger than available TU) and switching move type of unit.
Most critical consequence of this features is that you can create "jet pack" item that can be equipped before battle and when game start it change unit to flying one.
To prevent exploits cost of removing item will be so big that can't be done during mission.
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Delian on April 09, 2022, 04:32:53 pm
Wouldn't that mean that if the unit is knocked unconscious, it drops the jetpack and can't pick it up anymore? That doesn't make logical sense tho.
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Yankes on April 09, 2022, 05:54:44 pm
Jet pack break down and is not usable any more, this is logical :>

As for more serious answer script have option to increase and decrease cost, you could make more complex scripts to handle it better but still be some corner cases hard to handle.
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Solarius Scorch on April 10, 2022, 12:59:35 pm
Hmm, why prevent this unit from taking off the jetpack? Is it to prevent it from throwing it away in mid-air?
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Yankes on April 10, 2022, 01:39:15 pm
Item move cost, new feature I added, you can make that item will cost 1000 TU to move from inventory.
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: krautbernd on April 10, 2022, 04:30:29 pm
Item move cost, new feature I added, you can make that item will cost 1000 TU to move from inventory.
Doesn't inventoryMoveCost already accomplish the same thing?
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Yankes on April 10, 2022, 04:36:17 pm
Doesn't inventoryMoveCost already accomplish the same thing?
I was referring exactly to this, only details is that script can alter it, this mean item can be movable during one turn but unmovable on another.
If item should be equipable only during briefing then only item config change is required.
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Yankes on December 30, 2022, 03:29:28 pm
Script that show HK ufo from longer distance that normally when they are in "hunt" mode.
Distance on what HK is visible is `base_radar_range + hk_radar_range + small_bonus`
Code: [Select]
extended:
  scripts:
    detectUfoFromBase:
      - offset: 10
        code: |
          var int maxDistanceHK;
          var int radarRangeHK;
          var int hunter;
         
          ufo.Stats.getRadarRange radarRangeHK;
          set maxDistanceHK radar_max_distance;
          add maxDistanceHK 300;
          add maxDistanceHK radarRangeHK;
         
          ufo.isHunting hunter;
          if and eq hunter 1 lt distance maxDistanceHK;
            var int temp_chanc 30;
            if gt temp_chanc detection_chance;
              set detection_chance temp_chanc;
            end;
          end;
         
          return detection_type detection_chance;
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Solarius Scorch on December 30, 2022, 03:55:07 pm
Many thanks, Yankes.

Would it be possible to write that script that for certain UFOs displays full info, even if you don't have the Hyper-Wave Decoder? I'd like to mark some Earth vehicles like that.
Title: Re: [Documentation][y-script] OXCE Script examples
Post by: Yankes on December 30, 2022, 05:00:18 pm
Script that make some ufo permanently HW decoded but invisible until normal radar find it.
Code: [Select]
extended:
  tags:
    RuleUfo:
      PUBLIC_HYPERWAVE_DATA: int
  scripts:
    detectUfoFromBase:
      - offset: 10
        code: |
          var int showHwData;
         
          ufo.getTag showHwData Tag.PUBLIC_HYPERWAVE_DATA;
         
          if eq showHwData 1;
            var int temp DETECTION_HYPERWAVE;
            bit_xor temp DETECTION_RADAR; # remove from HW radar detection bit, it leave only HW data flag
            bit_or detection_type temp; # add only HW falag to detection
          end;
         
          return detection_type detection_chance;
ufos:
  - type: STR_SMALL_SCOUT
    tags:
      PUBLIC_HYPERWAVE_DATA: 1
Title: Re: [Documentation] OXCE Y-Script examples
Post by: MaxMahem on March 12, 2023, 07:27:19 am
Guard "Function" to check if an item is in the proper slot to be "active" (or otherwise proceed with the script). Uses an "ACTIVE_IN" tag which is a "flag enum" containing a bitmask of all the locations where an item should be active in. If this tag does not have a value (or if the value is set to 0 for some reason, maybe a sub-mod override) then this test will always pass. Otherwise the script will proceed only if the item is in a slot notated by the bitfield.

Code: [Select]
tags:
    RuleItem:
      ACTIVE_IN: int
          # Flag Enum
          # 0 = always active/NA?
          # 1 = L. Hand
          # 2 = R. Hand
          # 4 = Belt
          # 8 = R. Legt
          # 16 = L. Leg
          # 32 = R. Shoulder
          # 64 = L. Shoulder
          # 128 = Backpack
          # 256 = Quick Draw
          # 512 = Worn
          # 1024 = Jewlery
          # 2048 = Hat
          # 3 = R & L hands
          # 4095 = everywhere

scripts:
  newTurnItem:
    - override: ITEM_RESISTANCE_SCRIPT
      offset: 2
      code: |
        var ptr RuleItem itemRuleset;
        var int activeInEnum;
       
        item.getRuleItem itemRuleset;
        itemRuleset.getTag activeInEnum Tag.ACTIVE_IN;

        # activeInEnum has a value so we need to test it.
        if neq activeInEnum 0;
          var ptr RuleInventory itemInventory;
          var text inventoryId;
          var int testMask;

          item.getSlot itemInventory;
          itemInventory.getId inventoryId;
       
          # build a bitmask to test based on where we know the item is:
          if eq inventoryId "STR_LEFT_HAND";
            set testMask 1;
          end;
          if eq inventoryId "STR_RIGHT_HAND";
            set testMask 2;
          end;
          if eq inventoryId "STR_BELT";
            set testMask 4;
          end;
          if eq inventoryId "STR_RIGHT_LEG";
            set testMask 8;
          end;
          if eq inventoryId "STR_LEFT_LEG";
            set testMask 16;
          end;
          if eq inventoryId "STR_RIGHT_SHOULDER";
            set testMask 32;
          end;
          if eq inventoryId "STR_LEFT_SHOULDER";
            set testMask 64;
          end;
          if eq inventoryId "STR_BACK_PACK";
            set testMask 128;
          end;
          if eq inventoryId "STR_QD_SLOT";
            set testMask 256;
          end;
          if eq inventoryId "STR_WEAR";
            set testMask 512;
          end;
          if eq inventoryId "STR_WEAR_JEWELRY";
            set testMask 1024;
          end;
          if eq inventoryId "STR_WEAR_HAT";
            set testMask 2048;
          end;

          bit_and testMask activeInEnum;
          if eq testMask 0;
            debug_log "Item:" item " passed no tests:" testMask "enum:" activeInEnum;
            return;
          end;
          debug_log "Item:" item "passed the tests!:" testMask "enum:" activeInEnum;
        end;
       
        # script proceeds normally from here.