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

Debugging: how-to log all trigger executions?

Status
Not open for further replies.
Hello,

I am trying to debug a desync issue. For this I am already doing hooks on functions known for causing desync that write logs in a local file.

However, I'd like to also log trigger executions. This way I may be able to know what last triggers execute before desync.

Do you know how I can do that ?

Would a hook on "TriggerExecute" and/or "TriggerEvaluate" catch all trigger executions ?


Plus, from a hook with parameter "trigger whichTrigger", how could I get the trigger name ? I don't see any native to get the name of a trigger..

Thanks in advance for your advices :)
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
Would a hook on "TriggerExecute" and/or "TriggerEvaluate" catch all trigger executions ?
No, a trigger actually triggered by its event doesn't use either execute or evaluate. You will have to log this information yourself manually by adding a couple extra lines to each trigger.
how could I get the trigger name ?
You can't, there's no native for this. However, this is a case where GUI does something worthwhile that you can take advantage of. There is a "Name of the current trigger" string that is populated with the proper name of the trigger at compile time. For triggers that are already in GUI you can use this directly, but for JASS triggers you will have to name them yourself.
  • Actions
    • -------- put first in the trigger actions --------
    • Set TrigName = (Name of the current trigger)
    • Set ExecTime = (Elapsed time of GAMETIMECLOCK) //start a timer on map init for max duration and you can use it to timestamp your trigger executions, just a suggestion
    • Custom script: call DoWhateverToLogThisInfo(udg_TrigName, udg_ExecTime)
JASS:
call DoWhateverToLogThisInfo("your trigger name here", TimerGetElapsed(udg_GAMETIMECLOCK))
 
No, a trigger actually triggered by its event doesn't use either execute or evaluate. You will have to log this information yourself manually by adding a couple extra lines to each trigger.

You can't, there's no native for this. However, this is a case where GUI does something worthwhile that you can take advantage of. There is a "Name of the current trigger" string that is populated with the proper name of the trigger at compile time. For triggers that are already in GUI you can use this directly, but for JASS triggers you will have to name them yourself.
  • Actions
    • -------- put first in the trigger actions --------
    • Set TrigName = (Name of the current trigger)
    • Set ExecTime = (Elapsed time of GAMETIMECLOCK) //start a timer on map init for max duration and you can use it to timestamp your trigger executions, just a suggestion
    • Custom script: call DoWhateverToLogThisInfo(udg_TrigName, udg_ExecTime)
JASS:
call DoWhateverToLogThisInfo("your trigger name here", TimerGetElapsed(udg_GAMETIMECLOCK))

Thanks, it is as I thought :(
 
I am still stuck, I'd really need a way to Get current trigger name.

Indeed I just discovered that one can hook the two following functions:
- TriggerAddCondition
- TriggerAddAction

So it is quite easy to add a log action to every trigger in the map automatically (just be careful of avoiding infinite loop), like:

Code:
    public function TriggerLogAction takes nothing returns nothing
            call DisplayTimedTextToForce( GetPlayersAll(), 3.00, "Xxxxxxxxxxxxxxxxxxxx" )
    endfunction

    public function onTriggerAddAction takes trigger whichTrigger, code actionFunc returns nothing
        if ( actionFunc != function TriggerLogAction ) then
            call TriggerAddAction(whichTrigger, function TriggerLogAction)
        endif
    endfunction

    hook TriggerAddAction onTriggerAddAction

However this is useless if I cannot log or write in file any information that identifies the trigger being executed...
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
Get current trigger name.
Triggers have no name.
However this is useless if I cannot log or write in file any information that identifies the trigger being executed...
In general Lua the debug functions can be used for this. However all debug functions are disabled in Wacraft III as far as I am aware.
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
if all triggers are created in gui or at map init their handleIds should be the same over multiple runs.
Unfortunately this is not true. Here's a sample of the generated main() function from a custom map in my folder:
JASS:
function main takes nothing returns nothing
    call SetCameraBounds(- 3328.0 + GetCameraMargin(CAMERA_MARGIN_LEFT), - 3584.0 + GetCameraMargin(CAMERA_MARGIN_BOTTOM), 3328.0 - GetCameraMargin(CAMERA_MARGIN_RIGHT), 3072.0 - GetCameraMargin(CAMERA_MARGIN_TOP), - 3328.0 + GetCameraMargin(CAMERA_MARGIN_LEFT), 3072.0 - GetCameraMargin(CAMERA_MARGIN_TOP), 3328.0 - GetCameraMargin(CAMERA_MARGIN_RIGHT), - 3584.0 + GetCameraMargin(CAMERA_MARGIN_BOTTOM))
    call SetDayNightModels("Environment\\DNC\\DNCLordaeron\\DNCLordaeronTerrain\\DNCLordaeronTerrain.mdl", "Environment\\DNC\\DNCLordaeron\\DNCLordaeronUnit\\DNCLordaeronUnit.mdl")
    call NewSoundEnvironment("Default")
    call SetAmbientDaySound("LordaeronSummerDay")
    call SetAmbientNightSound("LordaeronSummerNight")
    call SetMapMusic("Music", true, 0)

    //regions and units are created here
    call CreateRegions()
    call CreateAllUnits()
    call InitBlizzard()

// Initalizers happen here
call ExecuteFunc("jasshelper__initstructs88292093")
call ExecuteFunc("DamagedEventAdder__init")
call ExecuteFunc("othertestes__init")

// Globals happen here
    call InitGlobals()

// ==== TRIGGERS CREATED HERE
    call InitCustomTriggers()
// ==== TRIGGERS CREATED HERE

    call RunInitializationTriggers()

endfunction
So any changes to the replaced units, preplaced regions, or any scope/library/module initializers that allocate handles will change the assigned handle ID for the triggers. Also any globals like groups and timers that default to an allocated handle simply existing will change the handle id.
 
Are function & variable names also lost in the last steps of compilation ? Where the .j becomes a binary files. Private & public ones ?
Is there any JASS type that we can dump ? :)

