1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. The mythological era has spawned some interesting characters around. Check them out and be sure to vote for them in the 30th Poll of the Texturing Contest.
    Dismiss Notice
  3. The 20th iteration of the Terraining Contest is upon us! Join and create exquisite Water Structures for it.
    Dismiss Notice
  4. Hivers united and created a bunch of 2v2 melee maps. Vote for the best in our Melee Mapping Contest #4 - Poll!
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice

Trigger Viewer

JustAZBound_FactoryMode.w3x
Variables
Factory Mode
Factory Mode
Factory Mode Demo
Libaries for Demo
SpellEffectEvent
RegisterPlayerUnitEvent
BlizzardMessage
Initialization
Initialization
Demo
Mobs
Revive
onESC
Enter map-specific custom script code below. This text will be included in the map script after variables are declared and before any trigger code.

		
Name Type Is Array Initial Value
Loc location No
library FactoryMode
   
    /*
        FactoryMode is a system that allows you to create your own version of PocketFactory but
        comes with added functionality like the ability to have multiple exit ports and dynamically
        changing spawn time.
    */

   
   
    //API
    /*
   
        /* FactoryMode */

       
        call FactoryMode.create takes unit u, real interval, integer chargeTrigger, integer chargeLimit returns thistype
            unit u ---------------- The Factory
            real interval --------- The time after which FACTORY_ON_CHARGE_INTERVAL will fire
            integer chargeTrigger - the amount of charges needed to fire FACTORY_ON_CHARGE_LIMIT
            integer chargeLimit --- this is the maximum number of charges a factory can hold at any
                                    time.
       
        call FactoryMode.remove takes FactoryMode this returns nothing
            FactoryMode this ------ this is the instance of a created FactoryMode. Be sure to store
                                    the instance or you will not be able to terminate it. This method
                                    will terimate a FactoryMode.
                               
        call FactoryMode.getFactory takes FactoryMode this returns unit
            FactoryMode this ------ similar to above, returns the Factory itself.
       
        call FactoryMode.getThreshold takes FactoryMode this returns integer
            FactoryMode this ------ similar to above, but returns the number of charges required to trigger the threshold.
           
        call FactoryMode.getCharges takes FactoryMode this returns integer
            FactoryMode this ------ similar to above, but returns the number of charges on a Factory.
       
        call FactoryMode.setCharges takes FactoryMode this, integer chargeCount, boolean muteEvent returns nothing
            FactoryMode this ------ similar to above.
            integer chargeCount --- sets the charges of a Factory. Use FactoryMode.getCharges() to
                                    find what the current number is.
            boolean muteEvent ----- Prevents a CAHRGE_UP event from firing. Useful when reducing charge count.

        /* ExitPort */
       
        static method ExitPort.getPortX takes thistype port returns real
            returns the X coordinate of a port
       
        static method ExitPort.getPortY takes thistype port returns real
            returns the Y coordinate of a port
       
        static method ExitPort.getPortZ takes thistype port returns real
            returns the Z value of a port
       
        static method ExitPort.getPortFacing takes thistype port returns real
            returns the facing angle of a port
           
        static method ExitPort.getPortFactoryId takes thistype port returns FactoryMode
            return the FactoryMode instance of a port
       
        static method ExitPort.getSpecific takes FactoryMode f, integer i returns thistype
            returns a specific exit port instance of a factory
           
        static method ExitPort.getRandom takes FactoryMode f returns thistype
            returns a random exit port instance of a factory
       
        static method ExitPort.createUnit takes thistype port, integer unitid returns unit
            special CreateUnit method for FactoryMode. Will create a unit depending on which port is
            chosen.
       
        static method ExitPort.create takes FactoryMode f, real X, real Y, real Z, real angle returns thistype
            Adds an exit port to a factory.Exit ports come with height and angle settings as well so
            you may make a unit exit the factory at a specific height and facing a particular direction.
           
        static method ExitPort.remove takes FactoryMode f, integer portNumber returns nothing
            removes an exit port from a factory.
       
       
    */
   
    globals
   
        private constant real TIMEOUT = .03125
       
        unit FACTORY = null
        FactoryMode FACTORY_ID = 0
        constant integer FACTORY_ON_CHARGE_INTERVAL = 1
        constant integer FACTORY_ON_CHARGE_LIMIT    = 2
        constant integer FACTORY_ON_CHARGE_UP       = 3
       
        private trigger array EventTrig
        private FactoryMode array Factory
       
        private hashtable PortsStorage = null
        private integer Factories = 0
        private timer tmr = null
       
        private unit Minitank = null
    endglobals
   
   
   
    private function FireTrigger takes integer ev, unit u, FactoryMode F returns nothing
        set FACTORY = u
        set FACTORY_ID = F
        call TriggerEvaluate(EventTrig[ev])
        set FACTORY = null
        set FACTORY_ID = 0
    endfunction
   
    function RegisterFactoryEvent takes integer ev, code c returns nothing
        call TriggerAddCondition(EventTrig[ev], Condition(c))
    endfunction
   
   
   
    struct FactoryMode
   
        private integer charges
        private integer triggerThreshold
        private integer limit
        private integer slot
        private unit factory
        private real timeout
        private real timeoutReset
        integer portsCount
       
        static method getFactory takes FactoryMode this returns unit
            return this.factory
        endmethod
       
        static method getLimit takes FactoryMode this returns integer
            return this.limit
        endmethod
       
        static method getThreshold takes FactoryMode this returns integer
            return this.triggerThreshold
        endmethod
       
        static method getCharges takes FactoryMode this returns integer
            return this.charges
        endmethod
       
        static method setCharges takes FactoryMode this, integer chargeCount, boolean muteEvent returns nothing
            local integer c
            set this.charges = chargeCount
            if this.charges >= this.limit then
                set this.charges = this.limit
            endif
            if not muteEvent then
                call FireTrigger(FACTORY_ON_CHARGE_UP, this.factory, this)
            endif
            set c = this.charges
            if c >= this.triggerThreshold then
                call FireTrigger(FACTORY_ON_CHARGE_LIMIT, this.factory, this)
            endif
        endmethod
       
        private static method factoryInterval takes nothing returns nothing
            local integer i = 0
            local thistype this
            if Factories > 0 then
                loop
                    set i = i + 1
                    exitwhen i > Factories
                    set this = Factory[i]
                    set this.timeout = this.timeout - TIMEOUT
                    if this.timeout <= 0. then
                        set this.timeout = this.timeoutReset
                        call FireTrigger(FACTORY_ON_CHARGE_INTERVAL, this.factory, this)
                    endif
                endloop
            else
                call DestroyTimer(tmr)
                set tmr = null
            endif
        endmethod
       
        private method destroy takes nothing returns nothing
            local integer i = 0
            local ExitPort port
            loop
                set i = i + 1
                exitwhen i > this.portsCount
                set port = LoadInteger(PortsStorage, this, i)
                call port.destroy()
            endloop
            call FlushChildHashtable(PortsStorage, this)
            set this.charges = 0
            set this.triggerThreshold = 0
            set this.limit = 0
            set this.slot = 0
            set this.timeout = 0.
            set this.timeoutReset = 0.
            set this.factory = null
            set this.portsCount = 0
            call this.deallocate()
        endmethod
       
        static method remove takes FactoryMode this returns nothing
            local integer i = this.slot
            local FactoryMode = nextF
            loop
                set nextF = Factory[i + 1]
                set Factory[i] = nextF
                set nextF.slot = i
                set i = i + 1
                exitwhen i > Factories
            endloop
            set Factories = Factories - 1
            call this.destroy()
        endmethod
       
        static method create takes unit u, real interval, integer chargeTrigger, integer chargeLimit returns thistype
            local thistype this = allocate()
            set this.charges = 0
            set this.triggerThreshold = chargeTrigger
            set this.limit = chargeLimit
            set this.timeout = interval
            set this.timeoutReset = interval
            set this.factory = u
            set this.portsCount = 0
            set Factories = Factories + 1
            set Factory[Factories] = this
            set this.slot = Factories
            if tmr == null then
                set tmr = CreateTimer()
                call TimerStart(tmr, TIMEOUT, true, function thistype.factoryInterval)
            endif
            return this
        endmethod
       
        private static method onInit takes nothing returns nothing
            set EventTrig[FACTORY_ON_CHARGE_UP]         = CreateTrigger()
            set EventTrig[FACTORY_ON_CHARGE_LIMIT]      = CreateTrigger()
            set EventTrig[FACTORY_ON_CHARGE_INTERVAL]   = CreateTrigger()
        endmethod
       
    endstruct
   
   
   
    struct ExitPort
       
        private real x
        private real y
        private real z
        private real facing
        FactoryMode fId
       
        method destroy takes nothing returns nothing
            set this.x = 0.
            set this.y = 0.
            set this.z = 0.
            set this.facing = 0.
            set this.fId = 0
            call this.deallocate()
        endmethod
       
        static method remove takes FactoryMode f, integer portNumber returns nothing
            local integer i = portNumber
            local thistype port = LoadInteger(PortsStorage, f, i)
            call port.destroy()
            loop
                call RemoveSavedInteger(PortsStorage, f, i)
                call SaveInteger(PortsStorage, f, i, LoadInteger(PortsStorage, f, i + 1))
                set i = i + 1
                exitwhen i > f.portsCount
            endloop
            set f.portsCount = f.portsCount - 1
        endmethod
       
        static method getPortX takes thistype port returns real
            return port.x
        endmethod
       
        static method getPortY takes thistype port returns real
            return port.y
        endmethod
       
        static method getPortZ takes thistype port returns real
            return port.z
        endmethod
       
        static method getPortFacing takes thistype port returns real
            return port.facing
        endmethod
       
        static method getPortFactoryId takes thistype port returns FactoryMode
            return port.fId
        endmethod
       
        static method getSpecific takes FactoryMode f, integer i returns thistype
            local thistype port = LoadInteger(PortsStorage, f, i)
            if port == 0 then
                set port = LoadInteger(PortsStorage, f, f.portsCount)
            endif
            return port
        endmethod
       
        static method getRandom takes FactoryMode f returns thistype
            return LoadInteger(PortsStorage, f, GetRandomInt(1, f.portsCount))
        endmethod
       
        static method createUnit takes thistype port, integer unitid returns unit
            local unit source = FactoryMode.getFactory(port.fId)
            local unit rallyU = GetUnitRallyUnit(source)
            local destructable rallyD = GetUnitRallyDestructable(source)
            local location loc
            set Minitank = CreateUnit(GetOwningPlayer(source), unitid, port.x, port.y, port.facing)
            call SetUnitFlyHeight(Minitank, port.z, 0.)
            if rallyU != null then
                if rallyU != source then
                    call IssueTargetOrderById(Minitank, 851971, rallyU) //order smart
                endif
            elseif rallyD != null then
                call IssueTargetOrderById(Minitank, 851971, rallyD) //order smart
            else
                set loc = GetUnitRallyPoint(source)
                call IssuePointOrderById(Minitank, 851983, GetLocationX(loc), GetLocationY(loc)) //order attack
                call RemoveLocation(loc)
            endif
            set rallyU = null
            set rallyD = null
            set source = null
            return Minitank
        endmethod
       
        static method create takes FactoryMode f, real X, real Y, real Z, real angle returns thistype
            local thistype port = allocate()
            set port.x = X
            set port.y = Y
            set port.z = Z
            set port.facing = angle
            set port.fId = f
            set f.portsCount = f.portsCount + 1
            if PortsStorage == null then
                set PortsStorage = InitHashtable()
            endif
            call SaveInteger(PortsStorage, f, f.portsCount, port)
            return port
        endmethod
       
    endstruct
   
   
   
