• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Advanced Event Management System 1.2

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Like
Reactions: Raised
This system is an event management system.

It is created to control priority (the order in which the event responses are called), remove event responses from an event and create subevents to save improve performance by ignoring triggers for other types on the same event.

How to install:
copy'n'paste

JASS:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Wietlol's Advanced Event Management System 1.2 24/04/2015
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Description:
//      This system is made to create events and add triggers aka event responses to an event.
//      The reason is that you can remove event responses from an event, create subevents to increase performance by ignoring checks
//      and to control priority of event responses.
//      This system is written in JASS and requires JASSHelper to copmile.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  How to install:
//      1. Copy the Advanced Event Management System (AEM) category and paste it in your map.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  How to create event responses for GUI triggers:
//      1. Find out how the trigger is called...
//          Trigger names are "gg_trg_" + the name of the trigger in the list at the left of the screen
//          where spaces are replaced by underscores.
//          Trigger "AEM System" is called "gg_trg_AEM_System"
//      2. Go to any JASS trigger and find the InitTrig_<triggerName> function. (Ussually found at the bottom.)
//          You can go to the AEM_Normal_Events_Implementation trigger.
//      3. Write "call AEM_FunctionRegisterEvent(<eventName>, <triggerName>, udg_AEM_EXECUTION_TYPE_CONDITIONAL, 0, true, true)"
//          <eventName> is the name of the event.
//          <triggerName> is the name of the trigger which we have made in step 1.
//      
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Feature list:
//      This system:
//      - allows you to create custom events.
//      - allows you to remove triggers from events.
//      - allows you to control priority of event responses.
//      - allows you to automatically remove an event response after the first call.
//      - allows you to create an event with a (integer)parameter to separate speficif event responses into the proper events.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Variable explaination:
//////////////////////////
//      General:
//      - AEM_EXECUTION_TYPE_CONDITIONAL        - integer
//          This is the execution type for regular execution.
//          It is recommended for GUI triggers.
//          
//      - AEM_EXECUTION_TYPE_EVALUATE           - integer
//          This is the execution type for conditions only.
//          It is recommended for JASS triggers.
//          
//      - AEM_EXECUTION_TYPE_EXECUTE            - integer
//          This is the execution type for actions only.
//          It is recommended for ... well... nothing.
//          
//      - AEM_Hashtable                         - hashtable
//          The AEM System uses 3 hashtables.
//          In the first hashtable are the events saved together with all their event responses.
//          In the second hashtable are event ids saved of events that have a subtype.
//          These subtypes can be used to increase performance of event responses
//          by only running the triggers that very probably have actions on that event.
//          The third hashtable allows a second subtype making events even more specific.
//          
//      - udg_AEM_NextIndex                     - integer
//          This is the index of the latest event.
//          When creating an event response to an unknown event, a unique number is created that will represent that event.
//          For NextIndex3, the next index is for the 
//          
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Changelog:
//      1.2 - 24/04/2015 - 
//          - Added other spell events in the Normal Event Implementation trigger.
//          - Added spell examples.
//          - Added the possibility to stop all other actions to the current event.
//          - Added the possibility to start an event from a certain priority.
//          
//      1.1 - 20/04/2015 - Second Subtype.
//          - Now has a second subtype for even more specific events.
//          - Renamed register functions so the name is more logic.
//          - Made the creation event have "bj_lastCreatedUnit" as the created unit.
//          
//      1.0 - 17/04/2015 - First official release on the Hive.
//          
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Known bugs:
//      - You can add an event response to an event multiple times but you only remove one.
//      
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////