Mhh...

At first, I could hook the following functions:

- TriggerRegisterXXXXXXEventXXXX
- TriggerAddCondition
- TriggerAddAction
Then save in a hashtable, with the trigger handle id as key, the events count & types, conditions count & actions count. Log them when the trigger is first executed.

- TriggerExecute
- TriggerEvaluate
And log that the trigger has been manually called.

- TriggerAddCondition
- TriggerAddAction
And add a "log" action to the trigger that would display "Trigger <handleid> executed".

However this is still very tough for the developper to retrieve the matching trigger...
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
I just thought of a possible solution.

One can iterate through the Lua main name space node and resolve all the functions in key (function name) value (function value) pairs. These values will be the same as the ones that get passed to the trigger and timer registration functions and hence one can perform an inverse map lookup to get the associated function name from the function value at the time the registration proxy function is called. This function name can then be mapped to the trigger or timer value and so from the trigger or timer value, which one can get from threads the trigger or timer spawns, one can get the associated function names that were registered to it and print or log these.
 
I just thought of a possible solution.

One can iterate through the Lua main name space node and resolve all the functions in key (function name) value (function value) pairs. These values will be the same as the ones that get passed to the trigger and timer registration functions and hence one can perform an inverse map lookup to get the associated function name from the function value at the time the registration proxy function is called. This function name can then be mapped to the trigger or timer value and so from the trigger or timer value, which one can get from threads the trigger or timer spawns, one can get the associated function names that were registered to it and print or log these.

The concept looks nice ! However I don't know LUA yet. It is a script language that compiles to JASS right isn't ?
So what you say here only applies to maps fully made in LUA ?
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
It is a script language that compiles to JASS right isn't ?
No it is an alternative virtual machine for Warcraft III to use. WC3 can either run a map with the JASS virtual machine or with the Lua virtual machine. These need the script to be completely in the appropriate language.
So what you say here only applies to maps fully made in LUA ?
Yes everything discussed here only applies to maps using the Lua virtual machine.
 
Level 12
Joined
Feb 22, 2010
Messages
1,115
Unfortunately this is not true. Here's a sample of the generated main() function from a custom map in my folder:
JASS:
function main takes nothing returns nothing
    //  long jass code here
endfunction
So any changes to the replaced units, preplaced regions, or any scope/library/module initializers that allocate handles will change the assigned handle ID for the triggers. Also any globals like groups and timers that default to an allocated handle simply existing will change the handle id.
I think what Tasyen wanted to say is handle id of the triggers with respect to each other will always be same, if you create another object within the map that might change the starting offset but distance between handle id of any two triggers will remain same.
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
I think what Tasyen wanted to say is handle id of the triggers with respect to each other will always be same, if you create another object within the map that might change the starting offset but distance between handle id of any two triggers will remain same.
Yeah that’s reasonable and probably true.

Variable names are not available in any way either. DSG’s suggestion requires the whole map script to be Lua (no JASS whatsoever), so if you can’t/won’t transpile all existing code then your only option is to provide each trigger/timer with a string variable identifying the function name or handle name associated with the action. You can save these in a hashtable with the associated handle’s ID as a key, then retrieve it and print it whenever appropriate.

With some textmacroes, automatically printing this information could be relatively simple. You could wrap TriggerAddAction and TriggerAddCondition to also add an additional action/condition function first that prints the trigger name (and checks to see if this action/condition has already been added to the trigger and if so skips adding it multiple times).
 
