• 🏆 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!

[GUI] Effect Over Time System 2.3.1

This is a system what you might know as a Damage over Time system and Buff system but then with more options.

Description:
This system is an Effect over Time system. Which means that you can give any unit an effect that will occur every (...) seconds for (...) seconds.
You can modify every effect and give it some special things to make it look cool.

How to install:
JASS:
//      1. Copy or create all variables that are used in this map into your map.
//          1a. If you use vJASS then you can enable the EOT_vJASS_variables trigger and use that one.
//          1b. If you use GUI then you can use the EOT_GUI_variables trigger to automatically import them.
//      2. Copy the EOT_System trigger and paste it into your map.
//          2a. (optional) You can also copy the DOT_Extension trigger to make use of damage over time effects.
//      3. Copy all code from the header file and paste it into your map's header file.
//      4. Create some spells with EOTs.
//      5. Enjoy your Effect Over Time Spells.
(More information inside the trigger editor.)

JASS:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Wietlol's Effect Over Time System 2.3.2 17/07/2015
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Description:
//      This system is made to create and add effects that expire over time.
//      Once in a while, which is configurable using the interval variable, the event "EOT_Event_On_Interval" is called.
//      You can define your own actions on the On_Interval event.
//      This system can be used as a buff system and there is an implemented extension for damage over time.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  How to install:
//      1. Copy or create all variables that are used in this map into your map.
//          1a. If you use vJASS then you can enable the EOT_vJASS_variables trigger and use that one.
//          1b. If you use GUI then you can use the EOT_GUI_variables trigger to automatically import them.
//      2. Copy the EOT_System trigger and paste it into your map.
//          2a. (optional) You can also copy the DOT_Extension trigger to make use of damage over time effects.
//      3. Copy all code from the header file and paste it into your map's header file.
//      4. Create some spells with EOTs.
//      5. Enjoy your Effect Over Time Spells.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  How to use:
//      Create an EOT:
//      1. Create a trigger for your spell.
//      2. Make a "Custom script: call EOT_Set_Default_Variables()".
//      3. Set the EOT_Param_Source and EOT_Param_Target to the proper units.
//      4. Set EOT_Param_Type to a variable specific for that type of EOT.
//          For abilities, you can use the id of the ability (which is the same for every casting of that ability).
//          You cannot use the handle id of a unit for example but you can use the unit-type id.
//          When you want subtypes of an EOT, you can put those inside the EOT_Param_Subtype.
//      5. Set additional data for the EOT.
//          5a. Set EOT_Param_Duration and EOT_Param_Interval.
//              If the duration is not specified or is 0 or lower, the duration is infinite.
//              If the interval is not specified or is 0 or lower, the EOT will not have intervals.
//          5b. Set EOT_Param_Buff and EOT_Param_Buff_Holder.
//              If EOT_Param_Buff_Holder is not specified, this EOT will not display a buff.
//              If EOT_Param_Buff_Holder is specified, this EOT will have the buff "EOT_Param_Buff".
//          5c. Set EOT_Param_Special_Effect_Model and EOT_Param_Special_Effect_Point.
//              If EOT_Param_Special_Effect_Model is not specified, this EOT will not have a special effect.
//              If EOT_Param_Special_Effect_Point is not specifid, the attachment point "origin" will be used.
//          5d. Set EOT_Param_Abiliy and EOT_Param_Abiliy_Level.
//              If EOT_Param_Abiliy is not specified or EOT_Param_Abiliy_Level is set to 0 (1 by default), this EOT will not have an ability.
//              Be aware that the ability given is showed in the UI. If you do not want this, add the ability to a disabled spellbook.
//          5e. Set EOT_Param_Positive and EOT_Param_Can_Dispell.
//              These variables are used as buff type variables.
//              EOT_Param_Positive is false by default, meaning that the EOT has a negative attitude.
//              When the EOT_Trigger_Remove_EOTs is called, you can specify if you want to remove positive, negative, both or neither of them.
//              EOT_Param_Can_Dispell is true by default, meaning that the EOT can be dispelled.
//              If it is set to false, the EOT will not dispell unless you set EOT_Param_Force_Destroy to true before the dispell is called.
//          5f. Set EOT_Param_Is_Passive to true if the EOT must not be removed on death.
//              This is usefull for units with passive abilities.
//              You can destroy these EOTs only with EOT_Param_Destroy_Passive.
//      6. Call the EOT_Trigger_Create_EOT trigger.
//      7. Create additional effects.
//          Since you created an EOT, you also have an id.
//          With this id, you can save data in the hashtable using the EOT_Save_Value (Value being the value type) functions.
//      
//      Using the EOT_System's events:
//      1. Create a trigger.
//      2. Create an event of "Game - Value Of Real Variable" and set the variable to the event you want. Leave the value to 0.
//          For spells you can use:
//              - EOT_Event_An_EOT_Is_Created
//              - EOT_Event_An_EOT_Is_Destroyed
//              - EOT_Event_An_EOT_Is_Dispelled
//              - EOT_Event_An_EOT_Has_Expired
//              - EOT_Event_On_Interval
//          All other events are reserved for extensions and systems.
//      3. Now you have the data of your EOT in the Param variables.
//          You can stop the destruction or dispell of an EOT by setting EOT_Param_Destroy to false.
//          You can stop the expiring of an EOT by setting EOT_Param_Expire to false.
//      (For actions on certain EOTs, you can also choose to run a trigger on the interval instead of using the event.
//       this improves performance very much.)
//      
//      Accessing and modifying an EOT's data:
//      1. Set the EOT_Param_Target to the unit that has the EOT.
//      2. Set the EOT_Param_Type to the type of EOT that you want.
//      3. Make an If/Then/Else function.
//          3a. Create a condition of "Boolean Comparison -> Trigger - Evaluate Trigger Conditions".
//              Set the trigger to EOT_Trigger_Get_Data.
//      4. Now you know if the target has the EOT or not.
//          If the target has it, (which means that the condition is right,) the data of the EOT is set in the Param variables.
//      5. Now you can also save the data of the Param variables (which you can change between these two function) by calling
//          the EOT_Trigger_Save_Data trigger.
//      
//      The additional data has some reserved slots. The first 1.000 slots are reserved for extensions or other systems.
//      However when calling the EOT_Save_Value functions, the 1.000 are automatically added.
//      So when making spells, you can start with 0.
//      When making extensions or systems, you have to descend, starting at -1.
//      The extension DOT (Damage Over Time) uses the last 3 of them (-1, -2, -3, aka 999, 998, 997).
//      Extensions/Systems cannot use the same indexes as other extensions/systems.
//      
//      The same counts for the EOT cache.
//      The first 100 cache slot are reserved.
//      The extension DOT (Damage Over Time) does not use an EOT cache.
//      
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Feature list:
//      This system:
//      - allows you to create an effect over time on a unit.
//      - allows you to give a unit a buff as long as the eot lasts.
//      - allows you to give a unit an ability as long as the eot lasts.
//      - allows you to run a piece of code once in a while as long as the eot lasts.
//      - allows you to attach a special effect to an eot.
//      - allows you to change the parameters of the eot.
//      - allows you to get the data, change the data and save the data of every eot that is active.
//      - allows you to create your own extensions to make better use of the system.
//      - allows you to save the data of an eot in the cache. The first 100 are reserved for systems and extensions.
//          This can be used for either presets, already having the references to units, and creation/modification of other eot's inside an eot's function.
//      - allows you to save additional data to an eot.
//          The first 1000 are reserved for systems and extensions.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Variable explaination:
//////////////////////////
//      General:
//      - EOT_Trigger_Create_EOT            - trigger
//          This is the function that creates an eot on a unit.
//          
//      - EOT_Trigger_Destroy_EOT           - trigger
//          This is the function that destroys the specified eot on the targeted unit.
//          
//      - EOT_Trigger_Get_Data              - trigger
//          This is the function that retrieves all the data of the specified eot on the targeted unit.
//          
//      - EOT_Trigger_Save_Data             - trigger
//          This is the function that saves all the variables to the specified eot on the targeted unit.
//          
//      - EOT_Trigger_Remove_EOTs           - trigger
//          This is the function that removes all or filtered eots on the targeted unit.
//          
//      - EOT_Hashtable                     - hashtable
//          This is the hashtable that is used by the Effect Over Time System.
//          
//      - EOT_Index                         - integer
//          This integer is used as an indexing number in loops.
//          
//      - EOT_Amount                        - integer
//          This is the amount of EOTs that are active.
//          
//      - EOT_Unique_Id                     - integer
//          This is a unique number that increases for each EOT.
//          
//      - EOT_Param_Destroy                 - booleam
//          This boolean tells if the EOT must be destroyed.
//          
//      - EOT_Param_Expire                  - boolean
//          This boolean tells if the EOT is expired and if it has to be destroyed.
//          This one is additional to EOT_Destroy because expired EOTs might be able to keep going
//          on certain conditions while destroyed EOTs may not.
//          
//      - EOT_Param_Force_Destroy           - boolean
//          This boolean tells if the destruction of an EOT must go through Can_Dispell values.
//          It can also be used as an additional Destroy variable.
//          
//      - EOT_Param_Destroy_Passive         - boolean
//          This boolean tells if the Destroy function must remove a passive effect.
//          This is the only way to remove the passive effects.
//          
//////////////////////////
//      Events:
//      Events must be called with "Real value becomes equal to 0"
//      - EOT_Event_An_EOT_Is_Created       - real (event simulator)
//          This event is ran when an eot is created.
//          EOT_Event_Creation_Before and EOT_Event_Creation_After are reserved for other systems and extensions.
//          
//      - EOT_Event_An_EOT_Is_Destroyed     - real (event simulator)
//          This event is ran when an eot is destroyed.
//          If an EOT is destroyed in any possible way (expired, dispelled, bugs, etc.) then this event will see it.
//          EOT_Event_Destruction_Before and EOT_Event_Destruction_After are reserved for other systems and extensions.
//          
//      - EOT_Event_An_EOT_Is_Dispelled     - real (event simulator)
//          This event is ran when an eot is dispelled.
//          Dispelling can be done via Remove_EOTs function
//          or on the next interval by having their buff removed. (non-hidden only)
//          EOT_Event_Dispell_Before and EOT_Event_Dispell_After are reserved for other systems and extensions.
//          
//      - EOT_Event_An_EOT_Has_Expired      - real (event simulator)
//          This event is ran when an eot has properly expired.
//          EOT_Event_Expire_Before and EOT_Event_Expire_After are reserved for other systems and extensions.
//          
//      - EOT_Event_On_Interval             - real (event simulator)
//          This event is ran when the interval is activated.
//          EOT_Event_Interval_Before and EOT_Event_Interval_After are reserved for other systems and extensions.
//          
//      - EOT_Event_Get_Data                - real (event simulator)
//          This event is made for extensions to know when a trigger called the "Get Data" function.
//          
//      - EOT_Event_Save_Data               - real (event simulator)
//          This event is made for extensions to know when a trigger called the "Save Data" function.
//          
//      - EOT_Event_Null_Variables          - real (event simulator)
//          This event is made for extensions to know when a trigger called the "Null Variables" function.
//          
//      - EOT_Event_EOT_Changed_Target      - real (event simulator)
//          This event fires when an EOT is changing targets.
//          The target in the array under the index is the old target and the target in the param is the new target.
//          
//////////////////////////
//      Parameters:
//      - EOT_Array_...                     - ... array
//          These variables are the parameters of EOTs saved for each active EOT.
//          
//      - EOT_Param_Id                      - integer
//          This is a unique Id of the EOT.
//          This value can be used to save additional data to an EOT.
//          This is similar to a handle id... but then an EOT id.
//          
//      - EOT_Param_Source                  - unit
//          This is the source of the eot.
//          This unit gets the credit for the kills, or whatever the eot is doing.
//          
//      - EOT_Param_Target                  - unit
//          This is the unit on which the eot runs.
//          
//      - EOT_Param_Duration                - real
//          This is the duration of the eot.
//          Be aware that this is not the remaining duration.
//          
//      - EOT_Param_Remaining_Duration      - real
//          This is the remaining duration of the eot.
//          
//      - EOT_Param_Interval                - real
//          This is the duration between each call of the trigger of the eot.
//          Be aware that this is not the remaining interval.
//          
//      - EOT_Param_Remaining_Interval      - real
//          This is the remaining duration between each call of the trigger of the eot.
//          
//      - EOT_Param_Hidden                  - boolean
//          If the eot is hidden, it will not display a buff.
//          When removing all eots, you can filter out hidden eots.
//          
//      - EOT_Param_Buff                    - buff (integer in JASS)
//          This is the buff that the target has if the eot is not hidden.
//          
//      - EOT_Param_Buff_Holder             - ability (integer in JASS)
//          This is the ability that makes the buff for the target.
//          
//      - EOT_Param_Buff_Holder_Level       - integer
//          This is the level for the ability that makes the buff.
//          This can be used to show different buffs or use an effect that is on that ability.
//          
//      - EOT_Param_Ability                 - ability (integer in JASS)
//          This ability is given to the target and removed when the eot ends.
//          
//      - EOT_Param_Ability_Level           - integer
//          This is the level of the EOT_Param_Ability.
//          
//      - EOT_Param_Positive                - boolean
//          This determines if the effect is positive or negative.
//          This is used to filter out positive or negative effects.
//          This is also used by the Remove_EOTs to know if positive EOTs should be removed.
//          
//      - EOT_Param_Negative                - boolean
//          This is used by the Remove_EOTs to know if negative EOTs should be removed.
//          
//      - EOT_Param_Special_Effect          - special effect (effect in JASS)
//          This is a special effect that is attached to the target.
//          You should not make the effect yourself but rather define the model and attachment point.
//          
//      - EOT_Param_Special_Effect_Model    - string
//          This is the filepath of the model that is used to create the special effect.
//          
//      - EOT_Param_Special_Effect_Point    - string
//          This is the attachment point for the special effect.
//          
//      - EOT_Param_Type                    - integer
//          This variable is a simple integer that can be used as the type of EOT.
//          The easiest way to make this is to set it to an ability id which created the EOT.
//          
//      - EOT_Param_Subtype                 - integer
//          This variable is a simple integer that can be used to give one type multiple subtypes.
//          
//      - EOT_Param_Subtype2                - integer
//          This variable is a simple integer that can be used to give and EOT even better MUI-ness.
//          
//      - EOT_Param_Is_Paused               - integer
//          Paused EOTs will not expire or call the interval.
//          
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Changelog:
//      2.3.1 - 17/07/2015 - Fixed death bug and added OnPeriodTrigger
//          - Fixed a bug where an EOT was not removed when a unit died.
//          - Re-added the option to run a trigger on the periods.
//          - Removed AEM implementation.
//          
//      2.3 - 17/04/2015 - Better Events
//          - Added AEM Events implementation.
//          - Improved Death checks.
//          - Created EOT_Does_Exist().
//          
//      2.2.2 - 25/03/2015 - Ultimate MUI-ness
//          - Added Subtype2 as an additional type. This can be used as sourceid for example to have even better MUI-ness.
//          - Added the event "EOT_Event_EOT_Changed_Target".
//          - Added the paused functionality.
//          
//      2.2.1 - 01/03/2015 - Fixed dead unit crash.
//          - Fixed a bug where the game would crash when a dead unit would gain an EOT.
//          
//      2.2 - 20/02/2015 - Added Is_Passive and fixed a few bugs. 
//          - Changed the variable type of EOT_Type from real to integer.
//              This is because a real has a much lower maximum than an integer.
//              The maximum would be a little bit below the value of ability ids.
//              Subtypes can be declared in the new variable: EOT_Subtype.
//          - Fixed a bug where the Id would be changed to the highest current Id. When an eot would be destroyed.
//          - Added Is_Passive and Destroy_Passive.
//              The Is_Passive is used for passive abilities.
//              They can only be removed using a manual Destroy call while Destroy_Passive is turned on.
//          
//      2.1 - 13/02/2015 - Finished the system. All upcoming updates are fixes.
//          Code:
//          - Replaced redundant code with "EOT_Check_For_New_Target".
//          - Changed the name of "EOT_Null_Variables" to "EOT_Set_Default_Variables" which makes more sense.
//          - Added a disabled trigger with all GUI variables.
//          - Now has a better order of which event/check is called first in the looping action.
//          - Now you don't have to set the hidden parameter in the creation. Just leaving the buff open is enough.
//          - Removed some bugs where ids would be changed.
//          
//      2.0.1 - 10/02/2015 - Fixed event simulators.
//          Code:
//          - The events now run on 0 and are separated to remove non-calling bugs.
//          
//      2.0 - 10/02/2015 - Rewritten the system from timers to arrays.
//          
//          Documentation:
//          - Updated for new functions and variables.
//          Code:
//          - Rewritten the whole code.
//          - Ripped the code into triggers only.
//          - Added hashtable functions in the header.
//          - Added cache functions in the header.
//          - Damage transferred to an extension to remove a lot of empty values in the arrays.
//          Added Features:
//          - Now has a cache where you can save the current EOT in or load a saved EOT from.
//              This can be used as presets or when you want to create a new one during the interval.
//          - Now you can save additional data to an EOT.
//          - Events are now handled better to function with extensions properly and create
//          - You can now leave unnecessary data open. The variables are set to their standard values.
//          - You can now set the level of the buff holder.
//          - Added the Force_Destroy variable which allows you to break through the Can_Dispell value.
//          Bug Fixes:
//          - The EOT is not removed if you set a too high interval.
//          - The Special Effect is now recreated properly if the EOT changed targets, effect-model or attachment point.
//          - The EOT is now removed immediately when the buff is removed.
//          
//      1.2 - 27/01/2015 - Update of simplified system.
//          
//          Documentation:
//          - Added the complete documentation.
//          Code:
//          - Put all code of the system in one trigger with exception of the configuration and made it more readable.
//          - Completed the buff system.
//          Added Features:
//          - Added an ability that is active on the unit as long as the eot exists.
//          - Automatically removes or adds existing eots depending on a configurable, eot-dependant variable.
//          - Now allows the player to change the target of the effect over time.
//          Bug Fixes:
//          - Fixed a bug where an eot which would not last until the next interval would be removed at that moment
//            rather than when the duration expires.
//          
//      1.1 - 20/01/2015 - Update of reworked system.
//          
//          Added Features:
//          - Added the Get_Data and Save_Data functions.
//          Bug Fixes:
//          - Fixed a bug where an eot which was already active on the target would have been removed when the first expired.
//          
//      1.0 - First official release on the Hive.
//          
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  Known bugs:
//      - The buffs of EOTs are aura buffs. This means that they are not dispelled by buff dispell abilities by default.
//          To be able to dispell the buffs you have to trigger all buff dispel abilities.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////





