void CSector::SetLightNow( bool fFlash ) { ADDTOCALLSTACK("CSector::SetLightNow"); // Set the light level for all the CClients here. CChar * pChar = STATIC_CAST <CChar*>( m_Chars_Active.GetHead()); for ( ; pChar != NULL; pChar = pChar->GetNext()) { if ( pChar->IsStatFlag( STATF_DEAD | STATF_NightSight )) continue; if ( pChar->IsClient()) { CClient * pClient = pChar->GetClient(); ASSERT(pClient); if ( fFlash ) // This does not seem to work predicably ! { BYTE bPrvLight = m_Env.m_Light; m_Env.m_Light = LIGHT_BRIGHT; // full bright. pClient->addLight(); m_Env.m_Light = bPrvLight; // back to previous. } pClient->addLight(); } // don't fire trigger when server is loading or light is flashing if (( ! g_Serv.IsLoading() && fFlash == false ) && ( IsTrigUsed(TRIGGER_ENVIRONCHANGE) )) { pChar->OnTrigger( CTRIG_EnvironChange, pChar ); } } }
int CItemMulti::Ship_ListObjs( CObjBase ** ppObjList ) { // List all the objects in the structure. // Move the ship and everything on the deck // If too much stuff. then some will fall overboard. hehe. if ( ! IsTopLevel()) return 0; int iMaxDist = Multi_GetMaxDist(); // always list myself first. All other items must see my new region ! int iCount = 0; ppObjList[iCount++] = this; CWorldSearch AreaChar( GetTopPoint(), iMaxDist ); while ( iCount < MAX_MULTI_LIST_OBJS ) { CChar * pChar = AreaChar.GetChar(); if ( pChar == NULL ) break; if ( pChar->IsClient()) { pChar->GetClient()->addPause(); // get rid of flicker. for anyone even seeing this. } if ( ! m_pRegion->IsInside2d( pChar->GetTopPoint())) continue; int zdiff = pChar->GetTopZ() - GetTopZ(); if ( abs( zdiff ) > 3 ) continue; ppObjList[iCount++] = pChar; } CWorldSearch AreaItem( GetTopPoint(), iMaxDist ); while ( iCount < MAX_MULTI_LIST_OBJS ) { CItem * pItem = AreaItem.GetItem(); if ( pItem == NULL ) break; if ( pItem == this ) // already listed. continue; if ( ! Multi_IsPartOf( pItem )) { if ( ! m_pRegion->IsInside2d( pItem->GetTopPoint())) continue; if ( ! pItem->IsMovable()) continue; int zdiff = pItem->GetTopZ() - GetTopZ(); if ( abs( zdiff ) > 3 ) continue; } ppObjList[iCount++] = pItem; } return( iCount ); }
// --------------------------------------------------------- bool CPartyDef::MessageEvent( CGrayUID uidDst, CGrayUID uidSrc, const NCHAR * pText, int ilenmsg ) { ADDTOCALLSTACK("CPartyDef::MessageEvent"); UNREFERENCED_PARAMETER(ilenmsg); if ( pText == NULL ) return( false ); if ( uidDst && !IsInParty( uidDst.CharFind() ) ) return( false ); CChar * pFrom = uidSrc.CharFind(); CChar * pTo = NULL; if ( uidDst != (DWORD) 0 ) pTo = uidDst.CharFind(); TCHAR * szText = Str_GetTemp(); CvtNUNICODEToSystem( szText, MAX_TALK_BUFFER, pText, MAX_TALK_BUFFER ); if ( ! m_pSpeechFunction.IsEmpty() ) { TRIGRET_TYPE tr = TRIGRET_RET_FALSE; CScriptTriggerArgs Args; Args.m_iN1 = uidSrc; Args.m_iN2 = uidDst; Args.m_s1 = szText; Args.m_s1_raw = szText; if ( r_Call(m_pSpeechFunction, &g_Serv, &Args, NULL, &tr) ) { if ( tr == TRIGRET_RET_TRUE ) return( false ); } } if ( g_Log.IsLoggedMask( LOGM_PLAYER_SPEAK )) g_Log.Event( LOGM_PLAYER_SPEAK, "%lx:'%s' Says '%s' in party to '%s'\n", pFrom->GetClient()->GetSocketID(), pFrom->GetName(), szText, pTo ? pTo->GetName() : "all" ); sprintf(szText, g_Cfg.GetDefaultMsg( DEFMSG_PARTY_MSG ), pText); PacketPartyChat cmd(pFrom, pText); if ( pTo != NULL ) SendMemberMsg(pTo, &cmd); else SendAll(&cmd); return( true ); }
// --------------------------------------------------------- void CPartyDef::AddStatsUpdate( CChar * pChar, PacketSend * pPacket ) { ADDTOCALLSTACK("CPartyDef::AddStatsUpdate"); size_t iQty = m_Chars.GetCharCount(); if ( iQty <= 0 ) return; for ( size_t i = 0; i < iQty; i++ ) { CChar * pCharNow = m_Chars.GetChar(i).CharFind(); if ( pCharNow && pCharNow != pChar ) { if ( pCharNow->CanSee( pChar ) && pCharNow->IsClient() ) pPacket->send(pCharNow->GetClient()); } } }
void CItemContainer::Trade_Delete() { ADDTOCALLSTACK("CItemContainer::Trade_Delete"); // Called when object deleted. ASSERT( IsType(IT_EQ_TRADE_WINDOW) ); CChar * pChar = dynamic_cast <CChar*> (GetParent()); if ( pChar == NULL ) return; if ( pChar->IsClient()) { // Send the cancel trade message. PacketTradeAction cmd(SECURE_TRADE_CLOSE); cmd.prepareClose(this); cmd.send(pChar->GetClient()); } // Drop items back in my pack. CItem * pItemNext; for ( CItem* pItem = GetContentHead(); pItem!=NULL; pItem=pItemNext) { pItemNext = pItem->GetNext(); pChar->ItemBounce( pItem ); } // Kill my trading partner. CItemContainer * pPartner = dynamic_cast <CItemContainer *> ( m_uidLink.ItemFind()); if ( pPartner == NULL ) return; if ( IsTrigUsed(TRIGGER_TRADECLOSE) ) { CChar * pChar2 = dynamic_cast <CChar*> (pPartner->GetParent()); CScriptTriggerArgs Args( pChar2 ); pChar->OnTrigger( CTRIG_TradeClose, pChar , &Args ); CScriptTriggerArgs Args2( pChar ); pChar2->OnTrigger( CTRIG_TradeClose, pChar, &Args2); } m_uidLink.InitUID(); // unlink. pPartner->m_uidLink.InitUID(); pPartner->Delete(); }
void CSector::SetSeason( SEASON_TYPE season ) { ADDTOCALLSTACK("CSector::SetSeason"); // Set the season type. if ( season == m_Env.m_Season ) return; m_Env.m_Season = season; CChar * pChar = STATIC_CAST <CChar*>( m_Chars_Active.GetHead()); for ( ; pChar != NULL; pChar = pChar->GetNext()) { if ( pChar->IsClient() ) pChar->GetClient()->addSeason(season); if ( IsTrigUsed(TRIGGER_ENVIRONCHANGE) ) pChar->OnTrigger(CTRIG_EnvironChange, pChar); } }
void CSector::SetWeather( WEATHER_TYPE w ) { ADDTOCALLSTACK("CSector::SetWeather"); // Set the immediate weather type. // 0=dry, 1=rain or 2=snow. if ( w == m_Env.m_Weather ) return; m_Env.m_Weather = w; CChar * pChar = STATIC_CAST <CChar*>( m_Chars_Active.GetHead()); for ( ; pChar != NULL; pChar = pChar->GetNext()) { if ( pChar->IsClient()) pChar->GetClient()->addWeather( w ); if ( IsTrigUsed(TRIGGER_ENVIRONCHANGE) ) pChar->OnTrigger( CTRIG_EnvironChange, pChar ); } }
bool CCharPlayer::r_LoadVal( CChar * pChar, CScript &s ) { ADDTOCALLSTACK("CCharPlayer::r_LoadVal"); EXC_TRY("LoadVal"); LPCTSTR pszKey = s.GetKey(); if ( !strnicmp(pszKey, "GMPAGE", 6) ) // GM pages { pszKey += 6; if ( *pszKey == '.' ) // GMPAGE.* { SKIP_SEPARATORS(pszKey); size_t index = Exp_GetVal(pszKey); if ( index >= g_World.m_GMPages.GetCount() ) return false; CGMPage* pPage = STATIC_CAST <CGMPage*> (g_World.m_GMPages.GetAt(index)); if ( pPage == NULL ) return false; SKIP_SEPARATORS(pszKey); if ( !strcmpi(pszKey, "HANDLE") ) { CChar *ppChar = pChar; LPCTSTR pszArgs = s.GetArgStr(); //Moved here because of error with quoted strings!?!? if ( *pszArgs ) ppChar = dynamic_cast<CChar*>(g_World.FindUID(s.GetArgVal())); if ( ppChar == NULL ) return false; CClient *pClient = ppChar->GetClient(); if ( pClient == NULL ) return false; pPage->SetGMHandler(pClient); } else if ( !strcmpi(pszKey, "DELETE") ) { delete pPage; } else if ( pPage->FindGMHandler() ) { CClient* pClient = pChar->GetClient(); if ( pClient != NULL && pClient->GetChar() != NULL ) pClient->Cmd_GM_PageCmd(pszKey); } else { return false; } return true; } return false; } else if ( ( !strnicmp(pszKey, "GUILD", 5) ) || ( !strnicmp(pszKey, "TOWN", 4) ) ) { bool bIsGuild = !strnicmp(pszKey, "GUILD", 5); pszKey += bIsGuild ? 5 : 4; if ( *pszKey == '.' ) { pszKey += 1; CItemStone *pMyGuild = pChar->Guild_Find(bIsGuild ? MEMORY_GUILD : MEMORY_TOWN); if ( pMyGuild ) return pMyGuild->r_SetVal(pszKey, s.GetArgRaw()); } return false; } switch ( FindTableHeadSorted( s.GetKey(), sm_szLoadKeys, COUNTOF( sm_szLoadKeys )-1 )) { case CPC_DEATHS: m_wDeaths = static_cast<WORD>(s.GetArgVal()); return true; case CPC_DSPEECH: return( m_Speech.r_LoadVal( s, RES_SPEECH )); case CPC_KILLS: m_wMurders = static_cast<WORD>(s.GetArgVal()); pChar->NotoSave_Update(); return true; case CPC_KRTOOLBARSTATUS: m_bKrToolbarEnabled = ( s.GetArgVal() != 0 ); if ( pChar->IsClient() ) pChar->GetClient()->addKRToolbar( m_bKrToolbarEnabled ); return true; case CPC_LASTUSED: m_timeLastUsed = CServTime::GetCurrentTime() - ( s.GetArgVal() * TICK_PER_SEC ); return( true ); case CPC_PFLAG: { m_pflag = s.GetArgVal(); } return( true ); case CPC_PROFILE: m_sProfile = Str_MakeFiltered( s.GetArgStr()); return( true ); case CPC_REFUSETRADES: pChar->SetDefNum(s.GetKey(), s.GetArgVal() > 0 ? 1 : 0, false); return( true ); case CPC_SKILLCLASS: return SetSkillClass( pChar, g_Cfg.ResourceGetIDType( RES_SKILLCLASS, s.GetArgStr())); case CPC_SKILLLOCK: { SKILL_TYPE skill = Skill_GetLockType( s.GetKey()); if ( skill <= SKILL_NONE ) return false; int bState = s.GetArgVal(); if ( bState < SKILLLOCK_UP || bState > SKILLLOCK_LOCK ) return false; Skill_SetLock(skill, static_cast<SKILLLOCK_TYPE>(bState)); } return true; case CPC_SPEEDMODE: { m_speedMode = static_cast<unsigned short>(s.GetArgVal()); pChar->UpdateSpeedMode(); } return true; case CPC_STATLOCK: { STAT_TYPE stat = Stat_GetLockType( s.GetKey()); if (( stat <= STAT_NONE ) || ( stat >= STAT_BASE_QTY )) return false; int bState = s.GetArgVal(); if ( bState < SKILLLOCK_UP || bState > SKILLLOCK_LOCK ) return false; Stat_SetLock(stat, static_cast<SKILLLOCK_TYPE>(bState)); } return true; default: // Just ignore any NPC type stuff. if ( FindTableSorted( s.GetKey(), CCharNPC::sm_szLoadKeys, COUNTOF( CCharNPC::sm_szLoadKeys )-1 ) >= 0 ) { return( true ); } return( false ); } EXC_CATCH; EXC_DEBUG_START; EXC_ADD_SCRIPT; EXC_DEBUG_END; 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); //pChar = STATIC_CAST <CChar*>( m_Chars_Active.GetHead()); CChar * pCharNext = NULL; CChar * pChar = dynamic_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->IsClient()) { CClient * pClient = pChar->GetClient(); ASSERT( pClient ); if ( sound ) pClient->addSound(sound, pChar); if ( fLightChange && ! pChar->IsStatFlag( STATF_DEAD | STATF_NightSight )) pClient->addLight(); if ( fWeatherChange ) 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 )
bool CSector::OnTick() { ADDTOCALLSTACK("CSector::OnTick"); /*Ticking sectors from CWorld * Timer is automatically updated at the end with a 30 seconds default delay * Any return before it will threat this CSector as Sleep and will make it * not tick again until a new player enters (WARNING: even if there are * players already inside). */ EXC_TRY("Tick"); // do not tick sectors on maps not supported by server if ( !g_MapList.m_maps[m_map] ) return true; EXC_SET_BLOCK("light change"); // 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; // 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_BLOCK("sector sleeping?"); bool fCanSleep = CanSleep(true); int64 iCurTime = CServerTime::GetCurrentTime().GetTimeRaw(); // Put the sector to sleep if no clients been here in a while. if (fCanSleep && (g_Cfg._iSectorSleepDelay > 0)) { if (!IsSleeping()) { GoSleep(); } return true; } EXC_SET_BLOCK("sound effects"); // random weather noises and effects. SOUND_TYPE sound = 0; bool fWeatherChange = false; int iRegionPeriodic = 0; 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 ( GetClientsNumber() > 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; } } // Check environ changes and inform clients of it. ProfileTask charactersTask(PROFILE_CHARS); CChar * pCharNext = nullptr; CChar * pChar = static_cast <CChar*>( m_Chars_Active.GetHead()); for ( ; pChar != nullptr; pChar = pCharNext ) { EXC_TRYSUB("TickChar"); pCharNext = pChar->GetNext(); if (( fEnvironChange ) && ( IsTrigUsed(TRIGGER_ENVIRONCHANGE) )) pChar->OnTrigger(CTRIG_EnvironChange, pChar); if ( pChar->IsClient()) { CClient * pClient = pChar->GetClient(); ASSERT( pClient ); if ( sound ) pClient->addSound(sound, pChar); if ( fLightChange && ! pChar->IsStatFlag( STATF_DEAD | STATF_NIGHTSIGHT )) pClient->addLight(); if ( fWeatherChange ) 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 ); } } EXC_CATCHSUB("Sector"); EXC_DEBUGSUB_START; CPointMap pt = GetBasePoint(); g_Log.EventDebug("#0 char 0%x '%s'\n", (dword)(pChar->GetUID()), pChar->GetName()); g_Log.EventDebug("#0 sector #%d [%d,%d,%d,%d]\n", GetIndex(), pt.m_x, pt.m_y, pt.m_z, pt.m_map); EXC_DEBUGSUB_END; } ProfileTask overheadTask(PROFILE_OVERHEAD); EXC_SET_BLOCK("check map cache"); if (fCanSleep && m_iMapBlockCacheTime < iCurTime) // Only if the sector can sleep. { // delete the static CServerMapBlock items that have not been used recently. m_iMapBlockCacheTime = CServerTime::GetCurrentTime().GetTimeRaw() + g_Cfg.m_iMapCacheTime ; CheckMapBlockCache(); } EXC_CATCH; SetTimeoutS(30); // Sector is Awake, make it tick after 30 seconds. EXC_DEBUG_START; CPointMap pt = GetBasePoint(); g_Log.EventError("#4 sector #%d [%hd,%hd,%hhd,%hhu]\n", GetIndex(), pt.m_x, pt.m_y, pt.m_z, pt.m_map); EXC_DEBUG_END; return true; }