Level 39
Joined
Feb 27, 2007
Messages
5,010
Here, I felt that this would be a fun project so I made something relatively simple that can show trigger evaluation/execution info:
JASS:
library Monitor initializer init
  //==========================================================================================
  //    Monitor - v1.0 - 9/24/19
  //       by Pyrogasm
  //
  // Have you wondered what the last trigger run before an error was? Did you wish you could
  // see a printout of what ran when and how many times? Have you always wanted to name your
  // triggers? Well... sometimes I have, but mostly Ricola3D has so I made this for them. If
  // this interests you or sounds like it might help, you should use this system to aid in
  // your debugging quest.
  //
  // It requires one small change on your part:
  // For any trigger you wish to register with Monitor, you must replace all calls to
  //       CreateTrigger()
  // with
  //       Monitor_CreateTrigger("your trigger name here")
  // which still returns the created trigger as the vanilla function does.
  //
  // The system automatically detects when you call TriggerAddCondition and TriggerAddAction
  // and assigns its own TC/TA first before the first time you use them on a trigger so that
  // its functions are called right before any of the trigger's real TCs and TAs. It requires
  // no further input from you.
  //
  // Data is automatically cleaned when using DestroyTrigger, TriggerClearActions, and
  // TriggerClearConditions, no input required.
  //
  // Monitor can output the following information immediately before that trigger's
  // Conditions or Actions are evaluated/executed:
  //  - Name of the trigger
  //  - Execution count of the conditions/actions since the trigger was created
  //  - Timestamp (in seconds since map init) at which the conditions/actions were run
  //
  // Monitor features two further functions you may find useful in your debugging quest:
  //  - Monitor_GetTriggerName(triggerVariable)
  //  - Monitor_DumpLast(triggerVariable)
  //    This prints the most recently stored information about execution count & timestamp
  //
  // If you have further questions, contact me directly by PM at hiveworkshop.com
  // Anyone is free to use all or part of this resource for any reason, all I ask
  // is that you credit me with the original code.
  //
  //==========================================================================================


  globals
    //These globals enable/disable tracking & printing of various parts of the system (compiletime static ifs)
    private constant boolean DO_CONDITIONS = true
    private constant boolean DO_ACTIONS    = true
    private constant boolean DO_TIMESTAMP  = true
    private constant boolean DO_EXEC_COUNT = true
   
    //This global enables/disables the system entirely while keeping the Monitor_CreateTrigger calls functional (compiletime static ifs)
    private constant boolean ENABLED = true
    private keyword ht
  endglobals
 
  globals
    //Probably don't fuck with these
    private hashtable ht
    private timer clock
    private boolexpr cPrint
    private code     aPrint
    private boolean  recursion = false
   
    private constant integer KEY_NAME   = 1
    private constant integer KEY_COND   = 2
    private constant integer KEY_ACT    = 3
    private constant integer KEY_TIME_C = 4
    private constant integer KEY_TIME_A = 5
    private constant integer KEY_EXEC_C = 6
    private constant integer KEY_EXEC_A = 7
  endglobals
 
  //====================
  //  PUBLIC FUNCTIONS  
  //====================
 
  // This function has to have no public/private prefix because of how I've named it;
  // calling it 'public function CreateTrigger' would produce a namespace conflict.
  function Monitor_CreateTrigger takes string triggerName returns trigger
    local trigger t = CreateTrigger()
   
    static if ENABLED then
      local integer ind = GetHandleId(t)
      call FlushChildHashtable(ht, ind) //probably not necessary
      call SaveStr(ht, ind, KEY_NAME, triggerName)
    endif
   
    return t
  endfunction

  public function GetTriggerName takes trigger t returns string
    local string p = LoadStr(ht, GetHandleId(t), KEY_NAME)
    static if ENABLED then
      if p == "" then
        debug call BJDebugMsg("Monitor Warning: name requested of trigger not registered with Monitor (or name left blank)")
      endif
    endif
    return p
  endfunction
 
  public function DumpLast takes trigger t returns nothing
    local integer ind = GetHandleId(t)
    local string p
   
    static if DO_CONDITIONS then
      set p = LoadStr(ht, ind, KEY_NAME)+" - dump of last condition(s):"
     
      static if DO_TIMESTAMP then
        set p = p + "\nTimestamp: "+R2S(LoadReal(ht, ind, KEY_TIME_C))
      endif
      static if DO_EXEC_COUNT then
        set p = p + "\nExec Count: "+I2S(LoadInteger(ht, ind, KEY_EXEC_C))
      endif
    endif
    call BJDebugMsg(p)
   
    static if DO_ACTIONS then
      set p = LoadStr(ht, ind, KEY_NAME)+" - dump of last action(s):"
     
      static if DO_TIMESTAMP then
        set p = p + "\nTimestamp: "+R2S(LoadReal(ht, ind, KEY_TIME_A))
      endif
      static if DO_EXEC_COUNT then
        set p = p + "\nExec Count: "+I2S(LoadInteger(ht, ind, KEY_EXEC_A))
      endif
    endif
    call BJDebugMsg(p)
  endfunction
  //====================
 
 
 
  //! textmacro MonitorInfoDump takes APPEND, DESCRIPTION
    local integer ind = GetHandleId(GetTriggeringTrigger())
    local real t
    local integer c
    local string p = LoadStr(ht, ind, KEY_NAME)+" - $DESCRIPTION$"

    static if DO_TIMESTAMP then
      set t = TimerGetElapsed(clock)
      call SaveReal(ht, ind, KEY_TIME_$APPEND$, t)
      set p = p + "\nTimestamp: "+R2S(t)
    endif
   
    static if DO_EXEC_COUNT then
      set c = LoadInteger(ht, ind, KEY_EXEC_$APPEND$) + 1
      call SaveInteger(ht, ind, KEY_EXEC_$APPEND$, c)
      set p = p + "\nExec Count: "+I2S(c)
    endif

    call BJDebugMsg(p)
  //! endtextmacro
 
  private function ConditionPrint takes nothing returns boolean
    //! runtextmacro MonitorInfoDump("C", "checking conditions:")
    return true
  endfunction
 
  private function ActionPrint takes nothing returns nothing
    //! runtextmacro MonitorInfoDump("A", "executing actions:")
  endfunction
 
  private function Monitor_TriggerAddCondition takes trigger t, boolexpr f returns nothing
    static if ENABLED and DO_CONDITIONS then
      local integer ind = GetHandleId(t)
      if not recursion and LoadBoolean(ht, ind, KEY_COND) == false then
        call SaveBoolean(ht, ind, KEY_COND, true)
        set recursion = true
        call TriggerAddCondition(t, cPrint)
        set recursion = false
      endif
    endif
  endfunction

  private function Monitor_TriggerAddAction takes trigger t, code f returns nothing
    static if ENABLED and DO_ACTIONS then
      local integer ind = GetHandleId(t)
      if not recursion and LoadBoolean(ht, ind, KEY_ACT) == false then
        call SaveBoolean(ht, ind, KEY_ACT, true)
        set recursion = true
        call TriggerAddAction(t, aPrint)
        set recursion = false
      endif
    endif
  endfunction
 
  private function Monitor_DestroyTrigger takes trigger t returns nothing
    call FlushChildHashtable(ht, GetHandleId(t))
  endfunction

  private function Monitor_TriggerClearConditions takes trigger t returns nothing
    static if ENABLED and DO_CONDITIONS then
      call RemoveSavedBoolean(ht, GetHandleId(t), KEY_COND)
    endif
  endfunction
 
  private function Monitor_TriggerClearActions takes trigger t returns nothing
    static if ENABLED and DO_ACTIONS then
      call RemoveSavedBoolean(ht, GetHandleId(t), KEY_ACT)
    endif
  endfunction
 
  private function Monitor_CreateTriggerWarning takes nothing returns nothing
    static if ENABLED then
      debug call BJDebugMsg("Monitor Warning: trigger created by native CreateTrigger without registering in the system. If you meant to do this, ignore this message.")
    endif
  endfunction

  hook CreateTrigger          Monitor_CreateTriggerWarning
  hook DestroyTrigger         Monitor_DestroyTrigger
  hook TriggerAddCondition    Monitor_TriggerAddCondition
  hook TriggerAddAction       Monitor_TriggerAddAction
  hook TriggerClearConditions Monitor_TriggerClearConditions
  hook TriggerClearActions    Monitor_TriggerClearActions
 
  private function init takes nothing returns nothing
    static if ENABLED then
      set ht = InitHashtable()
      set clock = CreateTimer()
      call TimerStart(clock, 999999999., true, null)
      set cPrint = Condition(function ConditionPrint)
      set aPrint = function ActionPrint
    endif
  endfunction