/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  These functions are used by this system only.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Check if the EOT has a new target. If so transfer buff, ability and special effect to the new target.
function EOT_Check_For_New_Target takes integer index returns nothing
    //Check for new target.
    if udg_EOT_Param_Target != udg_EOT_Array_Target[index] then
        //remove and add ability
        call UnitRemoveAbility(udg_EOT_Array_Target[index], udg_EOT_Array_Ability[index])
        if udg_EOT_Param_Ability > 0 and udg_EOT_Param_Ability_Level > 0 then
            call UnitAddAbility(udg_EOT_Param_Target, udg_EOT_Param_Ability)
            call SetUnitAbilityLevel(udg_EOT_Param_Target, udg_EOT_Param_Ability, udg_EOT_Param_Ability_Level)
        endif
        
        //remove and add buff
        call UnitRemoveAbility(udg_EOT_Array_Target[index], udg_EOT_Array_Buff[index])
        if udg_EOT_Param_Buff_Holder > 0 and udg_EOT_Param_Buff_Holder_Level > 0 then
            call UnitAddAbility(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder)
            call SetUnitAbilityLevel(udg_EOT_Param_Target, udg_EOT_Param_Ability, udg_EOT_Param_Buff_Holder_Level)
            call UnitRemoveAbility(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder)
        endif
        
        //remove and add special effect.
        call DestroyEffect(udg_EOT_Param_Special_Effect)
        if udg_EOT_Param_Special_Effect_Model != "" then
            if udg_EOT_Param_Special_Effect_Point == "" then
                set udg_EOT_Param_Special_Effect_Point = "origin"
            endif
            set udg_EOT_Param_Special_Effect = AddSpecialEffectTarget(udg_EOT_Param_Special_Effect_Model, udg_EOT_Param_Target, udg_EOT_Param_Special_Effect_Point)
        endif
    endif
endfunction

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  This code is the actions of this system.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//This is the loop for every 0.03 seconds of gametime.
function EOT_Interval takes nothing returns nothing
    local integer i
    set i = 0
    loop
        set udg_EOT_Index = i
        exitwhen udg_EOT_Index > udg_EOT_Amount
        
        //Set global variables.
        set udg_EOT_Param_Destroy = false
        set udg_EOT_Param_Expire = false
        set udg_EOT_Param_Force_Destroy = false
        set udg_EOT_Param_Id                    = udg_EOT_Array_Id[udg_EOT_Index]
        set udg_EOT_Param_Source                = udg_EOT_Array_Source[udg_EOT_Index]
        set udg_EOT_Param_Target                = udg_EOT_Array_Target[udg_EOT_Index]
        set udg_EOT_Param_Duration              = udg_EOT_Array_Duration[udg_EOT_Index]
        set udg_EOT_Param_Remaining_Duration    = udg_EOT_Array_Remaining_Duration[udg_EOT_Index]
        set udg_EOT_Param_Interval              = udg_EOT_Array_Interval[udg_EOT_Index]
        set udg_EOT_Param_Remaining_Interval    = udg_EOT_Array_Remaining_Interval[udg_EOT_Index]
        set udg_EOT_Param_Hidden                = udg_EOT_Array_Hidden[udg_EOT_Index]
        set udg_EOT_Param_Buff                  = udg_EOT_Array_Buff[udg_EOT_Index]
        set udg_EOT_Param_Buff_Holder           = udg_EOT_Array_Buff_Holder[udg_EOT_Index]
        set udg_EOT_Param_Buff_Holder_Level     = udg_EOT_Array_Buff_Holder_Level[udg_EOT_Index]
        set udg_EOT_Param_Ability               = udg_EOT_Array_Ability[udg_EOT_Index]
        set udg_EOT_Param_Ability_Level         = udg_EOT_Array_Ability_Level[udg_EOT_Index]
        set udg_EOT_Param_Type                  = udg_EOT_Array_Type[udg_EOT_Index]
        set udg_EOT_Param_Subtype               = udg_EOT_Array_Subtype[udg_EOT_Index]
        set udg_EOT_Param_Positive              = udg_EOT_Array_Positive[udg_EOT_Index]
        set udg_EOT_Param_Can_Dispell           = udg_EOT_Array_Can_Dispell[udg_EOT_Index]
        set udg_EOT_Param_Is_Passive            = udg_EOT_Array_Is_Passive[udg_EOT_Index]
        set udg_EOT_Param_Special_Effect        = udg_EOT_Array_Special_Effect[udg_EOT_Index]
        set udg_EOT_Param_Special_Effect_Model  = udg_EOT_Array_Special_Effect_Model[udg_EOT_Index]
        set udg_EOT_Param_Special_Effect_Point  = udg_EOT_Array_Special_Effect_Point[udg_EOT_Index]
        
        //Decrease remaining duration.
        set udg_EOT_Param_Remaining_Duration = udg_EOT_Param_Remaining_Duration - 0.03
        
        if IsUnitType(udg_EOT_Param_Target, UNIT_TYPE_DEAD) and GetUnitTypeId(udg_EOT_Param_Target) != 0 and udg_EOT_Param_Is_Passive then
            if udg_EOT_Param_Remaining_Duration <= 0. and udg_EOT_Param_Remaining_Duration > -1 then
                set udg_EOT_Param_Expire = true
                
                //Call the expire event.
                set udg_EOT_Event_Expire_Before = 1 //<<< don't use
                set udg_EOT_Event_Expire_Before = 0 //<<< use this
                set udg_EOT_Event_An_EOT_Has_Expired = 1 //<<< don't use
                set udg_EOT_Event_An_EOT_Has_Expired = 0 //<<< use this
                set udg_EOT_Event_Expire_After = 1 //<<< don't use
                set udg_EOT_Event_Expire_After = 0 //<<< use this
                
                call EOT_Check_For_New_Target(i)
            endif
        else
            set udg_EOT_Param_Remaining_Interval = udg_EOT_Param_Remaining_Interval - 0.03
            
            if GetUnitTypeId(udg_EOT_Param_Target) == 0 or (GetUnitAbilityLevel(udg_EOT_Param_Target, udg_EOT_Param_Buff) == 0 and not(udg_EOT_Param_Hidden)) or IsUnitType(udg_EOT_Param_Target, UNIT_TYPE_DEAD) then
                if GetUnitTypeId(udg_EOT_Param_Target) == 0 or IsUnitType(udg_EOT_Param_Target, UNIT_TYPE_DEAD) then
                    set udg_EOT_Param_Destroy_Passive = true
                    set udg_EOT_Param_Destroy = true
                    
                elseif not udg_EOT_Param_Can_Dispell  then
                    //This eot may not be dispelled.
                    call UnitAddAbility(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder)
                    //call SetUnitAbilityLevel(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder, udg_EOT_Param_Buff_Holder_Level) << removed because of bug with auras.
                    call UnitRemoveAbility(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder)
                else
                    set udg_EOT_Param_Destroy = true
                    
                    //Call the dispell event.
                    set udg_EOT_Event_Dispell_Before = 1 //<<< don't use
                    set udg_EOT_Event_Dispell_Before = 0 //<<< use this
                    set udg_EOT_Event_An_EOT_Is_Dispelled = 1 //<<< don't use
                    set udg_EOT_Event_An_EOT_Is_Dispelled = 0 //<<< use this
                    set udg_EOT_Event_Dispell_After = 1 //<<< don't use
                    set udg_EOT_Event_Dispell_After = 0 //<<< use this
                endif
                call EOT_Check_For_New_Target(i)
            endif
            
            if not(udg_EOT_Param_Destroy) then
                if udg_EOT_Param_Remaining_Interval <= 0. and udg_EOT_Param_Remaining_Interval > -1. and (udg_EOT_Param_Remaining_Interval <= udg_EOT_Param_Remaining_Duration or udg_EOT_Param_Duration == -1.) then
                    set udg_EOT_Param_Remaining_Interval = udg_EOT_Param_Remaining_Interval + udg_EOT_Param_Interval
                    
                    
                    set udg_EOT_Event_Interval_Before = 1 //<<< don't use
                    set udg_EOT_Event_Interval_Before = 0 //<<< use this
                    set udg_EOT_Event_On_Interval = 1 //<<< don't use
                    set udg_EOT_Event_On_Interval = 0 //<<< use this
                    set udg_EOT_Event_Interval_After = 1 //<<< don't use
                    set udg_EOT_Event_Interval_After = 0 //<<< use this
                    
                    //Check for new target.
                    call EOT_Check_For_New_Target(i)
                endif
            endif
        
            if not(udg_EOT_Param_Destroy) then
                //Check if EOT has expired.
                if udg_EOT_Param_Remaining_Duration <= 0. and udg_EOT_Param_Remaining_Duration > -1. then
                    set udg_EOT_Param_Expire = true
                    
                    //Call the expire event.
                    set udg_EOT_Event_Expire_Before = 1 //<<< don't use
                    set udg_EOT_Event_Expire_Before = 0 //<<< use this
                    set udg_EOT_Event_An_EOT_Has_Expired = 1 //<<< don't use
                    set udg_EOT_Event_An_EOT_Has_Expired = 0 //<<< use this
                    set udg_EOT_Event_Expire_After = 1 //<<< don't use
                    set udg_EOT_Event_Expire_After = 0 //<<< use this
                    
                    call EOT_Check_For_New_Target(i)
                endif
            endif
            
            //Update ability level.
            if udg_EOT_Param_Ability > 0 then
                call SetUnitAbilityLevel(udg_EOT_Param_Target, udg_EOT_Param_Ability, udg_EOT_Param_Ability_Level)
            endif
            
            //Update buff.
            if not(udg_EOT_Param_Hidden) then
                call UnitAddAbility(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder)
                //call SetUnitAbilityLevel(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder, udg_EOT_Param_Buff_Holder_Level) << removed because of bug with auras.
                call UnitRemoveAbility(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder)
            endif
        endif
        
        //Update new values.
        set udg_EOT_Array_Source[i]               = udg_EOT_Param_Source
        set udg_EOT_Array_Target[i]               = udg_EOT_Param_Target
        set udg_EOT_Array_Duration[i]             = udg_EOT_Param_Duration
        set udg_EOT_Array_Remaining_Duration[i]   = udg_EOT_Param_Remaining_Duration
        set udg_EOT_Array_Interval[i]             = udg_EOT_Param_Interval
        set udg_EOT_Array_Remaining_Interval[i]   = udg_EOT_Param_Remaining_Interval
        set udg_EOT_Array_Hidden[i]               = udg_EOT_Param_Hidden
        set udg_EOT_Array_Buff[i]                 = udg_EOT_Param_Buff
        set udg_EOT_Array_Buff_Holder[i]          = udg_EOT_Param_Buff_Holder
        set udg_EOT_Array_Buff_Holder_Level[i]    = udg_EOT_Param_Buff_Holder_Level
        set udg_EOT_Array_Ability[i]              = udg_EOT_Param_Ability
        set udg_EOT_Array_Ability_Level[i]        = udg_EOT_Param_Ability_Level
        set udg_EOT_Array_Type[i]                 = udg_EOT_Param_Type
        set udg_EOT_Array_Subtype[i]              = udg_EOT_Param_Subtype
        set udg_EOT_Array_Positive[i]             = udg_EOT_Param_Positive
        set udg_EOT_Array_Can_Dispell[i]          = udg_EOT_Param_Can_Dispell
        set udg_EOT_Array_Is_Passive[i]           = udg_EOT_Param_Is_Passive
        set udg_EOT_Array_Special_Effect[i]       = udg_EOT_Param_Special_Effect
        set udg_EOT_Array_Special_Effect_Model[i] = udg_EOT_Param_Special_Effect_Model
        set udg_EOT_Array_Special_Effect_Point[i] = udg_EOT_Param_Special_Effect_Point
        
        //Destroy.
        if udg_EOT_Param_Destroy or udg_EOT_Param_Expire or udg_EOT_Param_Force_Destroy then
            call TriggerExecute(udg_EOT_Trigger_Destroy_EOT)
            set i = i - 1
        endif
        
        //Next EOT.
        set i = i + 1
    endloop
    call EOT_Set_Default_Variables()
endfunction

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  This code is the functions that this system has.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//This function checks if the EOT exists.
function EOT_Does_Exist takes nothing returns boolean
    set udg_EOT_Index = 0
    loop
        exitwhen udg_EOT_Index > udg_EOT_Amount
        if udg_EOT_Param_Target == udg_EOT_Array_Target[udg_EOT_Index] and udg_EOT_Param_Type == udg_EOT_Array_Type[udg_EOT_Index] and udg_EOT_Param_Subtype == udg_EOT_Array_Subtype[udg_EOT_Index] then
            return true
        endif
        set udg_EOT_Index = udg_EOT_Index + 1
    endloop
    
    return false
endfunction

