Example #1
0
void CItemSpawn::DelObj( CGrayUID uid )
{
	ADDTOCALLSTACK("CitemSpawn:DelObj");
	if ( !uid.IsValidUID() )
		return;
	for ( unsigned char i = 0; i < GetCount(); i++ )
	{
		if ( m_obj[i].IsValidUID() && m_obj[i] == uid )	// found this uid, proceeding to clear it
		{
			if (GetType() == IT_SPAWN_CHAR)	// IT_SPAWN_ITEM uses 'more2' to store how much items to spawn at once, so we must not touch it.
				m_itSpawnChar.m_current--;	// found this UID in the spawn's list, decreasing CChar's count only in this case
			while ( m_obj[i + 1].IsValidUID() )			// searching for any entry higher than this one...
			{
				m_obj[i] = m_obj[i + 1];	// and moving it 1 position to keep values 'together'.
				i++;
			}
			m_obj[i].InitUID();				// Finished moving higher entries (if any) so we free the last entry.
			break;
		}
	}
	if (uid.ItemFind())
		uid.ItemFind()->m_uidSpawnItem.InitUID();
	else if (uid.CharFind())
	{
		uid.CharFind()->m_uidSpawnItem.InitUID();
		uid.CharFind()->StatFlag_Clear(STATF_Spawned);
	}
}
Example #2
0
void CItemSpawn::AddObj( CGrayUID uid )
{
	ADDTOCALLSTACK("CitemSpawn:AddObj");
	unsigned char iMax = GetAmount() > 0 ? static_cast<unsigned char>(GetAmount()) : 1;
	bool bIsSpawnChar = GetType() == IT_SPAWN_CHAR;
	if (!uid)
		return;

	if ( bIsSpawnChar )
	{
		if ( !uid.CharFind()->m_pNPC)	// Only adding NPCs to IT_SPAWN_CHAR..
			return;
		if ( uid.CharFind()->m_uidSpawnItem.ItemFind() )	//... if they doesn't have a SpawnItem already.
			return;
	} else if( !uid.ItemFind() )		// Only adding Items to IT_SPAWN_ITEM
		return;

	for ( unsigned char i = 0; i < iMax; i++ )
	{
		if ( m_obj[i] == uid )	// Not adding me again
			return;
		if ( !m_obj[i].ObjFind() )
		{
			m_obj[i] = uid;
			if (bIsSpawnChar)
			{
				m_itSpawnChar.m_current++;
				uid.CharFind()->StatFlag_Set(STATF_Spawned);
			}
			uid.ObjFind()->m_uidSpawnItem = GetUID();
			break;
		}
	}
}
Example #3
0
void CItemSpawn::AddObj(CGrayUID uid)
{
	ADDTOCALLSTACK("CitemSpawn:AddObj");
	// NOTE: This function is also called when loading spawn items
	// on server startup. In this case, some objs UID still invalid
	// (not loaded yet) so just proceed without any checks.

	bool bIsSpawnChar = IsType(IT_SPAWN_CHAR);
	if ( !g_Serv.IsLoading() )
	{
		if ( !uid.IsValidUID() )
			return;

		if ( bIsSpawnChar )				// IT_SPAWN_CHAR can only spawn NPCs
		{
			CChar *pChar = uid.CharFind();
			if ( !pChar || !pChar->m_pNPC )
				return;
		}
		else if ( !uid.ItemFind() )		// IT_SPAWN_ITEM can only spawn items
			return;

		CItemSpawn *pPrevSpawn = static_cast<CItemSpawn*>(uid.ObjFind()->m_uidSpawnItem.ItemFind());
		if ( pPrevSpawn )
		{
			if ( pPrevSpawn == this )		// obj already linked to this spawn
				return;
			pPrevSpawn->DelObj(uid);		// obj linked to other spawn, remove the link before proceed
		}
	}

	BYTE iMax = maximum(GetAmount(), 1);
	for (BYTE i = 0; i < iMax; i++ )
	{
		if ( !m_obj[i].IsValidUID() )
		{
			m_obj[i] = uid;
			m_currentSpawned++;

			// objects are linked to the spawn at each server start
			if ( !g_Serv.IsLoading() )
			{
				uid.ObjFind()->m_uidSpawnItem = GetUID();
				if ( bIsSpawnChar )
				{
					CChar *pChar = uid.CharFind();
					ASSERT(pChar->m_pNPC);
					pChar->StatFlag_Set(STATF_Spawned);
					pChar->m_ptHome = GetTopPoint();
					pChar->m_pNPC->m_Home_Dist_Wander = static_cast<WORD>(m_itSpawnChar.m_DistMax);
				}
			}
			break;
		}
	}
	if ( !g_Serv.IsLoading() )
		ResendTooltip();
}
void CItemStone::WeDeclarePeace(CGrayUID uid, bool fForcePeace)
{
	ADDTOCALLSTACK("CItemStone::WeDeclarePeace");
	CItemStone * pEnemyStone = dynamic_cast <CItemStone*>( uid.ItemFind());
	if (!pEnemyStone)
		return;

	CStoneMember * pMember = GetMember(pEnemyStone);
	if ( ! pMember ) // No such member
		return;

	// Set my flags on the subject.
	if (!pMember->GetTheyDeclared() || fForcePeace) // If they're not at war with us, delete this record
		delete pMember;
	else
		pMember->SetWeDeclared(false);

	pEnemyStone->TheyDeclarePeace( this, fForcePeace );
}
Example #5
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;
}
bool CItemStone::r_WriteVal( LPCTSTR pszKey, CGString & sVal, CTextConsole * pSrc )
{
	ADDTOCALLSTACK("CItemStone::r_WriteVal");
	EXC_TRY("WriteVal");
	CChar * pCharSrc = pSrc->GetChar();

	if ( !strnicmp("member.",pszKey,7) )
	{
		LPCTSTR pszCmd = pszKey + 7;

		if ( !strnicmp("COUNT",pszCmd,5) )
		{
			pszCmd = pszCmd + 5;

			int i = 0;
			CStoneMember * pMember = STATIC_CAST <CStoneMember *>(GetHead());

			if ( *pszCmd )
			{
				SKIP_ARGSEP(pszCmd);
				STONEPRIV_TYPE iPriv = static_cast<STONEPRIV_TYPE>(Exp_GetVal(pszCmd));

				for (; pMember != NULL; pMember = pMember->GetNext())
				{
					if ( !pMember->GetLinkUID().IsChar() )
						continue;

					if ( pMember->GetPriv() != iPriv )
						continue;

					i++;
				}
			}
			else
			{
				for (; pMember != NULL; pMember = pMember->GetNext())
				{
					if (!pMember->GetLinkUID().IsChar()) 
						continue;

					i++;
				}
			}

			sVal.FormatVal(i);
			return true;
		}
		int nNumber = Exp_GetVal(pszCmd);
		SKIP_SEPARATORS(pszCmd);

		CStoneMember * pMember = STATIC_CAST <CStoneMember *>(GetHead());
		sVal.FormatVal(0);

		for ( int i = 0 ; pMember != NULL; pMember = pMember->GetNext() )
		{
			if (!pMember->GetLinkUID().IsChar()) 
				continue;
				
			if ( nNumber == i )
			{
				if (!pszCmd[0]) 
					return true;

				return pMember->r_WriteVal(pszCmd, sVal, pSrc);
			}

			i++;
		}

		return true;
	}
	else if ( !strnicmp("memberfromuid.", pszKey, 14) )
	{
		LPCTSTR pszCmd = pszKey + 14;
		sVal.FormatVal(0);

		if ( !pszCmd[0] )
			return true;

		CGrayUID pMemberUid = static_cast<DWORD>(Exp_GetVal(pszCmd));
		SKIP_SEPARATORS(pszCmd);

		CChar * pMemberChar = pMemberUid.CharFind();
		if ( pMemberChar )
		{
			CStoneMember * pMemberGuild = GetMember( pMemberChar );
			if ( pMemberGuild )
			{
				return pMemberGuild->r_WriteVal(pszCmd, sVal, pSrc);
			}
		}

		return true;
	}
	else if ( !strnicmp("guild.",pszKey,6) )
	{
		LPCTSTR pszCmd = pszKey + 6;

		if ( !strnicmp("COUNT",pszCmd,5) )
		{
			pszCmd = pszCmd + 5;

			int i = 0;
			CStoneMember * pMember = STATIC_CAST <CStoneMember *>(GetHead());

			if ( *pszCmd )
			{
				SKIP_ARGSEP(pszCmd);
				int iToCheck = Exp_GetVal(pszCmd);

				for (; pMember != NULL; pMember = pMember->GetNext())
				{
					if ( pMember->GetLinkUID().IsChar() )
						continue;

					if ( ( iToCheck == 1 ) && ( pMember->GetWeDeclared() && !pMember->GetTheyDeclared() ) )
						i++;
					else if ( ( iToCheck == 2 ) && ( !pMember->GetWeDeclared() && pMember->GetTheyDeclared() ) )
						i++;
					else if ( ( iToCheck == 3 ) && ( pMember->GetWeDeclared() && pMember->GetTheyDeclared() ) )
						i++;
				}
			}
			else
			{
				for (; pMember != NULL; pMember = pMember->GetNext())
				{
					if (pMember->GetLinkUID().IsChar()) 
						continue;

					i++;
				}
			}

			sVal.FormatVal(i);
			return true;
		}
		int nNumber = Exp_GetVal(pszCmd);
		SKIP_SEPARATORS(pszCmd);

		CStoneMember * pMember = STATIC_CAST <CStoneMember *>(GetHead());
		sVal.FormatVal(0);

		for ( int i = 0 ; pMember != NULL; pMember = pMember->GetNext() )
		{
			if (pMember->GetLinkUID().IsChar()) 
				continue;
				
			if ( nNumber == i )
			{
				if (!pszCmd[0]) 
					return true;

				return pMember->r_WriteVal(pszCmd, sVal, pSrc);
			}

			i++;
		}

		return true;
	}
	else if ( !strnicmp("guildfromuid.", pszKey, 13) )
	{
		LPCTSTR pszCmd = pszKey + 13;
		sVal.FormatVal(0);

		if ( !pszCmd[0] )
			return true;

		CGrayUID pGuildUid = static_cast<DWORD>(Exp_GetVal(pszCmd));
		SKIP_SEPARATORS(pszCmd);

		CItem * pMemberGuild = pGuildUid.ItemFind();
		if ( pMemberGuild )
		{
			CStoneMember * pGuild = GetMember( pMemberGuild );
			if ( pGuild )
			{
				return pGuild->r_WriteVal(pszCmd, sVal, pSrc);
			}
		}

		return true;
	}
	else if ( !strnicmp(sm_szLoadKeys[STC_CHARTER], pszKey, 7) )
	{
		LPCTSTR pszCmd = pszKey + 7;
		unsigned int i = ATOI(pszCmd);
		if ( i >= COUNTOF(m_sCharter))
			sVal = "";
		else
			sVal = m_sCharter[i];

		return( true );
	}


	STC_TYPE iIndex = (STC_TYPE) FindTableSorted( pszKey, sm_szLoadKeys, COUNTOF( sm_szLoadKeys )-1 );

	switch ( iIndex )
	{
		case STC_ABBREV: // "ABBREV"
			sVal = m_sAbbrev;
			return true;
		case STC_ALIGN:
			sVal.FormatVal( GetAlignType());
			return true;
		case STC_WEBPAGE: // "WEBPAGE"
			sVal = GetWebPageURL();
			return true;
		case STC_AbbreviationToggle:
			{
				CStoneMember * pMember = GetMember(pCharSrc);
				CVarDefCont * pResult = NULL;

				if ( pMember == NULL )
				{
					pResult = g_Exp.m_VarDefs.GetKey("STONECONFIG_VARIOUSNAME_NONMEMBER");
				}
				else
				{
					pResult = pMember->IsAbbrevOn() ? g_Exp.m_VarDefs.GetKey("STONECONFIG_VARIOUSNAME_ABBREVON") :
								g_Exp.m_VarDefs.GetKey("STONECONFIG_VARIOUSNAME_ABBREVOFF");
				}

				sVal = pResult ? pResult->GetValStr() : "";
			}
			return true;
		case STC_AlignType:
			sVal = GetAlignName();
			return true;

		case STC_LoyalTo:
			{
				CStoneMember * pMember = GetMember(pCharSrc);
				CVarDefCont * pResult = NULL;

				if ( pMember == NULL )
				{
					pResult = g_Exp.m_VarDefs.GetKey("STONECONFIG_VARIOUSNAME_NONMEMBER");
				}
				else
				{
					CChar * pLoyalTo = pMember->GetLoyalToUID().CharFind();
					if ((pLoyalTo == NULL) || (pLoyalTo == pCharSrc ))
					{
						pResult = g_Exp.m_VarDefs.GetKey("STONECONFIG_VARIOUSNAME_YOURSELF");
					}
					else
					{
						sVal = pLoyalTo->GetName();
						return true;
					}
				}

				sVal = pResult ? pResult->GetValStr() : "";
			}
			return( true );
	
		case STC_Master:
			{
				CChar * pMaster = GetMaster();
				sVal = (pMaster) ? pMaster->GetName() : g_Exp.m_VarDefs.GetKeyStr("STONECONFIG_VARIOUSNAME_PENDVOTE");
			}
			return( true );
	
		case STC_MasterGenderTitle:
			{
				CChar * pMaster = GetMaster();
				if ( pMaster == NULL )
					sVal = ""; // If no master (vote pending)
				else if ( pMaster->Char_GetDef()->IsFemale())
					sVal = g_Exp.m_VarDefs.GetKeyStr("STONECONFIG_VARIOUSNAME_MASTERGENDERFEMALE");
				else
					sVal = g_Exp.m_VarDefs.GetKeyStr("STONECONFIG_VARIOUSNAME_MASTERGENDERMALE");
			}
			return( true );
	
		case STC_MasterTitle:
			{
				CStoneMember * pMember = GetMasterMember();
				sVal = (pMember) ? pMember->GetTitle() : "";
			}
			return( true );
	
		case STC_MasterUid:
			{
				CChar * pMaster = GetMaster();
				if ( pMaster )
					sVal.FormatHex( (DWORD) pMaster->GetUID() );
				else
					sVal.FormatHex( (DWORD) 0 );
			}
			return( true );
			
		default:
			return( CItem::r_WriteVal( pszKey, sVal, pSrc ));
	}

	EXC_CATCH;

	EXC_DEBUG_START;
	EXC_ADD_KEYRET(pSrc);
	EXC_DEBUG_END;
	return false;
}
bool CItemStone::r_GetRef( LPCTSTR & pszKey, CScriptObj * & pRef )
{
	ADDTOCALLSTACK("CItemStone::r_GetRef");
	if ( !strnicmp("member.", pszKey, 7) )
	{
		pszKey = pszKey + 7;
		if ( !pszKey[0] )
			return false;

		int nNumber = Exp_GetVal(pszKey);
		SKIP_SEPARATORS(pszKey);

		CStoneMember * pMember = STATIC_CAST <CStoneMember *>(GetHead());

		for ( int i = 0; pMember != NULL; pMember = pMember->GetNext() )
		{
			if ( !pMember->GetLinkUID().IsChar() ) 
				continue;

			if ( nNumber == i )
			{
				pRef = pMember; 
				return true;
			}

			i++;
		}
	}
	else if ( !strnicmp("memberfromuid.", pszKey, 14) )
	{
		pszKey = pszKey + 14;
		if ( !pszKey[0] )
			return false;

		CGrayUID pMemberUid = static_cast<DWORD>(Exp_GetVal(pszKey));
		SKIP_SEPARATORS(pszKey);

		CChar * pMemberChar = pMemberUid.CharFind();
		if ( pMemberChar )
		{
			CStoneMember * pMemberGuild = GetMember( pMemberChar );
			if ( pMemberGuild )
			{
				pRef = pMemberGuild; 
				return true;
			}
		}
	}
	else if ( !strnicmp("guild.", pszKey, 6) )
	{
		pszKey = pszKey + 6;
		if ( !pszKey[0] )
			return false;

		int nNumber = Exp_GetVal(pszKey);
		SKIP_SEPARATORS(pszKey);

		CStoneMember * pMember = STATIC_CAST <CStoneMember *>(GetHead());

		for ( int i = 0; pMember != NULL; pMember = pMember->GetNext() )
		{
			if ( pMember->GetLinkUID().IsChar() ) 
				continue;

			if ( nNumber == i )
			{
				pRef = pMember;
				return true;
			}

			i++;
		}
	}
	else if ( !strnicmp("guildfromuid.", pszKey, 13) )
	{
		pszKey = pszKey + 13;
		if ( !pszKey[0] )
			return false;

		CGrayUID pGuildUid = static_cast<DWORD>(Exp_GetVal(pszKey));
		SKIP_SEPARATORS(pszKey);

		CItem * pMemberGuild = pGuildUid.ItemFind();
		if ( pMemberGuild )
		{
			CStoneMember * pGuild = GetMember( pMemberGuild );
			if ( pGuild )
			{
				pRef = pGuild; 
				return true;
			}
		}
	}

	return CItem::r_GetRef( pszKey, pRef );
}
bool CItemStone::r_Verb( CScript & s, CTextConsole * pSrc ) // Execute command from script
{
	ADDTOCALLSTACK("CItemStone::r_Verb");
	EXC_TRY("Verb");
	// NOTE:: ONLY CALL this from CChar::r_Verb !!!
	// Little to no security checking here !!!

	ASSERT(pSrc);

	int index = FindTableSorted( s.GetKey(), sm_szVerbKeys, COUNTOF(sm_szVerbKeys)-1 );
	if ( index < 0 )
	{
		return( CItem::r_Verb( s, pSrc ));
	}

	CChar * pCharSrc = pSrc->GetChar();
	CStoneMember * pMember = GetMember(pCharSrc);

	switch ( index )
	{
		case ISV_ALLGUILDS:
			{
				if ( s.HasArgs() )
				{
					TCHAR * pszArgs = s.GetArgRaw();
					int iFlags = Exp_GetVal(pszArgs);
					SKIP_ARGSEP(pszArgs);

					if ( iFlags < 0 )
					{
						g_Log.EventError("ItemStone::AllGuilds invalid parameter '%i'.\n", iFlags);
						return false;
					}
					else
					{
						if ( pszArgs[0] != '\0' )
						{
							pMember = STATIC_CAST <CStoneMember *>(GetHead());
							CScript scriptVerb( pszArgs );

							for (; pMember != NULL; pMember = pMember->GetNext())
							{
								if ( pMember->GetLinkUID().IsChar() )
									continue;

								if ( !iFlags )
								{
									pMember->r_Verb(scriptVerb, pSrc);
								}
								else if ( ( iFlags == 1 ) && ( pMember->GetWeDeclared() && !pMember->GetTheyDeclared() ) )
								{
									pMember->r_Verb(scriptVerb, pSrc);
								}
								else if ( ( iFlags == 2 ) && ( !pMember->GetWeDeclared() && pMember->GetTheyDeclared() ) )
								{
									pMember->r_Verb(scriptVerb, pSrc);
								}
								else if ( ( iFlags == 3 ) && ( pMember->GetWeDeclared() && pMember->GetTheyDeclared() ) )
								{
									pMember->r_Verb(scriptVerb, pSrc);
								}
							}
						}
						else
						{
							g_Log.EventError("ItemStone::AllGuilds empty args.\n");
							return false;
						}
					}
				}
			}
			break;
		case ISV_ALLMEMBERS:
			{
				if ( s.HasArgs() )
				{
					TCHAR * pszArgs = s.GetArgRaw();
					int iFlags = Exp_GetVal(pszArgs);
					SKIP_ARGSEP(pszArgs);

					if (( iFlags < -1 ) || ( iFlags > STONEPRIV_ACCEPTED ))
					{
						g_Log.EventError("ItemStone::AllMembers invalid parameter '%i'.\n", iFlags);
						return false;
					}
					else
					{
						if ( pszArgs[0] != '\0' )
						{
							pMember = STATIC_CAST <CStoneMember *>(GetHead());
							CScript scriptVerb( pszArgs );

							for (; pMember != NULL; pMember = pMember->GetNext())
							{
								if ( !pMember->GetLinkUID().IsChar() )
									continue;

								if ( iFlags == -1 )
								{
									pMember->r_Verb(scriptVerb, pSrc);
								}
								else if ( pMember->GetPriv() == static_cast<STONEPRIV_TYPE>(iFlags) )
								{
									pMember->r_Verb(scriptVerb, pSrc);
								}
							}
						}
						else
						{
							g_Log.EventError("ItemStone::AllMembers empty args.\n");
							return false;
						}
					}
				}
			}
			break;
		case ISV_APPLYTOJOIN:
			if ( s.HasArgs())
			{
				CGrayUID pMemberUid = s.GetArgVal();
				CChar * pMemberChar = pMemberUid.CharFind();
				if ( pMemberChar )
				{
					AddRecruit( pMemberChar, STONEPRIV_CANDIDATE );
				}
			}
			break;
		case ISV_CHANGEALIGN:
			if ( s.HasArgs())
			{
				SetAlignType(static_cast<STONEALIGN_TYPE>(s.GetArgVal()));
				TCHAR *pszMsg = Str_GetTemp();
				sprintf(pszMsg, "%s is now a %s %s\n", static_cast<LPCTSTR>(GetName()), static_cast<LPCTSTR>(GetAlignName()), static_cast<LPCTSTR>(GetTypeName()));
				Speak(pszMsg);
			}
			break;
		case ISV_DECLAREPEACE:
			if ( s.HasArgs())
			{
				CGrayUID pMemberUid = s.GetArgVal();
				WeDeclarePeace(pMemberUid);
			}
			break;
		case ISV_DECLAREWAR:
			if ( s.HasArgs())
			{
				CGrayUID pMemberUid = s.GetArgVal();
				CItem * pEnemyItem = pMemberUid.ItemFind();
				if ( pEnemyItem )
				{
					CItemStone * pNewEnemy = dynamic_cast<CItemStone*>(pEnemyItem);
					if ( pNewEnemy )
					{
						WeDeclareWar(pNewEnemy);
					}
				}
			}
			break;
		case ISV_ELECTMASTER:
			ElectMaster();
			break;
		// Need to change FixWeirdness or rewrite how cstonemember guilds are handled.
		case ISV_INVITEWAR:
			{
				if ( s.HasArgs() )
				{
					INT64 piCmd[2];
					size_t iArgQty = Str_ParseCmds( s.GetArgStr(), piCmd, COUNTOF(piCmd));
					if ( iArgQty == 2 )
					{
						CGrayUID pGuildUid = static_cast<unsigned long>(piCmd[0]);
						bool bWeDeclared = (piCmd[1] != 0);
						CItem * pEnemyItem = pGuildUid.ItemFind();
						if ( pEnemyItem && (pEnemyItem->IsType(IT_STONE_GUILD) || pEnemyItem->IsType(IT_STONE_TOWN)) )
						{
							CStoneMember * pMemberGuild = GetMember( pEnemyItem );
							if ( !pMemberGuild )
								pMemberGuild = new CStoneMember(this, pGuildUid, STONEPRIV_ENEMY);

							if ( bWeDeclared )
								pMemberGuild->SetWeDeclared(true);
							else
								pMemberGuild->SetTheyDeclared(true);
						}
					}
				}
			} break;
		case ISV_JOINASMEMBER:
			if ( s.HasArgs())
			{
				CGrayUID pMemberUid = s.GetArgVal();
				CChar * pMemberChar = pMemberUid.CharFind();
				if ( pMemberChar )
				{
					AddRecruit( pMemberChar, STONEPRIV_MEMBER );
				}
			}
			break;
		case ISV_RESIGN:
			if ( s.HasArgs())
			{
				CGrayUID pMemberUid = s.GetArgVal();
				CChar * pMemberChar = pMemberUid.CharFind();
				if ( pMemberChar )
				{
					CStoneMember * pMemberGuild = GetMember( pMemberChar );
					if ( pMemberGuild )
					{
						delete pMemberGuild;
					}
				}
			}
			else
			{
				if ( pMember != NULL )
					delete pMember;
			}
			break;
		case ISV_TOGGLEABBREVIATION:
			{
				CGrayUID pMemberUid = pMember->GetLinkUID();
				if ( s.HasArgs() )
					pMemberUid = s.GetArgVal();
				CChar * pMemberChar = pMemberUid.CharFind();
				if ( pMemberChar )
				{
					CStoneMember * pMemberGuild = GetMember( pMemberChar );
					if ( pMemberGuild )
					{
						pMemberGuild->ToggleAbbrev();
						pMemberChar->ResendTooltip();
					}
				}
			}
			break;
		default:
			return( false );
	}
	return true;
	EXC_CATCH;

	EXC_DEBUG_START;
	EXC_ADD_SCRIPTSRC;
	EXC_DEBUG_END;
	return false;
}
Example #9
0
bool CClient::r_Verb( CScript & s, CTextConsole * pSrc ) // Execute command from script
{
	ADDTOCALLSTACK("CClient::r_Verb");
	EXC_TRY("Verb");
	// NOTE: This can be called directly from a RES_WEBPAGE script.
	//  So do not assume we are a game client !
	// NOTE: Mostly called from CChar::r_Verb
	// NOTE: Little security here so watch out for dangerous scripts !

	ASSERT(pSrc);
	LPCTSTR pszKey = s.GetKey();

	// Old ver
	if ( s.IsKeyHead("SET", 3) && !g_Cfg.m_Functions.ContainsKey(pszKey) )
	{
		PLEVEL_TYPE ilevel = g_Cfg.GetPrivCommandLevel("SET");
		if ( ilevel > GetPrivLevel() )
			return false;

		ASSERT(m_pChar);
		addTargetVerb(pszKey + 3, s.GetArgRaw());
		return true;
	}

	if ( (toupper(pszKey[0]) == 'X') && !g_Cfg.m_Functions.ContainsKey(pszKey) )
	{
		PLEVEL_TYPE ilevel = g_Cfg.GetPrivCommandLevel("SET");
		if ( ilevel > GetPrivLevel() )
			return false;

		// Target this command verb on some other object.
		ASSERT(m_pChar);
		addTargetVerb(pszKey + 1, s.GetArgRaw());
		return true;
	}

	int index = FindTableSorted(s.GetKey(), sm_szVerbKeys, COUNTOF(sm_szVerbKeys) - 1);
	switch ( index )
	{
		case CV_ADD:
			if ( s.HasArgs() )
			{
				TCHAR *ppArgs[2];
				size_t iQty = Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));

				if ( !IsValidGameObjDef(static_cast<LPCTSTR>(ppArgs[0])) )
				{
					g_Log.EventWarn("Invalid ADD argument '%s'\n", ppArgs[0]);
					SysMessageDefault(DEFMSG_CMD_INVALID);
					return true;
				}

				RESOURCE_ID rid = g_Cfg.ResourceGetID(RES_QTY, const_cast<LPCTSTR &>(ppArgs[0]));
				m_tmAdd.m_id = rid.GetResIndex();
				m_tmAdd.m_amount = (iQty > 1) ? static_cast<WORD>(maximum(ATOI(ppArgs[1]), 1)) : 1;

				if ( (rid.GetResType() == RES_CHARDEF) || (rid.GetResType() == RES_SPAWN) )
				{
					m_Targ_PrvUID.InitUID();
					return addTargetChars(CLIMODE_TARG_ADDCHAR, static_cast<CREID_TYPE>(m_tmAdd.m_id), false);
				}
				else
				{
					return addTargetItems(CLIMODE_TARG_ADDITEM, static_cast<ITEMID_TYPE>(m_tmAdd.m_id));
				}
			}
			else
			{
				if ( IsValidDef("d_add") )
					Dialog_Setup(CLIMODE_DIALOG, g_Cfg.ResourceGetIDType(RES_DIALOG, "d_add"), 0, m_pChar);
				else
					Menu_Setup(g_Cfg.ResourceGetIDType(RES_MENU, "MENU_ADDITEM"));
			}
			break;
		case CV_ADDBUFF:
		{
			TCHAR *ppArgs[11];
			Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));

			int iArgs[4];
			for ( int idx = 0; idx < 4; ++idx )
			{
				if ( !IsStrNumeric(ppArgs[idx]) )
				{
					DEBUG_ERR(("Invalid AddBuff argument number %u\n", idx + 1));
					return true;
				}
				iArgs[idx] = Exp_GetVal(ppArgs[idx]);
			}
			if ( (iArgs[0] < BI_START) || (iArgs[0] > BI_QTY) )
			{
				DEBUG_ERR(("Invalid AddBuff icon ID\n"));
				break;
			}

			LPCTSTR Args[7];
			size_t ArgsCount = 0;
			for ( int i = 0; i < 7; ++i )
			{
				Args[i] = ppArgs[i + 4];
				if ( Args[i] != NULL )
					ArgsCount++;
			}

			addBuff(static_cast<BUFF_ICONS>(iArgs[0]), iArgs[1], iArgs[2], static_cast<WORD>(iArgs[3]), Args, ArgsCount);
			break;
		}
		case CV_REMOVEBUFF:
		{
			BUFF_ICONS IconId = static_cast<BUFF_ICONS>(s.GetArgVal());
			if ( (IconId < BI_START) || (IconId > BI_QTY) )
			{
				DEBUG_ERR(("Invalid RemoveBuff icon ID\n"));
				break;
			}
			removeBuff(IconId);
			break;
		}
		case CV_ADDCLILOC:		// add cliloc in @ClientTooltip trigger
		{
			TCHAR *ppLocArgs[256];
			size_t qty = Str_ParseCmds(s.GetArgRaw(), ppLocArgs, COUNTOF(ppLocArgs), ",");
			DWORD clilocid = Exp_GetVal(ppLocArgs[0]);

			CGString LocArgs;
			for ( size_t y = 1; y < qty; y++ )
			{
				if ( LocArgs.GetLength() )
					LocArgs += "\t";
				LocArgs += (!strcmp(ppLocArgs[y], "NULL") ? " " : ppLocArgs[y]);
			}

			if ( g_Cfg.m_wDebugFlags & DEBUGF_SCRIPTS )
				g_Log.EventDebug("SCRIPT: addcliloc(%lu,'%s')\n", clilocid, static_cast<LPCTSTR>(LocArgs));
			m_TooltipData.Add(new CClientTooltip(clilocid, LocArgs));
			break;
		}
		case CV_ADDCONTEXTENTRY:
		{
			TCHAR *ppLocArgs[20];
			if ( Str_ParseCmds(s.GetArgRaw(), ppLocArgs, COUNTOF(ppLocArgs), ",") > 4 )
			{
				DEBUG_ERR(("Bad AddContextEntry usage: Function takes maximum of 4 arguments!\n"));
				return true;
			}
			if ( m_pPopupPacket == NULL )
			{
				DEBUG_ERR(("Bad AddContextEntry usage: Not used under a @ContextMenuRequest/@itemContextMenuRequest trigger!\n"));
				return true;
			}

			for ( int i = 0; i < 4; i++ )
			{
				if ( (i > 1) && IsStrEmpty(ppLocArgs[i]) )
					continue;

				if ( !IsStrNumeric(ppLocArgs[i]) )
				{
					DEBUG_ERR(("Bad AddContextEntry usage: Argument %d must be a number!\n", i + 1));
					return true;
				}
			}

			int entrytag = Exp_GetVal(ppLocArgs[0]);
			if ( entrytag < 100 )
			{
				DEBUG_ERR(("Bad AddContextEntry usage: TextEntry < 100 is reserved for server usage!\n"));
				return true;
			}
			m_pPopupPacket->addOption(static_cast<WORD>(entrytag), static_cast<DWORD>(Exp_GetVal(ppLocArgs[1])), static_cast<WORD>(Exp_GetVal(ppLocArgs[2])), static_cast<WORD>(Exp_GetVal(ppLocArgs[3])));
			break;
		}
		case CV_ARROWQUEST:
		{
			INT64 piVal[3];
			Str_ParseCmds(s.GetArgRaw(), piVal, COUNTOF(piVal));
			addArrowQuest(static_cast<WORD>(piVal[0]), static_cast<WORD>(piVal[1]), static_cast<DWORD>(piVal[2]));
#ifdef _ALPHASPHERE
			// todo: should use a proper container for these, since the arrows are lost
			// when the client logs out, and also newer clients support multiple arrows
			if ( piVal[0] && piVal[1] && m_pChar )
			{
				m_pChar->SetKeyNum("ARROWQUEST_X", piVal[0]);
				m_pChar->SetKeyNum("ARROWQUEST_Y", piVal[1]);
			}
			else {
				m_pChar->DeleteKey("ARROWQUEST_X");
				m_pChar->DeleteKey("ARROWQUEST_Y");
			}
#endif
			break;
		}
		case CV_BADSPAWN:
		{
			// Loop the world searching for bad spawns
			bool bFound = false;
			for ( int m = 0; (m < 256) && !bFound; m++ )
			{
				if ( !g_MapList.m_maps[m] )
					continue;

				for ( int d = 0; (d < g_MapList.GetSectorQty(m)) && !bFound; d++ )
				{
					CSector *pSector = g_World.GetSector(m, d);
					if ( !pSector )
						continue;

					CItem *pItem = static_cast<CItem *>(pSector->m_Items_Inert.GetHead());
					for ( ; (pItem != NULL) && !bFound; pItem = pItem->GetNext() )
					{
						if ( pItem->IsType(IT_SPAWN_ITEM) || pItem->IsType(IT_SPAWN_CHAR) )
						{
							CItemSpawn *pSpawn = static_cast<CItemSpawn *>(pItem);
							CResourceDef *pDef = pSpawn->FixDef();
							if ( !pDef )
							{
								RESOURCE_ID_BASE rid = pItem->IsType(IT_SPAWN_ITEM) ? pItem->m_itSpawnItem.m_ItemID : pItem->m_itSpawnChar.m_CharID;
								CPointMap pt = pItem->GetTopPoint();
								m_pChar->Spell_Teleport(pt, true, false);
								m_pChar->m_Act_Targ = pItem->GetUID();
								SysMessagef("Bad spawn (0%lx, id=%s). Set as ACT", static_cast<DWORD>(pItem->GetUID()), g_Cfg.ResourceGetName(rid));
								bFound = true;
							}
						}
					}
				}
			}
			if ( !bFound )
				SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_NO_BAD_SPAWNS));
			break;
		}
		case CV_BANKSELF:
		{
			addBankOpen(m_pChar, LAYER_BANKBOX);
			break;
		}
		case CV_CAST:
		{
			SPELL_TYPE spell = static_cast<SPELL_TYPE>(g_Cfg.ResourceGetIndexType(RES_SPELL, s.GetArgStr()));
			const CSpellDef *pSpellDef = g_Cfg.GetSpellDef(spell);
			if ( !pSpellDef )
				return true;

			CObjBase *pObjSrc = dynamic_cast<CObjBase *>(pSrc);
			if ( IsSetMagicFlags(MAGICF_PRECAST) && !pSpellDef->IsSpellType(SPELLFLAG_NOPRECAST) )
			{
				int skill;
				if ( !pSpellDef->GetPrimarySkill(&skill, NULL) )
					return true;

				m_tmSkillMagery.m_Spell = spell;	// m_atMagery.m_Spell
				m_pChar->m_atMagery.m_Spell = spell;
				if ( pObjSrc )
				{
					m_Targ_UID = pObjSrc->GetUID();	// default target.
					m_Targ_PrvUID = pObjSrc->GetUID();
				}
				else
				{
					m_Targ_UID.ClearUID();
					m_Targ_PrvUID.ClearUID();
				}
				m_pChar->Skill_Start(static_cast<SKILL_TYPE>(skill));
				break;
			}
			else
				Cmd_Skill_Magery(spell, pObjSrc);
			break;
		}
		case CV_CHARLIST:		// usually just a gm command
		{
			new PacketChangeCharacter(this);

			CharDisconnect();	// since there is no undoing this in the client.
			SetTargMode(CLIMODE_SETUP_CHARLIST);
			break;
		}
		case CV_CTAGLIST:
		{
			if ( !strcmpi(s.GetArgStr(), "log") )
				pSrc = &g_Serv;
			m_TagDefs.DumpKeys(pSrc, "CTAG.");
			break;
		}
		case CV_CLEARCTAGS:
		{
			if ( s.HasArgs() )
			{
				LPCTSTR pszArgs = s.GetArgStr();
				SKIP_SEPARATORS(pszArgs);
				m_TagDefs.ClearKeys(pszArgs);
			}
			else
				m_TagDefs.ClearKeys();
			break;
		}
		case CV_CLOSEPAPERDOLL:
		{
			CChar *pChar = m_pChar;
			if ( s.HasArgs() )
			{
				CGrayUID uid = static_cast<CGrayUID>(s.GetArgVal());
				pChar = uid.CharFind();
			}
			if ( pChar )
				closeUIWindow(pChar, 0x1);
			break;
		}
		case CV_CLOSEPROFILE:
		{
			CChar *pChar = m_pChar;
			if ( s.HasArgs() )
			{
				CGrayUID uid = static_cast<CGrayUID>(s.GetArgVal());
				pChar = uid.CharFind();
			}
			if ( pChar )
				closeUIWindow(pChar, 0x8);
			break;
		}
		case CV_CLOSESTATUS:
		{
			CChar *pChar = m_pChar;
			if ( s.HasArgs() )
			{
				CGrayUID uid = static_cast<CGrayUID>(s.GetArgVal());
				pChar = uid.CharFind();
			}
			if ( pChar )
				closeUIWindow(pChar, 0x2);
			break;
		}
		case CV_DYE:
		{
			if ( s.HasArgs() )
			{
				CGrayUID uid = static_cast<CGrayUID>(s.GetArgVal());
				CObjBase *pObj = uid.ObjFind();
				if ( pObj )
					addDyeOption(pObj);
			}
			break;
		}
		case CV_EVERBTARG:
		{
			m_Prompt_Text = s.GetArgStr();
			addPromptConsole(CLIMODE_PROMPT_TARG_VERB, m_Targ_Text.IsEmpty() ? "Enter the verb" : "Enter the text", m_Targ_UID);
			break;
		}
		case CV_EXTRACT:
		{
			// sort of like EXPORT but for statics.
			// Opposite of the "UNEXTRACT" command
			if ( !s.HasArgs() )
			{
				SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_EXTRACT_USAGE));
			}
			else
			{
				TCHAR *ppArgs[2];
				Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));

				m_Targ_Text = ppArgs[0];				// point at the options (if any)
				m_tmTile.m_ptFirst.InitPoint();			// clear this first
				m_tmTile.m_Code = CV_EXTRACT;			// set extract code
				m_tmTile.m_id = Exp_GetVal(ppArgs[1]);	// extract id
				addTarget(CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_EXTRACT_AREA), true);
			}
			break;
		}
		case CV_UNEXTRACT:
		{
			// Create item from script.
			// Opposite of the "EXTRACT" command
			if ( !s.HasArgs() )
			{
				SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_UNEXTRACT_USAGE));
			}
			else
			{
				TCHAR *ppArgs[2];
				Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));

				m_Targ_Text = ppArgs[0];				// point at the options (if any)
				m_tmTile.m_ptFirst.InitPoint();			// clear this first
				m_tmTile.m_Code = CV_UNEXTRACT;			// set extract code
				m_tmTile.m_id = Exp_GetVal(ppArgs[1]);	// extract id
				addTarget(CLIMODE_TARG_UNEXTRACT, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_MULTI_POS), true);
			}
			break;
		}
		case CV_GMPAGE:
		{
			m_Targ_Text = s.GetArgStr();
			if ( !m_Targ_Text.IsEmpty() && !strnicmp(m_Targ_Text, "ADD ", 4) )
			{
				Cmd_GM_Page(m_Targ_Text + 4);
				break;
			}
			addPromptConsole(CLIMODE_PROMPT_GM_PAGE_TEXT, g_Cfg.GetDefaultMsg(DEFMSG_GMPAGE_PROMPT));
			break;
		}
		case CV_GOTARG:		// go to my (preselected) target.
		{
			ASSERT(m_pChar);
			CObjBase *pObj = m_Targ_UID.ObjFind();
			if ( pObj )
			{
				CPointMap pt = pObj->GetTopLevelObj()->GetTopPoint();
				m_pChar->m_dirFace = m_pChar->GetDir(pObj, m_pChar->m_dirFace);
				m_pChar->Spell_Teleport(pt, true, false);
			}
			break;
		}
		case CV_INFO:
		{
			// We could also get ground tile info.
			addTarget(CLIMODE_TARG_OBJ_INFO, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_ITEM_INFO), true, false);
			break;
		}
		case CV_INFORMATION:
		{
			SysMessage(g_Serv.GetStatusString(0x22));
			SysMessage(g_Serv.GetStatusString(0x24));
			break;
		}
		case CV_LAST:	// fake previous target
		{
			if ( GetTargMode() >= CLIMODE_MOUSE_TYPE )
			{
				ASSERT(m_pChar);
				CObjBase *pObj = m_pChar->m_Act_Targ.ObjFind();
				if ( pObj )
				{
					Event_Target(GetTargMode(), pObj->GetUID(), pObj->GetTopPoint());
					addTargetCancel();
				}
				break;
			}
			return false;
		}
		case CV_LINK:	// link doors
		{
			m_Targ_UID.InitUID();
			addTarget(CLIMODE_TARG_LINK, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_LINK_ITEM));
			break;
		}
		case CV_MENU:
		{
			Menu_Setup(g_Cfg.ResourceGetIDType(RES_MENU, s.GetArgStr()));
			break;
		}
		case CV_MIDILIST:
		{
			INT64 piMidi[64];
			size_t iQty = Str_ParseCmds(s.GetArgStr(), piMidi, COUNTOF(piMidi));
			if ( iQty > 0 )
				addMusic(static_cast<MIDI_TYPE>(piMidi[Calc_GetRandVal(iQty)]));
			break;
		}
		case CV_NUDGE:
		{
			if ( !s.HasArgs() )
			{
				SysMessage("Usage: NUDGE dx dy dz");
			}
			else
			{
				m_Targ_Text = s.GetArgRaw();
				m_tmTile.m_ptFirst.InitPoint();		// clear this first
				m_tmTile.m_Code = CV_NUDGE;
				addTarget(CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_NUDGE_AREA), true);
			}
			break;
		}
		case CV_NUKE:
		{
			m_Targ_Text = s.GetArgRaw();
			m_tmTile.m_ptFirst.InitPoint();		// clear this first
			m_tmTile.m_Code = CV_NUKE;			// set nuke code
			addTarget(CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_NUKE_AREA), true);
			break;
		}
		case CV_NUKECHAR:
		{
			m_Targ_Text = s.GetArgRaw();
			m_tmTile.m_ptFirst.InitPoint();		// clear this first
			m_tmTile.m_Code = CV_NUKECHAR;		// set nuke code
			addTarget(CLIMODE_TARG_TILE, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_NUKE_CHAR_AREA), true);
			break;
		}
		case CV_OPENPAPERDOLL:
		{
			CChar *pChar = m_pChar;
			if ( s.HasArgs() )
			{
				CGrayUID uid = static_cast<CGrayUID>(s.GetArgVal());
				pChar = uid.CharFind();
			}
			if ( pChar )
				addCharPaperdoll(pChar);
			break;
		}
		case CV_OPENTRADEWINDOW:
		{
			TCHAR *ppArgs[2];
			Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));

			CChar *pChar = NULL;
			CItem *pItem = NULL;
			if ( ppArgs[0] )
			{
				CGrayUID uidChar = static_cast<CGrayUID>(Exp_GetVal(ppArgs[0]));
				pChar = uidChar.CharFind();
			}
			if ( ppArgs[1] )
			{
				CGrayUID uidItem = static_cast<CGrayUID>(Exp_GetVal(ppArgs[1]));
				pItem = uidItem.ItemFind();
			}
			if ( pChar )
				Cmd_SecureTrade(pChar, pItem);
			break;
		}
		case CV_PAGE:
			Cmd_GM_PageCmd(s.GetArgStr());
			break;
		case CV_REPAIR:
			addTarget(CLIMODE_TARG_REPAIR, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_ITEM_REPAIR));
			break;
		case CV_FLUSH:
#ifndef _MTNETWORK
			g_NetworkOut.flush(this);
#else
			g_NetworkManager.flush(m_NetState);
#endif
			break;
		case CV_RESEND:
			addReSync();
			break;
		case CV_SAVE:
			g_World.Save(s.GetArgVal() != 0);
			break;
		case CV_SCROLL:
			// put a scroll up.
			addScrollResource(s.GetArgStr(), SCROLL_TYPE_UPDATES);
			break;
		case CV_SENDPACKET:
			SendPacket(s.GetArgStr());
			break;
		case CV_SELF:		// fake self target
			if ( GetTargMode() >= CLIMODE_MOUSE_TYPE )
			{
				ASSERT(m_pChar);
				Event_Target(GetTargMode(), m_pChar->GetUID(), m_pChar->GetTopPoint());
				addTargetCancel();
				break;
			}
			return false;
		case CV_SHOWSKILLS:
			addSkillWindow(static_cast<SKILL_TYPE>(g_Cfg.m_iMaxSkill));		// reload the real skills
			break;
		case CV_SKILLMENU:
			Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, s.GetArgStr()));
			break;
		case CV_SKILLSELECT:
			Event_Skill_Use(g_Cfg.FindSkillKey(s.GetArgStr()));
			break;
		case CV_SUMMON:
		{
			ASSERT(m_pChar);
			const CSpellDef *pSpellDef = g_Cfg.GetSpellDef(SPELL_Summon);
			if ( !pSpellDef )
				return false;

			m_pChar->m_Act_Targ = m_pChar->GetUID();
			m_pChar->m_Act_TargPrv = m_pChar->GetUID();

			if ( pSpellDef->IsSpellType(SPELLFLAG_TARG_OBJ | SPELLFLAG_TARG_XYZ) )
			{
				m_tmSkillMagery.m_Spell = SPELL_Summon;
				m_tmSkillMagery.m_SummonID = static_cast<CREID_TYPE>(g_Cfg.ResourceGetIndexType(RES_CHARDEF, s.GetArgStr()));

				LPCTSTR pPrompt = g_Cfg.GetDefaultMsg(DEFMSG_SELECT_MAGIC_TARGET);
				if ( !pSpellDef->m_sTargetPrompt.IsEmpty() )
					pPrompt = pSpellDef->m_sTargetPrompt;

				int SpellTimeout = static_cast<int>(GetDefNum("SPELLTIMEOUT"));
				if ( !SpellTimeout )
					SpellTimeout = g_Cfg.m_iSpellTimeout * TICK_PER_SEC;

				addTarget(CLIMODE_TARG_SKILL_MAGERY, pPrompt, pSpellDef->IsSpellType(SPELLFLAG_TARG_XYZ), pSpellDef->IsSpellType(SPELLFLAG_HARM), SpellTimeout);
				break;
			}
			else
			{
				m_pChar->m_atMagery.m_Spell = SPELL_Summon;
				m_pChar->m_atMagery.m_SummonID = static_cast<CREID_TYPE>(g_Cfg.ResourceGetIndexType(RES_CHARDEF, s.GetArgStr()));

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

					m_pChar->Skill_Start(static_cast<SKILL_TYPE>(skill));
				}
			}
			break;
		}
		case CV_SMSG:
		case CV_SYSMESSAGE:
			SysMessage(s.GetArgStr());
			break;
		case CV_SYSMESSAGEF:	// there is still an issue with numbers not resolving properly when %i,%d,or other numeric format code is in use
		{
			TCHAR *pszArgs[4];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), pszArgs, COUNTOF(pszArgs));
			if ( iArgQty < 2 )
			{
				g_Log.EventError("SysMessagef with less than 1 args for the given text\n");
				return false;
			}
			if ( iArgQty > 4 )
			{
				g_Log.EventError("Too many arguments given to SysMessagef (max = text + 3\n");
				return false;
			}
			//strip quotes if any
			if ( *pszArgs[0] == '"' )
				pszArgs[0]++;
			for ( TCHAR *pEnd = pszArgs[0] + strlen(pszArgs[0]) - 1; pEnd >= pszArgs[0]; pEnd-- )
			{
				if ( *pEnd == '"' )
				{
					*pEnd = '\0';
					break;
				}
			}
			SysMessagef(pszArgs[0], pszArgs[1], pszArgs[2] ? pszArgs[2] : 0, pszArgs[3] ? pszArgs[3] : 0);
			break;
		}
		case CV_SMSGU:
		case CV_SYSMESSAGEUA:
		{
			TCHAR *pszArgs[5];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), pszArgs, COUNTOF(pszArgs));
			if ( iArgQty > 4 )
			{
				// Font and mode are actually ignored here, but they never made a difference anyway.. I'd like to keep the syntax similar to SAYUA
				NCHAR szBuffer[MAX_TALK_BUFFER];
				CvtSystemToNUNICODE(szBuffer, COUNTOF(szBuffer), pszArgs[4], -1);

				addBarkUNICODE(szBuffer, NULL, static_cast<HUE_TYPE>(Exp_GetVal(pszArgs[0])), TALKMODE_SYSTEM, FONT_NORMAL, pszArgs[3]);
			}
			break;
		}
		case CV_SMSGL:
		case CV_SYSMESSAGELOC:
		{
			TCHAR *ppArgs[256];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), ",");
			if ( iArgQty > 1 )
			{
				HUE_TYPE hue = -1;
				if ( ppArgs[0] )
					hue = Exp_GetVal(ppArgs[0]);
				if ( hue == -1 )
					hue = HUE_TEXT_DEF;

				DWORD iClilocId = Exp_GetVal(ppArgs[1]);

				CGString CArgs;
				for ( size_t i = 2; i < iArgQty; i++ )
				{
					if ( CArgs.GetLength() )
						CArgs += "\t";
					CArgs += (!strcmp(ppArgs[i], "NULL") ? " " : ppArgs[i]);
				}

				addBarkLocalized(iClilocId, NULL, hue, TALKMODE_SYSTEM, FONT_NORMAL, CArgs.GetPtr());
			}
			break;
		}
		case CV_SMSGLEX:
		case CV_SYSMESSAGELOCEX:
		{
			TCHAR *ppArgs[256];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), ",");
			if ( iArgQty > 2 )
			{
				HUE_TYPE hue = -1;
				int affix = 0;
				if ( ppArgs[0] )
					hue = Exp_GetVal(ppArgs[0]);
				if ( hue == -1 )
					hue = HUE_TEXT_DEF;

				DWORD iClilocId = Exp_GetVal(ppArgs[1]);

				if ( ppArgs[2] )
					affix = Exp_GetVal(ppArgs[2]);

				CGString CArgs;
				for ( size_t i = 4; i < iArgQty; i++ )
				{
					if ( CArgs.GetLength() )
						CArgs += "\t";
					CArgs += (!strcmp(ppArgs[i], "NULL") ? " " : ppArgs[i]);
				}

				addBarkLocalizedEx(iClilocId, NULL, hue, TALKMODE_SYSTEM, FONT_NORMAL, static_cast<AFFIX_TYPE>(affix), ppArgs[3], CArgs.GetPtr());
			}
			break;
		}
		case CV_TELE:
			Cmd_Skill_Magery(SPELL_Teleport, dynamic_cast<CObjBase *>(pSrc));
			break;
		case CV_TILE:
			if ( !s.HasArgs() )
			{
				SysMessage("Usage: TILE z-height item1 item2 itemX");
			}
			else
			{
				m_Targ_Text = s.GetArgStr();	// point at the options
				m_tmTile.m_ptFirst.InitPoint();	// clear this first
				m_tmTile.m_Code = CV_TILE;
				addTarget(CLIMODE_TARG_TILE, "Pick 1st corner:", true);
			}
			break;
		case CV_VERSION:	// "SHOW VERSION"
			SysMessage(g_szServerDescription);
			break;
		case CV_WEBLINK:
			addWebLaunch(s.GetArgStr());
			break;
		default:
			if ( r_LoadVal(s) )
			{
				CGString sVal;
				if ( r_WriteVal(s.GetKey(), sVal, pSrc) )
				{
					//if ( !s.IsKeyHead("CTAG.", 5) && !s.IsKeyHead("CTAG0.", 6) )	// We don't want output related to CTAG
					//	SysMessagef("%s = %s", s.GetKey(), static_cast<LPCTSTR>(sVal));	// feedback on what we just did.
					return true;
				}
			}
			return CScriptObj::r_Verb(s, pSrc);		// used in the case of web pages to access server level things
	}
	return true;
	EXC_CATCH;

	EXC_DEBUG_START;
	EXC_ADD_SCRIPTSRC;
	EXC_DEBUG_END;
	return false;
}