// ***************************************************************************
// Function:    Return
// Description: Our '/return' command
// Usage:       /return [value]
// ***************************************************************************
VOID Return(PSPAWNINFO pChar, PCHAR szLine)
{
    bRunNextCommand = TRUE;
    PMACROSTACK pStack = gMacroStack;
    if (!gMacroBlock) 
    {
        MacroError("Cannot return when a macro isn't running.");
        return;
    }
    if (!pStack->pNext) 
    {
        // Top of stack (ie. returning from Sub Main)
        EndMacro(pChar,"");
        return;
    }
    if (pStack->LocalVariables) 
        ClearMQ2DataVariables(&pStack->LocalVariables);
    if (pStack->Parameters) 
        ClearMQ2DataVariables(&pStack->Parameters);

    strcpy(pStack->pNext->Return,szLine);
    gMacroBlock = pStack->pNext->Location;
    gMacroStack = pStack->pNext;
    free(pStack);
    DebugSpewNoFile("Return - Returned to %s",gMacroBlock->Line);

}
Exemplo n.º 2
0
BOOL DoNextCommand()
{
	if (!ppCharSpawn || !pCharSpawn) return FALSE;
	PSPAWNINFO pCharOrMount = NULL;
	PCHARINFO pCharInfo = GetCharInfo();
	PSPAWNINFO pChar = pCharOrMount = (PSPAWNINFO)pCharSpawn;
	if (pCharInfo && pCharInfo->pSpawn) pChar = pCharInfo->pSpawn;
	if ((!pChar) || (gZoning)/* || (gDelayZoning)*/) return FALSE;
	if (((gFaceAngle != 10000.0f) || (gLookAngle != 10000.0f)) && (TurnNotDone)) return FALSE;
	if (IsMouseWaiting()) return FALSE;
	if (gDelay && gDelayCondition[0])
	{
		CHAR szCond[MAX_STRING];
		strcpy(szCond, gDelayCondition);
		ParseMacroParameter(GetCharInfo()->pSpawn, szCond);
		DOUBLE Result;
		if (!Calculate(szCond, Result))
		{
			FatalError("Failed to parse /delay condition '%s', non-numeric encountered", szCond);
			return false;
		}
		if (Result != 0)
		{
			DebugSpewNoFile("/delay ending early, conditions met");
			gDelay = 0;
		}
	}
	if (!gDelay && !gMacroPause && (!gMQPauseOnChat || *EQADDR_NOTINCHATMODE) &&
		gMacroBlock && gMacroStack) {
		PMACROBLOCK tmpBlock = gMacroBlock;
		gMacroStack->Location = gMacroBlock;
#ifdef MQ2_PROFILING
		LARGE_INTEGER BeforeCommand;
		QueryPerformanceCounter(&BeforeCommand);
		PMACROBLOCK ThisMacroBlock = gMacroBlock;
#endif
		gMacroBlock->MacroCmd = 0;
		DoCommand(pChar, gMacroBlock->Line);
		if (gMacroBlock) {
#ifdef MQ2_PROFILING
			LARGE_INTEGER AfterCommand;
			QueryPerformanceCounter(&AfterCommand);
			ThisMacroBlock->ExecutionCount++;
			ThisMacroBlock->ExecutionTime += AfterCommand.QuadPart - BeforeCommand.QuadPart;
#endif
			if (!gMacroBlock->pNext) {
				FatalError("Reached end of macro.");
			}
			else {
				// if the macro block changed and there was a /macro 
				// command don't bump the line 
				//if (gMacroBlock == tmpBlock || !gMacroBlock->MacroCmd) {
				gMacroBlock = gMacroBlock->pNext;
				//}
			}
		}
		return TRUE;
	}
	return FALSE;
}
Exemplo n.º 3
0
// ***************************************************************************
// Function:    DoBreak
// Description: Breaks the execution flow within a bucle.
//            If evaluate is set, the function set the execution pointer at
//            the end of the bucle, so the condition is evaluate.
// ***************************************************************************
VOID DoBreak(PSPAWNINFO pChar, PMACROBLOCK pStartLine, BOOL evaluate)
{
   if (!gMacroBlock)
   {
      DebugSpewNoFile("DoBreak - Macro was ended before we could handle the break command");
      return;
   }

   while (1)
   {   
      if (!strnicmp(gMacroBlock->Line,"Sub ",4))
      {
         gMacroBlock = pStartLine;
         FatalError("/break or /continue called outside a bucle");
         return;
      }
      if (!gMacroBlock->pNext)
      {
         gMacroBlock=pStartLine;
         FatalError("/break or /continue called outside a bucle");
            return;
      }      
      if (!strnicmp(gMacroBlock->Line,"/until",6) ||
         !strnicmp(gMacroBlock->Line, "/endwhile", 9) ||
         !strnicmp(gMacroBlock->Line, "/next", 4))
      {
         //We are on the /until or /endwhile command
         gMacroBlock = (evaluate)?gMacroBlock->pPrev:gMacroBlock;         
         break;
      }
      gMacroBlock = gMacroBlock->pNext;
   }
}
VOID ContinueWhile(PSPAWNINFO pChar, PMACROBLOCK pStartLine)
{
   if (!gMacroBlock) {
      DebugSpewNoFile("ContinueWhile - Macro was ended before we could handle the end of while command");
      return;
   }

   while (1)
   {
      if (!strnicmp(gMacroBlock->Line,"sub ",4))
      {
         gMacroBlock=pStartLine;
         FatalError("/while ran into another subroutine");
            return;
      }
      if (!gMacroBlock->pPrev)
      {
         gMacroBlock=pStartLine;
         FatalError("/while without an end");
            return;
      }
      if (!strnicmp(gMacroBlock->Line,"/while",6))
      {
         gMacroBlock = gMacroBlock->pPrev;
         break;
      }
      gMacroBlock = gMacroBlock->pPrev;
   }
}
// ***************************************************************************
// Function:    Cleanup
// Description: Our '/cleanup' command
//              Sends i, esc, esc, esc, esc, i
// Usage:       /cleanup
// ***************************************************************************
VOID Cleanup(PSPAWNINFO pChar, PCHAR szLine)
{
    DebugSpewNoFile("Cleanup - Cleaning up screen");
    DWORD i;
    KeyCombo Escape;
    ParseKeyCombo("Esc",Escape);
    if(ppContainerMgr && pContainerMgr) {
        PEQ_CONTAINERWND_MANAGER ContainerMgr = (PEQ_CONTAINERWND_MANAGER)pContainerMgr;
        DWORD concount=2; //Close inv + clear target
        if (ContainerMgr->pWorldContents && ContainerMgr->pWorldContents->Open==1) concount++;
        for (i=0;i<25;i++) {
            if (ContainerMgr->pPCContainers[i] && ContainerMgr->pPCContainers[i]->Wnd.dShow==1) concount++;
        }
        for (i=0;i<concount;i++) 
        {
            MQ2HandleKeyDown(Escape);
            MQ2HandleKeyUp(Escape);
        }
        if (!ppInventoryWnd) {
            PCSIDLWND pInvWindow = (PCSIDLWND)pInventoryWnd;
            if (pInvWindow && pInvWindow->dShow==0) 
                DoMappable(pChar,"inventory");
        }
    } else {
        DoMappable(pChar,"inventory");
        for (i=0;i<10;i++) 
        {
            MQ2HandleKeyDown(Escape);
            MQ2HandleKeyUp(Escape);
        }
        DoMappable(pChar,"inventory");
    }
}
VOID EndWhile(PSPAWNINFO pChar, PCHAR szCommand, PMACROBLOCK pStartLine, BOOL All=0)
{
    DWORD Scope = 0;
    if (szCommand[strlen(szCommand)-1]=='{') {
        if (!gMacroBlock) {
            DebugSpewNoFile("EndWhile - Macro was ended before we could handle the false while command");
            return;
        }
        Scope++;
        gMacroBlock = gMacroBlock->pNext;
        while ((Scope>0)) {
            if (gMacroBlock->Line[0]=='}') Scope--;
            if (All) if (gMacroBlock->Line[strlen(gMacroBlock->Line)-1]=='{') Scope++;
            if (Scope>0) {
                if (!All) if (gMacroBlock->Line[strlen(gMacroBlock->Line)-1]=='{') Scope++;
                if (!strnicmp(gMacroBlock->Line,"sub ",4)) {
                    gMacroBlock=pStartLine;
                    FatalError("{} pairing ran into anther subroutine");
                    return;
                }
                if (!gMacroBlock->pNext) {
                    gMacroBlock=pStartLine;
                    FatalError("Bad {} block pairing");
                    return;
                }
                gMacroBlock = gMacroBlock->pNext;
            }
        }
    } else {
		gMacroBlock = gMacroBlock->pNext;
        bRunNextCommand = TRUE;
    }
}
Exemplo n.º 7
0
// ***************************************************************************
// Function:    ContinueDo
// Description: Continues a /do bucle execution. Searchs the /do command
//            and set the execution pointer at that command.
// ***************************************************************************
VOID ContinueDo(PSPAWNINFO pChar, PMACROBLOCK pStartLine)
{
   if (!gMacroBlock) {
      DebugSpewNoFile("ContinueDo - Macro was ended before we could handle the do command");
      return;
   }

   while (1)
   {
      if (!strnicmp(gMacroBlock->Line,"sub ",4))
      {
         gMacroBlock=pStartLine;
         FatalError("/until without pairing /do");
            return;
      }
      if (!gMacroBlock->pPrev)
      {
         gMacroBlock=pStartLine;
         FatalError("/until without pairing /do");
            return;
      }
      if (!strnicmp(gMacroBlock->Line,"/do",3)) break;
      gMacroBlock = gMacroBlock->pPrev;
   }
}
Exemplo n.º 8
0
// ***************************************************************************
// Function:    EndWhile
// Description: Ends a /while bucle execution. Searchs the /endwhile command
//            and set the execution pointer at that command.
// ***************************************************************************
VOID EndWhile(PSPAWNINFO pChar, PMACROBLOCK pStartLine)
{
   if (!gMacroBlock) {
      DebugSpewNoFile("EndWhile - Macro was ended before we could handle the end of while command");
      return;
   }

   while (1)
   {
      if (!strnicmp(gMacroBlock->Line,"sub ",4))
      {
         gMacroBlock=pStartLine;
         FatalError("/while ran into another subroutine");
            return;
      }
      if (!gMacroBlock->pNext)
      {
         gMacroBlock=pStartLine;
         FatalError("/while without pairing /endwhile");
            return;
      }
      if (!strnicmp(gMacroBlock->Line,"/endwhile",9)) break;
      gMacroBlock = gMacroBlock->pNext;
   }
}
Exemplo n.º 9
0
VOID ShutdownParser()
{
    DebugSpewNoFile("ShutdownParser()");
    RemoveDetour(EQPlayer__SetNameSpriteState); // put here so it doesnt crash :)
    ShutdownMQ2Data();
    ShutdownMQ2DataTypes();
}
// ***************************************************************************
// Function:    Include
// Description: Includes another macro file
// Usage:       #include <filename>
// ***************************************************************************
DWORD Include(PCHAR szFile)
{
    CHAR szTemp[MAX_STRING] = {0};
    FILE *fMacro = fopen(szFile,"rt");
    DWORD LineNumber=0;
    BOOL InBlockComment = FALSE;
    PMACROBLOCK pAddedLine = NULL;
    char *tmp;
    if (!fMacro) {
        FatalError("Couldn't open include file: %s",szFile);
        return 0;
    }
    DebugSpewNoFile("Include - Including: %s",szFile);
    while (!feof(fMacro)) {

        tmp = fgets(szTemp,MAX_STRING,fMacro);

        if (!tmp && feof(fMacro)) break;

        CleanMacroLine(szTemp);

        LineNumber++;

        if (!strncmp(szTemp,"|**",3)) {
            InBlockComment=TRUE;
        }
        if (!InBlockComment) {
            if (NULL == (pAddedLine=AddMacroLine(szTemp))) {
                MacroError("Unable to add macro line.");
                fclose(fMacro);
                gszMacroName[0]=0;
                gRunning = 0;
                return 0;
            } else if (1 != (DWORD)pAddedLine) {
                pAddedLine->LineNumber = LineNumber;
                strcpy(pAddedLine->SourceFile, GetFilenameFromFullPath(szFile));
            }
        } else {
            DebugSpewNoFile("Macro - BlockComment: %s",szTemp);
            if (!strncmp(&szTemp[strlen(szTemp)-3],"**|",3)) {
                InBlockComment=FALSE;
            }
        }
    }
    fclose(fMacro);
    return 1;
}
Exemplo n.º 11
0
VOID InitializeParser()
{
    DebugSpewNoFile("InitializeParser()");

    InitializeMQ2DataTypes();
    InitializeMQ2Data();
    bmParseMacroParameter=AddMQ2Benchmark("ParseMacroParameter");
}
Exemplo n.º 12
0
VOID MarkWhile(PSPAWNINFO pChar, PCHAR szCommand, BOOL All=0)
{
	PMACROBLOCK pSaveLine = gMacroBlock;
	BOOL bDelay = 0;
    DWORD Scope = 0;
    if (szCommand[strlen(szCommand)-1]=='{') {
        if (!gMacroBlock) {
            DebugSpewNoFile("MarkWhile - Macro was ended before we could handle the command");
            return;
        }
        Scope++;
        gMacroBlock = gMacroBlock->pNext;
        while ((Scope>0)) {
            if (gMacroBlock->Line[0]=='}') {
				Scope--;
			}
            if (All) {
				if (gMacroBlock->Line[strlen(gMacroBlock->Line)-1]=='{') {
					Scope++;
				}
			}
            if (Scope>0) {
                if (!All) {
					if (gMacroBlock->Line[strlen(gMacroBlock->Line)-1]=='{') {
						Scope++;
					}
				}
                if (!strnicmp(gMacroBlock->Line,"sub ",4)) {
                    gMacroBlock=pSaveLine;
                    FatalError("{} pairing ran into anther subroutine");
                    return;
                }
                if (!gMacroBlock->pNext) {
                    gMacroBlock=pSaveLine;
                    FatalError("Bad {} block pairing");
                    return;
                }
                gMacroBlock = gMacroBlock->pNext;
            }
        }
    } else {
		//its a /while (something) /dosomething
		//but we know, that unless that /dosomething is a /delay ... we WILL fail them...
		Sleep(0);
    }
	gMacroBlock->LoopLine = pSaveLine->LineNumber;
	gMacroBlock = pSaveLine;
}
VOID FailIf(PSPAWNINFO pChar, PCHAR szCommand, PMACROBLOCK pStartLine, BOOL All)
{
    DWORD Scope = 0;
    if (szCommand[strlen(szCommand)-1]=='{') {
        if (!gMacroBlock) {
            DebugSpewNoFile("FailIf - Macro was ended before we could handle the false if command");
            return;
        }
        Scope++;
        gMacroBlock = gMacroBlock->pNext;
        while ((Scope>0)) {
            if (gMacroBlock->Line[0]=='}') Scope--;
            if (All) if (gMacroBlock->Line[strlen(gMacroBlock->Line)-1]=='{') Scope++;
            if (Scope>0) {
                if (!All) if (gMacroBlock->Line[strlen(gMacroBlock->Line)-1]=='{') Scope++;
                if (!strnicmp(gMacroBlock->Line,"sub ",4)) {
                    gMacroBlock=pStartLine;
                    FatalError("{} pairing ran into anther subroutine");
                    return;
                }
                if (!gMacroBlock->pNext) {
                    gMacroBlock=pStartLine;
                    FatalError("Bad {} block pairing");
                    return;
                }
                gMacroBlock = gMacroBlock->pNext;
            }
        }
        if ((!All) && (!strnicmp(gMacroBlock->Line,"} else ",7))) {
            DoCommand(pChar,gMacroBlock->Line+7);
        } else if ((!All) && (!strnicmp(gMacroBlock->Line,"} else",6))) {
            FatalError("} else lacks command or {");
            return;
        } else {
            bRunNextCommand = TRUE;
        }
    } else {
        bRunNextCommand = TRUE;
    }
}
// ***************************************************************************
// Function:    DoEvents
// Description: Our '/doevents' command
// Usage:       /doevents [flush] [custom event]
// ***************************************************************************
VOID DoEvents(PSPAWNINFO pChar, PCHAR szLine)
{
    if (!gEventQueue || !gMacroStack) 
        return;

    CHAR Arg1[MAX_STRING]={0};
    CHAR Arg2[MAX_STRING]={0};

    GetArg(Arg1,szLine,1);

    if (!stricmp(Arg1,"flush"))
    {
        GetArg(Arg2,szLine,2);
        if (Arg2[0])
        {
            sprintf(Arg1,"Sub Event_%s",Arg2);
            PEVENTQUEUE pEvent=gEventQueue;
            while (pEvent) 
            {
                if (
                    (pEvent->Type == EVENT_CHAT && !stricmp("Sub Event_Chat",Arg1)) ||
                    (pEvent->Type == EVENT_TIMER && !stricmp("Sub Event_Timer",Arg1)) ||
                    (pEvent->Type == EVENT_CUSTOM && !stricmp(pEvent->pEventList->szName,Arg1))
                    ) 
                {
                    PEVENTQUEUE pEventNext;
                    if (pEventNext = pEvent->pNext)
                        pEventNext->pPrev=pEvent->pPrev;
                    if (pEvent->pPrev)
                        pEvent->pPrev->pNext=pEvent->pNext;
                    else
                        gEventQueue=pEvent->pNext;
                    ClearMQ2DataVariables(&pEvent->Parameters);
                    free(pEvent);
                    pEvent=pEventNext;
                    continue;
                }
                pEvent = pEvent->pNext;
            }
        }
        else
        {
            while (gEventQueue) 
            {
                PEVENTQUEUE pEventNext = gEventQueue->pNext;
                ClearMQ2DataVariables(&gEventQueue->Parameters);
                free(gEventQueue);
                gEventQueue = pEventNext;
            }
        }
        return;
    }
    PEVENTQUEUE pEvent=gEventQueue;
    if (Arg1[0])
    {
        sprintf(Arg2,"Sub Event_%s",Arg1);
        while(pEvent)
        {
            if (
                (pEvent->Type == EVENT_CHAT && !stricmp("Sub Event_Chat",Arg2)) ||
                (pEvent->Type == EVENT_TIMER && !stricmp("Sub Event_Timer",Arg2)) ||
                (pEvent->Type == EVENT_CUSTOM && !stricmp(pEvent->pEventList->szName,Arg2))
                ) 
            {
                break;
            }
            pEvent=pEvent->pNext;
        }
        if (!pEvent)
            return;// no event found
    }

    if (pEvent->pPrev)
        pEvent->pPrev->pNext=pEvent->pNext;
    else
        gEventQueue=pEvent->pNext;
    if (pEvent->pNext)
        pEvent->pNext->pPrev=pEvent->pPrev;

    DebugSpewNoFile("DoEvents: Running event type %d (%s) = 0x%p",pEvent->Type,(pEvent->pEventList)?pEvent->pEventList->szName:"NONE",pEvent);

    PMACROSTACK pStack = (PMACROSTACK)malloc(sizeof(MACROSTACK));

    // back the current location to previous one so we fall into
    // /doevents again.  This screams for optimization!

    gMacroStack->Location = gMacroStack->Location->pPrev;
    pStack->Location = gMacroBlock;
    pStack->Return[0] = 0;
    pStack->Parameters = pEvent->Parameters;
    PDATAVAR pParam=pStack->Parameters;
    while(pParam) // FIX THE HEAD ON EVERY VAR WE MOVED
    {
        pParam->ppHead=&pStack->Parameters;
        pParam=pParam->pNext;
    }
    pStack->LocalVariables = NULL;
    pStack->pNext = gMacroStack;
    gMacroStack = pStack;
    if (pEvent->Type == EVENT_CUSTOM) 
    {
        gMacroBlock = pEvent->pEventList->pEventFunc;
    }
    else 
    {
        gMacroBlock = gEventFunc[pEvent->Type];
    }
    DebugSpewNoFile("DoEvents - Called event: %s",gMacroBlock->Line);
    free(pEvent);
    bRunNextCommand = FALSE;
}
// ***************************************************************************
// Function:    Call
// Description: Our '/call' command
// Usage:       /call <Subroutine>
// ***************************************************************************
VOID Call(PSPAWNINFO pChar, PCHAR szLine)
{
    PMACROSTACK pStack;
    PMACROBLOCK pCallingPoint = gMacroBlock;
    CHAR SubName[MAX_STRING] = {0};
    PCHAR SubParam = NULL;
    CHAR SubLine[MAX_STRING] = {0};
    CHAR SubLineP[MAX_STRING] = {0};
    DWORD StackNum = 0;
    bRunNextCommand = TRUE;
    if (szLine[0]==0) {
        SyntaxError("Usage: /call <subroutine> [param [param...]]");
        return;
    }
    if (!gMacroBlock) {
        MacroError("Cannot call when a macro isn't running.");
        return;
    }

    GetArg(SubName,szLine,1);
    SubParam = GetNextArg(szLine);

    sprintf(SubLine,"sub %s",SubName);
    sprintf(SubLineP,"sub %s(",SubName);

    // Sub in Map?
    PMACROBLOCK pSubBlock = gMacroSubLookupMap[SubName];

    // If not, find it and add.
    if (!pSubBlock) {
        while (gMacroBlock->pPrev) gMacroBlock = gMacroBlock->pPrev;
        while (gMacroBlock->pNext) {
            if (!stricmp(gMacroBlock->Line,SubLine) || !strnicmp(gMacroBlock->Line,SubLineP,strlen(SubLineP))) {
                pSubBlock = gMacroBlock;
                break;
            }
            gMacroBlock = gMacroBlock->pNext;
        }
        if (!pSubBlock) {
            gMacroBlock=pCallingPoint;
            FatalError("Subroutine %s wasn't found",SubName);
            return;
        } else {
            gMacroSubLookupMap[SubName] = pSubBlock;
        }
    }

    // Prep to call the Sub
    gMacroBlock = pSubBlock;

    DebugSpewNoFile("Call - Calling subroutine %s with params %s",SubName,SubParam);
    pStack = (PMACROSTACK)malloc(sizeof(MACROSTACK));
    pStack->Location = gMacroBlock;
    pStack->Return[0] = 0;
    pStack->Parameters = NULL;
    pStack->LocalVariables = NULL;
    pStack->pNext = gMacroStack;
    gMacroStack = pStack;
    if (SubParam) {
        StackNum = 0;
        while (SubParam[0]!=0) {
            CHAR szParamName[MAX_STRING] = {0};
            CHAR szParamType[MAX_STRING] = {0};
            CHAR szNewValue[MAX_STRING]={0};
            GetArg(szNewValue,SubParam,1);

            GetFuncParam(gMacroBlock->Line,StackNum,szParamName,szParamType);
            MQ2Type *pType = FindMQ2DataType(szParamType);
            if (!pType)
                pType=pStringType;

            AddMQ2DataVariable(szParamName,"",pType,&gMacroStack->Parameters,szNewValue);
            SubParam = GetNextArg(SubParam);
            StackNum++;
        }
    }
    return;
} 
// ***************************************************************************
// Function:    EndMacro
// Description: Our '/endmacro' command
// Usage:       /endmacro
// ***************************************************************************
VOID EndMacro(PSPAWNINFO pChar, PCHAR szLine)
{
    CHAR Buffer[MAX_STRING] = {0};
    DWORD i;
    PMACROBLOCK pPrev;
    PMACROSTACK pStack;
    PEVENTQUEUE pEvent;
    PEVENTLIST pEventL;
    BOOL bKeepKeys = gKeepKeys;
    if (szLine[0]!=0) {
        GetArg(Buffer,szLine,1);
        szLine = GetNextArg(szLine);
        if (stricmp(Buffer,"keep")) {
            SyntaxError("Usage: /endmacro [keep keys]");
            return;
        }
        while (szLine[0]!=0) {
            GetArg(Buffer,szLine,1);
            szLine = GetNextArg(szLine);
            if (!stricmp(Buffer,"keys")) bKeepKeys = TRUE;
        }
    }

    if (!gMacroBlock) {
        MacroError("Cannot end a macro when one isn't running.");
        return;
    }

    /////////////// 
    // Code allowing for a routine for "OnExit"
    while (gMacroBlock->pNext) 
    {
        gMacroBlock=gMacroBlock->pNext;
        //DebugSpew("%s",gMacroBlock->Line);
        if (!stricmp(":OnExit",gMacroBlock->Line)) 
        {
            if (gReturn)            // return to the macro the first time around
            {
                gReturn = false;    // We don't want to return the 2nd time.
                return;
            }
            else
                break;
        }
    }
    gReturn = true;            // reset for next time
    //
    ///////////////

#ifdef MQ2_PROFILING
    // How many performance counters in 1 second?
    LARGE_INTEGER PerformanceFrequency;
    QueryPerformanceCounter(&PerformanceFrequency);

    // Move to first macro line
    while (gMacroBlock->pPrev) gMacroBlock = gMacroBlock->pPrev;

    CHAR Filename[MAX_STRING] = {0};
    FILE *fMacro = NULL;
    while (gMacroBlock) {
        // Is this a different macro file?
        if (strcmp(Filename, gMacroBlock->SourceFile)) {
            // Close existing file
            if (fMacro) {
                fclose(fMacro);
            }
            // Open new profiling log file
            strcpy(Filename, gMacroBlock->SourceFile);
            sprintf(Buffer, "%s\\%s.mqp", gszMacroPath, Filename);
            fMacro = fopen(Buffer, "w");
            if (fMacro) {
                fprintf(fMacro, " Execute |  Total   | Avg uSec | Line | Macro Source Code\n");
                fprintf(fMacro, " Count   |   uSec   | Per 1000 |\n");
                fprintf(fMacro, "------------------------------------------------------------------------------------------------------------- \n");
            }
        }

        // Log execution/profiling information.  Output format is:
        // Execution Count | Microseconds | Line # | Macro Source
        if (fMacro) {
            DWORD count = gMacroBlock->ExecutionCount;
            DWORD total = (DWORD)(gMacroBlock->ExecutionTime * 1000000 / PerformanceFrequency.QuadPart);
            DWORD avg = 0;
            if (count > 0) {
                avg = total * 1000 / count;
            }
            fprintf(fMacro, "%8lu | %8lu | %8lu | %4lu | %s\n",
                count,
                total,
                avg,
                gMacroBlock->LineNumber,
                gMacroBlock->Line);
        }

        // Terminate on last macro line
        if (gMacroBlock->pNext) {
            gMacroBlock = gMacroBlock->pNext;
        } else {
            break;
        }
    }
    // Close existing file
    if (fMacro) {
        fclose(fMacro);
    }
#endif

    while (gMacroBlock->pNext) gMacroBlock=gMacroBlock->pNext;
    while (gMacroBlock) {
        pPrev = gMacroBlock->pPrev;
        free(gMacroBlock);
        gMacroBlock = pPrev;
    }
    while (gMacroStack) {
        pStack = gMacroStack->pNext;
        if (gMacroStack->LocalVariables) 
            ClearMQ2DataVariables(&gMacroStack->LocalVariables);
        if (gMacroStack->Parameters) 
            ClearMQ2DataVariables(&gMacroStack->Parameters);
        free(gMacroStack);
        gMacroStack = pStack;
    }
    gMacroSubLookupMap.clear(); 
    while (gEventQueue) {
        pEvent = gEventQueue->pNext;
        free(gEventQueue);
        gEventQueue = pEvent;
    }
    while (pEventList) {
        pEventL = pEventList->pNext;
        free(pEventList);
        pEventList = pEventL;
    }
#ifdef USEBLECHEVENTS
    pEventBlech->Reset();
#endif
    for  (i=0;i<NUM_EVENTS;i++) {
        gEventFunc[i]=NULL;
    }

    gMacroPause = FALSE;
    gEventChat=0;
    gFaceAngle=10000.0f;
    gLookAngle=10000.0f;
    gDelay = 0;
    gTurbo = FALSE;
    pDoorTarget = NULL;
#ifdef ISXEQ_LEGACY
    char ShortName[128];
    ShortName[0]=0;
    _splitpath(gszMacroName,0,0,ShortName,0);
    IS_ScriptEngineScriptEnds(pExtension,pISInterface,hScriptEngineService,&g_LegacyEngine,ShortName);
#endif

    gszMacroName[0]=0;
    gRunning = 0;

    if (!bKeepKeys) {
        KeyCombo TempCombo;
        for (i=0;gDiKeyID[i].szName[0];i++) 
        {
            TempCombo.Data[3]=(unsigned char)gDiKeyID[i].Id;
            MQ2HandleKeyUp(TempCombo);
        }
    }

    ClearMQ2DataVariables(&pMacroVariables);

    DebugSpewNoFile("EndMacro - Ended");
    if (gFilterMacro != FILTERMACRO_NONE && gFilterMacro != FILTERMACRO_MACROENDED)
        WriteChatColor("The current macro has ended.",USERCOLOR_DEFAULT);
}
// ***************************************************************************
// Function:    Next
// Description: Our '/next' command
// Usage:       /next v#
// ***************************************************************************
VOID Next(PSPAWNINFO pChar, PCHAR szLine)
{
    bRunNextCommand = TRUE;
    CHAR szComp[MAX_STRING] = {0};
    CHAR ForLine[MAX_STRING] = {0};
    CHAR szNext[MAX_STRING] = {0};
    PMACROBLOCK pMacroLine = gMacroBlock;
    LONG StepSize = 1;
    GetArg(szNext,szLine,1);

    PDATAVAR pVar = FindMQ2DataVariable(szNext);
    if (!pVar)
    {
        FatalError("/next using invalid variable");
        return;
    }
    if (pVar->Var.Type!=pIntType)
    {
        FatalError("/for loops must use an int variable");
        return;
    }

    if (!gMacroBlock) {
        MacroError("Can only use /next during a macro.");
        return;
    }
    sprintf(szComp,"/for %s ",pVar->szName);
    while (pMacroLine->pPrev) {
        strcpy(ForLine,pMacroLine->Line);
        if (!strnicmp(ForLine,"Sub ",4)) {
            FatalError("/next without matching /for");
            return;
        }
        if (strnicmp(ForLine,"/for ",5)) {
            pMacroLine = pMacroLine->pPrev;
            continue;
        }
        if (!strnicmp(ParseMacroParameter(pChar,ForLine),szComp,strlen(szComp))) {
            if (!gMacroBlock) {
                // PMP bailed on us, we need to exit...
                return;
            }
            CHAR szTemp[MAX_STRING] = {0};
            DWORD VarNum = atoi(szLine+1);
            LONG Loop;
            if (strstr(_strlwr(strcpy(szTemp,ForLine)),"step")) {
                PCHAR pTemp = strstr(szTemp,"step")+4;
                while ( (pTemp[0]!=0) && (pTemp[0]!=' ') && (pTemp[0]!='\t')) pTemp++;
                if (pTemp[0]!=0) StepSize = atoi(pTemp);
            }

            pVar = FindMQ2DataVariable(szNext);
            if (!pVar)
            {
                FatalError("/next without badly matching /for");
                return;
            }

            if (strstr(_strlwr(strcpy(szTemp,ForLine)),"downto")) 
            {
                Loop = atoi(strstr(szTemp,"downto")+7);
                DebugSpewNoFile("Next - End of loop %d downto %d", pVar->Var.Int, Loop);
                pVar->Var.Int-=StepSize;
                if (pVar->Var.Int >= Loop) 
                    gMacroBlock = pMacroLine;
            } 
            else 
            {
                Loop = atoi(strstr(szTemp,"to")+3);
                DebugSpewNoFile("Next - End of loop %d to %d", pVar->Var.Int, Loop);
                pVar->Var.Int+=StepSize;
                if (pVar->Var.Int <= Loop) 
                    gMacroBlock = pMacroLine;
            }
            return;
        }
        pMacroLine = pMacroLine->pPrev;
    }

    FatalError("/next without matching /for");
}