//This function creates a new EOT.
function EOT_Create_EOT takes nothing returns nothing
    //Requires:
    //  - udg_EOT_Param_Source                  : unit
    //  - udg_EOT_Param_Target                  : unit
    //  - udg_EOT_Param_Type                    : integer
    //Optional:
    //  - udg_EOT_Param_Subtype                 : integer
    //  - udg_EOT_Param_Duration                : real
    //  - udg_EOT_Param_Interval                : real
    //  - udg_EOT_Param_Buff                    : integer (buff)
    //  - udg_EOT_Param_Buff_Holder             : integer (ability)
    //  - udg_EOT_Param_Buff_Holder_Level       : integer
    //  - udg_EOT_Param_Ability                 : integer (ability)
    //  - udg_EOT_Param_Ability_Level           : integer
    //  - udg_EOT_Param_Positive                : boolean
    //  - udg_EOT_Param_Can_Dispell             : boolean
    //  - udg_EOT_Param_Is_Passive              : boolean
    //  - udg_EOT_Param_Special_Effect_Model    : string
    //  - udg_EOT_Param_Special_Effect_Point    : string
    
    //If target is dead then don't do SHIT!
    if IsUnitType(udg_EOT_Param_Target, UNIT_TYPE_DEAD) and GetUnitTypeId(udg_EOT_Param_Target) != 0 then
        return
    endif
    
    //If the duration is 0 or lower then dset the duration to -1 (infinite).
    if udg_EOT_Param_Duration <= 0. then
        set udg_EOT_Param_Duration = -1.
    endif
    
    //Update the old EOT if that one existed.
    if EOT_Does_Exist() then
        set udg_EOT_Param_Remaining_Duration = udg_EOT_Param_Duration
        call TriggerExecute(udg_EOT_Trigger_Save_Data)
        return
    endif
    
    //Add the buff if applyable.
    if udg_EOT_Param_Buff_Holder > 0 and udg_EOT_Param_Buff_Holder_Level > 0 then
        set udg_EOT_Param_Hidden = false
        call UnitAddAbility(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder)
        //call SetUnitAbilityLevel(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder, udg_EOT_Param_Buff_Holder_Level) << removed because of bug with auras.
        call UnitRemoveAbility(udg_EOT_Param_Target, udg_EOT_Param_Buff_Holder)
    else
        set udg_EOT_Param_Hidden = true
    endif
    
    //Add the ability if applyable.
    if udg_EOT_Param_Ability > 0 and udg_EOT_Param_Ability_Level > 0 then
        call UnitAddAbility(udg_EOT_Param_Target, udg_EOT_Param_Ability)
        call SetUnitAbilityLevel(udg_EOT_Param_Target, udg_EOT_Param_Ability, udg_EOT_Param_Ability_Level)
    endif
    
    //Make a special effect.
    if udg_EOT_Param_Special_Effect_Model != "" then
        if udg_EOT_Param_Special_Effect_Point == "" or udg_EOT_Param_Special_Effect_Point == null then
            set udg_EOT_Param_Special_Effect_Point = "origin"
        endif
        set udg_EOT_Param_Special_Effect = AddSpecialEffectTarget(udg_EOT_Param_Special_Effect_Model, udg_EOT_Param_Target, udg_EOT_Param_Special_Effect_Point)
    endif
    
    set udg_EOT_Param_Remaining_Duration = udg_EOT_Param_Duration
    set udg_EOT_Param_Remaining_Interval = udg_EOT_Param_Interval
    
    set udg_EOT_Amount = udg_EOT_Amount + 1
    set udg_EOT_Unique_Id = udg_EOT_Unique_Id + 1
    set udg_EOT_Param_Id = udg_EOT_Unique_Id
    call SaveInteger(udg_EOT_Hashtable, udg_EOT_Param_Id, 0, udg_EOT_Amount)
    
    //Call the event.
    set udg_EOT_Event_Creation_Before = 1 //<<< don't use
    set udg_EOT_Event_Creation_Before = 0 //<<< use this
    set udg_EOT_Event_An_EOT_Is_Created = 1 //<<< don't use
    set udg_EOT_Event_An_EOT_Is_Created = 0 //<<< use this
    set udg_EOT_Event_Creation_After = 1 //<<< don't use
    set udg_EOT_Event_Creation_After = 0 //<<< use this
    
    set udg_EOT_Array_Id[udg_EOT_Amount]                        = udg_EOT_Param_Id
    set udg_EOT_Array_Source[udg_EOT_Amount]                    = udg_EOT_Param_Source
    set udg_EOT_Array_Target[udg_EOT_Amount]                    = udg_EOT_Param_Target
    set udg_EOT_Array_Duration[udg_EOT_Amount]                  = udg_EOT_Param_Duration
    set udg_EOT_Array_Remaining_Duration[udg_EOT_Amount]        = udg_EOT_Param_Remaining_Duration
    set udg_EOT_Array_Interval[udg_EOT_Amount]                  = udg_EOT_Param_Interval
    set udg_EOT_Array_Remaining_Interval[udg_EOT_Amount]        = udg_EOT_Param_Remaining_Interval
    set udg_EOT_Array_Hidden[udg_EOT_Amount]                    = udg_EOT_Param_Hidden
    set udg_EOT_Array_Buff[udg_EOT_Amount]                      = udg_EOT_Param_Buff
    set udg_EOT_Array_Buff_Holder[udg_EOT_Amount]               = udg_EOT_Param_Buff_Holder
    set udg_EOT_Array_Buff_Holder_Level[udg_EOT_Amount]         = udg_EOT_Param_Buff_Holder_Level
    set udg_EOT_Array_Ability[udg_EOT_Amount]                   = udg_EOT_Param_Ability
    set udg_EOT_Array_Ability_Level[udg_EOT_Amount]             = udg_EOT_Param_Ability_Level
    set udg_EOT_Array_Type[udg_EOT_Amount]                      = udg_EOT_Param_Type
    set udg_EOT_Array_Subtype[udg_EOT_Amount]                   = udg_EOT_Param_Subtype
    set udg_EOT_Array_Positive[udg_EOT_Amount]                  = udg_EOT_Param_Positive
    set udg_EOT_Array_Can_Dispell[udg_EOT_Amount]               = udg_EOT_Param_Can_Dispell
    set udg_EOT_Array_Is_Passive[udg_EOT_Amount]                = udg_EOT_Param_Is_Passive
    set udg_EOT_Array_Special_Effect[udg_EOT_Amount]            = udg_EOT_Param_Special_Effect
    set udg_EOT_Array_Special_Effect_Model[udg_EOT_Amount]      = udg_EOT_Param_Special_Effect_Model
    set udg_EOT_Array_Special_Effect_Point[udg_EOT_Amount]      = udg_EOT_Param_Special_Effect_Point
    
    //Start the timer if this is the only EOT.
    if udg_EOT_Amount == 0 then
        call TimerStart(udg_EOT_Timer, 0.03, true, function EOT_Interval)
    endif
    return
endfunction

//This function destroys an EOT.
function EOT_Destroy_EOT takes nothing returns boolean
    //Requires:
    //  - udg_EOT_Index : integer
    
    set udg_EOT_Param_Destroy = true
    
    //Call the destroy event.
    set udg_EOT_Event_Destruction_Before = 1 //<<< don't use
    set udg_EOT_Event_Destruction_Before = 0 //<<< use this
    set udg_EOT_Event_An_EOT_Is_Destroyed = 1 //<<< don't use
    set udg_EOT_Event_An_EOT_Is_Destroyed = 0 //<<< use this
    set udg_EOT_Event_Destruction_After = 1 //<<< don't use
    set udg_EOT_Event_Destruction_After = 0 //<<< use this
    
    //Destroy the EOT.
    if not(udg_EOT_Param_Is_Passive) or udg_EOT_Param_Destroy_Passive then
        if udg_EOT_Param_Destroy or udg_EOT_Param_Force_Destroy then
            call DestroyEffect(udg_EOT_Array_Special_Effect[udg_EOT_Index])
            call UnitRemoveAbility(udg_EOT_Array_Target[udg_EOT_Index], udg_EOT_Array_Buff_Holder[udg_EOT_Index])
            call UnitRemoveAbility(udg_EOT_Array_Target[udg_EOT_Index], udg_EOT_Array_Buff[udg_EOT_Index])
            call UnitRemoveAbility(udg_EOT_Array_Target[udg_EOT_Index], udg_EOT_Array_Ability[udg_EOT_Index])
            
            call FlushChildHashtable(udg_EOT_Hashtable, udg_EOT_Array_Id[udg_EOT_Index])
            set udg_EOT_Array_Id[udg_EOT_Index]                     = udg_EOT_Array_Id[udg_EOT_Amount]
            call SaveInteger(udg_EOT_Hashtable, udg_EOT_Array_Id[udg_EOT_Index], 0, udg_EOT_Index)
            set udg_EOT_Array_Source[udg_EOT_Index]                 = udg_EOT_Array_Source[udg_EOT_Amount]
            set udg_EOT_Array_Target[udg_EOT_Index]                 = udg_EOT_Array_Target[udg_EOT_Amount]
            set udg_EOT_Array_Duration[udg_EOT_Index]               = udg_EOT_Array_Duration[udg_EOT_Amount]
            set udg_EOT_Array_Remaining_Duration[udg_EOT_Index]     = udg_EOT_Array_Remaining_Duration[udg_EOT_Amount]
            set udg_EOT_Array_Interval[udg_EOT_Index]               = udg_EOT_Array_Interval[udg_EOT_Amount]
            set udg_EOT_Array_Remaining_Interval[udg_EOT_Index]     = udg_EOT_Array_Remaining_Interval[udg_EOT_Amount]
            set udg_EOT_Array_Hidden[udg_EOT_Index]                 = udg_EOT_Array_Hidden[udg_EOT_Amount]
            set udg_EOT_Array_Buff[udg_EOT_Index]                   = udg_EOT_Array_Buff[udg_EOT_Amount]
            set udg_EOT_Array_Buff_Holder[udg_EOT_Index]            = udg_EOT_Array_Buff_Holder[udg_EOT_Amount]
            set udg_EOT_Array_Buff_Holder_Level[udg_EOT_Index]      = udg_EOT_Array_Buff_Holder_Level[udg_EOT_Amount]
            set udg_EOT_Array_Ability[udg_EOT_Index]                = udg_EOT_Array_Ability[udg_EOT_Amount]
            set udg_EOT_Array_Ability_Level[udg_EOT_Index]          = udg_EOT_Array_Ability_Level[udg_EOT_Amount]
            set udg_EOT_Array_Type[udg_EOT_Index]                   = udg_EOT_Array_Type[udg_EOT_Amount]
            set udg_EOT_Array_Subtype[udg_EOT_Index]                = udg_EOT_Array_Subtype[udg_EOT_Amount]
            set udg_EOT_Array_Positive[udg_EOT_Index]               = udg_EOT_Array_Positive[udg_EOT_Amount]
            set udg_EOT_Array_Can_Dispell[udg_EOT_Index]            = udg_EOT_Array_Can_Dispell[udg_EOT_Amount]
            set udg_EOT_Array_Is_Passive[udg_EOT_Index]             = udg_EOT_Array_Is_Passive[udg_EOT_Amount]
            set udg_EOT_Array_Special_Effect[udg_EOT_Index]         = udg_EOT_Array_Special_Effect[udg_EOT_Amount]
            set udg_EOT_Array_Special_Effect_Model[udg_EOT_Index]   = udg_EOT_Array_Special_Effect_Model[udg_EOT_Amount]
            set udg_EOT_Array_Special_Effect_Point[udg_EOT_Index]   = udg_EOT_Array_Special_Effect_Point[udg_EOT_Amount]
            set udg_EOT_Array_Id[udg_EOT_Amount]                    = 0
            set udg_EOT_Array_Source[udg_EOT_Amount]                = null
            set udg_EOT_Array_Target[udg_EOT_Amount]                = null
            set udg_EOT_Array_Duration[udg_EOT_Amount]              = 0.
            set udg_EOT_Array_Remaining_Duration[udg_EOT_Amount]    = 0.
            set udg_EOT_Array_Interval[udg_EOT_Amount]              = 0.
            set udg_EOT_Array_Remaining_Interval[udg_EOT_Amount]    = 0.
            set udg_EOT_Array_Hidden[udg_EOT_Amount]                = false
            set udg_EOT_Array_Buff[udg_EOT_Amount]                  = 0
            set udg_EOT_Array_Buff_Holder[udg_EOT_Amount]           = 0
            set udg_EOT_Array_Buff_Holder_Level[udg_EOT_Amount]     = 0
            set udg_EOT_Array_Ability[udg_EOT_Amount]               = 0
            set udg_EOT_Array_Ability_Level[udg_EOT_Amount]         = 0
            set udg_EOT_Array_Type[udg_EOT_Amount]                  = 0
            set udg_EOT_Array_Subtype[udg_EOT_Amount]               = 0
            set udg_EOT_Array_Positive[udg_EOT_Amount]              = false
            set udg_EOT_Array_Can_Dispell[udg_EOT_Amount]           = false
            set udg_EOT_Array_Is_Passive[udg_EOT_Amount]            = false
            set udg_EOT_Array_Special_Effect[udg_EOT_Amount]        = null
            set udg_EOT_Array_Special_Effect_Model[udg_EOT_Amount]  = ""
            set udg_EOT_Array_Special_Effect_Point[udg_EOT_Amount]  = ""
            set udg_EOT_Amount = udg_EOT_Amount - 1
            
            if udg_EOT_Amount < 0 then
                call PauseTimer(udg_EOT_Timer)
            endif
            
            set udg_EOT_Param_Destroy = false
            set udg_EOT_Param_Force_Destroy = false
            set udg_EOT_Param_Destroy_Passive = false
            return true
        endif
    endif
    
    set udg_EOT_Param_Destroy = false
	set udg_EOT_Param_Force_Destroy = false
    set udg_EOT_Param_Destroy_Passive = false
    return false
endfunction

//This function retrieves the data of an EOT and set the Param variables to that data.
function EOT_Get_Data takes nothing returns boolean
    //Requires:
    //  - udg_EOT_Param_Target  : unit
    //  - udg_EOT_Param_Type    : integer
    //  - udg_EOT_Param_Subtype : integer
    
    set udg_EOT_Index = 0
    loop
        exitwhen udg_EOT_Index > udg_EOT_Amount
        if udg_EOT_Param_Target == udg_EOT_Array_Target[udg_EOT_Index] and udg_EOT_Param_Type == udg_EOT_Array_Type[udg_EOT_Index] and udg_EOT_Param_Subtype == udg_EOT_Array_Subtype[udg_EOT_Index] then
            set udg_EOT_Param_Id                    = udg_EOT_Array_Id[udg_EOT_Index]
            set udg_EOT_Param_Source                = udg_EOT_Array_Source[udg_EOT_Index]
            set udg_EOT_Param_Duration              = udg_EOT_Array_Duration[udg_EOT_Index]
            set udg_EOT_Param_Remaining_Duration    = udg_EOT_Array_Remaining_Duration[udg_EOT_Index]
            set udg_EOT_Param_Interval              = udg_EOT_Array_Interval[udg_EOT_Index]
            set udg_EOT_Param_Remaining_Interval    = udg_EOT_Array_Remaining_Interval[udg_EOT_Index]
            set udg_EOT_Param_Hidden                = udg_EOT_Array_Hidden[udg_EOT_Index]
            set udg_EOT_Param_Buff                  = udg_EOT_Array_Buff[udg_EOT_Index]
            set udg_EOT_Param_Buff_Holder           = udg_EOT_Array_Buff_Holder[udg_EOT_Index]
            set udg_EOT_Param_Buff_Holder_Level     = udg_EOT_Array_Buff_Holder_Level[udg_EOT_Index]
            set udg_EOT_Param_Ability               = udg_EOT_Array_Ability[udg_EOT_Index]
            set udg_EOT_Param_Ability_Level         = udg_EOT_Array_Ability_Level[udg_EOT_Index]
            set udg_EOT_Param_Positive              = udg_EOT_Array_Positive[udg_EOT_Index]
            set udg_EOT_Param_Can_Dispell           = udg_EOT_Array_Can_Dispell[udg_EOT_Index]
            set udg_EOT_Param_Is_Passive            = udg_EOT_Array_Is_Passive[udg_EOT_Index]
            set udg_EOT_Param_Special_Effect        = udg_EOT_Array_Special_Effect[udg_EOT_Index]
            set udg_EOT_Param_Special_Effect_Model  = udg_EOT_Array_Special_Effect_Model[udg_EOT_Index]
            set udg_EOT_Param_Special_Effect_Point  = udg_EOT_Array_Special_Effect_Point[udg_EOT_Index]
            
            set udg_EOT_Event_Get_Data = 1 //<<< don't use
            set udg_EOT_Event_Get_Data = 0 //<<< use this
            
            return true
        endif
        set udg_EOT_Index = udg_EOT_Index + 1
    endloop
    
    return false
endfunction

