TRIGRET_TYPE CContainer::OnContTriggerForLoop( CScript &s, CTextConsole * pSrc, CScriptTriggerArgs * pArgs, CGString * pResult, CScriptLineContext & StartContext, CScriptLineContext & EndContext, RESOURCE_ID_BASE rid, DWORD dwArg, int iDecendLevels ) { ADDTOCALLSTACK("CContainer::OnContTriggerForLoop"); if ( rid.GetResIndex() != 0 ) { CItem* pItem = GetContentHead(); CItem * pItemNext; for ( ; pItem!=NULL; pItem=pItemNext) { pItemNext = pItem->GetNext(); if ( pItem->IsResourceMatch( rid, dwArg )) { s.SeekContext( StartContext ); TRIGRET_TYPE iRet = pItem->OnTriggerRun( s, TRIGRUN_SECTION_TRUE, pSrc, pArgs, pResult ); if ( iRet == TRIGRET_BREAK ) { EndContext = StartContext; break; } if (( iRet != TRIGRET_ENDIF ) && ( iRet != TRIGRET_CONTINUE )) return( iRet ); if ( iRet == TRIGRET_CONTINUE ) EndContext = StartContext; else EndContext = s.GetContext(); } if ( iDecendLevels <= 0 ) continue; CItemContainer * pCont = dynamic_cast <CItemContainer*>(pItem); if ( pCont != NULL ) { if ( pCont->IsSearchable()) { CContainer * pContBase = dynamic_cast <CContainer *> (pCont); TRIGRET_TYPE iRet = pContBase->OnContTriggerForLoop( s, pSrc, pArgs, pResult, StartContext, EndContext, rid, dwArg, iDecendLevels-1 ); if ( iRet != TRIGRET_ENDIF ) { return( iRet ); } // Since the previous call has already found the EndContext, set it. EndContext = s.GetContext(); } } } } if ( EndContext.m_lOffset <= StartContext.m_lOffset ) { CScriptObj * pScript = dynamic_cast <CScriptObj *> (this); TRIGRET_TYPE iRet = pScript->OnTriggerRun( s, TRIGRUN_SECTION_FALSE, pSrc, pArgs, pResult ); if ( iRet != TRIGRET_ENDIF ) return( iRet ); } else s.SeekContext( EndContext ); return( TRIGRET_ENDIF ); }
TRIGRET_TYPE CScriptObj::OnTriggerRun( CScript &s, TRIGRUN_TYPE trigrun, CTextConsole * pSrc, CScriptTriggerArgs * pArgs, CGString * pResult ) { // ARGS: // TRIGRUN_SECTION_SINGLE = just this 1 line. // RETURN: // TRIGRET_RET_FALSE = 0 = return and continue processing. // TRIGRET_RET_TRUE = 1 = return and handled. (halt further processing) // TRIGRET_RET_DEFAULT = 2 = if process returns nothing specifically. // CScriptFileContext set g_Log.m_pObjectContext is the current context (we assume) // DEBUGCHECK( this == g_Log.m_pObjectContext ); static LPCTSTR const m_ExcKeys[] = { "parsing", "parsing IF statement", "parsing begin/loop cycle", "foritem", "forchar", "forclients", "forobjs", "forplayers", "for", "while", "forcharlayer/memorytype", "forcont", "forcontid/type", "dorand/doswitch", "return", "CALLing a subfunction", "VERBing a value", }; #ifdef WIN32 EXC_TRY(("OnTriggerRun(%x,%i,%x,%x,%x)", s.GetKey(), trigrun, pSrc, pArgs, pResult)); #else EXC_TRY(("OnTriggerRun(??,%i,%x,%x,%x)", trigrun, pSrc, pArgs, pResult)); #endif bool fSectionFalse = (trigrun == TRIGRUN_SECTION_FALSE || trigrun == TRIGRUN_SINGLE_FALSE); if ( trigrun == TRIGRUN_SECTION_EXEC || trigrun == TRIGRUN_SINGLE_EXEC ) // header was already read in. goto jump_in; EXC_SET(m_ExcKeys[0]); while ( s.ReadKeyParse()) { // Hit the end of the next trigger. if ( s.IsKeyHead( "ON", 2 )) // done with this section. break; jump_in: SK_TYPE iCmd = (SK_TYPE) FindTableSorted( s.GetKey(), sm_szScriptKeys, COUNTOF( sm_szScriptKeys )-1 ); TRIGRET_TYPE iRet; switch ( iCmd ) { case SK_ENDIF: case SK_END: case SK_ENDDO: case SK_ENDFOR: case SK_ENDRAND: case SK_ENDSWITCH: case SK_ENDWHILE: return( TRIGRET_ENDIF ); case SK_ELIF: case SK_ELSEIF: return( TRIGRET_ELSEIF ); case SK_ELSE: return( TRIGRET_ELSE ); } if ( fSectionFalse ) { // Ignoring this whole section. don't bother parsing it. switch ( iCmd ) { case SK_IF: EXC_SET(m_ExcKeys[1]); do { iRet = OnTriggerRun( s, TRIGRUN_SECTION_FALSE, pSrc, pArgs, pResult ); } while ( iRet == TRIGRET_ELSEIF || iRet == TRIGRET_ELSE ); break; case SK_WHILE: case SK_FOR: case SK_FORCHARLAYER: case SK_FORCHARMEMORYTYPE: case SK_FORCHAR: case SK_FORCLIENTS: case SK_FORCONT: case SK_FORCONTID: case SK_FORCONTTYPE: case SK_FORITEM: case SK_FOROBJ: case SK_FORPLAYERS: case SK_DORAND: case SK_DOSWITCH: case SK_BEGIN: EXC_SET(m_ExcKeys[2]); iRet = OnTriggerRun( s, TRIGRUN_SECTION_FALSE, pSrc, pArgs, pResult ); break; } if ( trigrun >= TRIGRUN_SINGLE_EXEC ) return( TRIGRET_RET_DEFAULT ); continue; // just ignore it. } switch ( iCmd ) { case SK_FORITEM: EXC_SET(m_ExcKeys[3]); iRet = OnTriggerForLoop( s, 1, pSrc, pArgs, pResult ); break; case SK_FORCHAR: EXC_SET(m_ExcKeys[4]); iRet = OnTriggerForLoop( s, 2, pSrc, pArgs, pResult ); break; case SK_FORCLIENTS: EXC_SET(m_ExcKeys[5]); iRet = OnTriggerForLoop( s, 0x12, pSrc, pArgs, pResult ); break; case SK_FOROBJ: EXC_SET(m_ExcKeys[6]); iRet = OnTriggerForLoop( s, 3, pSrc, pArgs, pResult ); break; case SK_FORPLAYERS: EXC_SET(m_ExcKeys[7]); iRet = OnTriggerForLoop( s, 0x22, pSrc, pArgs, pResult ); break; case SK_FOR: EXC_SET(m_ExcKeys[8]); iRet = OnTriggerForLoop( s, 4, pSrc, pArgs, pResult ); break; case SK_WHILE: EXC_SET(m_ExcKeys[9]); iRet = OnTriggerForLoop( s, 8, pSrc, pArgs, pResult ); break; case SK_FORCHARLAYER: case SK_FORCHARMEMORYTYPE: { EXC_SET(m_ExcKeys[10]); CChar * pCharThis = dynamic_cast <CChar *> (this); if ( pCharThis ) { if ( s.HasArgs() ) { if ( iCmd == SK_FORCHARLAYER ) iRet = pCharThis->OnCharTrigForLayerLoop( s, pSrc, pArgs, pResult, (LAYER_TYPE) s.GetArgVal() ); else iRet = pCharThis->OnCharTrigForMemTypeLoop( s, pSrc, pArgs, pResult, s.GetArgVal() ); break; } } } case SK_FORCONT: { EXC_SET(m_ExcKeys[11]); if ( s.HasArgs() ) { TCHAR * ppArgs[2]; TCHAR * tempPoint; TCHAR *porigValue = Str_GetTemp(); int iArgQty = Str_ParseCmds( (TCHAR*) s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), " \t," ); if ( iArgQty >= 1 ) { strcpy(porigValue, ppArgs[0]); tempPoint = porigValue; ParseText( tempPoint, pSrc, 0, pArgs ); CGrayUID pCurUid = (DWORD) Exp_GetVal(tempPoint); if ( pCurUid.IsValidUID() ) { CObjBase * pObj = pCurUid.ObjFind(); if ( pObj && pObj->IsContainer() ) { CContainer * pContThis = dynamic_cast <CContainer *> (pObj); CScriptLineContext StartContext = s.GetContext(); CScriptLineContext EndContext = StartContext; iRet = pContThis->OnGenericContTriggerForLoop( s, pSrc, pArgs, pResult, StartContext, EndContext, ppArgs[1] != NULL ? Exp_GetVal(ppArgs[1]) : 255 ); break; } } } } } case SK_FORCONTID: case SK_FORCONTTYPE: { EXC_SET(m_ExcKeys[12]); CContainer * pCont = dynamic_cast <CContainer *> (this); if ( pCont ) { if ( s.HasArgs() ) { LPCTSTR pszKey = s.GetArgRaw(); SKIP_SEPERATORS(pszKey); TCHAR * ppArgs[2]; Str_ParseCmds( (TCHAR*) pszKey, ppArgs, COUNTOF(ppArgs), " \t," ); CScriptLineContext StartContext = s.GetContext(); CScriptLineContext EndContext = StartContext; #ifdef _WIN32 iRet = pCont->OnContTriggerForLoop( s, pSrc, pArgs, pResult, StartContext, EndContext, g_Cfg.ResourceGetID( ( iCmd == SK_FORCONTID ) ? RES_ITEMDEF : RES_TYPEDEF, ppArgs[0] ), 0, ppArgs[1] != NULL ? Exp_GetVal( ppArgs[1] ) : 255 ); #else iRet = pCont->OnContTriggerForLoop( s, pSrc, pArgs, pResult, StartContext, EndContext, g_Cfg.ResourceGetID( ( iCmd == SK_FORCONTID ) ? RES_ITEMDEF : RES_TYPEDEF, (const char*&) ppArgs[0] ), 0, ppArgs[1] != NULL ? Exp_GetVal( ppArgs[1] ) : 255 ); #endif break; } } } default: // Parse out any variables in it. (may act like a verb sometimes?) EXC_SET(m_ExcKeys[0]); ParseText( s.GetArgRaw(), pSrc, 0, pArgs ); } switch ( iCmd ) { case SK_FORITEM: case SK_FORCHAR: case SK_FORCHARLAYER: case SK_FORCHARMEMORYTYPE: case SK_FORCLIENTS: case SK_FORCONT: case SK_FORCONTID: case SK_FORCONTTYPE: case SK_FOROBJ: case SK_FORPLAYERS: case SK_FOR: case SK_WHILE: if ( iRet != TRIGRET_ENDIF ) { if ( iRet > TRIGRET_RET_DEFAULT ) { DEBUG_MSG(( "WARNING: Trigger Bad For Ret %d '%s','%s'\n", iRet, s.GetKey(), s.GetArgStr())); } return( iRet ); } break; case SK_DORAND: // Do a random line in here. case SK_DOSWITCH: { EXC_SET(m_ExcKeys[13]); int iVal = s.GetArgVal(); if ( iCmd == SK_DORAND ) iVal = Calc_GetRandVal(iVal); for ( ;true; iVal-- ) { iRet = OnTriggerRun( s, (!iVal) ? TRIGRUN_SINGLE_TRUE : TRIGRUN_SINGLE_FALSE, pSrc, pArgs, pResult ); if ( iRet == TRIGRET_RET_DEFAULT ) continue; if ( iRet == TRIGRET_ENDIF ) break; if ( iRet > TRIGRET_RET_DEFAULT ) { DEBUG_MSG(( "WARNING: Trigger Bad Ret %d '%s','%s'\n", iRet, s.GetKey(), s.GetArgStr())); } return( iRet ); } } break; case SK_RETURN: // Process the trigger. EXC_SET(m_ExcKeys[14]); if ( pResult ) { pResult->Copy( s.GetArgStr() ); return (TRIGRET_TYPE) 1; } return ( (TRIGRET_TYPE) s.GetArgVal() ); case SK_IF: { EXC_SET(m_ExcKeys[1]); bool fTrigger = s.GetArgVal() ? true : false; bool fBeenTrue = false; while (true) { iRet = OnTriggerRun( s, fTrigger ? TRIGRUN_SECTION_TRUE : TRIGRUN_SECTION_FALSE, pSrc, pArgs, pResult ); if ( iRet < TRIGRET_ENDIF ) return( iRet ); if ( iRet == TRIGRET_ENDIF ) break; fBeenTrue |= fTrigger; if ( fBeenTrue ) fTrigger = false; else if ( iRet == TRIGRET_ELSE ) fTrigger = true; else if ( iRet == TRIGRET_ELSEIF ) { ParseText( s.GetArgStr(), pSrc, 0, pArgs ); fTrigger = s.GetArgVal() ? true : false; } } } break; case SK_BEGIN: // Do this block here. { EXC_SET(m_ExcKeys[2]); iRet = OnTriggerRun( s, TRIGRUN_SECTION_TRUE, pSrc, pArgs, pResult ); if ( iRet != TRIGRET_ENDIF ) { if ( iRet > TRIGRET_RET_DEFAULT ) { DEBUG_MSG(( "WARNING: Trigger Bad Ret %d '%s','%s'\n", iRet, s.GetKey(), s.GetArgStr())); } return( iRet ); } } break; default: if ( IsSetEF( EF_Scripts_Parse_Verbs ) ) { EXC_SET(m_ExcKeys[0]); ParseText( s.GetKeyBuffer(), pSrc, 0, pArgs ); } EXC_SET(m_ExcKeys[0]); if ( pArgs && pArgs->r_Verb( s, pSrc ) ) ; else { bool fRes; if ( !strcmpi( (char *)s.GetKey(), "call" ) ) { EXC_SET(m_ExcKeys[15]); LPCTSTR pszArgs = strchr( s.GetArgRaw(), ' ' ); if ( pszArgs ) GETNONWHITESPACE( pszArgs ); if ( !pszArgs || !*pszArgs ) { fRes = this->r_Call( s.GetArgRaw(), pSrc, pArgs ); } else { CScriptTriggerArgs Args( pszArgs ); if ( pArgs ) Args.m_VarsLocal = pArgs->m_VarsLocal; fRes = this->r_Call( s.GetArgRaw(), pSrc, &Args ); if ( pArgs ) pArgs->m_VarsLocal = Args.m_VarsLocal; } } else { EXC_SET(m_ExcKeys[16]); fRes = r_Verb( s, pSrc ); } if ( !fRes ) { DEBUG_MSG(( "WARNING: Trigger Bad Verb '%s','%s'\n", s.GetKey(), s.GetArgStr())); } } break; } if ( trigrun >= TRIGRUN_SINGLE_EXEC ) return( TRIGRET_RET_DEFAULT ); } EXC_CATCH("running trigger line"); return( TRIGRET_RET_DEFAULT ); }
TRIGRET_TYPE CScriptObj::OnTriggerForLoop( CScript &s, int iType, CTextConsole * pSrc, CScriptTriggerArgs * pArgs, CGString * pResult ) { // loop from start here to the ENDFOR // See WebPageScriptList for dealing with Arrays. CScriptLineContext StartContext = s.GetContext(); CScriptLineContext EndContext = StartContext; int LoopsMade = 0; if ( iType & 8 ) // WHILE { TCHAR * pszCond; TCHAR *pszOrig = Str_GetTemp(); TCHAR *pszTemp = Str_GetTemp(); int iWhile = 0; strcpy( pszOrig, s.GetArgStr() ); while(true) { LoopsMade++; if ( g_Cfg.m_iMaxLoopTimes && ( LoopsMade >= g_Cfg.m_iMaxLoopTimes )) goto toomanyloops; pArgs->m_VarsLocal.SetNum( "_WHILE", iWhile, false ); iWhile++; strcpy( pszTemp, pszOrig ); pszCond = pszTemp; ParseText( pszCond, pSrc, 0, pArgs ); if ( !Exp_GetVal( pszCond ) ) break; TRIGRET_TYPE iRet = OnTriggerRun( s, TRIGRUN_SECTION_TRUE, pSrc, pArgs, pResult ); if ( iRet != TRIGRET_ENDIF ) { return( iRet ); } EndContext = s.GetContext(); s.SeekContext( StartContext ); } } else ParseText( s.GetArgStr(), pSrc, 0, pArgs ); if ( iType & 4 ) // FOR { int fCountDown = FALSE; int iMin = 0; int iMax = 0; int i; TCHAR * ppArgs[3]; int iQty = Str_ParseCmds( s.GetArgStr(), ppArgs, 3, ", " ); CGString sLoopVar = "_FOR"; switch( iQty ) { case 1: // FOR x iMin = 1; iMax = Exp_GetSingle( ppArgs[0] ); break; case 2: if ( isdigit( *ppArgs[0] ) ) { iMin = Exp_GetSingle( ppArgs[0] ); iMax = Exp_GetSingle( ppArgs[1] ); } else { iMin = 1; iMax = Exp_GetSingle( ppArgs[1] ); sLoopVar = ppArgs[0]; } break; case 3: sLoopVar = ppArgs[0]; iMin = Exp_GetSingle( ppArgs[1] );; iMax = Exp_GetSingle( ppArgs[2] ); break; default: iMin = iMax = 1; break; } if ( iMin > iMax ) fCountDown = true; if ( fCountDown ) for ( i = iMin; i >= iMax; --i ) { LoopsMade++; if ( g_Cfg.m_iMaxLoopTimes && ( LoopsMade >= g_Cfg.m_iMaxLoopTimes )) goto toomanyloops; pArgs->m_VarsLocal.SetNum( sLoopVar, i, false ); TRIGRET_TYPE iRet = OnTriggerRun( s, TRIGRUN_SECTION_TRUE, pSrc, pArgs, pResult ); if ( iRet != TRIGRET_ENDIF ) { return( iRet ); } EndContext = s.GetContext(); s.SeekContext( StartContext ); } else for ( i = iMin; i <= iMax; ++i ) { LoopsMade++; if ( g_Cfg.m_iMaxLoopTimes && ( LoopsMade >= g_Cfg.m_iMaxLoopTimes )) goto toomanyloops; pArgs->m_VarsLocal.SetNum( sLoopVar, i, false ); TRIGRET_TYPE iRet = OnTriggerRun( s, TRIGRUN_SECTION_TRUE, pSrc, pArgs, pResult ); if ( iRet != TRIGRET_ENDIF ) { return( iRet ); } EndContext = s.GetContext(); s.SeekContext( StartContext ); } } if ( (iType & 1) || (iType & 2) ) { int iDist; if ( s.HasArgs() ) iDist = s.GetArgVal(); else iDist = UO_MAP_VIEW_SIZE; CObjBaseTemplate * pObj = dynamic_cast <CObjBaseTemplate *>(this); if ( pObj == NULL ) { iType = 0; DEBUG_ERR(( "FOR Loop trigger on non-world object '%s'\n", GetName())); } CObjBaseTemplate * pObjTop = pObj->GetTopLevelObj(); CPointMap pt = pObjTop->GetTopPoint(); if ( iType & 1 ) // FORITEM, FOROBJ { CWorldSearch AreaItems( pt, iDist ); while(true) { LoopsMade++; if ( g_Cfg.m_iMaxLoopTimes && ( LoopsMade >= g_Cfg.m_iMaxLoopTimes )) goto toomanyloops; CItem * pItem = AreaItems.GetItem(); if ( pItem == NULL ) break; TRIGRET_TYPE iRet = pItem->OnTriggerRun( s, TRIGRUN_SECTION_TRUE, pSrc, pArgs, pResult ); if ( iRet != TRIGRET_ENDIF ) { return( iRet ); } EndContext = s.GetContext(); s.SeekContext( StartContext ); } } if ( iType & 2 ) // FORCHAR, FOROBJ { CWorldSearch AreaChars( pt, iDist ); while(true) { LoopsMade++; if ( g_Cfg.m_iMaxLoopTimes && ( LoopsMade >= g_Cfg.m_iMaxLoopTimes )) goto toomanyloops; CChar * pChar = AreaChars.GetChar(); if ( pChar == NULL ) break; if ( ( iType & 0x10 ) && ( ! pChar->IsClient() ) ) // FORCLIENTS continue; if ( ( iType & 0x20 ) && ( pChar->m_pPlayer == NULL ) ) // FORPLAYERS continue; TRIGRET_TYPE iRet = pChar->OnTriggerRun( s, TRIGRUN_SECTION_TRUE, pSrc, pArgs, pResult ); if ( iRet != TRIGRET_ENDIF ) { return( iRet ); } EndContext = s.GetContext(); s.SeekContext( StartContext ); } } } if ( g_Cfg.m_iMaxLoopTimes ) { toomanyloops: if ( LoopsMade >= g_Cfg.m_iMaxLoopTimes ) { g_Log.EventError("Terminating loop cycle since it seems being dead-locked (%d iterations already passed)" DEBUG_CR, LoopsMade); } } if ( EndContext.m_lOffset <= StartContext.m_lOffset ) { // just skip to the end. TRIGRET_TYPE iRet = OnTriggerRun( s, TRIGRUN_SECTION_FALSE, pSrc, pArgs, pResult ); if ( iRet != TRIGRET_ENDIF ) { return( iRet ); } } else { s.SeekContext( EndContext ); } return( TRIGRET_ENDIF ); }