library aemSystem
    globals
        
        integer         udg_AEM_EXECUTION_TYPE_CONDITIONAL      = 0
        integer         udg_AEM_EXECUTION_TYPE_EVALUATE         = 1
        integer         udg_AEM_EXECUTION_TYPE_EXECUTE          = 2
        
        hashtable       udg_AEM_Hashtable1                      = InitHashtable()
        hashtable       udg_AEM_Hashtable2                      = InitHashtable()
        hashtable       udg_AEM_Hashtable3                      = InitHashtable()
        
        integer         udg_AEM_NextIndex2                      = 9999
        integer         udg_AEM_NextIndex3                      = 9999
        
        integer         udg_AEM_StopRemainingEventResponses     = 1
        
        //////////////////////////////////////////////////////////////////////////////////////
        //  
        //  Event List:
        //  Make sure that all events have a unique id between 1 and 9,999.
        //  Events with 0 or lower are illegal events.
        //  Events above 9,999 are dynamic events, created by the second hashtable.
        //  You can increase that amount in the global variable above but you won't have much problems with 9,999 events.
        //  
        //  |----|-|----|   |----------------------------------------------------------------|
        //  |0001|-|0017|   |AEM_Normal_Events_Implementation                                |
        //  |----|-|----|   |----------------------------------------------------------------|
        //////////////////////////////////////////////////////////////////////////////////////
        
    endglobals
    
    //////////////////////////////////////////////////////////////////////////////////////
    //These functions remove an event response from an event.
    //  whichEvent      is the event id where the response is linked to.
    //  whichTrigger    is the trigger that must be removed.
    function AEM_FunctionRemoveEvent takes integer whichEvent, trigger whichTrigger returns nothing
        local integer i = 0
        local trigger t
        
        loop
            //The end of the responses is reached.
            exitwhen not(HaveSavedHandle(udg_AEM_Hashtable1, whichEvent, i))
            
            //The trigger has been found.
            set t = LoadTriggerHandle(udg_AEM_Hashtable1, whichEvent, i)
            if t == whichTrigger then
                loop
                    exitwhen not HaveSavedHandle(udg_AEM_Hashtable1, whichEvent, i+4)
                    
                    //Replace all event responses after the found trigger by the ones that follow it afterwards.
                    call SaveTriggerHandle(udg_AEM_Hashtable1, whichEvent, i, LoadTriggerHandle(udg_AEM_Hashtable1, whichEvent, i+4))
                    call SaveInteger(udg_AEM_Hashtable1, whichEvent, i+1, LoadInteger(udg_AEM_Hashtable1, whichEvent, i+5))
                    call SaveBoolean(udg_AEM_Hashtable1, whichEvent, i+2, LoadBoolean(udg_AEM_Hashtable1, whichEvent, i+6))
                    call SaveInteger(udg_AEM_Hashtable1, whichEvent, i+3, LoadInteger(udg_AEM_Hashtable1, whichEvent, i+7))
                    
                    set i = i + 3
                endloop
                
                //Remove the last event response from the event.
                call RemoveSavedHandle(udg_AEM_Hashtable1, whichEvent, i)
                call RemoveSavedInteger(udg_AEM_Hashtable1, whichEvent, i+1)
                call RemoveSavedBoolean(udg_AEM_Hashtable1, whichEvent, i+2)
                call RemoveSavedInteger(udg_AEM_Hashtable1, whichEvent, i+3)
                return
            endif
            set i = i + 3
        endloop
    endfunction
    
    //Same as above.
    //  whichParameter is the subtype of the event response.
    function AEM_FunctionRemoveEvent2 takes integer whichEvent, integer whichParameter2, trigger whichTrigger returns nothing
        local integer index = LoadInteger(udg_AEM_Hashtable2, whichEvent, whichParameter2)
        
        if index == 0 then
            return
        endif
        
        call AEM_FunctionRemoveEvent(index, whichTrigger)
    endfunction
    
    //Same as above.
    //  whichParameter is the subtype of the event response.
    function AEM_FunctionRemoveEvent3 takes integer whichEvent, integer whichParameter2, integer whichParameter3, trigger whichTrigger returns nothing
        local integer index = LoadInteger(udg_AEM_Hashtable3, whichEvent, whichParameter2)
        
        if index == 0 then
            return
        endif
        
        call AEM_FunctionRemoveEvent2(index, whichParameter3, whichTrigger)
    endfunction
    
    //////////////////////////////////////////////////////////////////////////////////////
    //These functions call the events made in this system.
    //  whichEvent is the event id that is fired.
    function AEM_CallEventWithPriority takes integer whichEvent, integer startingPriority returns nothing
        local trigger array triggers
        local integer index
        local integer i
        local integer array executionType
        local integer oldStopRemainingEventResponses
        
        //Check if the event is a valid event.
        if whichEvent <= 0 then
            return
        endif
        
        //Save all event responses locally.
        set i = startingPriority
        set index = 0
        loop
            exitwhen not(HaveSavedHandle(udg_AEM_Hashtable1, whichEvent, i))
            set triggers[index] = LoadTriggerHandle(udg_AEM_Hashtable1, whichEvent, i)
            
            set executionType[index] = LoadInteger(udg_AEM_Hashtable1, whichEvent, i+3)
            if not(LoadBoolean(udg_AEM_Hashtable1, whichEvent, i+2)) then
                
                //Remove the event response because it is not repeating.
                call AEM_FunctionRemoveEvent(whichEvent, triggers[index])
                set i = i - 4
            endif
            
            set index = index + 1
            set i = i + 4
        endloop
        
        //Call all locally saved triggers.
        set oldStopRemainingEventResponses = udg_AEM_StopRemainingEventResponses
        set udg_AEM_StopRemainingEventResponses = 1
        set i = 0
        loop
            exitwhen udg_AEM_StopRemainingEventResponses <= 0
            exitwhen i >= index
            if executionType[i] == udg_AEM_EXECUTION_TYPE_CONDITIONAL then
                if TriggerEvaluate(triggers[i]) then
                    call TriggerExecute(triggers[i])
                endif
            elseif executionType[i] == udg_AEM_EXECUTION_TYPE_EVALUATE then
                call TriggerEvaluate(triggers[i])
            elseif executionType[i] == udg_AEM_EXECUTION_TYPE_EXECUTE then
                call TriggerExecute(triggers[i])
            endif
            
            set triggers[i] = null
            set i = i + 1
        endloop
        
        set udg_AEM_StopRemainingEventResponses = oldStopRemainingEventResponses
        
    endfunction
    function AEM_CallEvent takes integer whichEvent returns nothing
        call AEM_CallEventWithPriority(whichEvent, 0)
    endfunction
    
    //Same as above.
    //  whichParameter2 is the subtype of the event response.
    function AEM_CallEvent2WithPriority takes integer whichEvent, integer whichParameter2, integer startingPriority returns nothing
        call AEM_CallEventWithPriority(LoadInteger(udg_AEM_Hashtable2, whichEvent, whichParameter2), startingPriority)
    endfunction
    function AEM_CallEvent2 takes integer whichEvent, integer whichParameter2 returns nothing
        call AEM_CallEvent2WithPriority(whichEvent, whichParameter2, 0)
    endfunction
    
    //Same as above.
    //  whichParameter3 is the sub-subtype of the event response.
    function AEM_CallEvent3WithPriority takes integer whichEvent, integer whichParameter2, integer whichParameter3, integer startingPriority returns nothing
        call AEM_CallEvent2WithPriority(LoadInteger(udg_AEM_Hashtable3, whichEvent, whichParameter2), whichParameter3, startingPriority)
    endfunction
    function AEM_CallEvent3 takes integer whichEvent, integer whichParameter2, integer whichParameter3 returns nothing
        call AEM_CallEvent3WithPriority(whichEvent, whichParameter2, whichParameter3, 0)
    endfunction
    
    //////////////////////////////////////////////////////////////////////////////////////
    //These functions register a trigger to an event.
    //  whichEvent      is the event id that is used.
    //  whichTrigger    is the trigger that is executed when the event fires.
    //  executionType   is the type of how the trigger is executed (only conditions, only actions, both (if conditions allow to)).
    //  priority        is the order in which the triggers are executed. Low priority is called first. High priority is called last.
    //  priorize        is if this trigger must be before the other trigger in the same priority. Be aware that registrations after this one can override that priority.
    //  repeating       is if the trigger must remain on the event. When this is put to false, the trigger gets removed from the event on the next call.
    function AEM_RegisterTrigger takes integer whichEvent, trigger whichTrigger, integer executionType, integer priority, boolean priorize, boolean repeating returns nothing
        local integer i = 0
        local integer i2
        local boolean shiftRemaining = false
        
        //Find the proper place for the event response.
        loop
            exitwhen not(HaveSavedHandle(udg_AEM_Hashtable1, whichEvent, i))
            set shiftRemaining = true
            if priorize then
                exitwhen LoadInteger(udg_AEM_Hashtable1, whichEvent, i+1) >= priority
            else
                exitwhen LoadInteger(udg_AEM_Hashtable1, whichEvent, i+1) > priority
            endif
            set shiftRemaining = false
            set i = i + 4
        endloop
        
        //Check if the event response is placed between other event responses or placed at the end.
        if shiftRemaining then
            set i2 = i + 4
            loop
                exitwhen not(HaveSavedHandle(udg_AEM_Hashtable1, whichEvent, i2))
                
                set i2 = i2 + 4
            endloop
            
            loop
                exitwhen i2 == i
                
                call SaveTriggerHandle(udg_AEM_Hashtable1, whichEvent, i2, LoadTriggerHandle(udg_AEM_Hashtable1, whichEvent, i2-4))
                call SaveInteger(udg_AEM_Hashtable1, whichEvent, i2+1, LoadInteger(udg_AEM_Hashtable1, whichEvent, i2-3))
                call SaveBoolean(udg_AEM_Hashtable1, whichEvent, i2+2, LoadBoolean(udg_AEM_Hashtable1, whichEvent, i2-2))
                call SaveInteger(udg_AEM_Hashtable1, whichEvent, i+3, LoadInteger(udg_AEM_Hashtable1, whichEvent, i2-1))
                
                set i2 = i2 - 4
            endloop
        endif
        
        //Save the event response to the event.
        call SaveTriggerHandle(udg_AEM_Hashtable1, whichEvent, i, whichTrigger)
        call SaveInteger(udg_AEM_Hashtable1, whichEvent, i+1, priority)
        call SaveBoolean(udg_AEM_Hashtable1, whichEvent, i+2, repeating)
        call SaveInteger(udg_AEM_Hashtable1, whichEvent, i+3, executionType)
    endfunction
    
    //Same as above.
    //  whichParameter2 is the subtype of the event.
    function AEM_RegisterTrigger2 takes integer whichEvent, integer whichParameter2, trigger whichTrigger, integer executionType, integer priority, boolean priorize, boolean repeating returns nothing
        
        //If the event doesn't exist yet, create an event with the NextIndex2.
        local integer index = LoadInteger(udg_AEM_Hashtable2, whichEvent, whichParameter2)
        if index == 0 then
            set udg_AEM_NextIndex2 = udg_AEM_NextIndex2 + 1
            set index = udg_AEM_NextIndex2
            call SaveInteger(udg_AEM_Hashtable2, whichEvent, whichParameter2, index)
        endif
        
        //Add the trigger to the event response.
        call AEM_RegisterTrigger(index, whichTrigger, executionType, priority, priorize, repeating)
    endfunction
    
    //Same as above.
    //  whichParameter3 is the sub-subtype of the event.
    function AEM_RegisterTrigger3 takes integer whichEvent, integer whichParameter2, integer whichParameter3, trigger whichTrigger, integer executionType, integer priority, boolean priorize, boolean repeating returns nothing
        
        //If the event doesn't exist yet, create an event with the NextIndex3.
        local integer index = LoadInteger(udg_AEM_Hashtable3, whichEvent, whichParameter2)
        if index == 0 then
            set udg_AEM_NextIndex3 = udg_AEM_NextIndex3 + 1
            set index = udg_AEM_NextIndex3
            call SaveInteger(udg_AEM_Hashtable3, whichEvent, whichParameter2, index)
        endif
        
        //Add the trigger to the event response.
        call AEM_RegisterTrigger2(index, whichParameter3, whichTrigger, executionType, priority, priorize, repeating)
    endfunction
    