//This function saves the data stored in the Param variables to the EOT.
function EOT_Save_Data takes nothing returns nothing
    //Requires:
    //  - udg_EOT_Param_Id  : integer
    
    //If target is dead then don't do SHIT!
    if IsUnitType(udg_EOT_Param_Target, UNIT_TYPE_DEAD) and GetUnitTypeId(udg_EOT_Param_Target) != 0 then
        return
    endif
    
    set udg_EOT_Index = LoadInteger(udg_EOT_Hashtable, udg_EOT_Param_Id, 0)
	
    //Check for new target.
    call EOT_Check_For_New_Target(udg_EOT_Index)
    
    set udg_EOT_Array_Source[udg_EOT_Index]                 = udg_EOT_Param_Source
    set udg_EOT_Array_Duration[udg_EOT_Index]               = udg_EOT_Param_Duration
    set udg_EOT_Array_Remaining_Duration[udg_EOT_Index]     = udg_EOT_Param_Remaining_Duration
    set udg_EOT_Array_Interval[udg_EOT_Index]               = udg_EOT_Param_Interval
    set udg_EOT_Array_Remaining_Interval[udg_EOT_Index]     = udg_EOT_Param_Remaining_Interval
    set udg_EOT_Array_Hidden[udg_EOT_Index]                 = udg_EOT_Param_Hidden
    set udg_EOT_Array_Buff[udg_EOT_Index]                   = udg_EOT_Param_Buff
    set udg_EOT_Array_Buff_Holder[udg_EOT_Index]            = udg_EOT_Param_Buff_Holder
    set udg_EOT_Array_Buff_Holder_Level[udg_EOT_Index]      = udg_EOT_Param_Buff_Holder_Level
    set udg_EOT_Array_Ability[udg_EOT_Index]                = udg_EOT_Param_Ability
    set udg_EOT_Array_Ability_Level[udg_EOT_Index]          = udg_EOT_Param_Ability_Level
    set udg_EOT_Array_Type[udg_EOT_Index]                   = udg_EOT_Param_Type
    set udg_EOT_Array_Subtype[udg_EOT_Index]                = udg_EOT_Param_Subtype
    set udg_EOT_Array_Positive[udg_EOT_Index]               = udg_EOT_Param_Positive
    set udg_EOT_Array_Can_Dispell[udg_EOT_Index]            = udg_EOT_Param_Can_Dispell
    set udg_EOT_Array_Is_Passive[udg_EOT_Index]             = udg_EOT_Param_Is_Passive
    set udg_EOT_Array_Special_Effect[udg_EOT_Index]         = udg_EOT_Param_Special_Effect
    set udg_EOT_Array_Special_Effect_Model[udg_EOT_Index]   = udg_EOT_Param_Special_Effect_Model
    set udg_EOT_Array_Special_Effect_Point[udg_EOT_Index]   = udg_EOT_Param_Special_Effect_Point
    
    set udg_EOT_Event_Save_Data = 1 //<<< don't use
    set udg_EOT_Event_Save_Data = 0 //<<< use this
endfunction

//This function removes EOTs that are filtered by the Hidden, Positive and Negative variables.
function EOT_Remove_EOTs takes nothing returns nothing
    //Requires:
    //  - udg_EOT_Param_Target          : unit
    //  - udg_EOT_Param_Hidden          : boolean
    //  - udg_EOT_Param_Positive        : boolean
    //  - udg_EOT_Param_Negative        : boolean
    //Optional:
    //  - udg_EOT_Param_Force_Destroy   : boolean
    
    local unit target = udg_EOT_Param_Target
    local boolean hidden = udg_EOT_Param_Hidden
    local boolean positive = udg_EOT_Param_Positive
    local boolean negative = udg_EOT_Param_Negative
    local integer i = 0
    
    loop
        exitwhen i > udg_EOT_Amount
        
        set udg_EOT_Param_Target = target
        set udg_EOT_Param_Ability = udg_EOT_Array_Ability[i]
        if TriggerEvaluate(udg_EOT_Trigger_Get_Data) then
            if not(udg_EOT_Param_Is_Passive) and (udg_EOT_Param_Can_Dispell or udg_EOT_Param_Force_Destroy) then
                if udg_EOT_Param_Hidden == hidden then
                    if (udg_EOT_Param_Positive and positive) or (not(udg_EOT_Param_Positive) and negative) then
                        
                        //Call the dispell event.
                        set udg_EOT_Event_Dispell_Before = 1 //<<< don't use
                        set udg_EOT_Event_Dispell_Before = 0 //<<< use this
                        set udg_EOT_Event_An_EOT_Is_Dispelled = 1 //<<< don't use
                        set udg_EOT_Event_An_EOT_Is_Dispelled = 0 //<<< use this
                        set udg_EOT_Event_Dispell_After = 1 //<<< don't use
                        set udg_EOT_Event_Dispell_After = 0 //<<< use this
                        call TriggerExecute(udg_EOT_Trigger_Destroy_EOT)
                        set i = i - 1
                    endif
                endif
            endif
        endif
        
        set i = i + 1
    endloop
    
    set udg_EOT_Param_Force_Destroy = false
    set target = null
endfunction

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  This code is the initialization of the system and it's functions.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//This is the initial function.
function InitTrig_EOT_System takes nothing returns nothing
    //Create the global variables.
    set udg_EOT_Hashtable = InitHashtable()
    set udg_EOT_Amount = -1
    set udg_EOT_Unique_Id = -1
    call EOT_Set_Default_Variables()
    
    //Create the interval timer.
    set udg_EOT_Timer = CreateTimer()
    
    //Create the "Create_EOT" function.
    //This function does not have to return a boolean.
    set udg_EOT_Trigger_Create_EOT = CreateTrigger()
    call TriggerAddAction(udg_EOT_Trigger_Create_EOT, function EOT_Create_EOT)
    
    //Create the "Destroy_EOT" function.
    //Returns true if destroyed and false if the EOT cannot be found.
    set udg_EOT_Trigger_Destroy_EOT = CreateTrigger()
    call TriggerAddCondition(udg_EOT_Trigger_Destroy_EOT, Filter(function EOT_Destroy_EOT))
    call TriggerAddAction(udg_EOT_Trigger_Destroy_EOT, function EOT_Destroy_EOT)
    
    //Create the "Get_Data" function.
    set udg_EOT_Trigger_Get_Data = CreateTrigger()
    call TriggerAddCondition(udg_EOT_Trigger_Get_Data, Filter(function EOT_Get_Data))
    call TriggerAddAction(udg_EOT_Trigger_Get_Data, function EOT_Get_Data)
    
	//Create the "Save_Data" function.
    //This function does not have to return a boolean.
    set udg_EOT_Trigger_Save_Data = CreateTrigger()
    call TriggerAddAction(udg_EOT_Trigger_Save_Data, function EOT_Save_Data)
    
    //Create the "Remove_EOTs" function.
    //This function does not have to return a boolean.
    set udg_EOT_Trigger_Remove_EOTs = CreateTrigger()
    call TriggerAddAction(udg_EOT_Trigger_Remove_EOTs, function EOT_Remove_EOTs)
endfunction


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  EOT System end
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
JASS:
function DOT_Deal_Damage takes nothing returns boolean
    if udg_DOT_Damage <= 0. then
        return false
    endif
    
    call UnitDamageTarget(udg_EOT_Param_Source, udg_EOT_Param_Target, udg_DOT_Damage, true, false, udg_DOT_Attack_Type, udg_DOT_Damage_Type, WEAPON_TYPE_WHOKNOWS)
    
    return false
endfunction

function DOT_Save_Data takes nothing returns boolean
    if udg_DOT_Damage <= 0. then
        return false
    endif
    
    call EOT_Save_Real(-1, udg_DOT_Damage)
    call EOT_Save_Integer(-2, ConvertAttackTypeReverse(udg_DOT_Attack_Type))
    call EOT_Save_Integer(-3, ConvertDamageTypeReverse(udg_DOT_Damage_Type))
    
    return false
endfunction

function DOT_Get_Data takes nothing returns boolean
    
    set udg_DOT_Damage = EOT_Load_Real(-1)
    set udg_DOT_Attack_Type = ConvertAttackType(EOT_Load_Integer(-2))
    set udg_DOT_Damage_Type = ConvertDamageType(EOT_Load_Integer(-3))
    
    return false
endfunction

function DOT_Reset_Data takes nothing returns boolean
    
    set udg_DOT_Damage = 0.
    set udg_DOT_Attack_Type = ConvertAttackType(0)
    set udg_DOT_Damage_Type = ConvertDamageType(0)
    
    return false
endfunction


//===========================================================================
function InitTrig_DOT_Extension takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_Interval_After", EQUAL, 0)
    call TriggerAddCondition(t, Filter(function DOT_Deal_Damage))
    
    set t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_Creation_Before", EQUAL, 0)
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_Save_Data", EQUAL, 0)
    call TriggerAddCondition(t, Filter(function DOT_Save_Data))
    
    set t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_Interval_Before", EQUAL, 0)
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_Get_Data", EQUAL, 0)
    call TriggerAddCondition(t, Filter(function DOT_Get_Data))
    
    set t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_Null_Variables", EQUAL, 0)
    call TriggerAddCondition(t, Filter(function DOT_Reset_Data))
    
    set t = null
endfunction
JASS:
function ConvertAttackTypeReverse takes attacktype at returns integer
    if at == ATTACK_TYPE_NORMAL then
        return 0
    elseif at == ATTACK_TYPE_MELEE then
        return 1
    elseif at == ATTACK_TYPE_PIERCE then
        return 2
    elseif at == ATTACK_TYPE_SIEGE then
        return 3
    elseif at == ATTACK_TYPE_MAGIC then
        return 4
    elseif at == ATTACK_TYPE_CHAOS then
        return 5
    elseif at == ATTACK_TYPE_HERO then
        return 6
    endif
    return 0
endfunction

function ConvertDamageTypeReverse takes damagetype dt returns integer
    if dt == DAMAGE_TYPE_UNKNOWN then
        return 0
    elseif dt == DAMAGE_TYPE_NORMAL then
        return 4
    elseif dt == DAMAGE_TYPE_ENHANCED then
        return 5
    elseif dt == DAMAGE_TYPE_FIRE then
        return 8
    elseif dt == DAMAGE_TYPE_COLD then
        return 9
    elseif dt == DAMAGE_TYPE_LIGHTNING then
        return 10
    elseif dt == DAMAGE_TYPE_POISON then
        return 11
    elseif dt == DAMAGE_TYPE_DISEASE then
        return 12
    elseif dt == DAMAGE_TYPE_DIVINE then
        return 13
    elseif dt == DAMAGE_TYPE_MAGIC then
        return 14
    elseif dt == DAMAGE_TYPE_SONIC then
        return 15
    elseif dt == DAMAGE_TYPE_ACID then
        return 16
    elseif dt == DAMAGE_TYPE_FORCE then
        return 17
    elseif dt == DAMAGE_TYPE_DEATH then
        return 18
    elseif dt == DAMAGE_TYPE_MIND then
        return 19
    elseif dt == DAMAGE_TYPE_PLANT then
        return 20
    elseif dt == DAMAGE_TYPE_DEFENSIVE then
        return 21
    elseif dt == DAMAGE_TYPE_DEMOLITION then
        return 22
    elseif dt == DAMAGE_TYPE_SLOW_POISON then
        return 23
    elseif dt == DAMAGE_TYPE_SPIRIT_LINK then
        return 24
    elseif dt == DAMAGE_TYPE_SHADOW_STRIKE then
        return 25
    elseif dt == DAMAGE_TYPE_UNIVERSAL then
        return 26
    endif
    return 0
endfunction



/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  EOT System header file
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Reset all variables to null.
function EOT_Set_Default_Variables takes nothing returns nothing
    set udg_EOT_Param_Source = null
    set udg_EOT_Param_Target = null
    set udg_EOT_Param_Duration = 0.
    set udg_EOT_Param_Remaining_Duration = -1.
    set udg_EOT_Param_Interval = 0.
    set udg_EOT_Param_Remaining_Interval = -1.
    set udg_EOT_Param_Hidden = false
    set udg_EOT_Param_Buff = 0
    set udg_EOT_Param_Buff_Holder = 0
    set udg_EOT_Param_Buff_Holder_Level = 1
    set udg_EOT_Param_Ability = 0
    set udg_EOT_Param_Ability_Level = 1
    set udg_EOT_Param_Type = 0
    set udg_EOT_Param_Subtype = 0
    set udg_EOT_Param_Subtype2 = 0
    set udg_EOT_Param_Positive = false
    set udg_EOT_Param_Can_Dispell = true
    set udg_EOT_Param_Is_Passive = false
    set udg_EOT_Param_Is_Paused = false
    set udg_EOT_Param_Special_Effect = null
    set udg_EOT_Param_Special_Effect_Model = ""
    set udg_EOT_Param_Special_Effect_Point = ""
    
    set udg_EOT_Event_Null_Variables = 1
    set udg_EOT_Event_Null_Variables = 0
endfunction

//Save an EOT in the cache.
function EOT_Save_To_Cache takes integer cacheId returns nothing
    call SaveUnitHandle(    udg_EOT_Hashtable, cacheId + 100, 1000, udg_EOT_Param_Source)
    call SaveUnitHandle(    udg_EOT_Hashtable, cacheId + 100, 1001, udg_EOT_Param_Target)
    call SaveReal(          udg_EOT_Hashtable, cacheId + 100, 1002, udg_EOT_Param_Duration)
    call SaveReal(          udg_EOT_Hashtable, cacheId + 100, 1003, udg_EOT_Param_Remaining_Duration)
    call SaveReal(          udg_EOT_Hashtable, cacheId + 100, 1004, udg_EOT_Param_Interval)
    call SaveReal(          udg_EOT_Hashtable, cacheId + 100, 1005, udg_EOT_Param_Remaining_Interval)
    call SaveBoolean(       udg_EOT_Hashtable, cacheId + 100, 1006, udg_EOT_Param_Hidden)
    call SaveInteger(       udg_EOT_Hashtable, cacheId + 100, 1007, udg_EOT_Param_Buff)
    call SaveInteger(       udg_EOT_Hashtable, cacheId + 100, 1008, udg_EOT_Param_Buff_Holder)
    call SaveInteger(       udg_EOT_Hashtable, cacheId + 100, 1009, udg_EOT_Param_Buff_Holder_Level)
    call SaveInteger(       udg_EOT_Hashtable, cacheId + 100, 1010, udg_EOT_Param_Ability)
    call SaveInteger(       udg_EOT_Hashtable, cacheId + 100, 1011, udg_EOT_Param_Ability_Level)
    call SaveInteger(       udg_EOT_Hashtable, cacheId + 100, 1012, udg_EOT_Param_Type)
    call SaveInteger(       udg_EOT_Hashtable, cacheId + 100, 1013, udg_EOT_Param_Subtype)
    call SaveInteger(       udg_EOT_Hashtable, cacheId + 100, 1014, udg_EOT_Param_Subtype2)
    call SaveBoolean(       udg_EOT_Hashtable, cacheId + 100, 1015, udg_EOT_Param_Positive)
    call SaveBoolean(       udg_EOT_Hashtable, cacheId + 100, 1016, udg_EOT_Param_Can_Dispell)
    call SaveBoolean(       udg_EOT_Hashtable, cacheId + 100, 1017, udg_EOT_Param_Is_Passive)
    call SaveBoolean(       udg_EOT_Hashtable, cacheId + 100, 1018, udg_EOT_Param_Is_Paused)
    call SaveEffectHandle(  udg_EOT_Hashtable, cacheId + 100, 1019, udg_EOT_Param_Special_Effect)
    call SaveStr(           udg_EOT_Hashtable, cacheId + 100, 1020, udg_EOT_Param_Special_Effect_Model)
    call SaveStr(           udg_EOT_Hashtable, cacheId + 100, 1021, udg_EOT_Param_Special_Effect_Point)
endfunction

