bool CPartyDef::RemoveMember( CGrayUID uidRemove, CGrayUID uidCommand ) { ADDTOCALLSTACK("CPartyDef::RemoveMember"); // ARGS: // uidRemove = Who is being removed. // uidCommand = who removed this person (only the master or self can remove) // // NOTE: remove of the master will cause the party to disband. if ( m_Chars.GetCharCount() <= 0 ) return false; CGrayUID uidMaster = GetMaster(); if ( (uidRemove != uidCommand) && (uidCommand != uidMaster) ) return false; CChar *pCharRemove = uidRemove.CharFind(); if ( !pCharRemove ) return false; if ( !IsInParty(pCharRemove) ) return false; if ( uidRemove == uidMaster ) return Disband(uidMaster); CChar *pSrc = uidCommand.CharFind(); if ( pSrc && IsTrigUsed(TRIGGER_PARTYREMOVE) ) { CScriptTriggerArgs args; if ( pCharRemove->OnTrigger(CTRIG_PartyRemove, pSrc, &args) == TRIGRET_RET_TRUE ) return false; } if ( IsTrigUsed(TRIGGER_PARTYLEAVE) ) { if ( pCharRemove->OnTrigger(CTRIG_PartyLeave, pCharRemove, 0) == TRIGRET_RET_TRUE ) return false; } // Remove it from the party SendRemoveList(pCharRemove, true); DetachChar(pCharRemove); pCharRemove->SysMessageDefault(DEFMSG_PARTY_LEAVE_2); TCHAR *pszMsg = Str_GetTemp(); sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_PARTY_LEAVE_1), pCharRemove->GetName()); SysMessageAll(pszMsg); if ( m_Chars.GetCharCount() <= 1 ) { // Disband the party SysMessageAll(g_Cfg.GetDefaultMsg(DEFMSG_PARTY_LEAVE_LAST_PERSON)); return Disband(uidMaster); } return true; }
// Create an NPC from script. void CChar::NPC_LoadScript( bool fRestock ) { ADDTOCALLSTACK("CChar::NPC_LoadScript"); if ( m_pNPC == NULL ) // Set a default brian type til we get the real one from scripts. SetNPCBrain(GetNPCBrain(false)); // should have a default brain. watch out for override vendor. CCharBase * pCharDef = Char_GetDef(); // 1) CHARDEF trigger if ( m_pPlayer == NULL ) // CHARDEF triggers (based on body type) { CChar * pChar = this->GetChar(); if ( pChar != NULL ) { CUID uidOldAct = pChar->m_Act_Targ; pChar->m_Act_Targ = GetUID(); pChar->ReadScriptTrig(pCharDef, CTRIG_Create); pChar->m_Act_Targ = uidOldAct; } } //This remains untouched but moved after the chardef's section if (( fRestock ) && ( IsTrigUsed(TRIGGER_NPCRESTOCK) )) ReadScriptTrig(pCharDef, CTRIG_NPCRestock); CreateNewCharCheck(); //This one is giving stats, etc to the char, so we can read/set them in the next triggers. }
bool CChar::FollowersUpdate( CChar * pChar, short iFollowerSlots, bool bCheckOnly ) { ADDTOCALLSTACK("CChar::FollowersUpdate"); // Attemp to update followers on this character based on pChar // bSustract = true for pet's release, shrink, etc ... // This is supossed to be called only when OF_PetSlots is enabled, so no need to check it here. if ( !bCheckOnly && IsTrigUsed(TRIGGER_FOLLOWERSUPDATE) ) { CScriptTriggerArgs Args; Args.m_iN1 = (iFollowerSlots > 0) ? 0 : 1; Args.m_iN2 = abs(iFollowerSlots); if ( OnTrigger(CTRIG_FollowersUpdate, pChar, &Args) == TRIGRET_RET_TRUE ) return false; iFollowerSlots = static_cast<short>(Args.m_iN2); } short iCurFollower = static_cast<short>(GetDefNum("CURFOLLOWER", true, true)); short iMaxFollower = static_cast<short>(GetDefNum("MAXFOLLOWER", true, true)); short iSetFollower = iCurFollower + iFollowerSlots; if ( (iSetFollower > iMaxFollower) && !IsPriv(PRIV_GM) ) return false; if ( !bCheckOnly ) { SetDefNum("CURFOLLOWER", maximum(iSetFollower, 0)); UpdateStatsFlag(); } return true; }
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 ); } } }
bool CClient::Cmd_Skill_Inscription() { ADDTOCALLSTACK("CClient::Cmd_Skill_Inscription"); // Select the scroll type to make. // iSelect = -1 = 1st setup. // iSelect = 0 = cancel // iSelect = x = execute the selection. // we should already be in inscription skill mode. ASSERT(m_pChar); CItem *pBlankScroll = m_pChar->ContentFind(RESOURCE_ID(RES_TYPEDEF, IT_SCROLL_BLANK)); if ( !pBlankScroll ) { SysMessageDefault(DEFMSG_INSCRIPTION_FAIL); return false; } if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_inscription"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_inscription")); }
void CClient::CharDisconnect() { ADDTOCALLSTACK("CClient::CharDisconnect"); // Disconnect the CChar from the client. // Even tho the CClient might stay active. if ( !m_pChar ) return; Announce(false); bool fCanInstaLogOut = CanInstantLogOut(); int iLingerTime = g_Cfg.m_iClientLingerTime; // We are not a client anymore if ( m_bChatActive ) g_Serv.m_Chats.QuitChat(this); if ( m_pHouseDesign ) m_pHouseDesign->EndCustomize(true); if ( IsTrigUsed(TRIGGER_LOGOUT) ) { CScriptTriggerArgs Args(iLingerTime, fCanInstaLogOut); m_pChar->OnTrigger(CTRIG_LogOut, m_pChar, &Args); iLingerTime = static_cast<int>(Args.m_iN1); fCanInstaLogOut = (Args.m_iN2 != 0); } m_pChar->ClientDetach(); // we are not a client any more. if ( iLingerTime <= 0 ) fCanInstaLogOut = true; // Gump memory cleanup, we don't want them on logged out players m_mapOpenedGumps.clear(); // Layer dragging, moving it to backpack CItem *pItemDragging = m_pChar->LayerFind(LAYER_DRAGGING); if ( pItemDragging ) m_pChar->ItemBounce(pItemDragging); // log out immediately ? (test before ClientDetach()) if ( !fCanInstaLogOut ) { // become an NPC for a little while CItem *pItemChange = CItem::CreateBase(ITEMID_RHAND_POINT_W); ASSERT(pItemChange); pItemChange->SetName("Client Linger"); pItemChange->SetType(IT_EQ_CLIENT_LINGER); pItemChange->SetTimeout(iLingerTime); m_pChar->LayerAdd(pItemChange, LAYER_FLAG_ClientLinger); } else { // remove me from other clients screens now. m_pChar->SetDisconnected(); } m_pChar = NULL; }
bool CPartyDef::Disband( CGrayUID uidMaster ) { ADDTOCALLSTACK("CPartyDef::Disband"); // Make sure i am the master. if ( m_Chars.GetCharCount() <= 0 ) return false; if ( GetMaster() != uidMaster ) return false; CChar *pMaster = GetMaster().CharFind(); if ( pMaster && IsTrigUsed(TRIGGER_PARTYDISBAND) ) { CScriptTriggerArgs args; if ( pMaster->OnTrigger(CTRIG_PartyDisband, pMaster, &args) == TRIGRET_RET_TRUE ) return false; } SysMessageAll(g_Cfg.GetDefaultMsg(DEFMSG_PARTY_DISBANDED)); CChar *pSrc = uidMaster.CharFind(); size_t iQty = m_Chars.GetCharCount(); ASSERT(iQty > 0); CChar *pChar = NULL; for ( size_t i = 0; i < iQty; i++ ) { pChar = m_Chars.GetChar(i).CharFind(); if ( !pChar ) continue; if ( IsTrigUsed(TRIGGER_PARTYREMOVE) ) { CScriptTriggerArgs args; args.m_iN1 = 1; pChar->OnTrigger(CTRIG_PartyRemove, pSrc, &args); } SendRemoveList(pChar, true); DetachChar(pChar); } delete this; // should remove itself from the world list. return true; }
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(); }
bool CClient::Cmd_Skill_Smith( CItem *pIngots ) { ADDTOCALLSTACK("CClient::Cmd_Skill_Smith"); ASSERT(m_pChar); if ( !pIngots || !pIngots->IsType(IT_INGOT) ) { SysMessageDefault(DEFMSG_SMITHING_FAIL); return false; } ASSERT(m_Targ_UID == pIngots->GetUID()); if ( pIngots->GetTopLevelObj() != m_pChar ) { SysMessageDefault(DEFMSG_SMITHING_REACH); return false; } // Must have smith hammer equipped CItem *pSmithHammer = m_pChar->LayerFind(LAYER_HAND1); if ( !pSmithHammer || !pSmithHammer->IsType(IT_WEAPON_MACE_SMITH) ) { SysMessageDefault(DEFMSG_SMITHING_HAMMER); return false; } // Select the blacksmith item type. // repair items or make type of items. if ( !g_World.IsItemTypeNear(m_pChar->GetTopPoint(), IT_FORGE, 3, false, true) ) { SysMessageDefault(DEFMSG_SMITHING_FORGE); return false; } // Select the blacksmith item type. // repair items or make type of items. if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_blacksmith"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_blacksmith")); }
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 ); } }
void CContainer::ContentNotifyDelete() { ADDTOCALLSTACK("CContainer::ContentNotifyDelete"); if ( IsTrigUsed(TRIGGER_DESTROY) ) // no point entering this loop if the trigger is disabled return; // trigger @Destroy on contained items CItem *pItemNext = NULL; for (CItem *pItem = GetContentHead(); pItem != NULL; pItem = pItemNext) { pItemNext = pItem->GetNext(); if ( pItem->NotifyDelete() == false ) { // item shouldn't be destroyed and so cannot remain in this container, // drop it to the ground if it hasn't been moved already if (pItem->GetParent() == this) pItem->MoveToCheck( pItem->GetTopLevelObj()->GetTopPoint() ); } } }
void CChar::NPC_PetDesert() { ADDTOCALLSTACK("CChar::NPC_PetDesert"); CChar * pCharOwn = NPC_PetGetOwner(); if ( !pCharOwn ) return; if ( IsTrigUsed(TRIGGER_PETDESERT) ) { if ( OnTrigger( CTRIG_PetDesert, pCharOwn, NULL ) == TRIGRET_RET_TRUE ) return; } NPC_PetClearOwners(); if ( ! pCharOwn->CanSee(this)) pCharOwn->SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_DESERTED), GetName()); TCHAR *pszMsg = Str_GetTemp(); sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_DECIDE_MASTER), GetName()); Speak(pszMsg); // free to do as i wish ! Skill_Start( SKILL_NONE ); }
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 )
void CItemContainer::Trade_Status( bool bCheck ) { ADDTOCALLSTACK("CItemContainer::Trade_Status"); // Update trade status check boxes to both sides. CItemContainer *pPartner = dynamic_cast<CItemContainer*>(m_uidLink.ItemFind()); if ( !pPartner ) return; CChar *pChar1 = dynamic_cast<CChar*>(GetParent()); if ( !pChar1 ) return; CChar *pChar2 = dynamic_cast<CChar*>(pPartner->GetParent()); if ( !pChar2 ) return; m_itEqTradeWindow.m_bCheck = bCheck ? 1 : 0; if ( !bCheck ) pPartner->m_itEqTradeWindow.m_bCheck = 0; PacketTradeAction cmd(SECURE_TRADE_CHANGE); if ( pChar1->IsClient() ) { cmd.prepareReadyChange(this, pPartner); cmd.send(pChar1->GetClient()); } if ( pChar2->IsClient() ) { cmd.prepareReadyChange(pPartner, this); cmd.send(pChar2->GetClient()); } // Check if both clients had pressed the 'accept' buttom if ( pPartner->m_itEqTradeWindow.m_bCheck == 0 || m_itEqTradeWindow.m_bCheck == 0 ) return; CItem *pItem, *pItemNext; int iCont1, iCont2; unsigned short i; CScriptTriggerArgs Args1(pChar1); pItem = pPartner->GetContentHead(); for ( i = 1; pItem != NULL; pItem = pItemNext, ++i ) { pItemNext = pItem->GetNext(); Args1.m_VarObjs.Insert(i, pItem, true); } Args1.m_iN1 = iCont1 = --i; pItemNext = NULL; CScriptTriggerArgs Args2(pChar2); pItem = GetContentHead(); for ( i = 1; pItem != NULL; pItem = pItemNext, ++i ) { pItemNext = pItem->GetNext(); Args2.m_VarObjs.Insert(i, pItem, true); } Args2.m_iN1 = iCont2 = --i; pItemNext = NULL; if ( (IsTrigUsed(TRIGGER_TRADEACCEPTED)) || (IsTrigUsed(TRIGGER_CHARTRADEACCEPTED)) ) { Args1.m_iN2 = iCont2; Args2.m_iN2 = iCont1; if ( (pChar1->OnTrigger(CTRIG_TradeAccepted, pChar2, &Args1) == TRIGRET_RET_TRUE) || (pChar2->OnTrigger(CTRIG_TradeAccepted, pChar1, &Args2) == TRIGRET_RET_TRUE) ) Delete(); } // Transfer items pItem = GetContentHead(); for ( ; pItem != NULL; pItem = pItemNext ) { pItemNext = pItem->GetNext(); pChar2->ItemBounce(pItem); } pItemNext = NULL; pItem = pPartner->GetContentHead(); for ( ; pItem != NULL; pItem = pItemNext ) { pItemNext = pItem->GetNext(); pChar1->ItemBounce(pItem); } // Transfer gold/platinum if ( g_Cfg.m_iFeatureTOL & FEATURE_TOL_VIRTUALGOLD ) { INT64 iGold1 = m_itEqTradeWindow.m_iGold + (m_itEqTradeWindow.m_iPlatinum * 1000000000); INT64 iGold2 = pPartner->m_itEqTradeWindow.m_iGold + (pPartner->m_itEqTradeWindow.m_iPlatinum * 1000000000); pChar1->m_virtualGold += iGold2 - iGold1; pChar2->m_virtualGold += iGold1 - iGold2; pChar1->UpdateStatsFlag(); pChar2->UpdateStatsFlag(); } // done with trade. Delete(); }
int CChar::Do_Use_Item(CItem *pItem, bool fLink) { ADDTOCALLSTACK("CChar::Do_Use_Item"); if (!pItem) return false; if (m_pNPC && (IsTrigUsed(TRIGGER_DCLICK) || IsTrigUsed(TRIGGER_ITEMDCLICK))) // for players, DClick was called before this function { if (pItem->OnTrigger(ITRIG_DCLICK, this) == TRIGRET_RET_TRUE) return false; } CItemSpawn *pSpawn = static_cast<CItemSpawn *>(pItem->m_uidSpawnItem.ItemFind()); if (pSpawn) pSpawn->DelObj(pItem->GetUID()); // remove this item from it's spawn when DClicks it int fAction = true; switch(pItem->GetType()) { case IT_ITEM_STONE: { // Give them this item if (pItem->m_itItemStone.m_wAmount == USHRT_MAX) { SysMessageDefault(DEFMSG_MSG_IT_IS_DEAD); return true; } if (pItem->m_itItemStone.m_wRegenTime) { if (pItem->IsTimerSet()) { SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_MSG_STONEREG_TIME), pItem->GetTimerDiff() / TICK_PER_SEC); return true; } pItem->SetTimeout(pItem->m_itItemStone.m_wRegenTime * TICK_PER_SEC); } ItemBounce(CItem::CreateTemplate(pItem->m_itItemStone.m_ItemID, GetPackSafe(), this)); if (pItem->m_itItemStone.m_wAmount != 0) { pItem->m_itItemStone.m_wAmount--; if (pItem->m_itItemStone.m_wAmount == 0) pItem->m_itItemStone.m_wAmount = USHRT_MAX; } return true; } case IT_SEED: return Use_Seed(pItem, NULL); case IT_BEDROLL: return Use_BedRoll(pItem); case IT_KINDLING: return Use_Kindling(pItem); case IT_SPINWHEEL: { if (fLink) return false; // Just make them spin pItem->SetAnim(static_cast<ITEMID_TYPE>(pItem->GetID() + 1), 2 * TICK_PER_SEC); SysMessageDefault(DEFMSG_ITEMUSE_SPINWHEEL); return true; } case IT_TRAIN_DUMMY: { if (fLink) return false; Use_Train_Dummy(pItem, true); return true; } case IT_TRAIN_PICKPOCKET: { if (fLink) return false; Use_Train_PickPocketDip(pItem, true); return true; } case IT_ARCHERY_BUTTE: { if (fLink) return false; Use_Train_ArcheryButte(pItem, true); return true; } case IT_LOOM: { if (fLink) return false; SysMessageDefault(DEFMSG_ITEMUSE_LOOM); return true; } case IT_BEE_HIVE: { if (fLink) return false; // Get honey from it ITEMID_TYPE id = ITEMID_NOTHING; if (!pItem->m_itBeeHive.m_honeycount) SysMessageDefault(DEFMSG_ITEMUSE_BEEHIVE); else { switch(Calc_GetRandVal(3)) { case 1: id = ITEMID_JAR_HONEY; break; case 2: id = ITEMID_BEE_WAX; break; } } if (id) { ItemBounce(CItem::CreateScript(id, this)); pItem->m_itBeeHive.m_honeycount--; } else { SysMessageDefault(DEFMSG_ITEMUSE_BEEHIVE_STING); OnTakeDamage(Calc_GetRandVal(5), this, DAMAGE_POISON | DAMAGE_GENERAL); } pItem->SetTimeout(15 * 60 * TICK_PER_SEC); return true; } case IT_MUSICAL: { if (!Skill_Wait(SKILL_MUSICIANSHIP)) { m_Act_Targ = pItem->GetUID(); Skill_Start(SKILL_MUSICIANSHIP); } break; } case IT_CROPS: case IT_FOLIAGE: { // Pick cotton/hay/etc fAction = pItem->Plant_Use(this); break; } case IT_FIGURINE: { // Create the creature here if (Use_Figurine(pItem) != NULL) pItem->Delete(); return true; } case IT_TRAP: case IT_TRAP_ACTIVE: { // Activate the trap (plus any linked traps) int iDmg = pItem->Use_Trap(); if (CanTouch(pItem->GetTopLevelObj()->GetTopPoint())) OnTakeDamage(iDmg, NULL, DAMAGE_HIT_BLUNT | DAMAGE_GENERAL); break; } case IT_SWITCH: { // Switches can be linked to gates and doors and such. // Flip the switch graphic. pItem->SetSwitchState(); break; } case IT_PORT_LOCKED: if (!fLink && !IsPriv(PRIV_GM)) { SysMessageDefault(DEFMSG_ITEMUSE_PORT_LOCKED); return true; } case IT_PORTCULIS: // Open a metal gate vertically pItem->Use_Portculis(); break; case IT_DOOR_LOCKED: if (!ContentFindKeyFor(pItem)) { SysMessageDefault(DEFMSG_MSG_KEY_DOORLOCKED); if (!pItem->IsTopLevel()) return false; if (pItem->IsAttr(ATTR_MAGIC)) // show it's magic face { ITEMID_TYPE id = (GetDispID() & DOOR_NORTHSOUTH) ? ITEMID_DOOR_MAGIC_SI_NS : ITEMID_DOOR_MAGIC_SI_EW; CItem *pFace = CItem::CreateBase(id); ASSERT(pFace); pFace->MoveToDecay(pItem->GetTopPoint(), 4 * TICK_PER_SEC); } if (!IsPriv(PRIV_GM)) return true; } case IT_DOOR_OPEN: case IT_DOOR: { bool fOpen = pItem->Use_DoorNew(fLink); if (fLink || !fOpen) // don't link if we are just closing the door return true; } break; case IT_SHIP_PLANK: { // Close the plank if I'm inside the ship if (m_pArea->IsFlag(REGION_FLAG_SHIP) && m_pArea->GetResourceID() == pItem->m_uidLink) { if (pItem->m_itShipPlank.m_itSideType == IT_SHIP_SIDE_LOCKED && !ContentFindKeyFor(pItem)) { SysMessageDefault(DEFMSG_ITEMUSE_SHIPSIDE); return true; } return pItem->Ship_Plank(false); } else if (pItem->IsTopLevel()) { // Teleport to plank if I'm outside the ship CPointMap pntTarg = pItem->GetTopPoint(); pntTarg.m_z++; Spell_Teleport(pntTarg, true, false, false); } return true; } case IT_SHIP_SIDE_LOCKED: if (!ContentFindKeyFor(pItem)) { SysMessageDefault(DEFMSG_ITEMUSE_SHIPSIDE); return true; } case IT_SHIP_SIDE: // Open the plank pItem->Ship_Plank(true); return true; case IT_GRAIN: case IT_GRASS: case IT_GARBAGE: case IT_FRUIT: case IT_FOOD: case IT_FOOD_RAW: case IT_MEAT_RAW: { if (fLink) return false; Use_Eat(pItem); return true; } case IT_POTION: case IT_DRINK: case IT_PITCHER: case IT_WATER_WASH: case IT_BOOZE: { if (fLink) return false; Use_Drink(pItem); return true; } case IT_LIGHT_OUT: // can the light be lit? case IT_LIGHT_LIT: // can the light be doused? fAction = pItem->Use_Light(); break; case IT_CLOTHING: case IT_ARMOR: case IT_ARMOR_LEATHER: case IT_SHIELD: case IT_WEAPON_MACE_CROOK: case IT_WEAPON_MACE_PICK: case IT_WEAPON_MACE_SMITH: case IT_WEAPON_MACE_SHARP: case IT_WEAPON_SWORD: case IT_WEAPON_FENCE: case IT_WEAPON_BOW: case IT_WEAPON_AXE: case IT_WEAPON_XBOW: case IT_WEAPON_MACE_STAFF: case IT_JEWELRY: case IT_WEAPON_THROWING: { if (fLink) return false; return ItemEquip(pItem); } case IT_WEB: { if (fLink) return false; Use_Item_Web(pItem); return true; } case IT_SPY_GLASS: { if (fLink) return false; // Spyglass will tell you the moon phases static LPCTSTR const sm_sPhases[8] = { g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M1), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M2), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M3), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M4), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M5), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M6), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M7), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M8) }; SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_TR), sm_sPhases[g_World.GetMoonPhase(false)]); SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_FE), sm_sPhases[g_World.GetMoonPhase(true)]); if (m_pArea && m_pArea->IsFlag(REGION_FLAG_SHIP)) ObjMessage(pItem->Use_SpyGlass(this), this); return true; } case IT_SEXTANT: { if (fLink) return false; if ((GetTopPoint().m_map <= 1) && (GetTopPoint().m_x > UO_SIZE_X_REAL)) // dungeons and T2A lands ObjMessage(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SEXTANT_T2A), this); else { TCHAR *pszMsg = Str_GetTemp(); sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SEXTANT), m_pArea->GetName(), pItem->Use_Sextant(GetTopPoint())); ObjMessage(pszMsg, this); } return true; } default: fAction = false; } return fAction | MASK_RETURN_FOLLOW_LINKS; }
bool CClient::Cmd_Use_Item( CItem *pItem, bool fTestTouch, bool fScript ) { ADDTOCALLSTACK("CClient::Cmd_Use_Item"); // Assume we can see the target. // called from Event_DoubleClick if ( !pItem ) return false; if ( pItem->m_Can & CAN_I_FORCEDC ) fTestTouch = false; if ( fTestTouch ) { if ( !fScript ) { CItemContainer *pContainer = dynamic_cast<CItemContainer *>(pItem->GetParent()); if ( pContainer ) { // protect from ,snoop - disallow picking from not opened containers bool isInOpenedContainer = false; if ( pContainer->GetType() == IT_EQ_TRADE_WINDOW ) isInOpenedContainer = true; else { CClient::OpenedContainerMap_t::iterator itContainerFound = m_openedContainers.find(pContainer->GetUID().GetPrivateUID()); if ( itContainerFound != m_openedContainers.end() ) { DWORD dwTopContainerUID = (((*itContainerFound).second).first).first; DWORD dwTopMostContainerUID = (((*itContainerFound).second).first).second; CPointMap ptOpenedContainerPosition = ((*itContainerFound).second).second; const CObjBaseTemplate *pObjTop = pItem->GetTopLevelObj(); const CObjBase *pObjParent = pContainer->GetParentObj(); DWORD dwTopContainerUID_ToCheck = 0; if ( pObjParent ) dwTopContainerUID_ToCheck = pObjParent->GetUID().GetPrivateUID(); else dwTopContainerUID_ToCheck = pObjTop->GetUID().GetPrivateUID(); if ( (dwTopMostContainerUID == pObjTop->GetUID().GetPrivateUID()) && (dwTopContainerUID == dwTopContainerUID_ToCheck) ) { if ( pObjTop->IsChar() ) { // probably a pickup check from pack if pCharTop != this? isInOpenedContainer = true; } else { const CItem *pItemTop = static_cast<const CItem *>(pObjTop); if ( pItemTop && (pItemTop->IsType(IT_SHIP_HOLD) || pItemTop->IsType(IT_SHIP_HOLD_LOCK)) && (pItemTop->GetTopPoint().GetRegion(REGION_TYPE_MULTI) == m_pChar->GetTopPoint().GetRegion(REGION_TYPE_MULTI)) ) isInOpenedContainer = true; else if ( ptOpenedContainerPosition.GetDist(pObjTop->GetTopPoint()) <= 3 ) isInOpenedContainer = true; } } } } if ( !isInOpenedContainer ) { SysMessageDefault(DEFMSG_REACH_UNABLE); return false; } } } // CanTouch handles priv level compares for chars if ( !m_pChar->CanUse(pItem, false) ) { if ( !m_pChar->CanTouch(pItem) ) SysMessage((m_pChar->IsStatFlag(STATF_DEAD)) ? g_Cfg.GetDefaultMsg(DEFMSG_REACH_GHOST) : g_Cfg.GetDefaultMsg(DEFMSG_REACH_FAIL)); else SysMessageDefault(DEFMSG_REACH_UNABLE); return false; } } if ( IsTrigUsed(TRIGGER_DCLICK) || IsTrigUsed(TRIGGER_ITEMDCLICK) ) { if ( pItem->OnTrigger(ITRIG_DCLICK, m_pChar) == TRIGRET_RET_TRUE ) return true; } CItemBase *pItemDef = pItem->Item_GetDef(); bool bIsEquipped = pItem->IsItemEquipped(); if ( pItemDef->IsTypeEquippable() && !bIsEquipped && pItemDef->GetEquipLayer() ) { bool bMustEquip = true; if ( pItem->IsTypeSpellbook() ) bMustEquip = false; else if ( (pItem->IsType(IT_LIGHT_OUT) || pItem->IsType(IT_LIGHT_LIT)) && !pItem->IsItemInContainer() ) bMustEquip = false; if ( bMustEquip ) { if ( !m_pChar->CanMove(pItem) ) return false; if ( !m_pChar->CanCarry(pItem) ) { SysMessageDefault(DEFMSG_MSG_HEAVY); return false; } if ( !m_pChar->ItemEquip(pItem, NULL, true) ) return false; } } CItemSpawn *pSpawn = static_cast<CItemSpawn *>(pItem->m_uidSpawnItem.ItemFind()); // remove this item from its spawn when players DClick it from ground, no other way to take it out. if ( pSpawn ) pSpawn->DelObj(pItem->GetUID()); SetTargMode(); m_Targ_PrvUID = m_Targ_UID; m_Targ_UID = pItem->GetUID(); m_tmUseItem.m_pParent = pItem->GetParent(); // store item location to check later if it was not moved // Use types of items (specific to client) switch ( pItem->GetType() ) { case IT_TRACKER: { if ( !m_pChar->Skill_Tracking(pItem->m_uidLink) ) { if ( pItem->m_uidLink.IsValidUID() ) SysMessageDefault(DEFMSG_TRACKING_UNABLE); addTarget(CLIMODE_TARG_LINK, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_TRACKER_ATTUNE)); } return true; } case IT_SHAFT: case IT_FEATHER: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_bolts"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_bolts")); } case IT_FISH_POLE: // Just be near water ? addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_FISHING_PROMT), true); return true; case IT_DEED: addTargetDeed(pItem); return true; case IT_EQ_BANK_BOX: case IT_EQ_VENDOR_BOX: if ( !fScript ) g_Log.Event(LOGL_WARN|LOGM_CHEAT, "%lx:Cheater '%s' is using 3rd party tools to open bank box\n", GetSocketID(), m_pAccount->GetName()); return false; case IT_CONTAINER_LOCKED: case IT_SHIP_HOLD_LOCK: if ( !m_pChar->GetContainerCreate(LAYER_PACK)->ContentFindKeyFor(pItem) ) { SysMessageDefault(DEFMSG_ITEMUSE_LOCKED); if ( !IsPriv(PRIV_GM) ) return false; } case IT_CORPSE: case IT_SHIP_HOLD: case IT_CONTAINER: case IT_TRASH_CAN: { CItemContainer *pPack = static_cast<CItemContainer *>(pItem); if ( !pPack ) return false; if ( !m_pChar->Skill_Snoop_Check(pPack) ) { if ( !addContainerSetup(pPack) ) return false; } const CItemCorpse *pCorpseItem = static_cast<const CItemCorpse *>(pPack); if ( m_pChar->CheckCorpseCrime(pCorpseItem, true, true) ) SysMessageDefault(DEFMSG_LOOT_CRIMINAL_ACT); return true; } case IT_GAME_BOARD: { if ( !pItem->IsTopLevel() ) { SysMessageDefault(DEFMSG_ITEMUSE_GAMEBOARD_FAIL); return false; } CItemContainer *pBoard = static_cast<CItemContainer *>(pItem); ASSERT(pBoard); pBoard->Game_Create(); addContainerSetup(pBoard); return true; } case IT_BBOARD: addBulletinBoard(static_cast<CItemContainer *>(pItem)); return true; case IT_SIGN_GUMP: { GUMP_TYPE gumpid = pItemDef->m_ttContainer.m_gumpid; if ( !gumpid ) return false; addGumpTextDisp(pItem, gumpid, pItem->GetName(), pItem->IsIndividualName() ? pItem->GetName() : NULL); return true; } case IT_BOOK: case IT_MESSAGE: { if ( !addBookOpen(pItem) ) SysMessageDefault(DEFMSG_ITEMUSE_BOOK_FAIL); return true; } case IT_STONE_GUILD: case IT_STONE_TOWN: return true; case IT_POTION: { if ( !m_pChar->CanMove(pItem) ) { SysMessageDefault(DEFMSG_ITEMUSE_POTION_FAIL); return false; } if ( RES_GET_INDEX(pItem->m_itPotion.m_Type) == SPELL_Poison ) { // If we click directly on poison potion, we will drink poison and get ill. // To use it on Poisoning skill, the skill will request to target the potion. m_pChar->OnSpellEffect(SPELL_Poison, m_pChar, pItem->m_itSpell.m_spelllevel, NULL); return true; } if ( RES_GET_INDEX(pItem->m_itPotion.m_Type) == SPELL_Explosion ) { // Throw explosion potion if ( !m_pChar->ItemPickup(pItem, 1) ) // put the potion in our hand return false; pItem->m_itPotion.m_tick = 4; // countdown to explode pItem->m_itPotion.m_ignited = 1; // ignite it pItem->m_uidLink = m_pChar->GetUID(); pItem->SetTimeout(TICK_PER_SEC); m_tmUseItem.m_pParent = pItem->GetParent(); addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_POTION_TARGET), true, true, pItem->m_itPotion.m_tick * TICK_PER_SEC); return true; } m_pChar->Use_Drink(pItem); return true; } case IT_ANIM_ACTIVE: SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_ITEM_IN_USE)); return false; case IT_CLOCK: addObjMessage(m_pChar->GetTopSector()->GetLocalGameTime(), pItem); return true; case IT_SPAWN_ITEM: case IT_SPAWN_CHAR: { pSpawn = static_cast<CItemSpawn *>(pItem); if ( !pSpawn ) return false; if ( pSpawn->m_currentSpawned ) { SysMessageDefault(DEFMSG_ITEMUSE_SPAWN_NEG); pSpawn->KillChildren(); // Removing existing objects spawned from it ( RESET ). } else { SysMessageDefault(DEFMSG_ITEMUSE_SPAWN_RESET); pSpawn->OnTick(true); // Forcing the spawn to work and create some objects ( START ). } return true; } case IT_SHRINE: { if ( m_pChar->OnSpellEffect(SPELL_Resurrection, m_pChar, 1000, pItem) ) return true; SysMessageDefault(DEFMSG_ITEMUSE_SHRINE); return true; } case IT_SHIP_TILLER: pItem->Speak(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_TILLERMAN), HUE_TEXT_DEF, TALKMODE_SAY, FONT_NORMAL); return true; case IT_WAND: case IT_SCROLL: { SPELL_TYPE spell = static_cast<SPELL_TYPE>(RES_GET_INDEX(pItem->m_itWeapon.m_spell)); CSpellDef *pSpellDef = g_Cfg.GetSpellDef(spell); if ( !pSpellDef ) return false; if ( IsSetMagicFlags(MAGICF_PRECAST) && !pSpellDef->IsSpellType(SPELLFLAG_NOPRECAST) ) { int skill; if ( !pSpellDef->GetPrimarySkill(&skill, NULL) ) return false; m_tmSkillMagery.m_Spell = spell; // m_atMagery.m_Spell m_pChar->m_atMagery.m_Spell = spell; m_pChar->Skill_Start(static_cast<SKILL_TYPE>(skill)); return true; } return Cmd_Skill_Magery(spell, pItem); } case IT_RUNE: { if ( !m_pChar->CanMove(pItem, true) ) return false; addPromptConsole(CLIMODE_PROMPT_NAME_RUNE, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_RUNE_NAME), pItem->GetUID()); return true; } case IT_CARPENTRY: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_carpentry"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_carpentry")); } case IT_FORGE: // Solve for the combination of this item with another. addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_FORGE)); return true; case IT_ORE: return m_pChar->Skill_Mining_Smelt(pItem, NULL); case IT_INGOT: return Cmd_Skill_Smith(pItem); case IT_KEY: case IT_KEYRING: { if ( pItem->GetTopLevelObj() != m_pChar && !m_pChar->IsPriv(PRIV_GM) ) { SysMessageDefault(DEFMSG_ITEMUSE_KEY_FAIL); return false; } addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_KEY_PROMT), false, true); return true; } case IT_BANDAGE: // SKILL_HEALING, or SKILL_VETERINARY addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_BANDAGE_PROMT), false, false); return true; case IT_BANDAGE_BLOOD: // Clean the bandages. case IT_COTTON: // use on a spinning wheel. case IT_WOOL: // use on a spinning wheel. case IT_YARN: // Use this on a loom. case IT_THREAD: // Use this on a loom. case IT_COMM_CRYSTAL: addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_TARGET_PROMT), false, false); return true; case IT_CARPENTRY_CHOP: case IT_LOCKPICK: // Use on a locked thing. case IT_SCISSORS: addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_TARGET_PROMT), false, true); return true; case IT_WEAPON_MACE_PICK: if ( bIsEquipped || !IsSetOF(OF_NoDClickTarget) ) { // Mine at the location TCHAR *pszTemp = Str_GetTemp(); sprintf(pszTemp, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_MACEPICK_TARG), pItem->GetName()); addTarget(CLIMODE_TARG_USE_ITEM, pszTemp, true, true); return true; } case IT_WEAPON_SWORD: case IT_WEAPON_FENCE: case IT_WEAPON_AXE: case IT_WEAPON_MACE_SHARP: case IT_WEAPON_MACE_STAFF: case IT_WEAPON_MACE_SMITH: { if ( bIsEquipped || !IsSetOF(OF_NoDClickTarget) ) addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_WEAPON_PROMT), false, true); return true; } case IT_WEAPON_MACE_CROOK: if ( bIsEquipped || !IsSetOF(OF_NoDClickTarget) ) addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_CROOK_PROMT), false, true); return true; case IT_FISH: SysMessageDefault(DEFMSG_ITEMUSE_FISH_FAIL); return true; case IT_TELESCOPE: SysMessageDefault(DEFMSG_ITEMUSE_TELESCOPE); return true; case IT_MAP: addDrawMap(static_cast<CItemMap *>(pItem)); return true; case IT_CANNON_BALL: { TCHAR *pszTemp = Str_GetTemp(); sprintf(pszTemp, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_CBALL_PROMT), pItem->GetName()); addTarget(CLIMODE_TARG_USE_ITEM, pszTemp); return true; } case IT_CANNON_MUZZLE: { if ( !m_pChar->CanUse(pItem, false) ) return false; // Make sure the cannon is loaded. if ( !(pItem->m_itCannon.m_Load & 1) ) { addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_CANNON_POWDER)); return true; } if ( !(pItem->m_itCannon.m_Load & 2) ) { addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_CANNON_SHOT)); return true; } addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_CANNON_TARG), false, true); return true; } case IT_CRYSTAL_BALL: // Gaze into the crystal ball. return true; case IT_SEED: case IT_PITCHER_EMPTY: { TCHAR *pszTemp = Str_GetTemp(); sprintf(pszTemp, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_PITCHER_TARG), pItem->GetName()); addTarget(CLIMODE_TARG_USE_ITEM, pszTemp, true); return true; } case IT_SPELLBOOK: addSpellbookOpen(pItem); return true; case IT_SPELLBOOK_NECRO: addSpellbookOpen(pItem, 101); return true; case IT_SPELLBOOK_PALA: addSpellbookOpen(pItem, 201); return true; case IT_SPELLBOOK_BUSHIDO: addSpellbookOpen(pItem, 401); return true; case IT_SPELLBOOK_NINJITSU: addSpellbookOpen(pItem, 501); return true; case IT_SPELLBOOK_ARCANIST: addSpellbookOpen(pItem, 601); return true; case IT_SPELLBOOK_MYSTIC: addSpellbookOpen(pItem, 678); return true; case IT_SPELLBOOK_BARD: addSpellbookOpen(pItem, 701); return true; case IT_HAIR_DYE: { if ( !m_pChar->LayerFind(LAYER_BEARD) && !m_pChar->LayerFind(LAYER_HAIR) ) { SysMessageDefault(DEFMSG_ITEMUSE_DYE_NOHAIR); return true; } Dialog_Setup(CLIMODE_DIALOG, g_Cfg.ResourceGetIDType(RES_DIALOG, "d_hair_dye"), 0, pItem); return true; } case IT_DYE: addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_DYE_VAT)); return true; case IT_DYE_VAT: addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_DYE_TARG), false, true); return true; case IT_MORTAR: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_alchemy"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_alchemy")); } case IT_CARTOGRAPHY: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_cartography"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_cartography")); } case IT_COOKING: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_cooking"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_cooking")); } case IT_TINKER_TOOLS: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_tinker"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_tinker")); } case IT_SEWING_KIT: { TCHAR *pszTemp = Str_GetTemp(); sprintf(pszTemp, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SEWKIT_PROMT), pItem->GetName()); addTarget(CLIMODE_TARG_USE_ITEM, pszTemp); return true; } case IT_SCROLL_BLANK: Cmd_Skill_Inscription(); return true; default: { // An NPC could use it this way. if ( m_pChar->Use_Item(pItem) ) return true; break; } } SysMessageDefault(DEFMSG_ITEMUSE_CANTTHINK); return false; }
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; }
bool CClient::Cmd_Skill_Magery( SPELL_TYPE iSpell, CObjBase * pSrc ) { ADDTOCALLSTACK("CClient::Cmd_Skill_Magery"); /* Start casting a spell. Prompt for target. pSrc = you the char. pSrc = magic object is source ? static const TCHAR sm_Txt_Summon[] = "Where would you like to summon the creature ?"; */ ASSERT(m_pChar); const CSpellDef * pSpellDef; if ( IsSetMagicFlags(MAGICF_PRECAST) && iSpell == m_tmSkillMagery.m_Spell ) { pSpellDef = g_Cfg.GetSpellDef(m_tmSkillMagery.m_Spell); if ( pSpellDef != NULL && !pSpellDef->IsSpellType(SPELLFLAG_NOPRECAST) ) iSpell = m_tmSkillMagery.m_Spell; } else pSpellDef = g_Cfg.GetSpellDef(iSpell); // Do we have the regs? Etc. if ( !m_pChar->Spell_CanCast(iSpell, true, pSrc, true) ) return false; ASSERT(pSpellDef); SetTargMode(); m_tmSkillMagery.m_Spell = iSpell; // m_atMagery.m_Spell m_Targ_UID = m_pChar->GetUID(); // Default target. m_Targ_PrvUID = pSrc->GetUID(); // Source of the spell. // Cast self if ( !pSpellDef->IsSpellType(SPELLFLAG_TARG_OBJ|SPELLFLAG_TARG_XYZ) ) { m_pChar->m_Act_p = m_pChar->GetTopPoint(); m_pChar->m_atMagery.m_Spell = iSpell; m_pChar->m_Act_Targ = m_Targ_UID; m_pChar->m_Act_TargPrv = m_Targ_PrvUID; m_Targ_p = m_pChar->GetTopPoint(); if ( iSpell == SPELL_Polymorph ) { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_polymorph"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu( g_Cfg.ResourceGetIDType( RES_SKILLMENU, "sm_polymorph" ) ); } // If NO PreCast -> Skill_Start() if ( !IsSetMagicFlags(MAGICF_PRECAST) || pSpellDef->IsSpellType(SPELLFLAG_NOPRECAST) ) { int skill; if ( !pSpellDef->GetPrimarySkill(&skill, NULL) ) return false; return m_pChar->Skill_Start(static_cast<SKILL_TYPE>(skill)); } else { // But if we use PreCast use Spell_CastDone() m_pChar->Spell_CastDone(); return true; } } // We need a target! LPCTSTR pPrompt = g_Cfg.GetDefaultMsg( DEFMSG_SELECT_MAGIC_TARGET ); switch ( iSpell ) { case SPELL_Recall: // pPrompt = g_Cfg.GetDefaultMsg( "Select rune to recall from." ); break; case SPELL_Blade_Spirit: // pPrompt = sm_Txt_Summon; break; case SPELL_Summon: { if (IsTrigUsed(TRIGGER_SKILLMENU)) { CScriptTriggerArgs args("sm_summon"); if (m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_summon")); } case SPELL_Mark: // pPrompt = "Select rune to mark."; break; case SPELL_Gate_Travel: // gate travel // pPrompt = "Select rune to gate from."; break; case SPELL_Resurrection: // pPrompt = "Select ghost to resurrect."; break; case SPELL_Vortex: case SPELL_Air_Elem: case SPELL_Daemon: case SPELL_Earth_Elem: case SPELL_Fire_Elem: case SPELL_Water_Elem: // pPrompt = sm_Txt_Summon; break; // Necro spells case SPELL_Summon_Undead: // Summon an undead // pPrompt = sm_Txt_Summon; break; case SPELL_Animate_Dead: // Corpse to zombie // pPrompt = "Choose a corpse"; break; case SPELL_Bone_Armor: // Skeleton corpse to bone armor // pPrompt = "Chose a skeleton"; break; case SPELL_Summon_Familiar: { if (IsTrigUsed(TRIGGER_SKILLMENU)) { CScriptTriggerArgs args("sm_summon_familiar"); if (m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_summon_familiar")); } default: break; } if ( !pSpellDef->m_sTargetPrompt.IsEmpty() ) pPrompt = pSpellDef->m_sTargetPrompt; int SpellTimeout = g_Cfg.m_iSpellTimeout * TICK_PER_SEC; if (m_pChar->GetDefNum("SPELLTIMEOUT",true)) SpellTimeout = static_cast<int>(m_pChar->GetDefNum("SPELLTIMEOUT",true)); addTarget( CLIMODE_TARG_SKILL_MAGERY, pPrompt, pSpellDef->IsSpellType( SPELLFLAG_TARG_XYZ ), pSpellDef->IsSpellType( SPELLFLAG_HARM ), SpellTimeout); return( true ); }
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; }
bool CClient::Cmd_SecureTrade( CChar *pChar, CItem *pItem ) { ADDTOCALLSTACK("CClient::Cmd_SecureTrade"); // Begin secure trading with a char. (Make the initial offer) if ( !pChar || pChar == m_pChar ) return false; // Make sure both clients can see each other, because trade window is an container // and containers can be opened only after the object is already loaded on screen if ( !m_pChar->CanSee(pChar) || !pChar->CanSee(m_pChar) ) return false; if ( pItem && (IsTrigUsed(TRIGGER_DROPON_CHAR) || IsTrigUsed(TRIGGER_ITEMDROPON_CHAR)) ) { CScriptTriggerArgs Args(pChar); if ( pItem->OnTrigger(ITRIG_DROPON_CHAR, m_pChar, &Args) == TRIGRET_RET_TRUE ) return false; } if ( pChar->m_pNPC ) // NPC's can't use trade windows return pItem ? pChar->NPC_OnItemGive(m_pChar, pItem) : false; if ( !pChar->m_pClient ) // and also offline players return false; if ( pChar->GetDefNum("REFUSETRADES") ) { SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_MSG_TRADE_REFUSE), pChar->GetName()); return false; } // Check if the trade window is already open for ( CItem *pItemCont = m_pChar->GetContentHead(); pItemCont != NULL; pItemCont = pItemCont->GetNext() ) { if ( !pItemCont->IsType(IT_EQ_TRADE_WINDOW) ) continue; CItem *pItemPartner = pItemCont->m_uidLink.ItemFind(); if ( !pItemPartner ) continue; CChar *pCharPartner = dynamic_cast<CChar *>(pItemPartner->GetParent()); if ( pCharPartner != pChar ) continue; if ( pItem ) { if ( IsTrigUsed(TRIGGER_DROPON_TRADE) ) { CScriptTriggerArgs Args1(pChar); if ( pItem->OnTrigger(ITRIG_DROPON_TRADE, this, &Args1) == TRIGRET_RET_TRUE ) return false; } CItemContainer *pCont = dynamic_cast<CItemContainer *>(pItemCont); if ( pCont ) pCont->ContentAdd(pItem); } return true; } // Open new trade window if ( IsTrigUsed(TRIGGER_TRADECREATE) ) { CScriptTriggerArgs Args(pItem); if ( (m_pChar->OnTrigger(CTRIG_TradeCreate, pChar, &Args) == TRIGRET_RET_TRUE) || (pChar->OnTrigger(CTRIG_TradeCreate, m_pChar, &Args) == TRIGRET_RET_TRUE) ) return false; } if ( IsTrigUsed(TRIGGER_DROPON_TRADE) && pItem ) { CScriptTriggerArgs Args1(pChar); if ( pItem->OnTrigger(ITRIG_DROPON_TRADE, this, &Args1) == TRIGRET_RET_TRUE ) return false; } CItem *pItem1 = CItem::CreateBase(ITEMID_Bulletin1); if ( !pItem1 ) return false; CItemContainer *pCont1 = static_cast<CItemContainer *>(pItem1); if ( !pCont1 ) { DEBUG_ERR(("Item 0%x must be a container type to enable player trading.\n", ITEMID_Bulletin1)); pItem1->Delete(); return false; } CItemContainer *pCont2 = static_cast<CItemContainer *>(CItem::CreateBase(ITEMID_Bulletin1)); ASSERT(pCont2); pCont1->SetName("Trade Window"); pCont1->SetType(IT_EQ_TRADE_WINDOW); pCont1->m_itEqTradeWindow.m_iWaitTime = 0; pCont1->m_itEqTradeWindow.m_bCheck = 0; pCont1->m_uidLink = pCont2->GetUID(); m_pChar->LayerAdd(pCont1, LAYER_SPECIAL); pCont2->SetName("Trade Window"); pCont2->SetType(IT_EQ_TRADE_WINDOW); pCont2->m_itEqTradeWindow.m_iWaitTime = 0; pCont2->m_itEqTradeWindow.m_bCheck = 0; pCont2->m_uidLink = pCont1->GetUID(); pChar->LayerAdd(pCont2, LAYER_SPECIAL); PacketTradeAction cmd(SECURE_TRADE_OPEN); cmd.prepareContainerOpen(pChar, pCont1, pCont2); cmd.send(this); cmd.prepareContainerOpen(m_pChar, pCont2, pCont1); cmd.send(pChar->m_pClient); if ( g_Cfg.m_iFeatureTOL & FEATURE_TOL_VIRTUALGOLD ) { PacketTradeAction cmd2(SECURE_TRADE_UPDATELEDGER); if ( m_NetState->isClientVersion(MINCLIVER_TOL) ) { cmd2.prepareUpdateLedger(pCont1, static_cast<DWORD>(m_pChar->m_virtualGold % 1000000000), static_cast<DWORD>(m_pChar->m_virtualGold / 1000000000)); cmd2.send(this); } if ( pChar->m_pClient->m_NetState->isClientVersion(MINCLIVER_TOL) ) { cmd2.prepareUpdateLedger(pCont2, static_cast<DWORD>(pChar->m_virtualGold % 1000000000), static_cast<DWORD>(pChar->m_virtualGold / 1000000000)); cmd2.send(pChar->m_pClient); } } LogOpenedContainer(pCont2); pChar->m_pClient->LogOpenedContainer(pCont1); if ( pItem ) { if ( IsTrigUsed(TRIGGER_DROPON_TRADE) ) { CScriptTriggerArgs Args1(pChar); if ( pItem->OnTrigger(ITRIG_DROPON_TRADE, this, &Args1) == TRIGRET_RET_TRUE ) { pCont1->Delete(); pCont2->Delete(); return false; } } pCont1->ContentAdd(pItem, pCont1->GetTopPoint()); } return true; }
bool CChar::NPC_Vendor_Restock(bool bForce, bool bFillStock) { ADDTOCALLSTACK("CChar::NPC_Vendor_Restock"); // Restock this NPC char. // Then Set the next restock time for this . if ( m_pNPC == NULL ) return false; // Make sure that we're a vendor and not a pet if ( IsStatFlag(STATF_Pet) || !NPC_IsVendor() ) return false; bool bRestockNow = true; if ( !bForce && m_pNPC->m_timeRestock.IsTimeValid() ) { // Restock occurs every 10 minutes of inactivity (unless // region tag specifies different time) CRegionWorld *region = GetRegion(); int64 restockIn = 10 * 60 * TICK_PER_SEC; if( region != NULL ) { CVarDefCont *vardef = region->m_TagDefs.GetKey("RestockVendors"); if( vardef != NULL ) restockIn = vardef->GetValNum(); if ( region->m_TagDefs.GetKey("NoRestock") != NULL ) bRestockNow = false; } if ( m_TagDefs.GetKey("NoRestock") != NULL ) bRestockNow = false; if (bRestockNow) bRestockNow = ( CServerTime::GetCurrentTime().GetTimeDiff(m_pNPC->m_timeRestock) > restockIn ); } // At restock the containers are actually emptied if ( bRestockNow ) { m_pNPC->m_timeRestock.Init(); for ( size_t i = 0; i < CountOf(sm_VendorLayers); ++i ) { CItemContainer *pCont = GetBank(sm_VendorLayers[i]); if ( !pCont ) return false; pCont->Empty(); } } if ( bFillStock ) { // An invalid restock time means that the containers are // waiting to be filled if ( !m_pNPC->m_timeRestock.IsTimeValid() ) { if ( IsTrigUsed(TRIGGER_NPCRESTOCK) ) { CCharBase *pCharDef = Char_GetDef(); ReadScriptTrig(pCharDef, CTRIG_NPCRestock, true); } // we need restock vendor money as well GetBank()->Restock(); } // remember that the stock was filled (or considered up-to-date) m_pNPC->m_timeRestock.SetCurrentTime(); } return true; }
bool CClient::Cmd_Skill_Magery( SPELL_TYPE iSpell, CObjBase *pSrc ) { ADDTOCALLSTACK("CClient::Cmd_Skill_Magery"); // Start casting a spell. Prompt for target. // ARGS: // pSrc = you the char. // pSrc = magic object is source ? ASSERT(m_pChar); const CSpellDef *pSpellDef; if ( IsSetMagicFlags(MAGICF_PRECAST) && iSpell == m_tmSkillMagery.m_Spell ) { pSpellDef = g_Cfg.GetSpellDef(m_tmSkillMagery.m_Spell); if ( pSpellDef != NULL && !pSpellDef->IsSpellType(SPELLFLAG_NOPRECAST) ) iSpell = m_tmSkillMagery.m_Spell; } else pSpellDef = g_Cfg.GetSpellDef(iSpell); if ( !pSpellDef ) return false; // Do we have the regs? Etc. if ( !m_pChar->Spell_CanCast(iSpell, true, pSrc, true) ) return false; SetTargMode(); m_tmSkillMagery.m_Spell = iSpell; // m_atMagery.m_Spell m_Targ_UID = m_pChar->GetUID(); // Default target. m_Targ_PrvUID = pSrc->GetUID(); // Source of the spell. switch ( iSpell ) { case SPELL_Polymorph: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_polymorph"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_polymorph")); } case SPELL_Summon: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_summon"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_summon")); } case SPELL_Summon_Familiar: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_summon_familiar"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_summon_familiar")); } default: break; } // Targeted spells if ( pSpellDef->IsSpellType(SPELLFLAG_TARG_OBJ|SPELLFLAG_TARG_XYZ) ) { LPCTSTR pPrompt = g_Cfg.GetDefaultMsg(DEFMSG_SELECT_MAGIC_TARGET); if ( !pSpellDef->m_sTargetPrompt.IsEmpty() ) pPrompt = pSpellDef->m_sTargetPrompt; int SpellTimeout = static_cast<int>(m_pChar->GetDefNum("SPELLTIMEOUT")); if ( !SpellTimeout ) SpellTimeout = g_Cfg.m_iSpellTimeout * TICK_PER_SEC; addTarget(CLIMODE_TARG_SKILL_MAGERY, pPrompt, pSpellDef->IsSpellType(SPELLFLAG_TARG_XYZ), pSpellDef->IsSpellType(SPELLFLAG_HARM), SpellTimeout); return true; } // Non-targeted spells m_pChar->m_Act_p = m_pChar->GetTopPoint(); m_pChar->m_Act_Targ = m_Targ_UID; m_pChar->m_Act_TargPrv = m_Targ_PrvUID; m_pChar->m_atMagery.m_Spell = iSpell; m_Targ_p = m_pChar->GetTopPoint(); if ( IsSetMagicFlags(MAGICF_PRECAST) && !pSpellDef->IsSpellType(SPELLFLAG_NOPRECAST) ) { m_pChar->Spell_CastDone(); return true; } else { int skill; if ( !pSpellDef->GetPrimarySkill(&skill, NULL) ) return false; return m_pChar->Skill_Start(static_cast<SKILL_TYPE>(skill)); } }
size_t CRandGroupDef::GetRandMemberIndex( CChar * pCharSrc, bool bTrigger ) const { ADDTOCALLSTACK("CRandGroupDef::GetRandMemberIndex"); int rid; size_t iCount = m_Members.GetCount(); if ( iCount <= 0 ) return m_Members.BadIndex(); int iWeight = 0; size_t i; if ( pCharSrc == NULL ) { iWeight = Calc_GetRandVal( m_iTotalWeight ) + 1; for ( i = 0; iWeight > 0 && i < iCount; i++ ) { iWeight -= static_cast<int>(m_Members[i].GetResQty()); } if ( i >= iCount && iWeight > 0 ) return m_Members.BadIndex(); ASSERT(i > 0); return( i - 1 ); } CGPtrTypeArray<size_t> members; // calculate weight only of items pCharSrc can get int iTotalWeight = 0; for ( i = 0; i < iCount; i++ ) { CRegionResourceDef * pOreDef = dynamic_cast <CRegionResourceDef *>( g_Cfg.ResourceGetDef( m_Members[i].GetResourceID() ) ); // If no regionresource, return just some random entry! if (pOreDef != NULL) { rid = pOreDef->m_ReapItem; if (rid != 0) { if (!pCharSrc->Skill_MakeItem(static_cast<ITEMID_TYPE>(rid), UID_CLEAR, SKTRIG_SELECT)) continue; if (IsTrigUsed(TRIGGER_RESOURCETEST)) { if (bTrigger && pOreDef->OnTrigger("@ResourceTest", pCharSrc, NULL) == TRIGRET_RET_TRUE) continue; } } } members.Add(i); iTotalWeight += static_cast<int>(m_Members[i].GetResQty()); } iWeight = Calc_GetRandVal( iTotalWeight ) + 1; iCount = members.GetCount(); for ( i = 0; iWeight > 0 && i < iCount; i++ ) { iWeight -= static_cast<int>(m_Members[members[i]].GetResQty()); } if ( i >= iCount && iWeight > 0 ) return m_Members.BadIndex(); ASSERT(i > 0); return members[i - 1]; }