endlibrary
And here's a simple demo library to show that it works:
JASS:
library MonitorTest initializer init requires Monitor
  private function c1 takes nothing returns boolean
    call BJDebugMsg("c1")
    return true
  endfunction
 
  private function c2 takes nothing returns boolean
    call BJDebugMsg("c2")
    return true
  endfunction
 
  private function c3 takes nothing returns boolean
    call BJDebugMsg("c3")
    return true
  endfunction
 
  private function c4 takes nothing returns boolean
    call BJDebugMsg("c4")
    return true
  endfunction
 
  private function a1 takes nothing returns nothing
      call BJDebugMsg("a1")
  endfunction
 
  private function a2 takes nothing returns nothing
      call BJDebugMsg("a2")
  endfunction
 
  private function a3 takes nothing returns nothing
      call BJDebugMsg("a3")
  endfunction
 
  private function a4 takes nothing returns nothing
      call BJDebugMsg("a4")
  endfunction

  private function init takes nothing returns nothing
    local trigger t1
    local trigger t2
    local trigger t3
    local trigger t4
 
    set t1 = Monitor_CreateTrigger("trig 1")
    call TriggerAddCondition(t1, Condition(function c1))
    call TriggerAddAction(t1, function a1)

    set t2 = Monitor_CreateTrigger("trig 1")
    call TriggerAddCondition(t2, Condition(function c2))
    call TriggerAddAction(t2, function a2)
    call TriggerAddAction(t2, function a1)
 
    set t3 = Monitor_CreateTrigger("trig 1")
    call TriggerAddCondition(t3, Condition(function c3))
    call TriggerAddAction(t3, function a3)
 
    set t4 = Monitor_CreateTrigger("trig 1")
    call TriggerAddCondition(t4, Condition(function c4))
    call TriggerAddAction(t4, function a4)
 
    call TriggerSleepAction(1.0)
    call ConditionalTriggerExecute(t1)
    call ConditionalTriggerExecute(t2)
    call ConditionalTriggerExecute(t2)
    call TriggerSleepAction(1.0)
    call Monitor_DumpLast(t2)

  endfunction
endlibrary
 
Last edited:

Nice !! I was still waiting for a solution for GUI before doing anything myself.

So you made a solution for all JASS and vJASS developers that only requires to replace CreateTrigger() by Monitor_CreateTrigger("<name for logs>") right ?
Correct me if I am wrong, this is system is pure vJASS, no additionnal systems are required isn't ?

About GUI, I am thinkin about another approach (use of macros to automatically generate 1 actionfunc per trigger & gathering all of the code modifications to one place):
For the moment the only solution I can forsee would be to ask the user to add calls for a text macro manually at the end of his triggers. A macro call per global trigger. The macro will take as input the name of a trigger global variable, and create a log action function for this name and register it as a new action for the trigger variable. Stop me if this is impossible, I'm a newbie with text macros^^

The developer would have to manually update the list, and add the text macro manually each time he create a local trigger variable.

At the beginning, to help the developer, I would create an external script (shell, python or anyother langage) that you feed with your war3map.j file. It would list all global triggers with a regex search for "set gg_trg_[:alnum:]+\s?=\sCreateTrigger\(\)".

I could also add all non-anonymous local triggers with a regex search for "set [:alnum:]+\s?=\sCreateTrigger\(\)". Then it's free to the user to complete the holes thanks to this list^^

Then the script returns either a list of global variable names, either the code to copy/paste (list of calls for the macro I talke about earlier).

Do you see any simpler idea ?
 
Last edited:
Level 39
Joined
Feb 27, 2007
Messages
5,010
Yes it only works for JASS and only for triggers (not timers). GUI is much simpler.

Do you see any simpler idea ?
  • Actions
    • -------- put first in the trigger actions --------
    • Set TrigName = (Name of the current trigger)
    • Set ExecTime = String(Elapsed time of GAMETIMECLOCK) //start a timer on map init for max duration and you can use it to timestamp your trigger executions, just a suggestion
    • Game - Display to (All Players) for 60 seconds the text (Trigname + “ - ” + ExecTime)
Note this won’t work for conditions but I doubt those would be problems anyway.
 
Edit:
- I found a way to register the log action as first and remove the Init function (by using a hook on TriggerAddAction).
- Currently my logger writes in file when a user leaves or an error happens. Sadly it does not occur when the only or the last player leaves... I could not find a way to fix that for the moment.




I did the following code. It uses macro to create new actions and add them to triggers.

I used notepadd++ & some regular expression searchs to generate the list of all my global triggers and call the 2 macros for them. I could automatize it with an external script that you feed with your war3map.j.

Pros:
- All the code at the same place. Easy to maintain, edit.
- Only a few minutes to implement (if you know Notepad++ or if I do a script to help you).
- In may incude all GUI triggers, and any JASS triggers stored in a global variable. Even works for perfectionnists who use "TriggerAddCondition" instead of "TriggerAddAction" because it runs faster!
- For JASS triggers stored in local variables, you can call the macros yourself!
- One can easy replace my logger by his own code.
- We can easily improve the system, with other MACROS to declare better log actions:
- Log with trigger unit
- Log with trigger player
...​

Cons:
- Because the log happens in the 2nd trigger action, the log displays only after code execution.
- Because of the high quantity of logs:
- I decided to only write them to file when a player leaves (I have another trigger for that).
- I only keep the 8192 last log entries.​


Dependencies (you can easily replace them by your own clock & logger)