//Load an EOT from the cache.
function EOT_Load_From_Cache takes integer cacheId returns nothing
    set udg_EOT_Param_Source                = LoadUnitHandle(   udg_EOT_Hashtable, cacheId + 100, 1000)
    set udg_EOT_Param_Target                = LoadUnitHandle(   udg_EOT_Hashtable, cacheId + 100, 1001)
    set udg_EOT_Param_Duration              = LoadReal(         udg_EOT_Hashtable, cacheId + 100, 1002)
    set udg_EOT_Param_Remaining_Duration    = LoadReal(         udg_EOT_Hashtable, cacheId + 100, 1003)
    set udg_EOT_Param_Interval              = LoadReal(         udg_EOT_Hashtable, cacheId + 100, 1004)
    set udg_EOT_Param_Remaining_Interval    = LoadReal(         udg_EOT_Hashtable, cacheId + 100, 1005)
    set udg_EOT_Param_Hidden                = LoadBoolean(      udg_EOT_Hashtable, cacheId + 100, 1006)
    set udg_EOT_Param_Buff                  = LoadInteger(      udg_EOT_Hashtable, cacheId + 100, 1007)
    set udg_EOT_Param_Buff_Holder           = LoadInteger(      udg_EOT_Hashtable, cacheId + 100, 1008)
    set udg_EOT_Param_Buff_Holder_Level     = LoadInteger(      udg_EOT_Hashtable, cacheId + 100, 1009)
    set udg_EOT_Param_Ability               = LoadInteger(      udg_EOT_Hashtable, cacheId + 100, 1010)
    set udg_EOT_Param_Ability_Level         = LoadInteger(      udg_EOT_Hashtable, cacheId + 100, 1011)
    set udg_EOT_Param_Type                  = LoadInteger(      udg_EOT_Hashtable, cacheId + 100, 1012)
    set udg_EOT_Param_Subtype               = LoadInteger(      udg_EOT_Hashtable, cacheId + 100, 1013)
    set udg_EOT_Param_Subtype               = LoadInteger(      udg_EOT_Hashtable, cacheId + 100, 1014)
    set udg_EOT_Param_Positive              = LoadBoolean(      udg_EOT_Hashtable, cacheId + 100, 1015)
    set udg_EOT_Param_Can_Dispell           = LoadBoolean(      udg_EOT_Hashtable, cacheId + 100, 1016)
    set udg_EOT_Param_Is_Passive            = LoadBoolean(      udg_EOT_Hashtable, cacheId + 100, 1017)
    set udg_EOT_Param_Is_Paused             = LoadBoolean(      udg_EOT_Hashtable, cacheId + 100, 1018)
    set udg_EOT_Param_Special_Effect        = LoadEffectHandle( udg_EOT_Hashtable, cacheId + 100, 1019)
    set udg_EOT_Param_Special_Effect_Model  = LoadStr(          udg_EOT_Hashtable, cacheId + 100, 1020)
    set udg_EOT_Param_Special_Effect_Point  = LoadStr(          udg_EOT_Hashtable, cacheId + 100, 1021)
endfunction

//Save and Load additional data to an EOT.
//Raw values:
function EOT_Save_Integer takes integer id, integer value returns nothing
    call SaveInteger(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction
function EOT_Save_Real takes integer id, real value returns nothing
    call SaveReal(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction
function EOT_Save_String takes integer id, string value returns nothing
    call SaveStr(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction
function EOT_Save_Boolean takes integer id, boolean value returns nothing
    call SaveBoolean(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction

function EOT_Load_Integer takes integer id returns integer
    return LoadInteger(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction
function EOT_Load_Real takes integer id returns real
    return LoadReal(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction
function EOT_Load_String takes integer id returns string
    return LoadStr(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction
function EOT_Load_Boolean takes integer id returns boolean
    return LoadBoolean(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction

//Handles:
function EOT_Save_Unit takes integer id, unit value returns nothing
    call SaveUnitHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction
function EOT_Save_Player takes integer id, player value returns nothing
    call SavePlayerHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction
function EOT_Save_Item takes integer id, item value returns nothing
    call SaveItemHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction
function EOT_Save_Group takes integer id, group value returns nothing
    call SaveGroupHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction
function EOT_Save_Effect takes integer id, effect value returns nothing
    call SaveEffectHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction
function EOT_Save_Location takes integer id, location value returns nothing
    call SaveLocationHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction
function EOT_Save_Lightning takes integer id, lightning value returns nothing
    call SaveLightningHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000, value)
endfunction

function EOT_Load_Unit takes integer id returns unit
    return LoadUnitHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction
function EOT_Load_Player takes integer id returns player
    return LoadPlayerHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction
function EOT_Load_Item takes integer id returns item
    return LoadItemHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction
function EOT_Load_Group takes integer id returns group
    return LoadGroupHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction
function EOT_Load_Effect takes integer id returns effect
    return LoadEffectHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction
function EOT_Load_Location takes integer id returns location
    return LoadLocationHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction
function EOT_Load_Lightning takes integer id returns lightning
    return LoadLightningHandle(udg_EOT_Hashtable, udg_EOT_Param_Id, id + 1000)
endfunction
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  EOT System header file end
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
JASS:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  
//  Be aware that the AEM Event Manager cannot register triggers to events in GUI events.
//  It can register GUI triggers to an event but it has to be done in a custom script or in JASS.
//  
//  Make sure that all variables listed below are unique numbers in the event list.
//  
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
globals
    
    integer         udg_EOT_AEMEvent_On_Interval                = 101
    integer         udg_EOT_AEMEvent_An_EOT_Is_Created          = 102
    integer         udg_EOT_AEMEvent_An_EOT_Is_Destroyed        = 103
    integer         udg_EOT_AEMEvent_An_EOT_Is_Dispelled        = 104
    integer         udg_EOT_AEMEvent_An_EOT_Has_Expired         = 105
    
endglobals

function EOT_AEMCall_An_EOT_Is_Created takes nothing returns boolean
    call AEM_CallEvent(udg_EOT_AEMEvent_An_EOT_Is_Created)
    call AEM_CallEvent2(udg_EOT_AEMEvent_An_EOT_Is_Created, udg_EOT_Param_Type)
    return false
endfunction
function EOT_AEMCall_An_EOT_Is_Destroyed takes nothing returns boolean
    call AEM_CallEvent(udg_EOT_AEMEvent_An_EOT_Is_Destroyed)
    call AEM_CallEvent2(udg_EOT_AEMEvent_An_EOT_Is_Destroyed, udg_EOT_Param_Type)
    return false
endfunction
function EOT_AEMCall_An_EOT_Is_Dispelled takes nothing returns boolean
    call AEM_CallEvent(udg_EOT_AEMEvent_An_EOT_Is_Dispelled)
    call AEM_CallEvent2(udg_EOT_AEMEvent_An_EOT_Is_Dispelled, udg_EOT_Param_Type)
    return false
endfunction
function EOT_AEMCall_An_EOT_Has_Expired takes nothing returns boolean
    call AEM_CallEvent(udg_EOT_AEMEvent_An_EOT_Has_Expired)
    call AEM_CallEvent2(udg_EOT_AEMEvent_An_EOT_Has_Expired, udg_EOT_Param_Type)
    return false
endfunction
function EOT_AEMCall_On_Interval takes nothing returns boolean
    call AEM_CallEvent(udg_EOT_AEMEvent_On_Interval)
    call AEM_CallEvent2(udg_EOT_AEMEvent_On_Interval, udg_EOT_Param_Type)
    return false
endfunction

//===========================================================================
function InitTrig_EOT_AEM_Events takes nothing returns nothing
    local trigger t
    
    set t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_An_EOT_Has_Expired", EQUAL, 0)
    call TriggerAddCondition(t, Filter(function EOT_AEMCall_An_EOT_Has_Expired))
    
    set t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_An_EOT_Is_Created", EQUAL, 0)
    call TriggerAddCondition(t, Filter(function EOT_AEMCall_An_EOT_Is_Created))
    
    set t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_An_EOT_Is_Destroyed", EQUAL, 0)
    call TriggerAddCondition(t, Filter(function EOT_AEMCall_An_EOT_Is_Destroyed))
    
    set t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_An_EOT_Is_Dispelled", EQUAL, 0)
    call TriggerAddCondition(t, Filter(function EOT_AEMCall_An_EOT_Is_Dispelled))
    
    set t = CreateTrigger()
    call TriggerRegisterVariableEvent(t, "udg_EOT_Event_On_Interval", EQUAL, 0)
    call TriggerAddCondition(t, Filter(function EOT_AEMCall_On_Interval))
    
endfunction

And a few examples:
  • Iron Will
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Iron Will (Paladin)
    • Actions
      • Custom script: call EOT_Set_Default_Variables()
      • Set EOT_Param_Source = (Triggering unit)
      • Set EOT_Param_Target = (Triggering unit)
      • Set EOT_Param_Duration = 10.00
      • Set EOT_Param_Buff = Custom Iron Will
      • Set EOT_Param_Buff_Holder = Iron Will (Buff Holder)
      • Set EOT_Param_Special_Effect_Point = overhead
      • Set EOT_Param_Special_Effect_Model = Abilities\Spells\Human\InnerFire\InnerFireTarget.mdl
      • Set EOT_Param_Ability = Iron Will (Effect)
      • Set EOT_Param_Ability_Level = (Level of (Ability being cast) for EOT_Param_Source)
      • Set TempAbility = (Ability being cast)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • Set EOT_Param_Type = TempInteger
      • Set EOT_Param_Positive = True
      • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
  • Immolation
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Immolation (Paladin)
    • Actions
      • Custom script: call EOT_Set_Default_Variables()
      • Set EOT_Param_Source = (Triggering unit)
      • Set EOT_Param_Target = (Triggering unit)
      • Set EOT_Param_Duration = (2.00 + (3.00 x (Real((Level of (Ability being cast) for EOT_Param_Source)))))
      • Set EOT_Param_Buff = Custom Immolation
      • Set EOT_Param_Buff_Holder = Immolation (Buff Holder)
      • Set EOT_Param_Special_Effect_Model = Environment\LargeBuildingFire\LargeBuildingFire1.mdl
      • Set EOT_Param_Ability = Immolation (Spell Book)
      • Set EOT_Param_Ability_Level = (Level of (Ability being cast) for EOT_Param_Source)
      • Set TempAbility = (Ability being cast)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • Set EOT_Param_Type = TempInteger
      • Set EOT_Param_Positive = True
      • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
  • Divine Shield
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Divine Shield (Paladin)
    • Actions
      • Custom script: call EOT_Set_Default_Variables()
      • Set EOT_Param_Source = (Triggering unit)
      • Set EOT_Param_Target = (Triggering unit)
      • Set EOT_Param_Duration = (5.00 + (5.00 x (Real((Level of (Ability being cast) for EOT_Param_Source)))))
      • Set EOT_Param_Buff_Holder = Divine Shield (Buff Holder)
      • Set EOT_Param_Buff = Custom Divine Shield
      • Set EOT_Param_Special_Effect_Model = Abilities\Spells\Human\DivineShield\DivineShieldTarget.mdl
      • Set EOT_Param_Ability = Invulnerable (Neutral)
      • Set TempAbility = (Ability being cast)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • Set EOT_Param_Type = TempInteger
      • Set EOT_Param_Positive = True
      • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
  • Magic Shield
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Level of Magic Shield (Paladin) for (Triggering unit)) Greater than 0
    • Actions
      • -------- The event should be made by a DDS. --------
      • Custom script: call EOT_Set_Default_Variables()
      • Set EOT_Param_Target = (Triggering unit)
      • Set EOT_Param_Ability = Magic Shield (Spell Book)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Evaluate EOT_Trigger_Get_Data conditions) Equal to True
        • Then - Actions
          • Set EOT_Param_Remaining_Duration = 6.00
          • Set EOT_Param_Ability_Level = (EOT_Param_Ability_Level + 1)
          • Trigger - Run EOT_Trigger_Save_Data (ignoring conditions)
        • Else - Actions
          • Set EOT_Param_Source = (Triggering unit)
          • Set EOT_Param_Duration = 6.00
          • Set EOT_Param_Buff = Custom Magic Shield
          • Set EOT_Param_Buff_Holder = Magic Shield (Buff Holder)
          • Set EOT_Param_Special_Effect_Model = Abilities\Spells\Undead\FrostArmor\FrostArmorTarget.mdl
          • Set EOT_Param_Special_Effect_Point = chest
          • Set TempAbility = Magic Shield (Paladin)
          • Custom script: set udg_TempInteger = udg_TempAbility
          • Set EOT_Param_Type = TempInteger
          • Set EOT_Param_Positive = True
          • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
Or more advanced spells:
  • Critical Strike Aura
    • Events
      • Unit - A unit Learns a skill
    • Conditions
    • Actions
      • Custom script: set udg_TempAbility = GetLearnedSkill()
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • TempAbility Equal to Critical Strike Aura (Death Knight)
        • Then - Actions
          • Custom script: call EOT_Set_Default_Variables()
          • Set EOT_Param_Source = (Triggering unit)
          • Set EOT_Param_Target = (Triggering unit)
          • Set EOT_Param_Interval = 1.00
          • Set EOT_Param_Hidden = True
          • Set EOT_Param_Ability = Critical Strike Aura (Effect)
          • Set EOT_Param_Special_Effect_Model = Abilities\Spells\Undead\RegenerationAura\ObsidianRegenAura.mdl
          • Set EOT_Param_Positive = True
          • Set EOT_Param_Can_Dispell = False
          • Set EOT_Param_Is_Passive = True
          • Custom script: set udg_TempInteger = udg_TempAbility
          • Set EOT_Param_Type = TempInteger
          • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
        • Else - Actions
  • Critical Strike Effect
    • Events
      • Game - EOT_Event_On_Interval becomes Equal to 0.00
    • Conditions
    • Actions
      • Set TempAbility = Critical Strike Aura (Death Knight)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • EOT_Param_Type Equal to TempInteger
          • EOT_Param_Subtype Equal to 0
        • Then - Actions
          • Custom script: call EOT_Save_To_Cache(0)
          • Set TempLocation = (Position of EOT_Param_Target)
          • Set TempUnit = EOT_Param_Source
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units within 900.00 of TempLocation) and do (Actions)
            • Loop - Actions
              • Custom script: call EOT_Set_Default_Variables()
              • Set EOT_Param_Target = (Picked unit)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (EOT_Param_Target is A structure) Equal to False
                  • (EOT_Param_Target belongs to an ally of (Owner of TempUnit)) Equal to True
                  • (EOT_Param_Target is alive) Equal to True
                • Then - Actions
                  • Set EOT_Param_Type = TempInteger
                  • Set EOT_Param_Subtype = 1
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Evaluate EOT_Trigger_Get_Data conditions) Equal to True
                    • Then - Actions
                      • Set EOT_Param_Remaining_Duration = 2.00
                      • Set EOT_Param_Ability_Level = (Level of Critical Strike Aura (Death Knight) for TempUnit)
                      • Trigger - Run EOT_Trigger_Save_Data (ignoring conditions)
                    • Else - Actions
                      • Set EOT_Param_Source = TempUnit
                      • Set EOT_Param_Target = (Picked unit)
                      • Set EOT_Param_Duration = 2.00
                      • Set EOT_Param_Interval = -1.00
                      • Set EOT_Param_Buff = Custom Critical Strike Aura
                      • Set EOT_Param_Buff_Holder = Critical Strike (Buff Holder)
                      • Set EOT_Param_Ability = Critical Strike Aura (Spell Book)
                      • Set EOT_Param_Ability_Level = (Level of Critical Strike Aura (Death Knight) for TempUnit)
                      • Set EOT_Param_Positive = True
                      • Set EOT_Param_Special_Effect_Model = Abilities\Spells\Orc\SpiritLink\SpiritLinkTarget.mdl
                      • Set EOT_Param_Type = TempInteger
                      • Set EOT_Param_Subtype = 1
                      • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
                • Else - Actions
          • Custom script: call RemoveLocation(udg_TempLocation)
          • Custom script: call EOT_Load_From_Cache(0)
        • Else - Actions
  • Hemoplague
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Hemoplague (Death Knight)
    • Actions
      • Set TempLocation = (Target point of ability being cast)
      • Set TempPlayer = (Owner of (Triggering unit))
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units within 200.00 of TempLocation) and do (Actions)
        • Loop - Actions
          • Custom script: call EOT_Set_Default_Variables()
          • Set EOT_Param_Target = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (EOT_Param_Target is A structure) Equal to False
              • (EOT_Param_Target belongs to an enemy of TempPlayer) Equal to True
              • (EOT_Param_Target is alive) Equal to True
            • Then - Actions
              • Set EOT_Param_Source = (Triggering unit)
              • Set EOT_Param_Duration = 5.00
              • Set EOT_Param_Interval = -1.00
              • Set EOT_Param_Buff = Custom Hemoplague
              • Set EOT_Param_Buff_Holder = Hemoplague (Buff Holder)
              • Set EOT_Param_Special_Effect_Point = chest
              • Set EOT_Param_Special_Effect_Model = Abilities\Weapons\LordofFlameMissile\LordofFlameMissile.mdl
              • Set TempAbility = (Ability being cast)
              • Custom script: set udg_TempInteger = udg_TempAbility
              • Set EOT_Param_Type = TempInteger
              • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
            • Else - Actions
      • Custom script: call RemoveLocation(udg_TempLocation)
  • Hemoplague Damage
    • Events
      • Game - EOT_Event_An_EOT_Has_Expired becomes Equal to 0.00
    • Conditions
      • EOT_Param_Buff Equal to Custom Hemoplague
    • Actions
      • Unit - Cause EOT_Param_Source to damage EOT_Param_Target, dealing 200.00 damage of attack type Spells and damage type Normal
  • Necrotic Plague
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Arcane Plague (Death Knight)
    • Actions
      • Custom script: call EOT_Set_Default_Variables()
      • Set EOT_Param_Source = (Triggering unit)
      • Set EOT_Param_Target = (Target unit of ability being cast)
      • Set EOT_Param_Duration = 9.00
      • Set EOT_Param_Interval = 3.00
      • Set EOT_Param_Buff = Custom Arcane Plague
      • Set EOT_Param_Buff_Holder = Arcane Plague (Buff Holder)
      • Set EOT_Param_Special_Effect_Model = Environment\LargeBuildingFire\LargeBuildingFire2.mdl
      • Set TempAbility = (Ability being cast)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • Set EOT_Param_Type = TempInteger
      • -------- start with 3 stacks --------
      • Set TempInteger = 3
      • Set DOT_Damage = (50.00 x (Real(TempInteger)))
      • Set DOT_Attack_Type = Spells
      • Set DOT_Damage_Type = Normal
      • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
      • Custom script: call EOT_Save_Integer(0, udg_TempInteger)
  • Necrotic Plague Jump On Expire
    • Events
      • Game - EOT_Event_An_EOT_Has_Expired becomes Equal to 0.00
    • Conditions
    • Actions
      • Set TempAbility = Arcane Plague (Death Knight)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • EOT_Param_Type Equal to TempInteger
        • Then - Actions
          • Set TempBoolean = False
          • Set TempLocation = (Position of EOT_Param_Target)
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units within 250.00 of TempLocation) and do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • TempBoolean Equal to False
                  • ((Picked unit) is A structure) Equal to False
                  • (Picked unit) Not equal to EOT_Param_Target
                  • ((Picked unit) is alive) Equal to True
                  • ((Picked unit) belongs to an enemy of (Owner of EOT_Param_Source)) Equal to True
                  • ((Picked unit) has buff Custom Hemoplague ) Equal to False
                • Then - Actions
                  • Set TempBoolean = True
                  • Set EOT_Param_Target = (Picked unit)
                  • Set EOT_Param_Remaining_Duration = 9.00
                  • Set EOT_Param_Remaining_Interval = 3.00
                  • Set EOT_Param_Expire = False
                  • Custom script: set udg_TempInteger = EOT_Load_Integer(0)
                  • Set TempInteger = (TempInteger + 1)
                  • Set DOT_Damage = (50.00 x (Real(TempInteger)))
                  • Custom script: call EOT_Save_Integer(0, udg_TempInteger)
                  • Trigger - Run EOT_Trigger_Save_Data (ignoring conditions)
                • Else - Actions
          • Custom script: call RemoveLocation(udg_TempLocation)
        • Else - Actions
  • Remorseless Winter Cast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Remorseless Winter (Death Knight)
    • Actions
      • Custom script: call EOT_Set_Default_Variables()
      • Set EOT_Param_Source = (Triggering unit)
      • Set EOT_Param_Target = (Triggering unit)
      • Set EOT_Param_Duration = 10.00
      • Set EOT_Param_Interval = 1.00
      • Set EOT_Param_Buff = Custom Remorseless Winter
      • Set EOT_Param_Buff_Holder = Remorseless Winter (Buff Holder)
      • Set EOT_Param_Special_Effect_Point = chest
      • Set EOT_Param_Special_Effect_Model = Abilities\Spells\Other\Drain\ManaDrainTarget.mdl
      • Set TempAbility = (Ability being cast)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • Set EOT_Param_Type = TempInteger
      • Set EOT_Param_Positive = True
      • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
  • Remorseless Winter Interval
    • Events
      • Game - EOT_Event_On_Interval becomes Equal to 0.00
    • Conditions
    • Actions
      • Set TempAbility = Remorseless Winter (Death Knight)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • EOT_Param_Type Equal to TempInteger
          • EOT_Param_Subtype Equal to 0
        • Then - Actions
          • Game - Display to (All players) the text: (ID = + (String(EOT_Param_Type)))
          • Custom script: call EOT_Save_To_Cache(0)
          • Set TempLocation = (Position of EOT_Param_Target)
          • Set TempUnit = EOT_Param_Source
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units within 250.00 of TempLocation) and do (Actions)
            • Loop - Actions
              • Custom script: call EOT_Set_Default_Variables()
              • Set EOT_Param_Target = (Picked unit)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (EOT_Param_Target is A structure) Equal to False
                  • (EOT_Param_Target belongs to an enemy of (Owner of TempUnit)) Equal to True
                  • (EOT_Param_Target is alive) Equal to True
                • Then - Actions
                  • Set TempAbility = Remorseless Winter (Death Knight)
                  • Custom script: set udg_TempInteger = udg_TempAbility
                  • Set EOT_Param_Type = TempInteger
                  • Set EOT_Param_Subtype = 1
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Evaluate EOT_Trigger_Get_Data conditions) Equal to True
                    • Then - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • EOT_Param_Ability_Level Equal to 6
                        • Then - Actions
                          • Unit - Create 1 DUMMY for (Owner of TempUnit) at TempLocation facing Default building facing degrees
                          • Set TempUnit2 = (Last created unit)
                          • Unit - Add a 2.00 second Generic expiration timer to TempUnit2
                          • Unit - Add STUN (Remorseless Winter) to TempUnit2
                          • Unit - Order TempUnit2 to Human Mountain King - Storm Bolt EOT_Param_Target
                        • Else - Actions
                      • Set EOT_Param_Remaining_Duration = 5.00
                      • Set EOT_Param_Ability_Level = (EOT_Param_Ability_Level + 1)
                      • Trigger - Run EOT_Trigger_Save_Data (ignoring conditions)
                    • Else - Actions
                      • Set EOT_Param_Source = TempUnit
                      • Set EOT_Param_Target = (Picked unit)
                      • Set EOT_Param_Duration = 5.00
                      • Set EOT_Param_Remaining_Duration = 5.00
                      • Set EOT_Param_Buff = Custom Remorseless Winter Slow
                      • Set EOT_Param_Special_Effect_Model = Abilities\Spells\Undead\FrostArmor\FrostArmorTarget.mdl
                      • Set EOT_Param_Ability = Remorseless Winter Slow (Effect)
                      • Set EOT_Param_Ability_Level = 1
                      • Set EOT_Param_Interval = 1.00
                      • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
                • Else - Actions
          • Custom script: call RemoveLocation(udg_TempLocation)
          • Custom script: call EOT_Load_From_Cache(0)
        • Else - Actions