endlibrary
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  AEM System end
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
JASS:
globals
    integer udg_AEM_Event_Player_Chat_Message       = 1
    integer udg_AEM_Event_Player_Esc_Button         = 2
    integer udg_AEM_Event_Player_Leave              = 3
    integer udg_AEM_Event_Unit_Pickup_Item          = 4
    integer udg_AEM_Event_Unit_Drop_Item            = 5
    integer udg_AEM_Event_Unit_Attacked             = 6
    integer udg_AEM_Event_Unit_Spell_Channel        = 7
    integer udg_AEM_Event_Unit_Spell_Cast           = 8
    integer udg_AEM_Event_Unit_Spell_Effect         = 9
    integer udg_AEM_Event_Unit_Spell_Finish         = 10
    integer udg_AEM_Event_Unit_Spell_Cancel         = 11
    integer udg_AEM_Event_Unit_Levelup              = 12
    integer udg_AEM_Event_Unit_Die                  = 13
    integer udg_AEM_Event_Unit_Order_Target         = 14
    integer udg_AEM_Event_Unit_Order_Point          = 15
    integer udg_AEM_Event_Unit_Order_Instant        = 16
    integer udg_AEM_Event_Unit_Created              = 17
endglobals


function AEM_Event_Player_Chat_Message takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Player_Chat_Message)
    return false
