void CItemSpawn::DelObj(CGrayUID uid) { ADDTOCALLSTACK("CitemSpawn:DelObj"); if ( !uid.IsValidUID() ) return; BYTE iMax = GetCount(); for ( BYTE i = 0; i < iMax; i++ ) { if ( m_obj[i] != uid ) continue; CObjBase *pObj = uid.ObjFind(); pObj->m_uidSpawnItem.InitUID(); m_currentSpawned--; if ( GetType() == IT_SPAWN_CHAR ) uid.CharFind()->StatFlag_Clear(STATF_Spawned); while ( m_obj[i + 1].IsValidUID() ) // searching for any entry higher than this one... { m_obj[i] = m_obj[i + 1]; // and moving it 1 position to keep values 'together'. i++; } m_obj[i].InitUID(); // Finished moving higher entries (if any) so we free the last entry. break; } ResendTooltip(); }
void CItemSpawn::AddObj(CGrayUID uid) { ADDTOCALLSTACK("CitemSpawn:AddObj"); // NOTE: This function is also called when loading spawn items // on server startup. In this case, some objs UID still invalid // (not loaded yet) so just proceed without any checks. bool bIsSpawnChar = IsType(IT_SPAWN_CHAR); if ( !g_Serv.IsLoading() ) { if ( !uid.IsValidUID() ) return; if ( bIsSpawnChar ) // IT_SPAWN_CHAR can only spawn NPCs { CChar *pChar = uid.CharFind(); if ( !pChar || !pChar->m_pNPC ) return; } else if ( !uid.ItemFind() ) // IT_SPAWN_ITEM can only spawn items return; CItemSpawn *pPrevSpawn = static_cast<CItemSpawn*>(uid.ObjFind()->m_uidSpawnItem.ItemFind()); if ( pPrevSpawn ) { if ( pPrevSpawn == this ) // obj already linked to this spawn return; pPrevSpawn->DelObj(uid); // obj linked to other spawn, remove the link before proceed } } BYTE iMax = maximum(GetAmount(), 1); for (BYTE i = 0; i < iMax; i++ ) { if ( !m_obj[i].IsValidUID() ) { m_obj[i] = uid; m_currentSpawned++; // objects are linked to the spawn at each server start if ( !g_Serv.IsLoading() ) { uid.ObjFind()->m_uidSpawnItem = GetUID(); if ( bIsSpawnChar ) { CChar *pChar = uid.CharFind(); ASSERT(pChar->m_pNPC); pChar->StatFlag_Set(STATF_Spawned); pChar->m_ptHome = GetTopPoint(); pChar->m_pNPC->m_Home_Dist_Wander = static_cast<WORD>(m_itSpawnChar.m_DistMax); } } break; } } if ( !g_Serv.IsLoading() ) ResendTooltip(); }
void CChar::NPC_PetClearOwners(bool bResendTooltip) { ADDTOCALLSTACK("CChar::NPC_PetClearOwners"); CChar *pOwner = NPC_PetGetOwner(); Memory_ClearTypes(MEMORY_IPET|MEMORY_FRIEND); if ( m_pNPC ) m_pNPC->m_bonded = 0; // pets without owner cannot be bonded if ( NPC_IsVendor() ) { StatFlag_Clear(STATF_INVUL); if ( pOwner ) // give back to NPC owner all the stuff we are trying to sell { CItemContainer *pBankVendor = GetContainerCreate(LAYER_BANKBOX); CItemContainer *pBankOwner = pOwner->GetContainerCreate(LAYER_BANKBOX); pOwner->AddGoldToPack(pBankVendor->m_itEqBankBox.m_Check_Amount, pBankOwner); pBankVendor->m_itEqBankBox.m_Check_Amount = 0; for ( size_t i = 0; i < COUNTOF(sm_VendorLayers); i++ ) { CItemContainer *pCont = GetContainerCreate(sm_VendorLayers[i]); if ( !pCont ) continue; CItem *pItemNext = NULL; for ( CItem *pItem = pCont->GetContentHead(); pItem != NULL; pItem = pItemNext ) { pItemNext = pItem->GetNext(); pBankOwner->ContentAdd(pItem); } } } } if ( IsStatFlag(STATF_Ridden) ) { CChar *pCharRider = Horse_GetMountChar(); if ( pCharRider ) pCharRider->Horse_UnMount(); } if ( pOwner ) { if ( IsSetOF(OF_PetSlots) ) pOwner->FollowersUpdate(this, static_cast<short>(-maximum(1, GetDefNum("FOLLOWERSLOTS", true)))); if ( bResendTooltip ) ResendTooltip(); } }
bool CChar::NPC_PetSetOwner(CChar *pChar, bool bResendTooltip) { ADDTOCALLSTACK("CChar::NPC_PetSetOwner"); // m_pNPC may not be set yet if this is a conjured creature. if ( !m_pNPC || !pChar || (pChar == this) ) return false; CChar *pOwner = NPC_PetGetOwner(); if ( pOwner == pChar ) return false; NPC_PetClearOwners(false); // clear previous owner before set the new owner m_ptHome.InitPoint(); // no longer homed CItemSpawn *pSpawn = static_cast<CItemSpawn *>(m_uidSpawnItem.ItemFind()); if ( pSpawn ) pSpawn->DelObj(GetUID()); Memory_AddObjTypes(pChar, MEMORY_IPET); if ( m_pNPC->m_Brain != NPCBRAIN_BERSERK) NPC_Act_Follow(); if ( NPC_IsVendor() ) { // Clear my cash total. CItemContainer *pBank = GetContainerCreate(LAYER_BANKBOX); pBank->m_itEqBankBox.m_Check_Amount = 0; StatFlag_Set(STATF_INVUL); } if ( IsSetOF(OF_PetSlots) ) pChar->FollowersUpdate(this, static_cast<short>(maximum(1, GetDefNum("FOLLOWERSLOTS", true)))); if ( bResendTooltip ) ResendTooltip(); return true; }
bool CChar::NPC_OnHearPetCmd( LPCTSTR pszCmd, CChar *pSrc, bool fAllPets ) { ADDTOCALLSTACK("CChar::NPC_OnHearPetCmd"); // This should just be another speech block !!! // We own this char (pet or hireling) // pObjTarget = the m_ActTarg has been set for them to attack. // RETURN: // true = we understand this. tho we may not do what we are told. // false = this is not a command we know. // if ( GetTargMode() == CLIMODE_TARG_PET_CMD ) it needs a target. if ( !pSrc->IsClient() || m_pPlayer || !m_pNPC ) return false; m_fIgnoreNextPetCmd = false; // We clear this incase it's true from previous pet cmds. TALKMODE_TYPE mode = TALKMODE_SAY; if ( OnTriggerSpeech(true, pszCmd, pSrc, mode) ) { m_fIgnoreNextPetCmd = !fAllPets; return true; } static LPCTSTR const sm_Pet_table[] = { "ATTACK", "BOUGHT", "CASH", "COME", "DROP", // "GIVE" ? "DROP ALL", "EQUIP", "FOLLOW", "FOLLOW ME", "FRIEND", "GO", "GUARD", "GUARD ME", "KILL", "PRICE", // may have args ? "RELEASE", "SAMPLES", "SPEAK", "STATUS", "STAY", "STOCK", "STOP", "TRANSFER", "UNFRIEND" }; PC_TYPE iCmd = static_cast<PC_TYPE>(FindTableSorted(pszCmd, sm_Pet_table, COUNTOF(sm_Pet_table))); if ( iCmd < 0 ) { if ( !strnicmp(pszCmd, sm_Pet_table[PC_PRICE], 5) ) iCmd = PC_PRICE; else return false; } switch ( iCmd ) { case PC_FOLLOW: case PC_STAY: case PC_STOP: { // Pet friends can use only these commands if ( Memory_FindObjTypes(pSrc, MEMORY_FRIEND) ) break; } default: { // All others commands are avaible only to pet owner if ( !NPC_IsOwnedBy(pSrc, true) ) return false; } } if ( IsStatFlag(STATF_DEAD) ) { // Bonded NPCs still placed on world even when dead. // They can listen to commands, but not to these commands below if ( iCmd == PC_GUARD || iCmd == PC_GUARD_ME || iCmd == PC_ATTACK || iCmd == PC_KILL || iCmd == PC_TRANSFER || iCmd == PC_DROP || iCmd == PC_DROP_ALL ) return true; } bool bTargAllowGround = false; bool bCheckCrime = false; LPCTSTR pTargPrompt = NULL; CCharBase *pCharDef = Char_GetDef(); switch ( iCmd ) { case PC_ATTACK: case PC_KILL: pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_ATT); bCheckCrime = true; break; case PC_COME: case PC_GUARD_ME: case PC_FOLLOW_ME: m_Act_Targ = pSrc->GetUID(); Skill_Start(NPCACT_FOLLOW_TARG); break; case PC_FOLLOW: pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_FOLLOW); break; case PC_FRIEND: if ( IsStatFlag(STATF_Conjured) ) { pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_FRIEND_SUMMONED)); return false; } pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_FRIEND); break; case PC_UNFRIEND: pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_UNFRIEND); break; case PC_GO: pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_GO); bTargAllowGround = true; break; case PC_GUARD: pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_GUARD); bCheckCrime = true; break; case PC_STAY: case PC_STOP: Skill_Start(NPCACT_STAY); break; case PC_TRANSFER: if ( IsStatFlag(STATF_Conjured) ) { pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_TRANSFER_SUMMONED)); return true; } pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_TRANSFER); break; case PC_RELEASE: SoundChar(CRESND_RAND2); if ( IsStatFlag(STATF_Conjured) || (m_pNPC->m_bonded && IsStatFlag(STATF_DEAD)) ) { Delete(); return true; } Skill_Start(SKILL_NONE); NPC_PetClearOwners(); ResendTooltip(); break; case PC_DROP: { // Drop backpack items on ground // NOTE: This is also called on pet release CItemContainer *pPack = GetPack(); if ( pPack ) { pPack->ContentsDump(GetTopPoint(), ATTR_OWNED); break; } if ( NPC_CanSpeak() ) Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_CARRYNOTHING)); return true; } case PC_DROP_ALL: DropAll(NULL, ATTR_OWNED); break; case PC_SPEAK: NPC_OnPetCommand(true, pSrc); return true; case PC_EQUIP: ItemEquipWeapon(false); ItemEquipArmor(false); break; case PC_STATUS: { if ( !NPC_CanSpeak() ) break; unsigned int iWage = pCharDef->GetHireDayWage(); CItemContainer *pBank = GetBank(); TCHAR *pszMsg = Str_GetTemp(); if ( NPC_IsVendor() ) { CItemContainer *pCont = GetBank(LAYER_VENDOR_STOCK); TCHAR *pszTemp1 = Str_GetTemp(); TCHAR *pszTemp2 = Str_GetTemp(); TCHAR *pszTemp3 = Str_GetTemp(); if ( iWage ) { sprintf(pszTemp1, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_1), pBank->m_itEqBankBox.m_Check_Amount); sprintf(pszTemp2, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_2), pBank->m_itEqBankBox.m_Check_Amount / iWage); sprintf(pszTemp3, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_3), static_cast<int>(pCont->GetCount())); } else { sprintf(pszTemp1, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_1), pBank->m_itEqBankBox.m_Check_Amount); sprintf(pszTemp2, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_4), pBank->m_itEqBankBox.m_Check_Restock, pBank->GetTimerAdjusted() / 60); sprintf(pszTemp3, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_3), static_cast<int>(pCont->GetCount())); } sprintf(pszMsg, "%s %s %s", pszTemp1, pszTemp2, pszTemp3); } else if ( iWage ) { sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_DAYS_LEFT), pBank->m_itEqBankBox.m_Check_Amount / iWage); } Speak(pszMsg); return true; } case PC_CASH: { // Give up my cash total. if ( !NPC_IsVendor() ) return false; CItemContainer *pBank = GetBank(); if ( pBank ) { unsigned int iWage = pCharDef->GetHireDayWage(); TCHAR *pszMsg = Str_GetTemp(); if ( pBank->m_itEqBankBox.m_Check_Amount > iWage ) { sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_GETGOLD_1), pBank->m_itEqBankBox.m_Check_Amount - iWage); pSrc->AddGoldToPack(pBank->m_itEqBankBox.m_Check_Amount - iWage); pBank->m_itEqBankBox.m_Check_Amount = iWage; } else sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_GETGOLD_2), pBank->m_itEqBankBox.m_Check_Amount); Speak(pszMsg); } return true; } case PC_BOUGHT: if ( !NPC_IsVendor() ) return false; Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_ITEMS_BUY)); pSrc->GetClient()->addBankOpen(this, LAYER_VENDOR_EXTRA); break; case PC_PRICE: if ( !NPC_IsVendor() ) return false; pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_SETPRICE); break; case PC_SAMPLES: if ( !NPC_IsVendor() ) return false; Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_ITEMS_SAMPLE)); pSrc->GetClient()->addBankOpen(this, LAYER_VENDOR_BUYS); break; case PC_STOCK: // Magic restocking container. if ( !NPC_IsVendor() ) return false; Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_ITEMS_SELL)); pSrc->GetClient()->addBankOpen(this, LAYER_VENDOR_STOCK); break; default: return false; } if ( pTargPrompt ) { pszCmd += strlen(sm_Pet_table[iCmd]); GETNONWHITESPACE(pszCmd); pSrc->m_pClient->m_tmPetCmd.m_iCmd = iCmd; pSrc->m_pClient->m_tmPetCmd.m_fAllPets = fAllPets; pSrc->m_pClient->m_Targ_UID = GetUID(); pSrc->m_pClient->m_Targ_Text = pszCmd; pSrc->m_pClient->addTarget(CLIMODE_TARG_PET_CMD, pTargPrompt, bTargAllowGround, bCheckCrime); return true; } // Make some sound to confirm we heard it NPC_OnPetCommand(true, pSrc); return true; }
bool CChar::NPC_OnHearPetCmd(LPCTSTR pszCmd, CChar *pSrc, bool bAllPets) { ADDTOCALLSTACK("CChar::NPC_OnHearPetCmd"); // This should just be another speech block !!! // We own this char (pet or hireling) // pObjTarget = the m_ActTarg has been set for them to attack. // RETURN: // true = we understand this. tho we may not do what we are told. // false = this is not a command we know. // if ( GetTargMode() == CLIMODE_TARG_PET_CMD ) it needs a target. if ( !m_pNPC || !pSrc->m_pClient ) return false; m_fIgnoreNextPetCmd = false; // we clear this incase it's true from previous pet commands TALKMODE_TYPE mode = TALKMODE_SAY; if ( OnTriggerSpeech(true, pszCmd, pSrc, mode) ) { m_fIgnoreNextPetCmd = !bAllPets; return true; } if ((m_pNPC->m_Brain == NPCBRAIN_BERSERK) && !pSrc->IsPriv(PRIV_GM)) return false; // Berserk npcs do not listen to any command (except if src is a GM) static LPCTSTR const sm_PetCommands[] = { "ATTACK", "BOUGHT", "CASH", "COME", "DROP", "DROP ALL", "EQUIP", "FOLLOW", "FOLLOW ME", "FRIEND", "GO", "GUARD", "GUARD ME", "KILL", "PRICE", "RELEASE", "SAMPLES", "SPEAK", "STATUS", "STAY", "STOCK", "STOP", "TRANSFER", "UNFRIEND" }; PC_TYPE iCmd = static_cast<PC_TYPE>(FindTableSorted(pszCmd, sm_PetCommands, COUNTOF(sm_PetCommands))); if ( iCmd < 0 ) { if ( !strnicmp(pszCmd, sm_PetCommands[PC_PRICE], 5) ) iCmd = PC_PRICE; else return false; } if ( !NPC_PetCheckAccess(iCmd, pSrc) ) return true; bool bTargAllowGround = false; bool bCheckCrime = false; LPCTSTR pTargPrompt = NULL; CCharBase *pCharDef = Char_GetDef(); switch ( iCmd ) { case PC_ATTACK: case PC_KILL: pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_ATT); bCheckCrime = true; break; case PC_COME: case PC_FOLLOW_ME: NPC_OnHearPetCmdTarg(PC_FOLLOW, pSrc, pSrc, NULL, NULL); break; case PC_FOLLOW: pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_FOLLOW); break; case PC_FRIEND: if ( IsStatFlag(STATF_Conjured) ) { pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_FRIEND_SUMMONED)); return false; } pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_FRIEND); break; case PC_UNFRIEND: pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_UNFRIEND); break; case PC_GO: pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_GO); bTargAllowGround = true; break; case PC_GUARD: pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_GUARD); bCheckCrime = true; break; case PC_GUARD_ME: NPC_OnHearPetCmdTarg(PC_GUARD, pSrc, pSrc, NULL, NULL); break; case PC_STAY: case PC_STOP: Skill_Start(NPCACT_STAY); break; case PC_TRANSFER: if ( IsStatFlag(STATF_Conjured) ) { pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_TRANSFER_SUMMONED)); return true; } pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_TRANSFER); break; case PC_RELEASE: if ( IsStatFlag(STATF_Conjured) || (m_pNPC->m_bonded && IsStatFlag(STATF_DEAD)) ) { Effect(EFFECT_XYZ, ITEMID_FX_TELE_VANISH, this, 10, 15); Sound(SOUND_TELEPORT); Delete(); return true; } SoundChar(CRESND_NOTICE); Skill_Start(SKILL_NONE); NPC_PetClearOwners(); ResendTooltip(); break; case PC_DROP: { // Drop backpack items on ground // NOTE: This is also called on pet release CItemContainer *pPack = GetContainer(LAYER_PACK); if ( pPack ) { pPack->ContentsDump(GetTopPoint(), ATTR_OWNED); break; } if ( NPC_CanSpeak() ) Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_CARRYNOTHING)); return true; } case PC_DROP_ALL: DropAll(NULL, ATTR_OWNED); break; case PC_SPEAK: NPC_PetConfirmCommand(true, pSrc); return true; case PC_EQUIP: ItemEquipWeapon(false); ItemEquipArmor(false); break; case PC_STATUS: { if ( !NPC_CanSpeak() ) break; CItemContainer *pBank = GetContainerCreate(LAYER_BANKBOX); TCHAR *pszMsg = Str_GetTemp(); if ( NPC_IsVendor() ) { CItemContainer *pCont = GetContainerCreate(LAYER_VENDOR_STOCK); TCHAR *pszTemp1 = Str_GetTemp(); TCHAR *pszTemp2 = Str_GetTemp(); TCHAR *pszTemp3 = Str_GetTemp(); if ( pCharDef->m_iHireDayWage ) { sprintf(pszTemp1, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_1), pBank->m_itEqBankBox.m_Check_Amount); sprintf(pszTemp2, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_2), pBank->m_itEqBankBox.m_Check_Amount / pCharDef->m_iHireDayWage); sprintf(pszTemp3, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_3), static_cast<int>(pCont->GetCount())); } else { sprintf(pszTemp1, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_1), pBank->m_itEqBankBox.m_Check_Amount); sprintf(pszTemp2, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_4), pBank->m_itEqBankBox.m_Check_Restock, pBank->GetTimerAdjusted() / 60); sprintf(pszTemp3, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_STAT_GOLD_3), static_cast<int>(pCont->GetCount())); } sprintf(pszMsg, "%s %s %s", pszTemp1, pszTemp2, pszTemp3); } else if ( pCharDef->m_iHireDayWage ) { sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_DAYS_LEFT), pBank->m_itEqBankBox.m_Check_Amount / pCharDef->m_iHireDayWage); } Speak(pszMsg); return true; } case PC_CASH: { // Give up my cash total. if ( !NPC_IsVendor() ) return false; CItemContainer *pBank = GetContainerCreate(LAYER_BANKBOX); if ( pBank ) { TCHAR *pszMsg = Str_GetTemp(); if ( pBank->m_itEqBankBox.m_Check_Amount > pCharDef->m_iHireDayWage ) { sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_GETGOLD_1), pBank->m_itEqBankBox.m_Check_Amount - pCharDef->m_iHireDayWage); pSrc->AddGoldToPack(pBank->m_itEqBankBox.m_Check_Amount - pCharDef->m_iHireDayWage); pBank->m_itEqBankBox.m_Check_Amount = pCharDef->m_iHireDayWage; } else sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_GETGOLD_2), pBank->m_itEqBankBox.m_Check_Amount); Speak(pszMsg); } return true; } case PC_BOUGHT: if ( !NPC_IsVendor() ) return false; Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_ITEMS_BUY)); pSrc->m_pClient->addBankOpen(this, LAYER_VENDOR_EXTRA); break; case PC_PRICE: if ( !NPC_IsVendor() ) return false; pTargPrompt = g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_SETPRICE); break; case PC_SAMPLES: if ( !NPC_IsVendor() ) return false; Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_ITEMS_SAMPLE)); pSrc->m_pClient->addBankOpen(this, LAYER_VENDOR_BUYS); break; case PC_STOCK: // Magic restocking container. if ( !NPC_IsVendor() ) return false; Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_ITEMS_SELL)); pSrc->m_pClient->addBankOpen(this, LAYER_VENDOR_STOCK); break; default: return false; } if ( pTargPrompt ) { pszCmd += strlen(sm_PetCommands[iCmd]); GETNONWHITESPACE(pszCmd); pSrc->m_pClient->m_tmPetCmd.m_iCmd = iCmd; pSrc->m_pClient->m_tmPetCmd.m_fAllPets = bAllPets; pSrc->m_pClient->m_Targ_UID = GetUID(); pSrc->m_pClient->m_Targ_Text = pszCmd; pSrc->m_pClient->addTarget(CLIMODE_TARG_PET_CMD, pTargPrompt, bTargAllowGround, bCheckCrime); return true; } // Make some sound to confirm we heard it NPC_PetConfirmCommand(true, pSrc); return true; }