I've encountered situations in KA12 where I couldn't make heads or tails out of where a bug (gasp... bugs? In KA?) originates. If only there was a stack trace in MQ2...
MQ2 does not provide a property that let's you know where a call originated from. It does provide the current sub name ${Macro.CurSub}. This is only a tidbit of the picture one needs to trace calls throughout MQ2 macros. I employed an array as a simple call trace stack within my doctored up KA12, and you are free to use it. KA12 has a lot going on and as a newcomer I've endeavored to understand and extend it. Legacy software is a challenge.
The method is simple. Within each sub, do this:
The words in ALLCAPS are defines. We set them up and plunk those into our subs and even other defines.
You can see that at the top of the sub, we retrieve the name of the calling sub (CALLINGSUB), and it's index in the array (CALLINGINDEX), which are local variables. Then we add the current sub name to the array and increase the index (PUSHCALL) which are outer variables.
POPCALL sets the stack index to the current sub index. Place POPCALL before /return or /goto. Each /call to a sub that employs the method increases the index. The limit is set to an arbitrary 100. You don't need to POPCALL each and every time you do a return, but place POPCALL at the base of likely branch conditions so the array doesn't overflow.
Our debug messages begin as defines:
Notice we also need an outer variable, ${Debug}, to enable the message output. ${KissRevision} is just an internal variable which isn't important here. When we use the debug define, our sub looks like this.
The output from each debug line will include the following, which is everything you need at a barest minimum to see what's going on:
S:CURRENTSUB L:${Macro.CurLine} C:${CallingSub} CI:${CallingSubIndex}
Coupled with MQ2Log you can now see what's going on and where calls are originating from within KA.
Here is the whole shebang if you'd like to take it further / dare to peel the onion.
Example log output:
MQ2 does not provide a property that let's you know where a call originated from. It does provide the current sub name ${Macro.CurSub}. This is only a tidbit of the picture one needs to trace calls throughout MQ2 macros. I employed an array as a simple call trace stack within my doctored up KA12, and you are free to use it. KA12 has a lot going on and as a newcomer I've endeavored to understand and extend it. Legacy software is a challenge.
The method is simple. Within each sub, do this:
Call tracing within sub:
Sub Combat
||| Debug call stack
CALLINGSUB
CALLINGINDEX
PUSHCALL
...the code and debug messages...
POPCALL
/return
The words in ALLCAPS are defines. We set them up and plunk those into our subs and even other defines.
DEFINE:
#DEFINE CURRENTSUB "${Macro.CurSub.Arg[1,(]}"
#DEFINE CALLINGSUB "/declare CallingSub string local ${CallStack[${CallStackIndex},1]}"
#DEFINE CALLINGINDEX "/declare CallingSubIndex int local ${CallStackIndex}"
#DEFINE PUSHCALL "/call PushCallStack CURRENTSUB"
#DEFINE POPCALL "/varset CallStackIndex ${CallingSubIndex}"
You can see that at the top of the sub, we retrieve the name of the calling sub (CALLINGSUB), and it's index in the array (CALLINGINDEX), which are local variables. Then we add the current sub name to the array and increase the index (PUSHCALL) which are outer variables.
POPCALL sets the stack index to the current sub index. Place POPCALL before /return or /goto. Each /call to a sub that employs the method increases the index. The limit is set to an arbitrary 100. You don't need to POPCALL each and every time you do a return, but place POPCALL at the base of likely branch conditions so the array doesn't overflow.
Our debug messages begin as defines:
Example debug define:
#DEFINE DEBUGN "/if (${Debug}) /echo \atDEBUG-${KissRevision} \agS:CURRENTSUB L:${Macro.CurLine} C:${CallingSub} CI:${CallingSubIndex} T:${Macro.RunTime} \aw"
Notice we also need an outer variable, ${Debug}, to enable the message output. ${KissRevision} is just an internal variable which isn't important here. When we use the debug define, our sub looks like this.
With debug line:
Sub Pull
||| Debug call stack
CALLINGSUB
CALLINGINDEX
PUSHCALL
DEBUGN Blah blah blah message with var outputs
...the code...
DEBUGN And another debug message
POPCALL
/return
The output from each debug line will include the following, which is everything you need at a barest minimum to see what's going on:
S:CURRENTSUB L:${Macro.CurLine} C:${CallingSub} CI:${CallingSubIndex}
Coupled with MQ2Log you can now see what's going on and where calls are originating from within KA.
Here is the whole shebang if you'd like to take it further / dare to peel the onion.
Example Main with subs:
||| Call trace
#DEFINE CURRENTSUB "${Macro.CurSub.Arg[1,(]}"
#DEFINE CALLINGSUB "/declare CallingSub string local ${CallStack[${CallStackIndex},1]}"
#DEFINE CALLINGINDEX "/declare CallingSubIndex int local ${CallStackIndex}"
#DEFINE PUSHCALL "/call PushCallStack CURRENTSUB"
#DEFINE POPCALL "/varset CallStackIndex ${CallingSubIndex}"
#DEFINE DEBUGN "/if (${Debug}) /echo \atDEBUG-${KissRevision} \agS:CURRENTSUB L:${Macro.CurLine} C:${CallingSub} CI:${CallingSubIndex} T:${Macro.RunTime} \aw"
#bind CallStack /callstack
Sub Main
/declare Debug int outer 1
/declare KissRevision int outer 12
||| Set up the debug call stack. We start with PUSHCALL to establish the array.
||| Main will always be 1.
PUSHCALL
CALLINGSUB
CALLINGINDEX
/while (1) {
/call Sub1
/call Sub2
POPCALL
}
POPCALL
:OnExit
/call Bind_CallStack
/return
Sub Sub1
||| Debug call stack
CALLINGSUB
CALLINGINDEX
PUSHCALL
DEBUGN Blah blah blah message with var outputs
...the code...
DEBUGN And another debug message
POPCALL
/return
Sub Sub2
||| Debug call stack
CALLINGSUB
CALLINGINDEX
PUSHCALL
DEBUGN Blah blah blah message with var outputs
/call Sub3
...more code...
DEBUGN And another debug message
POPCALL
/return
Sub Sub3
||| Debug call stack
CALLINGSUB
CALLINGINDEX
PUSHCALL
DEBUGN Blah blah blah message with var outputs
...the code...
DEBUGN And another debug message
POPCALL
/endmacro
/return
||| ---------------------------------------------------------------------------
||| Sub PushCallStack
||| Helper for debugging. Records current sub so next sub can read it.
||| Usage: /call PushCallStack CURRENTSUB
||| ---------------------------------------------------------------------------
Sub PushCallStack(string SubName)
/if (!${Defined[CallStack]}) {
||| If 100 isn't enough something is probably wrong. Allows for some slop.
/declare CallStack[100,1] string outer null
/declare CallStackIndex int outer 0
}
/if (${CallStackIndex}==100) {
/echo CallStack ${SubName} exceeds max stack size 100. Dumping stack and quitting.
/declare i int local 0
/for i 1 to 100
/echo ${i} ${CallStack[${i},1]}
/next i
/endmacro
}
/varcalc CallStackIndex ${CallStackIndex}+1
/varset CallStack[${CallStackIndex},1] ${SubName}
/return
||| ---------------------------------------------------------------------------
||| Sub PopCallStack - Not used
||| Helper for debugging. Removes the sub from the stack.
||| Usage: /call PopCallStack
||| ---------------------------------------------------------------------------
Sub PopCallStack(int CallIndex)
/while (${CallIndex}>${CallStackIndex})
/varset CallStack[${CallStackIndex},1] NULL
/varcalc CallStackIndex ${CallStackIndex}-1
}
/return
||| ---------------------------------------------------------------------------
||| Sub GetCall - Not used
||| Helper for debugging. Retrieves the top call from the stack (will be previous sub)
||| ---------------------------------------------------------------------------
Sub GetCall
/return ${CallStack[${CallStackIndex},1]}
||| ---------------------------------------------------------------------------
||| Sub Bind_CallStack
||| Helper for debugging. Records current sub so next sub can read it.
||| Usage: /callstack
||| ---------------------------------------------------------------------------
Sub Bind_CallStack
/if (!${Defined[CallStack]}) {
/echo No stack to check.
/return
}
/echo CallStack size ${CallStackIndex}.
/declare i int local 0
/for i 1 to ${CallStackIndex}
/echo ${i} ${CallStack[${i},1]}
/next i
/return
Example log output:
Log output:
[2021/06/17 23:57:08] [MQ2] ATTACKING -> a tiny zombie <-
[2021/06/17 23:57:08] [MQ2] COMBAT-400 S:CombatPet L:1867 C:Combat CI:5 T:426 Enter - use /debug petcombat to go further
[2021/06/17 23:57:08] [MQ2] COMBAT-400 S:CombatPet L:1867 C:CombatPet CI:6 T:426 Enter - use /debug petcombat to go further
[2021/06/17 23:57:08] [MQ2] COMBAT-400 S:PetEngageTarget L:20942 C:CombatPet CI:7 T:426 Enter - debug further using petcombat
[2021/06/17 23:57:08] [MQ2] COMBAT-400 S:IsFriendly L:20133 C:PetAttack CI:9 T:426 Enter Target Name:a tiny zombie ID:3292 Spawn Name: a tiny zombie ID:3292
[2021/06/17 23:57:08] [MQ2] COMBAT-400 S:IsFriendly L:20139 C:PetAttack CI:9 T:426 Validate Friendlies
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:IsFriendly L:20151 C:PetAttack CI:9 T:426 MobID 3292 MobMasterID 0
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:IsFriendly L:20165 C:PetAttack CI:9 T:426 It's not me apparently
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:IsFriendly L:20169 C:PetAttack CI:9 T:426 Not in the group apparently
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:IsFriendly L:20179 C:PetAttack CI:9 T:426 Not a groupmember, pet, or whatever... supposedly may be hostile
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:IsFriendly L:20181 C:PetAttack CI:9 T:426 Leave
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:CombatPet L:1867 C:CheckBeforeCast CI:5 T:427 Enter - use /debug petcombat to go further
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:CombatPet L:1867 C:DoWeMed CI:4 T:427 Enter - use /debug petcombat to go further
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:Combat L:1180 C:DoWeMed CI:4 T:427 1: MyTargetID 3292 AggroTargetID 3292
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:Combat L:1182 C:DoWeMed CI:4 T:427 Attack 1.20 Role PetTank ChainPull 0
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:Combat L:1195 C:DoWeMed CI:4 T:427 1: MyTargetID 3292 AggroTargetID 3292