endfunction

function AEM_Event_Player_Esc_Button takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Player_Esc_Button)
    return false
endfunction

function AEM_Event_Player_Leave takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Player_Leave)
    return false
endfunction

function AEM_Event_Unit_Pickup_Item takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Pickup_Item)
    call AEM_CallEvent2(udg_AEM_Event_Unit_Pickup_Item, GetItemTypeId(GetManipulatedItem()))
    return false
endfunction

function AEM_Event_Unit_Drop_Item takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Drop_Item)
    call AEM_CallEvent2(udg_AEM_Event_Unit_Drop_Item, GetItemTypeId(GetManipulatedItem()))
    return false
endfunction

function AEM_Event_Unit_Attacked takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Attacked)
    return false
endfunction

function AEM_Event_Unit_Spell_Cast takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Spell_Cast)
    call AEM_CallEvent2(udg_AEM_Event_Unit_Spell_Cast, GetSpellAbilityId())
    return false
endfunction

function AEM_Event_Unit_Spell_Channel takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Spell_Channel)
    call AEM_CallEvent2(udg_AEM_Event_Unit_Spell_Channel, GetSpellAbilityId())
    return false
endfunction

function AEM_Event_Unit_Spell_Effect takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Spell_Effect)
    call AEM_CallEvent2(udg_AEM_Event_Unit_Spell_Effect, GetSpellAbilityId())
    return false
