Skip to content

Tricks

Written by: Alian713 & Kramb


1. Setting and Unsetting Costs

A house normally costs 25 wood, but what if we want to make it cost, lets say, 10 stone instead?

1
2
3
4
5
const int HOUSE = 70;

xsEffectAmount(cMulAttribute, HOUSE, cWoodCost, -2, 1);
xsEffectAmount(cMulAttribute, HOUSE, cStoneCost, -1, 1);
xsEffectAmount(cSetAttribute, HOUSE, cStoneCost, 10, 1);

This same trick also works for changing technology costs.

2. Adding auras

Adding auras to units can be a bit tricky with lots of function calls and edge cases. This xs function handles most of those cases.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
bool xsAddAura(
    int auraUnit = -1, /* unit to add the aura to */
    int affectedUnit = -1, /* unit or unit class (9xx) to be affected by the aura */
    int player = -1, /* aura unit player, does not work with -1, make multiple calls to all players instead */
    int attribute = -1, /* aura attribute, not all attributes supported by auras, constants are provided */
    float value = 0, /* aura value */ 
    float range = 0,  /* aura range */
    int auraEffectsBitField = 0, /* bit field for aura effects, constants are provided, add them together for multiple effects */
    int targetDiplomacy = 0, /* aura target diplomacy, controls what diplomacy target unit needs to be to be affected, constants are provided */
    int tempAuraDuration = 0, /* only works with cAuraEffectBitTemporary effect, specifies how long the temp aura lasts in seconds */
    int tempAuraCooldown = 0, /* only works with cAuraEffectBitTemporary effect, specifies how long the cooldown period lasts is in seconds */
    int unitsInRangeToTurnOn = 1, /* how many units need to be in range for aura to turn on */
    bool affectSelf = false /* if set makes aura affect auraUnit instead, affectedUnit still needs to be in range to activate */
) {
    /* Function adds an aura to the provided unit based on a your config. 
    Note that adding auras "freezes" the unit for further non task modifications.
    To work around that can respawn the unit or do a double replace with another unit and itself.
    Adding an aura to a unit of the same player that already has an aura for the same attribute and affectedUnit will overwrite it instead.
    Function returns `true` if function parameter validation passed and `false` if it did not (no aura added). */

    /* Validation */
    if (auraUnit < 0 || affectedUnit < 0 || player < 0 || player > 8) {
        return (false);
    }
    if (attribute != 0 && attribute != 1 && attribute != 5 && attribute != 9 && attribute != 10 && attribute != 12 
        && attribute != 13 && attribute != 109 && attribute != 113 && attribute != 116 && attribute != 117 
        && attribute != 120) {
        return (false);
    }
    if (range < 0 || auraEffectsBitField < 0 || targetDiplomacy < 0 || targetDiplomacy > 6 
        || unitsInRangeToTurnOn < 0 || tempAuraDuration < 0 || tempAuraCooldown < 0) {
        return (false);
    }

    /* Handling gaia player */
    int setCommand = cSetAttribute;
    if (player == 0) {
        setCommand = cGaiaSetAttribute;
    }

    /* Setting right combat ability flags */
    float ca = xsGetObjectAttribute(player, auraUnit, cCombatAbility);
    if (ca < 0) {
        ca = 0;
    }
    float caMod = 0;
    float auraBit = (ca / 32) % 2;
    if (auraBit == 0) {
        caMod = 32;
    }
    float selfBit = (ca / 64) % 2;
    if (affectSelf && selfBit == 0) {
        caMod = caMod + 64;
    } else if (affectSelf == false && selfBit == 1) {
        caMod = caMod - 64;
    }
    if (caMod != 0) {
        xsEffectAmount(setCommand, auraUnit, cCombatAbility, ca + caMod, player);
    }

    /* Setting temporary aura values if enabled */
    int tempEffectBit = (auraEffectsBitField / 8) % 2;
    if (tempEffectBit == 1) {
        float maxCharge = 1;
        float cdRatio = 1000;
        if (tempAuraCooldown > 0) {
            float tacf = tempAuraCooldown;
            cdRatio = maxCharge / tacf;
        }
        xsEffectAmount(setCommand, auraUnit, cMaxCharge, maxCharge, player);
        xsEffectAmount(setCommand, auraUnit, cRechargeRate, cdRatio, player);
        xsEffectAmount(setCommand, auraUnit, cChargeEvent, 0.0 + tempAuraDuration, player);
        xsEffectAmount(setCommand, auraUnit, cChargeType, -3.0, player);
    }

    /* Workaround for a bug setting multiple unit classes with an aura*/
    float statMod = 0;
    if (affectedUnit >= 900 && affectedUnit < 1000) {
        statMod = (0.0 + affectedUnit - 900) / 100000;
    }

    /* Setting aura task */
    xsTaskAmount(0, value);
    xsTaskAmount(1, 0.0 + unitsInRangeToTurnOn);
    xsTaskAmount(2, range);
    xsTaskAmount(3, 0.0);
    xsTaskAmount(4, statMod + attribute);
    xsTaskAmount(5, 0.0 + auraEffectsBitField);
    xsTaskAmount(6, 0.0 + targetDiplomacy);
    xsTask(auraUnit, 155, affectedUnit, player);

    return (true);
}