A few images of how the example abilities look like.
F1w27Eh.png

shHHXTb.jpg

ydky3F5.jpg

D914lfz.png

e4fG4LD.png

jszPY7Y.jpg


Changelog:
- 2.3.1 - Death bug fix
- 2.3 - AEM Events
- 2.2.2 - Added ultimate MUI-ness.
- 2.2.1 - Fixed a bug where the game would crash when a dead unit would gain an EOT.
- 2.2 - Added Is_Passive and fixed a few bugs.
- 2.1 - Finished the system. All upcoming updates are fixes.
- 2.0.1 - Fixed the event firing. Now users should only use 0 as the event and there are several additional events made for other systems and extensions
- 2.0 - Rewritten the system with loops instead of timers. Added many functions too.
- 1.2 - Simplified the system and it's code. Added new functions and finished the Buff system.
- 1.1 - Reworked this system's base functions to make every effect use the same trigger.
- 1.0 - Added this system to the hive.

Feel free to post any feedback or suggestions.

Keywords:
Wietlol, Damage Over Time, Damage, Over, Time, Effect Over Time, Effect, Time, Duration, Interval, DoT, HoT, EoT, GUI, Buff, Buff System.
Contents

Just another Warcraft III map (Map)

Reviews
12:19, 26th Mar 2015 IcemanBo: http://www.hiveworkshop.com/forums/spells-569/gui-effect-over-time-system-2-2-2-a-261662/index2.html#post2667741 Offers many possibilities to create different effects. Approved! 12:52, 25th Jan 2015 IcemanBo: Needs...
Level 24
Joined
Aug 1, 2013
Messages
4,657

  • The buffs of EOTs are aura buffs. This means that they are not dispelled by buff dispell abilities by default. To be able to dispell the buffs you have to trigger all buff dispel abilities.
  • The EOT_Buff_Holder_Level doesn't work. Auras in WC3 are slow responsive and cannot update the level so fast as I want. So you have to add the buff in a spell book and update the level once in a while.

 
Last edited:
Level 10
Joined
Aug 21, 2010
Messages
316
looks like you missed something

EOT_SaveNextEOT
ConvertAttackTypeReverse
ConvertDamageTypeReverse
EOT_DestroyEOT
  • Trigger - Run EOT Get All Data <gen> (ignoring conditions)
  • Trigger - Run EOT Save All Data <gen> (ignoring conditions)
where is this, I do not see it anywhere
and how to install it at all

explain that a little better
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
You certainly didnt download the map before posting, did you?

I indeed did not add all triggers in the post and that is why some functions were not (completely) clear.

Installing is just copying the EOT category from the test map, create the global variables and copy the header.
(Everything is explained in comments in the trigger editor.)

Next to that, I never actually read the posts. I just watch some screenshots, download the map and watch what the example spells do.
Then I can tell if it was what I wanted.
___________________________________________________________________________

The map is reworked. Now you can easily add new effects and some triggers became useless and are removed.
 
Level 10
Joined
Aug 21, 2010
Messages
316
You certainly didnt download the map before posting, did you?

I indeed did not add all triggers in the post and that is why some functions were not (completely) clear.

Installing is just copying the EOT category from the test map, create the global variables and copy the header.
(Everything is explained in comments in the trigger editor.)

Next to that, I never actually read the posts. I just watch some screenshots, download the map and watch what the example spells do.
Then I can tell if it was what I wanted.
___________________________________________________________________________

The map is reworked. Now you can easily add new effects and some triggers became useless and are removed.

You have to put all the functions and to explain how to use and install
READ THE RULES BUDDY

If you're interested in the effects, look at this
JASS:
// How to install?
//----------------------------------
// Copy the code in the map header
// Copy the variable "TimedSFXHash"
// If you do not want to copy,simply create a new variable with this name "TimedSFXHash"
// Variable Type is: "hashtable"
// That's it.
// Very simply.
//----------------------------------
// How to use this system?
//----------------------------------
// For example:
//----------------------------------
// If you want to use a static or non-static effect at points X,Y
// For example, suppose that x = GetSpellTargetX() and y = GetSpellTargetY()
// or that x = GetUnitX(your unit) and y = GetUnitY(your unit)
// In this case we should call this function

// "AddStaticTimedSFX" or "AddNonStaticTimedSFX"

// call AddStaticTimedSFX(modelPath,yourunit,timeinterval,durationofeffect,x,y)
// call AddNonStaticTimedSFX(modelPath,yourunit,timeinterval,durationofeffect,x,y)

// Explanation:

// (modelPath)
// "Abilities\\Spells\\Undead\\FrostArmor\\FrostArmorTarget.mdl"

// (yourunit)
// GetTriggerUnit(),GetFilterUnit(),GetEnumUnit(),GetAttacker()...and so on

// (timeinterval)
// 0.03,0.04,0.05...bla,bla...and so on

// (durationofeffect)
// 1.00,2.00,3.00 or 1.5+(1.5*level)...and so on

// (x)
// GetSpellTargetX() or GetUnitX(yourunit)

// (y)
// GetSpellTargetY() or GetUnitY(yourunit)

// A few simple examples:
 
// local
// call AddStaticTimedSFX(modelPath,yourunit,timeinterval,durationofeffect,GetSpellTargetX(),GetSpellTargetY())

// global
// call AddStaticTimedSFX(udg_modelPath,udg_yourunit,udg_timeinterval,udg_durationofeffect,GetSpellTargetX(),GetSpellTargetY())

// func
// call AddStaticTimedSFX(modelPath(),yourunit(),timeinterval(),durationofeffect(),GetSpellTargetX(),GetSpellTargetY())

// directly
// call AddStaticTimedSFX("Abilities\\Spells\\Undead\\FrostArmor\\FrostArmorTarget.mdl",GetTriggerUnit(),0.03125,3.00,GetSpellTargetX(),GetSpellTargetY())

// As for other functions,all based on the same principle

// call AddStaticTimedSFXTarget(yourmodelPath,yourunit,yourattachpoint,youttimerint,yourdurationofeffect)

// call AddNonStaticTimedSFXTarget(yourmodelPath,yourunit,yourattachpoint,youttimerint,yourdurationofeffect)

// call AddStaticTimedSFXLoc(yourmodelPath,yourunit,timeinterval,durationofeffect,yourlocation)

// call AddNonStaticTimedSFXLoc(yourmodelPath,yourunit,timeinterval,durationofeffect,yourlocation)

//--------------------------------------------------------
// Static Non-Static Special Effect Timed System
//--------------------------------------------------------

function TimedSFXSystemTimer takes nothing returns nothing

    local timer t=GetExpiredTimer()
    local integer id=GetHandleId(t)    
    local boolean nonstatic=LoadBoolean(udg_TimedSFXHash,id,0)
    local boolean whichEffect=LoadBoolean(udg_TimedSFXHash,id,1)
    local string modelPath=LoadStr(udg_TimedSFXHash,id,2)
    local real x=LoadReal(udg_TimedSFXHash,id,3)
    local real y=LoadReal(udg_TimedSFXHash,id,4)
    local unit u=LoadUnitHandle(udg_TimedSFXHash,id,5)
    local string pointPath=LoadStr(udg_TimedSFXHash,id,6)
    local real effectduration=LoadReal(udg_TimedSFXHash,id,7)
    local effect sfx=LoadEffectHandle(udg_TimedSFXHash,id,8)
    local real timesec=LoadReal(udg_TimedSFXHash,id,9)

    if(effectduration<=0.00) or IsUnitType(u,UNIT_TYPE_DEAD) then
        call DestroyEffect(sfx)
        call FlushChildHashtable(udg_TimedSFXHash,id)
        call PauseTimer(t)
        call DestroyTimer(t)

    else

        call SaveReal(udg_TimedSFXHash,id,7,effectduration-timesec)

        if nonstatic then

            if whichEffect then
                call DestroyEffect(AddSpecialEffect(modelPath,x,y))
            else
                call DestroyEffect(AddSpecialEffectTarget(modelPath,u,pointPath))
            endif

        endif 
  
    endif

    set t=null
    set u=null
    set sfx=null 
        
endfunction

function RegisterTimedSFXSystem takes string modelPath,unit u,string pointPath,real timesec,real dur,real x,real y,boolean nonststic,boolean whichEffect returns nothing

    local timer t=CreateTimer()
    local integer id=GetHandleId(t)
    local effect sfx

    if nonststic then
        call SaveBoolean(udg_TimedSFXHash,id,0,nonststic)

        if whichEffect then                        
            call SaveBoolean(udg_TimedSFXHash,id,1,whichEffect) 
        endif

    else

        if whichEffect then
            set sfx=AddSpecialEffect(modelPath,x,y)
            call SaveAgentHandle(udg_TimedSFXHash,id,8,sfx)
            set sfx=null

        else

            call SaveAgentHandle(udg_TimedSFXHash,id,8,AddSpecialEffectTarget(modelPath,u,pointPath))

        endif

    endif

    call SaveStr(udg_TimedSFXHash,id,2,modelPath)
    call SaveReal(udg_TimedSFXHash,id,3,x)
    call SaveReal(udg_TimedSFXHash,id,4,y)
    call SaveReal(udg_TimedSFXHash,id,7,dur)
    call SaveAgentHandle(udg_TimedSFXHash,id,5,u)
    call SaveStr(udg_TimedSFXHash,id,6,pointPath)
    call SaveReal(udg_TimedSFXHash,id,9,timesec)
    call TimerStart(t,timesec,true,function TimedSFXSystemTimer) 
    set t=null