endfunction

function AEM_Event_Unit_Spell_Finish takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Spell_Finish)
    call AEM_CallEvent2(udg_AEM_Event_Unit_Spell_Finish, GetSpellAbilityId())
    return false
endfunction

function AEM_Event_Unit_Spell_Cancel takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Spell_Cancel)
    call AEM_CallEvent2(udg_AEM_Event_Unit_Spell_Cancel, GetSpellAbilityId())
    return false
endfunction

function AEM_Event_Unit_Levelup takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Levelup)
    return false
endfunction

function AEM_Event_Unit_Die takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Die)
    return false
endfunction

function AEM_Event_Unit_Order_Target takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Order_Target)
    call AEM_CallEvent2(udg_AEM_Event_Unit_Order_Target, GetIssuedOrderId())
    return false
endfunction

function AEM_Event_Unit_Order_Point takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Order_Point)
    call AEM_CallEvent2(udg_AEM_Event_Unit_Order_Point, GetIssuedOrderId())
    return false
endfunction

function AEM_Event_Unit_Order_Instant takes nothing returns boolean
    call AEM_CallEvent(udg_AEM_Event_Unit_Order_Instant)
    call AEM_CallEvent2(udg_AEM_Event_Unit_Order_Instant, GetIssuedOrderId())
    return false
