// *************************************************************************** // 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); }
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; }
// *************************************************************************** // 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; } }
// *************************************************************************** // 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; } }
// *************************************************************************** // 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; } }
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; }
VOID InitializeParser() { DebugSpewNoFile("InitializeParser()"); InitializeMQ2DataTypes(); InitializeMQ2Data(); bmParseMacroParameter=AddMQ2Benchmark("ParseMacroParameter"); }
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"); }