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:
[CODE lang="ini" title="Call tracing within sub"]Sub Combat
||| Debug call stack
CALLINGSUB
CALLINGINDEX
PUSHCALL
...the code and debug messages...
POPCALL
/return[/CODE]
The words in ALLCAPS are defines. We set them up and plunk those into our subs and even other defines.
[CODE lang="ini" title="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}"
[/CODE]
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:
[CODE lang="ini" title="Example debug define"]#DEFINE DEBUGN "/if (${Debug}) /echo \atDEBUG-${KissRevision} \agS:CURRENTSUB L:${Macro.CurLine} C:${CallingSub} CI:${CallingSubIndex} T:${Macro.RunTime} \aw"
[/CODE]
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.
[CODE lang="ini" title="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
[/CODE]
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.
[CODE lang="ini" title="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
[/CODE]
Example log output:
[CODE title="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
oWeMed 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
oWeMed CI:4 T:427 1: MyTargetID 3292 AggroTargetID 3292
[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:Combat L:1182 C
oWeMed 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
oWeMed CI:4 T:427 1: MyTargetID 3292 AggroTargetID 3292[/CODE]
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:
[CODE lang="ini" title="Call tracing within sub"]Sub Combat
||| Debug call stack
CALLINGSUB
CALLINGINDEX
PUSHCALL
...the code and debug messages...
POPCALL
/return[/CODE]
The words in ALLCAPS are defines. We set them up and plunk those into our subs and even other defines.
[CODE lang="ini" title="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}"
[/CODE]
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:
[CODE lang="ini" title="Example debug define"]#DEFINE DEBUGN "/if (${Debug}) /echo \atDEBUG-${KissRevision} \agS:CURRENTSUB L:${Macro.CurLine} C:${CallingSub} CI:${CallingSubIndex} T:${Macro.RunTime} \aw"
[/CODE]
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.
[CODE lang="ini" title="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
[/CODE]
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.
[CODE lang="ini" title="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
[/CODE]
Example log output:
[CODE title="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
oWeMed 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
oWeMed CI:4 T:427 1: MyTargetID 3292 AggroTargetID 3292[2021/06/17 23:57:09] [MQ2] COMBAT-400 S:Combat L:1182 C
oWeMed 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
oWeMed CI:4 T:427 1: MyTargetID 3292 AggroTargetID 3292[/CODE]