endfunction

function UnitCreation_Event takes nothing returns boolean
    set bj_lastCreatedUnit = GetFilterUnit()
    
    call AEM_CallEvent(udg_AEM_Event_Unit_Created)
    
    return false
endfunction

function UnitCreation_Start takes nothing returns nothing
    local group g = CreateGroup()
    local trigger t = CreateTrigger()
    local region rectRegion = CreateRegion()
    call DestroyTimer(GetExpiredTimer())
    
    call RegionAddRect(rectRegion, GetWorldBounds())
    call TriggerRegisterEnterRegion(t, rectRegion, Filter(function UnitCreation_Event))
    
    call GroupEnumUnitsInRect(g, GetWorldBounds(), Filter(function UnitCreation_Event))
    call DestroyGroup(g)
    set g = null
endfunction


//===========================================================================
function InitTrig_AEM_Normal_Events_Implementation takes nothing returns nothing
    local trigger t
    local integer i
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerChatEvent(t, Player(i), "", false)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Player_Chat_Message))
    
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_END_CINEMATIC)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Player_Esc_Button))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_LEAVE)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Player_Leave))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Pickup_Item))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_DROP_ITEM, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Drop_Item))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ATTACKED, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Attacked))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_CHANNEL, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Spell_Channel))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_CAST, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Spell_Cast))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Spell_Effect))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_FINISH, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Spell_Finish))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Spell_Cancel))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_HERO_LEVEL, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Levelup))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_DEATH, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Die))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Order_Target))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Order_Point))
    
    set t = CreateTrigger()
    set i = 0
    loop
        exitwhen i == bj_MAX_PLAYER_SLOTS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
        set i = i + 1
    endloop
    call TriggerAddCondition(t, Filter(function AEM_Event_Unit_Order_Instant))
    
    call TimerStart(CreateTimer(), 0.05, false, function UnitCreation_Start)
    
    set t = null
endfunction

Changelog:
- 1.2 - Added functionality to stop remaining triggers and start from certain priority.
- 1.1 - Second subtye.
- 1.0 - Official release on the Hive.

Keywords:
Wietlol, event, trigger, response, priority, call.
Contents

Just another Warcraft III map (Map)

Reviews
10:41, 24th Apr 2015 IcemanBo: Read my reply in thread.
Level 24
Joined
Aug 1, 2013
Messages
4,657
But you dont have to use the global blocks.
In that case you just put the variables inside the normal variable list.
However, this is more for JASS people and most prefer to have these variables inside tags instead of a massive list.

Also... i did read it.
Never got into it.
 
Level 33
Joined
Apr 24, 2012
Messages
5,113
But you dont have to use the global blocks.
In that case you just put the variables inside the normal variable list.
However, this is more for JASS people and most prefer to have these variables inside tags instead of a massive list.

Also... i did read it.
Never got into it.

As we have said, make them require JNGP.

Most people will be confused.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
So should I mark it vJASS?

--------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Even though I didn't thought I would need a third hashtable... I do.

I just released version 1.1

Here are the changes:
  • Now has a second subtype for even more specific events.
  • Renamed register functions so the name is more logic.
  • Made the creation event have "bj_lastCreatedUnit" as the created unit.
 
Last edited:
JASS:
// This system is made to create events and add triggers aka event responses to an event.
Sorry, I don't understand the goal of the system with this. And in what way are triggers event responses? I'm confused.

Can you make an example that demonstares it's usefulnes?

What I could read out is that you want to increase performance of event responses, or something similar.^^
But are you aware that loading data from hashtable is actually a very slow operation?

I share the skepticism with Almia towards the different types. How do you need 'em?

In the AEM Normal Events, why no loop in init?

