CItem * CWorld::CheckNaturalResource( const CPointMap & pt, IT_TYPE Type, bool fTest, CChar * pCharSrc ) { ADDTOCALLSTACK("CWorld::CheckNaturalResource"); // RETURN: // The resource tracking item. // NULL = nothing here. if ( !pt.IsValidPoint() ) return NULL; EXC_TRY("CheckNaturalResource"); // Check/Decrement natural resources at this location. // We create an invis object to time out and produce more. // RETURN: Quantity they wanted. 0 = none here. if ( fTest ) // Is the resource avail at all here ? { EXC_SET("is item near type"); if ((Type != IT_TREE) && (Type != IT_ROCK) ) { if ( !g_World.IsTypeNear_Top(pt, Type, 0) ) return NULL; } else { if ( !g_World.IsItemTypeNear(pt, Type, 0, false) ) //cannot be used, because it does no Z check... what if there is a static tile 70 tiles under me? return NULL; } } // Find the resource object. EXC_SET("find existant bit"); CItem * pResBit; CWorldSearch Area(pt); for (;;) { pResBit = Area.GetItem(); if ( !pResBit ) break; // NOTE: ??? Not all resource objects are world gems. should they be ? // I wanted to make tree stumps etc be the resource block some day. if ( pResBit->IsType(Type) && pResBit->GetID() == ITEMID_WorldGem ) break; } // If none then create one. if ( pResBit ) return pResBit; // What type of ore is here ? // NOTE: This is unrelated to the fact that we might not be skilled enough to find it. // Odds of a vein of ore being present are unrelated to my skill level. // Odds of my finding it are. // RES_REGIONRESOURCE from RES_REGIONTYPE linked to RES_AREA EXC_SET("get region"); CRegionWorld* pRegion = dynamic_cast<CRegionWorld*>( pt.GetRegion( REGION_TYPE_AREA )); if ( !pRegion ) return NULL; CWorldSearch AreaItems( pt ); AreaItems.SetAllShow(1); for (;;) { CItem *pItem = AreaItems.GetItem(); if ( !pItem ) break; if ( pItem->GetType() != Type ) return NULL; } // just use the background (default) region for this if ( pRegion->m_Events.GetCount() <= 0 ) { CPointMap ptZero(0,0,0,pt.m_map); pRegion = dynamic_cast<CRegionWorld*>(ptZero.GetRegion(REGION_TYPE_AREA)); } // Find RES_REGIONTYPE EXC_SET("resource group"); const CRandGroupDef * pResGroup = pRegion->FindNaturalResource(Type); if ( !pResGroup ) return NULL; // Find RES_REGIONRESOURCE EXC_SET("get random group element"); size_t id = pResGroup->GetRandMemberIndex(pCharSrc); CRegionResourceDef * pOreDef; if ( id == pResGroup->BadMemberIndex() ) { pOreDef = dynamic_cast <CRegionResourceDef *> (g_Cfg.ResourceGetDefByName(RES_REGIONRESOURCE, "mr_nothing")); } else { RESOURCE_ID rid = pResGroup->GetMemberID( id ); pOreDef = dynamic_cast <CRegionResourceDef *>( g_Cfg.ResourceGetDef( rid )); } if ( !pOreDef ) return NULL; EXC_SET("create bit"); pResBit = CItem::CreateScript(ITEMID_WorldGem, pCharSrc); if ( !pResBit ) return NULL; pResBit->SetType(Type); pResBit->SetAttr(ATTR_INVIS|ATTR_MOVE_NEVER); pResBit->m_itResource.m_rid_res = pOreDef->GetResourceID(); // Total amount of ore here. int amount = pOreDef->m_Amount.GetRandom(); if ( Type == IT_ROCK && g_Cfg.m_iFeatureML & FEATURE_ML_RACIAL_BONUS && pCharSrc->IsHuman() && pCharSrc->GetTopMap() == 0 ) amount += 1; // Workhorse racial bonus, giving +1 ore to humans in Felucca. if ( Type == IT_TREE && g_Cfg.m_iFeatureML & FEATURE_ML_RACIAL_BONUS && pCharSrc->IsHuman() && pCharSrc->GetTopMap() == 1 ) amount += 2; // Workhorse racial bonus, giving +2 logs to humans in Trammel. pResBit->SetAmount( amount ); pResBit->MoveToDecay(pt, pOreDef->m_iRegenerateTime.GetRandom() * TICK_PER_SEC); // Delete myself in this amount of time. EXC_SET("resourcefound"); if ( pCharSrc != NULL) { CScriptTriggerArgs Args(0, 0, pResBit); TRIGRET_TYPE tRet = TRIGRET_RET_DEFAULT; if ( IsTrigUsed(TRIGGER_REGIONRESOURCEFOUND) ) tRet = pCharSrc->OnTrigger(CTRIG_RegionResourceFound, pCharSrc, &Args); if ( IsTrigUsed(TRIGGER_RESOURCEFOUND) ) tRet = pOreDef->OnTrigger("@ResourceFound", pCharSrc, &Args); if (tRet == TRIGRET_RET_TRUE) { if ( pResBit->IsDisconnected() ) return NULL; pResBit->SetAmount(0); } } return pResBit; EXC_CATCH; EXC_DEBUG_START; g_Log.EventDebug("point '%d,%d,%d,%d' type '%d' [0%lx]\n", pt.m_x, pt.m_y, pt.m_z, pt.m_map, static_cast<int>(Type), pCharSrc ? static_cast<DWORD>(pCharSrc->GetUID()) : 0); EXC_DEBUG_END; return NULL; }
DWORD CServerDef::StatGet(SERV_STAT_TYPE i) const { ADDTOCALLSTACK("CServerDef::StatGet"); ASSERT( i >= 0 && i <= SERV_STAT_QTY ); DWORD d = m_dwStat[i]; EXC_TRY("StatGet"); if ( i == SERV_STAT_MEM ) // memory information { d = 0; if ( m_bPmemory ) { #ifdef _WIN32 if ( !m_hmPsapiDll ) // try to load psapi.dll if not loaded yet { EXC_SET("load process info"); m_hmPsapiDll = LoadLibrary(TEXT("psapi.dll")); if (m_hmPsapiDll == NULL) { m_bPmemory = false; g_Log.EventError(("Unable to load process information PSAPI.DLL library. Memory information will be not available.\n")); } else { m_GetProcessMemoryInfo = reinterpret_cast<pGetProcessMemoryInfo>(::GetProcAddress(m_hmPsapiDll,"GetProcessMemoryInfo")); } } if ( m_GetProcessMemoryInfo ) { EXC_SET("open process"); HANDLE hProcess = GetCurrentProcess(); if ( hProcess ) { ASSERT( hProcess == (HANDLE)-1 ); EXC_SET("get memory info"); if ( m_GetProcessMemoryInfo(hProcess, &pcnt, sizeof(pcnt)) ) { EXC_SET("read memory info"); d = pcnt.WorkingSetSize; } CloseHandle(hProcess); } } #else struct rusage usage; int res = getrusage(RUSAGE_SELF, &usage); if ( res == 0 && usage.ru_idrss ) d = usage.ru_idrss; else { CFileText inf; TCHAR * buf = Str_GetTemp(), * head; sprintf(buf, "/proc/%d/status", getpid()); if ( inf.Open(buf, OF_READ|OF_TEXT) ) { for (;;) { if ( !inf.ReadString(buf, SCRIPT_MAX_LINE_LEN) ) break; if ( (head = strstr(buf, "VmSize:")) != NULL ) { head += 7; GETNONWHITESPACE(head) d = ATOI(head) * 1000; break; } } inf.Close(); } } if ( !d ) { g_Log.EventError(("Unable to load process information from getrusage() and procfs. Memory information will be not available.\n")); m_bPmemory = false; } #endif if ( d != 0 ) d /= 1024; } } return d; EXC_CATCH; EXC_DEBUG_START; g_Log.EventDebug("stat '%d', val '%lu'\n", i, d); EXC_DEBUG_END; return 0; }
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 ); }
int CScriptObj::ParseText( TCHAR * pszResponse, CTextConsole * pSrc, int iFlags, CScriptTriggerArgs * pArgs ) { // Take in a line of text that may have fields that can be replaced with operators here. // ex. "SPEAK hello there my friend <SRC.NAME> my name is <NAME>" // ARGS: // iFlags = 2=Allow recusive bracket count. 1=use HTML %% as the delimiters. // NOTE: // html will have opening <script language="GRAY_FILE"> and then closing </script> // RETURN: // New length of the string. // // Parsing flags LPCTSTR pszKey; // temporary, set below bool fRes; static LPCTSTR const m_ExcKeys[] = { "too many entrances", "CALLing subfunction", "writing value", "memcpy/memmove", }; static int sm_iReentrant = 0; static bool sm_fBrackets = false; // allowed to span multi lines. if ( ! (iFlags&2)) { // DEBUG_CHECK(!sm_iReentrant); sm_fBrackets = false; } int iBegin = 0; TCHAR chBegin = '<'; TCHAR chEnd = '>'; bool fHTML = (iFlags&1); if ( fHTML ) { chBegin = '%'; chEnd = '%'; } int i; EXC_TRY(("ParseText('%s',%x,%i,%x)", pszResponse, pSrc, iFlags, pArgs)); for ( i = 0; pszResponse[i]; i++ ) { TCHAR ch = pszResponse[i]; if ( ! sm_fBrackets ) // not in brackets { if ( ch == chBegin ) // found the start ! { if ( !( isalnum( pszResponse[i+1] ) || pszResponse[i+1] == '<' ) ) // ignore this. continue; iBegin = i; sm_fBrackets = true; } continue; } if ( ch == '<' ) // recursive brackets { if ( !( isalnum( pszResponse[i+1] ) || pszResponse[i+1] == '<' ) ) // ignore this. continue; if (sm_iReentrant > 32 ) { EXC_SET(m_ExcKeys[0]); ASSERT( sm_iReentrant < 32 ); } sm_iReentrant++; sm_fBrackets = false; int ilen = ParseText( pszResponse+i, pSrc, 2, pArgs ); sm_fBrackets = true; sm_iReentrant--; i += ilen; // DEBUG_CHECK( ilen < 256 ); continue; } if ( ch == chEnd ) { sm_fBrackets = false; pszResponse[i] = '\0'; CGString sVal; pszKey = (LPCTSTR) pszResponse+iBegin+1; if ( !strnicmp( pszKey, "CALL", 4 ) && isspace(pszKey[4]) ) { EXC_SET(m_ExcKeys[1]); pszKey += 4; GETNONWHITESPACE( pszKey ); LPCTSTR pszArgs = strchr( pszKey, ' ' ); if ( pszArgs ) GETNONWHITESPACE( pszArgs ); if ( !pszArgs || !*pszArgs ) { fRes = this->r_Call( pszKey, pSrc, pArgs, &sVal ); } else { CScriptTriggerArgs Args( pszArgs ); if ( pArgs ) Args.m_VarsLocal = pArgs->m_VarsLocal; fRes = this->r_Call( pszKey, pSrc, &Args, &sVal ); if ( pArgs ) pArgs->m_VarsLocal = Args.m_VarsLocal; } } else { if ( !strnicmp( pszKey, "SRC", 3 ) && pszKey[3] == '\0' ) { pszKey = pszKey; } EXC_SET(m_ExcKeys[2]); if ( !( fRes = r_WriteVal( pszKey, sVal, pSrc ) ) ) { EXC_SET(m_ExcKeys[2]); if ( pArgs && pArgs->r_WriteVal( pszKey, sVal, pSrc ) ) fRes = true; } } if ( !fRes ) { DEBUG_ERR(( "Can't resolve <%s>\n", pszKey )); // Just in case this really is a <= operator ? pszResponse[i] = chEnd; // continue; // by Kell } resolved: if ( sVal.IsEmpty() && fHTML ) { sVal = " "; } int len = sVal.GetLength(); EXC_SET(m_ExcKeys[3]); memmove( pszResponse+iBegin+len, pszResponse+i+1, strlen( pszResponse+i+1 ) + 1 ); EXC_SET(m_ExcKeys[3]); memcpy( pszResponse+iBegin, (LPCTSTR) sVal, len ); i = iBegin+len-1; if ( iFlags&2 ) // just do this one then bail out. return( i ); } } EXC_CATCH("Script parse text"); return( i ); }
bool CScript::ReadKeyParse() // Read line from script { ADDTOCALLSTACK("CScript::ReadKeyParse"); EXC_TRY("ReadKeyParse"); EXC_SET("read"); if ( !ReadKey(true) ) { EXC_SET("init"); InitKey(); return false; // end of section. } ASSERT(m_pszKey); GETNONWHITESPACE( m_pszKey ); EXC_SET("parse"); Str_Parse( m_pszKey, &m_pszArg ); //if ( !m_pszArg[0] || m_pszArg[1] != '=' || !strchr( ".*+-/%|&!^", m_pszArg[0] ) ) if ( !m_pszArg[0] || ( m_pszArg[1] != '=' && m_pszArg[1] != '+' && m_pszArg[1] != '-' ) || !strchr( ".*+-/%|&!^", m_pszArg[0] ) ) return true; static LPCTSTR const sm_szEvalTypes[] = { "eval", "floatval" }; EXC_SET("parse"); LPCTSTR pszArgs = m_pszArg; pszArgs += 2; GETNONWHITESPACE( pszArgs ); TemporaryString buf; int iKeyIndex = (strnicmp(m_pszKey, "float.", 6) == 0) ? 1 : 0; if ( m_pszArg[0] == '.' ) { if ( *pszArgs == '"' ) { TCHAR * pQuote = const_cast<TCHAR*>(strchr( pszArgs+1, '"' )); if ( pQuote ) { pszArgs++; *pQuote = '\0'; } } sprintf(buf, "<%s>%s", m_pszKey, pszArgs); } else if ( m_pszArg[0] == m_pszArg[1] && m_pszArg[1] == '+' ) { if ( m_pszArg[2] != '\0' ) return true; sprintf(buf, "<eval (<%s> +1)>", m_pszKey); } else if ( m_pszArg[0] == m_pszArg[1] && m_pszArg[1] == '-' ) { if ( m_pszArg[2] != '\0' ) return true; sprintf(buf, "<eval (<%s> -1)>", m_pszKey); } else { sprintf(buf, "<%s (<%s> %c (%s))>", sm_szEvalTypes[iKeyIndex], m_pszKey, *m_pszArg, pszArgs); } strcpy(m_pszArg, buf); return true; EXC_CATCH; return false; }
void CSector::OnTick(int iPulseCount) { ADDTOCALLSTACK_INTENSIVE("CSector::OnTick"); // CWorld gives OnTick() to all CSectors. EXC_TRY("Tick"); EXC_SET("light change"); // do not tick sectors on maps not supported by server if ( !g_MapList.m_maps[m_map] ) return; // Check for light change before putting the sector to sleep, since in other case the // world light levels will be shitty bool fEnvironChange = false; bool fLightChange = false; bool fSleeping = false; if ( ! ( iPulseCount & 0x7f )) // 30 seconds or so. { // check for local light level change ? BYTE blightprv = m_Env.m_Light; m_Env.m_Light = GetLightCalc( false ); if ( m_Env.m_Light != blightprv ) { fEnvironChange = true; fLightChange = true; } } EXC_SET("sector sleeping?"); size_t clients = m_Chars_Active.HasClients(); if ( clients <= 0 ) // having no clients inside { // Put the sector to sleep if no clients been here in a while. fSleeping = IsSectorSleeping(); if ( fSleeping ) { if ( !g_Cfg.m_iSectorSleepMask ) return; if (( iPulseCount & g_Cfg.m_iSectorSleepMask ) != ( GetIndex() & g_Cfg.m_iSectorSleepMask )) return; } } EXC_SET("sound effects"); // random weather noises and effects. SOUND_TYPE sound = 0; bool fWeatherChange = false; int iRegionPeriodic = 0; if ( ! ( iPulseCount & 0x7f )) // 30 seconds or so. { // Only do this every x minutes or so (TICK_PER_SEC) // check for local weather change ? WEATHER_TYPE weatherprv = m_Env.m_Weather; if ( ! Calc_GetRandVal( 30 )) // change less often { m_Env.m_Weather = GetWeatherCalc(); if ( weatherprv != m_Env.m_Weather ) { fWeatherChange = true; fEnvironChange = true; } } // Random area noises. Only do if clients about. if ( clients > 0 ) { iRegionPeriodic = 2; static const SOUND_TYPE sm_SfxRain[] = { 0x10, 0x11 }; static const SOUND_TYPE sm_SfxWind[] = { 0x14, 0x15, 0x16 }; static const SOUND_TYPE sm_SfxThunder[] = { 0x28, 0x29 , 0x206 }; // Lightning ? // wind, rain, switch ( GetWeather() ) { case WEATHER_CLOUDY: break; case WEATHER_SNOW: if ( ! Calc_GetRandVal(5) ) sound = sm_SfxWind[ Calc_GetRandVal( COUNTOF( sm_SfxWind )) ]; break; case WEATHER_RAIN: { int iVal = Calc_GetRandVal(30); if ( iVal < 5 ) { // Mess up the light levels for a sec.. LightFlash(); sound = sm_SfxThunder[ Calc_GetRandVal( COUNTOF( sm_SfxThunder )) ]; } else if ( iVal < 10 ) sound = sm_SfxRain[ Calc_GetRandVal( COUNTOF( sm_SfxRain )) ]; else if ( iVal < 15 ) sound = sm_SfxWind[ Calc_GetRandVal( COUNTOF( sm_SfxWind )) ]; } break; default: break; } } } // regen all creatures and do AI ProfileTask charactersTask(PROFILE_CHARS); CChar * pCharNext = NULL; CChar * pChar = static_cast<CChar *>(m_Chars_Active.GetHead()); for ( ; pChar != NULL; pChar = pCharNext ) { EXC_TRYSUB("TickChar"); pCharNext = pChar->GetNext(); if ( fEnvironChange && IsTrigUsed(TRIGGER_ENVIRONCHANGE) ) pChar->OnTrigger(CTRIG_EnvironChange, pChar); if ( pChar->m_pClient ) { if ( sound ) pChar->m_pClient->addSound(sound, pChar); if ( fLightChange && !pChar->IsStatFlag(STATF_DEAD|STATF_NightSight) ) pChar->m_pClient->addLight(); if ( fWeatherChange ) pChar->m_pClient->addWeather(GetWeather()); if ( iRegionPeriodic && pChar->m_pArea ) { if ( (iRegionPeriodic == 2) && IsTrigUsed(TRIGGER_REGPERIODIC) ) { pChar->m_pArea->OnRegionTrigger(pChar, RTRIG_REGPERIODIC); iRegionPeriodic--; } if ( IsTrigUsed(TRIGGER_CLIPERIODIC) ) pChar->m_pArea->OnRegionTrigger(pChar, RTRIG_CLIPERIODIC); } } // Can only die on your own tick. if ( !pChar->OnTick() ) pChar->Delete(); EXC_CATCHSUB("Sector"); EXC_DEBUGSUB_START; CPointMap pt = GetBasePoint(); g_Log.EventDebug("char 0%lx '%s'\n", static_cast<DWORD>(pChar->GetUID()), pChar->GetName()); g_Log.EventDebug("sector #%d [%d,%d,%d,%d]\n", GetIndex(), pt.m_x, pt.m_y, pt.m_z, pt.m_map); EXC_DEBUGSUB_END; } // decay items on ground = time out spells / gates etc.. etc.. // No need to check these so often ! ProfileTask itemsTask(PROFILE_ITEMS); CItem * pItemNext = NULL; CItem * pItem = dynamic_cast <CItem*>( m_Items_Timer.GetHead()); for ( ; pItem != NULL; pItem = pItemNext ) { EXC_TRYSUB("TickItem"); pItemNext = pItem->GetNext(); EXC_SETSUB("TimerExpired"); if ( pItem->IsTimerExpired() ) { EXC_SETSUB("ItemTick"); if ( !pItem->OnTick() ) { EXC_SETSUB("ItemDelete"); pItem->Delete(); } else { EXC_SETSUB("TimerExpired2"); if ( pItem->IsTimerExpired() ) // forgot to clear the timer.? strange. { EXC_SETSUB("SetTimeout"); pItem->SetTimeout(-1); } } } EXC_SETSUB("UpdateFlags"); pItem->OnTickStatusUpdate(); #ifdef _WIN32 EXC_CATCHSUB("Sector"); EXC_DEBUGSUB_START; CPointMap pt = GetBasePoint(); g_Log.EventError("item 0%lx '%s' [timer=%lld, type=%lld]\n", static_cast<DWORD>(pItem->GetUID()), pItem->GetName(), pItem->GetTimerAdjusted(), static_cast<int>(pItem->GetType())); g_Log.EventError("sector #%d [%d,%d,%d,%d]\n", GetIndex(), pt.m_x, pt.m_y, pt.m_z, pt.m_map); EXC_DEBUGSUB_END; #else } #ifndef _DEBUG catch ( const CGrayError& e )