bool CChar::NPC_PetCheckAccess(int iCmd, CChar *pChar) { ADDTOCALLSTACK("CChar::NPC_PetCheckAccess"); // Check if pChar can use the required pet command if ( !m_pNPC || !pChar ) return false; switch ( iCmd ) { case PC_COME: case PC_FOLLOW: case PC_FOLLOW_ME: case PC_STAY: case PC_STOP: { // Pet friends can use only these commands if ( Memory_FindObjTypes(pChar, MEMORY_FRIEND) ) break; } default: { // All others commands are available only to pet owner if ( !NPC_IsOwnedBy(pChar) ) return false; } } if ( IsStatFlag(STATF_DEAD) ) { // Dead bonded pets can only listen to these commands if ( !((iCmd == PC_COME) || (iCmd == PC_FOLLOW) || (iCmd == PC_FOLLOW_ME) || (iCmd == PC_STAY) || (iCmd == PC_STOP) || (iCmd == PC_RELEASE)) ) return false; } 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_OnHearPetCmdTarg( int iCmd, CChar *pSrc, CObjBase *pObj, const CPointMap &pt, LPCTSTR pszArgs ) { ADDTOCALLSTACK("CChar::NPC_OnHearPetCmdTarg"); // Pet commands that required a target. if ( m_fIgnoreNextPetCmd ) { m_fIgnoreNextPetCmd = false; 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 bSuccess = false; CItem *pItemTarg = dynamic_cast<CItem *>(pObj); CChar *pCharTarg = dynamic_cast<CChar *>(pObj); switch ( iCmd ) { case PC_ATTACK: case PC_KILL: { if ( !pCharTarg || pCharTarg == pSrc ) break; bSuccess = pCharTarg->OnAttackedBy(pSrc, 1, true); // we know who told them to do this. if ( bSuccess ) bSuccess = Fight_Attack(pCharTarg, true); break; } case PC_FOLLOW: if ( !pCharTarg ) break; m_Act_Targ = pCharTarg->GetUID(); bSuccess = Skill_Start(NPCACT_FOLLOW_TARG); break; case PC_FRIEND: { if ( !pCharTarg || !pCharTarg->m_pPlayer || pCharTarg == pSrc ) { Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_CONFUSED)); break; } CItemMemory *pMemory = Memory_FindObjTypes(pCharTarg, MEMORY_FRIEND); if ( pMemory ) { pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_FRIEND_ALREADY)); break; } pSrc->SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_FRIEND_SUCCESS1), GetName(), pCharTarg->GetName()); pCharTarg->SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_FRIEND_SUCCESS2), pSrc->GetName(), GetName()); Memory_AddObjTypes(pCharTarg, MEMORY_FRIEND); m_Act_Targ = pCharTarg->GetUID(); bSuccess = Skill_Start(NPCACT_FOLLOW_TARG); break; } case PC_UNFRIEND: { if ( !pCharTarg || !pCharTarg->m_pPlayer ) { Speak(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_CONFUSED)); break; } CItemMemory *pMemory = Memory_FindObjTypes(pCharTarg, MEMORY_FRIEND); if ( !pMemory ) { pSrc->SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_UNFRIEND_NOTFRIEND)); break; } pSrc->SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_UNFRIEND_SUCCESS1), GetName(), pCharTarg->GetName()); pCharTarg->SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_UNFRIEND_SUCCESS2), pSrc->GetName(), GetName()); pMemory->Delete(); m_Act_Targ = pSrc->GetUID(); bSuccess = Skill_Start(NPCACT_FOLLOW_TARG); break; } case PC_GO: if ( !pt.IsValidPoint() ) break; m_Act_p = pt; bSuccess = Skill_Start(NPCACT_GOTO); break; case PC_GUARD: if ( !pCharTarg ) break; pCharTarg->SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_TARG_GUARD_SUCCESS), GetName()); m_Act_Targ = pCharTarg->GetUID(); bSuccess = Skill_Start(NPCACT_GUARD_TARG); break; case PC_TRANSFER: if ( !pCharTarg || !pCharTarg->IsClient() ) break; if ( IsSetOF(OF_PetSlots) ) { if ( !pCharTarg->FollowersUpdate(this, static_cast<short>(maximum(1, GetDefNum("FOLLOWERSLOTS", true, true))), true) ) { pSrc->SysMessageDefault(DEFMSG_PETSLOTS_TRY_TRANSFER); break; } } bSuccess = NPC_PetSetOwner( pCharTarg ); break; case PC_PRICE: // "PRICE" the vendor item. if ( !pItemTarg || !NPC_IsVendor() || !pSrc->IsClient() ) break; if ( IsDigit(pszArgs[0]) ) // did they name a price return NPC_SetVendorPrice(pItemTarg, ATOI(pszArgs)); if ( !NPC_SetVendorPrice(pItemTarg, -1) ) // test if it can be priced return false; pSrc->m_pClient->addPromptConsole(CLIMODE_PROMPT_VENDOR_PRICE, g_Cfg.GetDefaultMsg(DEFMSG_NPC_VENDOR_SETPRICE_2), pItemTarg->GetUID(), GetUID()); return true; default: break; } // Make some sound to confirm we heard it NPC_OnPetCommand(bSuccess, pSrc); return bSuccess; }
bool CChar::NPC_OnHearPetCmdTarg( int iCmd, CChar * pSrc, CObjBase * pObj, const CPointMap & pt, LPCTSTR pszArgs ) { ADDTOCALLSTACK("CChar::NPC_OnHearPetCmdTarg"); // Pet commands that required a target. if ( iCmd == PC_FOLLOW || iCmd == PC_STAY || iCmd == PC_STOP ) { // Pet friends can use only these commands if ( ! NPC_IsOwnedBy( pSrc ) && Memory_FindObjTypes( pSrc, MEMORY_FRIEND ) == NULL ) return false; } else { // All others commands are avaible only to pet owner if ( ! NPC_IsOwnedBy( pSrc, true ) ) return false; } if ( m_fIgnoreNextPetCmd == true ) { m_fIgnoreNextPetCmd = false; return(false); } bool fSuccess = false; // No they won't do it. // Could be NULL CItem * pItemTarg = dynamic_cast<CItem*>(pObj); CChar * pCharTarg = dynamic_cast<CChar*>(pObj); switch ( iCmd ) { case PC_GO: // Go to the location x,y if ( ! pt.IsValidPoint()) break; m_Act_p = pt; fSuccess = Skill_Start( NPCACT_GOTO ); break; case PC_GUARD: if ( pObj == NULL ) break; m_Act_Targ = pObj->GetUID(); fSuccess = Skill_Start( NPCACT_GUARD_TARG ); break; case PC_TRANSFER: // transfer ownership via the transfer command. if ( pCharTarg == NULL ) break; if ( pCharTarg->IsClient() ) { if ( IsSetOF(OF_PetSlots) ) { if ( !pCharTarg->FollowersUpdate(this, static_cast<short>(maximum(1, GetDefNum("FOLLOWERSLOTS", true, true))), true) ) { pSrc->SysMessageDefault( DEFMSG_PETSLOTS_TRY_TRANSFER ); break; } } fSuccess = NPC_PetSetOwner( pCharTarg ); } break; case PC_KILL: case PC_ATTACK: // Attack the target. if ( pCharTarg == NULL ) break; // refuse to attack friends. if ( NPC_IsOwnedBy( pCharTarg, true )) { fSuccess = false; // take no commands break; } fSuccess = pCharTarg->OnAttackedBy( pSrc, 1, true ); // we know who told them to do this. if ( fSuccess ) { fSuccess = Fight_Attack( pCharTarg, true ); } break; case PC_FOLLOW: if ( pCharTarg == NULL ) break; m_Act_Targ = pCharTarg->GetUID(); fSuccess = Skill_Start( NPCACT_FOLLOW_TARG ); break; case PC_FRIEND: // Not the same as owner, if ( pCharTarg == NULL ) break; Memory_AddObjTypes( pCharTarg, MEMORY_FRIEND ); break; case PC_PRICE: // "PRICE" the vendor item. if ( pItemTarg == NULL ) break; if ( ! NPC_IsVendor()) break; // did they name a price if ( IsDigit( pszArgs[0] )) { return NPC_SetVendorPrice( pItemTarg, ATOI(pszArgs) ); } // test if it is pricable. if ( ! NPC_SetVendorPrice( pItemTarg, -1 )) { return false; } // Now set it's price. if ( ! pSrc->IsClient()) break; pSrc->m_pClient->addPromptConsole( CLIMODE_PROMPT_VENDOR_PRICE, g_Cfg.GetDefaultMsg( DEFMSG_NPC_VENDOR_SETPRICE_2 ), pItemTarg->GetUID(), GetUID() ); return( true ); default: break; } // Make the yes/no noise. NPC_OnPetCommand( fSuccess, pSrc ); return fSuccess; }