Please seperate example from system folder.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
JASS:
// This system is made to create events and add triggers aka event responses to an event.
Sorry, I don't understand the goal of the system with this. And in what way are triggers event responses? I'm confused.
A trigger is a piece of executable code... an event response is a piece of code that is executed when a specific event is fired.
Triggers are not always executed by an event.
Also... you only read 1 line out of 4? If so, you won't understand anything anymore.
If you read the sentence below it, you might understand:
The reason is that you can remove event responses from an event, create subevents to increase performance by ignoring checks and to control priority of event responses.
You can add/remove events really easy, so you can add an event to a trigger... or actually a trigger to an event if you really care about how this system wors, and remove it after a while.
Like, if a unit will cast an ability within ... seconds, you can add the execution trigger (the trigger that will execute that action) to the cast ability event and remove it when the timer runs out.
One other main reason is that you can control priority.
This feature is because in normal triggers, it is almost impossible to know which action is fired first... and if you for example want a damage system and you reduce the damage taken by armor first and then you add damage which you wanted to be added before the armor calculation... you are pretty much fcked up... even on a very small problem.

Can you make an example that demonstares it's usefulnes?
You are really the last one of who I expected this question.
onInterval potentialy calls all periodic triggers by user very often, even they won't match because of not correct Param_Type.
You might think of letting the user to bind a trigger to the EOT that will be only called if it's instance will be looped by your system, but not by any random instance.
Maybe you remember that one.
With this system, you can instead of checking for an integer parameter constantly, just go and address the wanted triggers directly.
Imagine you want effects on spells.
A lot of people use this way:
  • Ability MySpell
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to MySpell
    • Actions
      • -------- here my custom actions --------
It is not a bad trigger on its own... but having 300 of those is the same as having that generic event in my EOT System.
This system allows you to call an event and give up to 2 parameters with it.
Like, call Event(StartsTheEffectOfAnAbility, GetSpellAbilityId()).
Then instead of using the "A unit Starts the effect of an ability" event, you register the trigger to the event StartsTheEffectOfAnAbility, 'myspellid'.
Now only that trigger is executed when that spell is cast.
In the new test map, I created 13 triggers for all active spells of the human heroes.
Each spell is registered to the OnSpellEffect event with their own id.
No checks and all work fine.
There is another trigger in it which shows how it is done normally.
(And even that one is pretty optimized because it is put in a single trigger instead of 13.)

What I could read out is that you want to increase performance of event responses, or something similar.^^
But are you aware that loading data from hashtable is actually a very slow operation?
I do know that... even now, as explained above, this might increase performance a lot if you have a lot of generic events with only a few to 1 trigger that should be executed.
But btdonald is so kind to rewrite this system in vJASS with structs so everything will be replaced by arrays... as far as I understand it :D