Clock System
  • Clock VariableCreator
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Countdown Timer - Start ClockTimer as a Repeating timer that will expire in 99999.00 seconds
DebugLogger
- Displays INFO/WARN/ERROR logs only to user "Ricola3".
- On player leaves, writes all logs in a text file all logs.
- Rolling logs (if more than 8192 log entries)
JASS:
library DebugLogger
    globals
        // --------------------------------------------------------------------
        // Enum log levels
        // --------------------------------------------------------------------
        public constant integer LVL_DEBUG = 0
        public constant integer LVL_INFO = 1
        public constant integer LVL_WARN = 2
        public constant integer LVL_ERROR = 3

        // --------------------------------------------------------------------
        // Config:  log limit (everything of lower level is skipped)
        // --------------------------------------------------------------------
        private constant integer LOG_LEVEL = LVL_DEBUG

        // --------------------------------------------------------------------
        // Config: display limit (everytjong of lower level is not displayed)
        // --------------------------------------------------------------------
        private constant integer DISPLAY_LEVEL = LVL_INFO

        // Logs (actualy last 8192 logs. Indexes 0 to 8191)
        private string array logs

        // Iterators to read & write in logs
        private integer firstLogIndex = -1
        private integer lastLogIndex = -1
    endglobals

    private function DebugUserFilter takes nothing returns boolean
        // Filter only players whose user name is a developer
        if ( GetPlayerName(GetEnumPlayer()) == "Ricola3D" ) then
            return true
        endif
        if ( GetPlayerName(GetEnumPlayer()) == "lajr" ) then
            return true
        endif
        return false
    endfunction

    public function WriteInFile takes string filename returns nothing
        local integer index
 
        // There are logs to write in file
        call PreloadGenClear()
        call PreloadGenStart()
        if ( (firstLogIndex != -1) and (lastLogIndex != -1) ) then
            set index = firstLogIndex
            loop
                call Preload(logs[index])
                set index = index + 1
                if ( index == 8192 ) then
                    set index = 0
                endif
                exitwhen index == lastLogIndex
            endloop
        else
            call Preload("<Empty log file>")
        endif
        call PreloadGenEnd(filename)
    endfunction

    private function InternalDebugLog takes integer level, string message returns nothing
        local force logForce
        local string color = ""
        local string formatedMessage = ""
        local string printMessage = ""
        local real elapsedTime = TimerGetElapsed(udg_ClockTimer)

        // Move last cursor
        set lastLogIndex = lastLogIndex + 1
        if ( lastLogIndex == 8192 ) then
            set lastLogIndex = 0
        endif
        // Move first cursor
        if ( (firstLogIndex) == -1 or (firstLogIndex == lastLogIndex) ) then
            set firstLogIndex = firstLogIndex + 1
        endif
        if ( firstLogIndex == 8192 ) then
            set firstLogIndex = 0
        endif

        // Prepare message format
        if (level == LVL_DEBUG) then
            set formatedMessage = "[DEBUG] "
            set printMessage = "[DEBUG] "
        elseif (level == LVL_INFO) then
            set formatedMessage = "[INFO] "
            set printMessage = "[INFO] "
        elseif (level == LVL_WARN) then
            set formatedMessage = "[WARN] "
            set printMessage = "[WARN] "
        elseif (level == LVL_ERROR) then
            set formatedMessage = "[ERROR] "
            set printMessage = "[ERROR] "
        endif

        if (level >= DISPLAY_LEVEL ) then
            // Log formating
            if (level == LVL_WARN) then
                set color = "ff7f00"
            elseif (level == LVL_ERROR) then
                set color = "ff0000"
            endif
            if (color != "") then
                set formatedMessage = formatedMessage + "|c00" + color + message +"|r"
            else
                set formatedMessage = formatedMessage + message
            endif
            set logForce = GetPlayersMatching(Condition(function DebugUserFilter))
            call DisplayTimedTextToForce( logForce, 3.00, formatedMessage )
            call DestroyForce(logForce)
            set logForce = null
        endif

        // Print formating
        set printMessage = printMessage + "[" + R2S(elapsedTime) + "] " + message

        // Save logs in a string array
        set logs[lastLogIndex] = printMessage
    endfunction

    public function DebugLog takes integer level, string message returns nothing
        if (level >= LOG_LEVEL ) then
            call InternalDebugLog(level, message)
        endif
    endfunction

    // ----------------------------------------------------------------------------
    public function onTriggerAddAction takes trigger whichTrigger, code actionFunc returns nothing
        // If somehow you find a way to log a trigger or function name, you can add another TriggerAction with log inside
    endfunction

    public function onGetDestructableName takes destructable d returns nothing
        call DebugLog(LVL_DEBUG, "GetDestructableName")
    endfunction

    public function onGetSoundDuration takes sound soundHandle returns nothing
        call DebugLog(LVL_WARN, "GetSoundDuration")
    endfunction

    public function onGetSoundFileDuration takes string musicFileName returns nothing
        call DebugLog(LVL_WARN, "GetSoundFileDuration")
    endfunction

    public function onGetCameraBoundMinX takes nothing returns nothing
        call DebugLog(LVL_WARN, "GetCameraBoundMinX")
    endfunction

    public function onGetCameraBoundMinY takes nothing returns nothing
        call DebugLog(LVL_WARN, "GetCameraBoundMinY")
    endfunction

    public function onGetCameraBoundMaxX takes nothing returns nothing
        call DebugLog(LVL_WARN, "GetCameraBoundMaxX")
    endfunction

    public function onGetCameraBoundMaxY takes nothing returns nothing
        call DebugLog(LVL_WARN, "GetCameraBoundMaxY")
    endfunction

    public function GetCameraField takes camerafield whichField returns nothing
        call DebugLog(LVL_WARN, "GetCameraField")
    endfunction

    public function onGetCameraTargetPositionX takes nothing returns nothing
        call DebugLog(LVL_WARN, "GetCameraTargetPositionX")
    endfunction

    public function onGetCameraTargetPositionY takes nothing returns nothing
        call DebugLog(LVL_WARN, "GetCameraTargetPositionY")
    endfunction

    public function onGetCameraTargetPositionZ takes nothing returns nothing
        call DebugLog(LVL_ERROR, "GetCameraTargetPositionZ")
    endfunction

    public function onGetCameraTargetPositionLoc takes nothing returns nothing
        call DebugLog(LVL_WARN, "GetCameraTargetPositionLoc")
    endfunction

    public function onGetCameraEyePositionX takes nothing returns nothing
        call DebugLog(LVL_WARN, "GetCameraEyePositionX")
    endfunction

    public function onGetCameraEyePositionY takes nothing returns nothing
        call DebugLog(LVL_WARN, "GetCameraEyePositionY")
    endfunction

    public function onGetCameraEyePositionZ takes nothing returns nothing
        call DebugLog(LVL_ERROR, "GetCameraEyePositionZ")
    endfunction

    public function onGetCameraEyePositionLoc takes nothing returns nothing
        call DebugLog(LVL_WARN, "GetCameraEyePositionLoc")
    endfunction

    public function onGetObjectName takes integer objectId returns nothing
        call DebugLog(LVL_DEBUG, "GetObjectName")
    endfunction

    public function onIsMultiboardMinimized takes multiboard lb returns nothing
        call DebugLog(LVL_ERROR, "IsMultiboardMinimized")
    endfunction

    public function onGetLocalPlayer takes nothing returns nothing
        call DebugLog(LVL_ERROR, "GetLocalPlayer")
    endfunction

    public function onGetLocationZ takes location whichLocation returns nothing
        call DebugLog(LVL_ERROR, "GetLocationZ")
    endfunction

    public function onGetLocalizedString takes string source returns nothing
        call DebugLog(LVL_DEBUG, "GetLocalizedString")
    endfunction

    public function onGetLocalizedHotkey takes string source returns nothing
        call DebugLog(LVL_DEBUG, "GetLocalizedHotkey")
    endfunction

    public function onGetUnitName takes unit whichUnit returns nothing
        call DebugLog(LVL_DEBUG, "GetUnitName")
    endfunction

    public function onBlzGetLocalUnitZ takes unit whichUnit returns nothing
        call DebugLog(LVL_ERROR, "BlzGetLocalUnitZ")
    endfunction

    public function onBlzGetUnitZ takes unit whichUnit returns nothing
        call DebugLog(LVL_ERROR, "BlzGetUnitZ")
    endfunction

    public function onGetItemName takes item whichItem returns nothing
        call DebugLog(LVL_DEBUG, "GetItemName")
    endfunction

    public function onBlzGetItemDescription takes item whichItem returns nothing
        call DebugLog(LVL_WARN, "BlzGetItemDescription")
    endfunction

    public function onBlzGetItemTooltip takes item whichItem returns nothing
        call DebugLog(LVL_WARN, "BlzGetItemTooltip")
    endfunction

    public function onBlzGetItemExtendedTooltip takes item whichItem returns nothing
        call DebugLog(LVL_WARN, "BlzGetItemExtendedTooltip")
    endfunction

    public function onSmartCameraPanBJ takes player whichPlayer, location loc, real duration returns nothing
        call DebugLog(LVL_ERROR, "SmartCameraPanBJ")
    endfunction

    public function onGetPlayerSlotState takes player whichPlayer returns nothing
        call DebugLog(LVL_WARN, "GetPlayerSlotState - Player " + GetPlayerName(whichPlayer))
    endfunction

    public function onGetPlayerController takes player whichPlayer returns nothing
        call DebugLog(LVL_WARN, "GetPlayerController - Player " + GetPlayerName(whichPlayer))
    endfunction

    public function onBlzGetLocalSpecialEffectX takes effect whichEffect returns nothing
        call DebugLog(LVL_WARN, "BlzGetLocalSpecialEffectX")
    endfunction

    public function onBlzGetLocalSpecialEffectY takes effect whichEffect returns nothing
        call DebugLog(LVL_WARN, "BlzGetLocalSpecialEffectY")
    endfunction

    public function onBlzGetLocalSpecialEffectZ takes effect whichEffect returns nothing
        call DebugLog(LVL_ERROR, "BlzGetLocalSpecialEffectZ")
    endfunction

    //hook TriggerAddAction onTriggerAddAction
    //hook GetDestructableName onGetDestructableName
    //hook GetSoundDuration onGetSoundDuration
    //hook GetSoundFileDuration onGetSoundFileDuration
    //hook GetCameraBoundMinX onGetCameraBoundMinX
    //hook GetCameraBoundMinX onGetCameraBoundMinY
    //hook GetCameraBoundMinX onGetCameraBoundMaxX
    //hook GetCameraBoundMinX onGetCameraBoundMaxY
    //hook GetCameraField onGetCameraField
    //hook GetCameraTargetPositionX onGetCameraTargetPositionX
    //hook GetCameraTargetPositionY onGetCameraTargetPositionY
    //hook GetCameraTargetPositionZ onGetCameraTargetPositionZ
    //hook GetCameraTargetPositionLoc onGetCameraTargetPositionLoc
    //hook GetCameraEyePositionX onGetCameraEyePositionX
    //hook GetCameraEyePositionY onGetCameraEyePositionY
    //hook GetCameraEyePositionZ onGetCameraEyePositionZ
    //hook GetCameraEyePositionLoc onGetCameraEyePositionLoc
    //hook GetObjectName onGetObjectName
    //hook IsMultiboardMinimized onIsMultiboardMinimized
    hook GetLocalPlayer onGetLocalPlayer
    hook GetLocationZ onGetLocationZ
    //hook GetLocalizedString onGetLocalizedString
    //hook GetLocalizedHotkey onGetLocalizedHotkey
    //hook GetUnitName onGetUnitName
    hook BlzGetLocalUnitZ onBlzGetLocalUnitZ
    hook BlzGetUnitZ onBlzGetUnitZ
    //hook GetItemName onGetItemName
    //hook BlzGetItemDescription onBlzGetItemDescription
    //hook BlzGetItemTooltip onBlzGetItemTooltip
    //hook BlzGetItemExtendedTooltip onBlzGetItemExtendedTooltip
    //hook SmartCameraPanBJ onSmartCameraPanBJ
    hook GetPlayerSlotState onGetPlayerSlotState
    hook GetPlayerController onGetPlayerController
    //hook BlzGetLocalSpecialEffectX onBlzGetLocalSpecialEffectX
    //hook BlzGetLocalSpecialEffectY onBlzGetLocalSpecialEffectY
    //hook BlzGetLocalSpecialEffectZ onBlzGetLocalSpecialEffectZ
