Пример #1
0
CResourceDef * CItemSpawn::FixDef()
{
	ADDTOCALLSTACK("CitemSpawn:FixDef");
	// Get a proper RESOURCE_ID from the id provided.
	// RETURN: true = ok.

	RESOURCE_ID_BASE rid = ( IsType(IT_SPAWN_ITEM) ? m_itSpawnItem.m_ItemID : m_itSpawnChar.m_CharID );

	if ( rid.GetResType() != RES_UNKNOWN )
	{
		return STATIC_CAST <CResourceDef *>(g_Cfg.ResourceGetDef(rid));
	}

	// No type info here !?
	if ( IsType(IT_SPAWN_ITEM))
	{
		ITEMID_TYPE id = static_cast<ITEMID_TYPE>(rid.GetResIndex());
		if ( id < ITEMID_TEMPLATE )
		{
			return( TryItem( id ) );
		}
		else
		{
			// try a template.
			rid = RESOURCE_ID( RES_TEMPLATE, id );
			CResourceDef * pDef = g_Cfg.ResourceGetDef(rid);
			if ( pDef )
			{
				m_itSpawnItem.m_ItemID = rid;
				return( STATIC_CAST <CResourceDef *>( pDef ));
			} //if fails
			return( TryItem( id ) );
		}
	}
	else
	{
		CREID_TYPE id = static_cast<CREID_TYPE>(rid.GetResIndex());
		if ( id < SPAWNTYPE_START )
		{
			return( TryChar( id ));
		}
		else
		{
			// try a spawn group.
			rid = RESOURCE_ID( RES_SPAWN, id );
			CResourceDef * pDef = g_Cfg.ResourceGetDef(rid);
			if ( pDef )
			{
				m_itSpawnChar.m_CharID = rid;
				return( STATIC_CAST <CResourceDef *>( pDef ));
			} //if fails
			return( TryChar( id ));
		}
	}
}
Пример #2
0
bool CClient::Cmd_Skill_Inscription()
{
	ADDTOCALLSTACK("CClient::Cmd_Skill_Inscription");
	// Select the scroll type to make.
	// iSelect = -1 = 1st setup.
	// iSelect = 0 = cancel
	// iSelect = x = execute the selection.
	// we should already be in inscription skill mode.

	ASSERT(m_pChar);

	CItem *pBlankScroll = m_pChar->ContentFind(RESOURCE_ID(RES_TYPEDEF, IT_SCROLL_BLANK));
	if ( !pBlankScroll )
	{
		SysMessageDefault(DEFMSG_INSCRIPTION_FAIL);
		return false;
	}

	if ( IsTrigUsed(TRIGGER_SKILLMENU) )
	{
		CScriptTriggerArgs args("sm_inscription");
		if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE )
			return true;
	}
	return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_inscription"));
}
Пример #3
0
bool CContainer::ContentFindKeyFor( CItem * pLocked ) const
{
	ADDTOCALLSTACK("CContainer::ContentFindKeyFor");
	// Look for the key that fits this in my possesion.
	// TODO: Double check for pLocked->m_itContainer.m_lockUID working
	return( pLocked->m_itContainer.m_lockUID && (ContentFind( RESOURCE_ID( RES_TYPEDEF, IT_KEY ), pLocked->m_itContainer.m_lockUID ) != NULL) );
}
Пример #4
0
int CChar::Use_PlayMusic( CItem * pInstrument, int iDifficultyToPlay )
{
	ADDTOCALLSTACK("CChar::Use_PlayMusic");
	// SKILL_ENTICEMENT, SKILL_MUSICIANSHIP,
	// ARGS:
	//	iDifficultyToPlay = 0-100
	// RETURN:
	//  >=0 = success
	//  -1 = too hard for u.
	//  -2 = can't play. no instrument.

	if ( !pInstrument )
	{
		pInstrument = ContentFind(RESOURCE_ID(RES_TYPEDEF, IT_MUSICAL), 0, 1);
		if ( !pInstrument )
		{
			SysMessageDefault(DEFMSG_MUSICANSHIP_NOTOOL);
			return -2;
		}
	}

	bool fSuccess = Skill_UseQuick(SKILL_MUSICIANSHIP, iDifficultyToPlay, (Skill_GetActive() != SKILL_MUSICIANSHIP));
	Sound(pInstrument->Use_Music(fSuccess));
	if ( fSuccess )
		return iDifficultyToPlay;	// success

	// Skill gain for SKILL_MUSICIANSHIP failure will need to be triggered
	// manually, since Skill_UseQuick isn't going to do it for us in this case
	if ( Skill_GetActive() == SKILL_MUSICIANSHIP )
		Skill_Experience(SKILL_MUSICIANSHIP, -iDifficultyToPlay);

	SysMessageDefault(DEFMSG_MUSICANSHIP_POOR);
	return -1;		// fail
}
Пример #5
0
CResourceDef *CItemSpawn::FixDef()
{
	ADDTOCALLSTACK("CitemSpawn:FixDef");

	RESOURCE_ID_BASE rid = (IsType(IT_SPAWN_ITEM) ? m_itSpawnItem.m_ItemID : m_itSpawnChar.m_CharID);
	if ( rid.GetResType() != RES_UNKNOWN )
		return static_cast<CResourceDef *>(g_Cfg.ResourceGetDef(rid));

	// No type info here !?
	if ( IsType(IT_SPAWN_CHAR) )
	{
		CREID_TYPE id = static_cast<CREID_TYPE>(rid.GetResIndex());
		if ( id < SPAWNTYPE_START )
			return TryChar(id);

		// try a spawn group.
		rid = RESOURCE_ID(RES_SPAWN, id);
		CResourceDef *pDef = g_Cfg.ResourceGetDef(rid);
		if ( pDef )
		{
			m_itSpawnChar.m_CharID = rid;
			return pDef;
		}
		return TryChar(id);
	}
	else
	{
		ITEMID_TYPE id = static_cast<ITEMID_TYPE>(rid.GetResIndex());
		if ( id < ITEMID_TEMPLATE )
			return TryItem(id);

		// try a template.
		rid = RESOURCE_ID(RES_TEMPLATE, id);
		CResourceDef *pDef = g_Cfg.ResourceGetDef(rid);
		if ( pDef )
		{
			m_itSpawnItem.m_ItemID = rid;
			return pDef;
		}
		return TryItem(id);
	}
}
Пример #6
0
inline CCharBase *CItemSpawn::TryChar(CREID_TYPE &id)
{
	ADDTOCALLSTACK("CitemSpawn:TryChar");
	CCharBase *pCharDef = CCharBase::FindCharBase(id);
	if ( pCharDef )
	{
		m_itSpawnChar.m_CharID = RESOURCE_ID(RES_CHARDEF, id);
		return pCharDef;
	}
	return NULL;
}
Пример #7
0
inline CItemBase *CItemSpawn::TryItem(ITEMID_TYPE &id)
{
	ADDTOCALLSTACK("CitemSpawn:TryItem");
	CItemBase *pItemDef = CItemBase::FindItemBase(id);
	if ( pItemDef )
	{
		m_itSpawnItem.m_ItemID = RESOURCE_ID(RES_ITEMDEF, id);
		return pItemDef;
	}
	return NULL;
}
Пример #8
0
CSkillDef::CSkillDef( SKILL_TYPE skill ) :
	CResourceLink( RESOURCE_ID( RES_SKILL, skill ))
{
	m_StatPercent	= 0;
	m_GainRadius	= 0;
	m_dwFlags		= 0;
	m_dwGroup		= 0;
	memset(m_Stat, 0, sizeof(m_Stat));
	memset(m_StatBonus, 0, sizeof(m_StatBonus));
	m_AdvRate.Init();
}
Пример #9
0
CCharPlayer::CCharPlayer(CChar *pChar, CAccount *pAccount) : m_pAccount(pAccount)
{
	m_wDeaths = m_wMurders = 0;
	m_speedMode = 0;
	m_pflag = 0;
	m_bKrToolbarEnabled = false;
	m_timeLastUsed.Init();

	memset(m_SkillLock, 0, sizeof(m_SkillLock));
	memset(m_StatLock, 0, sizeof(m_StatLock));
	SetSkillClass(pChar, RESOURCE_ID(RES_SKILLCLASS));
}
Пример #10
0
bool CDialogDef::GumpSetup( int iPage, CClient * pClient, CObjBase * pObjSrc, LPCTSTR Arguments )
{
	ADDTOCALLSTACK("CDialogDef::GumpSetup");
	CResourceLock	s;

	m_iControls		= 0;
	m_iTexts		= 0;
	m_pObj			= pObjSrc;
	m_iOriginX		= 0;
	m_iOriginY		= 0;
	m_iPage			= static_cast<WORD>(iPage);
	m_bNoDispose	= false;

	CScriptTriggerArgs	Args(iPage, 0, pObjSrc);
	//DEBUG_ERR(("Args.m_s1_raw %s  Args.m_s1 %s  Arguments 0x%x\n",Args.m_s1_raw, Args.m_s1, Arguments));
	Args.m_s1_raw = Args.m_s1 = Arguments;

	// read text first
	if ( g_Cfg.ResourceLock( s, RESOURCE_ID( RES_DIALOG, GetResourceID().GetResIndex(), RES_DIALOG_TEXT ) ) )
	{
		while ( s.ReadKey())
		{
			if ( m_iTexts >= (COUNTOF(m_sText) - 1) )
				break;
			m_pObj->ParseText( s.GetKeyBuffer(), pClient->GetChar() );
			m_sText[m_iTexts] = s.GetKey();
			m_iTexts++;
		}
	}
	else
	{
		// no gump text?
	}

	// read the main dialog
	if ( !ResourceLock( s ) )
		return false;
	if ( !s.ReadKey() )		// read the size.
		return( false );

	// starting x,y location.
	INT64 iSizes[2];
	TCHAR * pszBuf = s.GetKeyBuffer();
	m_pObj->ParseText( pszBuf, pClient->GetChar() );

	Str_ParseCmds( pszBuf, iSizes, COUNTOF(iSizes) );
	m_x		= static_cast<int>(iSizes[0]);
	m_y		= static_cast<int>(iSizes[1]);

	if ( OnTriggerRunVal( s, TRIGRUN_SECTION_TRUE, pClient->GetChar(), &Args ) == TRIGRET_RET_TRUE )
		return false;
	return true;
}
Пример #11
0
bool CItemMessage::LoadSystemPages()
{
	DEBUG_CHECK( IsBookSystem());

	CResourceLock s;
	if ( ! g_Cfg.ResourceLock( s, m_itBook.m_ResID ))
		return false;

	int iPages = -1;
	while ( s.ReadKeyParse())
	{
		switch ( FindTableSorted( s.GetKey(), sm_szLoadKeys, COUNTOF( sm_szLoadKeys )-1 ))
		{
		case CIC_AUTHOR:
			m_sAuthor = s.GetArgStr();
			break;
		case CIC_PAGES:
			iPages = s.GetArgVal();
			break;
		case CIC_TITLE:
			SetName( s.GetArgStr());	// Make sure the book is named.
			break;
		}
	}

	if ( iPages > 2*MAX_BOOK_PAGES || iPages < 0 )
		return( false );

	TCHAR szTemp[ 16*1024 ];
	for ( int iPage=1; iPage<=iPages; iPage++ )
	{
		if ( ! g_Cfg.ResourceLock( s, RESOURCE_ID( RES_BOOK, m_itBook.m_ResID.GetResIndex(), iPage )))
		{
			break;
		}

		int iLen = 0;
		while (s.ReadKey())
		{
			int iLenStr = strlen( s.GetKey());
			if ( iLen + iLenStr >= sizeof( szTemp ))
				break;
			iLen += strcpylen( szTemp+iLen, s.GetKey());
			szTemp[ iLen++ ] = '\t';
		}
		szTemp[ --iLen ] = '\0';

		AddPageText( szTemp );
	}

	return( true );
}
Пример #12
0
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;
}
Пример #13
0
CSpellDef::CSpellDef( SPELL_TYPE id ) :
	CResourceLink( RESOURCE_ID( RES_SPELL, id ))
{
	m_dwFlags = SPELLFLAG_DISABLED;
	m_dwGroup = 0;
	m_sound = 0;
	m_idSpell = ITEMID_NOTHING;
	m_idScroll = ITEMID_NOTHING;
	m_idEffect = ITEMID_NOTHING;
	m_idLayer = LAYER_NONE;
	m_wManaUse = 0;
	m_wTithingUse = 0;
	m_CastTime.Init();
	m_Interrupt.Init();
	m_Interrupt.m_aiValues.SetCount( 1 );
	m_Interrupt.m_aiValues[0] = 1000;
}
Пример #14
0
int CContainer::ContentConsume( RESOURCE_ID_BASE rid, int amount, bool fTest, DWORD dwArg )
{
	ADDTOCALLSTACK("CContainer::ContentConsume");
	// ARGS:
	//  dwArg = a hack for ores.
	// RETURN:
	//  0 = all consumed ok.
	//  # = number left to be consumed. (still required)

	if ( rid.GetResIndex() == 0 )
		return( amount );	// from skills menus.

	CItem * pItemNext;
	for ( CItem* pItem=GetContentHead(); pItem!=NULL; pItem=pItemNext)
	{
		pItemNext = pItem->GetNext();

		if ( pItem->IsResourceMatch( rid, dwArg ))
		{
			amount -= pItem->ConsumeAmount( amount, fTest );
			if ( amount <= 0 )
				break;
		}

		CItemContainer * pCont = dynamic_cast <CItemContainer*> (pItem);
		if ( pCont != NULL )	// this is a sub-container.
		{
			if ( rid == RESOURCE_ID(RES_TYPEDEF,IT_GOLD))
			{
				if ( pCont->IsType(IT_CONTAINER_LOCKED))
					continue;
			}
			else
			{
				if ( ! pCont->IsSearchable())
					continue;
			}
			amount = pCont->ContentConsume( rid, amount, fTest, dwArg );
			if ( amount <= 0 )
				break;
		}
	}
	return( amount );
}
Пример #15
0
CItemVendable *CChar::NPC_FindVendableItem(CItemVendable *pVendItem, CItemContainer *pContBuy)	// static
{
	ADDTOCALLSTACK("CChar::NPC_FindVendableItem");
	// Does the NPC want to buy this item?
	if ( !pVendItem || !pContBuy || !pVendItem->IsValidSaleItem(false) )
		return NULL;

	CItem *pItemTest = pContBuy->ContentFind(RESOURCE_ID(RES_ITEMDEF, pVendItem->GetID()));
	if ( !pItemTest )
		return NULL;

	CItemVendable *pItemSell = dynamic_cast<CItemVendable *>(pItemTest);
	if ( !pItemSell )	// the item is not vendable
		return NULL;
	if ( pVendItem->GetType() != pItemSell->GetType() )	// sanity check
		return NULL;

	return pItemSell;
}
Пример #16
0
TRIGRET_TYPE CClient::Dialog_OnButton( RESOURCE_ID_BASE rid, DWORD dwButtonID, CObjBase * pObj, CDialogResponseArgs * pArgs )
{
	ADDTOCALLSTACK("CClient::Dialog_OnButton");
	// one of the gump dialog buttons was pressed.
	if ( !pObj )		// object is gone ?
		return TRIGRET_ENDIF;

	CResourceLock s;
	if ( !g_Cfg.ResourceLock(s, RESOURCE_ID(RES_DIALOG, rid.GetResIndex(), RES_DIALOG_BUTTON)) )
		return TRIGRET_ENDIF;

	INT64 piCmd[3];
	while ( s.ReadKeyParse())
	{
		if ( ! s.IsKeyHead( "ON", 2 ))
			continue;

		size_t iArgs = Str_ParseCmds( s.GetArgStr(), piCmd, COUNTOF(piCmd) );
		if ( iArgs == 0 )
			continue;

		if ( iArgs == 1 )
		{
			// single button value
			if ( (DWORD)piCmd[0] != dwButtonID )
				continue;
		}
		else
		{
			// range of button values
			if ( dwButtonID < (DWORD)piCmd[0] || dwButtonID > (DWORD)piCmd[1] )
				continue;
		}

		pArgs->m_iN1	 = dwButtonID;		
		return pObj->OnTriggerRunVal( s, TRIGRUN_SECTION_TRUE, m_pChar, pArgs );
	}

	return( TRIGRET_ENDIF );
}
Пример #17
0
RESOURCE_ID CResourceBase::ResourceGetID( RES_TYPE restype, LPCTSTR & pszName )
{
	ADDTOCALLSTACK("CResourceBase::ResourceGetID");
	// Find the Resource ID given this name.
	// We are NOT creating a new resource. just looking up an existing one
	// NOTE: Do not enforce the restype.
	//		Just fill it in if we are not sure what the type is.
	// NOTE: 
	//  Some restype's have private name spaces. (ie. RES_AREA)
	// RETURN:
	//  pszName is now set to be after the expression.

	// We are NOT creating.
	RESOURCE_ID rid;

	// Try to handle private name spaces.
	switch ( restype )
	{
		case RES_ACCOUNT:
		case RES_AREA:
		case RES_GMPAGE:
		case RES_ROOM:
		case RES_SECTOR:
			break;

		default:
			break;
	}

	rid.SetPrivateUID( Exp_GetVal(pszName));	// May be some complex expression {}

	if ( restype != RES_UNKNOWN && rid.GetResType() == RES_UNKNOWN )
	{
		// Label it with the type we want.
		return RESOURCE_ID( restype, rid.GetResIndex());
	}

	return( rid );
}
Пример #18
0
        FOG_MERGE(0),
        OMOD(SQ_ALU_OMOD_OFF),
        ALU_INST(SQ_OP2_INST_KILLNE),
        BANK_SWIZZLE(SQ_ALU_VEC_012),
        DST_GPR(0),
        DST_REL(ABSOLUTE),
        DST_ELEM(ELEM_X),
        CLAMP(0)),