I share the skepticism with Almia towards the different types. How do you need 'em?
In JASS, we all know that we should use TriggerAddCondition() over TriggerAddAction() to improve performance.
However, calling TriggerEvaluate() might help to improve it even more than checking if TriggerEvaluate() is true.
Also, GUI triggers cannot be written in conditions and so they must be executed by TriggerExecute() or ConditionalTriggerExecute() which I copied the content from (it's a BJ).
If that is not enough, you might be able to design a structure of a trigger that TriggerEvaluate might do something completely different as TriggerExecute.
Even ConditionalTriggerExecute() might do something different.
So having the execution type, you can choose how the trigger is executed.
What is not clear?
 
Also... you only read 1 line out of 4? If so, you won't understand anything anymore.
If you read the sentence below it, you might understand:
I quoted only 1 line, but of course have read the next lines too. No need to assume I'm an idiot.

A function will be executed. If a function is binded as action/condition to a trigger, then it also will be executed when the trigger is.
A trigger is not only the a code. It is a own complex type. That's why your documentation is confusing.

and if you for example want a damage system and you reduce the damage taken by armor first and then you add damage which you wanted to be added before the armor calculation
No? Why don't make it in same operation thread?
1. Damage
2. Add armor
3. Damage

You are really the last one of who I expected this questio.
That means your comments and demonsration don't have convinced me.

Maybe you remember that one.
Yes, I remember that one. I have not thought of to make a complex system because of it that handles it.
I thought of very simple other solutions.

calling TriggerEvaluate() might help to improve it even more than checking if TriggerEvaluate() is true.
Just as note. In both example the function will be called.

If you have a public function for user then also name it in your description.
If needed, explain paramters.
If user don't need to call certain functions, then don't let them public.

And need of a correct order of trigger execution is anyway a bad sign already. Can be avoided with proper sturcture.

But seriously, this has too much weight for such a system.
I'm sure calling senselessly some conditions is still faster than using the system.
It's not straight forward.

JASS:
hashtable       udg_AEM_Hashtable1              = InitHashtable()
hashtable       udg_AEM_Hashtable2              = InitHashtable()
hashtable       udg_AEM_Hashtable3              = InitHashtable()
Three hashtables seems too much for it.

Your thinking of saving performance is fine. But not in a heavy way like this.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
trigger in itself is far more than executable code. Triggers can have events hooked to them, so trigger's actions and conditions get ran when any of the events hits, but that doesnt make it executable code per se.

I can have trigger that will never execute anything despite having 1000 events, and then I kinda proven you wrong.

Yes Im nitpicking motherfucker :D

You never check if trigger evaulate returned true. Its actually really, really bad idea to even return true from your conditions, because even if the trigger has no actions, it will go and look who to slap next(which function to run), just to be diasppointed that he cant really slap anyone, cause his class(as in school) is empty.

As pointed out, I dont think you will ever need 3 hashtables, doesnt matter the occurance. You can just define 1 hashtable and 2 integers which will work as offset, simulating the second and third hashtable, and if you make them big enough(few million each), you have literally 0 chance to collide when used on parent keys
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
No? Why don't make it in same operation thread?
1. Damage
2. Add armor
3. Damage
Because you want stuff to be separated to make your map readable and you have to control the priority when you register triggers to an event.
If you would write all your spells into that damage system equal as everything else... this would first of all be a horrible idea for readability and I am almost sure that this wont work because of that you will eventually try to call functions that are defined after that.

Yes, I remember that one. I have not thought of to make a complex system because of it that handles it.
I thought of very simple other solutions.


Just as note. In both example the function will be called.
But not the action.

And need of a correct order of trigger execution is anyway a bad sign already. Can be avoided with proper sturcture.
... if you use normal triggers with normal events, you cannot control the order of execution flawlessly.
You would have to recreate triggers over and over again to make sure that they run in specific order.

But seriously, this has too much weight for such a system.
I'm sure calling senselessly some conditions is still faster than using the system.
It's not straight forward.

JASS:
hashtable       udg_AEM_Hashtable1              = InitHashtable()
hashtable       udg_AEM_Hashtable2              = InitHashtable()
hashtable       udg_AEM_Hashtable3              = InitHashtable()
Three hashtables seems too much for it.

Your thinking of saving performance is fine. But not in a heavy way like this.
And so, the hashtables will be replaced by arrays.

trigger in itself is far more than executable code. Triggers can have events hooked to them, so trigger's actions and conditions get ran when any of the events hits, but that doesnt make it executable code per se.

I can have trigger that will never execute anything despite having 1000 events, and then I kinda proven you wrong.
Yea, kinda... except that there is no need to have a trigger if it hasnt got actions or conditions.

You never check if trigger evaulate returned true. Its actually really, really bad idea to even return true from your conditions, because even if the trigger has no actions, it will go and look who to slap next(which function to run), just to be diasppointed that he cant really slap anyone, cause his class(as in school) is empty.
And why should I check if the conditions are true?
I do check it when the execution type is the conditional one which is the same as normal events will execute the trigger.
When you don't care about what the result of the conditions is... why check?

As pointed out, I dont think you will ever need 3 hashtables, doesnt matter the occurance. You can just define 1 hashtable and 2 integers which will work as offset, simulating the second and third hashtable, and if you make them big enough(few million each), you have literally 0 chance to collide when used on parent keys
That should work as well yea.
 
Top