endlibrary
library FactoryModeDemo initializer init requires FactoryMode, SpellEffectEvent optional BlizzardMessage
   
    /*
        This demo shows how the Factory Mode library is being used. Each function has a brief
        description to help you understand their use.
    */

   
    globals
       
        //CONFIG
        private constant integer    SPELL_ID            = 'A000'
        private constant integer    RALLY_ID            = 'ARal'
        private constant integer    CREATE_TANK_ID      = 'A001'
        private constant integer    BASE_HERO_ID        = 'N000'
        private constant string     SPAWN_FX_STRING     = "Objects\\Spawnmodels\\Other\\ToonBoom\\ToonBoom.mdl"
        private constant integer    ORDER_UNMORPH       = 852657            //order unrobogoblin
        private constant integer    ORDER_MAKETANK      = 852561            //order frenzy
        private constant integer    ORDER_TANKON        = 852562            //order frenzyon
        private constant integer    ORDER_TANKOFF       = 852563            //order frenzyoff
        private constant integer    TANK_ID             = 'tan1'
        private constant integer    NUMBER_OF_PORTS     = 3
        private constant real       TANK_LIFESPAN       = 25.
        private constant real       PORTS_DISTANCE      = 160.
        private constant real       ANGLE_PER_PORT      = 90. * bj_DEGTORAD //Must be in radians
        private constant real       CHARGE_INTERVAL     = 1.
        private constant integer    CHARGE_THRESHOLD    = 7
        private constant integer    CHARGE_REDUCTION_PER_LEVEL = 1
        private constant integer    CHARGE_LIMIT        = 20
        private constant integer    CHARGE_RETURNED     = 2
        private constant boolean    SHOW_CHARGE_COUNT   = true
        private constant boolean    SHOW_CHARGE_CHANGE  = true
        private constant real       TEXT_HEIGHT         = 240.
        private constant string     CHARGES_MSG         = "Insufficient Charges"
        //END CONFIG
       
        private hashtable F_ID_Storage = InitHashtable()
        private hashtable Hero_Storage = InitHashtable()
        private trigger onDeathTrig = CreateTrigger()
        private trigger onTankTrig = CreateTrigger()
        private trigger array HeroTrigger
        private boolean array IsCreateTankOn
        private integer array NextPort
        private texttag array ChargeText
    endglobals
   
   
    /*  This is the main function that produces the tanks. The next exit port is then picked so that the
    next tank will exit from a different point.
    */

    private function CreateTank takes FactoryMode F returns nothing
        local integer thld = FactoryMode.getThreshold(F)
        local integer c = FactoryMode.getCharges(F)
        local integer diff = c - thld
        local unit u
        local ExitPort port
        if diff >= 0 then
            call FactoryMode.setCharges(F, c - thld, true)
            if ChargeText[F] != null then
                call SetTextTagText(ChargeText[F], I2S(FactoryMode.getCharges(F)), .023)
            endif
            set port = ExitPort.getSpecific(F, NextPort[F])
            set u = ExitPort.createUnit(port, TANK_ID)
            call DestroyEffect(AddSpecialEffect(SPAWN_FX_STRING, GetUnitX(u), GetUnitY(u)))
            call UnitApplyTimedLife(u, 'BTLF', TANK_LIFESPAN)
            call SaveUnitHandle(Hero_Storage, GetHandleId(u), 0, FACTORY)
            set u = null
            set NextPort[F] = NextPort[F] + 1
            if NextPort[F] > NUMBER_OF_PORTS then
                set NextPort[F] = 1
            endif
        else
            static if LIBRARY_BlizzardMessage then
                call BlizzardMessage(CHARGES_MSG, "|cffffcc00", 31, GetOwningPlayer(FactoryMode.getFactory(F)))
            else
                call BJDebugMsg(CHARGES_MSG)
            endif
        endif
    endfunction
   
   
    /*  This function fires when the Create Tank ability is cast.
    */

    private function onTank takes nothing returns nothing
        call CreateTank(LoadInteger(F_ID_Storage, GetHandleId(GetTriggerUnit()), 0))
    endfunction
   
   
    /*  This custom event fires whenever a charge count has changed. It checks for a relevant number
    of charges and if it does have it, orders the hero to cast Create Tank.
    */

    private function ActionsChargeUp takes nothing returns nothing
        local FactoryMode F = FACTORY_ID //Store this because calling FactoryMode.setCharges will null the value of FACTORY_ID otherwise. More info below.
        local unit Factory = FACTORY
        local texttag ChargeCount
        local real x = GetUnitX(Factory)
        local real y = GetUnitY(Factory)
        local real z = GetUnitFlyHeight(Factory) + TEXT_HEIGHT
        local player play = GetOwningPlayer(Factory)
       
        if IsCreateTankOn[F] and FactoryMode.getCharges(F) >= FactoryMode.getThreshold(F) then
            call IssueImmediateOrderById(Factory, ORDER_MAKETANK)
        endif
       
        if ChargeText[F] != null then
            call SetTextTagText(ChargeText[F], I2S(FactoryMode.getCharges(F)), .023)
        endif
       
        if SHOW_CHARGE_COUNT and FactoryMode.getCharges(F) < FactoryMode.getLimit(F) then
            set ChargeCount = CreateTextTag()
            call SetTextTagPos(ChargeCount, x, y, z + 50.)
            call SetTextTagPermanent(ChargeCount, false)
            call SetTextTagLifespan(ChargeCount, 2.0)
            call SetTextTagFadepoint(ChargeCount, 1.0)
            call SetTextTagVelocity(ChargeCount, .0355 * Cos(1.5708), .0355 * Sin(1.5708))
            call SetTextTagColor(ChargeCount, 255, 255, 255, 255)
            call SetTextTagText(ChargeCount, "+1", .023)
            call SetTextTagVisibility(ChargeCount, (GetLocalPlayer() == GetOwningPlayer(Factory)))
        endif
    endfunction
   
   
    /*  This custom event fires whenever an interval for the FactoryMode has been reached. In this
    instance, the number of charges is increased by 1.
    */

    private function ActionsInterval takes nothing returns nothing
        local FactoryMode F = FACTORY_ID //Store this because calling FactoryMode.setCharges will null the value of FACTORY_ID otherwise. More info below.
        call FactoryMode.setCharges(F, FactoryMode.getCharges(F) + 1, false)
        //Store FACTORY_ID and/or FACTORY inside of a local because calling FactoryMode.setCharges will null these values.
        //call BJDebugMsg(I2S(F.charges))
    endfunction
   
   
    /*  This functions handles the heros's death and increasing the level of the Factory Mode abiltiy.
    If he dies, the same code is call as when he morphs back into a hero from Factory Mode. If he levels
    up the ability, he is ordered to morph back into a hero to reset the spell.
    */

    private function OnHeroEvent takes nothing returns boolean
        local unit hero = GetTriggerUnit()
        local FactoryMode F
        if GetTriggerEventId() == EVENT_UNIT_HERO_SKILL then
            if GetLearnedSkill() == SPELL_ID then
                call IssueImmediateOrderById(hero, ORDER_UNMORPH)
            endif
        elseif GetTriggerEventId() == EVENT_UNIT_ISSUED_ORDER then
            if GetIssuedOrderId() == ORDER_TANKON then //frenzyon
                set F = LoadInteger(F_ID_Storage, GetHandleId(hero), 0)
                set IsCreateTankOn[F] = true
            elseif GetIssuedOrderId() == ORDER_TANKOFF then //frenzyoff
                set F = LoadInteger(F_ID_Storage, GetHandleId(hero), 0)
                set IsCreateTankOn[F] = false
            endif
        else
            set F = LoadInteger(F_ID_Storage, GetHandleId(hero), 0)
            call DestroyTrigger(HeroTrigger[F])
            if ChargeText[F] != null then
                call DestroyTextTag(ChargeText[F])
            endif
            set IsCreateTankOn[F] = false
            set NextPort[F] = 0
            call FactoryMode.remove(F)
            call UnitRemoveAbility(hero, RALLY_ID)
        endif
        set hero = null
        return false
    endfunction
   
   
    /*  This trigger checks for the death of nearby minitanks. If they die in the vicinity of their
    spawner, FactoryMode.setCharges() is called to increase the number of charges the main tank has,
    effectively reducing spawn time between tanks.
    */

    private function OnMachineDeath takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local unit factory = LoadUnitHandle(Hero_Storage, GetHandleId(u), 0)
        local FactoryMode F
        if factory != null and IsUnitInRange(u, factory, 750.) then
            set F = LoadInteger(F_ID_Storage, GetHandleId(factory), 0)
            call FactoryMode.setCharges(F, FactoryMode.getCharges(F) + CHARGE_RETURNED, false)
        endif
        set factory = null
        set u = null
        return false
    endfunction
   
   
    /*  When the spell is cast, the trigger checks for the ID of the hero - if the ID is that of the
    deployed tank, then the ability has been activated. If the ID is that of the base hero, then the
    ability has been deactivated. In the former case, FactoryMode.create() is called and the instance
    is stored in a hashtable. In the latter case, the instance number is loaded and Factory.remove()
    is called.
    */

    private function onCast takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local FactoryMode F
        local real xCaster
        local real yCaster
        local real x
        local real y
        local real a
        local integer i = 0
        local integer spellLevel = GetUnitAbilityLevel(caster, SPELL_ID)
        if GetUnitTypeId(caster) == BASE_HERO_ID then //morph has been initiated
            set F = FactoryMode.create(caster, CHARGE_INTERVAL, CHARGE_THRESHOLD - CHARGE_REDUCTION_PER_LEVEL * spellLevel, CHARGE_LIMIT)
            call SaveInteger(F_ID_Storage, GetHandleId(caster), 0, F)
            set xCaster = GetUnitX(caster)
            set yCaster = GetUnitY(caster)
            set a = (GetUnitFacing(caster) * bj_DEGTORAD) - ANGLE_PER_PORT
            loop
                set i = i + 1
                exitwhen i > NUMBER_OF_PORTS
                set x = xCaster + Cos(a) * PORTS_DISTANCE
                set y = yCaster + Sin(a) * PORTS_DISTANCE
                call ExitPort.create(F, x, y, 0, a * bj_RADTODEG)
                set a = a + ANGLE_PER_PORT
            endloop
            set NextPort[F] = 1
            call UnitAddAbility(caster, RALLY_ID)
            call UnitAddAbility(caster, CREATE_TANK_ID)
            call UnitMakeAbilityPermanent(caster, true, CREATE_TANK_ID)
            call SetUnitAbilityLevel(caster, CREATE_TANK_ID, spellLevel)
            set HeroTrigger[F] = CreateTrigger()
            call TriggerRegisterUnitEvent(HeroTrigger[F], caster, EVENT_UNIT_DEATH)
            call TriggerRegisterUnitEvent(HeroTrigger[F], caster, EVENT_UNIT_HERO_SKILL)
            call TriggerRegisterUnitEvent(HeroTrigger[F], caster, EVENT_UNIT_ISSUED_ORDER)
            call TriggerAddCondition(HeroTrigger[F], Condition(function OnHeroEvent))
            if SHOW_CHARGE_COUNT then
                set ChargeText[F] = CreateTextTag()
                call SetTextTagPos(ChargeText[F], xCaster, yCaster, GetUnitFlyHeight(caster) + TEXT_HEIGHT)
                call SetTextTagPermanent(ChargeText[F], true)
                call SetTextTagColor(ChargeText[F], 255, 255, 255, 255)
                call SetTextTagText(ChargeText[F], I2S(FactoryMode.getCharges(F)), .023)
                call SetTextTagVisibility(ChargeText[F], (GetLocalPlayer() == GetOwningPlayer(caster)))
            endif
        else
            set F = LoadInteger(F_ID_Storage, GetHandleId(caster), 0)
            call DestroyTrigger(HeroTrigger[F])
            if ChargeText[F] != null then
                call DestroyTextTag(ChargeText[F])
            endif
            set IsCreateTankOn[F] = false
            set NextPort[F] = 0
            call FactoryMode.remove(F)
            call UnitRemoveAbility(caster, RALLY_ID)
            call UnitMakeAbilityPermanent(caster, false, CREATE_TANK_ID)
            call UnitRemoveAbility(caster, CREATE_TANK_ID)
        endif
        set caster = null
    endfunction
   
   
    private function init takes nothing returns nothing
        call RegisterFactoryEvent(FACTORY_ON_CHARGE_UP, function ActionsChargeUp)
        call RegisterFactoryEvent(FACTORY_ON_CHARGE_INTERVAL, function ActionsInterval)
        call RegisterSpellEffectEvent(SPELL_ID, function onCast)
        call RegisterSpellEffectEvent(CREATE_TANK_ID, function onTank)
        call TriggerRegisterAnyUnitEventBJ(onDeathTrig, EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(onDeathTrig, Condition(function OnMachineDeath))
    endfunction
   
   
endlibrary
//============================================================================
// SpellEffectEvent
// - Version 1.1.0.0
//
// API
// ---
//     RegisterSpellEffectEvent(integer abil, code onCast)
//
// Requires
// --------
//     RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
// Optional
// --------
//     Table: hiveworkshop.com/forums/showthread.php?t=188084
//
library SpellEffectEvent requires RegisterPlayerUnitEvent, optional Table
 
//============================================================================
private module M
   
    static if LIBRARY_Table then
        static Table tb
    else
        static hashtable ht = InitHashtable()
    endif
   
    static method onCast takes nothing returns nothing
        static if LIBRARY_Table then
            call TriggerEvaluate(.tb.trigger[GetSpellAbilityId()])
        else
            call TriggerEvaluate(LoadTriggerHandle(.ht, 0, GetSpellAbilityId()))
        endif
    endmethod
 
    private static method onInit takes nothing returns nothing
        static if LIBRARY_Table then
            set .tb = Table.create()
        endif
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
    endmethod
endmodule
 
//============================================================================
private struct S extends array
    implement M
endstruct
 
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
    static if LIBRARY_Table then
        if not S.tb.handle.has(abil) then
            set S.tb.trigger[abil] = CreateTrigger()
        endif
        call TriggerAddCondition(S.tb.trigger[abil], Filter(onCast))
    else
        if not HaveSavedHandle(S.ht, 0, abil) then
            call SaveTriggerHandle(S.ht, 0, abil, CreateTrigger())
        endif
        call TriggerAddCondition(LoadTriggerHandle(S.ht, 0, abil), Filter(onCast))
    endif
endfunction
 
endlibrary
/**************************************************************
*
*   RegisterPlayerUnitEvent
*   v5.1.0.1
*   By Magtheridon96
*
*   I would like to give a special thanks to Bribe, azlier
*   and BBQ for improving this library. For modularity, it only
*   supports player unit events.
*
*   Functions passed to RegisterPlayerUnitEvent must either
*   return a boolean (false) or nothing. (Which is a Pro)
*
*   Warning:
*   --------
*
*       - Don't use TriggerSleepAction inside registered code.
*       - Don't destroy a trigger unless you really know what you're doing.
*
*   API:
*   ----
*
*       - function RegisterPlayerUnitEvent takes playerunitevent whichEvent, code whichFunction returns nothing
*           - Registers code that will execute when an event fires.
*       - function RegisterPlayerUnitEventForPlayer takes playerunitevent whichEvent, code whichFunction, player whichPlayer returns nothing
*           - Registers code that will execute when an event fires for a certain player.
*       - function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
*           - Returns the trigger corresponding to ALL functions of a playerunitevent.
*
**************************************************************/

library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
    globals
        private trigger array t
    endglobals
   
    function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
        local integer i = GetHandleId(p)
        local integer k = 15
        if t[i] == null then
            set t[i] = CreateTrigger()
            loop
                call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
                exitwhen k == 0
                set k = k - 1
            endloop
        endif
        call TriggerAddCondition(t[i], Filter(c))
    endfunction
   
    function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing
        local integer i = 16 * GetHandleId(p) + GetPlayerId(pl)
        if t[i] == null then
            set t[i] = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(t[i], pl, p, null)
        endif
        call TriggerAddCondition(t[i], Filter(c))
    endfunction
   
    function GetPlayerUnitEventTrigger takes playerunitevent p returns trigger
        return t[GetHandleId(p)]
    endfunction
endlibrary
library BlizzardMessage /* v1.0.0.4
*************************************************************************************
*
*   For creating Blizzard-like messages with a variety of sounds.
*
*************************************************************************************
*
*   Credits
*
*       Vexorian
*       -----------------------
*
*           The original SimError
*
*
*       Maker
*       -----------------------
*
*           Sound label help
*
************************************************************************************
*
*   Function
*   -----------------------
*
*        function BlizzardMessage takes string msg, string colorCode, integer soundLabel, player forPlayer returns nothing
*
*   Description
*   -----------------------
*
*       This function creates a Blizzard-like message with a sound for a player.
*
*   Takes
*   -----------------------
*
*       string msg
*           -   The message to be displayed.
*
*       string colorCode
*           -   Adds a color for the message through an ARBG color code. A null value creates a normal white text.
*      
*       integer soundLabel
*           -   The sound to be played.
*
*       player forPlayer
*           -   The player that receives the message.
*
*   Returns
*   -----------------------
*
*       nothing
*
*************************************************************************************
*
*   Function
*   -----------------------
*
*        function BlizzardMessageTimed takes string msg, string colorCode, real dur, integer soundLabel, player forPlayer returns nothing
*
*   Description
*   -----------------------
*
*       This function creates a timed Blizzard-like message with a sound for a player.
*
*   Takes
*   -----------------------
*
*       string msg
*           -   The message to be displayed.
*
*       string colorCode
*           -   Adds a color for the message through an ARBG color code. A null value creates a normal white text.
*
*       real dur
*           -   The duration of the message.
*
*       integer soundLabel
*           -   The sound to be played.
*
*       player forPlayer
*           -   The player that receives the message.
*
*   Returns
*   -----------------------
*
*       nothing
*
*************************************************************************************
*
*   SETTINGS
*   -----------------------
*
*/

    globals
   
        constant real MSG_DURATION = 2.00 //Message Duration
   
        /*************************************************************************************
        *
        *   Sound Labels
        *
        *************************************************************************************/

       
        constant integer ALLY_HERO_DIES_HUMAN = 0
        constant integer ALLY_HERO_DIES_NAGA = 1
        constant integer ALLY_HERO_DIES_NIGHTELF = 2
        constant integer ALLY_HERO_DIES_ORC = 3
        constant integer ALLY_HERO_DIES_UNDEAD = 4
        constant integer ALLY_TOWN_UNDER_ATTACK_HUMAN = 5
        constant integer ALLY_TOWN_UNDER_ATTACK_NAGA = 6
        constant integer ALLY_TOWN_UNDER_ATTACK_NIGHTELF = 7
        constant integer ALLY_TOWN_UNDER_ATTACK_ORC = 8
        constant integer ALLY_TOWN_UNDER_ATTACK_UNDEAD = 9
        constant integer ALLY_UNDER_ATTACK_HUMAN = 10
        constant integer ALLY_UNDER_ATTACK_NAGA = 11
        constant integer ALLY_UNDER_ATTACK_NIGHTELF = 12
        constant integer ALLY_UNDER_ATTACK_ORC = 13
        constant integer ALLY_UNDER_ATTACK_UNDEAD = 14
        constant integer ARRANGED_TEAM_INVITATION = 15
        constant integer AUTO_CAST_BUTTON_CLICK = 16
        constant integer CANT_PLACE_HUMAN = 17
        constant integer CANT_PLACE_NAGA = 18
        constant integer CANT_PLACE_NIGHTELF = 19
        constant integer CANT_PLACE_ORC = 20
        constant integer CANT_PLACE_UNDEAD = 21
        constant integer CANT_ROOT_NIGHTELF = 22
        constant integer CHATROOM_TIMER_TICK = 23
        constant integer CLAN_INVITATION = 24
        constant integer CONSTRUCTING_BUILDING_DEFAULT = 25
        constant integer CONSTRUCTING_BUILDING_NAGA = 26
        constant integer CONSTRUCTING_BUILDING_NIGHTELF = 27
        constant integer CONSTRUCTING_BUILDING_ORC = 28
        constant integer CONSTRUCTING_BUILDING_UNDEAD = 29
        constant integer CREEP_AGGRO = 30
        constant integer ERROR_MESSAGE = 31
        constant integer GAME_FOUND = 32
        constant integer GLUE_SCREEN_CLICK = 33
        constant integer GOLD_MINE_COLLAPSE_HUMAN = 34
        constant integer GOLD_MINE_COLLAPSE_NAGA = 35
        constant integer GOLD_MINE_COLLAPSE_NIGHTELF = 36
        constant integer GOLD_MINE_COLLAPSE_ORC = 37
        constant integer GOLD_MINE_COLLAPSE_UNDEAD = 38
        constant integer GOLD_MINE_LOW_GENERIC = 39
        constant integer GOLD_MINE_LOW_HUMAN = 40
        constant integer GOLD_MINE_LOW_NAGA = 41
        constant integer GOLD_MINE_LOW_NIGHTELF = 42
        constant integer GOLD_MINE_LOW_ORC = 43
        constant integer GOLD_MINE_LOW_UNDEAD = 44
        constant integer GOOD_JOB = 45
        constant integer HERO_DIES_GENERIC = 46
        constant integer HERO_DIES_HUMAN = 47
        constant integer HERO_DIES_NAGA = 48
        constant integer HERO_DIES_NIGHTELF = 49
        constant integer HERO_DIES_ORC = 50
        constant integer HERO_DIES_UNDEAD = 51
        constant integer HINT = 52
        constant integer IN_GAME_CHAT_WHAT = 53
        constant integer INTERFACE_CLICK = 54
        constant integer INTERFACE_ERROR = 55
        constant integer INVENTORY_FULL_HUMAN = 56
        constant integer INVENTORY_FULL_NAGA = 57
        constant integer INVENTORY_FULL_NIGHTELF = 58
        constant integer INVENTORY_FULL_ORC = 59
        constant integer INVENTORY_FULL_UNDEAD = 60
        constant integer ITEM_DROP = 61
        constant integer ITEM_GET = 62
        constant integer ITEM_REWARD = 63
        constant integer JOB_DONE_SOUND_HUMAN = 64
        constant integer JOB_DONE_SOUND_NAGA = 65
        constant integer JOB_DONE_SOUND_NIGHTELF = 66
        constant integer JOB_DONE_SOUND_ORC = 67
        constant integer JOB_DONE_SOUND_UNDEAD = 68
        constant integer MAP_PING = 69
        constant integer MENU_BUTTON_CLICK = 70
        constant integer NEW_TOURNAMENT = 71
        constant integer NO_FOOD_HUMAN = 72
        constant integer NO_FOOD_NAGA = 73
        constant integer NO_FOOD_NIGHTELF = 74
        constant integer NO_FOOD_ORC = 75
        constant integer NO_FOOD_UNDEAD = 76
        constant integer NO_GOLD_GENERIC = 77
        constant integer NO_GOLD_HUMAN = 78
        constant integer NO_GOLD_NAGA = 79
        constant integer NO_GOLD_NIGHTELF = 80
        constant integer NO_GOLD_ORC = 81
        constant integer NO_GOLD_UNDEAD = 82
        constant integer NO_LUMBER_HUMAN = 83
        constant integer NO_LUMBER_NAGA = 84
        constant integer NO_LUMBER_NIGHTELF = 85
        constant integer NO_LUMBER_ORC = 86
        constant integer NO_LUMBER_UNDEAD = 87
        constant integer NO_MANA_GENERIC = 88
        constant integer NO_MANA_HUMAN = 89
        constant integer NO_MANA_NAGA = 90
        constant integer NO_MANA_NIGHTELF = 91
        constant integer NO_MANA_ORC = 92
        constant integer NO_MANA_UNDEAD = 93
        constant integer OFF_BLIGHT_UNDEAD = 94
        constant integer PAUSE_GAME = 95
        constant integer PLACE_BUILDING_DEFAULT = 96
        constant integer QUEST_COMPLETED = 97
        constant integer QUEST_FAILED = 98
        constant integer QUEST_LOG_MODIFIED = 99
        constant integer QUEST_NEW = 100
        constant integer QUEST_UPDATE = 101
        constant integer RALLY_POINT_PLACE = 102
        constant integer RESCUE = 103
        constant integer RESEARCH_COMPLETE_GENERIC = 104
        constant integer RESEARCH_COMPLETE_HUMAN = 105
        constant integer RESEARCH_COMPLETE_NAGA = 106
        constant integer RESEARCH_COMPLETE_NIGHTELF = 107
        constant integer RESEARCH_COMPLETE_ORC = 108
        constant integer RESEARCH_COMPLETE_UNDEAD = 109
        constant integer SCORE_SCREEN_TAB_CLICK = 110
        constant integer SECRET_FOUND = 111
        constant integer SUB_GROUP_SELECTION_CHANGE = 112
        constant integer TOWN_ATTACK_GENERIC = 113
        constant integer TOWN_ATTACK_HUMAN = 114
        constant integer TOWN_ATTACK_NAGA = 115
        constant integer TOWN_ATTACK_NIGHTELF = 116
        constant integer TOWN_ATTACK_ORC = 117
        constant integer TOWN_ATTACK_UNDEAD = 118
        constant integer UNDER_ATTACK_HUMAN = 119
        constant integer UNDER_ATTACK_NAGA = 120
        constant integer UNDER_ATTACK_NIGHTELF = 121
        constant integer UNDER_ATTACK_ORC = 122
        constant integer UNDER_ATTACK_UNDEAD = 123
        constant integer UPGRADE_COMPLETE_GENERIC = 124
        constant integer UPGRADE_COMPLETE_HUMAN = 125
        constant integer UPGRADE_COMPLETE_NAGA = 126
        constant integer UPGRADE_COMPLETE_NIGHTELF = 127
        constant integer UPGRADE_COMPLETE_ORC = 128
        constant integer UPGRADE_COMPLETE_UNDEAD = 129
        constant integer UPKEEP_LEVEL = 130
        constant integer WARNING = 131
        constant integer WAYPOINT = 132
   
        /* private */ string array SOUND_LABEL
    endglobals
   
/*
************************************************************************************
*/


    function BlizzardMessage takes string msg, string colorCode, integer soundLabel, player forPlayer returns nothing
        local sound snd
        local string s
   
        debug if soundLabel >= 0 and soundLabel <= 132 and forPlayer != null then
       
            set snd = CreateSoundFromLabel (SOUND_LABEL[soundLabel], false, false, false, 10, 10)
           
            if colorCode != null then
                set s = "|r"
            else
                set colorCode = ""
                set s = ""
            endif
           
            if GetLocalPlayer () == forPlayer then
                call ClearTextMessages ()
                call DisplayTimedTextToPlayer (forPlayer, 0.52, 0.96, MSG_DURATION, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + colorCode + msg + s)
                call StartSound (snd)
            endif
           
            if s != null then
                set s = ""
            endif
           
            set snd = null
           
        debug else
            debug if msg == null
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[BlizzardMessage] [BlizzardMessage] Null message")
            debug endif            
            debug if forPlayer == null
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[BlizzardMessage] [BlizzardMessage] Null forPlayer")
            debug endif
            debug if soundLabel < 0 or soundLabel > 132
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[BlizzardMessage] [BlizzardMessage] Invalid sound label")
            debug endif
        debug endif
    endfunction
   
    function BlizzardMessageTimed takes string msg, string colorCode, real dur, integer soundLabel, player forPlayer returns nothing
        local sound snd
        local string s
   
        debug if soundLabel >= 0 and soundLabel <= 132 and forPlayer != null then
       
            set snd = CreateSoundFromLabel (SOUND_LABEL[soundLabel], false, false, false, 10, 10)
           
            if colorCode != null then
                set s = "|r"
            else
                set colorCode = ""
                set s = ""
            endif
           
            if GetLocalPlayer () == forPlayer then
                call ClearTextMessages ()
                call DisplayTimedTextToPlayer (forPlayer, 0.52, 0.96, dur, "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + colorCode + msg + s)
                call StartSound (snd)
            endif
           
            if s != null then
                set s = ""
            endif
           
            set snd = null
           
        debug else
            debug if msg == null
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[BlizzardMessage] [BlizzardMessage] Null message")
            debug endif            
            debug if forPlayer == null
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[BlizzardMessage] [BlizzardMessage] Null forPlayer")
            debug endif
            debug if soundLabel < 0 or soundLabel > 132
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[BlizzardMessage] [BlizzardMessage] Invalid sound label")
            debug endif
        debug endif
    endfunction

    private module BMInit
        private static method onInit takes nothing returns nothing
            call init()
        endmethod
    endmodule
   
    private struct InitStruct extends array
        private static method init takes nothing returns nothing
            set SOUND_LABEL[0] = "AllyHeroDiesHuman"
            set SOUND_LABEL[1] = "AllyHeroDiesNaga"
            set SOUND_LABEL[2] = "AllyHeroDiesNightElf"
            set SOUND_LABEL[3] = "AllyHeroDiesOrc"
            set SOUND_LABEL[4] = "AllyHeroDiesUndead"
            set SOUND_LABEL[5] = "AllyTownUnderAttackHuman"
            set SOUND_LABEL[6] = "AllyTownUnderAttackNaga"
            set SOUND_LABEL[7] = "AllyTownUnderAttackNightElf"
            set SOUND_LABEL[8] = "AllyTownUnderAttackOrc"
            set SOUND_LABEL[9] = "AllyTownUnderAttackUndead"
            set SOUND_LABEL[10] = "AllyUnderAttackHuman"
            set SOUND_LABEL[11] = "AllyUnderAttackNaga"
            set SOUND_LABEL[12] = "AllyUnderAttackNightElf"
            set SOUND_LABEL[13] = "AllyUnderAttackOrc"
            set SOUND_LABEL[14] = "AllyUnderAttackUndead"
            set SOUND_LABEL[15] = "ArrangedTeamInvitation"
            set SOUND_LABEL[16] = "AutoCastButtonClick"
            set SOUND_LABEL[17] = "CantPlaceHuman"
            set SOUND_LABEL[18] = "CantPlaceNaga"
            set SOUND_LABEL[19] = "CantPlaceNightElf"
            set SOUND_LABEL[20] = "CantPlaceOrc"
            set SOUND_LABEL[21] = "CantPlaceUndead"
            set SOUND_LABEL[22] = "CantRootNightElf"
            set SOUND_LABEL[23] = "ChatroomTimerTick"
            set SOUND_LABEL[24] = "ClanInvitation"
            set SOUND_LABEL[25] = "ConstructingBuildingDefault"
            set SOUND_LABEL[26] = "ConstructingBuildingNaga"
            set SOUND_LABEL[27] = "ConstructingBuildingNightElf"
            set SOUND_LABEL[28] = "ConstructingBuildingOrc"
            set SOUND_LABEL[29] = "ConstructingBuildingUndead"
            set SOUND_LABEL[30] = "CreepAggro"
            set SOUND_LABEL[31] = "ErrorMessage"
            set SOUND_LABEL[32] = "GameFound"
            set SOUND_LABEL[33] = "GlueScreenClick"
            set SOUND_LABEL[34] = "GoldMineCollapseHuman"
            set SOUND_LABEL[35] = "GoldMineCollapseNaga"
            set SOUND_LABEL[36] = "GoldMineCollapseNightElf"
            set SOUND_LABEL[37] = "GoldMineCollapseOrc"
            set SOUND_LABEL[38] = "GoldMineCollapseUndead"
            set SOUND_LABEL[39] = "GoldMineLowGeneric"
            set SOUND_LABEL[40] = "GoldMineLowHuman"
            set SOUND_LABEL[41] = "GoldMineLowNaga"
            set SOUND_LABEL[42] = "GoldMineLowNightElf"
            set SOUND_LABEL[43] = "GoldMineLowOrc"
            set SOUND_LABEL[44] = "GoldMineLowUndead"
            set SOUND_LABEL[45] = "GoodJob"
            set SOUND_LABEL[46] = "HeroDiesGeneric"
            set SOUND_LABEL[47] = "HeroDiesHuman"
            set SOUND_LABEL[48] = "HeroDiesNaga"
            set SOUND_LABEL[49] = "HeroDiesNightElf"
            set SOUND_LABEL[50] = "HeroDiesOrc"
            set SOUND_LABEL[51] = "HeroDiesUndead"
            set SOUND_LABEL[52] = "Hint"
            set SOUND_LABEL[53] = "InGameChatWhat"
            set SOUND_LABEL[54] = "InterfaceClick"
            set SOUND_LABEL[55] = "InterfaceError"
            set SOUND_LABEL[56] = "InventoryFullHuman"
            set SOUND_LABEL[57] = "InventoryFullNaga"
            set SOUND_LABEL[58] = "InventoryFullNightElf"
            set SOUND_LABEL[59] = "InventoryFullOrc"
            set SOUND_LABEL[60] = "InventoryFullUndead"
            set SOUND_LABEL[61] = "ItemDrop"
            set SOUND_LABEL[62] = "ItemGet"
            set SOUND_LABEL[63] = "ItemReward"
            set SOUND_LABEL[64] = "JobDoneSoundHuman"
            set SOUND_LABEL[65] = "JobDoneSoundNaga"
            set SOUND_LABEL[66] = "JobDoneSoundNightElf"
            set SOUND_LABEL[67] = "JobDoneSoundOrc"
            set SOUND_LABEL[68] = "JobDoneSoundUndead"
            set SOUND_LABEL[69] = "MapPing"
            set SOUND_LABEL[70] = "MenuButtonClick"
            set SOUND_LABEL[71] = "NewTournament"
            set SOUND_LABEL[72] = "NoFoodHuman"
            set SOUND_LABEL[73] = "NoFoodNaga"
            set SOUND_LABEL[74] = "NoFoodNightElf"
            set SOUND_LABEL[75] = "NoFoodOrc"
            set SOUND_LABEL[76] = "NoFoodUndead"
            set SOUND_LABEL[77] = "NoGoldGeneric"
            set SOUND_LABEL[78] = "NoGoldHuman"
            set SOUND_LABEL[79] = "NoGoldNaga"
            set SOUND_LABEL[80] = "NoGoldNightElf"
            set SOUND_LABEL[81] = "NoGoldOrc"
            set SOUND_LABEL[82] = "NoGoldUndead"
            set SOUND_LABEL[83] = "NoLumberHuman"
            set SOUND_LABEL[84] = "NoLumberNaga"
            set SOUND_LABEL[85] = "NoLumberNightElf"
            set SOUND_LABEL[86] = "NoLumberOrc"
            set SOUND_LABEL[87] = "NoLumberUndead"
            set SOUND_LABEL[88] = "NoManaGeneric"
            set SOUND_LABEL[89] = "NoManaHuman"
            set SOUND_LABEL[90] = "NoManaNaga"
            set SOUND_LABEL[91] = "NoManaNightElf"
            set SOUND_LABEL[92] = "NoManaOrc"
            set SOUND_LABEL[93] = "NoManaUndead"
            set SOUND_LABEL[94] = "OffBlightUndead"
            set SOUND_LABEL[95] = "PauseGame"
            set SOUND_LABEL[96] = "PlaceBuildingDefault"
            set SOUND_LABEL[97] = "QuestCompleted"
            set SOUND_LABEL[98] = "QuestFailed"
            set SOUND_LABEL[99] = "QuestLogModified"
            set SOUND_LABEL[100] = "QuestNew"
            set SOUND_LABEL[101] = "QuestUpdate"
            set SOUND_LABEL[102] = "RallyPointPlace"
            set SOUND_LABEL[103] = "Rescue"
            set SOUND_LABEL[104] = "ResearchCompleteGeneric"
            set SOUND_LABEL[105] = "ResearchCompleteHuman"
            set SOUND_LABEL[106] = "ResearchCompleteNaga"
            set SOUND_LABEL[107] = "ResearchCompleteNightElf"
            set SOUND_LABEL[108] = "ResearchCompleteOrc"
            set SOUND_LABEL[109] = "ResearchCompleteUndead"
            set SOUND_LABEL[110] = "ScoreScreenTabClick"
            set SOUND_LABEL[111] = "SecretFound"
            set SOUND_LABEL[112] = "SubGroupSelectionChange"
            set SOUND_LABEL[113] = "TownAttackGeneric"
            set SOUND_LABEL[114] = "TownAttackHuman"
            set SOUND_LABEL[115] = "TownAttackNaga"
            set SOUND_LABEL[116] = "TownAttackNightElf"
            set SOUND_LABEL[117] = "TownAttackOrc"
            set SOUND_LABEL[118] = "TownAttackUndead"
            set SOUND_LABEL[119] = "UnderAttackHuman"
            set SOUND_LABEL[120] = "UnderAttackNaga"
            set SOUND_LABEL[121] = "UnderAttackNightElf"
            set SOUND_LABEL[122] = "UnderAttackOrc"
            set SOUND_LABEL[123] = "UnderAttackUndead"
            set SOUND_LABEL[124] = "UpgradeCompleteGeneric"
            set SOUND_LABEL[125] = "UpgradeCompleteHuman"
            set SOUND_LABEL[126] = "UpgradeCompleteNaga"
            set SOUND_LABEL[127] = "UpgradeCompleteNightElf"
            set SOUND_LABEL[128] = "UpgradeCompleteOrc"
            set SOUND_LABEL[129] = "UpgradeCompleteUndead"
            set SOUND_LABEL[130] = "UpkeepLevel"
            set SOUND_LABEL[131] = "Warning"
            set SOUND_LABEL[132] = "WayPoint"
        endmethod
   
        implement BMInit
    endstruct
endlibrary
Default melee game initialization for all players
Initialization
  Events
    Map initialization
  Conditions
  Actions
    Visibility - Disable fog of war
    Visibility - Disable black mask
    Game - Set the time of day to 12
    Game - Display to (All players) for 30 seconds the text: Morph your hero into Factory Mode and watch as the charges build up. Activate |cffffcc00Create Tank|r to allow your hero to automatically produce tanks as the required amount of charges is gathered.Press ESC to clear this message.
Mobs
  Events
    Time - Every 30.00 seconds of game time
  Conditions
  Actions
    If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      If - Conditions
        (Castle 0002 <gen> is alive) Equal to True
      Then - Actions
        Set Loc = (Random point in Region_000 <gen>)
        Unit - Create 1 Footman for Neutral Hostile at Loc facing 90.00 degrees
        Unit - Order (Last created unit) to Attack-Move To (Point(0, 0))
        Set Loc = (Random point in Region_000 <gen>)
        Unit - Create 1 Rifleman for Neutral Hostile at Loc facing 90.00 degrees
        Unit - Order (Last created unit) to Attack-Move To (Point(0, 0))
        Set Loc = (Random point in Region_000_Copy <gen>)
        Unit - Create 1 Footman for Neutral Hostile at Loc facing 90.00 degrees
        Unit - Order (Last created unit) to Attack-Move To (Point(0, 0))
        Set Loc = (Random point in Region_000_Copy <gen>)
        Unit - Create 1 Rifleman for Neutral Hostile at Loc facing 90.00 degrees
        Unit - Order (Last created unit) to Attack-Move To (Point(0, 0))
        Set Loc = ((Point(0, 0)) offset by 700.00 towards (Random real number between 30.00 and 150.00) degrees)
        Unit - Create 1 Dryad for Player 2 (Blue) at Loc facing 270.00 degrees
        Unit - Order (Last created unit) to Attack-Move To (Point(0, -2300.00))
        Set Loc = ((Point(0, 0)) offset by 700.00 towards (Random real number between 30.00 and 150.00) degrees)
        Unit - Create 1 Dryad for Player 2 (Blue) at Loc facing 270.00 degrees
        Unit - Order (Last created unit) to Attack-Move To (Point(0, -2300.00))
        Custom script: call RemoveLocation(udg_Loc)
      Else - Actions
        Trigger - Turn off (This trigger)
Revive
  Events
    Unit - Fabricator Tank 0000 <gen> Dies
  Conditions
  Actions
    Set Loc = (Position of Fabricator Tank 0000 <gen>)
    Hero - Instantly revive Fabricator Tank 0000 <gen> at Loc, Show revival graphics
    Custom script: call RemoveLocation(udg_Loc)
onESC
  Events
    Player - Player 1 (Red) skips a cinematic sequence
  Conditions
  Actions
    Cinematic - Clear the screen of text messages for (All players)