Cần giúp về skill Jass Necromastery

Thảo luận trong 'World Editor' bắt đầu bởi hieu2525, 21/6/11.

  1. hieu2525

    hieu2525 Mr & Ms Pac-Man

    Tham gia ngày:
    23/3/09
    Bài viết:
    111
    Nơi ở:
    HN
    Em đang muốn cóp skill Necromastery của SF vào map của em nhưng em ko biết gì về Jass, vậy mọi người có thể giúp em sửa về mấy cái trong trigger đc ko ạ :-s



    [spoil]scope Necromastery initializer SetUp // requires Timer32, GTrigger

    globals
    private integer array DAMAGEID[4]
    endglobals

    //===========================================================================
    // CONFIGURABLES
    //===========================================================================

    globals
    private constant integer ABILID = 'ABNe' // raw code of ability "Necromastery"
    public constant integer DUMABILID = 'ANe0' // raw code of ability "Necromastery (Display)"
    private constant integer DUMMYID = 'nECD' // raw code of unit "Necromastery Dummy"

    private constant integer DAMAGE = 2 // damage bonus per soul

    private constant real COL = 50.0 // collision size of the soul
    private constant real SPEED = 500.0 // distance traveled by the soul per second
    private constant real TRUESPEED = SPEED * T32_PERIOD // distance traveled by the soul per period
    private constant string DEATHART = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl" // death art used upon soul expiration
    private constant string DEATHARTPOINT = "chest" // attachment point of DEATHART
    endglobals

    private function SetUp takes nothing returns nothing
    local integer i = 0
    local unit u = CreateUnit(Player(13), DUMMYID, 0, 0, 0)

    set DAMAGEID[0] = 'dmg0' // raw code of ability "Damage (10000's) (Necromastery)"
    set DAMAGEID[1] = 'dmg1' // raw code of ability "Damage (1000's) (Necromastery)"
    set DAMAGEID[2] = 'dmg2' // raw code of ability "Damage (100's) (Necromastery)"
    set DAMAGEID[3] = 'dmg3' // raw code of ability "Damage (10's) (Necromastery)"
    set DAMAGEID[4] = 'dmg4' // raw code of ability "Damage (1's) (Necromastery)"

    //preload
    loop
    exitwhen i > 4
    call UnitAddAbility(u, DAMAGEID)
    set i = i + 1
    endloop
    call UnitAddAbility(u, DUMABILID)
    call RemoveUnit(u)
    set u = null
    endfunction

    private function GetMaxSoul takes integer level returns integer // maximum number of souls
    if level == 1 then
    return 8
    elseif level == 2 then
    return 15
    elseif level == 3 then
    return 23
    elseif level == 4 then
    return 30
    endif
    return 0
    endfunction

    private function GetSoulLost takes integer level returns real
    return 0.50 // amount of souls lost on death, where 1.0 = 100%
    endfunction

    //===========================================================================
    // END CONFIGURABLES
    //===========================================================================

    private struct Data
    unit killer
    unit dummy

    private static method setDamage takes unit u returns nothing
    local integer damage = DAMAGE * (GetUnitAbilityLevel(u, DUMABILID) - 1)
    local integer factor = 10000
    local integer level
    local integer i = 0

    loop
    exitwhen i > 4
    set level = damage / factor
    call SetUnitAbilityLevel(u, DAMAGEID, level + 1)
    set damage = damage - (level * factor)
    set factor = factor / 10
    set i = i + 1
    endloop
    endmethod

    private method periodic takes nothing returns nothing
    local integer level
    local real x = GetUnitX(this.dummy)
    local real y = GetUnitY(this.dummy)
    local real dx = GetUnitX(this.killer) - x
    local real dy = GetUnitY(this.killer) - y
    local real a
    local real height
    local real dist = SquareRoot(dx * dx + dy * dy)

    if dist <= 50.0 then
    set level = GetUnitAbilityLevel(this.killer, DUMABILID)
    if level < GetMaxSoul(GetUnitAbilityLevel(this.killer, ABILID)) + 1 then
    call UnitRemoveAbility(this.killer, DUMABILID)
    call UnitAddAbility(this.killer, DUMABILID)
    call SetUnitAbilityLevel(this.killer, DUMABILID, level + 1)
    call setDamage(this.killer)
    endif
    call DestroyEffect(AddSpecialEffectTarget(DEATHART, this.killer, DEATHARTPOINT))
    call RemoveUnit(this.dummy)
    call this.stopPeriodic()
    call this.deallocate()
    else
    set a = Atan2(dy, dx)
    call SetUnitX(this.dummy, x + TRUESPEED * Cos(a))
    call SetUnitY(this.dummy, y + TRUESPEED * Sin(a))
    set height = GetUnitFlyHeight(this.dummy)
    call SetUnitFlyHeight(this.dummy, height + ((GetUnitFlyHeight(this.killer) + 100) - height) / (dist / TRUESPEED), 0)
    endif
    endmethod
    implement T32x

    private static method actions takes nothing returns boolean
    local thistype this
    local unit u = GetTriggerUnit()
    local unit killer = GetKillingUnit()
    local integer ulevel = GetUnitAbilityLevel(u, ABILID)
    local integer klevel = GetUnitAbilityLevel(killer, ABILID)
    local integer i
    local real x
    local real y

    if ulevel > 0 then
    set i = R2I((GetUnitAbilityLevel(u, DUMABILID) - 1) * GetSoulLost(ulevel))
    call UnitRemoveAbility(u, DUMABILID)
    call UnitAddAbility(u, DUMABILID)
    call SetUnitAbilityLevel(u, DUMABILID, i + 1)
    call setDamage(u)
    elseif klevel > 0 then
    set this = this.allocate()
    set x = GetUnitX(u)
    set y = GetUnitY(u)
    set this.killer = killer
    set this.dummy = CreateUnit(Player(13), DUMMYID, x, y, Atan2(GetUnitY(this.killer) - y, GetUnitX(this.killer) - x) * bj_RADTODEG)

    call this.startPeriodic()
    endif

    set u = null
    set killer = null
    return false
    endmethod

    private static method learn takes nothing returns boolean
    local unit u = GetTriggerUnit()
    local integer i

    if GetUnitAbilityLevel(u, DUMABILID) == 0 then
    call UnitAddAbility(u, DUMABILID)

    set i = 0
    loop
    exitwhen i > 4
    call UnitAddAbility(u, DAMAGEID)
    set i = i + 1
    endloop
    endif

    set u = null
    return false
    endmethod

    private static method onInit takes nothing returns nothing
    local trigger t = CreateTrigger()

    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(t, Condition(function thistype.actions))
    set t = null

    set t = CreateTrigger()
    call GT_RegisterLearnsAbilityEvent(t, ABILID)
    call TriggerAddCondition(t, Condition(function thistype.learn))
    set t = null
    endmethod
    endstruct

    endscope[/spoil]

    Còn đây là mấy cái system của nó ạ
    [spoil]//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //~~ 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[/spoil]

    [spoil]//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //~~ 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=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
    [/spoil]

    [spoil]//
    // ___ _ __ __ _ ___ ____ _______________________________
    // | \ /_\ / |/ | /_\ / _\| __| || D E A L I T , ||
    // | |) / _ \ / / | / |/ _ \| |/|| __| || D E T E C T I T , ||
    // |___/_/ \_/_/|__/|_|_/ \_\___/|____| || B L O C K I T . ||
    // By Jesus4Lyf _______________________________
    // v 1.0.1
    // What is Damage?
    // _________________
    // Damage is a damage dealing, detection and blocking system. It implements
    // all such functionality. It also provides a means to detect what type
    // of damage was dealt, so long as all damage in your map is dealt using
    // this system's deal damage functions (except for basic attacks).
    //
    // It is completely recursively defined, meaning if you deal damage on
    // taking damage, the type detection and other features like blocking
    // will not malfunction.
    //
    // How to implement?
    // ___________________
    // Create a new trigger object called Damage, go to 'Edit -> Convert to
    // Custom Text', and replace everything that's there with this script.
    //
    // At the top of the script, there is a '//! external ObjectMerger' line.
    // Save your map, close your map, reopen your map, and then comment out this
    // line. Damage is now implemented. This line creates a dummy ability used
    // in the system in some circumstances with damage blocking.
    //
    // Functions:
    // ____________
    // function Damage_RegisterEvent takes trigger whichTrigger returns nothing
    // - This registers a special "any unit takes damage" event.
    // - This event supports dynamic trigger use.
    // - Only triggers registered on this event may block damage.
    //
    // function Damage_GetType takes nothing returns damagetype
    // - This will get the type of damage dealt, like an event response,
    // for when using a unit takes damage event (or the special event above).
    //
    // function Damage_Block takes real amount returns nothing
    // function Damage_BlockAll takes nothing returns nothing
    // - For use only with Damage_RegisterEvent.
    // - Blocks 'amount' of the damage dealt.
    // - Multiple blocks at once work correctly.
    // - Blocking more than 100% of the damage will block 100% instead.
    // - Damage_BlockAll blocks 100% of the damage being dealt.
    //
    // function Damage_EnableEvent takes boolean enable returns nothing
    // - For disabling and re-enabling the special event.
    // - Use it to deal damage which you do not want to be detected by
    // the special event.
    //
    // function UnitDamageTargetEx takes lots of things returns boolean
    // - Replaces UnitDamageTarget in your map, with the same arguments.
    //
    // function Damage_Physical takes unit source, unit target, real amount,
    // attacktype whichType, boolean attack, boolean ranged returns boolean
    // - A clean wrapper for physical damage.
    // - 'attack' determines if this is to be treated as a real physical
    // attack or just physical type damage.
    // - 'ranged' determines if this is to be treated as a ranged or melee
    // attack.
    //
    // function Damage_Spell takes unit source, unit target, real amount returns boolean
    // - A clean wrapper for spell damage.
    //
    // function Damage_Pure takes unit source, unit target, real amount returns boolean
    // - A clean wrapper for pure type damage (universal type, 100% damage).
    //
    // Thanks:
    // _________
    // - Romek, for helping me find a better way to think about damage blocking.
    //
    library Damage initializer OnInit uses AIDS, Event
    //============================================================
    ////! external ObjectMerger w3a AIlz dprv anam "Life Bonus" ansf "(Damage System)" Ilif 1 500000 aite 0
    globals
    private constant integer LIFE_BONUS_ABIL='dprv'
    endglobals

    //============================================================
    globals
    private Event OnDamageEvent
    private boolean EventEnabled=true
    endglobals

    public function RegisterEvent takes trigger whichTrigger returns nothing
    call OnDamageEvent.register(whichTrigger)
    endfunction

    public function EnableEvent takes boolean enable returns nothing
    set EventEnabled=enable
    endfunction

    //============================================================
    globals
    private integer TypeStackLevel=0
    private damagetype array TypeStackValue
    private real array ToBlock
    endglobals

    public function GetType takes nothing returns damagetype
    return TypeStackValue[TypeStackLevel]
    endfunction

    public function Block takes real amount returns nothing
    set ToBlock[TypeStackLevel]=ToBlock[TypeStackLevel]+amount
    endfunction

    public function BlockAll takes nothing returns nothing
    set ToBlock[TypeStackLevel]=ToBlock[TypeStackLevel]+GetEventDamage()
    endfunction

    //============================================================
    globals
    private integer BlockNum=0
    private unit array BlockUnit
    private real array BlockUnitLife
    private real array BlockRedamage
    private unit array BlockDamageSource

    private timer BlockTimer=CreateTimer()
    endglobals

    //============================================================
    globals
    private unit array RemoveBoosted
    private integer RemoveBoostedMax=0

    private timer RemoveBoostedTimer=CreateTimer()
    endglobals

    globals//locals
    private real BoostedLifeTemp
    private unit BoostedLifeUnit
    endglobals
    private function RemoveBoostedTimerFunc takes nothing returns nothing
    loop
    exitwhen RemoveBoostedMax==0
    set BoostedLifeUnit=RemoveBoosted[RemoveBoostedMax]
    set BoostedLifeTemp=GetWidgetLife(BoostedLifeUnit)
    call UnitRemoveAbility(BoostedLifeUnit,LIFE_BONUS_ABIL)
    if BoostedLifeTemp>0.405 then
    call SetWidgetLife(BoostedLifeUnit,BoostedLifeTemp)
    endif
    set RemoveBoostedMax=RemoveBoostedMax-1
    endloop
    endfunction

    //============================================================
    private keyword Detector // Darn, I actually had to do this. XD
    globals//locals
    private unit ForUnit
    private real NextHealth
    endglobals
    private function OnDamageActions takes nothing returns boolean
    if EventEnabled then
    call OnDamageEvent.fire()
    endif
    if ToBlock[TypeStackLevel]!=0. then
    //====================================================
    // Blocking
    set ForUnit=GetTriggerUnit()

    set NextHealth=GetEventDamage()
    if ToBlock[TypeStackLevel]>=NextHealth then
    set NextHealth=GetWidgetLife(ForUnit)+NextHealth
    else
    set NextHealth=GetWidgetLife(ForUnit)+ToBlock[TypeStackLevel]
    endif

    call SetWidgetLife(ForUnit,NextHealth)
    if GetWidgetLife(ForUnit)<NextHealth then
    // NextHealth is over max health.
    call UnitAddAbility(ForUnit,LIFE_BONUS_ABIL)
    call SetWidgetLife(ForUnit,NextHealth)

    set RemoveBoostedMax=RemoveBoostedMax+1
    set RemoveBoosted[RemoveBoostedMax]=ForUnit
    call ResumeTimer(RemoveBoostedTimer)
    endif
    //====================================================
    set ToBlock[TypeStackLevel]=0.
    endif
    return false
    endfunction

    //============================================================
    function UnitDamageTargetEx takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
    local boolean result
    set TypeStackLevel=TypeStackLevel+1
    set TypeStackValue[TypeStackLevel]=damageType
    set result=UnitDamageTarget(whichUnit,target,amount,attack,ranged,attackType,damageType,weaponType)
    set TypeStackLevel=TypeStackLevel-1
    return result
    endfunction
    //! textmacro Damage__DealTypeFunc takes NAME, TYPE
    public function $NAME$ takes unit source, unit target, real amount returns boolean
    return UnitDamageTargetEx(source,target,amount,false,false,ATTACK_TYPE_NORMAL,$TYPE$,WEAPON_TYPE_WHOKNOWS)
    endfunction
    //! endtextmacro

    //! runtextmacro Damage__DealTypeFunc("Pure","DAMAGE_TYPE_UNIVERSAL")
    //! runtextmacro Damage__DealTypeFunc("Spell","DAMAGE_TYPE_MAGIC")

    // Uses different stuff, but works much the same way.
    public function Physical takes unit source, unit target, real amount, attacktype whichType, boolean attack, boolean ranged returns boolean
    return UnitDamageTargetEx(source,target,amount,attack,ranged,whichType,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
    endfunction

    //============================================================
    private struct Detector extends array // Uses AIDS.
    //! runtextmacro AIDS()

    private static conditionfunc ACTIONS_COND

    private trigger t

    private method AIDS_onCreate takes nothing returns nothing
    set this.t=CreateTrigger()
    call TriggerAddCondition(this.t,thistype.ACTIONS_COND)
    call TriggerRegisterUnitEvent(this.t,this.unit,EVENT_UNIT_DAMAGED)
    endmethod

    private method AIDS_onDestroy takes nothing returns nothing
    call DestroyTrigger(this.t)
    endmethod

    private static method AIDS_onInit takes nothing returns nothing
    set thistype.ACTIONS_COND=Condition(function OnDamageActions)
    endmethod
    endstruct

    //============================================================
    private function OnInit takes nothing returns nothing
    local unit abilpreload=CreateUnit(Player(15),'uloc',0,0,0)
    call UnitAddAbility(abilpreload,LIFE_BONUS_ABIL)
    call RemoveUnit(abilpreload)
    set abilpreload=null

    set OnDamageEvent=Event.create()
    set TypeStackValue[TypeStackLevel]=DAMAGE_TYPE_NORMAL
    call TimerStart(RemoveBoostedTimer,0.0,false,function RemoveBoostedTimerFunc)
    endfunction
    endlibrary
    [/spoil]

    [spoil]//
    // _ ___ ___ ___ _______________________________________________
    // /_\ |_ _| \/ __| || 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.0.3
    // 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.
    //
    // 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 real PERIOD = 0.03125 // Recycles 32 units/second max.
    endglobals // Lower to be able to recycle faster.

    private constant 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
    // 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
    return DecayingIndex[DecayChecker]
    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.
    set getindex=GetUnitId(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

    // Add index to recycle list.
    set MaxDecayingIndex=MaxDecayingIndex+1
    set DecayingIndex[MaxDecayingIndex]=getindex

    // 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
    endfunction

    //==============================================================================
    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

    //==============================================================================
    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 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]

    // Add index to recycle list.
    set MaxDecayingIndex=MaxDecayingIndex+1
    set DecayingIndex[MaxDecayingIndex]=ARStackIndex[ARStackLevel]

    // 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

    // 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

    // This must be done first, due to recursion. :)
    call RegionAddRect(r,bj_mapInitialPlayableArea)
    call TriggerRegisterEnterRegion(CreateTrigger(),r,Condition(function IndexEnum))
    set r=null

    loop
    call GroupEnumUnitsOfPlayer(g,Player(n),Condition(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

    call TimerStart(CreateTimer(),PERIOD,true,function PeriodicRecycler)
    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 method 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(Condition(function thistype.AIDS_onEnter))
    call AIDS_RegisterOnEnterAllocated(Condition(function thistype.AIDS_onEnterAllocated))
    call AIDS_RegisterOnDeallocate(Condition(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
    [/spoil]

    [spoil]//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // ~~ Event ~~ By Jesus4Lyf ~~ Version 1.02 ~~
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // What is Event?
    // - Event simulates Warcraft III events. They can be created,
    // registered for, fired and also destroyed.
    // - Event, therefore, can also be used like a trigger "group".
    // - This was created when there was an influx of event style systems
    // emerging that could really benefit from a standardised custom
    // events snippet. Many users were trying to achieve the same thing
    // and making the same kind of errors. This snippet aims to solve that.
    //
    // Functions:
    // - Event.create() --> Creates a new Event.
    // - .chainDestroy() --> Destroys an Event.
    // DO NOT use .destroy().
    // - .fire() --> Fires all triggers which have been
    // registered on this Event.
    // - .register(trigger) --> Registers another trigger on this Event.
    //
    // Details:
    // - Event is extremely efficient and lightweight.
    // - It is safe to use with dynamic triggers.
    // - Internally, it is just a singularly linked list. Very simple.
    //
    // How to import:
    // - Create a trigger named Event.
    // - Convert it to custom text and replace the whole trigger text with this.
    //
    // Thanks:
    // - Builder Bob for the trigger destroy detection method.
    // - Azlier for inspiring this by ripping off my dodgier code.
    //
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    library Event
    ///////////////
    // EventRegs //
    ////////////////////////////////////////////////////////////////////////////
    // For reading this far, you can learn one thing more.
    // Unlike normal Warcraft III events, you can attach to Event registries.
    //
    // Event Registries are registrations of one trigger on one event.
    // These cannot be created or destroyed, just attached to.
    //
    // It is VERY efficient for loading and saving data.
    //
    // Functions:
    // - set eventReg.data = someStruct --> Store data.
    // - eventReg.data --> Retreive data.
    // - Event.getTriggeringEventReg() --> Get the triggering EventReg.
    //
    struct EventReg
    integer data
    method clear takes nothing returns nothing
    set this.data=0
    endmethod
    endstruct

    struct Event
    private trigger trig
    private Event next
    static method create takes nothing returns Event
    local Event this=Event.allocate()
    set this.next=0
    return this
    endmethod
    private static Event current
    static method getTriggeringEventReg takes nothing returns EventReg
    return .current
    endmethod
    private static trigger t
    method fire takes nothing returns nothing
    // this = last.
    loop
    set .current=this.next
    exitwhen .current==0
    set .t=.current.trig
    if IsTriggerEnabled(.t) then
    if TriggerEvaluate(.t) then
    call TriggerExecute(.t)
    endif
    set this=.current
    else
    call EnableTrigger(.t) // Was trigger destroyed?
    if IsTriggerEnabled(.t) then
    call DisableTrigger(.t)
    set this=.current
    else // If trigger destroyed...
    set .current.trig=null
    set this.next=.current.next
    call .current.destroy()
    endif
    endif
    endloop
    endmethod
    method register takes trigger t returns EventReg
    local Event new=Event.allocate()
    set new.next=this.next
    set new.trig=t
    set this.next=new
    call EventReg(new).clear()
    return new
    endmethod
    method chainDestroy takes nothing returns nothing
    loop
    call this.destroy()
    set this=this.next
    exitwhen this==0
    set this.trig=null
    endloop
    endmethod
    endstruct

    /////////////////////////////////////////////////////
    // Demonstration Functions & Alternative Interface //
    ////////////////////////////////////////////////////////////////////////////
    // What this would look like in normal WC3 style JASS (should all inline).
    //
    function CreateEvent takes nothing returns Event
    return Event.create()
    endfunction
    function DestroyEvent takes Event whichEvent returns nothing
    call whichEvent.chainDestroy()
    endfunction
    function FireEvent takes Event whichEvent returns nothing
    call whichEvent.fire()
    endfunction
    function TriggerRegisterEvent takes trigger whichTrigger, Event whichEvent returns EventReg
    return whichEvent.register(whichTrigger)
    endfunction

    // And for EventRegs...
    function SetEventRegData takes EventReg whichEventReg, integer data returns nothing
    set whichEventReg.data=data
    endfunction
    function GetEventRegData takes EventReg whichEventReg returns integer
    return whichEventReg.data
    endfunction
    function GetTriggeringEventReg takes nothing returns integer
    return Event.getTriggeringEventReg()
    endfunction
    endlibrary
    [/spoil]

    [spoil]//! textmacro CreateNec takes CODE, NAME, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN
    //! external ObjectMerger w3a AItg dmg$CODE$ aart "" anam "Damage ($NAME$)" ansf "(Necromastery)" alev 10 Iatt 1 $ONE$ Iatt 2 $TWO$ Iatt 3 $THREE$ Iatt 4 $FOUR$ Iatt 5 $FIVE$ Iatt 6 $SIX$ Iatt 7 $SEVEN$ Iatt 8 $EIGHT$ Iatt 9 $NINE$ Iatt 10 $TEN$ aite 0
    //! endtextmacro
    //! runtextmacro CreateNec("0", "10000's", "0", "10000", "20000", "30000", "40000", "50000", "60000", "70000", "80000", "90000")
    //! runtextmacro CreateNec("1", "1000's", "0", "1000", "2000", "3000", "4000", "5000", "6000", "7000", "8000", "9000")
    //! runtextmacro CreateNec("2", "100's", "0", "100", "200", "300", "400", "500", "600", "700", "800", "900")
    //! runtextmacro CreateNec("3", "10's", "0", "10", "20", "30", "40", "50", "60", "70", "80", "90")
    //! runtextmacro CreateNec("4", "1's", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9")

    //! external ObjectMerger w3a Acri ARS0 aart "" alev 3 arac "other" areq "" arqa "" ansf "(Reduction)" anam "Requiem of Souls" Cri2 1 0 Cri3 1 0.15 Cri3 2 0.20 Cri3 3 0.25 Cri1 1 0.15 Cri1 2 0.20 Cri1 3 0.25 abuf 1 BRS0 abuf 2 BRS0 abuf 3 BRS0 aran 1 99999 aran 2 99999 aran 3 99999 acdn 1 0 ahdu 1 0 ahdu 2 0 ahdu 3 0 adur 1 0 adur 2 0 adur 3 0 amcs 1 0 atar 1 "" atp1 1 "" aub1 1 ""
    //! external ObjectMerger w3h Bcri BRS0 fart "ReplaceableTextures\CommandButtons\BTNDizzy.blp" ftat "Abilities\Spells\Undead\Possession\PossessionTarget.mdl" fta0 "overhead" ftac 1 frac "other" fnam "Requiem of Souls" ftip "Requiem of Souls" fube "This unit has been hit by evil spirits; its movement speed and damage have been reduced."

    //! external ObjectMerger w3u nalb nECD uabi Aloc ucbs 0 udtm 0 ushr 0 umdl "Abilities\Weapons\AvengerMissile\AvengerMissile.mdl" usca 1 ushu "None" util " " umvh 0 umvf 0 umvs 522 umas 522 umis 522 ucol 0 urac "human" unam "Necromastery Dummy" utip " " utub " " usid 0 usin 0
    //! external ObjectMerger w3u nalb sHAD uabi Aloc ucbs 0 udtm 0 ushr 0 umdl "Abilities\Spells\Undead\AnimateDead\AnimateDeadTarget.mdl" usca 1 ushu "None" util " " umvh 0 umvf 0 umvs 522 umas 522 umis 522 ucol 0 urac "human" unam "Shadowraze Dummy" utip " " utub " " usid 0 usin 0
    //! external ObjectMerger w3u nalb rOSD uabi Aloc ucbs 0 udtm 0 ushr 0 umdl "Objects\Spawnmodels\Undead\UndeadDissipate\UndeadDissipate.mdl" usca 1 ushu "None" util " " umvh 0 umvf 0 umvs 522 umas 522 umis 522 ucol 0 urac "human" unam "Requiem of Souls Dummy" utip " " utub " " usid 0 usin 0
    //! external ObjectMerger w3u nalb cAST uabi Aloc ucbs 0 udtm 0 ushr 0 umdl "none.mdl" usca 0.1 ushu "None" util " " umvh 0 umvf 0 umvs 0 umas 0 umis 0 ucol 0 urac "human" unam "Caster Dummy" utip " " utub " " usid 0 usin 0

    //! external ObjectMerger w3u nalb prel uabi Aloc ucbs 0 udtm 0 ushr 0 umdl "none.mdl" usca 0.1 ushu "None" util " " umvh 0 umvf 0 umvs 0 umas 0 umis 0 ucol 0 urac "human" unam "Preloader" utip " " utub " " usid 0 usin 0[/spoil]

    Ai rảnh có thể giúp em để sửa được ko ạ :-s em luôn gặp lỗi khi save map ạ.
     
  2. AzuhaSky

    AzuhaSky T.E.T.Я.I.S

    Tham gia ngày:
    30/5/10
    Bài viết:
    550
    Nơi ở:
    WE Box
    Đầu tiên cần Jassnewgenpack 1.5d! nếu đã có mà save không được mời bạn xem và tải về ngay X Design Pack của dh-g >:D< ! Từ đó có thể save được!
    Thứ hai là muốn sửa vui lòng bạn bỏ vào
    Mã:
     [/code.] để dễ nhìn bạn nhé! Như vậy người ta dễ trả lời hơn!
     
  3. hieu2525

    hieu2525 Mr & Ms Pac-Man

    Tham gia ngày:
    23/3/09
    Bài viết:
    111
    Nơi ở:
    HN
    Thêm 1 trigger này nữa ạ, khi em copy nó vào map thì nó báo lỗi là...
    Mã:
    call PolledWait2(1.)
    Mã:
    scope BloodBath
    
    globals
        private integer abil_id = 'A066' // Blood Bath ability rawcode
        private real unit_id = .05 // Factor per level for units killed
        private real hero_id = .1 // Factor per level for heroes killed
        private string SFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl" // Effect created on killer
    endglobals
    
    private function Conditions takes nothing returns boolean
        return GetUnitAbilityLevel(GetKillingUnit(),abil_id)>0 and not IsUnitType(GetDyingUnit(),UNIT_TYPE_STRUCTURE)
    endfunction
    private function Actions takes nothing returns nothing
        local real hp 
    	local effect sfx = AddSpecialEffectTarget(SFX,GetKillingUnit(),"overhead")
        
    	if(IsUnitType(GetDyingUnit(),UNIT_TYPE_HERO))then
    		set hp = hero_id
    	else
            set hp = unit_id
        endif
    	set hp = GetUnitAbilityLevel(GetKillingUnit(),abil_id)*hp*GetUnitState(GetDyingUnit(),UNIT_STATE_MAX_LIFE)
    	call SetWidgetLife(GetKillingUnit(),GetUnitState(GetKillingUnit(),UNIT_STATE_LIFE)+hp)
    	call PolledWait2(1.)
        
    	call DestroyEffect(sfx)
        set sfx = null
    endfunction
    
    //===========================================================================
    public function InitTrig takes nothing returns nothing
        local trigger trig = CreateTrigger(  )
        
        call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddAction( trig, function Actions )
        call TriggerAddCondition(trig,Condition(function Conditions))
    endfunction
    
    endscope
    
    có ai giải thích được hộ em tại sao nó lại bị thế được ko ạ :(
     
  4. AzuhaSky

    AzuhaSky T.E.T.Я.I.S

    Tham gia ngày:
    30/5/10
    Bài viết:
    550
    Nơi ở:
    WE Box
    Ờ thì nó báo đấy! call PolledWait2 :|
    Cậu biết mà còn hỏi nữa là sao?:-?
     
  5. hieu2525

    hieu2525 Mr & Ms Pac-Man

    Tham gia ngày:
    23/3/09
    Bài viết:
    111
    Nơi ở:
    HN
    nhưng sửa như thế nào để cho nó chuẩn ạ @@, em đang mù tịt về Jass nên ko biết nghĩa là gì ạ :D
     
  6. AzuhaSky

    AzuhaSky T.E.T.Я.I.S

    Tham gia ngày:
    30/5/10
    Bài viết:
    550
    Nơi ở:
    WE Box
    Đơn giản lắm, nếu muốn biết đúng hay sai, cứ việc gõ call PolledW rồi nó gợi ý ra đúng nghĩ liền hà!=))
    Hàm trên bỏ số 2 ở call PolledWait đi nghĩ sẽ là: call PolledWait(.1)
     
  7. hieu2525

    hieu2525 Mr & Ms Pac-Man

    Tham gia ngày:
    23/3/09
    Bài viết:
    111
    Nơi ở:
    HN
    Cảm ơn anh :D, anh có thể cho em yahoo để em tiện hỏi về Jass được ko ạ :D (nhân tiện em học hỏi thêm từ anh :">)
     
  8. hieu2525

    hieu2525 Mr & Ms Pac-Man

    Tham gia ngày:
    23/3/09
    Bài viết:
    111
    Nơi ở:
    HN
    em mới lấy 1 spell Jass ở trên Hiveworkshop về nhưng sau khi chỉnh lại hết raw code thì nó báo là lỗi cái trigger của system đó ạ, cụ thể như sau:
    Mã:
    Line 8186: "type", "struct", "interface", "function", "keyword" or "scope"
            private static unit thistype array
    
    
    [spoil]
    Mã:
    //  
    //        _   ___ ___  ___    _______________________________________________
    //       /_\ |_ _|   \/ __|   ||     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.0.5
    //      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
            [B]private static thistype array[/B]
            
            // 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
    
    [/spoil]

    ai có thể fix lại dùm em được ko ạ :( em mò cả đêm rồi mà vẫn chưa tìm được cách fix :((
     
    Last edited by a moderator: 24/6/11
  9. AzuhaSky

    AzuhaSky T.E.T.Я.I.S

    Tham gia ngày:
    30/5/10
    Bài viết:
    550
    Nơi ở:
    WE Box
    Thử thêm hai cái này vào hàm xem:
     
  10. hieu2525

    hieu2525 Mr & Ms Pac-Man

    Tham gia ngày:
    23/3/09
    Bài viết:
    111
    Nơi ở:
    HN
    em sửa như anh nói nhưng giờ nó lại bị lỗi ở 1 trigger khác ạ...
    Mã:
        private module InitModule
    
    Trigger Damage
    [spoil]
    Mã:
    //  
    //      ___   _     __  __   _   ___  ____    _______________________________
    //     |   \ /_\   /  |/  | /_\ /  _\|  __|   ||      D E A L   I T ,      ||
    //     | |) / _ \ / / | / |/ _ \| |/||  __|   ||    D E T E C T   I T ,    ||
    //     |___/_/ \_/_/|__/|_|_/ \_\___/|____|   ||     B L O C K   I T .     ||
    //                            By Jesus4Lyf    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    //                                                                    v 1.0.5
    //      What is Damage?
    //     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    //          Damage is a damage dealing, detection and blocking system. It implements
    //          all such functionality. It also provides a means to detect what type
    //          of damage was dealt, so long as all damage in your map is dealt using
    //          this system's deal damage functions (except for basic attacks).
    //
    //          It is completely recursively defined, meaning if you deal damage on
    //          taking damage, the type detection and other features like blocking
    //          will not malfunction.
    //          
    //      How to implement?
    //     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    //          Create a new trigger object called Damage, go to 'Edit -> Convert to
    //          Custom Text', and replace everything that's there with this script.
    //
    //          At the top of the script, there is a '//! external ObjectMerger' line.
    //          Save your map, close your map, reopen your map, and then comment out this
    //          line. Damage is now implemented. This line creates a dummy ability used
    //          in the system in some circumstances with damage blocking.
    //
    //      Functions:
    //     ¯¯¯¯¯¯¯¯¯¯¯¯
    //          function Damage_RegisterEvent takes trigger whichTrigger returns nothing
    //              - This registers a special "any unit takes damage" event.
    //              - This event supports dynamic trigger use.
    //              - Only triggers registered on this event may block damage.
    //              - Only fires when the damage dealt is not 0.
    //
    //          function Damage_RegisterZeroEvent takes trigger whichTrigger returns nothing
    //              - The same as Damage_RegisterEvent, but for only zero damage events
    //                (which are excluded from Damage_RegisterEvent).
    //              - Note that getting the damage type may be unreliable, since spells
    //                like faerie fire trigger 0 damage, but it will count as an attack.
    //
    //          function Damage_GetType takes nothing returns damagetype
    //              - This will get the type of damage dealt, like an event response,
    //                for when using a unit takes damage event (or the special event above).
    //
    //          function Damage_IsPhysical takes nothing returns boolean
    //          function Damage_IsSpell takes nothing returns boolean
    //          function Damage_IsPure takes nothing returns boolean
    //              - Wrappers to simply check if Damage_GetType is certain types.
    //
    //          function Damage_IsAttack takes nothing returns boolean
    //              - Checks if the damage is from a physical attack (so you can deal
    //                physical damage without it being registered as an actual attack).
    //
    //          function Damage_Block takes real amount returns nothing
    //          function Damage_BlockAll takes nothing returns nothing
    //              - For use only with Damage_RegisterEvent.
    //              - Blocks 'amount' of the damage dealt.
    //              - Multiple blocks at once work correctly.
    //              - Blocking more than 100% of the damage will block 100% instead.
    //              - Damage_BlockAll blocks 100% of the damage being dealt.
    //
    //          function Damage_EnableEvent takes boolean enable returns nothing
    //              - For disabling and re-enabling the special event.
    //              - Use it to deal damage which you do not want to be detected by
    //                the special event.
    //
    //          function UnitDamageTargetEx takes lots of things returns boolean
    //              - Replaces UnitDamageTarget in your map, with the same arguments.
    //
    //          function Damage_Physical takes unit source, unit target, real amount,
    //            attacktype whichType, boolean attack, boolean ranged returns boolean
    //              - A clean wrapper for physical damage.
    //              - 'attack' determines if this is to be treated as a real physical
    //                attack or just physical type damage.
    //              - 'ranged' determines if this is to be treated as a ranged or melee
    //                attack.
    //
    //          function Damage_Spell takes unit source, unit target, real amount returns boolean
    //              - A clean wrapper for spell damage.
    //
    //          function Damage_Pure takes unit source, unit target, real amount returns boolean
    //              - A clean wrapper for pure type damage (universal type, 100% damage).
    //          
    //      Thanks:
    //     ¯¯¯¯¯¯¯¯¯
    //          - Romek, for helping me find a better way to think about damage blocking.
    //
    library Damage uses AIDS, Event
        //============================================================
        globals
            private constant integer LIFE_BONUS_ABIL='dprv'
        endglobals
        
        //============================================================
        globals
            private Event OnDamageEvent
            private Event OnZeroDamageEvent
            private boolean EventEnabled=true
        endglobals
        
        public function RegisterEvent takes trigger whichTrigger returns nothing
            call OnDamageEvent.register(whichTrigger)
        endfunction
        
        public function RegisterZeroEvent takes trigger whichTrigger returns nothing
            call OnZeroDamageEvent.register(whichTrigger)
        endfunction
        
        public function EnableEvent takes boolean enable returns nothing
            set EventEnabled=enable
        endfunction
        
        //============================================================
        globals
            private integer TypeStackLevel=0
            private damagetype array TypeStackValue
            private boolean array TypeStackAttack
            private real array ToBlock
        endglobals
        
        public function GetType takes nothing returns damagetype
            return TypeStackValue[TypeStackLevel]
        endfunction
        
        public function IsAttack takes nothing returns boolean
            return TypeStackAttack[TypeStackLevel]
        endfunction
        
        public function Block takes real amount returns nothing
            set ToBlock[TypeStackLevel]=ToBlock[TypeStackLevel]+amount
        endfunction
        
        public function BlockAll takes nothing returns nothing
            set ToBlock[TypeStackLevel]=ToBlock[TypeStackLevel]+GetEventDamage()
        endfunction
        
        //============================================================
        globals
            private integer BlockNum=0
            private unit array BlockUnit
            private real array BlockUnitLife
            private real array BlockRedamage
            private unit array BlockDamageSource
            
            private timer BlockTimer=CreateTimer()
        endglobals
        
        //============================================================
        globals
            private unit array RemoveBoosted
            private integer RemoveBoostedMax=0
            
            private timer RemoveBoostedTimer=CreateTimer()
        endglobals
        
        globals//locals
            private real BoostedLifeTemp
            private unit BoostedLifeUnit
        endglobals
        private function RemoveBoostedTimerFunc takes nothing returns nothing
            loop
                exitwhen RemoveBoostedMax==0
                set BoostedLifeUnit=RemoveBoosted[RemoveBoostedMax]
                set BoostedLifeTemp=GetWidgetLife(BoostedLifeUnit)
                call UnitRemoveAbility(BoostedLifeUnit,LIFE_BONUS_ABIL)
                if BoostedLifeTemp>0.405 then
                    call SetWidgetLife(BoostedLifeUnit,BoostedLifeTemp)
                endif
                set RemoveBoostedMax=RemoveBoostedMax-1
            endloop
        endfunction
        
        //============================================================
        private keyword Detector // Darn, I actually had to do this. XD
        globals//locals
            private unit ForUnit
            private real NextHealth
        endglobals
        private function OnDamageActions takes nothing returns boolean
            if EventEnabled then
                if GetEventDamage()==0. then
                    call OnZeroDamageEvent.fire()
                else
                    call OnDamageEvent.fire()
                endif
                
                if ToBlock[TypeStackLevel]!=0. then
                    //====================================================
                    // Blocking
                    set ForUnit=GetTriggerUnit()
                    
                    set NextHealth=GetEventDamage()
                    if ToBlock[TypeStackLevel]>=NextHealth then
                        set NextHealth=GetWidgetLife(ForUnit)+NextHealth
                    else
                        set NextHealth=GetWidgetLife(ForUnit)+ToBlock[TypeStackLevel]
                    endif
                    
                    call SetWidgetLife(ForUnit,NextHealth)
                    if GetWidgetLife(ForUnit)<NextHealth then
                        // NextHealth is over max health.
                        call UnitAddAbility(ForUnit,LIFE_BONUS_ABIL)
                        call SetWidgetLife(ForUnit,NextHealth)
                        
                        set RemoveBoostedMax=RemoveBoostedMax+1
                        set RemoveBoosted[RemoveBoostedMax]=ForUnit
                        call ResumeTimer(RemoveBoostedTimer)
                    endif
                    //====================================================
                    set ToBlock[TypeStackLevel]=0.
                endif
            endif
            return false
        endfunction
        
        //============================================================
        function UnitDamageTargetEx takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
            local boolean result
            set TypeStackLevel=TypeStackLevel+1
            set TypeStackValue[TypeStackLevel]=damageType
            set TypeStackAttack[TypeStackLevel]=attack
            set result=UnitDamageTarget(whichUnit,target,amount,attack,ranged,attackType,damageType,weaponType)
            set TypeStackLevel=TypeStackLevel-1
            return result
        endfunction
        //! textmacro Damage__DealTypeFunc takes NAME, TYPE
            public function $NAME$ takes unit source, unit target, real amount returns boolean
                return UnitDamageTargetEx(source,target,amount,false,false,ATTACK_TYPE_NORMAL,$TYPE$,WEAPON_TYPE_WHOKNOWS)
            endfunction
            public function Is$NAME$ takes nothing returns boolean
                return GetType()==$TYPE$
            endfunction
        //! endtextmacro
        
        //! runtextmacro Damage__DealTypeFunc("Pure","DAMAGE_TYPE_UNIVERSAL")
        //! runtextmacro Damage__DealTypeFunc("Spell","DAMAGE_TYPE_MAGIC")
        
        // Uses different stuff, but works much the same way.
        public function Physical takes unit source, unit target, real amount, attacktype whichType, boolean attack, boolean ranged returns boolean
            return UnitDamageTargetEx(source,target,amount,attack,ranged,whichType,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
        endfunction
        public function IsPhysical takes nothing returns boolean
            return GetType()==DAMAGE_TYPE_NORMAL
        endfunction
        
        //============================================================
        private struct Detector extends array // Uses AIDS.
            //! runtextmacro AIDS()
            
            private static conditionfunc ACTIONS_COND
            
            private trigger t
            
            private method AIDS_onCreate takes nothing returns nothing
                set this.t=CreateTrigger()
                call TriggerAddCondition(this.t,thistype.ACTIONS_COND)
                call TriggerRegisterUnitEvent(this.t,this.unit,EVENT_UNIT_DAMAGED)
            endmethod
            
            private method AIDS_onDestroy takes nothing returns nothing
                call DestroyTrigger(this.t)
            endmethod
            
            private static method AIDS_onInit takes nothing returns nothing
                set thistype.ACTIONS_COND=Condition(function OnDamageActions)
            endmethod
        endstruct
        
        //============================================================
        private module InitModule
            private static method onInit takes nothing returns nothing
                local unit abilpreload=CreateUnit(Player(15),'uloc',0,0,0)
                call UnitAddAbility(abilpreload,LIFE_BONUS_ABIL)
                call RemoveUnit(abilpreload)
                set abilpreload=null
                
                set OnDamageEvent=Event.create()
                set OnZeroDamageEvent=Event.create()
                set TypeStackValue[TypeStackLevel]=DAMAGE_TYPE_NORMAL
                set TypeStackAttack[TypeStackLevel]=true
                call TimerStart(RemoveBoostedTimer,0.0,false,function RemoveBoostedTimerFunc)
            endmethod
        endmodule
        private struct InitStruct extends array
            implement InitModule
        endstruct
    endlibrary
    
    [/spoil]

    đây là spell em down từ hive work shop về ạ, nó khá hay nhưng em ko biết làm cách nào để cóp hẳn vào map mình nên đành nhờ anh xem hộ em :D
    http://www.mediafire.com/?xo7hkasur9nncsq (Link sạch ko virus)
     
  11. hieu2525

    hieu2525 Mr & Ms Pac-Man

    Tham gia ngày:
    23/3/09
    Bài viết:
    111
    Nơi ở:
    HN
    Em cóp 1 cái system từ map blade n demon của anh dragon, nhưng khi save thì nó bị lỗi như sau:
    Mã:
    Line xxx: Function redeclared: H2I
    Line xxxx: previous declaration
    
    [b]Function H2I takes handle h returns integer[/b]
    
    Em đã hỏi anh Romek về lỗi nhưng sau khi fix xong thì nó bị như thế này...
     

Chia sẻ trang này