void CChar::NPC_OnHirePayMore( CItem * pGold, bool fHire ) { ADDTOCALLSTACK("CChar::NPC_OnHirePayMore"); // We have been handed money. // similar to PC_STATUS CCharBase * pCharDef = Char_GetDef(); unsigned int iWage = pCharDef->GetHireDayWage(); CItemContainer *pBank = GetBank(); if ( !iWage || !pBank ) return; if ( pGold ) { if ( fHire ) { pBank->m_itEqBankBox.m_Check_Amount = 0; // zero any previous balance. } pBank->m_itEqBankBox.m_Check_Amount += pGold->GetAmount(); Sound( pGold->GetDropSound( NULL )); pGold->Delete(); } TCHAR *pszMsg = Str_GetTemp(); sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_NPC_PET_HIRE_TIME), pBank->m_itEqBankBox.m_Check_Amount / iWage); Speak(pszMsg); }
bool CChar::ItemEquipWeapon( bool fForce ) { ADDTOCALLSTACK("CChar::ItemEquipWeapon"); // Find my best weapon and equip it if ( !fForce && m_uidWeapon.IsValidUID() ) // we already have a weapon equipped return true; CCharBase *pCharDef = Char_GetDef(); CItemContainer *pPack = GetPack(); if ( !pPack || !pCharDef || !pCharDef->Can(CAN_C_USEHANDS) ) return false; // Loop through all my weapons and come up with a score for it's usefulness CItem *pBestWeapon = NULL; int iWeaponScoreMax = NPC_GetWeaponUseScore(NULL); // wrestling for ( CItem *pItem = pPack->GetContentHead(); pItem != NULL; pItem = pItem->GetNext() ) { int iWeaponScore = NPC_GetWeaponUseScore(pItem); if ( iWeaponScore > iWeaponScoreMax ) { iWeaponScoreMax = iWeaponScore; pBestWeapon = pItem; } } if ( pBestWeapon ) return ItemEquip(pBestWeapon); return true; }
size_t CChar::NPC_OnHearName(LPCTSTR pszText) const { ADDTOCALLSTACK("CChar::NPC_OnHearName"); // Did I just hear my name in this text ? // should be able to deal with "hi Dennis" in the future. // RETURN: // index to skip past the name. LPCTSTR pszName = GetName(); size_t i = FindStrWord(pszText, pszName); if ( i ) return i; // Named the chars type ? (must come first !) CCharBase *pCharDef = Char_GetDef(); pszName = pCharDef->GetTradeName(); for ( i = 0; pszText[i] != '\0'; i++ ) { if ( pszName[i] == '\0' ) { // found name while ( ISWHITESPACE(pszText[i]) ) i++; return i; // char name found } if ( toupper(pszName[i]) != toupper(pszText[i]) ) // not the name break; } return 0; }
bool CChar::NPC_CheckHirelingStatus() { ADDTOCALLSTACK("CChar::NPC_CheckHirelingStatus"); // Am i happy at the moment ? // If not then free myself. // // RETURN: // true = happy. if ( ! IsStatFlag( STATF_Pet )) return( true ); CCharBase * pCharDef = Char_GetDef(); int iFoodConsumeRate = g_Cfg.m_iRegenRate[STAT_FOOD]; unsigned int iWage = pCharDef->GetHireDayWage(); if ( ! iWage || ! iFoodConsumeRate ) return( true ); // I am hired for money not for food. unsigned int iPeriodWage = IMULDIV( iWage, iFoodConsumeRate, 24 * 60 * g_Cfg.m_iGameMinuteLength ); if ( iPeriodWage <= 0 ) iPeriodWage = 1; CItemContainer * pBank = GetBank(); if ( pBank->m_itEqBankBox.m_Check_Amount > iPeriodWage ) { pBank->m_itEqBankBox.m_Check_Amount -= iPeriodWage; } else { TCHAR* pszMsg = Str_GetTemp(); sprintf(pszMsg, g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_WAGE_COST ), iWage); Speak(pszMsg); CChar * pOwner = NPC_PetGetOwner(); if ( pOwner ) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_HIRE_TIMEUP ) ); CItem * pMemory = Memory_AddObjTypes( pOwner, MEMORY_SPEAK ); if ( pMemory ) pMemory->m_itEqMemory.m_Action = NPC_MEM_ACT_SPEAK_HIRE; NPC_PetDesert(); return false; } // Some sort of strange bug to get here. Memory_ClearTypes( MEMORY_IPET ); StatFlag_Clear( STATF_Pet ); } return( true ); }
bool CChar::ItemEquipArmor( bool fForce ) { ADDTOCALLSTACK("CChar::ItemEquipArmor"); // Equip ourselves as best as possible. CCharBase *pCharDef = Char_GetDef(); CItemContainer *pPack = GetPack(); if ( !pPack || !pCharDef || !pCharDef->Can(CAN_C_EQUIP) ) return false; int iBestScore[LAYER_HORSE]; memset(iBestScore, 0, sizeof(iBestScore)); CItem *pBestArmor[LAYER_HORSE]; memset(pBestArmor, 0, sizeof(pBestArmor)); if ( !fForce ) { // Block those layers that are already used for ( size_t i = 0; i < COUNTOF(iBestScore); i++ ) { pBestArmor[i] = LayerFind(static_cast<LAYER_TYPE>(i)); if ( pBestArmor[i] != NULL ) iBestScore[i] = INT_MAX; } } for ( CItem *pItem = pPack->GetContentHead(); pItem != NULL; pItem = pItem->GetNext() ) { int iScore = pItem->Armor_GetDefense(); if ( !iScore ) // might not be armor continue; // Can I even equip this? LAYER_TYPE layer = CanEquipLayer(pItem, LAYER_QTY, NULL, true); if ( layer == LAYER_NONE ) continue; if ( iScore > iBestScore[layer] ) { iBestScore[layer] = iScore; pBestArmor[layer] = pItem; } } // Equip all the stuff we found for ( size_t i = 0; i < COUNTOF(iBestScore); i++ ) { if ( pBestArmor[i] ) ItemEquip(pBestArmor[i], this); } return true; }
size_t CChar::NPC_OnHearName( LPCTSTR pszText ) const { ADDTOCALLSTACK("CChar::NPC_OnHearName"); // Did I just hear my name in this text ? // should be able to deal with "hi Dennis" in the future. // RETURN: // index to skip past the name. LPCTSTR pszName = GetName(); size_t i = FindStrWord( pszText, pszName ); if ( i ) return( i ); if ( m_pNPC ) { // My title ? if ( m_pNPC->m_Brain == NPCBRAIN_GUARD ) { if ( ! strnicmp( pszText, "GUARD ", 6 )) return 6; } else if ( NPC_IsVendor()) { if ( ! strnicmp( pszText, "VENDOR ", 7 )) return 7; } } CCharBase * pCharDef = Char_GetDef(); // Named the chars type ? (must come first !) pszName = pCharDef->GetTradeName(); for ( i = 0; pszText[i] != '\0'; i++ ) { if ( pszName[i] == '\0' ) { // found name. while ( ISWHITESPACE( pszText[i] )) i++; return( i ); // Char name found } if ( toupper( pszName[i] ) != toupper( pszText[i] )) // not the name. break; } return( 0 ); }
bool CChar::NPC_OnHireHear( CChar * pCharSrc ) { ADDTOCALLSTACK("CChar::NPC_OnHireHear"); if ( !m_pNPC ) return false; CCharBase * pCharDef = Char_GetDef(); unsigned int iWage = pCharDef->GetHireDayWage(); if ( ! iWage ) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_NOT_FOR_HIRE ) ); return false; } CItemMemory * pMemory = Memory_FindObj( pCharSrc ); if ( pMemory ) { if ( pMemory->IsMemoryTypes(MEMORY_IPET|MEMORY_FRIEND)) { // Next gold i get goes toward hire. pMemory->m_itEqMemory.m_Action = NPC_MEM_ACT_SPEAK_HIRE; NPC_OnHirePayMore( NULL, false ); return true; } if ( pMemory->IsMemoryTypes( MEMORY_FIGHT|MEMORY_HARMEDBY|MEMORY_IRRITATEDBY )) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_NOT_WORK ) ); return false; } } if ( IsStatFlag( STATF_Pet )) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_EMPLOYED ) ); return false; } TCHAR *pszMsg = Str_GetTemp(); sprintf(pszMsg, Calc_GetRandVal(2) ? g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_HIRE_AMNT ) : g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_HIRE_RATE ), iWage ); Speak(pszMsg); pMemory = Memory_AddObjTypes( pCharSrc, MEMORY_SPEAK ); if ( pMemory ) pMemory->m_itEqMemory.m_Action = NPC_MEM_ACT_SPEAK_HIRE; return true; }
bool CChar::NPC_OnHirePay( CChar * pCharSrc, CItemMemory * pMemory, CItem * pGold ) { ADDTOCALLSTACK("CChar::NPC_OnHirePay"); if ( !m_pNPC || !pCharSrc || !pMemory ) return false; CCharBase * pCharDef = Char_GetDef(); if ( IsStatFlag( STATF_Pet )) { if ( ! pMemory->IsMemoryTypes(MEMORY_IPET|MEMORY_FRIEND)) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_EMPLOYED ) ); return false; } } else { unsigned int iWage = pCharDef->GetHireDayWage(); if ( iWage <= 0 ) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_NOT_FOR_HIRE ) ); return false; } if ( pGold->GetAmount() < iWage ) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_NOT_ENOUGH ) ); return false; } // NOTO_TYPE ? if ( pMemory->IsMemoryTypes( MEMORY_FIGHT|MEMORY_HARMEDBY|MEMORY_IRRITATEDBY )) { Speak( g_Cfg.GetDefaultMsg( DEFMSG_NPC_PET_NOT_WORK ) ); return false; } // Put all my loot cash away. ContentConsume( RESOURCE_ID(RES_TYPEDEF,IT_GOLD), INT_MAX, false, 0 ); // Mark all my stuff ATTR_OWNED - i won't give it away. ContentAttrMod( ATTR_OWNED, true ); NPC_PetSetOwner( pCharSrc ); } pMemory->m_itEqMemory.m_Action = NPC_MEM_ACT_NONE; NPC_OnHirePayMore( pGold, true ); 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; }