bool xsRemoveAura(
    int auraUnit = -1, /* unit from which remove the aura */
    int affectedUnit = -1, /* unit or unit class (9xx) to be affected by the aura */
    int player = -1, /* aura unit player, does not work with -1, make multiple calls to all players instead */
    int attribute = -1, /* aura attribute, not all attributes supported by auras, constants are provided */
    bool removeTempAuraAttributes = false, /* if set removes temp aura attributes from unit */
    bool removeAllAuraAbilities = false /* if set removes unit aura ability disabling all auras and removing indicators */
) { 
    /* Function removes the aura added by xsAddAura. Leaves combat ability unchanged. 
    Removing auras "freezes" the unit for further non task modifications.
    Function returns `true` if function parameter validation passed and `false` if it did not (no aura removed). */

    /* Validation */
    if (auraUnit < 0 || affectedUnit < 0 || player < 0 || player > 8) {
        return (false);
    }
    if (attribute != 0 && attribute != 1 && attribute != 5 && attribute != 9 && attribute != 10 && attribute != 12 
        && attribute != 13 && attribute != 109 && attribute != 113 && attribute != 116 && attribute != 117 
        && attribute != 120) {
        return (false);
    }

    /* Handling gaia player */
    int setCommand = cSetAttribute;
    if (player == 0) {
        setCommand = cGaiaSetAttribute;
    }

    /* Remove temporary aura values */
    if (removeTempAuraAttributes) {
        float ct = xsGetObjectAttribute(player, auraUnit, cChargeType);
        if (ct == -3) {
            xsEffectAmount(setCommand, auraUnit, cMaxCharge, 0.0, player);
            xsEffectAmount(setCommand, auraUnit, cRechargeRate, 0.0, player);
            xsEffectAmount(setCommand, auraUnit, cChargeEvent, 0.0, player);
            xsEffectAmount(setCommand, auraUnit, cChargeType, 0.0, player);
        }
    }

    /* Remove combat ability */
    if (removeAllAuraAbilities) {
        float ca = xsGetObjectAttribute(player, auraUnit, cCombatAbility);
        float caMod = 0;
        float auraBit = (ca / 32) % 2;
        if (auraBit == 1) {
            caMod = -32;
        }
        float selfBit = (ca / 64) % 2;
        if (selfBit == 1) {
            caMod = caMod - 64;
        }
        if (caMod != 0) {
            xsEffectAmount(setCommand, auraUnit, cCombatAbility, ca + caMod, player);
        }
    }

    /* Workaround for a bug setting multiple unit classes with an aura*/
    float statMod = 0;
    if (affectedUnit >= 900 && affectedUnit < 1000) {
        statMod = (0.0 + affectedUnit - 900) / 100000;
    }

    /* Setting aura task */
    xsTaskAmount(4, statMod + attribute);
    xsRemoveTask(auraUnit, 155, affectedUnit, player);

    return (true);
}

extern const int cAuraAttributeHitpoints = 0;
extern const int cAuraAttributeLineOfSights = 1;
extern const int cAuraAttributeMovementSpeed = 5;
extern const int cAuraAttributeAttack = 9;
extern const int cAuraAttributeAttackReloadTime = 10;
extern const int cAuraAttributeMaxRange = 12; /* changes the display attribute, but not the range, bug? */
extern const int cAuraAttributeWorkRate = 13;
extern const int cAuraAttributeRegenerationRate = 109;
extern const int cAuraAttributeConversionChanceMod = 113;
extern const int cAuraAttributeMeleeArmor = 116;
extern const int cAuraAttributePierceArmor = 117;
extern const int cAuraAttributeRegenerationHpPercent = 120;

extern const int cAuraEffectBitMultiply = 1; /* if not added, value is added instead */
extern const int cAuraEffectBitCircular = 2; /* if not added, aura is square shaped */
extern const int cAuraEffectBitRangeIndicator = 4;
extern const int cAuraEffectBitTemporary = 8;
extern const int cAuraEffectBitAppliedWhenActivatedOnly = 16; /* only works with cAuraEffectBitTemporary */
extern const int cAuraEffectBitAdvancedRangeIndicator = 32;

extern const int cAuraDiplomacyAll = 0;
extern const int cAuraDiplomacyYou = 1;
extern const int cAuraDiplomacyNeutralEnemy = 2;
extern const int cAuraDiplomacyGaia = 3;
extern const int cAuraDiplomacyGaiaYouAlly = 4;
extern const int cAuraDiplomacyGaiaNeutralAlly = 5;
extern const int cAuraDiplomacyAllButYou = 6;

To use, copy the code above to a non-running Script Call effect or to your scenarios .xs file and then call the function in your xs code, eg:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
void addAuraTest() {
  /* Adds a temporary activatable aura that doubles cavalry (912) speed for player 1 joan of arc hero (629) */
  int tempAuraEffects = cAuraEffectBitTemporary + cAuraEffectBitMultiply + cAuraEffectBitCircular + cAuraEffectBitRangeIndicator;
  bool aura1Added = xsAddAura(629, 912, 1, cAuraAttributeMovementSpeed, 2.0, 10.0, tempAuraEffects, cAuraDiplomacyGaiaYouAlly, 30, 60);

  /* also adds a permanent aura that adds +5 to attack for cavalry (912) and infantry (906) */
  int permaAuraEffects = cAuraEffectBitCircular + cAuraEffectBitRangeIndicator + cAuraEffectBitAdvancedRangeIndicator;
  bool aura2Added = xsAddAura(629, 912, 1, cAuraAttributeAttack, 5.0, 10.0, permaAuraEffects, cAuraDiplomacyGaiaYouAlly);
  bool aura3Added = xsAddAura(629, 906, 1, cAuraAttributeAttack, 5.0, 10.0, permaAuraEffects, cAuraDiplomacyGaiaYouAlly);

  xsChatData("aura 1 added: " + aura1Added + ", aura 2 added: " + aura2Added + ", aura 3 added: " + aura3Added);
}