#endif

    /* TEX INST 0 */
    TEX_DWORD0(TEX_INST(SQ_TEX_INST_SAMPLE),
        BC_FRAC_MODE(0),
        FETCH_WHOLE_QUAD(0),
        RESOURCE_ID(0),
        SRC_GPR(0),
        SRC_REL(ABSOLUTE),
        R7xx_ALT_CONST(0)),
    TEX_DWORD1(DST_GPR(0),
        DST_REL(ABSOLUTE),
        DST_SEL_X(SQ_SEL_X), /* R */
        DST_SEL_Y(SQ_SEL_Y), /* G */
        DST_SEL_Z(SQ_SEL_Z), /* B */
        DST_SEL_W(SQ_SEL_W), /* A */
        LOD_BIAS(0),
        COORD_TYPE_X(TEX_UNNORMALIZED),
        COORD_TYPE_Y(TEX_UNNORMALIZED),
        COORD_TYPE_Z(TEX_UNNORMALIZED),
        COORD_TYPE_W(TEX_UNNORMALIZED)),
    TEX_DWORD2(OFFSET_X(0),
Пример #19
0
CResourceDef * CItem::Spawn_FixDef()
{
	// Get a proper RESOURCE_ID from the id provided.
	// RETURN: true = ok.

	RESOURCE_ID_BASE rid;
	if ( IsType(IT_SPAWN_ITEM))
	{
		rid = m_itSpawnItem.m_ItemID;
	}
	else
	{
		ASSERT( IsType(IT_SPAWN_CHAR) );
		rid = m_itSpawnChar.m_CharID;
	}

	if ( rid.GetResType() != RES_UNKNOWN )
	{
		return STATIC_CAST <CResourceDef *>( g_Cfg.ResourceGetDef(rid));
	}

	// No type info here !?

	if ( IsType(IT_SPAWN_ITEM))
	{
		ITEMID_TYPE id = (ITEMID_TYPE) rid.GetResIndex();
		if ( id < ITEMID_TEMPLATE )
		{
why_not_try_this_item:
			CItemBase * pItemDef = CItemBase::FindItemBase( id );
			if ( pItemDef )
			{
				m_itSpawnItem.m_ItemID = RESOURCE_ID( RES_ITEMDEF, id );
				return( pItemDef );
			}
		}
		else
		{
			// try a template.
			rid = RESOURCE_ID( RES_TEMPLATE, id );
			CResourceDef * pDef = g_Cfg.ResourceGetDef(rid);
			if ( pDef )
			{
				m_itSpawnItem.m_ItemID = rid;
				return( STATIC_CAST <CResourceDef *>( pDef ));
			}
			goto why_not_try_this_item;
		}
	}
	else
	{
		CREID_TYPE id = (CREID_TYPE) rid.GetResIndex();
		if ( id < SPAWNTYPE_START )
		{
why_not_try_this_char:
			CCharBase * pCharDef = CCharBase::FindCharBase( id );
			if ( pCharDef )
			{
				m_itSpawnChar.m_CharID = RESOURCE_ID( RES_CHARDEF, id );
				return( pCharDef );
			}
		}
		else
		{
			// try a spawn group.
			rid = RESOURCE_ID( RES_SPAWN, id );
			CResourceDef * pDef = g_Cfg.ResourceGetDef(rid);
			if ( pDef )
			{
				m_itSpawnChar.m_CharID = rid;
				return( STATIC_CAST <CResourceDef *>( pDef ));
			}
			goto why_not_try_this_char;
		}
	}

	return( NULL );
}
Пример #20
0
bool CClient::Cmd_Use_Item( CItem * pItem, bool fTestTouch, bool fScript )
{
	ADDTOCALLSTACK("CClient::Cmd_Use_Item");
	// Assume we can see the target.
	// called from Event_DoubleClick

	if ( pItem == NULL )
		return false;

	if (pItem->m_Can & CAN_I_FORCEDC)
		fTestTouch = false;

	if ( fTestTouch )
	{
		if( !fScript ) 
		{
			CItemContainer * container = (dynamic_cast <CItemContainer*>(pItem->GetParent()));
			if( container != NULL ) 
			{
				// protect from ,snoop - disallow picking from not opened containers
				bool isInOpenedContainer = false;
				IT_TYPE type = container->GetType();
				if ( type == IT_EQ_TRADE_WINDOW)
				{
					isInOpenedContainer = true;
				} else {
					CClient::OpenedContainerMap_t::iterator itContainerFound = m_openedContainers.find( container->GetUID().GetPrivateUID() );
					if ( itContainerFound != m_openedContainers.end() )
					{
						DWORD dwTopContainerUID = (((*itContainerFound).second).first).first;
						DWORD dwTopMostContainerUID = (((*itContainerFound).second).first).second;
						CPointMap ptOpenedContainerPosition = ((*itContainerFound).second).second;
						const CObjBaseTemplate * pObjTop = pItem->GetTopLevelObj();
					
						DWORD dwTopContainerUID_ToCheck = 0;
						if ( container->GetContainer() )
							dwTopContainerUID_ToCheck = container->GetContainer()->GetUID().GetPrivateUID();
						else
							dwTopContainerUID_ToCheck = pObjTop->GetUID().GetPrivateUID();

						if ( ( dwTopMostContainerUID == pObjTop->GetUID().GetPrivateUID() ) && ( dwTopContainerUID == dwTopContainerUID_ToCheck ) )
						{
							if ( pObjTop->IsChar() )
							{
								isInOpenedContainer = true;
								// probably a pickup check from pack if pCharTop != this?
							}
							else
							{
								const CItem * pItemTop = dynamic_cast<const CItem *>(pObjTop);
								if ( pItemTop && (pItemTop->IsType(IT_SHIP_HOLD) || pItemTop->IsType(IT_SHIP_HOLD_LOCK)) && (pItemTop->GetTopPoint().GetRegion(REGION_TYPE_MULTI) == m_pChar->GetTopPoint().GetRegion(REGION_TYPE_MULTI)) )
								{
									isInOpenedContainer = true;
								}
								else if ( ptOpenedContainerPosition.GetDist( pObjTop->GetTopPoint() ) <= 3 )
								{
									isInOpenedContainer = true;
								}
							}
						}
					}
				}
				
				if( !isInOpenedContainer ) 
				{
					SysMessageDefault(DEFMSG_REACH_UNABLE);
					return false;
				}
			}
		}

		// CanTouch handles priv level compares for chars
		if ( ! m_pChar->CanUse( pItem, false ))
		{
			if ( ! m_pChar->CanTouch( pItem ))
			{
				SysMessage(( m_pChar->IsStatFlag( STATF_DEAD )) ?
					g_Cfg.GetDefaultMsg( DEFMSG_REACH_GHOST ) :
					g_Cfg.GetDefaultMsg( DEFMSG_REACH_FAIL ) );
			}
			else
			{
				SysMessageDefault( DEFMSG_REACH_UNABLE );
			}
			
			return false;
		}
	}

	CItemBase * pItemDef = pItem->Item_GetDef();
	bool fWasEquipped = pItem->IsItemEquipped();

	if (( IsTrigUsed(TRIGGER_DCLICK) ) || ( IsTrigUsed(TRIGGER_ITEMDCLICK) ))
	{
		if ( pItem->OnTrigger( ITRIG_DCLICK, m_pChar ) == TRIGRET_RET_TRUE )
			return true;
	}

	if ( pItemDef->IsTypeEquippable() && ! pItem->IsItemEquipped() && pItemDef->GetEquipLayer() )
	{
		if ( pItem->IsType(IT_LIGHT_OUT) && pItem->IsItemInContainer())
		{
			if ( ! Cmd_Use_Item_MustEquip( pItem ) )
				return false;
		}
		else if ( ! pItem->IsType(IT_LIGHT_OUT) && ! pItem->IsType(IT_LIGHT_LIT) &&
					! pItem->IsTypeSpellbook() )
		{
			if ( ! Cmd_Use_Item_MustEquip( pItem ) )
				return false;
		}
	}

	CItemSpawn * pSpawn = static_cast<CItemSpawn*>(pItem->m_uidSpawnItem.ItemFind()); //Removing this item from it's spawn when players DClick it from ground, no other way to take it out.
	if ( pSpawn )
		pSpawn->DelObj(pItem->GetUID());

	SetTargMode();
	m_Targ_UID = pItem->GetUID(); // probably already set anyhow.
	m_tmUseItem.m_pParent = pItem->GetParent(); // Cheat Verify.
	// Use types of items. (specific to client)
	switch ( pItem->GetType() )
	{
		case IT_TRACKER:
			{
				DIR_TYPE dir = static_cast<DIR_TYPE>(DIR_QTY + 1); // invalid value.
				if ( ! m_pChar->Skill_Tracking( pItem->m_uidLink, dir ))
				{
					if ( pItem->m_uidLink.IsValidUID())
					{
						SysMessageDefault( DEFMSG_TRACKING_UNABLE );
					}
					m_Targ_UID = pItem->GetUID();
					addTarget( CLIMODE_TARG_LINK, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_TRACKER_ATTUNE ) );
				}
			}
			return true;

		case IT_TRACK_ITEM:		// 109 - track a id or type of item.
		case IT_TRACK_CHAR:		// 110 = track a char or range of char id's
			// Track a type of item or creature.
			{
				// Look in the local area for this item or char.


			}
			break;

		case IT_SHAFT:
		case IT_FEATHER:
			{
				if ( IsTrigUsed(TRIGGER_SKILLMENU) )
				{
					CScriptTriggerArgs args("sm_bolts");
					if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE )
						return true;
				}
				return Cmd_Skill_Menu( g_Cfg.ResourceGetIDType( RES_SKILLMENU, "sm_bolts" ) );
			}
		case IT_FISH_POLE:	// Just be near water ?
			m_pChar->m_atResource.m_ridType	= RESOURCE_ID( RES_TYPEDEF, IT_WATER );
			addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_FISHING_PROMT ), true );
			return true;
		case IT_DEED:
			addTargetDeed( pItem );
			return true;

		case IT_EQ_BANK_BOX:
		case IT_EQ_VENDOR_BOX:
			if ( !fScript )
			g_Log.Event( LOGL_WARN|LOGM_CHEAT,
				"%lx:Cheater '%s' is using 3rd party tools to open bank box\n",
				GetSocketID(), static_cast<LPCTSTR>(GetAccount()->GetName()));
			return false;

		case IT_CONTAINER_LOCKED:
		case IT_SHIP_HOLD_LOCK:
			if ( ! m_pChar->GetPackSafe()->ContentFindKeyFor( pItem ))
			{
				SysMessageDefault( DEFMSG_ITEMUSE_LOCKED );
				if ( ! IsPriv( PRIV_GM ))
					return false;
			}

		case IT_CORPSE:
		case IT_SHIP_HOLD:
		case IT_CONTAINER:
		case IT_TRASH_CAN:
			{
				CItemContainer * pPack = dynamic_cast <CItemContainer *>(pItem);
				if (!pPack)
					return false;
				if ( ! m_pChar->Skill_Snoop_Check( pPack ))
				{
					if( !addContainerSetup(pPack) ) {
						return false;
					}
				}

				const CItemCorpse * pCorpseItem = dynamic_cast <const CItemCorpse *>(pPack);
				if ( m_pChar->CheckCorpseCrime( pCorpseItem, true, true ) )
					SysMessageDefault(DEFMSG_LOOT_CRIMINAL_ACT);
			}
			return true;

		case IT_GAME_BOARD:
			if ( ! pItem->IsTopLevel())
			{
				SysMessageDefault( DEFMSG_ITEMUSE_GAMEBOARD_FAIL );
				return false;
			}
			{
				CItemContainer* pBoard = dynamic_cast <CItemContainer *>(pItem);
				ASSERT(pBoard);
				pBoard->Game_Create();
				addContainerSetup( pBoard );
			}
			return true;

		case IT_BBOARD:
			addBulletinBoard( dynamic_cast<CItemContainer *>(pItem));
			return true;

		case IT_SIGN_GUMP:
			// Things like grave stones and sign plaques.
			// Need custom gumps.
			{
			GUMP_TYPE gumpid = pItemDef->m_ttContainer.m_gumpid;
			if ( ! gumpid )
			{
				return false;
			}
			addGumpTextDisp( pItem, gumpid,	pItem->GetName(),
				( pItem->IsIndividualName()) ? pItem->GetName() : NULL );
			}
			return true;

		case IT_BOOK:
		case IT_MESSAGE:
			if ( ! addBookOpen( pItem ))
			{
				SysMessageDefault( DEFMSG_ITEMUSE_BOOK_FAIL );
			}
			return true;

		case IT_STONE_GUILD:
		case IT_STONE_TOWN:
			// Guild and town stones.
			return true;

		case IT_POTION:
			if ( !m_pChar->CanMove(pItem) )
			{
				SysMessageDefault( DEFMSG_ITEMUSE_POTION_FAIL );
				return false;
			}
			if ( RES_GET_INDEX(pItem->m_itPotion.m_Type) == SPELL_Poison )
			{
				// If we click directly on poison potion, we will drink poison and get ill.
				// To use it on Poisoning skill, the skill will request to target the potion.
				m_pChar->OnSpellEffect(SPELL_Poison, m_pChar, pItem->m_itSpell.m_spelllevel, NULL);
				return true;
			}
			else if ( RES_GET_INDEX(pItem->m_itPotion.m_Type) == SPELL_Explosion )
			{
				// Throw explode potion.
				if ( !m_pChar->ItemPickup(pItem, 1) )
					return false;

				m_tmUseItem.m_pParent = pItem->GetParent();		// put the potion in our hand
				addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_POTION_TARGET), true, true, 5*TICK_PER_SEC);

				pItem->m_itPotion.m_tick = 4;		// countdown to explode
				pItem->m_itPotion.m_ignited = 1;	// ignite it
				pItem->SetTimeout(TICK_PER_SEC);
				pItem->m_uidLink = m_pChar->GetUID();
				return true;
			}
			m_pChar->Use_Drink(pItem);
			return true;

		case IT_ANIM_ACTIVE:
			SysMessage( g_Cfg.GetDefaultMsg( DEFMSG_ITEM_IN_USE ) );
			return false;

		case IT_CLOCK:
			addObjMessage( m_pChar->GetTopSector()->GetLocalGameTime(), pItem );
			return true;

		case IT_SPAWN_CHAR:
			{
				bool	fReset	= false;
			if ( pItem->m_itSpawnChar.m_current )
				SysMessageDefault( DEFMSG_ITEMUSE_SPAWNCHAR_NEG );
			else
			{
				SysMessageDefault( DEFMSG_ITEMUSE_SPAWNCHAR_RSET );
				fReset	= true;
			}
			static_cast<CItemSpawn*>(pItem)->KillChildren();
			if ( fReset )
				pItem->SetTimeout( TICK_PER_SEC );
			}
			return true;

		case IT_SPAWN_ITEM:
			{
				SysMessageDefault(DEFMSG_ITEMUSE_SPAWNITEM_TRIG);
				//CItemSpawn *pSpawn = static_cast<CItemSpawn*>(pItem);
				pSpawn->OnTick(true);
			}
			return true;

		case IT_SHRINE:
			if ( m_pChar->OnSpellEffect( SPELL_Resurrection, m_pChar, 1000, pItem ))
				return true;
			SysMessageDefault( DEFMSG_ITEMUSE_SHRINE );
			return true;

		case IT_SHIP_TILLER:
			// dclick on tiller man.
			pItem->Speak( g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_TILLERMAN ), HUE_TEXT_DEF, TALKMODE_SAY, FONT_NORMAL );
			return true;

			// A menu or such other action ( not instantanious)

		case IT_WAND:
		case IT_SCROLL:	// activate the scroll.
			{
				SPELL_TYPE spell = static_cast<SPELL_TYPE>(RES_GET_INDEX(pItem->m_itWeapon.m_spell));
				const CSpellDef* pSpellDef = g_Cfg.GetSpellDef(spell);
				if (pSpellDef == NULL)
					return false;

				if ( IsSetMagicFlags( MAGICF_PRECAST ) && !pSpellDef->IsSpellType( SPELLFLAG_NOPRECAST ) )
				{
					int skill;
					if (!pSpellDef->GetPrimarySkill(&skill, NULL))
						return false;

					m_tmSkillMagery.m_Spell = spell;	// m_atMagery.m_Spell
					m_pChar->m_atMagery.m_Spell = spell;
					m_Targ_UID = pItem->GetUID();	// default target.
					m_Targ_PrvUID = pItem->GetUID();
					m_pChar->Skill_Start(static_cast<SKILL_TYPE>(skill));
					return true;
				}
				return Cmd_Skill_Magery( spell, pItem );
			}
		case IT_RUNE:
			// name the rune.
			if ( ! m_pChar->CanMove( pItem, true ))
			{
				return false;
			}
			addPromptConsole( CLIMODE_PROMPT_NAME_RUNE, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_RUNE_NAME ), pItem->GetUID() );
			return true;

		case IT_CARPENTRY:
			// Carpentry type tool
			{
				if ( IsTrigUsed(TRIGGER_SKILLMENU) )
				{
					CScriptTriggerArgs args("sm_carpentry");
					if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE )
						return true;
				}
				return Cmd_Skill_Menu( g_Cfg.ResourceGetIDType( RES_SKILLMENU, "sm_carpentry" ) );
			}
			// Solve for the combination of this item with another.
		case IT_FORGE:
			addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg ( DEFMSG_ITEMUSE_FORGE ) );
			return true;
		case IT_ORE:
			// just use the nearest forge.
			return m_pChar->Skill_Mining_Smelt( pItem, NULL );
		case IT_INGOT:
			return Cmd_Skill_Smith( pItem );

		case IT_KEY:
		case IT_KEYRING:
			if ( pItem->GetTopLevelObj() != m_pChar && ! m_pChar->IsPriv(PRIV_GM))
			{
				SysMessageDefault( DEFMSG_ITEMUSE_KEY_FAIL );
				return false;
			}
			addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_KEY_PROMT ), false, true );
			return true;

		case IT_BANDAGE:		// SKILL_HEALING, or SKILL_VETERINARY
			addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_BANDAGE_PROMT ), false, false );
			return true;

		case IT_BANDAGE_BLOOD:	// Clean the bandages.
		case IT_COTTON:			// use on a spinning wheel.
		case IT_WOOL:			// use on a spinning wheel.
		case IT_YARN:			// Use this on a loom.
		case IT_THREAD: 		// Use this on a loom.
		case IT_COMM_CRYSTAL:
			addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_TARGET_PROMT ), false, false );
			return true;

		case IT_CARPENTRY_CHOP:
		case IT_LOCKPICK:		// Use on a locked thing.
		case IT_SCISSORS:
			addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_TARGET_PROMT ), false, true );
			return true;

		case IT_WEAPON_MACE_SHARP:	// war axe can be used to cut/chop trees.
		case IT_WEAPON_SWORD:		// 23 =
		case IT_WEAPON_FENCE:		// 24 = can't be used to chop trees.
		case IT_WEAPON_AXE:
			// set resource to trees
			m_pChar->m_atResource.m_ridType	= RESOURCE_ID( RES_TYPEDEF, IT_TREE );

		case IT_WEAPON_MACE_STAFF:
		case IT_WEAPON_MACE_SMITH:	// Can be used for smithing ?
		{
			if (fWasEquipped || !IsSetOF(OF_NoDClickTarget))
				addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_WEAPON_PROMT), false, true);
			}
			return true;

		case IT_FISH:
			SysMessageDefault( DEFMSG_ITEMUSE_FISH_FAIL );
			return true;
		case IT_TELESCOPE:
			// Big telescope.
			SysMessageDefault( DEFMSG_ITEMUSE_TELESCOPE );
			return true;
		case IT_MAP:
			addDrawMap(dynamic_cast<CItemMap*>(pItem));
			return true;

		case IT_CANNON_BALL:
			{
				TCHAR *pszTemp = Str_GetTemp();
				sprintf(pszTemp, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_CBALL_PROMT ), static_cast<LPCTSTR>(pItem->GetName()));
				addTarget(CLIMODE_TARG_USE_ITEM, pszTemp);
			}
			return true;

		case IT_CANNON_MUZZLE:
			// Make sure the cannon is loaded.
			if ( ! m_pChar->CanUse( pItem, false ))
				return( false );
			if ( ! ( pItem->m_itCannon.m_Load & 1 ))
			{
				addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_CANNON_POWDER ) );
				return true;
			}
			if ( ! ( pItem->m_itCannon.m_Load & 2 ))
			{
				addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_CANNON_SHOT ) );
				return true;
			}
			addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_CANNON_TARG ), false, true );
			return true;

		case IT_CRYSTAL_BALL:
			// Gaze into the crystal ball.

			return true;

		case IT_WEAPON_MACE_CROOK:
			if (fWasEquipped || !IsSetOF(OF_NoDClickTarget))
				addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_CROOK_PROMT ), false, true );
			return true;

		case IT_SEED:
		case IT_PITCHER_EMPTY:
			{ // not a crime.
				TCHAR *pszTemp = Str_GetTemp();
				sprintf(pszTemp, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_PITCHER_TARG ), static_cast<LPCTSTR>(pItem->GetName()));
				addTarget(CLIMODE_TARG_USE_ITEM, pszTemp, true);
			}
			return true;

		case IT_WEAPON_MACE_PICK:

			if (fWasEquipped || !IsSetOF(OF_NoDClickTarget))
			{	// Mine at the location. (possible crime?)
				TCHAR *pszTemp = Str_GetTemp();
				sprintf(pszTemp, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_MACEPICK_TARG ), static_cast<LPCTSTR>(pItem->GetName()));
				m_pChar->m_atResource.m_ridType	= RESOURCE_ID(RES_TYPEDEF, IT_ROCK);
				addTarget(CLIMODE_TARG_USE_ITEM, pszTemp, true, true);
			}
			return true;

		case IT_SPELLBOOK:
			addSpellbookOpen( pItem );
			return true;

		case IT_SPELLBOOK_NECRO:
			addSpellbookOpen( pItem, 101 );
			return true;

		case IT_SPELLBOOK_PALA:
			addSpellbookOpen( pItem, 201 );
			return true;

		case IT_SPELLBOOK_BUSHIDO:
			addSpellbookOpen( pItem, 401 );
			return true;

		case IT_SPELLBOOK_NINJITSU:
			addSpellbookOpen( pItem, 501 );
			return true;

		case IT_SPELLBOOK_ARCANIST:
			addSpellbookOpen( pItem, 601 );
			return true;
 
		case IT_SPELLBOOK_MYSTIC:
			addSpellbookOpen( pItem, 678 );
			return true;

		case IT_SPELLBOOK_BARD:
			addSpellbookOpen( pItem, 701 );
			return true;

		case IT_HAIR_DYE:
			if (!m_pChar->LayerFind( LAYER_BEARD ) && !m_pChar->LayerFind( LAYER_HAIR ))
			{
				SysMessageDefault( DEFMSG_ITEMUSE_DYE_NOHAIR );
				return true;
			}
			Dialog_Setup(CLIMODE_DIALOG, g_Cfg.ResourceGetIDType( RES_DIALOG, "d_HAIR_DYE" ), 0, pItem );
			return true;
		case IT_DYE:
			addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_DYE_VAT ) );
			return true;
		case IT_DYE_VAT:
			addTarget( CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_DYE_TARG ), false, true );
			return true;

		case IT_MORTAR:
			{
				if ( IsTrigUsed(TRIGGER_SKILLMENU) )
				{
					CScriptTriggerArgs args("sm_alchemy");
					if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE )
						return true;
				}
				return Cmd_Skill_Menu( g_Cfg.ResourceGetIDType( RES_SKILLMENU, "sm_alchemy" ) );
			}

		case IT_CARTOGRAPHY:
			{
				if ( IsTrigUsed(TRIGGER_SKILLMENU) )
				{
					CScriptTriggerArgs args("sm_cartography");
					if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE )
						return true;
				}
				return Cmd_Skill_Menu( g_Cfg.ResourceGetIDType( RES_SKILLMENU, "sm_cartography" ) );
			}

		case IT_COOKING:
			{
				if ( IsTrigUsed(TRIGGER_SKILLMENU) )
				{
					CScriptTriggerArgs args("sm_cooking");
					if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE )
						return true;
				}
				return Cmd_Skill_Menu( g_Cfg.ResourceGetIDType( RES_SKILLMENU, "sm_cooking" ) );
			}

		case IT_TINKER_TOOLS:
			{
				if ( IsTrigUsed(TRIGGER_SKILLMENU) )
				{
					CScriptTriggerArgs args("sm_tinker");
					if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE )
						return true;
				}
				return Cmd_Skill_Menu( g_Cfg.ResourceGetIDType( RES_SKILLMENU, "sm_tinker" ) );
			}

		case IT_SEWING_KIT:	// IT_SEWING_KIT Sew with materials we have on hand.
			{
				TCHAR *pszTemp = Str_GetTemp();
				sprintf(pszTemp, g_Cfg.GetDefaultMsg( DEFMSG_ITEMUSE_SEWKIT_PROMT ), static_cast<LPCTSTR>(pItem->GetName()));
				addTarget(CLIMODE_TARG_USE_ITEM, pszTemp);
			}
			return true;

		case IT_SCROLL_BLANK:
			Cmd_Skill_Inscription();
			return true;

		default:
			// An NPC could use it this way.
			if ( m_pChar->Use_Item( pItem ))
				return( true );
			break;
	}

	SysMessageDefault( DEFMSG_ITEMUSE_CANTTHINK );
	return( false );
}
Пример #21
0
bool CChar::Use_Train_ArcheryButte( CItem * pButte, bool fSetup )
{
	ADDTOCALLSTACK("CChar::Use_Train_ArcheryButte");
	// IT_ARCHERY_BUTTE
	ASSERT(pButte);

	ITEMID_TYPE AmmoID;
	if ( GetDist(pButte) < 2 )		// if we are standing right next to the butte, retrieve the arrows/bolts
	{
		if ( pButte->m_itArcheryButte.m_AmmoCount == 0 )
		{
			SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_EMPTY);
			return true;
		}

		AmmoID = pButte->m_itArcheryButte.m_AmmoType;
		CItemBase *pAmmoDef = CItemBase::FindItemBase(AmmoID);
		if ( pAmmoDef )
		{
			TCHAR *pszMsg = Str_GetTemp();
			sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_REM), pAmmoDef->GetName(), (pButte->m_itArcheryButte.m_AmmoCount == 1) ? "" : g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_REMS));
			Emote(pszMsg);

			CItem *pRemovedAmmo = CItem::CreateBase(AmmoID);
			ASSERT(pRemovedAmmo);
			pRemovedAmmo->SetAmount(pButte->m_itArcheryButte.m_AmmoCount);
			ItemBounce(pRemovedAmmo);
		}

		// Clear the target
		pButte->m_itArcheryButte.m_AmmoType = ITEMID_NOTHING;
		pButte->m_itArcheryButte.m_AmmoCount = 0;
		return true;
	}

	SKILL_TYPE skill = Fight_GetWeaponSkill();
	if ( !g_Cfg.IsSkillFlag(skill, SKF_RANGED) )
	{
		SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_WS);
		return true;
	}
	if ( Skill_GetBase(skill) > g_Cfg.m_iSkillPracticeMax )
	{
		SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_SKILL);
		return true;
	}

	// Make sure we have some ammo
	CItem *pWeapon = m_uidWeapon.ItemFind();
	ASSERT(pWeapon);
	const CItemBase *pWeaponDef = pWeapon->Item_GetDef();

	// Determine ammo type
	CVarDefCont *pVarAmmoType = pWeapon->GetDefKey("AMMOTYPE", true);
	RESOURCE_ID_BASE rid;
	LPCTSTR t_Str;

	if ( pVarAmmoType )
	{
		t_Str = pVarAmmoType->GetValStr();
		rid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str));
	}
	else
	{
		rid = pWeaponDef->m_ttWeaponBow.m_idAmmo;
	}
	AmmoID = static_cast<ITEMID_TYPE>(rid.GetResIndex());

	// If there is a different ammo type on the butte currently, tell us to remove the current type first
	if ( (pButte->m_itArcheryButte.m_AmmoType != ITEMID_NOTHING) && (pButte->m_itArcheryButte.m_AmmoType != AmmoID) )
	{
		SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_X);
		return true;
	}

	// We need to be correctly aligned with the target before we can use it
	// For the south facing butte, we need to have the same X value and a Y > 2
	// For the east facing butte, we need to have the same Y value and an X > 2
	if ( !pButte->IsTopLevel() )
	{
	badalign:
		SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_P);
		return true;
	}

	int targDistX = GetTopPoint().m_x - pButte->GetTopPoint().m_x;
	int targDistY = GetTopPoint().m_y - pButte->GetTopPoint().m_y;

	if ( (pButte->GetID() == ITEMID_ARCHERYBUTTE_S) || (pButte->GetID() == ITEMID_MONGBATTARGET_S) )
	{
		if ( !(targDistX == 0 && targDistY > 2) )
			goto badalign;
	}
	else
	{
		if ( !(targDistY == 0 && targDistX > 2) )
			goto badalign;
	}

	if ( !CanSeeLOS(pButte, LOS_NB_WINDOWS) )	//we should be able to shoot through a window
	{
		SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_BLOCK);
		return true;
	}

	if ( fSetup )
	{
		if ( Skill_GetActive() == NPCACT_TRAINING )
			return true;
		UpdateAnimate(ANIM_ATTACK_WEAPON);
		m_Act_TargPrv = m_uidWeapon;
		m_Act_Targ = pButte->GetUID();
		Skill_Start(NPCACT_TRAINING);
		return true;
	}

	CVarDefCont *pCont = pWeapon->GetDefKey("AMMOCONT",true);

	if ( m_pPlayer && AmmoID )
	{
		int iFound = 1;
		if ( pCont )
		{
			//check for UID
			CGrayUID uidCont = static_cast<DWORD>(pCont->GetValNum());
			CItemContainer *pNewCont = dynamic_cast<CItemContainer*>(uidCont.ItemFind());
			if ( !pNewCont )	//if no UID, check for ITEMID_TYPE
			{
				t_Str = pCont->GetValStr();
				RESOURCE_ID_BASE rContid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str));
				ITEMID_TYPE ContID = static_cast<ITEMID_TYPE>(rContid.GetResIndex());
				if ( ContID )
					pNewCont = dynamic_cast<CItemContainer*>(ContentFind(rContid));
			}

			if ( pNewCont )
				iFound = pNewCont->ContentConsume(RESOURCE_ID(RES_ITEMDEF, AmmoID));
			else
				iFound = ContentConsume(RESOURCE_ID(RES_ITEMDEF, AmmoID));
		}
		else
			iFound = ContentConsume(RESOURCE_ID(RES_ITEMDEF, AmmoID));
		if ( iFound )
		{
			SysMessageDefault(DEFMSG_ITEMUSE_ARCHB_NOAMMO);
			return(true);
		}
	}

	// OK...go ahead and fire at the target
	// Check the skill
	bool fSuccess = Skill_UseQuick(skill, Calc_GetRandLLVal(40));

	// determine animation parameters
	CVarDefCont *pVarAnim = pWeapon->GetDefKey("AMMOANIM", true);
	CVarDefCont *pVarAnimColor = pWeapon->GetDefKey("AMMOANIMHUE", true);
	CVarDefCont *pVarAnimRender = pWeapon->GetDefKey("AMMOANIMRENDER", true);
	ITEMID_TYPE AmmoAnim;
	DWORD AmmoHue;
	DWORD AmmoRender;

	if ( pVarAnim )
	{
		t_Str = pVarAnim->GetValStr();
		rid = static_cast<RESOURCE_ID_BASE>(g_Cfg.ResourceGetID(RES_ITEMDEF, t_Str));
		AmmoAnim = static_cast<ITEMID_TYPE>(rid.GetResIndex());
	}
	else
		AmmoAnim = static_cast<ITEMID_TYPE>(pWeaponDef->m_ttWeaponBow.m_idAmmoX.GetResIndex());

	AmmoHue = pVarAnimColor ? static_cast<DWORD>(pVarAnimColor->GetValNum()) : 0;
	AmmoRender = pVarAnimRender ? static_cast<DWORD>(pVarAnimRender->GetValNum()) : 0;
	
	pButte->Effect(EFFECT_BOLT, AmmoAnim, this, 16, 0, false, AmmoHue, AmmoRender);
	pButte->Sound(0x224);

	// Did we destroy the ammo?
	const CItemBase *pAmmoDef = NULL;
	if ( AmmoID )
		pAmmoDef = CItemBase::FindItemBase(AmmoID);

	if ( !fSuccess )
	{
		// Small chance of destroying the ammo
		if ( pAmmoDef && !Calc_GetRandVal(10) )
		{
			TCHAR *pszMsg = Str_GetTemp();
			sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_DEST), pAmmoDef->GetName());
			Emote(pszMsg, NULL, true);
			return true;
		}

		static LPCTSTR const sm_Txt_ArcheryButte_Failure[] =
		{
			g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_MISS_1),
			g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_MISS_2),
			g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_MISS_3),
			g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_MISS_4)
		};
		Emote(sm_Txt_ArcheryButte_Failure[Calc_GetRandVal(COUNTOF(sm_Txt_ArcheryButte_Failure))]);
	}
	else
	{
		// Very small chance of destroying another arrow
		if ( pAmmoDef && !Calc_GetRandVal(50) && pButte->m_itArcheryButte.m_AmmoCount )
		{
			TCHAR *pszMsg = Str_GetTemp();
			sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_SPLIT), pAmmoDef->GetName());
			Emote(pszMsg, NULL, true);
			return true;
		}

		static LPCTSTR const sm_Txt_ArcheryButte_Success[] =
		{
			g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_HIT_1),
			g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_HIT_2),
			g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_HIT_3),
			g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_ARCHB_HIT_4)
		};
		Emote(sm_Txt_ArcheryButte_Success[Calc_GetRandVal(COUNTOF(sm_Txt_ArcheryButte_Success))]);
	}

	// Update the target
	if ( AmmoID )
	{
		pButte->m_itArcheryButte.m_AmmoType = AmmoID;
		pButte->m_itArcheryButte.m_AmmoCount++;
	}
	return true;
}