endlibrary

DebugLogger - WriteInFile (only on player leave)
  • WriteInFile
    • Events
      • Player - Player 1 (Red) leaves the game
      • Player - Player 2 (Blue) leaves the game
      • Player - Player 3 (Teal) leaves the game
      • Player - Player 4 (Purple) leaves the game
      • Player - Player 5 (Yellow) leaves the game
      • Player - Player 6 (Orange) leaves the game
      • Player - Player 7 (Green) leaves the game
      • Player - Player 8 (Pink) leaves the game
    • Conditions
    • Actions
      • Custom script: call DebugLogger_WriteInFile("XndHeroSiegeLogs.txt")


DebugLoggerAutomation

JASS:
// Macro to be called outside of a function context, in a library context (or remove the private)
//! textmacro DECLARE_LOG_ACTION takes GLOBALVARIABLENAME
    globals
   private triggeraction LogAction_$GLOBALVARIABLENAME$
    endglobals

    // Create a log action function just for this trigger
    function Log_$GLOBALVARIABLENAME$ takes nothing returns nothing
        call DebugLogger_DebugLog(DebugLogger_LVL_DEBUG, "Trigger $GLOBALVARIABLENAME$ executed")
    endfunction
//! endtextmacro

// Macro to be called inside of a function cuntext, once all global trigger variables have been initialized
//! textmacro ADD_LOG_ACTION takes GLOBALVARIABLENAME
        set LogAction_$GLOBALVARIABLENAME$ = TriggerAddAction($GLOBALVARIABLENAME$, function Log_$GLOBALVARIABLENAME$)