endfunction

function AddStaticTimedSFX takes string s,unit u,real t,real r,real x,real y returns nothing
    call RegisterTimedSFXSystem(s,u,null,t,r,x,y,false,true)
endfunction

function AddNonStaticTimedSFX takes string s,unit u,real t,real r,real x,real y returns nothing
    call RegisterTimedSFXSystem(s,u,null,t,r,x,y,true,true)
endfunction

function AddStaticTimedSFXTarget takes string s,unit u,string s1,real t,real r returns nothing
    call RegisterTimedSFXSystem(s,u,s1,t,r,0.00,0.00,false,false)
endfunction

function AddNonStaticTimedSFXTarget takes string s,unit u,string s1,real t,real r returns nothing
    call RegisterTimedSFXSystem(s,u,s1,t,r,0.00,0.00,true,false)
endfunction

function AddStaticTimedSFXLoc takes string s,unit u,real t,real r,location l returns nothing
    call RegisterTimedSFXSystem(s,u,null,t,r,GetLocationX(l),GetLocationY(l),false,true)
endfunction

function AddNonStaticTimedSFXLoc takes string s,unit u,real t,real r,location l returns nothing
    call RegisterTimedSFXSystem(s,u,null,t,r,GetLocationX(l),GetLocationY(l),true,true)
endfunction

So, in this same way you can make the damage over time

http://www.hiveworkshop.com/forums/spells-569/staticnonstatictimedsfxsystem_1-0c-w3x-218471/
 
Last edited:
Level 24
Joined
Aug 1, 2013
Messages
4,657
Update 1.2

I just released version 1.2

Here are the changes:
  • Added the complete documentation.
  • Put all code of the system in one trigger with exception of the configuration and made it more readable.
  • Completed the buff system.
  • Added an ability that is active on the unit as long as the eot exists.
  • Automatically removes or adds existing eots depending on a configurable, eot-dependant variable.
  • Now allows the player to change the target of the effect over time.
  • Fixed a bug where an eot which would not last until the next interval would be removed at that moment rather than when the duration expires.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
I just released version 2.0

Here are the changes:
  • Updated for new functions and variables.
  • Rewritten the whole code.
  • Ripped the code into triggers only.
  • Added hashtable functions in the header.
  • Added cache functions in the header.
  • Damage transferred to an extension to remove a lot of empty values in the arrays.
  • Now has a cache where you can save the current EOT in or load a saved EOT from. This can be used as presets or when you want to create a new one during the interval.
  • Now you can save additional data to an EOT.
  • Events are now handled better to function with extensions properly and create
  • You can now leave unnecessary data open. The variables are set to their standard values.
  • You can now set the level of the buff holder.
  • Added the Force_Destroy variable which allows you to break through the Can_Dispell value.
  • The EOT is not removed if you set a too high interval.
  • The Special Effect is now recreated properly if the EOT changed targets, effect-model or attachment point.
  • The EOT is now removed immediately when the buff is removed.

I might have forgotten to remove some variables, redundant code or other simple things.
But I just couldn't wait uploading the new version.
 
Hiho.

Does the GUI user need to create all variables on his own? I only saw you offer the globals block.

I believe you can avoid forcing the user to call the "null_variables" function.
You might do it once yourself somewhere at initialization, and then call it yourself after registration.
Btw, function EOT_Null_Variables is not the best name, as you actually re-set them to kind of default values, it doesn't mean you null them.

You should note to copy the header functions in the "How to install" part.

JASS:
//If the duration or interval are 0 or below, then do not create it.
if udg_EOT_Param_Duration <= 0. and udg_EOT_Param_Duration > -1. then
    return false
endif
^The comment and the actual condition is not in harmony. Your check is actually if it equals "0".

Why do you need all these triggers? For example for Get/Save data. Why not normaly call functions?

Only check to turn off your periodic trigger onDestroy, not onPeriod.

JASS:
//Null all variables.
call EnableTrigger(udg_EOT_Trigger_Interval)
^Only turn on the periodic trigger if amount equals "0".
In JASS you can take advantage of timers. You can use start/pause timer instead of using a trigger.

JASS:
//This function saves the data of the Param variables according to the data of the EOT if it can be found.
function EOT_Get_Data takes nothing returns boolean
Eh, the GetData function saves data? The name makes it confusing.

Is the "DOT Extension" really needed? Isn't it more like a one more example of usage of periodic event?

You partially leak in your demonstration examples.
Even they are examples, user might want to copy your example and take usage of it.

Edit: I realized you uploaded a new version today. I had a look at the one from yesterday. (already downloaded it :s)
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
I think he's going for the layman's term of cleaning leaks, maybe that's why the function was named thus.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Does the GUI user need to create all variables on his own? I only saw you offer the globals block.
So how do I not let them create them on their own?

I believe you can avoid forcing the user to call the "null_variables" function.
You might do it once yourself somewhere at initialization, and then call it yourself after registration.
Btw, function EOT_Null_Variables is not the best name, as you actually re-set them to kind of default values, it doesn't mean you null them.
At first that function would null/0/"" all variables and I didn't bother to change the name indeed.
It also was called on initialization and after each create and stuff but as a part of how the global variables are saved all the time, I thought it would be easier to just call that function which is always the same instead than having millions of them hardcoded.

JASS:
//If the duration or interval are 0 or below, then do not create it.
if udg_EOT_Param_Duration <= 0. and udg_EOT_Param_Duration > -1. then
    return false
endif
^The comment and the actual condition is not in harmony. Your check is actually if it equals "0".
Yea I mentioned that I have left some weird stuff in it.
I didn't thought about changing the comment when I changed the below zero to below/equal to zero but higher than -1.
-1 (or lower) is now never for intervals and infinite for duration.

Why do you need all these triggers? For example for Get/Save data. Why not normaly call functions?
I thought that it would be more GUI friendly... especially for the ones that return a boolean like Get Data.
For the ones that always return false... I suppose I could change those... but it is still a Custom Script and therefor less GUI friendly.

JASS:
//Null all variables.
call EnableTrigger(udg_EOT_Trigger_Interval)
^Only turn on the periodic trigger if amount equals "0".
In JASS you can take advantage of timers. You can use start/pause timer instead of using a trigger.
I have seen that before... however I was not sure which one would be more efficient as both work perfectly... you cannot turn something on that already is on :D
Will change it though...

JASS:
//This function saves the data of the Param variables according to the data of the EOT if it can be found.
function EOT_Get_Data takes nothing returns boolean
Eh, the GetData function saves data? The name makes it confusing.
Yea it saves the "Param" to the "Array" variables of the EOT you want...
I didn't thought about people who read save as a bit more "save" :D

Is the "DOT Extension" really needed? Isn't it more like a one more example of usage of periodic event?
It is in one way an example of how Extensions are made... In the other way. I removed the possibility of damage over time from 1.2 to 2.0.
I removed it because there are a lot of EOTs that do not use DOT so there will be a lot of empty variables.
So I added it to the system because people might be surprised about me removing such a lot used thing.
No, it is not required.
Yes, it is part of the system.

Edit: I realized you uploaded a new version today. I had a look at the one from yesterday. (already downloaded it :s)
I uploaded 2 versions today :D 2.0 and 2.0.1 (difference is that events would be hard to use if you would have 2 as before, 1 as on and 0 as after.
You might know why ;)
But still... I didn't upload a version yesterday...


You should note to copy the header functions in the "How to install" part.

You partially leak in your demonstration examples.
Even they are examples, user might want to copy your example and take usage of it.

Will do.

Only check to turn off your periodic trigger onDestroy, not onPeriod.
I feel so stupid -_-
It was my intention to make one function that would catch all forms of remove/dispell/expire/etc but didn't thought about it to let that one turn the loop off.


I think he's going for the layman's term of cleaning leaks, maybe that's why the function was named thus.

I went for the... who?

EDIT: Oh yea. I also made triggers of the functions because I didn't want to put massive code in the header file...
People who use vJASS know that they can also call the functions after they added library keys.

One question about hashtables.
In the header file, you can see how I save additional data to an EOT.
However, do I can only clear the child of a hashtable.
Is how I save the values properly?
 
Last edited:
So how do I not let them create them on their own?
The GUI will automatically create unknown variables if used in a trigger.
User need to have this feature enabled, then he can just copy a trigger, which includes all variables into his map.

About duration. Is "0" also for infinite duration? It probably should be, as it's the same for default OE data.

I thought that it would be more GUI friendly... especially for the ones that return a boolean like Get Data.
But user won't touch this part of the system? It'll simplify it. :)
And you only have to ensure the functions are above the functions inwhich you call them.

About flushing in hashtable. You save data under [parentKey, childKey].
Imagine parentKey is row, childKey is column for example.
If you use native FlushChildHashtable takes hashtable table, integer parentKey returns nothing
you will flush each cell in the row of given parentKey.
native FlushParentHashtable takes hashtable table returns nothing will just flush all cells in any row/column.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
About duration. Is "0" also for infinite duration? It probably should be, as it's the same for default OE data.
I suppose it could... however it does not make any difference in the configuration as the Null_Variables (Default_Variables <<< will be changed) sets the duration to -1 as a standard.
I had to use some buffer because -0.03 on 0.01 would reduce the remaining duration to -0.02 which is below 0. It will never reach -1. though.
But yes those are different variables... will change it.

But user won't touch this part of the system? It'll simplify it. :)
And you only have to ensure the functions are above the functions inwhich you call them.
So non-vJASS users have to put it in the header file.
I suppose that vJASS users can put library keywords around the whole EOT_System trigger and they know that there is no functional difference between running a trigger and calling (all) it's functions.
But again, my resources are all non-vJASS and GUI friendly... at least I try :D
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Update 2.1

I just released version 2.1

Here are the changes:
  • Replaced redundant code with "EOT_Check_For_New_Target".
  • Changed the name of "EOT_Null_Variables" to "EOT_Set_Default_Variables" which makes more sense.
  • Added a disabled trigger with all GUI variables.
  • Now has a better order of which event/check is called first in the looping action.
  • Now you don't have to set the hidden parameter in the creation. Just leaving the buff open is enough.
  • Removed some bugs where ids would be changed.

This is the final main update.
All updates after this one are (bug)fixes.
 
set udg_EOT_Param_Remaining_Interval = udg_EOT_Param_Remaining_Interval + udg_EOT_Param_Interval
^Why not just
set udg_EOT_Param_Remaining_Interval = udg_EOT_Param_Interval

JASS:
if udg_EOT_Amount < 0 then
    set udg_EOT_Amount = -1 // seems redundant
    call PauseTimer(udg_EOT_Timer)
endif
^Read comment.

The SaveData event? How is it useful?

In demo map. When I trained the critical strike aura, it periodicly gets added/removed for all units.
You just can see it because of the appearing and disappearing buff icon.
Also when it disappears, and hero is about to use his skill points, the ability menu will just close.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
set udg_EOT_Param_Remaining_Interval = udg_EOT_Param_Remaining_Interval + udg_EOT_Param_Interval
^Why not just
set udg_EOT_Param_Remaining_Interval = udg_EOT_Param_Interval

Well... imagine the interval is 1 second... seems to be used a lot too.
Interval = 1.00
Interval = 0.97
Interval = 0.94
Interval = 0.91
...
Interval = 0.10
Interval = 0.07
Interval = 0.04
Interval = 0.01
Interval = -0.02 -> 1
Then the next interval will be called 1 second after the 0.02 second difference.
It will be called 0.02 seconds too late. (Which has no difference... YET!)
Lets do that again... and again... and again... and again.
Now the difference is 0.1
The difference is small but it is bad too.

JASS:
if udg_EOT_Amount < 0 then
    set udg_EOT_Amount = -1 // seems redundant
    call PauseTimer(udg_EOT_Timer)
endif
^Read comment.
Yea I kinda was afraid that I would have some bug that an EOT could be destroyed twice... so the amount would be -2... so the first new EOT would be denied... destroyed... amount is -2 again.
But because I made that function catch all possible destroys... that cannot happen.
That is kinda why it is there... will remove it though.

The SaveData event? How is it useful?
This event is made for extensions to know when a trigger called the "Save Data" function.
Check DOT Extension for example.

In demo map. When I trained the critical strike aura, it periodicly gets added/removed for all units.
You just can see it because of the appearing and disappearing buff icon.
Also when it disappears, and hero is about to use his skill points, the ability menu will just close.
I had that problem too... until I fixed it.
I made a mistake in the configuration but as I said... I fixed it... at least I thought I did.

EDIT: Fixed the Critical Strike Aura.
  • Critical Strike Effect
    • Events
      • Game - EOT_Event_On_Interval becomes Equal to 0.00
    • Conditions
    • Actions
      • Set TempAbility = Critical Strike Aura (Death Knight)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • EOT_Param_Type Not equal to (Real(TempInteger)) <<<<< Changed!
        • Then - Actions
          • Skip remaining actions
        • Else - Actions
      • Custom script: call EOT_Save_To_Cache(0)
      • Set TempLocation = (Position of EOT_Param_Target)
      • Set TempUnit = EOT_Param_Source
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units within 900.00 of TempLocation) and do (Actions)
        • Loop - Actions
          • Custom script: call EOT_Set_Default_Variables()
          • Set EOT_Param_Target = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (EOT_Param_Target is A structure) Equal to False
              • (EOT_Param_Target belongs to an ally of (Owner of TempUnit)) Equal to True
              • (EOT_Param_Target is alive) Equal to True
            • Then - Actions
              • Set EOT_Param_Type = ((Real(TempInteger)) + 0.10) <<<<< Changed!
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Evaluate EOT_Trigger_Get_Data conditions) Equal to True
                • Then - Actions
                  • Set EOT_Param_Remaining_Duration = 2.00
                  • Set EOT_Param_Ability_Level = (Level of Critical Strike Aura (Death Knight) for TempUnit)
                  • Trigger - Run EOT_Trigger_Save_Data (ignoring conditions)
                • Else - Actions
                  • Set EOT_Param_Source = TempUnit
                  • Set EOT_Param_Target = (Picked unit)
                  • Set EOT_Param_Duration = 2.00
                  • Set EOT_Param_Interval = -1.00
                  • Set EOT_Param_Buff = Custom Critical Strike Aura
                  • Set EOT_Param_Buff_Holder = Critical Strike (Buff Holder)
                  • Set EOT_Param_Ability = Critical Strike Aura (Spell Book)
                  • Set EOT_Param_Ability_Level = (Level of Critical Strike Aura (Death Knight) for TempUnit)
                  • Set EOT_Param_Positive = True
                  • Set EOT_Param_Special_Effect_Model = Abilities\Spells\Orc\SpiritLink\SpiritLinkTarget.mdl
                  • Set EOT_Param_Type = ((Real(TempInteger)) + 0.10)
                  • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
            • Else - Actions
      • Custom script: call RemoveLocation(udg_TempLocation)
      • Custom script: call EOT_Load_From_Cache(0)
However someone told me another bug: What if the Death Knight dies as long as he has the Critical Strike Aura on.
Then he won't have that effect any more.

So I will add a passive function.

--------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------

I just released version 2.2

Here are the changes:
  • Changed the variable type of EOT_Type from real to integer.
  • Fixed a bug where the Id would be changed to the highest current Id. When an eot would be destroyed.
  • Added Is_Passive and Destroy_Passive.

--------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------

I just released version 2.2.1

Here are the changes:
  • Fixed a bug where the game would crash when a dead unit would gain an EOT.
 
Last edited:
First sorry you guys have to wait long time sometimes in spell section.

To check if a unit is dead, don't make
IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0
, but:
IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0

You don't necessarily need so much triggers. Don't forget you also can just directly call functions.

