Name | Type | is_array | initial_value |
Y_Map_Point | location | Yes | |
Y_Map_Region | rect | Yes | |
Y_Map_Tip | string | Yes | |
Y_Player | player | No | |
Y_Wish_Group | group | Yes |
//TESH.scrollpos=0
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Timer32 ~~ By Jesus4Lyf ~~ Version 1.06 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Timer32?
// - Timer32 implements a fully optimised timer loop for a struct.
// - Instances can be added to the loop, which will call .periodic every
// PERIOD until .stopPeriodic() is called.
//
// =Pros=
// - Efficient.
// - Simple.
//
// =Cons=
// - Only allows one period.
// - The called method must be named ".periodic".
//
// Methods:
// - struct.startPeriodic()
// - struct.stopPeriodic()
//
// - private method periodic takes nothing returns nothing
//
// This must be defined in structs that implement Periodic Module.
// It will be executed by the module every PERIOD until .stopPeriodic() is called.
// Put "implement T32x" BELOW this method.
//
// Modules:
// - T32x
// Has no safety on .stopPeriodic or .startPeriodic (except debug messages
// to warn).
//
// - T32xs
// Has safety on .stopPeriodic and .startPeriodic so if they are called
// multiple times, or while otherwise are already stopped/started respectively,
// no error will occur, the call will be ignored.
//
// - T32
// The original, old version of the T32 module. This remains for backwards
// compatability, and is deprecated. The periodic method must return a boolean,
// false to continue running or true to stop.
//
// Details:
// - Uses one timer.
//
// - Do not, within a .periodic method, follow a .stopPeriodic call with a
// .startPeriodic call.
//
// How to import:
// - Create a trigger named T32.
// - Convert it to custom text and replace the whole trigger text with this.
//
// Thanks:
// - Infinitegde for finding a bug in the debug message that actually altered
// system operation (when in debug mode).
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library T32 initializer OnInit
globals
public constant real PERIOD=0.03125
public constant integer FPS=R2I(1/PERIOD)
public integer Tick=0 // very useful.
//==============================================================================
private trigger Trig=CreateTrigger()
endglobals
//==============================================================================
// The standard T32 module, T32x.
//
module T32x
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
method stopPeriodic takes nothing returns nothing
debug if this.prev==0 and thistype(0).next!=this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had stopPeriodic called while not running!")
debug endif
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// The standard T32 module with added safety checks on .startPeriodic() and
// .stopPeriodic(), T32xs.
//
module T32xs
private thistype next
private thistype prev
private boolean runningPeriodic
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
if not this.runningPeriodic then
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
set this.runningPeriodic=true
endif
endmethod
method stopPeriodic takes nothing returns nothing
if this.runningPeriodic then
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
set this.runningPeriodic=false
endif
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// The original T32 module, for backwards compatability only.
//
module T32 // deprecated.
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
if this.periodic() then
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endif
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// System Core.
//
private function OnExpire takes nothing returns nothing
set Tick=Tick+1
call TriggerEvaluate(Trig)
endfunction
private function OnInit takes nothing returns nothing
call TimerStart(CreateTimer(),PERIOD,true,function OnExpire)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//
// ___ _____ _ _____ _ _ ___
// / __|_ _/_\_ _| | | / __|
// \__ \ | |/ _ \| | | |_| \__ \ By Jesus4Lyf.
// |___/ |_/_/ \_\_| \____/|___/ v 1.3.0
//
// What is Status?
// —————————————————
// Status allows you to apply stuns, silences, disable attacks and much
// more. Status effects based off dummy casted spells are applied 0.0
// seconds after the "add" method is called. Status aims to commoditise
// unit effects in WC3.
//
// Restrictions
// ——————————————
// Disarming spell immune units is not possible. Some status effects will
// not apply to invulnerable units, namely those which are dummy casted.
//
// How to implement?
// ———————————————————
// Create a new trigger called Status, go to 'Edit -> Convert to
// Custom Text', and replace everything that's there with this script.
//
// Save the map, close it, reopen it, and then delete the "!" from the
// FAR left side of the next line (so "runtextmacro" will line up with this line):
// runtextmacro Status__CreateAbilities()
//
// Go to the object editor, and select abilities. Go to Special > Heroes,
// and select Disarm (Both). Change Data - Attacks Prevented to Melee, Ranged.
// For Disarm (Melee), change Attacks Prevented to Melee. For Disarm (Range),
// change Attacks Prevented to Ranged. Object merger has a bug that does not
// allow setting this field automatically.
//
// Methods:
// ——————————
// Statuses (short list):
// - Disable (addDisable, removeDisable, isDisabled)
// - Stun (addStun, removeStun, isStunned)
// - Silence (addSilence, removeSilence, isSilenced)
// - Doom (addDoom, removeDoom, isDoomed)
// - DisarmMelee (addDisarmMelee, removeDisarmMelee, isDisarmedMelee)
// - DisarmRange (addDisarmRange, removeDisarmRange, isDisarmedRange)
// - Disarm (addDisarm, removeDisarm, isDisarmed) // this is both Melee AND Ranged.
// - Immobolise (addImmobolise, removeImmobolise, isImmobolised)
// - Invisible (addInvisible, removeInvisible, isInvisible)
// - Ghost (addGhost, removeGhost, isGhost)
// - Invulnerable (addInvulnerable, removeInvulnerable, isInvulnerable)
// - Immunity (addImmunity, removeImmunity, isImmune)
// - Pause (addPause, removePause, isPaused)
// - Hide (addHide, removeHide, isHidden)
// - Unpath (addUnpath, removeUnpath, isUnpathed)
// - Hex (addHex, removeHex, isHexed)
// - Locust (addLocust, removeLocust, isLocust) // does not remove correctly for flying units, use with caution.
// - NeverMiss (addNeverMiss, removeNeverMiss, isNeverMiss)
// - AlwaysMiss (addAlwaysMiss, removeAlwaysMiss, isAlwaysMiss)
// - Untouchable (addUntouchable, removeUntouchable, isUntouchable) // 100% evasion
// - Banish (addBanish, removeBanish, isBanished)
// - Phase (addPhase, removePhase, isPhased) // clashes with windwalk, interrupts current order
// - ResistantSkin (addResistantSkin, removeResistantSkin, isResistantSkin)
// - ReflectPiercing (addReflectPiercing, removeReflectPiercing, isReflectPiercing)
//
// Bonuses (short list):
// - ArmorBonus (modArmorBonus, getArmorBonus)
// - DamageBonus (modDamageBonus, getDamageBonus)
// - StrBonus (modStrBonus, getStrBonus)
// - AgiBonus (modAgiBonus, getAgiBonus)
// - IntBonus (modIntBonus, getIntBonus)
// - AttackSpeedBonus (modAttackSpeedBonus, getAttackSpeedBonus)
// - Health (modHealthBonus, getHealthBonus)
// - Mana (modManaBonus, getManaBonus)'
// - HealthRegen (modHealthRegenBonus, getHealthRegenBonus)
// - HealthRegenPercent (modHealthRegenPercentBonus, getHealthRegenPercentBonus) // percent of max
// - ManaRegen (modManaRegenBonus, getManaRegenBonus)
// - ManaRegenPercent (modManaRegenPercentBonus, getManaRegenPercentBonus) // percent of max
// - MoveSpeed (modMoveSpeedBonus, getMoveSpeedBonus)
// - MoveSpeedPercent (modMoveSpeedPercentBonus, getMoveSpeedPercentBonus) // percent of current move speed (after normal bonuses).
//
// How to Use:
// —————————————
// Statuses:
// Status[unit].add?()
// - Adds the status effect to the unit.
// - This does not add any animation.
// Status[unit].remove?()
// - Removes the status effect added with .add?().
// - Will not actually remove it until all added instances are removed.
// Status[unit].is?() --> boolean
// - Checks to see whether or not a unit has a status effect applied.
//
// Bonuses:
// Status[unit].mod?(amount)
// - Modifies the bonus by the amount given.
// - Use a negative value to reverse a bonus.
// - Supports giving negative of a bonus.
// Status[unit].get?()
// - Gets the curret total amount for a given bonus.
//
// Thanks:
// —————————
// - Weep: for suggesting that making the ability an ultimate hero ability
// would allow it to stun magic immune units, and suggesting a simpler
// target allowance for the ability.
//
// - 13lade619: for noticing that the PreloadModule was not actually
// implemented, causing first use lag.
//
library Status uses AIDS, DummyCaster, T32
globals
private constant real PERIOD=0.1 // for regen effects.
private constant player DUMMY_CASTER_OWNER=Player(PLAYER_NEUTRAL_PASSIVE)
private constant boolean PERMENANTLY_REVEAL=true // reveal all units always, or only during dummy spells
// To change these, change them also in the externalblock before executing it.
private constant integer ABIL_STUN='A500'
private constant integer ABIL_SILENCE='A501'
private constant integer ABIL_DISARM_BOTH='A502'
private constant integer ABIL_DISARM_MELEE='A503'
private constant integer ABIL_DISARM_RANGE='A504'
private constant integer ABIL_IMMOBOLISE='A505'
private constant integer ABIL_INVISIBLE='A507'
private constant integer ABIL_GHOST='A508'
private constant integer ABIL_DOOM='A509'
private constant integer ABIL_IMMUNITY='A50B'
private constant integer ABIL_HEX='A50C'
private constant integer ABIL_UNLOCUST='A50D'
private constant integer ABIL_NEVER_MISS='A50F'
private constant integer ABIL_ALWAYS_MISS='A50H'
private constant integer ABIL_UNTOUCHABLE='A50J'
private constant integer ABIL_BANISH='A50K'
private constant integer ABIL_PHASE='A50L'
//private constant integer ABIL_DOUBLE_ATTACK='A50O'
private constant integer ABIL_RESISTANT_SKIN='A50Q'
private constant integer ABIL_REFLECT_PIERCING='A50S'
private constant integer ABIL_DISABLE='A50T'
private constant integer ABIL_ARMOR='A5A@'
private constant integer ABIL_DAMAGE='A5B@'
private constant integer ABIL_STR='A5C@'
private constant integer ABIL_AGI='A5D@'
private constant integer ABIL_INT='A5E@'
private constant integer ABIL_ATTACK_SPEED='A5F@'
private constant integer ABIL_HEALTH='A5G@'
private constant integer ABIL_MANA='A5H@'
private constant integer LEVELS_ARMOR=10
private constant integer LEVELS_DAMAGE=15
private constant integer LEVELS_STR=10
private constant integer LEVELS_AGI=10
private constant integer LEVELS_INT=10
private constant integer LEVELS_ATTACK_SPEED=9
private constant integer LEVELS_HEALTH=20
private constant integer LEVELS_MANA=20
// To change these, change them also in the externalblock before executing it.
private constant integer BUFF_STUN='B500'
private constant integer BUFF_SILENCE='B501'
private constant integer BUFF_DOOM='B509'
private constant integer BUFF_DISARM_MELEE='B503'
private constant integer BUFF_DISARM_RANGE='B504'
private constant integer BUFF_DISARM_BOTH='B502'
private constant integer BUFF_IMMOBOLISE_GROUND='B505'
private constant integer BUFF_IMMOBOLISE_AIR='B506'
private constant integer BUFF_HEX='B50C'
private constant integer BUFF_BANISH='B50K'
private constant integer BUFF_PHASE='B50L'
private constant integer BUFF_DISABLE='B50T'
private constant integer OID_STOP=851972 //stop
private constant integer OID_STUN=852231 //firebolt
private constant integer OID_SILENCE=852668 //soulburn
private constant integer OID_DISARM=852585 //drunkenhaze
private constant integer OID_IMMOBOLISE=852106 //ensnare
private constant integer OID_DOOM=852583 //doom
private constant integer OID_HEX=852502 //hex
private constant integer OID_UNLOCUST=852155 //ravenform
private constant integer OID_BANISH=852486 //banish
private constant integer OID_PHASE=852129 //windwalk
private constant integer OID_DISABLE=852252 //creepthunderbolt (hurlboulder)
private unit CASTER_DISARM_BOTH=null
private unit CASTER_DISARM_MELEE=null
private unit CASTER_DISARM_RANGE=null
endglobals
native UnitAlive takes unit id returns boolean
private module PreloadModule
private static method onInit takes nothing returns nothing
local unit u=CreateUnit(DUMMY_CASTER_OWNER,DUMMY_TYPE,0,0,0)
local integer abil
//! textmacro Status__PreloadBonus takes BONUS
set abil=ABIL_$BONUS$+LEVELS_$BONUS$
loop
call UnitAddAbility(u,abil)
exitwhen abil==ABIL_$BONUS$
set abil=abil-1
endloop
//! endtextmacro
call UnitAddAbility(u,ABIL_INVISIBLE)
call UnitAddAbility(u,ABIL_GHOST)
call UnitAddAbility(u,ABIL_IMMUNITY)
call UnitAddAbility(u,ABIL_UNLOCUST)
call UnitAddAbility(u,ABIL_NEVER_MISS)
call UnitAddAbility(u,ABIL_ALWAYS_MISS)
call UnitAddAbility(u,ABIL_UNTOUCHABLE)
call UnitAddAbility(u,ABIL_PHASE)
//call UnitAddAbility(u,ABIL_DOUBLE_ATTACK)
call UnitAddAbility(u,ABIL_RESISTANT_SKIN)
call UnitAddAbility(u,ABIL_REFLECT_PIERCING)
//! runtextmacro Status__PreloadBonus("ARMOR")
//! runtextmacro Status__PreloadBonus("DAMAGE")
//! runtextmacro Status__PreloadBonus("STR")
//! runtextmacro Status__PreloadBonus("AGI")
//! runtextmacro Status__PreloadBonus("INT")
//! runtextmacro Status__PreloadBonus("ATTACK_SPEED")
//! runtextmacro Status__PreloadBonus("HEALTH")
//! runtextmacro Status__PreloadBonus("MANA")
call KillUnit(u)
call RemoveUnit(u)
set u=null
endmethod
endmodule
private module StaticPeriodic
private static method onInit takes nothing returns nothing
call TimerStart(CreateTimer(),PERIOD,true,function thistype.periodicLink)
endmethod
endmodule
private module StatusInit
private static method onInit takes nothing returns nothing
local integer i
//! textmacro Status__CreateAbilities
// For reflecting piercing.
//! externalblock extension=lua ConstantMerger $FILENAME$
//! i setvalue("Misc","DefendDeflection","1")
//! endexternalblock
// Start externalblock
//! externalblock extension=lua ObjectMerger $FILENAME$
////////////////////
// Status Effects //
////////////////////
// Stun (X500, firebolt)
//! i setobjecttype("buffs")
//! i createobject("BPSE","B500")
//! i makechange(current,"frac","other")
//! i makechange(current,"ftip","Stunned")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"fube","This unit is stunned; it cannot move, attack or cast spells.")
//! i makechange(current,"ftat","")
//! i setobjecttype("abilities")
//! i createobject("ACfb","A500")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Stun")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"aani","")
//! i makechange(current,"amat","")
//! i makechange(current,"amsp",0)
//! i makechange(current,"Htb1",1,0)
//! i makechange(current,"aran",1,99999)
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"ahdu",1,0)
//! i makechange(current,"adur",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"invulnerable,vulnerable")
//! i makechange(current,"abuf",1,"B500")
//! i makechange(current,"aher",1)
//! i makechange(current,"arlv",6)
// Silence (X501, soulburn)
//! i setobjecttype("buffs")
//! i createobject("BNso","B501")
//! i makechange(current,"frac","other")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"ftip","Silence")
//! i makechange(current,"fube","This unit is Silenced; it cannot cast spells.")
//! i makechange(current,"fart","ReplaceableTextures\\CommandButtons\\BTNSilence.blp")
//! i makechange(current,"ftat","")
//! i setobjecttype("abilities")
//! i createobject("ANso","A501")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Silence")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"Nso1",1,0)
//! i makechange(current,"Nso3",1,0)
//! i makechange(current,"Nso2",1,99999)
//! i makechange(current,"aran",1,99999)
//! i makechange(current,"abuf",1,"B501")
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"ahdu",1,0)
//! i makechange(current,"adur",1,0)
//! i makechange(current,"arlv",6)
//! i makechange(current,"alev",1)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"invulnerable,vulnerable")
// Disarm (Both) (X502, drunkenhaze)
//! i setobjecttype("buffs")
//! i createobject("BNdh", "B502")
//! i makechange(current,"frac","other")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"ftip","Disarmed")
//! i makechange(current,"fube","This unit is Disarmed; it cannot attack.")
//! i makechange(current,"fart","ReplaceableTextures\\CommandButtons\\BTNBattleStations.blp")
//! i makechange(current,"ftat","")
//! i setobjecttype("abilities")
//! i createobject("ANdh","A502")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Disarm (Both)")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"amat","")
//! i makechange(current,"amac",0)
//! i makechange(current,"amsp",0)
//! i makechange(current,"arlv",6)
//! i makechange(current,"alev",1)
//! i makechange(current,"Nsi2",1,0)
//! i makechange(current,"Nsi3",1,0)
//! i makechange(current,"aare",1,0)
//! i makechange(current,"aran",1,99999)
//! i makechange(current,"abuf",1,"B502")
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"ahdu",1,0)
//! i makechange(current,"adur",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"notself")
// Disarm (Melee) (X503, drunkenhaze)
//! i setobjecttype("buffs")
//! i createobject("BNdh", "B503")
//! i makechange(current,"frac","other")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"ftip","Disarmed (Melee)")
//! i makechange(current,"fube","This unit is Disarmed; it cannot use melee attacks.")
//! i makechange(current,"fart","ReplaceableTextures\\CommandButtons\\BTNBattleStations.blp")
//! i makechange(current,"ftat","")
//! i setobjecttype("abilities")
//! i createobject("ANdh","A503")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Disarm (Melee)")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"amat","")
//! i makechange(current,"amac",0)
//! i makechange(current,"amsp",0)
//! i makechange(current,"arlv",6)
//! i makechange(current,"alev",1)
//! i makechange(current,"Nsi2",1,0)
//! i makechange(current,"Nsi3",1,0)
//! i makechange(current,"aare",1,0)
//! i makechange(current,"aran",1,99999)
//! i makechange(current,"abuf",1,"B503")
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"ahdu",1,0)
//! i makechange(current,"adur",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"notself")
// Disarm (Range) (X504, drunkenhaze)
//! i setobjecttype("buffs")
//! i createobject("BNdh", "B504")
//! i makechange(current,"frac","other")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"ftip","Disarmed (Ranged)")
//! i makechange(current,"fube","This unit is Disarmed; it cannot use ranged attacks.")
//! i makechange(current,"fart","ReplaceableTextures\\CommandButtons\\BTNBattleStations.blp")
//! i makechange(current,"ftat","")
//! i setobjecttype("abilities")
//! i createobject("ANdh","A504")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Disarm (Range)")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"amat","")
//! i makechange(current,"amac",0)
//! i makechange(current,"amsp",0)
//! i makechange(current,"arlv",6)
//! i makechange(current,"alev",1)
//! i makechange(current,"Nsi2",1,0)
//! i makechange(current,"Nsi3",1,0)
//! i makechange(current,"aare",1,0)
//! i makechange(current,"aran",1,99999)
//! i makechange(current,"abuf",1,"B504")
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"ahdu",1,0)
//! i makechange(current,"adur",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"notself")
// Entangle (X505 - X506, ensnare)
//! i setobjecttype("buffs")
//! i createobject("Beng","B505")
//! i makechange(current,"frac","other")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"ftip","Immobilised")
//! i makechange(current,"fube","This unit is immobilised; it cannot move or fly.")
//! i makechange(current,"fart","ReplaceableTextures\\CommandButtons\\BTNWirtsOtherLeg.blp")
//! i makechange(current,"ftat","")
//! i createobject("Bena","B506")
//! i makechange(current,"frac","other")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"ftip","Immobilised")
//! i makechange(current,"fube","This unit is immobilised; it cannot move or fly.")
//! i makechange(current,"fart","ReplaceableTextures\\CommandButtons\\BTNWirtsOtherLeg.blp")
//! i makechange(current,"ftat", "")
//! i setobjecttype("abilities")
//! i createobject("ACen","A505")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Immobilise")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"aani","")
//! i makechange(current,"amat","")
//! i makechange(current,"amsp",0)
//! i makechange(current,"aher",1)
//! i makechange(current,"arlv",6)
//! i makechange(current,"alev",1)
//! i makechange(current,"areq","")
//! i makechange(current,"Ens1",1,-1)
//! i makechange(current,"Ens2",1,-1)
//! i makechange(current,"aran",1,99999)
//! i makechange(current,"abuf",1,"B505,B506")
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"ahdu",1,0)
//! i makechange(current,"adur",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"notself")
// Invisibility (X507)
//! i setobjecttype("abilities")
//! i createobject("Apiv","A507")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Invisibility")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"ahdu",1,0.5)
//! i makechange(current,"adur",1,0.5)
// Ghost (X508)
//! i setobjecttype("abilities")
//! i createobject("Agho","A508")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Ghost")
//! i makechange(current,"ansf","(Status System)")
// Doom (X509, doom)
//! i setobjecttype("buffs")
//! i createobject("BNdo","B509")
//! i makechange(current,"frac","other")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"ftat","")
//! i makechange(current,"fube","This unit has been stricken with Doom; it cannot cast spells.")
//! i setobjecttype("abilities")
//! i createobject("ANdo","A509")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Doom")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"aani","")
//! i makechange(current,"Ndo1",1,0)
//! i makechange(current,"Ndo2",1,0)
//! i makechange(current,"Ndo3",1,0)
//! i makechange(current,"aran",1,99999)
//! i makechange(current,"abuf",1,"B509")
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"notself")
// Spell Immunity (X50A - X50B)
//! i setobjecttype("abilities")
//! i createobject("Amim","A50A")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Spell Immunity")
//! i makechange(current,"ansf","(Status System)")
//! i createobject("Aspb","A50B")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Spell Immunity")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"spb5",1,"")
//! i makechange(current,"spb4",1,1)
//! i makechange(current,"spb3",1,1)
//! i makechange(current,"spb1",1,"A50A")
// Hex (X50C, hex)
//! i setobjecttype("buffs")
//! i createobject("BOhx","B50C")
//! i makechange(current,"frac","other")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"feat","")
//! i setobjecttype("abilities")
//! i createobject("AOhx","A50C")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Hex")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"aani","")
//! i makechange(current,"asat","")
//! i makechange(current,"alev",1)
//! i makechange(current,"arlv",6)
//! i makechange(current,"aran",1,99999)
//! i makechange(current,"abuf",1,"B50C")
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"notself")
//! i makechange(current,"ahdu",1,0)
//! i makechange(current,"adur",1,0)
// Unlocust (X50D, crowform)
//! i setobjecttype("abilities")
//! i createobject("Amrf","A50D")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Unlocust")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"aani","")
//! i makechange(current,"Eme3",1,-1)
//! i makechange(current,"Eme4",1,-1)
//! i makechange(current,"acas",1,0)
//! i makechange(current,"adur",1,0)
// Never Miss (X50E - X50F)
//! i setobjecttype("abilities")
//! i createobject("ACct","A50E")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Never Miss")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"aani","")
//! i makechange(current,"Ocr1",1,100)
//! i makechange(current,"Ocr2",1,0)
//! i makechange(current,"Ocr5",1,1)
//! i makechange(current,"atar",1,"notself")
//! i createobject("Aspb","A50F")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Never Miss")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"spb5",1,"")
//! i makechange(current,"spb4",1,1)
//! i makechange(current,"spb3",1,1)
//! i makechange(current,"spb1",1,"A50E")
// Always Miss (X50G - X50H)
//! i setobjecttype("abilities")
//! i createobject("ACbh","A50G")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Always Miss")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"aani","")
//! i makechange(current,"Hbh1",1,0)
//! i makechange(current,"Hbh4",1,100)
//! i makechange(current,"atar",1,"notself")
//! i createobject("Aspb","A50H")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Always Miss")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"spb5",1,"")
//! i makechange(current,"spb4",1,1)
//! i makechange(current,"spb3",1,1)
//! i makechange(current,"spb1",1,"A50G")
// Untouchable (X50I - X50J)
//! i setobjecttype("abilities")
//! i createobject("ACes","A50I")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Untouchable")
//! i makechange(current,"ansf","(Status System)")
//! i createobject("Aspb","A50J")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Untouchable")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"spb5",1,"")
//! i makechange(current,"spb4",1,1)
//! i makechange(current,"spb3",1,1)
//! i makechange(current,"spb1",1,"A50I")
// Banish (X50K, banish)
//! i setobjecttype("buffs")
//! i createobject("BNdo","B50K")
//! i makechange(current,"frac","other")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"ftat","")
//! i makechange(current,"fefl","")
//! i setobjecttype("abilities")
//! i createobject("AHbn","A50K")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Banish")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"aani","")
//! i makechange(current,"aefs","")
//! i makechange(current,"alev",1)
//! i makechange(current,"arlv",6)
//! i makechange(current,"Hbn1",1,0)
//! i makechange(current,"aran",1,99999)
//! i makechange(current,"abuf",1,"B50K")
//! i makechange(current,"ahdu",1,0)
//! i makechange(current,"adur",1,0)
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"notself")
// Phase (X50L, windwalk)
//! i setobjecttype("buffs")
//! i createobject("BOwk","B50L")
//! i makechange(current,"frac","other")
//! i makechange(current,"ftip","Phase")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"fube","This unit is Phasing; it can walk through other units.")
//! i makechange(current,"fart","ReplaceableTextures\\CommandButtons\\BTNMirrorImage.blp")
//! i setobjecttype("abilities")
//! i createobject("ANwk","A50L")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Phase")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"aefs","")
//! i makechange(current,"Owk3",1,0)
//! i makechange(current,"Owk4",1,0)
//! i makechange(current,"Owk2",1,0)
//! i makechange(current,"Owk1",1,-1)
//! i makechange(current,"abuf",1,"B50L")
//! i makechange(current,"ahdu",1,0)
//! i makechange(current,"adur",1,0)
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"aher",0)
/*
// Double Attack (X50M - X50O)
//! i setobjecttype("abilities")
//! i createobject("ACsa","A50M")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Double Attack")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"amat","")
//! i makechange(current,"Hfa1",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"invulnerable,vulnerable")
//! i createobject("AIll","A50N")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Double Attack")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"amat","")
//! i makechange(current,"asat","")
//! i makechange(current,"atat","")
//! i makechange(current,"Iob2",1,100)
//! i makechange(current,"Iob3",1,100)
//! i makechange(current,"Iob4",1,100)
//! i makechange(current,"Idam",1,0)
//! i makechange(current,"Iobu",1,"A50M")
//! i makechange(current,"atar",1,"invulnerable,vulnerable")
//! i createobject("Aspb","A50O")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Double Attack")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"spb5",1,"")
//! i makechange(current,"spb4",1,1)
//! i makechange(current,"spb3",1,1)
//! i makechange(current,"spb1",1,"A50N")
*/
// Resistant Skin (X50P - X50Q)
//! i setobjecttype("abilities")
//! i createobject("ACrk","A50P")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Resistant Skin")
//! i makechange(current,"ansf","(Status System)")
//! i createobject("Aspb","A50Q")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Resistant Skin")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"spb5",1,"")
//! i makechange(current,"spb4",1,1)
//! i makechange(current,"spb3",1,1)
//! i makechange(current,"spb1",1,"A50P")
// Reflect Piercing (X50R - X50S)
//! i setobjecttype("abilities")
//! i createobject("Aegr","A50R")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Reflect Piercing")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"Def6",1,100)
//! i makechange(current,"Def1",1,1)
//! i makechange(current,"Def7",1,0)
//! i makechange(current,"Def5",1,0)
//! i createobject("Aspb","A50S")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Reflect Piercing")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"spb5",1,"")
//! i makechange(current,"spb4",1,1)
//! i makechange(current,"spb3",1,1)
//! i makechange(current,"spb1",1,"A50R")
// Disable (X50T, creepthunderbolt (hurlboulder))
//! i setobjecttype("buffs")
//! i createobject("BPSE","B50T")
//! i makechange(current,"frac","other")
//! i makechange(current,"ftip","Disabled")
//! i makechange(current,"fube","This unit is Disabled; it cannot do anything.")
//! i makechange(current,"fnsf","(Status System)")
//! i makechange(current,"fart","ReplaceableTextures\\CommandButtons\\BTNReplay-Pause.blp")
//! i makechange(current,"ftat","")
//! i setobjecttype("abilities")
//! i createobject("ACtb","A50T")
//! i makechange(current,"aart","")
//! i makechange(current,"arac","other")
//! i makechange(current,"anam","Disable")
//! i makechange(current,"ansf","(Status System)")
//! i makechange(current,"aani","")
//! i makechange(current,"amat","")
//! i makechange(current,"amsp",0)
//! i makechange(current,"Ctb1",1,0)
//! i makechange(current,"aran",1,99999)
//! i makechange(current,"acdn",1,0)
//! i makechange(current,"ahdu",1,0)
//! i makechange(current,"adur",1,0)
//! i makechange(current,"amcs",1,0)
//! i makechange(current,"atar",1,"invulnerable,vulnerable")
//! i makechange(current,"abuf",1,"B50T")
//! i makechange(current,"aher",1)
//! i makechange(current,"arlv",6)
////////////////////
// Status Bonuses //
////////////////////
//! i setobjecttype("abilities")
//! i myChar={}
//! i myChar[1]="A"
//! i myChar[2]="B"
//! i myChar[3]="C"
//! i myChar[4]="D"
//! i myChar[5]="E"
//! i myChar[6]="F"
//! i myChar[7]="G"
//! i myChar[8]="H"
//! i myChar[9]="I"
//! i myChar[10]="J"
//! i myChar[11]="K"
//! i myChar[12]="L"
//! i myChar[13]="M"
//! i myChar[14]="N"
//! i myChar[15]="O"
//! i myChar[16]="P"
//! i myChar[17]="Q"
//! i myChar[18]="R"
//! i myChar[19]="S"
//! i myChar[20]="T"
//! i myChar[21]="U"
//! i myChar[22]="V"
//! i myChar[23]="W"
//! i myChar[24]="X"
//! i myChar[25]="Y"
//! i myChar[26]="Z"
//! i myBin={}
//! i myBin[1]=1
//! i myBin[2]=2
//! i myBin[3]=4
//! i myBin[4]=8
//! i myBin[5]=16
//! i myBin[6]=32
//! i myBin[7]=64
//! i myBin[8]=128
//! i myBin[9]=256
//! i myBin[10]=512
//! i myBin[11]=1024
//! i myBin[12]=2048
//! i myBin[13]=4096
//! i myBin[14]=8192
//! i myBin[15]=16384
//! i myBin[16]=32768
//! i myBin[17]=65536
//! i myBin[18]=131072
//! i myBin[19]=262144
//! i myBin[20]=524288
//! i myBin[21]=1048576
//! i myBin[22]=2097152
//! i myBin[23]=4194304
//! i myBin[24]=8388608
//! i myBin[25]=16777216
//! i myBin[26]=33554432
// Armor (10 = 1023 max)
//! i for i=1,10 do
//! i createobject("AId1","A5A"..myChar[i])
//! i makechange(current,"Idef",1,myBin[i])
//! i makechange(current,"anam","Armor Bonus")
//! i makechange(current,"ansf","(Status System)")
//! i end
//! i createobject("AId1","A5A@")
//! i makechange(current,"Idef",1,-myBin[11])
//! i makechange(current,"anam","Armor Bonus")
//! i makechange(current,"ansf","(Status System)")
// Damage (15 = 32767 max)
//! i for i=1,15 do
//! i createobject("AItg","A5B"..myChar[i])
//! i makechange(current,"Iatt",1,myBin[i])
//! i makechange(current,"anam","Damage Bonus")
//! i makechange(current,"ansf","(Status System)")
//! i end
//! i createobject("AItg","A5B@")
//! i makechange(current,"Iatt",1,-myBin[16])
//! i makechange(current,"anam","Damage Bonus")
//! i makechange(current,"ansf","(Status System)")
// Str/Agi/Int (10 = 1023 max)
//! i for i=1,10 do
//! i createobject("AIs1","A5C"..myChar[i])
//! i makechange(current,"Istr",1,myBin[i])
//! i makechange(current,"anam","Strength Bonus")
//! i makechange(current,"ansf","(Status System)")
//! i createobject("AIa1","A5D"..myChar[i])
//! i makechange(current,"Iagi",1,myBin[i])
//! i makechange(current,"anam","Agility Bonus")
//! i makechange(current,"ansf","(Status System)")
//! i createobject("AIi1","A5E"..myChar[i])
//! i makechange(current,"Iint",1,myBin[i])
//! i makechange(current,"anam","Intelligence Bonus")
//! i makechange(current,"ansf","(Status System)")
//! i end
//! i createobject("AIs1","A5C@")
//! i makechange(current,"Istr",1,-myBin[11])
//! i makechange(current,"anam","Strength Bonus")
//! i makechange(current,"ansf","(Status System)")
//! i createobject("AIa1","A5D@")
//! i makechange(current,"Iagi",1,-myBin[11])
//! i makechange(current,"anam","Agility Bonus")
//! i makechange(current,"ansf","(Status System)")
//! i createobject("AIi1","A5E@")
//! i makechange(current,"Iint",1,-myBin[11])
//! i makechange(current,"anam","Intelligence Bonus")
//! i makechange(current,"ansf","(Status System)")
// Attack Speed (9 = 511% max)
//! i for i=1,9 do
//! i createobject("AIsx","A5F"..myChar[i])
//! i makechange(current,"Isx1",1,myBin[i]*0.01)
//! i makechange(current,"anam","Attack Speed Bonus")
//! i makechange(current,"ansf","(Status System)")
//! i end
//! i createobject("AIsx","A5F@")
//! i makechange(current,"Isx1",1,-myBin[10]*0.01)
//! i makechange(current,"anam","Attack Speed Bonus")
//! i makechange(current,"ansf","(Status System)")
// Max HP (20 = 1048575 max)
//! i for i=1,20 do
//! i createobject("AIl2","A5G"..myChar[i])
//! i makechange(current,"Ilif",1,myBin[i])
//! i makechange(current,"anam","Health Bonus")
//! i makechange(current,"ansf","(Status System)")
//! i end
//! i createobject("AIl2","A5G@")
//! i makechange(current,"Ilif",1,-myBin[21])
//! i makechange(current,"anam","Health Bonus")
//! i makechange(current,"ansf","(Status System)")
// Max Mana (20 = 1048575 max)
//! i for i=1,20 do
//! i createobject("AImz","A5H"..myChar[i])
//! i makechange(current,"Iman",1,myBin[i])
//! i makechange(current,"anam","Mana Bonus")
//! i makechange(current,"ansf","(Status System)")
//! i end
//! i createobject("AImz","A5H@")
//! i makechange(current,"Iman",1,-myBin[21])
//! i makechange(current,"anam","Mana Bonus")
//! i makechange(current,"ansf","(Status System)")
// End externalblock
//! endexternalblock
//! endtextmacro
set thistype.dummyCaster=CreateUnit(DUMMY_CASTER_OWNER,DUMMY_TYPE,0,0,0)
set thistype.dummyCaster2=CreateUnit(DUMMY_CASTER_OWNER,DUMMY_TYPE,0,0,0)
set thistype.dummyCaster3=CreateUnit(DUMMY_CASTER_OWNER,DUMMY_TYPE,0,0,0)
call UnitAddAbility(thistype.dummyCaster,ABIL_STUN)
call UnitAddAbility(thistype.dummyCaster,ABIL_DISABLE)
call UnitAddAbility(thistype.dummyCaster,ABIL_SILENCE)
set CASTER_DISARM_BOTH=thistype.dummyCaster
set CASTER_DISARM_MELEE=thistype.dummyCaster2
set CASTER_DISARM_RANGE=thistype.dummyCaster3
call UnitAddAbility(CASTER_DISARM_BOTH,ABIL_DISARM_BOTH)
call UnitAddAbility(CASTER_DISARM_MELEE,ABIL_DISARM_MELEE)
call UnitAddAbility(CASTER_DISARM_RANGE,ABIL_DISARM_RANGE)
call UnitAddAbility(thistype.dummyCaster,ABIL_IMMOBOLISE)
call UnitAddAbility(thistype.dummyCaster,ABIL_DOOM)
call UnitAddAbility(thistype.dummyCaster,ABIL_HEX)
call UnitAddAbility(thistype.dummyCaster,ABIL_BANISH)
set i=bj_MAX_PLAYERS
loop
set i=i-1
call SetPlayerAbilityAvailable(Player(i),ABIL_IMMUNITY,false)
call SetPlayerAbilityAvailable(Player(i),ABIL_NEVER_MISS,false)
call SetPlayerAbilityAvailable(Player(i),ABIL_ALWAYS_MISS,false)
call SetPlayerAbilityAvailable(Player(i),ABIL_UNTOUCHABLE,false)
//call SetPlayerAbilityAvailable(Player(i),ABIL_DOUBLE_ATTACK,false)
call SetPlayerAbilityAvailable(Player(i),ABIL_RESISTANT_SKIN,false)
call SetPlayerAbilityAvailable(Player(i),ABIL_REFLECT_PIERCING,false)
exitwhen i==0
endloop
endmethod
endmodule
private module TwoPowArray
readonly static integer array twoPow
private static method onInit takes nothing returns nothing
local integer i=0
local integer val=1
loop
set thistype.twoPow[i]=val // thistype.twoPow[0]=1
exitwhen i==30
set i=i+1
set val=val*2
endloop
endmethod
endmodule
struct Status extends array
private method AIDS_onCreate takes nothing returns nothing
static if PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
set this.disableLevel=0
set this.stunLevel=0
set this.silenceLevel=0
set this.doomLevel=0
set this.disarmMeleeLevel=0
set this.disarmRangeLevel=0
set this.immoboliseLevel=0
set this.invisibleLevel=0
set this.ghostLevel=0
set this.invulnerableLevel=0
set this.immunityLevel=0
set this.pauseLevel=0
set this.hideLevel=0
set this.unpathLevel=0
set this.hexLevel=0
set this.locustLevel=0
set this.neverMissLevel=0
set this.alwaysMissLevel=0
set this.untouchableLevel=0
set this.banishLevel=0
set this.phaseLevel=0
set this.resistantSkinLevel=0
set this.reflectPiercingLevel=0
set this.armorBonus=0
set this.damageBonus=0
set this.strBonus=0
set this.agiBonus=0
set this.intBonus=0
set this.attackSpeedBonus=0
set this.healthBonus=0
set this.manaBonus=0
set this.healthRegenBonus=0
set this.manaRegenBonus=0
set this.healthRegenPercentBonus=0
set this.manaRegenPercentBonus=0
set this.moveSpeedBonus=0.0
set this.moveSpeedPercentBonus=0.0
call this.stopPeriodic()
endmethod
private static unit dummyCaster=null
private static unit dummyCaster2=null
private static unit dummyCaster3=null
implement StatusInit
implement TwoPowArray
implement PreloadModule
////////////////////
// Status Effects //
////////////////////
// Stun
private integer stunLevel
method addStun takes nothing returns nothing
set this.stunLevel=this.stunLevel+1
if this.stunLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(thistype.dummyCaster,OID_STUN,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endmethod
method removeStun takes nothing returns nothing
set this.stunLevel=this.stunLevel-1
if this.stunLevel==0 then
call UnitRemoveAbility(this.unit,BUFF_STUN)
endif
endmethod
method isStunned takes nothing returns boolean
return this.stunLevel>0
endmethod
// Disable
private integer disableLevel
method addDisable takes nothing returns nothing
set this.disableLevel=this.disableLevel+1
if this.disableLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(thistype.dummyCaster,OID_DISABLE,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endmethod
method removeDisable takes nothing returns nothing
set this.disableLevel=this.disableLevel-1
if this.disableLevel==0 then
call UnitRemoveAbility(this.unit,BUFF_DISABLE)
debug elseif this.disableLevel<0 then
debug call BJDebugMsg("Status Error - More disables removed than previously added.")
endif
endmethod
method isDisabled takes nothing returns boolean
return this.disableLevel>0
endmethod
// Silence
private integer silenceLevel
method addSilence takes nothing returns nothing
set this.silenceLevel=this.silenceLevel+1
if this.silenceLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(thistype.dummyCaster,OID_SILENCE,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endmethod
method removeSilence takes nothing returns nothing
set this.silenceLevel=this.silenceLevel-1
if this.silenceLevel==0 then
call UnitRemoveAbility(this.unit,BUFF_SILENCE)
endif
endmethod
method isSilenced takes nothing returns boolean
return this.silenceLevel>0
endmethod
private integer doomLevel
method addDoom takes nothing returns nothing
set this.doomLevel=this.doomLevel+1
if this.doomLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(thistype.dummyCaster,OID_DOOM,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endmethod
method removeDoom takes nothing returns nothing
set this.doomLevel=this.doomLevel-1
if this.doomLevel==0 then
call UnitRemoveAbility(this.unit,BUFF_DOOM)
endif
endmethod
method isDoomed takes nothing returns boolean
return this.doomLevel>0
endmethod
// Disarm (Melee)
private integer disarmMeleeLevel
private integer disarmRangeLevel
method addDisarmMelee takes nothing returns nothing
set this.disarmMeleeLevel=this.disarmMeleeLevel+1
if this.disarmMeleeLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
if this.disarmRangeLevel>0 then
call UnitRemoveAbility(this.unit,BUFF_DISARM_RANGE)
call IssueTargetOrderById(CASTER_DISARM_BOTH,OID_DISARM,this.unit)
else
call IssueTargetOrderById(CASTER_DISARM_MELEE,OID_DISARM,this.unit)
endif
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endmethod
method addDisarmRange takes nothing returns nothing
set this.disarmRangeLevel=this.disarmRangeLevel+1
if this.disarmRangeLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
if this.disarmMeleeLevel>0 then
call UnitRemoveAbility(this.unit,BUFF_DISARM_MELEE)
call IssueTargetOrderById(CASTER_DISARM_BOTH,OID_DISARM,this.unit)
else
call IssueTargetOrderById(CASTER_DISARM_RANGE,OID_DISARM,this.unit)
endif
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endmethod
method addDisarm takes nothing returns nothing
set this.disarmMeleeLevel=this.disarmMeleeLevel+1
set this.disarmRangeLevel=this.disarmRangeLevel+1
if this.disarmMeleeLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
if this.disarmRangeLevel>0 then
call UnitRemoveAbility(this.unit,BUFF_DISARM_RANGE)
call UnitRemoveAbility(this.unit,BUFF_DISARM_MELEE)
call IssueTargetOrderById(CASTER_DISARM_BOTH,OID_DISARM,this.unit)
else
call IssueTargetOrderById(CASTER_DISARM_MELEE,OID_DISARM,this.unit)
endif
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
else
if this.disarmRangeLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(CASTER_DISARM_RANGE,OID_DISARM,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endif
endmethod
method removeDisarmMelee takes nothing returns nothing
set this.disarmMeleeLevel=this.disarmMeleeLevel-1
if this.disarmMeleeLevel==0 then
if this.disarmRangeLevel>0 then
call UnitRemoveAbility(this.unit,BUFF_DISARM_BOTH)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(CASTER_DISARM_RANGE,OID_DISARM,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
else
call UnitRemoveAbility(this.unit,BUFF_DISARM_MELEE)
endif
endif
endmethod
method removeDisarmRange takes nothing returns nothing
set this.disarmRangeLevel=this.disarmRangeLevel-1
if this.disarmRangeLevel==0 then
if this.disarmMeleeLevel>0 then
call UnitRemoveAbility(this.unit,BUFF_DISARM_BOTH)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(CASTER_DISARM_MELEE,OID_DISARM,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
else
call UnitRemoveAbility(this.unit,BUFF_DISARM_RANGE)
endif
endif
endmethod
method removeDisarm takes nothing returns nothing
set this.disarmMeleeLevel=this.disarmMeleeLevel-1
set this.disarmRangeLevel=this.disarmRangeLevel-1
if this.disarmMeleeLevel==0 then
call UnitRemoveAbility(this.unit,BUFF_DISARM_BOTH)
call UnitRemoveAbility(this.unit,BUFF_DISARM_MELEE)
if this.disarmRangeLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(CASTER_DISARM_RANGE,OID_DISARM,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
elseif this.disarmRangeLevel==0 then
call UnitRemoveAbility(this.unit,BUFF_DISARM_BOTH)
call UnitRemoveAbility(this.unit,BUFF_DISARM_RANGE)
if this.disarmMeleeLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(CASTER_DISARM_MELEE,OID_DISARM,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endif
endmethod
method isDisarmedMelee takes nothing returns boolean
return this.disarmMeleeLevel>0
endmethod
method isDisarmedRange takes nothing returns boolean
return this.disarmRangeLevel>0
endmethod
method isDisarmed takes nothing returns boolean
return this.disarmMeleeLevel>0 and this.disarmRangeLevel>0
endmethod
// Immobolise
private integer immoboliseLevel
method addImmobolise takes nothing returns nothing
set this.immoboliseLevel=this.immoboliseLevel+1
if this.immoboliseLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(thistype.dummyCaster,OID_IMMOBOLISE,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endmethod
method removeImmobolise takes nothing returns nothing
set this.immoboliseLevel=this.immoboliseLevel-1
if this.immoboliseLevel==0 then
call UnitRemoveAbility(this.unit,BUFF_IMMOBOLISE_GROUND)
call UnitRemoveAbility(this.unit,BUFF_IMMOBOLISE_AIR)
endif
endmethod
method isImmobolised takes nothing returns boolean
return this.immoboliseLevel>0
endmethod
// Invisibility
private integer invisibleLevel
method addInvisible takes nothing returns nothing
set this.invisibleLevel=this.invisibleLevel+1
if this.invisibleLevel>0 then
call UnitAddAbility(this.unit,ABIL_INVISIBLE)
call UnitMakeAbilityPermanent(this.unit,true,ABIL_INVISIBLE)
endif
endmethod
method removeInvisible takes nothing returns nothing
set this.invisibleLevel=this.invisibleLevel-1
if this.invisibleLevel==0 then
call UnitMakeAbilityPermanent(this.unit,false,ABIL_INVISIBLE)
call UnitRemoveAbility(this.unit,ABIL_INVISIBLE)
endif
endmethod
method isInvisible takes nothing returns boolean
return this.invisibleLevel>0
endmethod
// Ghost
private integer ghostLevel
method addGhost takes nothing returns nothing
set this.ghostLevel=this.ghostLevel+1
if this.ghostLevel>0 then
call UnitAddAbility(this.unit,ABIL_GHOST)
call UnitMakeAbilityPermanent(this.unit,true,ABIL_GHOST)
endif
endmethod
method removeGhost takes nothing returns nothing
set this.ghostLevel=this.ghostLevel-1
if this.ghostLevel==0 then
call UnitMakeAbilityPermanent(this.unit,false,ABIL_GHOST)
call UnitRemoveAbility(this.unit,ABIL_GHOST)
endif
endmethod
method isGhost takes nothing returns boolean
return this.ghostLevel>0
endmethod
// Invulnerability
private integer invulnerableLevel
method addInvulnerable takes nothing returns nothing
set this.invulnerableLevel=this.invulnerableLevel+1
if this.invulnerableLevel>0 then
call SetUnitInvulnerable(this.unit,true)
endif
endmethod
method removeInvulnerable takes nothing returns nothing
set this.invulnerableLevel=this.invulnerableLevel-1
if this.invulnerableLevel==0 then
call SetUnitInvulnerable(this.unit,false)
endif
endmethod
method isInvulnerable takes nothing returns boolean
return this.invulnerableLevel>0
endmethod
// Spell Immunity
private integer immunityLevel
method addImmunity takes nothing returns nothing
set this.immunityLevel=this.immunityLevel+1
if this.immunityLevel>0 then
call UnitAddAbility(this.unit,ABIL_IMMUNITY)
call UnitMakeAbilityPermanent(this.unit,true,ABIL_IMMUNITY)
endif
endmethod
method removeImmunity takes nothing returns nothing
set this.immunityLevel=this.immunityLevel-1
if this.immunityLevel==0 then
call UnitMakeAbilityPermanent(this.unit,false,ABIL_IMMUNITY)
call UnitRemoveAbility(this.unit,ABIL_IMMUNITY)
endif
endmethod
method isImmune takes nothing returns boolean
return this.immunityLevel>0
endmethod
// Pause
private integer pauseLevel
method addPause takes nothing returns nothing
set this.pauseLevel=this.pauseLevel+1
if this.pauseLevel>0 then
call PauseUnit(this.unit,true)
endif
endmethod
method removePause takes nothing returns nothing
set this.pauseLevel=this.pauseLevel-1
if this.pauseLevel==0 then
call PauseUnit(this.unit,false)
endif
endmethod
method isPaused takes nothing returns boolean
return this.pauseLevel>0
endmethod
// Hide
private integer hideLevel
method addHide takes nothing returns nothing
set this.hideLevel=this.hideLevel+1
if this.hideLevel>0 then
call ShowUnit(this.unit,false)
endif
endmethod
method removeHide takes nothing returns nothing
set this.hideLevel=this.hideLevel-1
if this.hideLevel==0 then
call ShowUnit(this.unit,true)
endif
endmethod
method isHidden takes nothing returns boolean
return this.hideLevel>0
endmethod
// Unpath
private integer unpathLevel
method addUnpath takes nothing returns nothing
set this.unpathLevel=this.unpathLevel+1
if this.unpathLevel>0 then
call SetUnitPathing(this.unit,false)
endif
endmethod
method removeUnpath takes nothing returns nothing
set this.unpathLevel=this.unpathLevel-1
if this.unpathLevel==0 then
call SetUnitPathing(this.unit,true)
endif
endmethod
method isUnpathed takes nothing returns boolean
return this.unpathLevel>0
endmethod
// Hex
private integer hexLevel
method addHex takes nothing returns nothing
set this.hexLevel=this.hexLevel+1
if this.hexLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(thistype.dummyCaster,OID_HEX,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endmethod
method removeHex takes nothing returns nothing
set this.hexLevel=this.hexLevel-1
if this.hexLevel==0 then
call UnitRemoveAbility(this.unit,BUFF_HEX)
endif
endmethod
method isHexed takes nothing returns boolean
return this.hexLevel>0
endmethod
// Locust
private integer locustLevel
method addLocust takes nothing returns nothing
set this.locustLevel=this.locustLevel+1
if this.locustLevel>0 then
call UnitAddAbility(this.unit,'Aloc')
call UnitMakeAbilityPermanent(this.unit,true,'Aloc')
endif
endmethod
method removeLocust takes nothing returns nothing
set this.locustLevel=this.locustLevel-1
if this.locustLevel==0 then
call ShowUnit(this.unit,false)
call UnitMakeAbilityPermanent(this.unit,false,'Aloc')
call UnitRemoveAbility(this.unit,'Aloc')
call ShowUnit(this.unit,true)
call UnitAddAbility(this.unit,ABIL_UNLOCUST)
call UnitMakeAbilityPermanent(this.unit,true,ABIL_UNLOCUST)
call IssueImmediateOrderById(this.unit,OID_UNLOCUST)
call UnitMakeAbilityPermanent(this.unit,false,ABIL_UNLOCUST)
call UnitRemoveAbility(this.unit,ABIL_UNLOCUST)
endif
endmethod
method isLocust takes nothing returns boolean
return this.locustLevel>0
endmethod
// Never Miss
private integer neverMissLevel
method addNeverMiss takes nothing returns nothing
set this.neverMissLevel=this.neverMissLevel+1
if this.neverMissLevel>0 then
call UnitAddAbility(this.unit,ABIL_NEVER_MISS)
call UnitMakeAbilityPermanent(this.unit,true,ABIL_NEVER_MISS)
endif
endmethod
method removeNeverMiss takes nothing returns nothing
set this.neverMissLevel=this.neverMissLevel-1
if this.neverMissLevel==0 then
call UnitMakeAbilityPermanent(this.unit,false,ABIL_NEVER_MISS)
call UnitRemoveAbility(this.unit,ABIL_NEVER_MISS)
endif
endmethod
method isNeverMiss takes nothing returns boolean
return this.neverMissLevel>0
endmethod
// Always Miss
private integer alwaysMissLevel
method addAlwaysMiss takes nothing returns nothing
set this.alwaysMissLevel=this.alwaysMissLevel+1
if this.alwaysMissLevel>0 then
call UnitAddAbility(this.unit,ABIL_ALWAYS_MISS)
call UnitMakeAbilityPermanent(this.unit,true,ABIL_ALWAYS_MISS)
endif
endmethod
method removeAlwaysMiss takes nothing returns nothing
set this.alwaysMissLevel=this.alwaysMissLevel-1
if this.alwaysMissLevel==0 then
call UnitMakeAbilityPermanent(this.unit,false,ABIL_ALWAYS_MISS)
call UnitRemoveAbility(this.unit,ABIL_ALWAYS_MISS)
endif
endmethod
method isAlwaysMiss takes nothing returns boolean
return this.alwaysMissLevel>0
endmethod
// Untouchable
private integer untouchableLevel
method addUntouchable takes nothing returns nothing
set this.untouchableLevel=this.untouchableLevel+1
if this.untouchableLevel>0 then
call UnitAddAbility(this.unit,ABIL_UNTOUCHABLE)
call UnitMakeAbilityPermanent(this.unit,true,ABIL_UNTOUCHABLE)
endif
endmethod
method removeUntouchable takes nothing returns nothing
set this.untouchableLevel=this.untouchableLevel-1
if this.untouchableLevel==0 then
call UnitMakeAbilityPermanent(this.unit,false,ABIL_UNTOUCHABLE)
call UnitRemoveAbility(this.unit,ABIL_UNTOUCHABLE)
endif
endmethod
method isUntouchable takes nothing returns boolean
return this.untouchableLevel>0
endmethod
// Banish
private integer banishLevel
method addBanish takes nothing returns nothing
set this.banishLevel=this.banishLevel+1
if this.banishLevel>0 then
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,true)
endif
call IssueTargetOrderById(thistype.dummyCaster,OID_BANISH,this.unit)
static if not PERMENANTLY_REVEAL then
call UnitShareVision(this.unit,DUMMY_CASTER_OWNER,false)
endif
endif
endmethod
method removeBanish takes nothing returns nothing
set this.banishLevel=this.banishLevel-1
if this.banishLevel==0 then
call UnitRemoveAbility(this.unit,BUFF_BANISH)
endif
endmethod
method isBanished takes nothing returns boolean
return this.banishLevel>0
endmethod
// Phase
private integer phaseLevel
method addPhase takes nothing returns nothing
set this.phaseLevel=this.phaseLevel+1
if this.phaseLevel>0 then
call SetPlayerAbilityAvailable(GetOwningPlayer(this.unit),ABIL_PHASE,true)
if UnitAddAbility(this.unit,ABIL_PHASE) then
call UnitMakeAbilityPermanent(this.unit,true,ABIL_PHASE)
endif
call IssueImmediateOrderById(this.unit,OID_PHASE)
call SetPlayerAbilityAvailable(GetOwningPlayer(this.unit),ABIL_PHASE,false)
endif
endmethod
method removePhase takes nothing returns nothing
set this.phaseLevel=this.phaseLevel-1
if this.phaseLevel==0 then
call UnitRemoveAbility(this.unit,BUFF_PHASE)
endif
endmethod
method isPhased takes nothing returns boolean
return this.phaseLevel>0
endmethod
/*
// Double Attack
private integer doubleAttackLevel
method addDoubleAttack takes nothing returns nothing
set this.doubleAttackLevel=this.doubleAttackLevel+1
if this.doubleAttackLevel>0 then
call UnitAddAbility(this.unit,ABIL_DOUBLE_ATTACK)
call UnitMakeAbilityPermanent(this.unit,true,ABIL_DOUBLE_ATTACK)
endif
endmethod
method removeDoubleAttack takes nothing returns nothing
set this.doubleAttackLevel=this.doubleAttackLevel-1
if this.doubleAttackLevel==0 then
call UnitMakeAbilityPermanent(this.unit,false,ABIL_DOUBLE_ATTACK)
call UnitRemoveAbility(this.unit,ABIL_DOUBLE_ATTACK)
endif
endmethod
method isDoubleAttack takes nothing returns boolean
return this.doubleAttackLevel>0
endmethod
*/
// Resistant Skin
private integer resistantSkinLevel
method addResistantSkin takes nothing returns nothing
set this.resistantSkinLevel=this.resistantSkinLevel+1
if this.resistantSkinLevel>0 then
call UnitAddAbility(this.unit,ABIL_RESISTANT_SKIN)
call UnitMakeAbilityPermanent(this.unit,true,ABIL_RESISTANT_SKIN)
endif
endmethod
method removeResistantSkin takes nothing returns nothing
set this.resistantSkinLevel=this.resistantSkinLevel-1
if this.resistantSkinLevel==0 then
call UnitMakeAbilityPermanent(this.unit,false,ABIL_RESISTANT_SKIN)
call UnitRemoveAbility(this.unit,ABIL_RESISTANT_SKIN)
endif
endmethod
method isResistantSkin takes nothing returns boolean
return this.resistantSkinLevel>0
endmethod
// Reflect Piercing
private integer reflectPiercingLevel
method addReflectPiercing takes nothing returns nothing
set this.reflectPiercingLevel=this.reflectPiercingLevel+1
if this.reflectPiercingLevel>0 then
call UnitAddAbility(this.unit,ABIL_REFLECT_PIERCING)
call UnitMakeAbilityPermanent(this.unit,true,ABIL_REFLECT_PIERCING)
endif
endmethod
method removeReflectPiercing takes nothing returns nothing
set this.reflectPiercingLevel=this.reflectPiercingLevel-1
if this.reflectPiercingLevel==0 then
call UnitMakeAbilityPermanent(this.unit,false,ABIL_REFLECT_PIERCING)
call UnitRemoveAbility(this.unit,ABIL_REFLECT_PIERCING)
endif
endmethod
method isReflectPiercing takes nothing returns boolean
return this.reflectPiercingLevel>0
endmethod
////////////////////
// Status Bonuses //
////////////////////
private static method setBonus takes unit u, integer abil, integer levels, integer amount returns nothing
local boolean addNeg=false
if amount<0 then
set addNeg=true
set amount=amount+thistype.twoPow[levels]
else
call UnitMakeAbilityPermanent(u,false,abil)
call UnitRemoveAbility(u,abil)
endif
set abil=abil+levels
set levels=thistype.twoPow[levels]
loop
set levels=levels/2
if amount>=levels then
call UnitAddAbility(u,abil)
call UnitMakeAbilityPermanent(u,true,abil)
set amount=amount-levels
else
call UnitMakeAbilityPermanent(u,false,abil)
call UnitRemoveAbility(u,abil)
endif
set abil=abil-1
exitwhen levels==1
endloop
if addNeg then
call UnitAddAbility(u,abil)
call UnitMakeAbilityPermanent(u,true,abil)
endif
endmethod
private integer armorBonus
method modArmorBonus takes integer amount returns nothing
set this.armorBonus=this.armorBonus+amount
debug if this.armorBonus>=thistype.twoPow[LEVELS_ARMOR] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modArmorBonus("+I2S(amount)+") - must not reach >= "+I2S(thistype.twoPow[LEVELS_ARMOR])+".")
debug endif
debug if this.armorBonus<-thistype.twoPow[LEVELS_ARMOR] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modArmorBonus("+I2S(amount)+") - must not reach < -"+I2S(thistype.twoPow[LEVELS_ARMOR])+".")
debug endif
call thistype.setBonus(this.unit,ABIL_ARMOR,LEVELS_ARMOR,this.armorBonus)
endmethod
method getArmorBonus takes nothing returns integer
return this.armorBonus
endmethod
private integer damageBonus
method modDamageBonus takes integer amount returns nothing
set this.damageBonus=this.damageBonus+amount
debug if this.damageBonus>=thistype.twoPow[LEVELS_DAMAGE] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modDamageBonus("+I2S(amount)+") - must not reach >= "+I2S(thistype.twoPow[LEVELS_DAMAGE])+".")
debug endif
debug if this.damageBonus<-thistype.twoPow[LEVELS_DAMAGE] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modDamageBonus("+I2S(amount)+") - must not reach < -"+I2S(thistype.twoPow[LEVELS_DAMAGE])+".")
debug endif
call thistype.setBonus(this.unit,ABIL_DAMAGE,LEVELS_DAMAGE,this.damageBonus)
endmethod
method getDamageBonus takes nothing returns integer
return this.damageBonus
endmethod
private integer strBonus
method modStrBonus takes integer amount returns nothing
set this.strBonus=this.strBonus+amount
debug if this.strBonus>=thistype.twoPow[LEVELS_STR] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modStrBonus("+I2S(amount)+") - must not reach >= "+I2S(thistype.twoPow[LEVELS_STR])+".")
debug endif
debug if this.strBonus<-thistype.twoPow[LEVELS_STR] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modStrBonus("+I2S(amount)+") - must not reach < -"+I2S(thistype.twoPow[LEVELS_STR])+".")
debug endif
call thistype.setBonus(this.unit,ABIL_STR,LEVELS_STR,this.strBonus)
endmethod
method getStrBonus takes nothing returns integer
return this.strBonus
endmethod
private integer agiBonus
method modAgiBonus takes integer amount returns nothing
set this.agiBonus=this.agiBonus+amount
debug if this.agiBonus>=thistype.twoPow[LEVELS_AGI] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modAgiBonus("+I2S(amount)+") - must not reach >= "+I2S(thistype.twoPow[LEVELS_AGI])+".")
debug endif
debug if this.agiBonus<-thistype.twoPow[LEVELS_AGI] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modAgiBonus("+I2S(amount)+") - must not reach < -"+I2S(thistype.twoPow[LEVELS_AGI])+".")
debug endif
call thistype.setBonus(this.unit,ABIL_AGI,LEVELS_AGI,this.agiBonus)
endmethod
method getAgiBonus takes nothing returns integer
return this.agiBonus
endmethod
private integer intBonus
method modIntBonus takes integer amount returns nothing
set this.intBonus=this.intBonus+amount
debug if this.intBonus>=thistype.twoPow[LEVELS_INT] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modIntBonus("+I2S(amount)+") - must not reach >= "+I2S(thistype.twoPow[LEVELS_INT])+".")
debug endif
debug if this.intBonus<-thistype.twoPow[LEVELS_INT] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modIntBonus("+I2S(amount)+") - must not reach < -"+I2S(thistype.twoPow[LEVELS_INT])+".")
debug endif
call thistype.setBonus(this.unit,ABIL_INT,LEVELS_INT,this.intBonus)
endmethod
method getIntBonus takes nothing returns integer
return this.intBonus
endmethod
private integer attackSpeedBonus
method modAttackSpeedBonus takes integer amount returns nothing
set this.attackSpeedBonus=this.attackSpeedBonus+amount
debug if this.attackSpeedBonus>=thistype.twoPow[LEVELS_ATTACK_SPEED] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modAttackSpeedBonus("+I2S(amount)+") - must not reach >= "+I2S(thistype.twoPow[LEVELS_ATTACK_SPEED])+".")
debug endif
debug if this.attackSpeedBonus<-thistype.twoPow[LEVELS_ATTACK_SPEED] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modAttackSpeedBonus("+I2S(amount)+") - must not reach < -"+I2S(thistype.twoPow[LEVELS_ATTACK_SPEED])+".")
debug endif
call thistype.setBonus(this.unit,ABIL_ATTACK_SPEED,LEVELS_ATTACK_SPEED,this.attackSpeedBonus)
endmethod
method getAttackSpeedBonus takes nothing returns integer
return this.attackSpeedBonus
endmethod
private integer healthBonus
method modHealthBonus takes integer amount returns nothing
set this.healthBonus=this.healthBonus+amount
debug if this.healthBonus>=thistype.twoPow[LEVELS_HEALTH] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modHealthBonus("+I2S(amount)+") - must not reach >= "+I2S(thistype.twoPow[LEVELS_HEALTH])+".")
debug endif
debug if this.healthBonus<-thistype.twoPow[LEVELS_HEALTH] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modHealthBonus("+I2S(amount)+") - must not reach < -"+I2S(thistype.twoPow[LEVELS_HEALTH])+".")
debug endif
call thistype.setBonus(this.unit,ABIL_HEALTH,LEVELS_HEALTH,this.healthBonus)
endmethod
method getHealthBonus takes nothing returns integer
return this.healthBonus
endmethod
private integer manaBonus
method modManaBonus takes integer amount returns nothing
set this.manaBonus=this.manaBonus+amount
debug if this.manaBonus>=thistype.twoPow[LEVELS_MANA] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modManaBonus("+I2S(amount)+") - must not reach >= "+I2S(thistype.twoPow[LEVELS_MANA])+".")
debug endif
debug if this.manaBonus<-thistype.twoPow[LEVELS_MANA] then
debug call BJDebugMsg("Status Error: Status["+GetUnitName(this.unit)+"].modManaBonus("+I2S(amount)+") - must not reach < -"+I2S(thistype.twoPow[LEVELS_MANA])+".")
debug endif
call thistype.setBonus(this.unit,ABIL_MANA,LEVELS_MANA,this.manaBonus)
endmethod
method getManaBonus takes nothing returns integer
return this.manaBonus
endmethod
// Periodic bonuses
private static unit updateUnit
private static group healthRegenGroup=CreateGroup()
private static method healthRegenPeriodic takes nothing returns nothing
set thistype.updateUnit=GetEnumUnit()
if UnitAlive(thistype.updateUnit) then
call SetWidgetLife(thistype.updateUnit,GetWidgetLife(thistype.updateUnit)+thistype[thistype.updateUnit].healthRegenBonus)
endif
endmethod
private real healthRegenBonus
method modHealthRegenBonus takes real amount returns nothing
set this.healthRegenBonus=this.healthRegenBonus+amount*PERIOD
if this.healthRegenBonus==0 then
call GroupRemoveUnit(thistype.healthRegenGroup,this.unit)
else
call GroupAddUnit(thistype.healthRegenGroup,this.unit)
endif
endmethod
method getHealthRegenBonus takes nothing returns real
return this.healthRegenBonus/PERIOD
endmethod
private static group manaRegenGroup=CreateGroup()
private static method manaRegenPeriodic takes nothing returns nothing
set thistype.updateUnit=GetEnumUnit()
if UnitAlive(thistype.updateUnit) then
call SetUnitState(thistype.updateUnit,UNIT_STATE_MANA,GetUnitState(thistype.updateUnit,UNIT_STATE_MANA)+thistype[thistype.updateUnit].manaRegenBonus)
endif
endmethod
private real manaRegenBonus
method modManaRegenBonus takes real amount returns nothing
set this.manaRegenBonus=this.manaRegenBonus+amount*PERIOD
if this.manaRegenBonus==0 then
call GroupRemoveUnit(thistype.manaRegenGroup,this.unit)
else
call GroupAddUnit(thistype.manaRegenGroup,this.unit)
endif
endmethod
method getManaRegenBonus takes nothing returns real
return this.manaRegenBonus/PERIOD
endmethod
private static group healthRegenPercentGroup=CreateGroup()
private static method healthRegenPercentPeriodic takes nothing returns nothing
set thistype.updateUnit=GetEnumUnit()
if UnitAlive(thistype.updateUnit) then
call SetWidgetLife(thistype.updateUnit,GetWidgetLife(thistype.updateUnit)+GetUnitState(thistype.updateUnit,UNIT_STATE_MAX_LIFE)*thistype[thistype.updateUnit].healthRegenPercentBonus)
endif
endmethod
private real healthRegenPercentBonus
method modHealthRegenPercentBonus takes real amount returns nothing
set this.healthRegenPercentBonus=this.healthRegenPercentBonus+amount*PERIOD*0.01
if this.healthRegenPercentBonus==0 then
call GroupRemoveUnit(thistype.healthRegenPercentGroup,this.unit)
else
call GroupAddUnit(thistype.healthRegenPercentGroup,this.unit)
endif
endmethod
method getHealthRegenPercentBonus takes nothing returns real
return this.healthRegenPercentBonus/PERIOD/0.01
endmethod
private static group manaRegenPercentGroup=CreateGroup()
private static method manaRegenPercentPeriodic takes nothing returns nothing
set thistype.updateUnit=GetEnumUnit()
if UnitAlive(thistype.updateUnit) then
call SetUnitState(thistype.updateUnit,UNIT_STATE_MANA,GetUnitState(thistype.updateUnit,UNIT_STATE_MANA)+GetUnitState(thistype.updateUnit,UNIT_STATE_MAX_MANA)*thistype[thistype.updateUnit].manaRegenPercentBonus)
endif
endmethod
private real manaRegenPercentBonus
method modManaRegenPercentBonus takes real amount returns nothing
set this.manaRegenPercentBonus=this.manaRegenPercentBonus+amount*PERIOD*0.01
if this.manaRegenPercentBonus==0 then
call GroupRemoveUnit(thistype.manaRegenPercentGroup,this.unit)
else
call GroupAddUnit(thistype.manaRegenPercentGroup,this.unit)
endif
endmethod
method getManaRegenPercentBonus takes nothing returns real
return this.manaRegenPercentBonus/PERIOD/0.01
endmethod
// Links periodic effects.
private static method periodicLink takes nothing returns nothing
call ForGroup(thistype.healthRegenGroup,function thistype.healthRegenPeriodic)
call ForGroup(thistype.manaRegenGroup,function thistype.manaRegenPeriodic)
call ForGroup(thistype.healthRegenPercentGroup,function thistype.healthRegenPercentPeriodic)
call ForGroup(thistype.manaRegenPercentGroup,function thistype.manaRegenPercentPeriodic)
endmethod
implement StaticPeriodic
////////////////////
// Movement Speed //
////////////////////
private real moveSpeedBonus
private real moveSpeedPercentBonus
private real x
private real y
private static real updateUnitX
private static real updateUnitY
private static real xInc
private static real yInc
private static real updateDist
private method periodic takes nothing returns nothing
set thistype.updateUnit=this.unit
set thistype.updateUnitX=GetUnitX(thistype.updateUnit)
set thistype.updateUnitY=GetUnitY(thistype.updateUnit)
set thistype.xInc=thistype.updateUnitX-this.x
set thistype.yInc=thistype.updateUnitY-this.y
set thistype.updateDist=SquareRoot(thistype.xInc*thistype.xInc+thistype.yInc*thistype.yInc)
if thistype.updateDist>0 then
if UnitAlive(thistype.updateUnit) and this.disableLevel<=0 and this.stunLevel<=0 and this.pauseLevel<=0 and this.immoboliseLevel<=0 and GetUnitMoveSpeed(thistype.updateUnit)>0 then
if this.moveSpeedPercentBonus!=0.0 then
set thistype.updateUnitX=thistype.updateUnitX+thistype.xInc*this.moveSpeedPercentBonus
set thistype.updateUnitY=thistype.updateUnitY+thistype.yInc*this.moveSpeedPercentBonus
endif
if this.moveSpeedBonus!=0.0 then
set thistype.updateDist=this.moveSpeedBonus/thistype.updateDist
set thistype.updateUnitX=thistype.updateUnitX+thistype.xInc*thistype.updateDist
set thistype.updateUnitY=thistype.updateUnitY+thistype.yInc*thistype.updateDist
endif
call SetUnitX(thistype.updateUnit,thistype.updateUnitX)
call SetUnitY(thistype.updateUnit,thistype.updateUnitY)
endif
endif
set this.x=thistype.updateUnitX
set this.y=thistype.updateUnitY
endmethod
implement T32xs
method modMoveSpeedBonus takes real amount returns nothing
set this.moveSpeedBonus=this.moveSpeedBonus+amount*T32_PERIOD
if this.moveSpeedBonus==0 and this.moveSpeedPercentBonus==0 then
call this.stopPeriodic()
else
set this.x=GetUnitX(this.unit)
set this.y=GetUnitY(this.unit)
call this.startPeriodic()
endif
endmethod
method getMoveSpeedBonus takes nothing returns real
return this.moveSpeedBonus/T32_PERIOD
endmethod
method modMoveSpeedPercentBonus takes real amount returns nothing
set this.moveSpeedPercentBonus=this.moveSpeedPercentBonus+amount*0.01
if this.moveSpeedBonus==0 and this.moveSpeedPercentBonus==0 then
call this.stopPeriodic()
else
set this.x=GetUnitX(this.unit)
set this.y=GetUnitY(this.unit)
call this.startPeriodic()
endif
endmethod
method getMoveSpeedPercentBonus takes nothing returns real
return this.moveSpeedPercentBonus/0.01
endmethod
//! runtextmacro AIDS()
endstruct
endlibrary
library Stun uses Status // Deprecated. Backwards compatability with "Stun" system.
function AddStun takes unit whichUnit returns nothing
call Status[whichUnit].addStun()
endfunction
function RemoveStun takes unit whichUnit returns nothing
call Status[whichUnit].removeStun()
endfunction
function Stun_IsUnitStunned takes unit whichUnit returns boolean
return Status[whichUnit].isStunned()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ GT ~~ GTrigger ~~ By Jesus4Lyf ~~ Version 1.05 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is GTrigger?
// - GTrigger is an event system that replaces the cumbersome WC3
// event system.
// - GTrigger only launches the necessary threads instead of x threads,
// where x is the number of times the event type occurs in the map.
//
// =Pros=
// - Instead of having 16 events (for "16" players) per use of an,
// event type, you have 0 per use and 16 total for that event type.
// - If you have 100 events of one type in your map, instead of firing
// 100 triggers each time any spell is cast, you fire only what's needed.
// - GTrigger is faster to code with, more efficient to execute, and just
// better programming practises and nicer code all round.
//
// =Cons=
// - If a trigger with a GTrigger event is destroyed, it must have its
// event unregistered first or it will leak an event (slows firing down).
// - Shouldn't use "wait" actions anywhere in the triggers.
//
// Functions:
// // General
// - GT_UnregisterTriggeringEvent()
//
// // Ability events
// - GT_RegisterStartsEffectEvent(trigger, abilityid) (returns the trigger passed in)
// - GT_RegisterBeginsChanellingEvent(trigger, abilityid) (returns the trigger passed in)
// - GT_RegisterBeginsCastingEvent(trigger, abilityid) (returns the trigger passed in)
// - GT_RegisterStopsCastingEvent(trigger, abilityid) (returns the trigger passed in)
// - GT_RegisterFinishesCastingEvent(trigger, abilityid) (returns the trigger passed in)
// - GT_RegisterLearnsAbilityEvent(trigger, abilityid) (returns the trigger passed in)
// // Order events // (can use String2OrderIdBJ("OrderString") for orderid
// - GT_RegisterTargetOrderEvent(trigger, orderid) (returns the trigger passed in)
// - GT_RegisterPointOrderEvent(trigger, orderid) (returns the trigger passed in)
// - GT_RegisterNoTargetOrderEvent(trigger, orderid) (returns the trigger passed in)
// // Item events
// - GT_RegisterItemUsedEvent(trigger, itemtypeid) (returns the trigger passed in)
// - GT_RegisterItemAcquiredEvent(trigger, itemtypeid) (returns the trigger passed in)
// - GT_RegisterItemDroppedEvent(trigger, itemtypeid) (returns the trigger passed in)
// // Unit events
// - GT_RegisterUnitDiesEvent(trigger, unittypeid) (returns the trigger passed in)
//
// // Ability Events
// - GT_UnregisterSpellEffectEvent(trigger, abilityid) (returns the trigger passed in)
// - GT_UnregisterBeginsChanellingEvent(trigger, abilityid) (returns the trigger passed in)
// - GT_UnregisterBeginsCastingEvent(trigger, abilityid) (returns the trigger passed in)
// - GT_UnregisterStopsCastingEvent(trigger, abilityid) (returns the trigger passed in)
// - GT_UnregisterFinishesCastingEvent(trigger, abilityid) (returns the trigger passed in)
// - GT_UnregisterLearnsAbilityEvent(trigger, abilityid) (returns the trigger passed in)
// // Order events // (can use String2OrderIdBJ("OrderString") for orderid
// - GT_UnregisterTargetOrderEvent(trigger, orderid) (returns the trigger passed in)
// - GT_UnregisterPointOrderEvent(trigger, orderid) (returns the trigger passed in)
// - GT_UnregisterNoTargetOrderEvent(trigger, orderid) (returns the trigger passed in)
// // Item events
// - GT_UnregisterItemUsedEvent(trigger, itemtypeid) (returns the trigger passed in)
// - GT_UnregisterItemAcquiredEvent(trigger, itemtypeid) (returns the trigger passed in)
// - GT_UnregisterItemDroppedEvent(trigger, itemtypeid) (returns the trigger passed in)
// // Unit events
// - GT_UnregisterUnitDiesEvent(trigger, unittypeid) (returns the trigger passed in)
//
// Alternative interface (not recommended):
// If you aren't familiar with how this works, you shouldn't use it.
// All funcs must return false. (That is the only reason it isn't recommended.)
// // General
// - GT_RemoveTriggeringAction() // Use this to remove actions.
// // Ability Events
// - GT_AddStartsEffectAction(func, abilityid)
// - GT_AddBeginsChanellingActon(func, abilityid)
// - GT_AddBeginsCastingAction(func, abilityid)
// - GT_AddStopsCastingAction(func, abilityid)
// - GT_AddFinishesCastingAction(func, abilityid)
// - GT_AddLearnsAbilityAction(func, abilityid)
// // Order events // (can use String2OrderIdBJ("OrderString") for orderid
// - GT_AddTargetOrderAction(func, orderid)
// - GT_AddPointOrderAction(func, orderid)
// - GT_AddNoTargetOrderAction(func, orderid)
// // Item events
// - GT_AddItemUsedAction(func, itemtypeid)
// - GT_AddItemAcquiredAction(func, itemtypeid)
// - GT_AddItemDroppedAction(func, itemtypeid)
// // Unit events
// - GT_AddUnitDiesAction(func, unittypeid)
//
// Details:
// - Due to the storage method, only 8191 GTrigger events are possible at any one time.
//
// Thanks:
// - Daxtreme: For voluntarily testing this system and the UnitDies event idea.
// - kenny!: For the Order and Learns Ability event ideas.
//
// How to import:
// - Create a trigger named GT.
// - Convert it to custom text and replace the whole trigger text with this.
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library GT initializer Init
//////////////
// Pointers //
////////////////////////////////////////////////////////////////////////////
// Assigned to abilities, and point to trigger grouping linked lists.
//
// Use:
// GetPointer --> int (pointer)
// FreePointer(int (pointer))
// set PointerTarget[int (pointer)]=int (list link)
// PointerTarget[int (pointer)] --> int (list link)
globals
// Pointer
private integer array PointerTarget
private integer PointerMax=0
// Spare Pointer Stack
private integer array NextPointer
private integer NextPointerMaxPlusOne=1
endglobals
private function GetPointer takes nothing returns integer
if NextPointerMaxPlusOne==1 then
set PointerMax=PointerMax+1
return PointerMax
endif
set NextPointerMaxPlusOne=NextPointerMaxPlusOne-1
return NextPointer[NextPointerMaxPlusOne]
endfunction
private function FreePointer takes integer pointer returns nothing
set PointerTarget[pointer]=0
set NextPointer[NextPointerMaxPlusOne]=pointer
set NextPointerMaxPlusOne=NextPointerMaxPlusOne+1
endfunction
///////////////////////////////////
// Trigger Grouping Linked Lists //
////////////////////////////////////////////////////////////////////////////
// Contains a chain of triggers to be executed together.
//
// Use:
// GetMem() --> int (mem)
// FreeMem(int (mem))
// Link(int (pointer), int (mem))
// Unlink(int (pointer), int (mem))
globals
// Spare Link Stack
private integer array NextMem
private integer NextMemMaxPlusOne=1
// Linked list
private trigger array Trig
private integer array Next
private integer array Prev
private integer TrigMax=0
endglobals
private function GetMem takes nothing returns integer
if NextMemMaxPlusOne==1 then
set TrigMax=TrigMax+1
return TrigMax
endif
set NextMemMaxPlusOne=NextMemMaxPlusOne-1
return NextMem[NextMemMaxPlusOne]
endfunction
private function FreeMem takes integer i returns nothing
set Trig[i]=null
set NextMem[NextMemMaxPlusOne]=i
set NextMemMaxPlusOne=NextMemMaxPlusOne+1
endfunction
// Linked list functionality
// NOTE: This means "Next" must be loaded BEFORE executing the trigger, which could delete the current link.
private function Link takes integer pointer, integer new returns nothing
set Prev[new]=0
set Next[new]=PointerTarget[pointer]
set Prev[PointerTarget[pointer]]=new
set PointerTarget[pointer]=new
endfunction
private function Unlink takes integer pointer, integer rem returns nothing
if Prev[rem]==0 then
set PointerTarget[pointer]=Next[rem]
set Prev[Next[rem]]=0
endif
set Next[Prev[rem]]=Next[rem]
set Prev[Next[rem]]=Prev[rem]
endfunction
//////////////////////
// GTrigger General //
////////////////////////////////////////////////////////////////////////////
// Only contains the UnregisterTriggeringEvent action for public use.
globals
boolean UnregisterLastEvent=false
endglobals
public function UnregisterTriggeringEvent takes nothing returns nothing
set UnregisterLastEvent=true
endfunction
/////////////////////////////////////
// GTrigger Ability Implementation //
////////////////////////////////////////////////////////////////////////////
// The nasty textmacro implementation of special "All Players" events.
//! textmacro SetupSpecialAllPlayersEvent takes NAME, EVENT, GETSPECIAL
globals
private trigger $NAME$Trigger=CreateTrigger()
// Extendable arrays
private integer array $NAME$AbilityIdA
private integer array $NAME$ListPointerA
private integer array $NAME$AbilityIdB
private integer array $NAME$ListPointerB
private integer array $NAME$AbilityIdC
private integer array $NAME$ListPointerC
private integer array $NAME$AbilityIdD
private integer array $NAME$ListPointerD
private integer array $NAME$AbilityIdE
private integer array $NAME$ListPointerE
endglobals
globals//locals
private integer GetOrCreateListPointer$NAME$AbilHashed
endglobals
private function GetOrCreate$NAME$ListPointer takes integer abil returns integer
set GetOrCreateListPointer$NAME$AbilHashed=abil-(abil/8191)*8191
if $NAME$AbilityIdA[GetOrCreateListPointer$NAME$AbilHashed]==abil then // Correct
return $NAME$ListPointerA[GetOrCreateListPointer$NAME$AbilHashed]
elseif $NAME$AbilityIdA[GetOrCreateListPointer$NAME$AbilHashed]<1 then // Empty
set $NAME$AbilityIdA[GetOrCreateListPointer$NAME$AbilHashed]=abil
set $NAME$ListPointerA[GetOrCreateListPointer$NAME$AbilHashed]=GetPointer()
return $NAME$ListPointerA[GetOrCreateListPointer$NAME$AbilHashed]
endif
if $NAME$AbilityIdB[GetOrCreateListPointer$NAME$AbilHashed]==abil then // Correct
return $NAME$ListPointerB[GetOrCreateListPointer$NAME$AbilHashed]
elseif $NAME$AbilityIdB[GetOrCreateListPointer$NAME$AbilHashed]<1 then // Empty
set $NAME$AbilityIdB[GetOrCreateListPointer$NAME$AbilHashed]=abil
set $NAME$ListPointerB[GetOrCreateListPointer$NAME$AbilHashed]=GetPointer()
return $NAME$ListPointerB[GetOrCreateListPointer$NAME$AbilHashed]
endif
if $NAME$AbilityIdC[GetOrCreateListPointer$NAME$AbilHashed]==abil then // Correct
return $NAME$ListPointerC[GetOrCreateListPointer$NAME$AbilHashed]
elseif $NAME$AbilityIdC[GetOrCreateListPointer$NAME$AbilHashed]<1 then // Empty
set $NAME$AbilityIdC[GetOrCreateListPointer$NAME$AbilHashed]=abil
set $NAME$ListPointerC[GetOrCreateListPointer$NAME$AbilHashed]=GetPointer()
return $NAME$ListPointerC[GetOrCreateListPointer$NAME$AbilHashed]
endif
if $NAME$AbilityIdD[GetOrCreateListPointer$NAME$AbilHashed]==abil then // Correct
return $NAME$ListPointerD[GetOrCreateListPointer$NAME$AbilHashed]
elseif $NAME$AbilityIdD[GetOrCreateListPointer$NAME$AbilHashed]<1 then // Empty
set $NAME$AbilityIdD[GetOrCreateListPointer$NAME$AbilHashed]=abil
set $NAME$ListPointerD[GetOrCreateListPointer$NAME$AbilHashed]=GetPointer()
return $NAME$ListPointerD[GetOrCreateListPointer$NAME$AbilHashed]
endif
if $NAME$AbilityIdE[GetOrCreateListPointer$NAME$AbilHashed]==abil then // Correct
return $NAME$ListPointerE[GetOrCreateListPointer$NAME$AbilHashed]
elseif $NAME$AbilityIdE[GetOrCreateListPointer$NAME$AbilHashed]<1 then // Empty
set $NAME$AbilityIdE[GetOrCreateListPointer$NAME$AbilHashed]=abil
set $NAME$ListPointerE[GetOrCreateListPointer$NAME$AbilHashed]=GetPointer()
return $NAME$ListPointerE[GetOrCreateListPointer$NAME$AbilHashed]
endif
call BJDebugMsg("GTrigger Error: Ran out of storage locations for pointers on object "+GetObjectName(abil)+"!")
set PointerTarget[0]=0
return 0
endfunction
globals//locals
private integer GetListPointer$NAME$AbilHashed
endglobals
private function Get$NAME$ListPointer takes integer abil returns integer
set GetListPointer$NAME$AbilHashed=abil-(abil/8191)*8191
if $NAME$AbilityIdA[GetListPointer$NAME$AbilHashed]==abil then // Correct
return $NAME$ListPointerA[GetListPointer$NAME$AbilHashed]
elseif $NAME$AbilityIdA[GetListPointer$NAME$AbilHashed]<1 then // Empty
set PointerTarget[0]=0 // Make sure.
return 0
endif
if $NAME$AbilityIdB[GetListPointer$NAME$AbilHashed]==abil then // Correct
return $NAME$ListPointerB[GetListPointer$NAME$AbilHashed]
elseif $NAME$AbilityIdB[GetListPointer$NAME$AbilHashed]<1 then // Empty
set PointerTarget[0]=0 // Make sure.
return 0
endif
if $NAME$AbilityIdC[GetListPointer$NAME$AbilHashed]==abil then // Correct
return $NAME$ListPointerC[GetListPointer$NAME$AbilHashed]
elseif $NAME$AbilityIdC[GetListPointer$NAME$AbilHashed]<1 then // Empty
set PointerTarget[0]=0 // Make sure.
return 0
endif
if $NAME$AbilityIdD[GetListPointer$NAME$AbilHashed]==abil then // Correct
return $NAME$ListPointerD[GetListPointer$NAME$AbilHashed]
elseif $NAME$AbilityIdD[GetListPointer$NAME$AbilHashed]<1 then // Empty
set PointerTarget[0]=0 // Make sure.
return 0
endif
if $NAME$AbilityIdE[GetListPointer$NAME$AbilHashed]==abil then // Correct
return $NAME$ListPointerE[GetListPointer$NAME$AbilHashed]
elseif $NAME$AbilityIdE[GetListPointer$NAME$AbilHashed]<1 then // Empty
set PointerTarget[0]=0 // Make sure.
return 0
endif
call BJDebugMsg("GTrigger Error: Ran out of storage locations for pointers at ability "+GetObjectName(abil)+"!")
set PointerTarget[0]=0
return 0
endfunction
globals//locals
private integer Register$NAME$Mem
endglobals
public function Register$NAME$Event takes trigger t, integer abil returns trigger
set Register$NAME$Mem=GetMem()
set Trig[Register$NAME$Mem]=t
call Link(GetOrCreate$NAME$ListPointer(abil),Register$NAME$Mem)
return t
endfunction
globals//locals
private integer Unregister$NAME$Pointer
private integer Unregister$NAME$Mem
endglobals
public function Unregister$NAME$Event takes trigger t, integer abil returns trigger
set Unregister$NAME$Pointer=Get$NAME$ListPointer(abil)
set Unregister$NAME$Mem=PointerTarget[Unregister$NAME$Pointer]
loop
exitwhen Trig[Unregister$NAME$Mem]==t
if Unregister$NAME$Mem==0 then
return t // Not found.
endif
set Unregister$NAME$Mem=Next[Unregister$NAME$Mem]
endloop
call Unlink(Unregister$NAME$Pointer,Unregister$NAME$Mem)
call FreeMem(Unregister$NAME$Mem)
return t
endfunction
private function Trigger$NAME$Event takes nothing returns boolean
local integer Trigger$NAME$Pointer=Get$NAME$ListPointer($GETSPECIAL$)
local integer Trigger$NAME$Mem=PointerTarget[Trigger$NAME$Pointer]
local integer Trigger$NAME$NextMem
set UnregisterLastEvent=false
loop
exitwhen Trigger$NAME$Mem<1
set Trigger$NAME$NextMem=Next[Trigger$NAME$Mem]
if TriggerEvaluate(Trig[Trigger$NAME$Mem]) then
call TriggerExecute(Trig[Trigger$NAME$Mem])
endif
if UnregisterLastEvent then
set UnregisterLastEvent=false
call Unlink(Trigger$NAME$Pointer,Trigger$NAME$Mem)
call FreeMem(Trigger$NAME$Mem)
endif
set Trigger$NAME$Mem=Trigger$NAME$NextMem
endloop
return false
endfunction
private function Init$NAME$ takes nothing returns nothing
local integer i=bj_MAX_PLAYER_SLOTS
call TriggerAddCondition($NAME$Trigger,Condition(function Trigger$NAME$Event))
loop
set i=i-1
call TriggerRegisterPlayerUnitEvent($NAME$Trigger,Player(i),EVENT_PLAYER_$EVENT$,null)
exitwhen i==0
endloop
endfunction
//! endtextmacro
//! runtextmacro SetupSpecialAllPlayersEvent("StartsEffect", "UNIT_SPELL_EFFECT", "GetSpellAbilityId()")
//! runtextmacro SetupSpecialAllPlayersEvent("BeginsChanelling", "UNIT_SPELL_CHANNEL", "GetSpellAbilityId()")
//! runtextmacro SetupSpecialAllPlayersEvent("BeginsCasting", "UNIT_SPELL_CAST", "GetSpellAbilityId()")
//! runtextmacro SetupSpecialAllPlayersEvent("StopsCasting", "UNIT_SPELL_ENDCAST", "GetSpellAbilityId()")
//! runtextmacro SetupSpecialAllPlayersEvent("FinishesCasting", "UNIT_SPELL_FINISH", "GetSpellAbilityId()")
//! runtextmacro SetupSpecialAllPlayersEvent("TargetOrder", "UNIT_ISSUED_TARGET_ORDER", "GetIssuedOrderId()")
//! runtextmacro SetupSpecialAllPlayersEvent("PointOrder", "UNIT_ISSUED_POINT_ORDER", "GetIssuedOrderId()")
//! runtextmacro SetupSpecialAllPlayersEvent("NoTargetOrder", "UNIT_ISSUED_ORDER", "GetIssuedOrderId()")
//! runtextmacro SetupSpecialAllPlayersEvent("ItemUsed", "UNIT_USE_ITEM", "GetItemTypeId(GetManipulatedItem())")
//! runtextmacro SetupSpecialAllPlayersEvent("ItemAcquired", "UNIT_PICKUP_ITEM", "GetItemTypeId(GetManipulatedItem())")
//! runtextmacro SetupSpecialAllPlayersEvent("ItemDropped", "UNIT_DROP_ITEM", "GetItemTypeId(GetManipulatedItem())")
//! runtextmacro SetupSpecialAllPlayersEvent("UnitDies", "UNIT_DEATH", "GetUnitTypeId(GetTriggerUnit())")
//! runtextmacro SetupSpecialAllPlayersEvent("LearnsAbility", "HERO_SKILL", "GetLearnedSkill()")
// Note to self: Remember to update the Init function.
/////////////////////////////////////////
// GTrigger All Players Implementation //
////////////////////////////////////////////////////////////////////////////
// The textmacro implementation of other "All Players" events.
//! textmacro SetupAllPlayersEvent takes NAME, EVENT
globals
private trigger $NAME$Trigger=CreateTrigger()
private integer $NAME$ListPointer=0
endglobals
globals//locals
private integer Register$NAME$Mem
endglobals
public function Register$NAME$Event takes trigger t returns trigger
set Register$NAME$Mem=GetMem()
set Trig[Register$NAME$Mem]=t
call Link($NAME$ListPointer,Register$NAME$Mem)
return t
endfunction
globals//locals
private integer Unregister$NAME$Pointer
private integer Unregister$NAME$Mem
endglobals
public function Unregister$NAME$Event takes trigger t returns trigger
set Unregister$NAME$Mem=PointerTarget[$NAME$ListPointer]
loop
exitwhen Trig[Unregister$NAME$Mem]==t
if Unregister$NAME$Mem==0 then
return t // Not found.
endif
set Unregister$NAME$Mem=Next[Unregister$NAME$Mem]
endloop
call Unlink($NAME$ListPointer,Unregister$NAME$Mem)
call FreeMem(Unregister$NAME$Mem)
return t
endfunction
private function Trigger$NAME$Event takes nothing returns boolean
local integer Trigger$NAME$Mem=PointerTarget[$NAME$ListPointer]
local integer Trigger$NAME$NextMem
set UnregisterLastEvent=false
loop
exitwhen Trigger$NAME$Mem<1
set Trigger$NAME$NextMem=Next[Trigger$NAME$Mem]
if TriggerEvaluate(Trig[Trigger$NAME$Mem]) then
call TriggerExecute(Trig[Trigger$NAME$Mem])
endif
if UnregisterLastEvent then
set UnregisterLastEvent=false
call Unlink($NAME$ListPointer,Trigger$NAME$Mem)
call FreeMem(Trigger$NAME$Mem)
endif
set Trigger$NAME$Mem=Trigger$NAME$NextMem
endloop
return false
endfunction
private function Init$NAME$ takes nothing returns nothing
local integer i=bj_MAX_PLAYER_SLOTS
call TriggerAddCondition($NAME$Trigger,Condition(function Trigger$NAME$Event))
loop
set i=i-1
call TriggerRegisterPlayerUnitEvent($NAME$Trigger,Player(i),EVENT_PLAYER_UNIT_$EVENT$,null)
exitwhen i==0
endloop
// Initialise the pointer.
set $NAME$ListPointer=GetPointer()
endfunction
//! endtextmacro
// Old: //! runtextmacro SetupAllPlayersEvent("AnyUnitDies", "DEATH")
private function Init takes nothing returns nothing
// Ability events
call InitStartsEffect()
call InitBeginsChanelling()
call InitBeginsCasting()
call InitStopsCasting()
call InitFinishesCasting()
call InitLearnsAbility()
// Order events
call InitTargetOrder()
call InitPointOrder()
call InitNoTargetOrder()
// Item events
call InitItemUsed()
call InitItemAcquired()
call InitItemDropped()
// Unit events
call InitUnitDies()
endfunction
//////////////
// Wrappers //
////////////////////////////////////////////////////////////////////////////
// Wraps it up, for those who really want this interface.
// General
public function RemoveTriggeringAction takes nothing returns nothing
call UnregisterTriggeringEvent()
call DestroyTrigger(GetTriggeringTrigger())
endfunction
// Special All Player Events
//! textmacro AddSpecialAllPlayersWrapper takes EVENT
public function Add$EVENT$Action takes code func, integer special returns nothing
call TriggerAddCondition(Register$EVENT$Event(CreateTrigger(),special),Condition(func))
endfunction
//! endtextmacro
//! runtextmacro AddSpecialAllPlayersWrapper("StartsEffect")
//! runtextmacro AddSpecialAllPlayersWrapper("BeginsChanelling")
//! runtextmacro AddSpecialAllPlayersWrapper("BeginsCasting")
//! runtextmacro AddSpecialAllPlayersWrapper("StopsCasting")
//! runtextmacro AddSpecialAllPlayersWrapper("FinishesCasting")
//! runtextmacro AddSpecialAllPlayersWrapper("TargetOrder")
//! runtextmacro AddSpecialAllPlayersWrapper("PointOrder")
//! runtextmacro AddSpecialAllPlayersWrapper("NoTargetOrder")
//! runtextmacro AddSpecialAllPlayersWrapper("ItemUsed")
//! runtextmacro AddSpecialAllPlayersWrapper("ItemAcquired")
//! runtextmacro AddSpecialAllPlayersWrapper("ItemDropped")
//! runtextmacro AddSpecialAllPlayersWrapper("UnitDies")
//! runtextmacro AddSpecialAllPlayersWrapper("LearnsAbility")
// Note to self: Remember to update the Init function.
// All Player Events
//! textmacro AddAllPlayersWrapper takes EVENT
public function Add$EVENT$Action takes code func returns nothing
call TriggerAddCondition(Register$EVENT$Event(CreateTrigger()),Condition(func))
endfunction
//! endtextmacro
// Old: //! runtextmacro AddAllPlayersWrapper("AnyUnitDies")
endlibrary
//TESH.scrollpos=34
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = false
private constant boolean USE_FLEXIBLE_OFFSET = true
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
set tT[0]=CreateTimer()
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//* [group] ENUM_GROUP As you might expect, this group is good for
//* when you need a group just for enumeration.
//* [boolexpr] BOOLEXPR_TRUE This is a true boolexpr, which is important
//* because a 'null' boolexpr in enumeration
//* calls results in a leak. Use this instead.
//* [boolexpr] BOOLEXPR_FALSE This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//* local group MyGroup = NewGroup()
//* call GroupRefresh(MyGroup)
//* call ReleaseGroup(MyGroup)
//* call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//* call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
//If you don't have xebasic in your map, this value will be used instead.
//This value corresponds to the max collision size of a unit in your map.
private constant real MAX_COLLISION_SIZE = 197.
//If you are insane and don't care about any of the protection involved in
//this library, but want this script to be really fast, set this to true.
private constant boolean LESS_SAFETY = false
endglobals
globals
//* Constants that are available to the user
group ENUM_GROUP = CreateGroup()
boolexpr BOOLEXPR_TRUE = null
boolexpr BOOLEXPR_FALSE = null
endglobals
globals
//* Hashtable for debug purposes
private hashtable ht = InitHashtable()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Arrays and counter for the group stack
private group array Groups
private integer Count = 0
//* Variables for use with the GroupUnitsInArea function
private real X = 0.
private real Y = 0.
private real R = 0.
private hashtable H = InitHashtable()
endglobals
private function HookDestroyGroup takes group g returns nothing
if g == ENUM_GROUP then
call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
endif
endfunction
debug hook DestroyGroup HookDestroyGroup
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Refr)
set Flag = false
endif
call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Refr = g
call ForGroup(Refr, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
static if not LESS_SAFETY then
call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
endif
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer id = GetHandleId(g)
static if LESS_SAFETY then
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
else
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif not HaveSavedInteger(ht, 0, id) then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Group not part of stack")
return false
elseif LoadInteger(ht, 0, id) == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
call SaveInteger(ht, 0, id, 2)
endif
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
return true
endfunction
private function Filter takes nothing returns boolean
return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction
private function HookDestroyBoolExpr takes boolexpr b returns nothing
local integer bid = GetHandleId(b)
if HaveSavedHandle(H, 0, bid) then
//Clear the saved boolexpr
call DestroyBoolExpr(LoadBooleanExprHandle(H, 0, bid))
call RemoveSavedHandle(H, 0, bid)
endif
endfunction
hook DestroyBoolExpr HookDestroyBoolExpr
private constant function GetRadius takes real radius returns real
static if LIBRARY_xebasic then
return radius+XE_MAX_COLLISION_SIZE
else
return radius+MAX_COLLISION_SIZE
endif
endfunction
function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
local integer bid = 0
//Set variables to new values
set X = x
set Y = y
set R = radius
if filter == null then
//Adjusts for null boolexprs passed to the function
set filter = Condition(function Filter)
else
//Check for a saved boolexpr
set bid = GetHandleId(filter)
if HaveSavedHandle(H, 0, bid) then
//Set the filter to use to the saved one
set filter = LoadBooleanExprHandle(H, 0, bid)
else
//Create a new And() boolexpr for this filter
set filter = And(Condition(function Filter), filter)
call SaveBooleanExprHandle(H, 0, bid, filter)
endif
endif
//Enumerate, if they want to use the boolexpr, this lets them
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
//Set variables to new values
set X = x
set Y = y
set R = radius
//Enumerate
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), Condition(function Filter))
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
private function True takes nothing returns boolean
return true
endfunction
private function False takes nothing returns boolean
return false
endfunction
private function Init takes nothing returns nothing
set BOOLEXPR_TRUE = Condition(function True)
set BOOLEXPR_FALSE = Condition(function False)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//
// _ ___ ___ ___ _______________________________________________
// /_\ |_ _| \/ __| || A D V A N C E D I N D E X I N G ||
// / _ \ | || |) \__ \ || A N D ||
// /_/ \_\___|___/|___/ || D A T A S T O R A G E ||
// By Jesus4Lyf ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// v 1.1.0
// What is AIDS?
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// AIDS assigns unique integers between 1 and 8191 to units which enter
// the map. These can be used for arrays and data attaching.
//
// AIDS also allows you to define structs which are created automatically
// when units enter the map, and filtering which units should be indexed
// as well as for which units these structs should be created.
//
// How to implement?
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// Simply create a new trigger object called AIDS, go to 'Edit -> Convert
// to Custom Text', and replace everything that's there with this script.
//
// Save the map, close it, reopen it, and then delete the "!" from the
// FAR left side of the next lines (so "external" will line up with this line):
// external ObjectMerger w3a Adef AIDS anam "State Detection" ansf "(AIDS)" aart "" arac 0
//
// At the top of the script, there is a 'UnitIndexingFilter' constant
// function. If the function returns true for the unit, then that unit
// will be automatically indexed. Setting this to true will automatically
// index all units. Setting it to false will disable automatic indexing.
//
// Functions:
// ¯¯¯¯¯¯¯¯¯¯¯¯
// function GetUnitId takes unit u returns integer
// - This returns the index of an indexed unit. This will return 0
// if the unit has not been indexed.
// - This function inlines. It does not check if the unit needs an
// index. This function is for the speed freaks.
// - Always use this if 'UnitIndexingFilter' simply returns true.
//
// function GetUnitIndex takes unit u returns integer
// - This will return the index of a unit if it has one, or assign
// an index if the unit doesn't have one (and return the new index).
// - Use this if 'UnitIndexingFilter' doesn't return true.
//
// function GetIndexUnit takes integer index returns unit
// - This returns the unit which has been assigned the 'index'.
//
// AIDS Structs:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// - Insert: //! runtextmacro AIDS() at the top of a struct to make it
// an AIDS struct.
// - AIDS structs cannot be created or destroyed manually. Instead, they
// are automatically created when an appropriate unit enters the map.
// - You cannot give members default values in their declaration.
// (eg: private integer i=5 is not allowed)
// - You cannot use array members.
// - AIDS structs must "extend array". This will remove some unused
// functions and enforce the above so there will be no mistakes.
// - There are four optional methods you can use in AIDS structs:
// - AIDS_onCreate takes nothing returns nothing
// - This is called when the struct is 'created' for the unit.
// - In here you can assign members their default values, which
// you would usually assign in their declarations.
// (eg: set this.i=5)
// - AIDS_onDestroy takes nothing returns nothing
// - This is called when the struct is 'destroyed' for the unit.
// - This is your substitute to the normal onDestroy method.
// - AIDS_filter takes unit u returns boolean
// - This is similar to the constant filter in the main system.
// - Each unit that enters the map will be tested by each AIDS
// struct filter. If it returns true for that unit, that unit
// will be indexed if it was not already, the AIDS struct will
// have its AIDS_onCreate method called, and later have its
// AIDS_onDestroy method called when the index is recycled.
// - Not declaring this will use the default AIDS filter instead.
// - AIDS_onInit takes nothing returns nothing
// - This is because I stole your onInit function with my textmacro.
// - You can use '.unit' from any AIDS struct to get the unit for which
// the struct is for.
// - The structs id will be the units index, so getting the struct for
// a unit inlines to a single native call, and you can typecast between
// different AIDS structs. This is the premise of AIDS.
// - Never create or destroy AIDS structs directly.
// - You can call .AIDS_addLock() and AIDS_removeLock() to increase or
// decrease the lock level on the struct. If a struct's lock level is
// not 0, it will not be destroyed until it is reduced to 0. Locks just
// put off AIDS struct destruction in case you wish to attach to a timer
// or something which must expire before the struct data disappears.
// Hence, not freeing all locks will leak the struct (and index).
//
// PUI and AutoIndex:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// - AIDS includes the PUI textmacros and the AutoIndex module, because
// these systems are not compatible with AIDS but have valid and distinct
// uses.
// - The PUI textmacros are better to use for spells than AIDS structs,
// because they are not created for all units, just those targetted by
// the spell (or whatever else is necessary).
// - The AutoData module is good for very simple array syntax for data
// attachment (although I don't recommend that people actually use it,
// it's here mostly for compatability). Note that unlike the PUI textmacros,
// units must pass the AIDS filter in order for this module to work with
// them. This is exactly as the same as in AutoIndex itself (AutoIndex
// has a filter too).
//
// Thanks:
// ¯¯¯¯¯¯¯¯¯
// - Romek, for writing 90% of this user documentation, challenging my
// interface, doing some testing, suggesting improvements and inspiring
// me to re-do my code to include GetUnitIndex as non-inlining.
// - grim001, for writing the AutoData module, and AutoIndex. I used the
// on-enter-map method that he used. Full credits for the AutoData module.
// - Cohadar, for writing his PUI textmacros. Full credits to him for these,
// except for my slight optimisations for this system.
// Also, I have used an optimised version of his PeriodicRecycler from
// PUI in this system to avoid needing a RemoveUnitEx function.
// - Vexorian, for helping Cohadar on the PUI textmacro.
// - Larcenist, for suggesting the AIDS acronym. Originally he suggested
// 'Alternative Index Detection System', but obviously I came up with
// something better. In fact, I'd say it looks like the acronym was
// an accident. Kinda neat, don't you think? :P
//
// Final Notes:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// - With most systems, I wouldn't usually add substitutes for alternative
// systems. However, UnitData systems are an exception, because they
// are incompatible with eachother. Since using this system forbids
// people from using the real PUI or AutoIndex, and a lot of resources
// use either of these, it made sense not to break them all.
//
// - If this documentation confused you as to how to use the system, just
// leave everything as default and use GetUnitId everywhere.
//
// - To use this like PUI (if you don't like spamming indices) simply
// make the AIDS filter return false, and use GetUnitIndex.
//
library AIDS initializer InitAIDS
//==============================================================================
// Configurables
//
globals
private constant boolean USE_PERIODIC_RECYCLER = false
private constant real PERIOD = 0.03125 // Recycles 32 units/second max.
// Lower to be able to recycle faster.
// Only used if USE_PERIODIC_RECYCLER
// is set to true.
private constant integer LEAVE_DETECTION_ABILITY = 'AIDS'
endglobals
private function UnitIndexingFilter takes unit u returns boolean
return true
endfunction
//==============================================================================
// System code
//
globals
// The unit stored at an index.
private unit array IndexUnit
private integer array LockLevel
endglobals
//==============================================================================
globals
// Recycle stack
private integer array RecycledIndex
private integer MaxRecycledIndex = 0
// Previous highest index
private integer MaxIndex = 0
endglobals
//==============================================================================
globals
private integer array DecayingIndex
private integer MaxDecayingIndex=0
private integer DecayChecker=0
endglobals
globals
private timer UndefendTimer=CreateTimer()
private integer array UndefendIndex
private integer UndefendStackIndex=0
endglobals
globals
private integer array UndefendExpiringIndex
private integer UndefendExpiringIndexLevel=0
endglobals
//==============================================================================
globals
// The Add/Remove stack (or assign/recycle stack).
//
// Indexing can become recusive since units can be created on index
// assignment or deallocation.
// To support this, a stack is used to store the event response results.
private integer ARStackLevel=0
private integer array ARStackIndex
private unit array ARStackUnit
// A later discovery revealed that the Add/Remove stack did not need to be
// used for deallocation. The alternative used works fine...
endglobals
public constant function GetEnteringIndexUnit takes nothing returns unit
return ARStackUnit[ARStackLevel]
endfunction
public function GetIndexOfEnteringUnit takes nothing returns integer
// Called in AIDS structs when units do not pass the initial AIDS filter.
if ARStackIndex[ARStackLevel]==0 then
// Get new index, from recycler first, else new.
// Store the current index on the (new) top level of the AR stack.
if MaxRecycledIndex==0 then // Get new.
set MaxIndex=MaxIndex+1
set ARStackIndex[ARStackLevel]=MaxIndex
else // Get from recycle stack.
set ARStackIndex[ARStackLevel]=RecycledIndex[MaxRecycledIndex]
set MaxRecycledIndex=MaxRecycledIndex-1
endif
// Store index on unit.
call SetUnitUserData(ARStackUnit[ARStackLevel],ARStackIndex[ARStackLevel])
set IndexUnit[ARStackIndex[ARStackLevel]]=ARStackUnit[ARStackLevel]
// Add index to recycle list.
set MaxDecayingIndex=MaxDecayingIndex+1
set DecayingIndex[MaxDecayingIndex]=ARStackIndex[ARStackLevel]
endif
return ARStackIndex[ARStackLevel]
endfunction
public constant function GetIndexOfEnteringUnitAllocated takes nothing returns integer
// Called in AIDS structs when units have passed the initial AIDS filter.
return ARStackIndex[ARStackLevel]
endfunction
public constant function GetDecayingIndex takes nothing returns integer
static if USE_PERIODIC_RECYCLER then
return DecayingIndex[DecayChecker]
else
return UndefendExpiringIndex[UndefendExpiringIndexLevel]
endif
endfunction
//==============================================================================
globals
// For structs and such which need to do things on unit index assignment.
private trigger OnEnter=CreateTrigger()
// The same, but for when units pass the initial filter anyway.
private trigger OnEnterAllocated=CreateTrigger()
// For structs and such which need to do things on unit index deallocation.
private trigger OnDeallocate=CreateTrigger()
endglobals
public function RegisterOnEnter takes boolexpr b returns triggercondition
return TriggerAddCondition(OnEnter,b)
endfunction
public function RegisterOnEnterAllocated takes boolexpr b returns triggercondition
return TriggerAddCondition(OnEnterAllocated,b)
endfunction
public function RegisterOnDeallocate takes boolexpr b returns triggercondition
return TriggerAddCondition(OnDeallocate,b)
endfunction
//==============================================================================
function GetIndexUnit takes integer index returns unit
debug if index==0 then
debug call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the unit of index 0.")
debug elseif IndexUnit[index]==null then
debug call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the unit of unassigned index.")
debug endif
return IndexUnit[index]
endfunction
function GetUnitId takes unit u returns integer
debug if u==null then
debug call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the id (inlines) of null unit.")
debug elseif GetUnitUserData(u)==0 then
debug call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to use GetUnitId (inlines) when you should be using GetUnitIndex (unit didn't pass filter).")
debug endif
return GetUnitUserData(u)
endfunction
globals//locals
private integer getindex
endglobals
function GetUnitIndex takes unit u returns integer // Cannot be recursive.
debug if u==null then
debug call BJDebugMsg("|cFFFF0000Error using AIDS:|r Trying to get the index of null unit.")
debug endif
set getindex=GetUnitUserData(u)
if getindex==0 then
// Get new index, from recycler first, else new.
// Store the current index in getindex.
if MaxRecycledIndex==0 then // Get new.
set MaxIndex=MaxIndex+1
set getindex=MaxIndex
else // Get from recycle stack.
set getindex=RecycledIndex[MaxRecycledIndex]
set MaxRecycledIndex=MaxRecycledIndex-1
endif
// Store index on unit.
call SetUnitUserData(u,getindex)
set IndexUnit[getindex]=u
static if USE_PERIODIC_RECYCLER then
// Add index to recycle list.
set MaxDecayingIndex=MaxDecayingIndex+1
set DecayingIndex[MaxDecayingIndex]=getindex
else
// Add leave detection ability.
call UnitAddAbility(ARStackUnit[ARStackLevel],LEAVE_DETECTION_ABILITY)
call UnitMakeAbilityPermanent(ARStackUnit[ARStackLevel],true,LEAVE_DETECTION_ABILITY)
endif
// Do not fire things here. No AIDS structs will be made at this point.
endif
return getindex
endfunction
//==============================================================================
public function AddLock takes integer index returns nothing
set LockLevel[index]=LockLevel[index]+1
endfunction
public function RemoveLock takes integer index returns nothing
set LockLevel[index]=LockLevel[index]-1
static if not USE_PERIODIC_RECYCLER then
if GetUnitUserData(IndexUnit[index])==0 and LockLevel[index]==0 then
// Increment stack for recursion.
set UndefendExpiringIndexLevel=UndefendExpiringIndexLevel+1
set UndefendExpiringIndex[UndefendExpiringIndexLevel]=index
// Fire things.
call TriggerEvaluate(OnDeallocate)
// Decrement stack for recursion.
set UndefendExpiringIndexLevel=UndefendExpiringIndexLevel-1
// Add the index to the recycler stack.
set MaxRecycledIndex=MaxRecycledIndex+1
set RecycledIndex[MaxRecycledIndex]=index
// Null the unit.
set IndexUnit[index]=null
endif
endif
endfunction
//==============================================================================
static if USE_PERIODIC_RECYCLER then
private function PeriodicRecycler takes nothing returns nothing
if MaxDecayingIndex>0 then
set DecayChecker=DecayChecker+1
if DecayChecker>MaxDecayingIndex then
set DecayChecker=1
endif
if GetUnitUserData(IndexUnit[DecayingIndex[DecayChecker]])==0 then
if LockLevel[DecayingIndex[DecayChecker]]==0 then
// Fire things.
call TriggerEvaluate(OnDeallocate)
// Add the index to the recycler stack.
set MaxRecycledIndex=MaxRecycledIndex+1
set RecycledIndex[MaxRecycledIndex]=DecayingIndex[DecayChecker]
// Null the unit.
set IndexUnit[DecayingIndex[DecayChecker]]=null
// Remove index from decay list.
set DecayingIndex[DecayChecker]=DecayingIndex[MaxDecayingIndex]
set MaxDecayingIndex=MaxDecayingIndex-1
endif
endif
endif
endfunction
else
private function UndefendFilter takes nothing returns boolean
return IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD)
endfunction
private function OnUndefendTimer takes nothing returns nothing
loop
exitwhen UndefendStackIndex==0
set UndefendStackIndex=UndefendStackIndex-1
set UndefendExpiringIndex[0]=UndefendIndex[UndefendStackIndex]
if IndexUnit[UndefendExpiringIndex[0]]!=null then
if GetUnitUserData(IndexUnit[UndefendExpiringIndex[0]])==0 then
if LockLevel[UndefendExpiringIndex[0]]==0 then
// Fire things.
call TriggerEvaluate(OnDeallocate)
// Add the index to the recycler stack.
set MaxRecycledIndex=MaxRecycledIndex+1
set RecycledIndex[MaxRecycledIndex]=UndefendExpiringIndex[0]
// Null the unit.
set IndexUnit[UndefendExpiringIndex[0]]=null
endif
endif
endif
endloop
endfunction
globals//locals
private integer UndefendFilterIndex
endglobals
private function OnUndefend takes nothing returns boolean
if GetIssuedOrderId()==852056 then // If undefend then...
set UndefendFilterIndex=GetUnitUserData(GetOrderedUnit())
if UndefendIndex[UndefendStackIndex-1]!=UndefendFilterIndex then // Efficiency perk.
set UndefendIndex[UndefendStackIndex]=UndefendFilterIndex
set UndefendStackIndex=UndefendStackIndex+1
call TimerStart(UndefendTimer,0,false,function OnUndefendTimer)
endif
endif
return false
endfunction
endif
//==============================================================================
public function IndexEnum takes nothing returns boolean // Can be recursive...
// Start by adding another level on the AR stack (for recursion's sake).
set ARStackLevel=ARStackLevel+1
// Store the current unit on the (new) top level of the AR stack.
set ARStackUnit[ARStackLevel]=GetFilterUnit()
if GetUnitUserData(ARStackUnit[ARStackLevel])==0 then // Has not been indexed.
if UnitIndexingFilter(ARStackUnit[ARStackLevel]) then
// Get new index, from recycler first, else new.
// Store the current index on the (new) top level of the AR stack.
if MaxRecycledIndex==0 then // Get new.
set MaxIndex=MaxIndex+1
set ARStackIndex[ARStackLevel]=MaxIndex
else // Get from recycle stack.
set ARStackIndex[ARStackLevel]=RecycledIndex[MaxRecycledIndex]
set MaxRecycledIndex=MaxRecycledIndex-1
endif
// Store index on unit.
call SetUnitUserData(ARStackUnit[ARStackLevel],ARStackIndex[ARStackLevel])
set IndexUnit[ARStackIndex[ARStackLevel]]=ARStackUnit[ARStackLevel]
static if USE_PERIODIC_RECYCLER then
// Add index to recycle list.
set MaxDecayingIndex=MaxDecayingIndex+1
set DecayingIndex[MaxDecayingIndex]=ARStackIndex[ARStackLevel]
else
// Add leave detection ability.
call UnitAddAbility(ARStackUnit[ARStackLevel],LEAVE_DETECTION_ABILITY)
call UnitMakeAbilityPermanent(ARStackUnit[ARStackLevel],true,LEAVE_DETECTION_ABILITY)
endif
// Fire things.
call TriggerEvaluate(OnEnter)
else
// The unit did not pass the filters, so does not need to be auto indexed.
// However, for certain AIDS structs, it may still require indexing.
// These structs may index the unit on their creation.
// We flag that an index must be assigned by setting the current index to 0.
set ARStackIndex[ARStackLevel]=0
// Fire things.
call TriggerEvaluate(OnEnter)
endif
endif
// Decrement the stack.
set ARStackLevel=ARStackLevel-1
return false
endfunction
//==============================================================================
private function InitAIDS takes nothing returns nothing
local region r=CreateRegion()
local group g=CreateGroup()
local integer n=15
static if USE_PERIODIC_RECYCLER then
call TimerStart(UndefendTimer,PERIOD,true,function PeriodicRecycler)
else
local trigger t=CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t,Player(n),EVENT_PLAYER_UNIT_ISSUED_ORDER,Filter(function UndefendFilter))
call SetPlayerAbilityAvailable(Player(n),LEAVE_DETECTION_ABILITY,false)
// Capture "undefend" orders.
exitwhen n==0
set n=n-1
endloop
set n=15
call TriggerAddCondition(t,Filter(function OnUndefend))
set t=null
endif
// This must be done first, due to recursion. :)
call RegionAddRect(r,GetWorldBounds())
call TriggerRegisterEnterRegion(CreateTrigger(),r,Filter(function IndexEnum))
set r=null
loop
call GroupEnumUnitsOfPlayer(g,Player(n),Filter(function IndexEnum))
//Enum every non-filtered unit on the map during initialization and assign it a unique
//index. By using GroupEnumUnitsOfPlayer, even units with Locust can be detected.
exitwhen n==0
set n=n-1
endloop
call DestroyGroup(g)
set g=null
endfunction
//==============================================================================
public struct DEFAULT extends array
method AIDS_onCreate takes nothing returns nothing
endmethod
method AIDS_onDestroy takes nothing returns nothing
endmethod
static method AIDS_filter takes unit u returns boolean
return UnitIndexingFilter(u)
endmethod
static method AIDS_onInit takes nothing returns nothing
endmethod
endstruct
//===========================================================================
// Never create or destroy AIDS structs directly.
// Also, do not initialise members except by using the AIDS_onCreate method.
//===========================================================================
//! textmacro AIDS
// This magic line makes default methods get called which do nothing
// if the methods are otherwise undefined.
private static delegate AIDS_DEFAULT AIDS_DELEGATE=0
//-----------------------------------------------------------------------
// Gotta know whether or not to destroy on deallocation...
private boolean AIDS_instanciated
//-----------------------------------------------------------------------
static method operator[] takes unit whichUnit returns thistype
return GetUnitId(whichUnit)
endmethod
method operator unit takes nothing returns unit
// Allows structVar.unit to return the unit.
return GetIndexUnit(this)
endmethod
//-----------------------------------------------------------------------
method AIDS_addLock takes nothing returns nothing
call AIDS_AddLock(this)
endmethod
method AIDS_removeLock takes nothing returns nothing
call AIDS_RemoveLock(this)
endmethod
//-----------------------------------------------------------------------
private static method AIDS_onEnter takes nothing returns boolean
// At this point, the unit might not have been assigned an index.
if thistype.AIDS_filter(AIDS_GetEnteringIndexUnit()) then
// Flag it for destruction on deallocation.
set thistype(AIDS_GetIndexOfEnteringUnit()).AIDS_instanciated=true
// Can use inlining "Assigned" function now, as it must be assigned.
call thistype(AIDS_GetIndexOfEnteringUnitAllocated()).AIDS_onCreate()
endif
return false
endmethod
private static method AIDS_onEnterAllocated takes nothing returns boolean
// At this point, the unit must have been assigned an index.
if thistype.AIDS_filter(AIDS_GetEnteringIndexUnit()) then
// Flag it for destruction on deallocation. Slightly faster!
set thistype(AIDS_GetIndexOfEnteringUnitAllocated()).AIDS_instanciated=true
// Can use inlining "Assigned" function now, as it must be assigned.
call thistype(AIDS_GetIndexOfEnteringUnitAllocated()).AIDS_onCreate()
endif
return false
endmethod
private static method AIDS_onDeallocate takes nothing returns boolean
if thistype(AIDS_GetDecayingIndex()).AIDS_instanciated then
call thistype(AIDS_GetDecayingIndex()).AIDS_onDestroy()
// Unflag destruction on deallocation.
set thistype(AIDS_GetDecayingIndex()).AIDS_instanciated=false
endif
return false
endmethod
//-----------------------------------------------------------------------
private static method onInit takes nothing returns nothing
call AIDS_RegisterOnEnter(Filter(function thistype.AIDS_onEnter))
call AIDS_RegisterOnEnterAllocated(Filter(function thistype.AIDS_onEnterAllocated))
call AIDS_RegisterOnDeallocate(Filter(function thistype.AIDS_onDeallocate))
// Because I robbed you of your struct's onInit method.
call thistype.AIDS_onInit()
endmethod
//! endtextmacro
endlibrary
library PUI uses AIDS
//===========================================================================
// Allowed PUI_PROPERTY TYPES are: unit, integer, real, boolean, string
// Do NOT put handles that need to be destroyed here (timer, trigger, ...)
// Instead put them in a struct and use PUI textmacro
//===========================================================================
//! textmacro PUI_PROPERTY takes VISIBILITY, TYPE, NAME, DEFAULT
$VISIBILITY$ struct $NAME$
private static unit array pui_unit
private static $TYPE$ array pui_data
//-----------------------------------------------------------------------
// Returns default value when first time used
//-----------------------------------------------------------------------
static method operator[] takes unit whichUnit returns $TYPE$
local integer pui = GetUnitId(whichUnit) // Changed from GetUnitIndex.
if .pui_unit[pui] != whichUnit then
set .pui_unit[pui] = whichUnit
set .pui_data[pui] = $DEFAULT$
endif
return .pui_data[pui]
endmethod
//-----------------------------------------------------------------------
static method operator[]= takes unit whichUnit, $TYPE$ whichData returns nothing
local integer pui = GetUnitIndex(whichUnit)
set .pui_unit[pui] = whichUnit
set .pui_data[pui] = whichData
endmethod
endstruct
//! endtextmacro
//===========================================================================
// Never destroy PUI structs directly.
// Use .release() instead, will call .destroy()
//===========================================================================
//! textmacro PUI
private static unit array pui_unit
private static integer array pui_data
private static integer array pui_id
//-----------------------------------------------------------------------
// Returns zero if no struct is attached to unit
//-----------------------------------------------------------------------
static method operator[] takes unit whichUnit returns integer
local integer pui = GetUnitId(whichUnit) // Changed from GetUnitIndex.
// Switched the next two lines for optimisation.
if .pui_unit[pui] != whichUnit then
if .pui_data[pui] != 0 then
// recycled index detected
call .destroy(.pui_data[pui])
set .pui_unit[pui] = null
set .pui_data[pui] = 0
endif
endif
return .pui_data[pui]
endmethod
//-----------------------------------------------------------------------
// This will overwrite already attached struct if any
//-----------------------------------------------------------------------
static method operator[]= takes unit whichUnit, integer whichData returns nothing
local integer pui = GetUnitIndex(whichUnit)
if .pui_data[pui] != 0 then
call .destroy(.pui_data[pui])
endif
set .pui_unit[pui] = whichUnit
set .pui_data[pui] = whichData
set .pui_id[whichData] = pui
endmethod
//-----------------------------------------------------------------------
// If you do not call release struct will be destroyed when unit handle gets recycled
//-----------------------------------------------------------------------
method release takes nothing returns nothing
local integer pui= .pui_id[integer(this)]
call .destroy()
set .pui_unit[pui] = null
set .pui_data[pui] = 0
endmethod
//! endtextmacro
endlibrary
library AutoIndex uses AIDS
module AutoData
private static thistype array data
// Fixed up the below to use thsitype instead of integer.
static method operator []= takes unit u, thistype i returns nothing
set .data[GetUnitId(u)] = i //Just attaching a struct to the unit
endmethod //using the module's thistype array.
static method operator [] takes unit u returns thistype
return .data[GetUnitId(u)] //Just returning the attached struct.
endmethod
endmodule
endlibrary
//TESH.scrollpos=54
//TESH.alwaysfold=0
//
// ___ _ _ __ __ __ __ __ __
// | \| | | |/ |/ |/ |/ |\ \/ /
// | |) | |_| | / | / | / | / | \ /
// |___/\____/_/|__/|_|/|__/|_|_|_|__
// / _/ /_\ / __\_ _| __| _ \
// | |_ / _ \\__ \ | | | __| _ /
// \___\_/ \_\___/ |_| |____|_|\_\ By Jesus4Lyf
//
// What is DummyCaster?
// —————————————————————
// DummyCaster is designed to be the perfect dummy caster for dummy abilities.
// There has been a lot of thought put into this unit type, and dummy casting
// has evolved over the years of WC3 mapping. These days, best practise is that
// damage is triggered, and the effects of an ability such as slow or stun
// are applied through a global dummy caster (which is owned by Neutral Hostile).
//
// A lot of thought has been put into this unit. It has no mana, because if
// it had mana then it could potentially run out and suddenly fail without
// an apparent reason. It has no movement speed or casting time, allowing it
// to instantly cast. Hence, this library only exposes one thing. A "DUMMY"
// unit constant (global variable).
//
// You may provide this unit with a model by having a model imported into the
// path "Dummy.mdx". The purpose of this is allowing the same unit type
// to be created dynamically for special effect attachment.
//
// The rawcode of the "Dummy Caster" type is 'dumy'.
//
// Upon issueing the order to cast a spell using the DUMMY global, as long as
// the spell is instant, the casting will occur before the next line of
// JASS code is executed, meaning you can cast in a loop or a ForGroup, etc
// without bugging or dynamically creating (or recycling) dummies.
//
// The initialiser is in a struct because struct onInit methods are called
// before library "initializers". This allows abilities to be added on the
// constant DUMMY unit on map initialisation.
//
// Spells that this dummy casts should have no mana cost, no cooldown, no
// cast time and infinite range. They also must be able to be cast from a
// Neutral Hostile unit to your target, meaning they must be castable on
// enemies (if you must, you can change the owner of the dummy for the cast,
// and then change it back if you need to have it target allied units and such).
//
// Be sure to add your spell to the dummy before trying to cast it! :)
// Beware of permenantly adding spells with conflicting order ids/strings.
//
// How to implement?
// ———————————————————
// Create a new trigger object called DummyCaster, go to 'Edit -> Convert to
// Custom Text', and replace everything that's there with this script.
//
// Save the map, close it, reopen it, and then delete the "!" from the
// FAR left side of the next line (so "external" will line up with this line):
// external ObjectMerger w3u ushd dumy unam "Dummy Caster" uabi Aloc ucbs 0 ucpt 0 umvs 0 ushu "" umvh 0 umdl "Dummy.mdl" umpi 100000 umpm 100000 umpr 1000 ufoo 0
//
// Thanks:
// —————————
// - Viikuna for demonstrating how to make dummy casters cast instantaneously.
//
library DummyCaster
// If you're looking for where the 'dumy' type is declared, it is declared
// in the object merger line at the end of "How to implement?" in the above
// documentation.
globals
// If this is changed, the object merger line must also be changed
// before the second implementation step is followed.
constant integer DUMMY_TYPE='u000'
// This shouldn't be changed, but in some maps perhaps it is necessary.
constant player DUMMY_OWNER=Player(PLAYER_NEUTRAL_AGGRESSIVE)
// Just because these belong here:
private constant real CREATED_AT_X=0.0
private constant real CREATED_AT_Y=0.0
//=====================================================================================
unit DUMMY=null
endglobals
private struct Initializer extends array // "extends array" removes
// create/destoy methods.
// The initialisation is done this way because struct initialisers are
// called before library initialisers, making this important for adding
// abilities on map initialisation.
private static method onInit takes nothing returns nothing
set DUMMY=CreateUnit(DUMMY_OWNER,DUMMY_TYPE,CREATED_AT_X,CREATED_AT_Y,0)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
// AutoFly - by Azlier, AIDS version by Jesus4Lyf
// Requires a vJass preprocessor, AIDS
// How to import:
// 1. Create a new trigger called AutoFly.
// 2. Convert the trigger to custom script, and replace all the code inside with this.
// 3. Import AIDS if it is not in your map already.
library AutoFly requires AIDS
private struct Hack extends array
private static method AIDS_filter takes unit u returns boolean
if UnitAddAbility(u,'Amrf') then
call UnitRemoveAbility(u,'Amrf')
endif
return false
endmethod
//! runtextmacro AIDS()
endstruct
endlibrary
//TESH.scrollpos=240
//TESH.alwaysfold=0
scope Torrent
/*
Requires Status, T32, TimerUtils, AutoFly
Thus Status requires AIDS and DummyCaster as well.
*Torrent v1.1d by baassee
Description:
Using his unparalleled knowledge of the sea,
Kunkka is able to summon a blast of water at
a targeted area. After 2 seconds a fierce
torrent of water erupts from the ground, the
stream blasting enemies caught in the AoE into
the sky and dealing damage.
Level 1 - 120 damage.
Level 2 - 180 damage.
Level 3 - 240 damage.
Level 4 - 300 damage.
*FAQ about code
The code contains two structs, one for just the initial delay of two seocnds
and the second for the actual eruption.
I used GT as I am used to it.
I used Status because it's the best out there at the moment.
I used AutoFly(Aids Version) because I had AIDS already with Status
I recommend though using UnitIndexer by Nestharus with the AIDS BC
Can be found at this link below:
http://www.hiveworkshop.com/forums/jass-functions-413/system-unit-indexer-172090/
Yes I didn't want the spell to stack with itself because it would have looked ridiculous with the height changes.
And I was lazy so that's the reason behind the stackgroup.
Typical parabola function, first made by Moyack and Spec(?) anyway it's way too common to be credited.
And there are two boolean constants
one for pausing or not pausing (will stun if not paused)
second for preloading or not preloading
*Information
Yes this spell is based on DotA's Admiral's Torrent spell. It's exactly the same except
the slowing part and the height (couldn't find the maximum height at playdota).
Also added an option to pause or not pause the units thrown up in the air.
I cannot use any custom icon although I recommend using this icon:
http://www.hiveworkshop.com/forums/icons-541/btntorrent-162809/?prev=search%3Dtorrent%26d%3Dlist%26r%3D20
The TidalEruption model was found in a spellpack by RMX, no credits were actually given in that spellpack
thus I don't know who's the author of the model but it's not mine.
*Credits
*Status, AIDS, T32, GTrigger, DummyCaster - Jesus4Lyf
*TimerUtils - Vexorian
*GroupUtils - Rising_Dusk
*Autofly - Azlier
*TidalEruption model - Unknown Author
Also remember to give me credits if the spell is used along with the authors above.
*How to import
1. Import all required Libraries and create the object data (AIDS, Status, DummyCaster)
2. Copy this code and paste into a trigger or copy the trigger.
3. Copy the ability and change the ABILID to the new id given.
4. Give the spell to a hero, credit me and the authors in the credits section above and enjoy!
*Changelog
v1.0 - Released
v1.1 - Made GTrigger optional along with making SpellEffectEvent optional as well.
- Made Damage optional.
- Made GroupUtils optional.
- Changed Condition into Filter.
v1.1b- Fixed a mistake with optionalizing GT and SpellEffectEvent.
v1.1c- Forgot to static if out GroupEnumUnitsInArea which made it uncompileable.
v1.1d- Removed GetWidgetLife(u) > 0.405 and just because of "I could add this"
I added a FoG loop instead of groupenumeration + filter.
Also made the filter among the configuration functions.
**************************************************************************************************************************
*Configurables
*/
//CONSTANTS
globals
//The abilityid when pasting into the object editor
private constant integer ABILID = 'A000'
//the ground effect that will be on the ground during the 2 seconds delay
private constant string GROUNDEFFECT = "Objects\\Spawnmodels\\Other\\IllidanFootprint\\IllidanWaterSpawnFootPrint.mdl"
//the splash effect when the delay reached 0.
private constant string SPLASHEFFECT = "war3mapImported\\TidalEruption.mdx"
//the attacktype of the damage
private constant attacktype ATT = ATTACK_TYPE_NORMAL
//damagetype of the damage
private constant damagetype DAM = DAMAGE_TYPE_MAGIC
//weapontype of the damage
private constant weapontype WEA = null
//if you want the spell to pause the units or not
//if false then it will stun them instead
private constant boolean PAUSE = false
//preload the specialeffects used?
private constant boolean PRELOAD = true
//don't touch this, it's because it would look stupid without it
//and I'm lazy of course
private group stackgroup = CreateGroup()
endglobals
//FUNCTIONS
//the delay before the eruption
private function GetDelay takes integer lvl returns real
return 2. + lvl * 0.
endfunction
//the aoe of the spell
private function GetAoe takes integer lvl returns real
return 200. + lvl * 0.
endfunction
//the damage dealt
private function GetDmg takes integer lvl returns real
return 60. + 60. * lvl
endfunction
//the duration in the air, taken from playdota.com
private function GetDur takes integer lvl returns real
return 1.53 + lvl*0.
endfunction
//the maximum height the units thrown in the air will reach
//no idea what the original value is
private function GetHei takes integer lvl returns real
return 400. + lvl * 0.
endfunction
private function GetFilter takes unit u, player p returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and/*
*/ IsUnitEnemy(u, p) and/*
*/ not IsUnitInGroup(u, stackgroup) and/*
*/ not IsUnitType(u, UNIT_TYPE_STRUCTURE) and/*
*/ not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)
endfunction
// END OF CONFIGURABLES
//standard parabola formula
private function ParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)
endfunction
//eruption struct, the struct throwing units in the air
private struct Eruption extends array
unit u //unit in the air
real counter //counter to cheat the parabola function
real dur //duration in the air, cheats the parabola function as maxdistance
real h //maximum height
//recycling variables
static integer ic = 0
static thistype r = 0
thistype rn
//loop method
private method periodic takes nothing returns nothing
set .counter = .counter + T32_PERIOD //increasing "x" in the parabola function
call SetUnitFlyHeight(.u, ParabolaZ(.h, .dur, .counter), 0.) //sets the new flyheight of the unit
if .counter >= .dur then //checks if the spell has ended or not
static if PAUSE then //static if to check if pause is allowed or not
call Status[.u].removePause()
else
call Status[.u].removeStun()
endif
call SetUnitFlyHeight(.u, GetUnitDefaultFlyHeight(.u), 0.) //return to the default flying height
call GroupRemoveUnit(stackgroup, .u) //remove the unit from the stackgroup
call .stopPeriodic()//stop the periodic
set rn = r //recycling structs
set r = this // - || -
endif
endmethod
implement T32x
//create method
static method create takes unit u, real dur, real h returns thistype
local thistype this //dunno what to call it, indexing?
if (r == 0) then
set ic = ic + 1
set this = ic
else
set this = r
set r = r.rn
endif
set .u = u //unit
set .counter = 0. //initializing the counter
set .dur = dur //duration
set .h = h //height
call GroupAddUnit(stackgroup, u)//add the unit to the stackgroup
static if PAUSE then //static if about pausing
call Status[u].addPause()
else
call Status[u].addStun() //else we stun the unit
endif
call .startPeriodic() //fire the periodic (t32)
return this
endmethod
endstruct
//the delay struct
private struct Torrent extends array
unit caster //casting unit
real dmg //dmg
real aoe //aoe
real x //the targetx
real y //the targety
real dur //duration for the eruption struct
real h //height yes we need it here as well
effect eff //special effect on the ground
//recycle variables
static integer ic = 0
static thistype r = 0
thistype rn
static thistype dat //for the filter function
static if not LIBRARY_GroupUtils then
static group ENUM_GROUP = CreateGroup()
endif
static method secondphase takes nothing returns nothing
local timer t = GetExpiredTimer() //track the timer
local thistype this = GetTimerData(t) //get the data
local unit u
call DestroyEffect(.eff) //destroy the effect on the ground
set dat = this //for the filter method
call DestroyEffect(AddSpecialEffect(SPLASHEFFECT, .x, .y)) //create the eruption effect
// just because this is faster...
static if LIBRARY_GroupUtils then
call GroupEnumUnitsInArea(ENUM_GROUP, .x, .y, .aoe, null) //enum
else
call GroupEnumUnitsInRange(ENUM_GROUP, .x, .y, .aoe, null)
endif
loop
set u = FirstOfGroup(ENUM_GROUP)
exitwhen null == u
if GetFilter(u, GetOwningPlayer(.caster)) then
static if LIBRARY_Damage then
call Damage_Spell(.caster, u, .dmg)
else
call UnitDamageTarget(.caster, u, .dmg, false,false, ATT, DAM, WEA)
endif
call Eruption.create(u, .dur, .h)
endif
call GroupRemoveUnit(ENUM_GROUP, u)
endloop
//endfaster
call ReleaseTimer(t) //recycle timer
set t = null //null local
set u = null
//recycle part
set rn = r
set r = this
endmethod
static method create takes nothing returns thistype
local thistype this
local integer lvl = GetUnitAbilityLevel(GetTriggerUnit(), ABILID) //because I want to set it at declaration not after
local timer t = NewTimer() //get timer
local string s = GROUNDEFFECT //local player thingie
if (r == 0) then //indexing part?
set ic = ic + 1
set this = ic
else
set this = r
set r = r.rn
endif
set .caster = GetTriggerUnit() //casting unit
set .dmg = GetDmg(lvl) //dmg
set .aoe = GetAoe(lvl) //aoe
if IsPlayerEnemy(GetLocalPlayer(), GetTriggerPlayer()) then //to make the effect only show for allies
set s = ""
endif
set .x = GetSpellTargetX() //targetx
set .y = GetSpellTargetY() //targety
set .dur = GetDur(lvl) //duration
set .h = GetHei(lvl) //height
set .eff = AddSpecialEffect(s, .x, .y) //create the effect
call SetTimerData(t, this)
call TimerStart(t, GetDelay(lvl), false, function thistype.secondphase) //fire timer with the delay
set t = null //nullling
return this
endmethod
static method condition takes nothing returns boolean
static if not LIBRARY_GT then
static if not LIBRARY_SpellEffectEvent then
if GetSpellAbilityId() == ABILID then
call thistype.create()
endif
else
call thistype.create()
endif
else
call thistype.create()
endif
return false
endmethod
//initializing
private static method onInit takes nothing returns nothing
local trigger t
static if LIBRARY_GT then
call TriggerAddCondition(GT_RegisterStartsEffectEvent(CreateTrigger(), ABILID), Filter(function thistype.condition))
else
static if LIBRARY_SpellEffectEvent then
call RegisterSpellEffectEvent(ABILID, function thistype.condition)
else
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Filter(function thistype.condition))
set t = null
endif
endif
static if PRELOAD then //to preload or not preload
call Preload(GROUNDEFFECT)
call Preload(SPLASHEFFECT)
endif
endmethod
endstruct //end of story
endscope