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(); } }
void CChar::NPC_OnHirePayMore(CItem *pGold, bool bHire) { ADDTOCALLSTACK("CChar::NPC_OnHirePayMore"); // We have been handed money. // similar to PC_STATUS CCharBase *pCharDef = Char_GetDef(); CItemContainer *pBank = GetContainerCreate(LAYER_BANKBOX); if ( !pCharDef->m_iHireDayWage || !pBank ) return; if ( pGold ) { if ( bHire ) pBank->m_itEqBankBox.m_Check_Amount = 0; // clear 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 / pCharDef->m_iHireDayWage); Speak(pszMsg); }
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]; if ( !pCharDef->m_iHireDayWage || !iFoodConsumeRate ) return true; DWORD iPeriodWage = IMULDIV(pCharDef->m_iHireDayWage, iFoodConsumeRate, 24 * 60 * g_Cfg.m_iGameMinuteLength); if ( iPeriodWage <= 0 ) iPeriodWage = 1; CItemContainer *pBank = GetContainerCreate(LAYER_BANKBOX); 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), pCharDef->m_iHireDayWage); 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::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 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; }
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, GetContainerCreate(LAYER_PACK), 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; default: 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) ) 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: { if ( fLink || !pItem->Use_DoorNew(fLink) ) // 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; }