Why you always do like this:
JASS:
//Call the event.
set udg_EOT_Event_Creation_Before = 1 //<<< don't use
set udg_EOT_Event_Creation_Before = 0 //<<< use this
set udg_EOT_Event_An_EOT_Is_Created = 1 //<<< don't use
set udg_EOT_Event_An_EOT_Is_Created = 0 //<<< use this
set udg_EOT_Event_Creation_After = 1 //<<< don't use
set udg_EOT_Event_Creation_After = 0 //<<< use this
Why is one event not enough? Why user needs to have 3 of them directly after each other?
I can imagine he/she could easily handle all combined, or I'm wrong?
If it's needed to keep for you, it might be more logical in "destroy" function to fire the "after destruction" event after things are done. Like ability/buff/effect was removed. (?)

I could imagine "Set EOT_Param_Type" might be not easy to use/clear to understand for the normal GUI user.
I probably would explain it a bit better what you do there exactly. Else it might be like: "huh ability? huh integer? wtf should I do here?" :D

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.

Examples are always good. And you made several examples. But it's also very helpful if there are some descriptive comments here and there.

Positive is the system might be widely used. User can make many things with it.
Negative is, it's not very straight forward. It caers about many aspects, and maybe will almost always have an overhead.

But I see you've put a lot of effort into it, it's noticeable. I think the general GUI user would need some time to get used to it, but once he understood all it might assist him for his effects pretty good.

I know you will update the death check pretty soon, that I mentioned in first point so I'll directly approve this. :csmile:

Approved.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
First sorry you guys have to wait long time sometimes in spell section.
Don't worry, it is very understandable.

To check if a unit is dead, don't make
IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0
, but:
IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0
Uhm... no?
There are 4 different situations:
IsDead + 0
IsDead + !0
NotDead + 0
NotDead + !0
The last one is easy: A unit exist and is not dead.
The third one is probably impossible :D
The second one: A unit exist and is dead.
The first one: A unit doest exists and so is dead.

The only one that I use is the second which results in a dead existing unit... or not.
When units don't exist they have different behaviour.

You don't necessarily need so much triggers. Don't forget you also can just directly call functions.
I don't want to use vJASS so library tags will not be in it.
I don't want to put it in the header file so it will not be there either.
I don't want to force people to recreate all triggers that they have in their map when they installed my system and even then, trigger order things turn out to be really weird when I tried them.
So yea I do need that many (5) triggers.

Why you always do like this:
JASS:
//Call the event.
set udg_EOT_Event_Creation_Before = 1 //<<< don't use
set udg_EOT_Event_Creation_Before = 0 //<<< use this
set udg_EOT_Event_An_EOT_Is_Created = 1 //<<< don't use
set udg_EOT_Event_An_EOT_Is_Created = 0 //<<< use this
set udg_EOT_Event_Creation_After = 1 //<<< don't use
set udg_EOT_Event_Creation_After = 0 //<<< use this
Why is one event not enough? Why user needs to have 3 of them directly after each other?
I can imagine he/she could easily handle all combined, or I'm wrong?
If it's needed to keep for you, it might be more logical in "destroy" function to fire the "after destruction" event after things are done. Like ability/buff/effect was removed. (?)
Well, the before and after events are pretty much for extentions and stuff.
Spells and other effects should only use the middle one.
I could change all events and switch to my Event Management System but that would mean JASS all over the place.
Next to that, the event systems isn't even complete.

I could imagine "Set EOT_Param_Type" might be not easy to use/clear to understand for the normal GUI user.
I probably would explain it a bit better what you do there exactly. Else it might be like: "huh ability? huh integer? wtf should I do here?" :D
Yea I think I could... In fact is is the "EOT_Type_Id" of the EOT.
It is set to an integer and in most cases being the abilityid of the ability being cast and that number can only be retrieved by JASS.
Dunno how to explain it better than that.

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.
Hmm... I thought about setting the Interval variable to the type and setting the interval triggers to have an event to that amount but then again, I still have to use JASS to add the events to every single trigger.
Having triggers to be added to an EOT was how it was in 1.0 until 2.0 but then you had to place all effects in one trigger for each EOT.
I wanted to have an event... I will try to find a better solution anyway.

Examples are always good. And you made several examples. But it's also very helpful if there are some descriptive comments here and there.
-_- damn son. Hoped noone would say that.

Positive is the system might be widely used. User can make many things with it.
Negative is, it's not very straight forward. It caers about many aspects, and maybe will almost always have an overhead.
An overhead?
Yea it is quite heavy for people who want to do simple things with it but indeed it can do more than even I have thought of.

But I see you've put a lot of effort into it, it's noticeable. I think the general GUI user would need some time to get used to it, but once he understood all it might assist him for his effects pretty good.
Yea, the users really need something to learn about how it is used but once they do... :D

And in what kind of weird fantasy world of yours is this a spell?

For real, Systems that have visual things become more clear with screenshots etc but in here there isn't much visuals added to it. Yes you CAN add a special effect, buff or ability to a unit but that is a situational property.
The most usefull EOTs have no buff, have no special effect and have no ability.
They are completely invisible but they have a functional effect.

I can add screenshots a bit about what it can do but am pretty busy these days.
All other systems of mine also have no screenshots and I will add them... when I actually have the time and the will to do it :D
 
Uhm... no?
There are 4 different situations:
IsDead + 0
IsDead + !0
NotDead + 0
NotDead + !0
The last one is easy: A unit exist and is not dead.
The third one is probably impossible :D
The second one: A unit exist and is dead.
The first one: A unit doest exists and so is dead.

The only one that I use is the second which results in a dead existing unit... or not.
When units don't exist they have different behaviour.
You explain situations with "and", but with "or" it would make sense to me.
Or unit is dead, or unit does not exist -> do actions. (onInterval, for example you use it)
Not?

No vJASS needed. In jass a function can be called if it's above the caller function.
native ExecuteFunc takes string funcName returns nothing
would also exist, but is probably not needed here.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
When a unit is dead, the effect still must remain on the unit if it is a passive... until the unit is removed from the map.
That is why I need the difference between "A unit doesn't exist" and "An existing unit is dead".

But ExecuteFunc() will become slow, the more functions exist in the map...
And when it is above the call, I do require people to remake all triggers that use it that are made after the import of the system... and even then, my tests about calling functions from other triggers do weird things after saving maps.
 
Level 10
Joined
Aug 21, 2010
Messages
316
JASS:
function DOT_Deal_Damage takes nothing returns boolean
    if udg_DOT_Damage <= 0. then
        return false
    endif
    
    call UnitDamageTarget(udg_EOT_Param_Source, udg_EOT_Param_Target, udg_DOT_Damage, true, false, udg_DOT_Attack_Type, udg_DOT_Damage_Type, WEAPON_TYPE_WHOKNOWS)
    
    return false
endfunction

->

JASS:
function DOT_Deal_Damage takes nothing returns boolean
    if udg_DOT_Damage <= 0. then
        return false
    endif
    return UnitDamageTarget(udg_EOT_Param_Source, udg_EOT_Param_Target, udg_DOT_Damage, true, false, udg_DOT_Attack_Type, udg_DOT_Damage_Type, WEAPON_TYPE_WHOKNOWS)
endfunction
 
Level 6
Joined
Feb 6, 2015
Messages
266
Hello, After adding a similar spell to Critical strike aura. with exactly the same order of triggers shown in ur spell. The map doesn't start now. If I delete the triggers, it works fine. But once I put the triggers in, the map turns black and stays like that.

What can be the cause of this ?
 
Level 6
Joined
Feb 6, 2015
Messages
266
  • Paladin Presence
    • Events
      • Unit - A unit Learns a skill
    • Conditions
    • Actions
      • Custom script: set udg_TempAbility = GetLearnedSkill()
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • TempAbility Equal to Paladin Presence
        • Then - Actions
          • Custom script: call EOT_Set_Default_Variables()
          • Set EOT_Param_Source = (Triggering unit)
          • Set EOT_Param_Target = (Triggering unit)
          • Set EOT_Param_Interval = 1.00
          • Set EOT_Param_Hidden = True
          • Set EOT_Param_Ability = Paladin Presence
          • Set EOT_Param_Special_Effect_Model = Abilities\Spells\Undead\VampiricAura\VampiricAura.mdl
          • Set EOT_Param_Positive = True
          • Set EOT_Param_Can_Dispell = False
          • Set EOT_Param_Is_Passive = True
          • Custom script: set udg_TempInteger = udg_TempAbility
          • Set EOT_Param_Type = TempInteger
          • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
        • Else - Actions
  • Paladin Presence Effect
    • Events
      • Game - EOT_Event_On_Interval becomes Equal to 0.00
    • Conditions
    • Actions
      • Set TempAbility = Paladin Presence
      • Custom script: set udg_TempInteger = udg_TempAbility
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • EOT_Param_Type Equal to TempInteger
          • EOT_Param_Subtype Equal to 0
        • Then - Actions
          • Custom script: call EOT_Save_To_Cashe(0)
          • Set TempLocation = (Position of EOT_Param_Target)
          • Set TempUnit = EOT_Param_Source
          • Custom script: set bj_wantDestroyGroup = true
          • Unit Group - Pick every unit in (Units within 900.00 of TempLocation) and do (Actions)
            • Loop - Actions
              • Custom script: call EOT_Set_Default_Variables()
              • Set EOT_Param_Target = (Picked unit)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (EOT_Param_Target is A structure) Equal to False
                  • (EOT_Param_Target belongs to an ally of (Owner of TempUnit)) Equal to True
                  • True Equal to True
                • Then - Actions
                  • Set EOT_Param_Type = TempInteger
                  • Set EOT_Param_Subtype = 1
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Evaluate EOT_Trigger_Get_Data conditions) Equal to True
                    • Then - Actions
                      • Set EOT_Param_Remaining_Duration = 2.00
                      • Set EOT_Param_Ability_Level = (Level of Paladin Presence for TempUnit)
                      • Trigger - Run EOT_Trigger_Save_Data (ignoring conditions)
                    • Else - Actions
                      • Set EOT_Param_Source = TempUnit
                      • Set EOT_Param_Target = (Picked unit)
                      • Set EOT_Param_Duration = 2.00
                      • Set EOT_Param_Interval = -1.00
                      • Set EOT_Param_Buff = Paladin's Presence
                      • Set EOT_Param_Buff_Holder = Paladin Presence
                      • Set EOT_Param_Ability = Paladin Presence
                      • Set EOT_Param_Ability_Level = (Level of Paladin Presence for TempUnit)
                      • Set EOT_Param_Positive = True
                      • Set EOT_Param_Special_Effect_Model = Abilities\Spells\Undead\VampiricAura\VampiricAura.mdl
                      • Set EOT_Param_Type = TempInteger
                      • Set EOT_Param_Subtype = 1
                      • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
                • Else - Actions
          • Custom script: call RemoveLocation(udg_TempLocation)
          • Custom script: call EOT_Load_From_Cashe(0)
        • Else - Actions
See any problem ?
 
Level 7
Joined
Aug 11, 2010
Messages
269
I love this! It's like your missile system, very useful. Unfortunately, though. I'm having a few issues with it. When I first cast the spell I'm making (Initial damage, heals based off damage dealt over time) the spell works perfectly fine however, after the first cast it ceases to work. It's very strange.

  • HFBIND Cauterize Effect
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to [Hero - Flamebinder] Cauterize - (W)
    • Actions
      • -------- - - - EOT Clear Variables - - - --------
      • Custom script: call EOT_Set_Default_Variables()
      • -------- - - - Set Important Variables - - - --------
      • Set TempRealArray[1] = ((Life of (Triggering unit)) x 0.25)
      • Set TempRealArray[2] = (TempRealArray[1] x (1.40 + (0.40 x (Real((Level of [Hero - Flamebinder] Cauterize - (W) for (Triggering unit)))))))
      • Set TempReal = (TempRealArray[2] / 8.00)
      • Custom script: call EOT_Save_Real(0, udg_TempReal)
      • -------- - - - Spell Effect - - - --------
      • Unit - Cause (Triggering unit) to damage (Triggering unit), dealing TempRealArray[1] damage of attack type Chaos and damage type Universal
      • -------- - - - EOT Set Basic Variables - - - --------
      • Set EOT_Param_Source = (Triggering unit)
      • Set EOT_Param_Target = EOT_Param_Source
      • Set EOT_Param_Duration = 8.00
      • Set EOT_Param_Interval = 1.00
      • -------- - - - EOT Buff Holder - - - --------
      • Set EOT_Param_Buff = [Custom] - Cauterize - (Flamebinder)
      • Set EOT_Param_Buff_Holder = [Buff Holder] Cauterize
      • -------- - - - EOT Get Param Type ID - - - --------
      • Set TempAbility = (Ability being cast)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • Set EOT_Param_Type = TempInteger
      • -------- - - - EOT Set Advanced Variables - - - --------
      • Set EOT_Param_Positive = True
      • -------- - - - EOT Run EOT - - - --------
      • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
      • -------- - - - - - - - - - - - - --------
  • HFBIND Cauterize EOT
    • Events
      • Game - EOT_Event_On_Interval becomes Equal to 0.00
    • Conditions
    • Actions
      • -------- - - - - - - - - - - - - --------
      • Set TempAbility = [Hero - Flamebinder] Cauterize - (W)
      • Custom script: set udg_TempInteger = udg_TempAbility
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • EOT_Param_Type Equal to TempInteger
          • EOT_Param_Subtype Equal to 0
        • Then - Actions
          • Custom script: call EOT_Save_To_Cache(0)
          • Set TempUnit = EOT_Param_Target
          • Custom script: set udg_TempReal = EOT_Load_Real(0)
          • Set NextHealTarget = TempUnit
          • Set NextHealAmount = TempReal
          • Trigger - Run SYS Heal Unit <gen> (ignoring conditions)
          • Custom script: call EOT_Load_From_Cache(0)
        • Else - Actions
      • -------- - - - - - - - - - - - - --------
Can anyone help me with this issue? I have a hunch that it might be EOT_Load_Real and EOT_Save_Real related.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Your problem lies indeed in the custom values.
According to the documentation:
JASS:
//      7. Create additional effects.
//          Since you created an EOT, you also have an id.
//          With this id, you can save data in the hashtable using the EOT_Save_Value (Value being the value type) functions.
This step is done after the creation of the effect.
So the custom script that stores the healing value has to be after the trigger call that creates the effect.
It sounds a bit silly to add values to something that doesnt yet exist right? At least so it did for me.
  • -------- create the EOT --------
  • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
  • Custom script: call EOT_Save_Real(0, udg_TempReal)
The thing that it works correctly the first cast is probably because of the id value that is used for the very first EOT and the default value of the variables that are used.
But in any case, just use those functions after the trigger call and you will be fine.

I thought I fixed the issue that intervals calculated properly, but it seems that I missed to upload that.
In any case, make the duration 8.01 seconds instead of 8 seconds so the interval trigger will run 8 times instead of 7 times while still having technically the same duration.
 
Level 7
Joined
Aug 11, 2010
Messages
269
Your problem lies indeed in the custom values.
According to the documentation:
JASS:
//      7. Create additional effects.
//          Since you created an EOT, you also have an id.
//          With this id, you can save data in the hashtable using the EOT_Save_Value (Value being the value type) functions.
This step is done after the creation of the effect.
So the custom script that stores the healing value has to be after the trigger call that creates the effect.
It sounds a bit silly to add values to something that doesnt yet exist right? At least so it did for me.
  • -------- create the EOT --------
  • Trigger - Run EOT_Trigger_Create_EOT (ignoring conditions)
  • Custom script: call EOT_Save_Real(0, udg_TempReal)
The thing that it works correctly the first cast is probably because of the id value that is used for the very first EOT and the default value of the variables that are used.
But in any case, just use those functions after the trigger call and you will be fine.

I thought I fixed the issue that intervals calculated properly, but it seems that I missed to upload that.
In any case, make the duration 8.01 seconds instead of 8 seconds so the interval trigger will run 8 times instead of 7 times while still having technically the same duration.

Oh wow. You're right, that fixed it. I feel relatively silly that it was such a simple fix. I guess it makes sense, yeah. I guess I just didn't really think much about it, though.

Also thanks for the tip with the duration things, I wouldn't have noticed there was a missing tick unless you did.
 
Top