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; }
bool CScriptObj::r_Verb( CScript & s, CTextConsole * pSrc ) // Execute command from script { LOCKDATA; EXC_TRY(("r_Verb('%s %s',%x)", s.GetKey(), s.GetArgStr(), pSrc)); int index; LPCTSTR pszKey = s.GetKey(); ASSERT( pSrc ); CScriptObj * pRef; if ( r_GetRef( pszKey, pRef )) { if ( pszKey[0] ) { if ( !pRef ) return true; CScript script( pszKey, s.GetArgStr()); return pRef->r_Verb( script, pSrc ); } // else just fall through. as they seem to be setting the pointer !? } if ( s.IsKeyHead( "SRC.", 4 )) { pszKey += 4; pRef = dynamic_cast <CScriptObj*> (pSrc->GetChar()); // if it can be converted . if ( ! pRef ) { pRef = dynamic_cast <CScriptObj*> (pSrc); if ( ! pRef ) return( false ); } CScript script( pszKey, s.GetArgStr()); return pRef->r_Verb( script, pSrc ); } index = FindTableSorted( s.GetKey(), sm_szVerbKeys, COUNTOF( sm_szVerbKeys )-1 ); switch (index) { case SSV_OBJ: g_World.m_uidObj = s.GetArgVal(); if ( !g_World.m_uidObj.ObjFind() ) g_World.m_uidObj = 0; return( true ); case SSV_NEW: g_World.m_uidNew = s.GetArgVal(); if ( !g_World.m_uidNew.ObjFind() ) g_World.m_uidNew = 0; return( true ); case SSV_DUMPKEYS: r_DumpLoadKeys( pSrc ); return( true ); case SSV_DUMPVERBS: r_DumpVerbKeys( pSrc ); return( true ); case SSV_SHOW: { CGString sVal; if ( ! r_WriteVal( s.GetArgStr(), sVal, pSrc )) return( false ); TCHAR *pszMsg = Str_GetTemp(); sprintf(pszMsg, "'%s' for '%s' is '%s'\n", (LPCTSTR) s.GetArgStr(), (LPCTSTR) GetName(), (LPCTSTR) sVal ); pSrc->SysMessage(pszMsg); } return( true ); case SSV_TRIGGER: { // This is effectively a goto to an alternate trigger. (for this same object) TCHAR * pszVals[2]; // CScriptTriggerArgs * pArgs = NULL ? if ( Str_ParseCmds( s.GetArgStr(), pszVals, COUNTOF(pszVals))) { TRIGRET_TYPE tRet = OnTrigger( pszVals[0], pSrc, NULL ); return( true ); } } return( false ); } return r_LoadVal( s ); // default to loading values. EXC_CATCH("CScriptObj"); return false; }
int CScriptObj::ParseText( TCHAR * pszResponse, CTextConsole * pSrc, int iFlags, CScriptTriggerArgs * pArgs ) { // Take in a line of text that may have fields that can be replaced with operators here. // ex. "SPEAK hello there my friend <SRC.NAME> my name is <NAME>" // ARGS: // iFlags = 2=Allow recusive bracket count. 1=use HTML %% as the delimiters. // NOTE: // html will have opening <script language="GRAY_FILE"> and then closing </script> // RETURN: // New length of the string. // // Parsing flags LPCTSTR pszKey; // temporary, set below bool fRes; static LPCTSTR const m_ExcKeys[] = { "too many entrances", "CALLing subfunction", "writing value", "memcpy/memmove", }; static int sm_iReentrant = 0; static bool sm_fBrackets = false; // allowed to span multi lines. if ( ! (iFlags&2)) { // DEBUG_CHECK(!sm_iReentrant); sm_fBrackets = false; } int iBegin = 0; TCHAR chBegin = '<'; TCHAR chEnd = '>'; bool fHTML = (iFlags&1); if ( fHTML ) { chBegin = '%'; chEnd = '%'; } int i; EXC_TRY(("ParseText('%s',%x,%i,%x)", pszResponse, pSrc, iFlags, pArgs)); for ( i = 0; pszResponse[i]; i++ ) { TCHAR ch = pszResponse[i]; if ( ! sm_fBrackets ) // not in brackets { if ( ch == chBegin ) // found the start ! { if ( !( isalnum( pszResponse[i+1] ) || pszResponse[i+1] == '<' ) ) // ignore this. continue; iBegin = i; sm_fBrackets = true; } continue; } if ( ch == '<' ) // recursive brackets { if ( !( isalnum( pszResponse[i+1] ) || pszResponse[i+1] == '<' ) ) // ignore this. continue; if (sm_iReentrant > 32 ) { EXC_SET(m_ExcKeys[0]); ASSERT( sm_iReentrant < 32 ); } sm_iReentrant++; sm_fBrackets = false; int ilen = ParseText( pszResponse+i, pSrc, 2, pArgs ); sm_fBrackets = true; sm_iReentrant--; i += ilen; // DEBUG_CHECK( ilen < 256 ); continue; } if ( ch == chEnd ) { sm_fBrackets = false; pszResponse[i] = '\0'; CGString sVal; pszKey = (LPCTSTR) pszResponse+iBegin+1; if ( !strnicmp( pszKey, "CALL", 4 ) && isspace(pszKey[4]) ) { EXC_SET(m_ExcKeys[1]); pszKey += 4; GETNONWHITESPACE( pszKey ); LPCTSTR pszArgs = strchr( pszKey, ' ' ); if ( pszArgs ) GETNONWHITESPACE( pszArgs ); if ( !pszArgs || !*pszArgs ) { fRes = this->r_Call( pszKey, pSrc, pArgs, &sVal ); } else { CScriptTriggerArgs Args( pszArgs ); if ( pArgs ) Args.m_VarsLocal = pArgs->m_VarsLocal; fRes = this->r_Call( pszKey, pSrc, &Args, &sVal ); if ( pArgs ) pArgs->m_VarsLocal = Args.m_VarsLocal; } } else { if ( !strnicmp( pszKey, "SRC", 3 ) && pszKey[3] == '\0' ) { pszKey = pszKey; } EXC_SET(m_ExcKeys[2]); if ( !( fRes = r_WriteVal( pszKey, sVal, pSrc ) ) ) { EXC_SET(m_ExcKeys[2]); if ( pArgs && pArgs->r_WriteVal( pszKey, sVal, pSrc ) ) fRes = true; } } if ( !fRes ) { DEBUG_ERR(( "Can't resolve <%s>\n", pszKey )); // Just in case this really is a <= operator ? pszResponse[i] = chEnd; // continue; // by Kell } resolved: if ( sVal.IsEmpty() && fHTML ) { sVal = " "; } int len = sVal.GetLength(); EXC_SET(m_ExcKeys[3]); memmove( pszResponse+iBegin+len, pszResponse+i+1, strlen( pszResponse+i+1 ) + 1 ); EXC_SET(m_ExcKeys[3]); memcpy( pszResponse+iBegin, (LPCTSTR) sVal, len ); i = iBegin+len-1; if ( iFlags&2 ) // just do this one then bail out. return( i ); } } EXC_CATCH("Script parse text"); return( i ); }
bool CScriptObj::r_WriteVal( LPCTSTR pszKey, CGString &sVal, CTextConsole * pSrc ) { EXC_TRY(("r_WriteVal('%s',,%x)", pszKey, pSrc)); CScriptObj * pRef; if ( r_GetRef( pszKey, pRef )) { if ( pRef == NULL ) // good command but bad link. { sVal = "0"; return true; } if ( pszKey[0] == '\0' ) // we where just testing the ref. { CObjBase * pObj = dynamic_cast <CObjBase *> (pRef); if ( pObj ) sVal.FormatHex( (DWORD) pObj->GetUID() ); else sVal.FormatVal( 1 ); return( true ); } return pRef->r_WriteVal( pszKey, sVal, pSrc ); } int i = FindTableHeadSorted( pszKey, sm_szLoadKeys, COUNTOF( sm_szLoadKeys )-1 ); if ( i < 0 ) { // <dSOMEVAL> same as <eval <SOMEVAL>> to get dec from the val if (( *pszKey == 'd' ) || ( *pszKey == 'D' )) { LPCTSTR arg = pszKey + 1; if ( r_WriteVal(arg, sVal, pSrc) ) { if ( !IsStrNumericDec(sVal) ) // dValue dec -> hex fix { sVal.FormatVal(ahextoi(sVal)); } return true; } } // <r>, <r15>, <r3,15> are shortcuts to rand(), rand(15) and rand(3,15) else if (( *pszKey == 'r' ) || ( *pszKey == 'R' )) { char *zTemp = Str_GetTemp(); strcpy(zTemp, pszKey+1); if (( *zTemp ) && (( *zTemp < '0' ) || ( *zTemp > '9' )) ) goto badcmd; TCHAR *ppCmd[2]; int qty = Str_ParseCmds(zTemp, ppCmd, COUNTOF(ppCmd)); int min = 0, max = 1000; if ( qty == 1 ) max = atoi(ppCmd[0]); else if ( qty == 2 ) { min = g_Exp.GetVal(ppCmd[0]); max = g_Exp.GetVal(ppCmd[1]); } if ( min > max ) { int a = min; min = max; max = a; } if ( min == max ) sVal.FormatVal(min); else sVal.FormatVal(min + Calc_GetRandVal(max - min)); return true; } badcmd: return false; // Bad command. } pszKey += strlen( sm_szLoadKeys[i] ); SKIP_SEPERATORS(pszKey); bool fZero = false; switch ( i ) { case SSC_LISTCOL: // Set the alternating color. sVal = (CWebPageDef::sm_iListIndex&1) ? "bgcolor=\"#E8E8E8\"" : ""; return( true ); case SSC_OBJ: if ( !g_World.m_uidObj.ObjFind() ) g_World.m_uidObj = 0; sVal.FormatHex((DWORD)g_World.m_uidObj); return true; case SSC_NEW: if ( !g_World.m_uidNew.ObjFind() ) g_World.m_uidNew = 0; sVal.FormatHex((DWORD)g_World.m_uidNew); return true; case SSC_SRC: if ( pSrc == NULL ) pRef = NULL; else { pRef = pSrc->GetChar(); // if it can be converted . if ( ! pRef ) pRef = dynamic_cast <CScriptObj*> (pSrc); // if it can be converted . } if ( ! pRef ) { sVal.FormatVal( 0 ); return true; } if ( !*pszKey ) { CObjBase * pObj = dynamic_cast <CObjBase*> (pRef); // if it can be converted . sVal.FormatHex( pObj ? (DWORD) pObj->GetUID() : 0 ); return true; } return pRef->r_WriteVal( pszKey, sVal, pSrc ); case SSC_VAR0: fZero = true; case SSC_VAR: // "VAR." = get/set a system wide variable. { CVarDefBase * pVar = g_Exp.m_VarGlobals.GetKey(pszKey); if ( pVar ) sVal = pVar->GetValStr(); else if ( fZero ) sVal = "0"; } return true; case SSC_DEF0: fZero = true; case SSC_DEF: { CVarDefBase * pVar = g_Exp.m_VarDefs.GetKey(pszKey); if ( pVar ) sVal = pVar->GetValStr(); else if ( fZero ) sVal = "0"; } return( true ); case SSC_EVAL: sVal.FormatVal( Exp_GetVal( pszKey )); return( true ); case SSC_FVAL: { int iVal = Exp_GetVal( pszKey ); sVal.Format( "%i.%i", iVal/10, abs(iVal%10) ); return true; } case SSC_HVAL: sVal.FormatHex( Exp_GetVal( pszKey )); return( true ); case SSC_QVAL: { // Do a switch ? type statement <QVAL conditional ? option1 : option2> TCHAR * ppCmds[3]; ppCmds[0] = const_cast<TCHAR*>(pszKey); Str_Parse( ppCmds[0], &(ppCmds[1]), "?" ); Str_Parse( ppCmds[1], &(ppCmds[2]), ":" ); sVal = ppCmds[ Exp_GetVal( ppCmds[0] ) ? 1 : 2 ]; if ( sVal.IsEmpty()) sVal = " "; } return( true ); case SSC_ISEMPTY: sVal.FormatVal( IsStrEmpty( pszKey ) ); return true; case SSC_ISNUM: GETNONWHITESPACE( pszKey ); sVal.FormatVal( IsStrNumeric( pszKey ) ); return true; case SSC_StrRev: { GETNONWHITESPACE( pszKey ); sVal = pszKey; sVal.Reverse(); return true; } case SSC_StrPos: { GETNONWHITESPACE( pszKey ); int iPos = Exp_GetVal( pszKey ); TCHAR ch; if ( isdigit( *pszKey) && isdigit( *(pszKey+1) ) ) ch = (TCHAR) Exp_GetVal( pszKey ); else { ch = *pszKey; pszKey++; } GETNONWHITESPACE( pszKey ); int iLen = strlen( pszKey ); if ( iPos < 0 ) iPos = iLen + iPos; if ( iPos < 0 ) iPos = 0; else if ( iPos > iLen ) iPos = iLen; TCHAR * pszPos = strchr( pszKey + iPos, ch ); if ( !pszPos ) sVal.FormatVal( -1 ); else sVal.FormatVal( pszPos - pszKey ); } return true; case SSC_StrSub: { int iPos = Exp_GetVal( pszKey ); int iCnt = Exp_GetVal( pszKey ); SKIP_ARGSEP( pszKey ); GETNONWHITESPACE( pszKey ); int iLen = strlen( pszKey ); if ( iPos < 0 ) iPos += iLen; if ( iPos > iLen || iPos < 0 ) iPos = 0; if ( iPos + iCnt > iLen || iCnt == 0 ) iCnt = iLen - iPos; TCHAR *buf = Str_GetTemp(); strncpy( buf, pszKey + iPos, iCnt ); buf[iCnt] = '\0'; sVal = buf; } return true; case SSC_StrArg: { TCHAR *buf = Str_GetTemp(); GETNONWHITESPACE( pszKey ); if ( *pszKey == '"' ) pszKey++; int i = 0; while ( *pszKey && !isspace( *pszKey ) && *pszKey != ',' ) { buf[i] = *pszKey; pszKey++; i++; } buf[i] = '\0'; sVal = buf; } return true; case SSC_StrEat: { GETNONWHITESPACE( pszKey ); while ( *pszKey && !isspace( *pszKey ) && *pszKey != ',' ) pszKey++; SKIP_ARGSEP( pszKey ); sVal = pszKey; } return true; case SSC_ASC: { TCHAR *buf = Str_GetTemp(); REMOVE_QUOTES( pszKey ); sVal.FormatHex( *pszKey ); sprintf( buf, sVal ); while ( *(++pszKey) ) { if ( *pszKey == '"' ) break; sVal.FormatHex( *pszKey ); strcat( buf, " " ); strcat( buf, sVal ); } sVal = buf; } return true; case SSC_READFILE: { if ( !IsSetOF( OF_FileCommands ) ) return false; TCHAR *rfArgs[1]; FILE *rfFD; TCHAR *buf = Str_GetTemp(); int line; rfArgs[0] = const_cast<TCHAR*>(pszKey); Str_Parse( rfArgs[0], &(rfArgs[1]), " " ); // Remove other junk Str_Parse( rfArgs[1], NULL, " " ); line = atoi( rfArgs[1] ); sVal = ""; if ( rfFD = fopen( rfArgs[0], "r" )) { if ( line == -1 ) // First line of the file fgets(buf, SCRIPT_MAX_LINE_LEN, rfFD ); else if ( line == 0 ) { // Last line of the file while ( ! feof( rfFD ) ) fgets(buf, SCRIPT_MAX_LINE_LEN, rfFD ); } else { // Line "line" of the file int x; for ( x = 1; x <= line; x++ ) { if ( feof(rfFD) ) { buf[0] = 0; break; } fgets(buf, SCRIPT_MAX_LINE_LEN, rfFD ); } } sVal = buf; fclose(rfFD); } } return true; case SSC_FILELINES: { if ( !IsSetOF( OF_FileCommands ) ) return false; TCHAR *buf = Str_GetTemp(); FILE *flFD; int x(0); GETNONWHITESPACE( pszKey ); if ( flFD = fopen( pszKey, "r" ) ) { while ( ! feof(flFD) ) { fgets(buf, SCRIPT_MAX_LINE_LEN, flFD ); x++; } fclose(flFD); } sVal.FormatVal(x); } return true; case SSC_SYSCMD: case SSC_SYSSPAWN: { if ( !IsSetOF(OF_FileCommands) ) return false; GETNONWHITESPACE(pszKey); TCHAR *buf = Str_GetTemp(); TCHAR *Arg_ppCmd[10]; // limit to 9 arguments strcpy(buf, pszKey); int iQty = Str_ParseCmds(buf, Arg_ppCmd, COUNTOF(Arg_ppCmd)); if ( iQty < 1 ) return false; #ifdef WIN32 _spawnl( ( i == SSC_SYSCMD ) ? _P_WAIT : _P_NOWAIT, Arg_ppCmd[0], Arg_ppCmd[0], Arg_ppCmd[1], Arg_ppCmd[2], Arg_ppCmd[3], Arg_ppCmd[4], Arg_ppCmd[5], Arg_ppCmd[6], Arg_ppCmd[7], Arg_ppCmd[8], Arg_ppCmd[9], NULL ); #else g_Log.EventError("sysspawn/syscmd is not available on unix builds." DEBUG_CR); #endif return true; } default: StringFunction( i, pszKey, sVal ); return true; } EXC_CATCH("CScriptObj"); return false; }
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; }