예제 #1
0
bool CClient::OnRxConsoleLoginComplete()
{
	ADDTOCALLSTACK("CClient::OnRxConsoleLoginComplete");
	if ( GetConnectType() != CONNECT_TELNET )
		return false;
	if ( !GetPeer().IsValidAddr() )
		return false;

	if ( GetPrivLevel() < PLEVEL_Admin )	// this really should not happen.
	{
		SysMessagef("%s\n", g_Cfg.GetDefaultMsg(DEFMSG_CONSOLE_NO_ADMIN));
		return false;
	}

	SysMessagef("%s '%s' ('%s')\n", g_Cfg.GetDefaultMsg(DEFMSG_CONSOLE_WELCOME_2), GetName(), GetPeerStr());
	return true;
}
예제 #2
0
bool CClient::Cmd_SecureTrade( CChar *pChar, CItem *pItem )
{
	ADDTOCALLSTACK("CClient::Cmd_SecureTrade");
	// Begin secure trading with a char. (Make the initial offer)
	if ( !pChar || pChar == m_pChar )
		return false;

	// Make sure both clients can see each other, because trade window is an container
	// and containers can be opened only after the object is already loaded on screen
	if ( !m_pChar->CanSee(pChar) || !pChar->CanSee(m_pChar) )
		return false;

	if ( pItem && (IsTrigUsed(TRIGGER_DROPON_CHAR) || IsTrigUsed(TRIGGER_ITEMDROPON_CHAR)) )
	{
		CScriptTriggerArgs Args(pChar);
		if ( pItem->OnTrigger(ITRIG_DROPON_CHAR, m_pChar, &Args) == TRIGRET_RET_TRUE )
			return false;
	}

	if ( pChar->m_pNPC )		// NPC's can't use trade windows
		return pItem ? pChar->NPC_OnItemGive(m_pChar, pItem) : false;
	if ( !pChar->m_pClient )	// and also offline players
		return false;

	if ( pChar->GetDefNum("REFUSETRADES") )
	{
		SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_MSG_TRADE_REFUSE), pChar->GetName());
		return false;
	}

	// Check if the trade window is already open
	for ( CItem *pItemCont = m_pChar->GetContentHead(); pItemCont != NULL; pItemCont = pItemCont->GetNext() )
	{
		if ( !pItemCont->IsType(IT_EQ_TRADE_WINDOW) )
			continue;

		CItem *pItemPartner = pItemCont->m_uidLink.ItemFind();
		if ( !pItemPartner )
			continue;

		CChar *pCharPartner = dynamic_cast<CChar *>(pItemPartner->GetParent());
		if ( pCharPartner != pChar )
			continue;

		if ( pItem )
		{
			if ( IsTrigUsed(TRIGGER_DROPON_TRADE) )
			{
				CScriptTriggerArgs Args1(pChar);
				if ( pItem->OnTrigger(ITRIG_DROPON_TRADE, this, &Args1) == TRIGRET_RET_TRUE )
					return false;
			}
			CItemContainer *pCont = dynamic_cast<CItemContainer *>(pItemCont);
			if ( pCont )
				pCont->ContentAdd(pItem);
		}
		return true;
	}

	// Open new trade window
	if ( IsTrigUsed(TRIGGER_TRADECREATE) )
	{
		CScriptTriggerArgs Args(pItem);
		if ( (m_pChar->OnTrigger(CTRIG_TradeCreate, pChar, &Args) == TRIGRET_RET_TRUE) || (pChar->OnTrigger(CTRIG_TradeCreate, m_pChar, &Args) == TRIGRET_RET_TRUE) )
			return false;
	}

	if ( IsTrigUsed(TRIGGER_DROPON_TRADE) && pItem )
	{
		CScriptTriggerArgs Args1(pChar);
		if ( pItem->OnTrigger(ITRIG_DROPON_TRADE, this, &Args1) == TRIGRET_RET_TRUE )
			return false;
	}

	CItem *pItem1 = CItem::CreateBase(ITEMID_Bulletin1);
	if ( !pItem1 )
		return false;

	CItemContainer *pCont1 = static_cast<CItemContainer *>(pItem1);
	if ( !pCont1 )
	{
		DEBUG_ERR(("Item 0%x must be a container type to enable player trading.\n", ITEMID_Bulletin1));
		pItem1->Delete();
		return false;
	}

	CItemContainer *pCont2 = static_cast<CItemContainer *>(CItem::CreateBase(ITEMID_Bulletin1));
	ASSERT(pCont2);

	pCont1->SetName("Trade Window");
	pCont1->SetType(IT_EQ_TRADE_WINDOW);
	pCont1->m_itEqTradeWindow.m_iWaitTime = 0;
	pCont1->m_itEqTradeWindow.m_bCheck = 0;
	pCont1->m_uidLink = pCont2->GetUID();
	m_pChar->LayerAdd(pCont1, LAYER_SPECIAL);

	pCont2->SetName("Trade Window");
	pCont2->SetType(IT_EQ_TRADE_WINDOW);
	pCont2->m_itEqTradeWindow.m_iWaitTime = 0;
	pCont2->m_itEqTradeWindow.m_bCheck = 0;
	pCont2->m_uidLink = pCont1->GetUID();
	pChar->LayerAdd(pCont2, LAYER_SPECIAL);

	PacketTradeAction cmd(SECURE_TRADE_OPEN);
	cmd.prepareContainerOpen(pChar, pCont1, pCont2);
	cmd.send(this);
	cmd.prepareContainerOpen(m_pChar, pCont2, pCont1);
	cmd.send(pChar->m_pClient);

	if ( g_Cfg.m_iFeatureTOL & FEATURE_TOL_VIRTUALGOLD )
	{
		PacketTradeAction cmd2(SECURE_TRADE_UPDATELEDGER);
		if ( m_NetState->isClientVersion(MINCLIVER_TOL) )
		{
			cmd2.prepareUpdateLedger(pCont1, static_cast<DWORD>(m_pChar->m_virtualGold % 1000000000), static_cast<DWORD>(m_pChar->m_virtualGold / 1000000000));
			cmd2.send(this);
		}
		if ( pChar->m_pClient->m_NetState->isClientVersion(MINCLIVER_TOL) )
		{
			cmd2.prepareUpdateLedger(pCont2, static_cast<DWORD>(pChar->m_virtualGold % 1000000000), static_cast<DWORD>(pChar->m_virtualGold / 1000000000));
			cmd2.send(pChar->m_pClient);
		}
	}

	LogOpenedContainer(pCont2);
	pChar->m_pClient->LogOpenedContainer(pCont1);

	if ( pItem )
	{
		if ( IsTrigUsed(TRIGGER_DROPON_TRADE) )
		{
			CScriptTriggerArgs Args1(pChar);
			if ( pItem->OnTrigger(ITRIG_DROPON_TRADE, this, &Args1) == TRIGRET_RET_TRUE )
			{
				pCont1->Delete();
				pCont2->Delete();
				return false;
			}
		}
		pCont1->ContentAdd(pItem, pCont1->GetTopPoint());
	}
	return true;
}
예제 #3
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 ) == false ) )
	{
		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 ) == false ) )
	{
		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())
			{
				// FindItemName ???
				TCHAR * pszArgs = s.GetArgStr();
				if ( !IsValidGameObjDef( static_cast<LPCTSTR>(pszArgs) ) )
				{
					g_Log.EventWarn("Invalid ADD argument '%s'\n", pszArgs);
					SysMessageDefault( DEFMSG_CMD_INVALID );
					return true;
				}

				RESOURCE_ID rid = g_Cfg.ResourceGetID( RES_QTY, const_cast<LPCTSTR &>(reinterpret_cast<LPTSTR &>(pszArgs)));
				if (( rid.GetResType() == RES_CHARDEF ) || ( rid.GetResType() == RES_SPAWN ))
				{
					m_Targ_PrvUID.InitUID();
					return Cmd_CreateChar(static_cast<CREID_TYPE>(rid.GetResIndex()), SPELL_Summon, false );
				}

				ITEMID_TYPE id = static_cast<ITEMID_TYPE>(rid.GetResIndex());
				return Cmd_CreateItem( id );
			}
			else
			{
				if ( IsValidDef( "d_add" ) )
					Dialog_Setup( CLIMODE_DIALOG, g_Cfg.ResourceGetIDType(RES_DIALOG, "d_add"), 0, this->GetChar() );
				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/* || iArgs[0] == 0x3EB || iArgs[0] == 0x3EC*/) {	// 0x3eb and 0x3ec among some others does not exists now, which doesn't mean they won't fill them and, since nothing happens when wrong id is sent, we can let them be sent.
					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/* || IconId == 0x3EB || IconId == 0x3EC*/) {
					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));
				this->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<int>(piVal[0]), static_cast<int>(piVal[1]), static_cast<int>(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 fFound = false;
				for ( int m = 0; m < 256 && !fFound; m++ )
				{
					if ( !g_MapList.m_maps[m] ) continue;

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

						CItem	*pNext;
						CItem	*pItem = STATIC_CAST <CItem*>(pSector->m_Items_Inert.GetHead());
						for ( ; pItem != NULL && !fFound; pItem = pNext )
						{
							pNext = 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", (DWORD)pItem->GetUID(), g_Cfg.ResourceGetName(rid));
									fFound = true;
								}
							}
						}
					}
				}
				if ( ! fFound )
					SysMessage(g_Cfg.GetDefaultMsg( DEFMSG_NO_BAD_SPAWNS ));
			}
			break;
		case CV_BANKSELF: // open my own bank
			addBankOpen( m_pChar, static_cast<LAYER_TYPE>(s.GetArgVal()));
			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 == NULL)
					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 != NULL)
					{
						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 = s.GetArgVal();
					pChar = uid.CharFind();
				}
				if ( pChar )
					closeUIWindow(pChar, 0x01);
			}
			break;

		case CV_CLOSEPROFILE:
			{
				CChar *pChar = m_pChar;
				if ( s.HasArgs() )
				{
					CGrayUID uid = s.GetArgVal();
					pChar = uid.CharFind();
				}
				if ( pChar )
					closeUIWindow(pChar, 0x08);
			}
			break;

		case CV_CLOSESTATUS:
			{
				CChar *pChar = m_pChar;
				if ( s.HasArgs() )
				{
					CGrayUID uid = s.GetArgVal();
					pChar = uid.CharFind();
				}
				if ( pChar )
					closeUIWindow(pChar, 0x02);
			}
			break;

		case CV_DYE:
			if ( s.HasArgs() )
			{
				CGrayUID uid(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 != NULL )
				{
					CPointMap po = pObj->GetTopLevelObj()->GetTopPoint();
					CPointMap pnt = po;
					pnt.MoveN( DIR_W, 3 );
					DWORD wBlockFlags = m_pChar->GetMoveBlockFlags();
					pnt.m_z = g_World.GetHeightPoint2( pnt, wBlockFlags );	// ??? Get Area
					m_pChar->m_dirFace = pnt.GetDir( po, m_pChar->m_dirFace ); // Face the player
					m_pChar->Spell_Teleport( pnt, 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 != NULL )
				{
					Event_Target(GetTargMode(), pObj->GetUID(), pObj->GetUnkPoint());
					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 = s.GetArgVal();
				pChar = uid.CharFind();
			}
			if ( pChar )
				addCharPaperdoll(pChar);
		}
		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(GetNetState());
#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:				// Just put up another menu.
			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:	// from the spell skill script.
			// m_Targ_PrvUID should already be set.
			return Cmd_CreateChar(static_cast<CREID_TYPE>(g_Cfg.ResourceGetIndexType( RES_CHARDEF, s.GetArgStr())), SPELL_Summon, true );
		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 )
				{
					int hue = -1;
					if ( ppArgs[0] )
						hue = Exp_GetVal( ppArgs[0] );
					int iClilocId = Exp_GetVal( ppArgs[1] );

					if ( hue == -1 )	hue = HUE_TEXT_DEF;

					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, static_cast<HUE_TYPE>(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 )
				{
					int hue = -1;
					int affix = 0;
					if ( ppArgs[0] )
						hue = Exp_GetVal( ppArgs[0] );
					int iClilocId = Exp_GetVal( ppArgs[1] );
					if ( ppArgs[2] )
						affix = Exp_GetVal( ppArgs[2] );

					if ( hue == -1 )	hue = HUE_TEXT_DEF;

					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, static_cast<HUE_TYPE>(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", (LPCTSTR) s.GetKey(), (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;
}
예제 #4
0
bool CClient::r_LoadVal( CScript & s )
{
	ADDTOCALLSTACK("CClient::r_LoadVal");
	EXC_TRY("LoadVal");
	if ( GetAccount() == NULL )
		return( false );

	LPCTSTR pszKey = s.GetKey();

	if ( s.IsKeyHead( "CTAG.", 5 ) || s.IsKeyHead( "CTAG0.", 6 ) )
	{
		bool fZero = s.IsKeyHead( "CTAG0.", 6 );
		bool fQuoted = false;

		pszKey = pszKey + (fZero ? 6 : 5);
		m_TagDefs.SetStr( pszKey, fQuoted, s.GetArgStr( &fQuoted ), fZero );
		return( true );
	}

	switch ( FindTableSorted( pszKey, sm_szLoadKeys, COUNTOF(sm_szLoadKeys)-1 ))
	{
		case CC_ALLMOVE:
			addRemoveAll(true, false);
			GetAccount()->TogPrivFlags( PRIV_ALLMOVE, s.GetArgStr() );
			if ( IsSetOF( OF_Command_Sysmsgs ) )
				m_pChar->SysMessage( IsPriv(PRIV_ALLMOVE)? "Allmove ON" : "Allmove OFF" );
			addPlayerView(NULL);
			break;
		case CC_ALLSHOW:
			addRemoveAll(false, true);
			GetAccount()->TogPrivFlags( PRIV_ALLSHOW, s.GetArgStr() );
			if ( IsSetOF( OF_Command_Sysmsgs ) )
				m_pChar->SysMessage( IsPriv(PRIV_ALLSHOW)? "Allshow ON" : "Allshow OFF" );
			addPlayerView(NULL);
			break;
		case CC_DEBUG:
			addRemoveAll(true, false);
			GetAccount()->TogPrivFlags( PRIV_DEBUG, s.GetArgStr() );
			if ( IsSetOF( OF_Command_Sysmsgs ) )
					m_pChar->SysMessage( IsPriv(PRIV_DEBUG)? "Debug ON" : "Debug OFF" );
			addPlayerView(NULL);
			break;
		case CC_DETAIL:
			GetAccount()->TogPrivFlags( PRIV_DETAIL, s.GetArgStr() );
			if ( IsSetOF( OF_Command_Sysmsgs ) )
					m_pChar->SysMessage( IsPriv(PRIV_DETAIL)? "Detail ON" : "Detail OFF" );
			break;
		case CC_GM: // toggle your GM status on/off
			if ( GetPrivLevel() >= PLEVEL_GM )
			{
				GetAccount()->TogPrivFlags( PRIV_GM, s.GetArgStr() );
				m_pChar->ResendTooltip();
				if ( IsSetOF( OF_Command_Sysmsgs ) )
					m_pChar->SysMessage( IsPriv(PRIV_GM)? "GM ON" : "GM OFF" );
			}
			break;
		case CC_HEARALL:
			GetAccount()->TogPrivFlags( PRIV_HEARALL, s.GetArgStr() );
			if ( IsSetOF( OF_Command_Sysmsgs ) )
					m_pChar->SysMessage( IsPriv(PRIV_HEARALL)? "Hearall ON" : "Hearall OFF" );
			break;
		case CC_PRIVSHOW:
			// Hide my priv title.
			if ( GetPrivLevel() >= PLEVEL_Counsel )
			{
				if ( ! s.HasArgs())
				{
					GetAccount()->TogPrivFlags( PRIV_PRIV_NOSHOW, NULL );
				}
				else if ( s.GetArgVal() )
				{
					GetAccount()->ClearPrivFlags( PRIV_PRIV_NOSHOW );
				}
				else
				{
					GetAccount()->SetPrivFlags( PRIV_PRIV_NOSHOW );
				}
				m_pChar->ResendTooltip();
				if ( IsSetOF( OF_Command_Sysmsgs ) )
					m_pChar->SysMessage( IsPriv(PRIV_PRIV_NOSHOW)? "Privshow OFF" : "Privshow ON" );
			}
			break;

		case CC_TARG:
			m_Targ_UID = s.GetArgVal();
			break;
		case CC_TARGP:
			m_Targ_p.Read( s.GetArgRaw());
			if ( !m_Targ_p.IsValidPoint() )
			{
				m_Targ_p.ValidatePoint();
				SysMessagef( "Invalid point: %s", s.GetArgStr() );
			}
			break;
		case CC_TARGPROP:
			m_Prop_UID = s.GetArgVal();
			break;
		case CC_TARGPRV:
			m_Targ_PrvUID = s.GetArgVal();
			break;
		default:
			return( false );
	}
	return true;
	EXC_CATCH;

	EXC_DEBUG_START;
	EXC_ADD_SCRIPT;
	EXC_DEBUG_END;
	return false;
}
예제 #5
0
bool CChar::Use_Repair( CItem * pItemArmor )
{
	ADDTOCALLSTACK("CChar::Use_Repair");
	// Attempt to repair the item.
	// If it is repairable.

	if ( !pItemArmor || !pItemArmor->Armor_IsRepairable() )
	{
		SysMessageDefault(DEFMSG_REPAIR_NOT);
		return false;
	}

	if ( pItemArmor->IsItemEquipped() )
	{
		SysMessageDefault(DEFMSG_REPAIR_WORN);
		return false;
	}
	if ( !CanUse(pItemArmor, true) )
	{
		SysMessageDefault(DEFMSG_REPAIR_REACH);
		return false;
	}

	// Quickly use arms lore skill, but don't gain any skill until later on
	int iArmsLoreDiff = Calc_GetRandVal(30);
	if ( !Skill_UseQuick(SKILL_ARMSLORE, iArmsLoreDiff, false) )
	{
		// apply arms lore skillgain for failure
		Skill_Experience(SKILL_ARMSLORE, -iArmsLoreDiff);
		SysMessageDefault(DEFMSG_REPAIR_UNK);
		return false;
	}

	if ( pItemArmor->m_itArmor.m_Hits_Cur >= pItemArmor->m_itArmor.m_Hits_Max )
	{
		SysMessageDefault(DEFMSG_REPAIR_FULL);
		return false;
	}

	m_Act_p = g_World.FindItemTypeNearby(GetTopPoint(), IT_ANVIL, 2, false);
	if ( !m_Act_p.IsValidPoint() )
	{
		SysMessageDefault(DEFMSG_REPAIR_ANVIL);
		return false;
	}

	CItemBase *pItemDef = pItemArmor->Item_GetDef();
	ASSERT(pItemDef);

	// Use up some raw materials to repair.
	int iTotalHits = pItemArmor->m_itArmor.m_Hits_Max;
	int iDamageHits = pItemArmor->m_itArmor.m_Hits_Max - pItemArmor->m_itArmor.m_Hits_Cur;
	int iDamagePercent = IMULDIV(100, iDamageHits, iTotalHits);

	size_t iMissing = ResourceConsumePart(&(pItemDef->m_BaseResources), 1, iDamagePercent / 2, true);
	if ( iMissing != pItemDef->m_BaseResources.BadIndex() )
	{
		// Need this to repair.
		const CResourceDef *pCompDef = g_Cfg.ResourceGetDef(pItemDef->m_BaseResources.GetAt(iMissing).GetResourceID());
		SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_LACK_1), pCompDef ? pCompDef->GetName() : g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_LACK_2));
		return false;
	}

	UpdateDir(m_Act_p);
	UpdateAnimate(ANIM_ATTACK_1H_SLASH);

	// quarter the skill to make it.
	// + more damaged items should be harder to repair.
	// higher the percentage damage the closer to the skills to make it.

	size_t iRes = pItemDef->m_SkillMake.FindResourceType(RES_SKILL);
	if ( iRes == pItemDef->m_SkillMake.BadIndex() )
		return false;

	CResourceQty RetMainSkill = pItemDef->m_SkillMake[iRes];
	int iSkillLevel = static_cast<int>(RetMainSkill.GetResQty()) / 10;
	int iDifficulty = IMULDIV(iSkillLevel, iDamagePercent, 100);
	if ( iDifficulty < iSkillLevel / 4 )
		iDifficulty = iSkillLevel / 4;

	// apply arms lore skillgain now
	LPCTSTR pszText;
	Skill_Experience(SKILL_ARMSLORE, iArmsLoreDiff);
	bool fSuccess = Skill_UseQuick(static_cast<SKILL_TYPE>(RetMainSkill.GetResIndex()), iDifficulty);
	if ( fSuccess )
	{
		pItemArmor->m_itArmor.m_Hits_Cur = static_cast<WORD>(iTotalHits);
		pszText = g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_1);
	}
	else
	{
		/*****************************
		// not sure if this is working!
		******************************/
		// Failure
		if ( !Calc_GetRandVal(6) )
		{
			pszText = g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_2);
			pItemArmor->m_itArmor.m_Hits_Max--;
			pItemArmor->m_itArmor.m_Hits_Cur--;
		}
		else if ( !Calc_GetRandVal(3) )
		{
			pszText = g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_3);
			pItemArmor->m_itArmor.m_Hits_Cur--;
		}
		else
			pszText = g_Cfg.GetDefaultMsg( DEFMSG_REPAIR_4 );

		iDamagePercent = Calc_GetRandVal(iDamagePercent);	// some random amount
	}

	ResourceConsumePart(&(pItemDef->m_BaseResources), 1, iDamagePercent / 2, false);
	if ( pItemArmor->m_itArmor.m_Hits_Cur <= 0 )
		pszText = g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_5);

	TCHAR *pszMsg = Str_GetTemp();
	sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_REPAIR_MSG), pszText, pItemArmor->GetName());
	Emote(pszMsg);

	if ( pItemArmor->m_itArmor.m_Hits_Cur <= 0 )
		pItemArmor->Delete();
	else
		pItemArmor->UpdatePropertyFlag(AUTOTOOLTIP_FLAG_DURABILITY);

	return fSuccess;
}
예제 #6
0
bool CChar::Use_Item_Web( CItem * pItemWeb )
{
	ADDTOCALLSTACK("CChar::Use_Item_Web");
	// IT_WEB
	// IT_EQ_STUCK
	// Try to break out of the web.
	// Or just try to damage it.
	//
	// RETURN: true = held in place.
	//  false = walk thru it.

	if ( GetDispID() == CREID_GIANT_SPIDER || !pItemWeb || !pItemWeb->IsTopLevel() || IsStatFlag(STATF_DEAD|STATF_Insubstantial) || IsPriv(PRIV_GM) )
		return false;	// just walk through it

	// Try to break it.
	int iStr = pItemWeb->m_itWeb.m_Hits_Cur;
	if ( iStr == 0 )
		iStr = pItemWeb->m_itWeb.m_Hits_Cur = 60 + Calc_GetRandVal(250);

	// Since broken webs become spider silk, we should get out of here now if we aren't in a web.
	CItem *pFlag = LayerFind(LAYER_FLAG_Stuck);
	if ( CanMove(pItemWeb, false) )
	{
		if ( pFlag )
			pFlag->Delete();
		return false;
	}

	if ( pFlag )
	{
		if ( pFlag->IsTimerSet() )	// don't allow me to try to damage it too often
			return true;
	}

	int iDmg = pItemWeb->OnTakeDamage(Stat_GetAdjusted(STAT_STR), this);
	switch ( iDmg )
	{
		case 0:			// damage blocked
		case 1:			// web survived
		default:		// unknown
			if ( GetTopPoint() == pItemWeb->GetTopPoint() )		// is character still stuck on the web?
				break;

		case 2:			// web turned into silk
		case INT_MAX:	// web destroyed
			if ( pFlag )
				pFlag->Delete();
			return false;
	}

	// Stuck in it still.
	if ( !pFlag )
	{
		if ( iDmg < 0 )
			return false;

		// First time message.
		pFlag = CItem::CreateBase(ITEMID_WEB1_1);
		ASSERT(pFlag);
		pFlag->SetAttr(ATTR_DECAY);
		pFlag->SetType(IT_EQ_STUCK);
		pFlag->m_uidLink = pItemWeb->GetUID();
		pFlag->SetTimeout(pItemWeb->GetTimerDAdjusted());
		LayerAdd(pFlag, LAYER_FLAG_Stuck);
	}
	else
	{
		if ( iDmg < 0 )
		{
			pFlag->Delete();
			return false;
		}
		SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SWEB_STUCK), pItemWeb->GetName());
	}

	return true;
}
예제 #7
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, GetPackSafe(), 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;
				}
			}
			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) != NULL)
				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: {
			bool fOpen = pItem->Use_DoorNew(fLink);
			if (fLink || !fOpen)    // 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;
}
예제 #8
0
bool CClient::OnRxPing( const byte * pData, size_t iLen )
{
	ADDTOCALLSTACK("CClient::OnRxPing");
	// packet iLen < 5
	// UOMon should work like this.
	// RETURN: true = keep the connection open.
	if ( GetConnectType() != CONNECT_UNK )
		return false;

	if ( !iLen || iLen > 4 )
		return false;

	switch ( pData[0] )
	{
		// Remote Admin Console
		case '\x1':
		case ' ':
		{
			if ( (iLen > 1) &&
				 (iLen != 2 || pData[1] != '\n') &&
				 (iLen != 3 || pData[1] != '\r' || pData[2] != '\n') &&
				 (iLen != 3 || pData[1] != '\n' || pData[2] != '\0') )
				break;

			// enter into remote admin mode. (look for password).
			SetConnectType( CONNECT_TELNET );
			m_zLogin[0] = 0;
			SysMessagef("%s %s Admin Telnet\n", g_Cfg.GetDefaultMsg(DEFMSG_CONSOLE_WELCOME_1), g_Serv.GetName());

			if ( g_Cfg.m_fLocalIPAdmin )
			{
				// don't bother logging in if local.

				if ( GetPeer().IsLocalAddr() )
				{
					CAccountRef pAccount = g_Accounts.Account_Find("Administrator");
					if ( !pAccount )
						pAccount = g_Accounts.Account_Find("RemoteAdmin");
					if ( pAccount )
					{
						CSString sMsg;
						byte lErr = LogIn( pAccount, sMsg );
						if ( lErr != PacketLoginError::Success )
						{
							if ( lErr != PacketLoginError::Invalid )
								SysMessage( sMsg );
							return false;
						}
						return OnRxConsoleLoginComplete();
					}
				}
			}

			SysMessage("Login:\n");
			return true;
		}

		//Axis Connection
		case '@':
		{
			if ( (iLen > 1) &&
				 (iLen != 2 || pData[1] != '\n') &&
				 (iLen != 3 || pData[1] != '\r' || pData[2] != '\n') &&
				 (iLen != 3 || pData[1] != '\n' || pData[2] != '\0') )
				break;

			// enter into Axis mode. (look for password).
			SetConnectType( CONNECT_AXIS );
			m_zLogin[0] = 0;

			time_t dateChange;
			dword dwSize = 0;
			CSFileList::ReadFileInfo( "Axis.db", dateChange, dwSize );
			SysMessagef("%u",dwSize);
			return true;
		}

		// ConnectUO Status
		case 0xF1:
		{
			// ConnectUO sends a 4-byte packet when requesting status info
			// byte Cmd		(0xF1)
			// word Unk		(0x04)
			// byte SubCmd	(0xFF)

			if ( iLen != MAKEWORD( pData[2], pData[1] ) )
				break;

			if ( pData[3] != 0xFF )
				break;

			if ( g_Cfg.m_fCUOStatus == false )
			{
				g_Log.Event( LOGM_CLIENTS_LOG|LOGL_EVENT, "%x:CUO Status request from %s has been rejected.\n", GetSocketID(), GetPeerStr());
				return false;
			}

			// enter 'remote admin mode'
			SetConnectType( CONNECT_TELNET );

			g_Log.Event( LOGM_CLIENTS_LOG|LOGL_EVENT, "%x:CUO Status request from %s\n", GetSocketID(), GetPeerStr());

			SysMessage( g_Serv.GetStatusString( 0x25 ) );

			// exit 'remote admin mode'
			SetConnectType( CONNECT_UNK );
			return false;
		}

		// UOGateway Status
		case 0xFF:
		case 0x7F:
		case 0x22:
		{
			if ( iLen > 1 )
				break;

			if ( g_Cfg.m_fUOGStatus == false )
			{
				g_Log.Event( LOGM_CLIENTS_LOG|LOGL_EVENT, "%x:UOG Status request from %s has been rejected.\n", GetSocketID(), GetPeerStr());
				return false;
			}

			// enter 'remote admin mode'
			SetConnectType( CONNECT_TELNET );

			g_Log.Event( LOGM_CLIENTS_LOG|LOGL_EVENT, "%x:UOG Status request from %s\n", GetSocketID(), GetPeerStr());

			if (pData[0] == 0x7F)
				SetConnectType( CONNECT_UOG );

			SysMessage( g_Serv.GetStatusString( 0x22 ) );

			// exit 'remote admin mode'
			SetConnectType( CONNECT_UNK );
			return false;
		}
	}

	g_Log.Event( LOGM_CLIENTS_LOG|LOGL_EVENT, "%x:Unknown/invalid ping data '0x%x' from %s (Len: %" PRIuSIZE_T ")\n", GetSocketID(), pData[0], GetPeerStr(), iLen);
	return false;
}
예제 #9
0
bool CClient::OnRxAxis( const byte * pData, size_t iLen )
{
	ADDTOCALLSTACK("CClient::OnRxAxis");
	if ( !iLen || ( GetConnectType() != CONNECT_AXIS ))
		return false;

	while ( iLen -- )
	{
		int iRet = OnConsoleKey( m_Targ_Text, *pData++, GetAccount() != NULL );
		if ( ! iRet )
			return false;
		if ( iRet == 2 )
		{
			if ( GetAccount() == NULL )
			{
				if ( !m_zLogin[0] )
				{
					if ( (uint)(m_Targ_Text.GetLength()) <= (CountOf(m_zLogin) - 1) )
						strcpy(m_zLogin, m_Targ_Text);
					m_Targ_Text.Empty();
				}
				else
				{
					CSString sMsg;

					CAccountRef pAccount = g_Accounts.Account_Find(m_zLogin);
					if (( pAccount == NULL ) || ( pAccount->GetPrivLevel() < PLEVEL_Counsel ))
					{
						SysMessagef("\"MSG:%s\"", g_Cfg.GetDefaultMsg(DEFMSG_AXIS_NOT_PRIV));
						m_Targ_Text.Empty();
						return false;
					}
					if ( LogIn(m_zLogin, m_Targ_Text, sMsg ) == PacketLoginError::Success )
					{
						m_Targ_Text.Empty();
						if ( GetPrivLevel() < PLEVEL_Counsel )
						{
							SysMessagef("\"MSG:%s\"", g_Cfg.GetDefaultMsg(DEFMSG_AXIS_NOT_PRIV));
							return false;
						}
						if (GetPeer().IsValidAddr())
						{
							CScriptTriggerArgs Args;
							Args.m_VarsLocal.SetStrNew("Account",GetName());
							Args.m_VarsLocal.SetStrNew("IP",GetPeer().GetAddrStr());
							TRIGRET_TYPE tRet = TRIGRET_RET_DEFAULT;
							r_Call("f_axis_preload", this, &Args, NULL, &tRet);
							if ( tRet == TRIGRET_RET_FALSE )
								return false;
							if ( tRet == TRIGRET_RET_TRUE )
							{
								SysMessagef("\"MSG:%s\"", g_Cfg.GetDefaultMsg(DEFMSG_AXIS_DENIED));
								return false;
							}

							time_t dateChange;
							dword dwSize;
							if ( ! CSFileList::ReadFileInfo( "Axis.db", dateChange, dwSize ))
							{
								SysMessagef("\"MSG:%s\"", g_Cfg.GetDefaultMsg(DEFMSG_AXIS_INFO_ERROR));
								return false;
							}

							CSFile FileRead;
							if ( ! FileRead.Open( "Axis.db", OF_READ|OF_BINARY ))
							{
								SysMessagef("\"MSG:%s\"", g_Cfg.GetDefaultMsg(DEFMSG_AXIS_FILE_ERROR));
								return false;
							}

							tchar szTmp[8*1024];
							PacketWeb packet;
							for (;;)
							{
								size_t iLength = FileRead.Read( szTmp, sizeof( szTmp ) );
								if ( iLength <= 0 )
									break;
								packet.setData((byte*)szTmp, iLength);
								packet.send(this);
								dwSize -= (dword)iLength;
								if ( dwSize <= 0 )
									break;
							}
							return true;
						}
						return false;
					}
					else if ( ! sMsg.IsEmpty())
					{
						SysMessagef("\"MSG:%s\"", (lpctstr)sMsg);
						return false;
					}
					m_Targ_Text.Empty();
				}
				return true;
			}
		}
	}
	return true;
}
예제 #10
0
bool CClient::OnRxConsole( const byte * pData, size_t iLen )
{
	ADDTOCALLSTACK("CClient::OnRxConsole");
	// A special console version of the client. (Not game protocol)
	if ( !iLen || ( GetConnectType() != CONNECT_TELNET ))
		return false;

	if ( IsSetEF( EF_AllowTelnetPacketFilter ) )
	{
		bool fFiltered = xPacketFilter(pData, iLen);
		if ( fFiltered )
			return fFiltered;
	}

	while ( iLen -- )
	{
		int iRet = OnConsoleKey( m_Targ_Text, *pData++, GetAccount() != NULL );
		if ( ! iRet )
			return false;
		if ( iRet == 2 )
		{
			if ( GetAccount() == NULL )
			{
				if ( !m_zLogin[0] )
				{
					if ( (uint)(m_Targ_Text.GetLength()) > (CountOf(m_zLogin) - 1) )
					{
						SysMessage("Login:\n");
					}
					else
					{
						strcpy(m_zLogin, m_Targ_Text);
						SysMessage("Password:\n");
					}
					m_Targ_Text.Empty();
				}
				else
				{
					CSString sMsg;

					CAccountRef pAccount = g_Accounts.Account_Find(m_zLogin);
					if (( pAccount == NULL ) || ( pAccount->GetPrivLevel() < PLEVEL_Admin ))
					{
						SysMessagef("%s\n", g_Cfg.GetDefaultMsg(DEFMSG_CONSOLE_NOT_PRIV));
						m_Targ_Text.Empty();
						return false;
					}
					if ( LogIn(m_zLogin, m_Targ_Text, sMsg ) == PacketLoginError::Success )
					{
						m_Targ_Text.Empty();
						return OnRxConsoleLoginComplete();
					}
					else if ( ! sMsg.IsEmpty())
					{
						SysMessage( sMsg );
						return false;
					}
					m_Targ_Text.Empty();
				}
				return true;
			}
			else
			{
				iRet = g_Serv.OnConsoleCmd( m_Targ_Text, this );

				if (g_Cfg.m_fTelnetLog && GetPrivLevel() >= g_Cfg.m_iCommandLog)
					g_Log.Event(LOGM_GM_CMDS, "%x:'%s' commands '%s'=%d\n", GetSocketID(), GetName(), static_cast<lpctstr>(m_Targ_Text), iRet);
			}
		}
	}
	return true;
}
예제 #11
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 iArgQty = 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 = (iArgQty > 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));
				break;
			}

			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 i = 0; i < 4; ++i )
			{
				if ( !IsStrNumeric(ppArgs[i]) )
				{
					DEBUG_ERR(("Invalid AddBuff argument number %u\n", i + 1));
					return true;
				}
				iArgs[i] = Exp_GetVal(ppArgs[i]);
			}
			if ( (iArgs[0] < 0) || (iArgs[0] > USHRT_MAX) )
			{
				DEBUG_ERR(("Invalid AddBuff icon ID\n"));
				break;
			}

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

			addBuff(static_cast<BUFF_ICONS>(iArgs[0]), static_cast<DWORD>(iArgs[1]), static_cast<DWORD>(iArgs[2]), static_cast<WORD>(iArgs[3]), pszArgs, iArgQty);
			break;
		}
		case CV_REMOVEBUFF:
		{
			BUFF_ICONS IconId = static_cast<BUFF_ICONS>(s.GetArgVal());
			if ( (IconId < 0) || (IconId > USHRT_MAX) )
			{
				DEBUG_ERR(("Invalid RemoveBuff icon ID\n"));
				break;
			}
			removeBuff(IconId);
			break;
		}
		case CV_ADDCLILOC:
		{
			// Add cliloc in @ClientTooltip trigger
			TCHAR *ppArgs[256];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), ",");
			DWORD dwClilocId = static_cast<DWORD>(Exp_GetLLVal(ppArgs[0]));

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

			if ( g_Cfg.m_wDebugFlags & DEBUGF_SCRIPTS )
				g_Log.EventDebug("SCRIPT: addcliloc(%lu,'%s')\n", dwClilocId, static_cast<LPCTSTR>(sVal));
			m_TooltipData.Add(new CClientTooltip(dwClilocId, sVal));
			break;
		}
		case CV_ADDCONTEXTENTRY:
		{
			TCHAR *ppArgs[20];
			if ( Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs), ",") > 4 )
			{
				DEBUG_ERR(("Bad AddContextEntry usage: Function takes maximum of 4 arguments!\n"));
				return true;
			}
			if ( !m_pPopupPacket )
			{
				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(ppArgs[i]) )
					continue;

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

			int iTextEntry = Exp_GetVal(ppArgs[0]);
			if ( iTextEntry < 100 )
			{
				DEBUG_ERR(("Bad AddContextEntry usage: TextEntry < 100 is reserved for server usage!\n"));
				return true;
			}
			m_pPopupPacket->addOption(static_cast<WORD>(iTextEntry), static_cast<DWORD>(Exp_GetLLVal(ppArgs[1])), static_cast<WORD>(Exp_GetLLVal(ppArgs[2])), static_cast<WORD>(Exp_GetLLVal(ppArgs[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]));
			break;
		}
		case CV_BADSPAWN:
		{
			// Loop the world searching for bad spawns
			bool fFound = false;
			CItem *pItem = NULL;
			CSector *pSector = NULL;
			CResourceDef *pSpawnDef = NULL;
			for ( int m = 0; (m < 256) && !fFound; ++m )
			{
				if ( !g_MapList.m_maps[m] )
					continue;

				for ( int s = 0; (s < g_MapList.GetSectorQty(m)) && !fFound; ++s )
				{
					pSector = g_World.GetSector(m, s);
					if ( !pSector )
						continue;

					for ( pItem = static_cast<CItem *>(pSector->m_Items_Timer.GetHead()); (pItem != NULL) && !fFound; pItem = pItem->GetNext() )
					{
						if ( pItem->IsType(IT_SPAWN_ITEM) || pItem->IsType(IT_SPAWN_CHAR) )
						{
							pSpawnDef = static_cast<CItemSpawn *>(pItem)->FixDef();
							if ( !pSpawnDef )
							{
								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));
								fFound = true;
							}
						}
					}
				}
			}
			if ( !fFound )
				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 iSkill;
				if ( !pSpellDef->GetPrimarySkill(&iSkill, 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>(iSkill));
				break;
			}
			else
				Cmd_Skill_Magery(spell, pObjSrc);
			break;
		}
		case CV_CHANGEFACE:		// open 'face selection' dialog (enhanced clients only)
		{
			addGumpDialog(CLIMODE_DIALOG, NULL, 0, NULL, 0, 0, 0, m_pChar, CLIMODE_DIALOG_FACESELECTION);
			break;
		}
		case CV_CHARLIST:		// usually just a gm command
		{
			if ( !PacketChangeCharacter::CanSendTo(m_NetState) )
				break;
			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:
		{
			const CChar *pChar = s.HasArgs() ? static_cast<CGrayUID>(s.GetArgVal()).CharFind() : m_pChar;
			if ( pChar )
				closeUIWindow(pChar, 0x1);
			break;
		}
		case CV_CLOSEPROFILE:
		{
			const CChar *pChar = s.HasArgs() ? static_cast<CGrayUID>(s.GetArgVal()).CharFind() : m_pChar;
			if ( pChar )
				closeUIWindow(pChar, 0x8);
			break;
		}
		case CV_CLOSESTATUS:
		{
			const CChar *pChar = s.HasArgs() ? static_cast<CGrayUID>(s.GetArgVal()).CharFind() : m_pChar;
			if ( pChar )
				closeUIWindow(pChar, 0x2);
			break;
		}
		case CV_CODEXOFWISDOM:
		{
			INT64 piArgs[2];
			size_t iArgQty = Str_ParseCmds(s.GetArgStr(), piArgs, COUNTOF(piArgs));
			if ( iArgQty < 1 )
			{
				SysMessage("Usage: CODEXOFWISDOM TopicID [ForceOpen]");
				break;
			}

			addCodexOfWisdom(static_cast<DWORD>(piArgs[0]), static_cast<bool>(piArgs[1]));
			break;
		}
		case CV_DYE:
		{
			const CObjBase *pObj = s.HasArgs() ? static_cast<CGrayUID>(s.GetArgVal()).ObjFind() : NULL;
			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
			TCHAR *ppArgs[2];
			size_t iArgQty = Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));
			if ( iArgQty < 2 )
			{
				SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_EXTRACT_USAGE));
				break;
			}

			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
			TCHAR *ppArgs[2];
			size_t iArgQty = Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));
			if ( iArgQty < 2 )
			{
				SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_UNEXTRACT_USAGE));
				break;
			}

			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_MAPWAYPOINT:
		{
			INT64 piVal[2];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), piVal, COUNTOF(piVal));
			if ( iArgQty < 2 )
			{
				SysMessage("Usage: MAPWAYPOINT uid type");
				break;
			}
			CObjBase *pObj = static_cast<CGrayUID>(piVal[0]).ObjFind();
			addMapWaypoint(pObj, static_cast<MAPWAYPOINT_TYPE>(piVal[1]));
			break;
		}
		case CV_MENU:
		{
			Menu_Setup(g_Cfg.ResourceGetIDType(RES_MENU, s.GetArgStr()));
			break;
		}
		case CV_MIDILIST:
		{
			INT64 piMidi[64];
			size_t iArgQty = Str_ParseCmds(s.GetArgStr(), piMidi, COUNTOF(piMidi));
			if ( iArgQty > 0 )
				addMusic(static_cast<MIDI_TYPE>(piMidi[Calc_GetRandVal(iArgQty)]));
			break;
		}
		case CV_NUDGE:
		{
			if ( !s.HasArgs() )
			{
				SysMessage("Usage: NUDGE dx dy dz");
				break;
			}
			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:
		{
			const CChar *pChar = s.HasArgs() ? static_cast<CGrayUID>(s.GetArgVal()).CharFind() : m_pChar;
			if ( pChar )
				addCharPaperdoll(pChar);
			break;
		}
		case CV_OPENTRADEWINDOW:
		{
			TCHAR *ppArgs[2];
			Str_ParseCmds(s.GetArgStr(), ppArgs, COUNTOF(ppArgs));

			CChar *pChar = ppArgs[0] ? static_cast<CGrayUID>(Exp_GetLLVal(ppArgs[0])).CharFind() : NULL;
			if ( pChar )
			{
				CItem *pItem = ppArgs[1] ? static_cast<CGrayUID>(Exp_GetLLVal(ppArgs[1])).ItemFind() : NULL;
				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 pszPrompt = g_Cfg.GetDefaultMsg(DEFMSG_SELECT_MAGIC_TARGET);
				if ( !pSpellDef->m_sTargetPrompt.IsEmpty() )
					pszPrompt = pSpellDef->m_sTargetPrompt;

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

				addTarget(CLIMODE_TARG_SKILL_MAGERY, pszPrompt, pSpellDef->IsSpellType(SPELLFLAG_TARG_XYZ), pSpellDef->IsSpellType(SPELLFLAG_HARM), iSpellTimeout);
				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 iSkill;
					if ( !pSpellDef->GetPrimarySkill(&iSkill, NULL) )
						return false;

					m_pChar->Skill_Start(static_cast<SKILL_TYPE>(iSkill));
				}
			}
			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 *ppArgs[4];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs));
			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;
			}
			if ( *ppArgs[0] == '"' )	// skip quotes
				++ppArgs[0];
			for ( TCHAR *pEnd = ppArgs[0] + strlen(ppArgs[0]) - 1; pEnd >= ppArgs[0]; --pEnd )
			{
				if ( *pEnd == '"' )		// skip quotes
				{
					*pEnd = '\0';
					break;
				}
			}
			SysMessagef(ppArgs[0], ppArgs[1], ppArgs[2] ? ppArgs[2] : 0, ppArgs[3] ? ppArgs[3] : 0);
			break;
		}
		case CV_SMSGU:
		case CV_SYSMESSAGEUA:
		{
			TCHAR *ppArgs[5];
			size_t iArgQty = Str_ParseCmds(s.GetArgRaw(), ppArgs, COUNTOF(ppArgs));
			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), ppArgs[4], -1);

				addBarkUNICODE(szBuffer, NULL, static_cast<HUE_TYPE>(Exp_GetLLVal(ppArgs[0])), TALKMODE_SYSTEM, FONT_NORMAL, ppArgs[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 = HUE_TEXT_DEF;
				if ( ATOI(ppArgs[0]) > 0 )
					hue = static_cast<HUE_TYPE>(Exp_GetLLVal(ppArgs[0]));

				DWORD dwClilocId = static_cast<DWORD>(Exp_GetLLVal(ppArgs[1]));

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

				addBarkLocalized(dwClilocId, NULL, hue, TALKMODE_SYSTEM, FONT_NORMAL, sVal.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 = HUE_TEXT_DEF;
				AFFIX_TYPE affix = AFFIX_APPEND;
				if ( ATOI(ppArgs[0]) > 0 )
					hue = static_cast<HUE_TYPE>(Exp_GetLLVal(ppArgs[0]));

				DWORD dwClilocId = static_cast<DWORD>(Exp_GetLLVal(ppArgs[1]));

				if ( ppArgs[2] )
					affix = static_cast<AFFIX_TYPE>(Exp_GetLLVal(ppArgs[2]));

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

				addBarkLocalizedEx(dwClilocId, NULL, hue, TALKMODE_SYSTEM, FONT_NORMAL, affix, ppArgs[3], sVal.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");
				break;
			}
			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:
			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) )
					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;
}