//! endtextmacro


library DebugLoggerAutomation
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Alliances")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Buildings")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DarkUnits")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Flags")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LightHeroes")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Invulnerables")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ItemTypes")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Music")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Points")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Quests")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Regions")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Times")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_UnitStats")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_UnitTypes")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Check")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_StartGame")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OptionsGame")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OptionsDifficulty")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OptionsHeroes")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OptionsTimeOut")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ModeNormal")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ModeRandom")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ModeExtreme")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ModeEasy")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ReviveTrees")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CastleUnderAttack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_StopAttackCastle")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MuradinHelp")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MuradinAttacked")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_BuyLevels")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_BuyTomes")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CloseWay")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ExtremeLevel")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Fog")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Info")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Kick")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OpenWay")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Random")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RandomNumber")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Repick")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RepickTip")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Host")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_FullRestoration")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SuperItems")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LeaderBoard")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LeaderBoardAdd")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect1a")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect1b")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect2a")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect2b")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect3a")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect3b")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect4a")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect4b")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect5a")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect5b")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect6a")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect6b")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect7a")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect7b")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect8a")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSelect8b")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSetup")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroDead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ControlSharing")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EasyPowerUp")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroSetupDual")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroDeadDual")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroChange")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroChangeShared")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroStats")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroLevel")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroMoveItem")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroUseItem")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroAcquireItem")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DualHeroLoseItem")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_BoostLevel")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EnableHeroAbilities")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EnableItemAbilities")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Level20Abilities")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Armor")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttributeBonusPerLevel")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AuraOfBlight")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Bomb")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CommandAura")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CooldownsReduction")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CriticalStrikeAura")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_CursedClaws")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DamageDealtMalus")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DamageTakenMalus")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DebilitationAura")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Earthquake")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EarthquakeStop")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Ensnare")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_FanOfKnives")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_FrostParalysisAura")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Immolation")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ImmolationGhost")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Hex")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HolyLight")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_InnerFire")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LifeRegenerationAura")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LightFrenzy")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LightningAttackOnOff")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MagicDefenseOnOff")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MorphingCopyStats")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_OwlScout")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_PermanentLightning")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Polymorph")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RealmOfSoul")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RefreshCooldownChance")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RefreshCooldowns")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RuneClockCreate")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RuneClockDestroy")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RunicWeaponCreate")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ThunderClap")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ShadowStrike")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ShockWave")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpiritPig")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpiritualPresence")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_StormBolt")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WarDrumsAura")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WarStomp")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Kills100")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Kills500")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Kills1000")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Kills2000")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttackStart")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttackCome")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttackCheck")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttackTower")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_AttackNecropolis")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_ExtremePowerUp")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_DragonAttack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_HeroAttack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_LightningAttack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SilentAssassin")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Rune")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_GameLevel1")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WarnBeforeGameLevel2")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_GameLevel2")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_GameLevel3")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_GameLevel4")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveTimer")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveAttack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveKills20")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveKills40")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveKills60")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_WaveKills80")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_FinalWaveReady")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_FinalWaveStart")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_BossUnregister")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_BossRearFlankAttack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival1Ready")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival1Start")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival1Attack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Teleport")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss1Teleport")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss1Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival2Start")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival2Attack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss2Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss2Leave")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss3Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss4Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss5Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival3Start")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Survival3Attack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss6Come")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss6Teleport")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss6Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss7Come")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss7Colour")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss7Power")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Boss7Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special4Agree")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special4Won")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special4Leave")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special5Agree")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special5EnableAbilities")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special5Won")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special5Leave")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Timer")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Start")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Attack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Stop")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Teleport")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Leave")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8AntiHack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special8Move")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MuradinClap")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_MuradinBolt")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Timer")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Start")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Attack")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Corpse")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Stop")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special1Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special2Start")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special2Stop")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special2Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special2TimeOut")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special2Teleport")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3Start")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3Stop")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3Count")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3Dead")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3TimeOut")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special3Teleport")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special6Agree")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Special7Agree")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXDialog")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXStart")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXDisagree")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXRevive")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXTeleport")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXPause")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXResume")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_SpecialXCancel")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Victory")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_YouLose")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EndGame")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_Disconnect")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_RemovePlayer")
    //! runtextmacro DECLARE_LOG_ACTION("gg_trg_EndPitch")

    public function Init takes nothing returns nothing
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Alliances")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Buildings")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DarkUnits")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Flags")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_LightHeroes")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Invulnerables")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ItemTypes")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Music")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Points")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Quests")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Regions")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Times")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_UnitStats")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_UnitTypes")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Check")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_StartGame")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_OptionsGame")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_OptionsDifficulty")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_OptionsHeroes")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_OptionsTimeOut")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ModeNormal")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ModeRandom")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ModeExtreme")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ModeEasy")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ReviveTrees")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_CastleUnderAttack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_StopAttackCastle")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_MuradinHelp")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_MuradinAttacked")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_BuyLevels")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_BuyTomes")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_CloseWay")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ExtremeLevel")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Fog")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Info")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Kick")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_OpenWay")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Random")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_RandomNumber")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Repick")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_RepickTip")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Host")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_FullRestoration")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SuperItems")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_LeaderBoard")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_LeaderBoardAdd")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect1a")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect1b")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect2a")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect2b")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect3a")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect3b")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect4a")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect4b")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect5a")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect5b")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect6a")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect6b")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect7a")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect7b")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect8a")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSelect8b")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSetup")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroDead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ControlSharing")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_EasyPowerUp")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroSetupDual")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroDeadDual")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroChange")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroChangeShared")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroStats")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroLevel")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroMoveItem")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroUseItem")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroAcquireItem")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DualHeroLoseItem")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_BoostLevel")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_EnableHeroAbilities")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_EnableItemAbilities")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Level20Abilities")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Armor")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_AttributeBonusPerLevel")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_AuraOfBlight")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Bomb")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_CommandAura")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_CooldownsReduction")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_CriticalStrikeAura")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_CursedClaws")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DamageDealtMalus")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DamageTakenMalus")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DebilitationAura")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Earthquake")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_EarthquakeStop")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Ensnare")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_FanOfKnives")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_FrostParalysisAura")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Immolation")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ImmolationGhost")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Hex")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HolyLight")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_InnerFire")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_LifeRegenerationAura")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_LightFrenzy")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_LightningAttackOnOff")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_MagicDefenseOnOff")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_MorphingCopyStats")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_OwlScout")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_PermanentLightning")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Polymorph")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_RealmOfSoul")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_RefreshCooldownChance")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_RefreshCooldowns")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_RuneClockCreate")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_RuneClockDestroy")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_RunicWeaponCreate")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ThunderClap")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ShadowStrike")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ShockWave")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SpiritPig")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SpiritualPresence")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_StormBolt")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_WarDrumsAura")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_WarStomp")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Kills100")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Kills500")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Kills1000")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Kills2000")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_AttackStart")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_AttackCome")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_AttackCheck")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_AttackTower")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_AttackNecropolis")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_ExtremePowerUp")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_DragonAttack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_HeroAttack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_LightningAttack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SilentAssassin")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Rune")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_GameLevel1")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_WarnBeforeGameLevel2")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_GameLevel2")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_GameLevel3")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_GameLevel4")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveTimer")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveAttack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveKills20")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveKills40")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveKills60")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_WaveKills80")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_FinalWaveReady")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_FinalWaveStart")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_BossUnregister")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_BossRearFlankAttack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival1Ready")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival1Start")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival1Attack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Teleport")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss1Teleport")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss1Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival2Start")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival2Attack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss2Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss2Leave")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss3Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss4Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss5Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival3Start")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Survival3Attack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss6Come")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss6Teleport")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss6Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss7Come")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss7Colour")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss7Power")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Boss7Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special4Agree")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special4Won")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special4Leave")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special5Agree")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special5EnableAbilities")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special5Won")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special5Leave")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Timer")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Start")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Attack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Stop")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Teleport")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Leave")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8AntiHack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special8Move")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_MuradinClap")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_MuradinBolt")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Timer")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Start")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Attack")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Corpse")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Stop")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special1Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special2Start")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special2Stop")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special2Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special2TimeOut")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special2Teleport")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3Start")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3Stop")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3Count")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3Dead")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3TimeOut")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special3Teleport")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special6Agree")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Special7Agree")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXDialog")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXStart")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXDisagree")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXRevive")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXTeleport")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXPause")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXResume")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_SpecialXCancel")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Victory")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_YouLose")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_EndGame")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_Disconnect")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_RemovePlayer")
    //! runtextmacro ADD_LOG_ACTION("gg_trg_EndPitch")
   endfunction
endlibrary

Init
  • Init
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Custom script: call DebugLoggerAutomation_Init()


I'm not pro of JASS, so I couldn't find a way to do the following:
- One macro only that both declares a new function & execute some instructions (once needs out of function context, the other needs within a function context...).
- Add the log action as 1st, not 2nd. For GUI triggers, it would mean find a way to do it after the CreateTrigger() but before the "TriggerAddAction" that are automatically generated code...
 
Last edited:
Status
Not open for further replies.
Top