示例#1
0
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();
	}
}
示例#2
0
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);
}
示例#3
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];

	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;
}
示例#4
0
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;
}
示例#5
0
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;
}
示例#6
0
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;
}