int CItemMulti::Ship_ListObjs( CObjBase ** ppObjList ) { // List all the objects in the structure. // Move the ship and everything on the deck // If too much stuff. then some will fall overboard. hehe. if ( ! IsTopLevel()) return 0; int iMaxDist = Multi_GetMaxDist(); // always list myself first. All other items must see my new region ! int iCount = 0; ppObjList[iCount++] = this; CWorldSearch AreaChar( GetTopPoint(), iMaxDist ); while ( iCount < MAX_MULTI_LIST_OBJS ) { CChar * pChar = AreaChar.GetChar(); if ( pChar == NULL ) break; if ( pChar->IsClient()) { pChar->GetClient()->addPause(); // get rid of flicker. for anyone even seeing this. } if ( ! m_pRegion->IsInside2d( pChar->GetTopPoint())) continue; int zdiff = pChar->GetTopZ() - GetTopZ(); if ( abs( zdiff ) > 3 ) continue; ppObjList[iCount++] = pChar; } CWorldSearch AreaItem( GetTopPoint(), iMaxDist ); while ( iCount < MAX_MULTI_LIST_OBJS ) { CItem * pItem = AreaItem.GetItem(); if ( pItem == NULL ) break; if ( pItem == this ) // already listed. continue; if ( ! Multi_IsPartOf( pItem )) { if ( ! m_pRegion->IsInside2d( pItem->GetTopPoint())) continue; if ( ! pItem->IsMovable()) continue; int zdiff = pItem->GetTopZ() - GetTopZ(); if ( abs( zdiff ) > 3 ) continue; } ppObjList[iCount++] = pItem; } return( iCount ); }
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; }
void CWorld::GetFixPoint( const CPointMap & pt, CGrayMapBlockState & block) { //Will get the highest CAN_I_PLATFORM|CAN_I_CLIMB and places it into block.Bottom ADDTOCALLSTACK("CWorld::GetFixPoint"); CItemBase * pItemDef = NULL; CItemBaseDupe * pDupeDef = NULL; CItem * pItem = NULL; DWORD wBlockThis = 0; signed char z = 0; int x2 = 0, y2 = 0; // Height of statics at/above given coordinates // do gravity here for the z. const CGrayMapBlock * pMapBlock = GetMapBlock( pt ); if (pMapBlock == NULL) return; size_t iQty = pMapBlock->m_Statics.GetStaticQty(); if ( iQty > 0 ) // no static items here. { x2 = pMapBlock->GetOffsetX(pt.m_x); y2 = pMapBlock->GetOffsetY(pt.m_y); const CUOStaticItemRec * pStatic = NULL; for ( size_t i = 0; i < iQty; ++i, z = 0, pStatic = NULL, pDupeDef = NULL ) { if ( ! pMapBlock->m_Statics.IsStaticPoint( i, x2, y2 )) continue; pStatic = pMapBlock->m_Statics.GetStatic( i ); if ( pStatic == NULL ) continue; z = pStatic->m_z; pItemDef = CItemBase::FindItemBase( pStatic->GetDispID() ); if ( pItemDef ) { if (pItemDef->GetID() == pStatic->GetDispID()) //parent item { wBlockThis = (pItemDef->m_Can & CAN_I_MOVEMASK); z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight()); } else //non-parent item { pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pStatic->GetDispID())); if ( ! pDupeDef ) { g_Log.EventDebug("Failed to get non-parent reference (static) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pStatic->GetDispID(),pStatic->m_x+pMapBlock->m_x,pStatic->m_y+pMapBlock->m_y,pStatic->m_z); wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight()); } else { wBlockThis = (pDupeDef->m_Can & CAN_I_MOVEMASK); z += ((wBlockThis & CAN_I_CLIMB) ? pDupeDef->GetHeight()/2 : pDupeDef->GetHeight()); } } } else if ( pStatic->GetDispID() ) CItemBase::GetItemTiledataFlags(wBlockThis,pStatic->GetDispID()); if (block.m_Bottom.m_z < z) { if ((z < pt.m_z+PLAYER_HEIGHT) && (wBlockThis & (CAN_I_PLATFORM|CAN_I_CLIMB|CAN_I_WATER))) { block.m_Bottom.m_dwBlockFlags = wBlockThis; block.m_Bottom.m_dwTile = pStatic->GetDispID() + TERRAIN_QTY; block.m_Bottom.m_z = z; } else if (block.m_Top.m_z > z) { block.m_Top.m_dwBlockFlags = wBlockThis; block.m_Top.m_dwTile = pStatic->GetDispID() + TERRAIN_QTY; block.m_Top.m_z = z; } } } } pItemDef = NULL; pDupeDef = NULL; pItem = NULL; wBlockThis = 0; z = 0; x2 = y2 = 0; iQty = 0; // Any multi items here ? // Check all of them CRegionLinks rlinks; size_t iRegionQty = pt.GetRegions( REGION_TYPE_MULTI, rlinks ); if ( iRegionQty > 0 ) { // ------------ For variables -------------------- CRegionBase * pRegion = NULL; const CGrayMulti * pMulti = NULL; const CUOMultiItemRec2 * pMultiItem = NULL; x2 = 0; y2 = 0; // ------------ For variables -------------------- for ( size_t iRegion = 0; iRegion < iRegionQty; ++iRegion, pRegion = NULL, pItem = NULL, pMulti = NULL, x2 = 0, y2 = 0 ) { pRegion = rlinks.GetAt(iRegion); if ( pRegion != NULL ) pItem = pRegion->GetResourceID().ItemFind(); if ( pItem != NULL ) { pMulti = g_Cfg.GetMultiItemDefs(pItem); if ( pMulti ) { x2 = pt.m_x - pItem->GetTopPoint().m_x; y2 = pt.m_y - pItem->GetTopPoint().m_y; iQty = pMulti->GetItemCount(); for ( size_t ii = 0; ii < iQty; ++ii, pMultiItem = NULL, z = 0 ) { pMultiItem = pMulti->GetItem(ii); if ( !pMultiItem ) break; if ( ! pMultiItem->m_visible ) continue; if ( pMultiItem->m_dx != x2 || pMultiItem->m_dy != y2 ) continue; z = static_cast<signed char>(pItem->GetTopZ() + pMultiItem->m_dz); pItemDef = CItemBase::FindItemBase( pMultiItem->GetDispID() ); if ( pItemDef != NULL ) { if ( pItemDef->GetID() == pMultiItem->GetDispID() ) //parent item { wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight()); } else //non-parent item { pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pMultiItem->GetDispID())); if ( pDupeDef == NULL ) { g_Log.EventDebug("Failed to get non-parent reference (multi) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pMultiItem->GetDispID(),pMultiItem->m_dx+pItem->GetTopPoint().m_x,pMultiItem->m_dy+pItem->GetTopPoint().m_y,pMultiItem->m_dz+pItem->GetTopPoint().m_z); wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight()); } else { wBlockThis = ( pDupeDef->m_Can & CAN_I_MOVEMASK ); z += ((wBlockThis & CAN_I_CLIMB) ? pDupeDef->GetHeight()/2 : pDupeDef->GetHeight()); } } } else if ( pMultiItem->GetDispID() ) CItemBase::GetItemTiledataFlags(wBlockThis,pMultiItem->GetDispID()); if (block.m_Bottom.m_z < z) { if ((z < pt.m_z+PLAYER_HEIGHT) && (wBlockThis & (CAN_I_PLATFORM|CAN_I_CLIMB|CAN_I_WATER))) { block.m_Bottom.m_dwBlockFlags = wBlockThis; block.m_Bottom.m_dwTile = pMultiItem->GetDispID() + TERRAIN_QTY; block.m_Bottom.m_z = z; } else if (block.m_Top.m_z > z) { block.m_Top.m_dwBlockFlags = wBlockThis; block.m_Top.m_dwTile = pMultiItem->GetDispID() + TERRAIN_QTY; block.m_Top.m_z = z; } } } } } } } pItemDef = NULL; pDupeDef = NULL; pItem = NULL; wBlockThis = 0; x2 = y2 = iQty = 0; z = 0; // Any dynamic items here ? // NOTE: This could just be an item that an NPC could just move ? CWorldSearch Area( pt ); for (;;) { pItem = Area.GetItem(); if ( !pItem ) break; z = pItem->GetTopZ(); // Invis items should not block ??? pItemDef = CItemBase::FindItemBase( pItem->GetDispID() ); if ( pItemDef ) { if ( pItemDef->GetDispID() == pItem->GetDispID() )//parent item { wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight()); } else //non-parent item { pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pItem->GetDispID())); if ( ! pDupeDef ) { g_Log.EventDebug("Failed to get non-parent reference (dynamic) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pItem->GetDispID(),pItem->GetTopPoint().m_x,pItem->GetTopPoint().m_y,pItem->GetTopPoint().m_z); wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); z += ((wBlockThis & CAN_I_CLIMB) ? pItemDef->GetHeight()/2 : pItemDef->GetHeight()); } else { wBlockThis = ( pDupeDef->m_Can & CAN_I_MOVEMASK ); z += ((wBlockThis & CAN_I_CLIMB) ? pDupeDef->GetHeight()/2 : pDupeDef->GetHeight()); } } if ( block.m_Bottom.m_z < z ) { if ( (z < pt.m_z + PLAYER_HEIGHT) && (wBlockThis & (CAN_I_PLATFORM|CAN_I_CLIMB|CAN_I_WATER)) ) { block.m_Bottom.m_dwBlockFlags = wBlockThis; block.m_Bottom.m_dwTile = pItemDef->GetDispID() + TERRAIN_QTY; block.m_Bottom.m_z = z; } else if ( block.m_Top.m_z > z ) { block.m_Top.m_dwBlockFlags = wBlockThis; block.m_Top.m_dwTile = pItemDef->GetDispID() + TERRAIN_QTY; block.m_Top.m_z = z; } } } else if (pItem->GetDispID()) CItemBase::GetItemTiledataFlags(wBlockThis,pItem->GetDispID()); } wBlockThis = 0; // Terrain height is screwed. Since it is related to all the terrain around it. const CUOMapMeter * pMeter = pMapBlock->GetTerrain( UO_BLOCK_OFFSET(pt.m_x), UO_BLOCK_OFFSET(pt.m_y)); if ( ! pMeter ) return; if ( pMeter->m_wTerrainIndex == TERRAIN_HOLE ) { wBlockThis = 0; } else if ( CUOMapMeter::IsTerrainNull( pMeter->m_wTerrainIndex ) ) // inter dungeon type. { wBlockThis = CAN_I_BLOCK; } else { CGrayTerrainInfo land( pMeter->m_wTerrainIndex ); //DEBUG_ERR(("Terrain flags - land.m_flags 0%x wBlockThis (0%x)\n",land.m_flags,wBlockThis)); if ( land.m_flags & UFLAG1_WATER ) wBlockThis |= CAN_I_WATER; if ( land.m_flags & UFLAG1_DAMAGE ) wBlockThis |= CAN_I_FIRE; if ( land.m_flags & UFLAG1_BLOCK ) wBlockThis |= CAN_I_BLOCK; if (( ! wBlockThis ) || ( land.m_flags & UFLAG2_PLATFORM )) // Platform items should take precendence over non-platforms. wBlockThis = CAN_I_PLATFORM; } if (block.m_Bottom.m_z < pMeter->m_z) { if (((pMeter->m_z < pt.m_z+PLAYER_HEIGHT) && (wBlockThis & (CAN_I_PLATFORM|CAN_I_CLIMB|CAN_I_WATER))) || (block.m_Bottom.m_z == UO_SIZE_MIN_Z)) { block.m_Bottom.m_dwBlockFlags = wBlockThis; block.m_Bottom.m_dwTile = pMeter->m_wTerrainIndex; block.m_Bottom.m_z = pMeter->m_z; } else if (block.m_Top.m_z > pMeter->m_z) { block.m_Top.m_dwBlockFlags = wBlockThis; block.m_Top.m_dwTile = pMeter->m_wTerrainIndex; block.m_Top.m_z = pMeter->m_z; } } if ( block.m_Bottom.m_z == UO_SIZE_MIN_Z ) { //Fail safe... Reset to 0z with no top block; block.m_Bottom.m_dwBlockFlags = 0; block.m_Bottom.m_dwTile = 0; block.m_Bottom.m_z = 0; block.m_Top.m_dwBlockFlags = 0; block.m_Top.m_dwTile = 0; block.m_Top.m_z = UO_SIZE_Z; } }
void CWorld::GetHeightPoint( const CPointMap & pt, CGrayMapBlockState & block, bool fHouseCheck ) { ADDTOCALLSTACK("CWorld::GetHeightPoint"); CItemBase * pItemDef = NULL; CItemBaseDupe * pDupeDef = NULL; CItem * pItem = NULL; DWORD wBlockThis = 0; signed char z = 0; height_t zHeight = 0; int x2 = 0, y2 = 0; // Height of statics at/above given coordinates // do gravity here for the z. const CGrayMapBlock * pMapBlock = GetMapBlock( pt ); if (pMapBlock == NULL) return; size_t iQty = pMapBlock->m_Statics.GetStaticQty(); if ( iQty > 0 ) // no static items here. { x2 = pMapBlock->GetOffsetX(pt.m_x); y2 = pMapBlock->GetOffsetY(pt.m_y); const CUOStaticItemRec * pStatic = NULL; for ( size_t i = 0; i < iQty; ++i, z = 0, zHeight = 0, pStatic = NULL, pDupeDef = NULL ) { if ( ! pMapBlock->m_Statics.IsStaticPoint( i, x2, y2 )) continue; pStatic = pMapBlock->m_Statics.GetStatic( i ); if ( pStatic == NULL ) continue; z = pStatic->m_z; //DEBUG_ERR(("z (%d) block.m_zHeight (%d) block.m_Bottom.m_z (%d)\n",z,block.m_zHeight,block.m_Bottom.m_z)); if ( ! block.IsUsableZ( z, block.m_zHeight )) continue; // This static is at the coordinates in question. // enough room for me to stand here ? pItemDef = CItemBase::FindItemBase( pStatic->GetDispID() ); if ( pItemDef ) { //DEBUG_ERR(("pItemDef->GetID(0%x) pItemDef->GetDispID(0%x) pStatic->GetDispID(0%x)\n",pItemDef->GetID(),pItemDef->GetDispID(),pStatic->GetDispID())); if ( pItemDef->GetID() == pStatic->GetDispID() ) //parent item { zHeight = pItemDef->GetHeight(); wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove } else //non-parent item { pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pStatic->GetDispID())); if ( ! pDupeDef ) { g_Log.EventDebug("Failed to get non-parent reference (static) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pStatic->GetDispID(),pStatic->m_x+pMapBlock->m_x,pStatic->m_y+pMapBlock->m_y,pStatic->m_z); zHeight = pItemDef->GetHeight(); wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); } else { zHeight = pDupeDef->GetHeight(); wBlockThis = ( pDupeDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove - CAN flags cannot be inherited from the parent item due to bad script pack... } } } else if ( pStatic->GetDispID() ) CItemBase::GetItemTiledataFlags(wBlockThis,pStatic->GetDispID()); block.CheckTile_Item( wBlockThis, z, zHeight, pStatic->GetDispID() + TERRAIN_QTY ); } } pItemDef = NULL; pDupeDef = NULL; pItem = NULL; wBlockThis = 0; z = 0; zHeight = 0; x2 = y2 = 0; iQty = 0; // Any multi items here ? // Check all of them if ( fHouseCheck ) { CRegionLinks rlinks; size_t iRegionQty = pt.GetRegions( REGION_TYPE_MULTI, rlinks ); if ( iRegionQty > 0 ) { // ------------ For variables -------------------- CRegionBase * pRegion = NULL; const CGrayMulti * pMulti = NULL; const CUOMultiItemRec2 * pMultiItem = NULL; x2 = 0; y2 = 0; // ------------ For variables -------------------- for ( size_t iRegion = 0; iRegion < iRegionQty; ++iRegion, pRegion = NULL, pItem = NULL, pMulti = NULL, x2 = 0, y2 = 0 ) { pRegion = rlinks.GetAt(iRegion); if ( pRegion != NULL ) pItem = pRegion->GetResourceID().ItemFind(); if ( pItem != NULL ) { pMulti = g_Cfg.GetMultiItemDefs(pItem); if ( pMulti ) { x2 = pt.m_x - pItem->GetTopPoint().m_x; y2 = pt.m_y - pItem->GetTopPoint().m_y; iQty = pMulti->GetItemCount(); for ( size_t ii = 0; ii < iQty; ++ii, pMultiItem = NULL, z = 0, zHeight = 0 ) { pMultiItem = pMulti->GetItem(ii); if ( !pMultiItem ) break; if ( ! pMultiItem->m_visible ) continue; if ( pMultiItem->m_dx != x2 || pMultiItem->m_dy != y2 ) continue; z = static_cast<signed char>( pItem->GetTopZ() + pMultiItem->m_dz ); if ( ! block.IsUsableZ(z,block.m_zHeight)) continue; pItemDef = CItemBase::FindItemBase( pMultiItem->GetDispID() ); if ( pItemDef != NULL ) { if ( pItemDef->GetID() == pMultiItem->GetDispID() ) //parent item { zHeight = pItemDef->GetHeight(); wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove } else //non-parent item { pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pMultiItem->GetDispID())); if ( pDupeDef == NULL ) { g_Log.EventDebug("Failed to get non-parent reference (multi) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pMultiItem->GetDispID(),pMultiItem->m_dx+pItem->GetTopPoint().m_x,pMultiItem->m_dy+pItem->GetTopPoint().m_y,pMultiItem->m_dz+pItem->GetTopPoint().m_z); zHeight = pItemDef->GetHeight(); wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); } else { zHeight = pDupeDef->GetHeight(); wBlockThis = ( pDupeDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove - CAN flags cannot be inherited from the parent item due to bad script pack... } } } else if ( pMultiItem->GetDispID() ) CItemBase::GetItemTiledataFlags(wBlockThis,pMultiItem->GetDispID()); block.CheckTile_Item( wBlockThis, z, zHeight, pMultiItem->GetDispID() + TERRAIN_QTY ); } } } } } } pItemDef = NULL; pDupeDef = NULL; pItem = NULL; wBlockThis = 0; x2 = y2 = iQty = 0; zHeight = 0; z = 0; // Any dynamic items here ? // NOTE: This could just be an item that an NPC could just move ? CWorldSearch Area( pt ); for (;;) { pItem = Area.GetItem(); if ( !pItem ) break; z = pItem->GetTopZ(); if ( !block.IsUsableZ( z, block.m_zHeight ) ) continue; // Invis items should not block ??? pItemDef = CItemBase::FindItemBase( pItem->GetDispID() ); if ( pItemDef ) { if ( pItemDef->GetDispID() == pItem->GetDispID() )//parent item { zHeight = pItemDef->GetHeight(); wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove } else //non-parent item { pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pItem->GetDispID())); if ( ! pDupeDef ) { g_Log.EventDebug("Failed to get non-parent reference (dynamic) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pItem->GetDispID(),pItem->GetTopPoint().m_x,pItem->GetTopPoint().m_y,pItem->GetTopPoint().m_z); zHeight = pItemDef->GetHeight(); wBlockThis = ( pItemDef->m_Can & CAN_I_MOVEMASK ); } else { zHeight = pDupeDef->GetHeight(); wBlockThis = ( pDupeDef->m_Can & CAN_I_MOVEMASK ); //Use only Block flags, other remove - CAN flags cannot be inherited from the parent item due to bad script pack... } } } else if (pItem->GetDispID()) CItemBase::GetItemTiledataFlags(wBlockThis,pItem->GetDispID()); block.CheckTile_Item(wBlockThis, z, zHeight, pItem->GetDispID() + TERRAIN_QTY); } wBlockThis = 0; // Terrain height is screwed. Since it is related to all the terrain around it. const CUOMapMeter * pMeter = pMapBlock->GetTerrain( UO_BLOCK_OFFSET(pt.m_x), UO_BLOCK_OFFSET(pt.m_y)); if ( ! pMeter ) return; if ( block.IsUsableZ( pMeter->m_z,block.m_zHeight ) ) { //DEBUG_ERR(("pMeter->m_wTerrainIndex 0%x wBlockThis (0%x)\n",pMeter->m_wTerrainIndex,wBlockThis)); if ( pMeter->m_wTerrainIndex == TERRAIN_HOLE ) { wBlockThis = 0; } else if ( CUOMapMeter::IsTerrainNull( pMeter->m_wTerrainIndex ) ) // inter dungeon type. { wBlockThis = CAN_I_BLOCK; } else { CGrayTerrainInfo land( pMeter->m_wTerrainIndex ); //DEBUG_ERR(("Terrain flags - land.m_flags 0%x wBlockThis (0%x)\n",land.m_flags,wBlockThis)); if ( land.m_flags & UFLAG1_WATER ) wBlockThis |= CAN_I_WATER; if ( land.m_flags & UFLAG1_DAMAGE ) wBlockThis |= CAN_I_FIRE; if ( land.m_flags & UFLAG1_BLOCK ) wBlockThis |= CAN_I_BLOCK; if (( ! wBlockThis ) || ( land.m_flags & UFLAG2_PLATFORM )) // Platform items should take precendence over non-platforms. wBlockThis = CAN_I_PLATFORM; } //DEBUG_ERR(("TERRAIN wBlockThis (0%x)\n",wBlockThis)); block.CheckTile_Terrain( wBlockThis, pMeter->m_z, pMeter->m_wTerrainIndex ); } if ( block.m_Bottom.m_z == UO_SIZE_MIN_Z ) { block.m_Bottom = block.m_Lowest; if ( block.m_Top.m_z == block.m_Bottom.m_z ) { block.m_Top.m_dwBlockFlags = 0; block.m_Top.m_dwTile = 0; block.m_Top.m_z = UO_SIZE_Z; } } }
CPointMap CWorld::FindTypeNear_Top( const CPointMap & pt, IT_TYPE iType, int iDistance ) { ADDTOCALLSTACK("CWorld::FindTypeNear_Top"); #define RESOURCE_Z_CHECK 8 CPointMap ptFound; CItemBase * pItemDef = NULL; CItem * pItem = NULL; CItemBaseDupe * pDupeDef = NULL; height_t Height = 0; BYTE z = 0; CPointMap ptTest; unsigned int iRetElem = 4; CPointMap ptElem[5]; memset(ptElem, 0, sizeof(ptElem)); //for ( iQty = 0; iQty < 4; ++iQty ) // ptElem[iQty].m_z = UO_SIZE_MIN_Z; ptElem[0].m_z = ptElem[1].m_z = ptElem[2].m_z = ptElem[3].m_z = UO_SIZE_MIN_Z; ptElem[4] = CPointMap(USHRT_MAX, USHRT_MAX, UO_SIZE_MIN_Z); bool fElem[4] = { false, false, false, false }; // Check dynamics CWorldSearch Area( pt, iDistance ); Area.SetAllShow( true ); for (;;) { z = 0; Height = 0; pItem = Area.GetItem(); if ( pItem == NULL ) break; if ( pt.GetDist( pItem->GetTopPoint() ) > iDistance ) continue; pItemDef = CItemBase::FindItemBase( pItem->GetDispID() ); if ( pItemDef == NULL ) continue; Height = pItemDef->GetHeight(); if ( pItemDef->GetID() != pItem->GetDispID() ) //not a parent item { pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pItem->GetDispID())); if ( ! pDupeDef ) { g_Log.EventDebug("Failed to get non-parent reference (dynamic) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pItem->GetDispID(),ptTest.m_x,ptTest.m_y,ptTest.m_z); Height = pItemDef->GetHeight(); } else Height = pDupeDef->GetHeight(); } z = minimum( Height + pItem->GetTopPoint().m_z, UO_SIZE_Z ); //height + current position = the top point if ( ptElem[0].m_z > z ) //if ( ptElem[0].m_z > pItem->GetTopPoint().m_z ) continue; if ( ((( z - pt.m_z ) > 0) && ( z - pt.m_z ) > RESOURCE_Z_CHECK ) || ((( pt.m_z - z ) < 0) && (( pt.m_z - z ) < - RESOURCE_Z_CHECK ))) //if ( ((( pItem->GetTopPoint().m_z - pt.m_z ) > 0) && ( pItem->GetTopPoint().m_z - pt.m_z ) > RESOURCE_Z_CHECK ) || ((( pt.m_z - pItem->GetTopPoint().m_z ) < 0) && (( pt.m_z - pItem->GetTopPoint().m_z ) < - RESOURCE_Z_CHECK ))) continue; if (( z < ptElem[0].m_z ) || (( z == ptElem[0].m_z ) && ( fElem[0] ))) continue; ptElem[0] = pItem->GetTopPoint(); ptElem[0].m_z = z; fElem[0] = false; //DEBUG_ERR(("dynamic pItem->IsType( iType %d) %d\n",iType,pItem->IsType( iType ))); if ( pItem->IsType( iType ) ) //( pItem->Item_GetDef()->IsType(iType) ) ) { fElem[0] = true; iRetElem = 0; } } // Parts of multis ? const CGrayMulti * pMulti = NULL; // Multi Def (multi check) const CUOMultiItemRec2 * pMultiItem = NULL; // Multi item iterator CRegionBase * pRegion = NULL; CRegionLinks rlinks; size_t iRegionQty = pt.GetRegions( REGION_TYPE_MULTI, rlinks ); if ( iRegionQty > 0 ) { for ( size_t iRegion = 0; iRegion < iRegionQty; pMulti = NULL, ++iRegion) { pRegion = rlinks.GetAt(iRegion); pItem = pRegion->GetResourceID().ItemFind(); if ( !pItem ) continue; pMulti = g_Cfg.GetMultiItemDefs(pItem); if ( !pMulti ) continue; size_t iMultiQty = pMulti->GetItemCount(); for ( size_t iMulti = 0; iMulti < iMultiQty; pItemDef = NULL, pMultiItem = NULL, Height = 0, ++iMulti ) { pMultiItem = pMulti->GetItem(iMulti); if ( !pMultiItem ) break; //DEBUG_ERR(("abs( pMultiItem->m_dx ) %x, abs( pMultiItem->m_dy ) %x, abs( pMultiItem->m_dz ) %x,\n iDistance %x IF STATEMENT %x %x\n", abs( pMultiItem->m_dx ), abs( pMultiItem->m_dy ), abs( pMultiItem->m_dz ), iDistance, ( abs( pMultiItem->m_dx ) <= iDistance ), ( abs( pMultiItem->m_dy ) <= iDistance ) )); if ( !pMultiItem->m_visible ) continue; ptTest = CPointMap( pMultiItem->m_dx + pt.m_x, pMultiItem->m_dy + pt.m_y, static_cast<signed char>( pMultiItem->m_dz + pt.m_z ), pt.m_map ); pItemDef = CItemBase::FindItemBase( pMultiItem->GetDispID() ); if ( pItemDef == NULL ) continue; Height = pItemDef->GetHeight(); if ( pItemDef->GetID() != pMultiItem->GetDispID() ) //not a parent item { pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pMultiItem->GetDispID())); if ( ! pDupeDef ) { g_Log.EventDebug("Failed to get non-parent reference (multi) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pMultiItem->GetDispID(),ptTest.m_x,ptTest.m_y,ptTest.m_z); Height = pItemDef->GetHeight(); } else Height = pDupeDef->GetHeight(); } ptTest.m_z = minimum(ptTest.m_z + Height, UO_SIZE_Z); //height + current position = the top point if ( pt.GetDist( ptTest ) > iDistance ) continue; if ( ptElem[1].m_z > ptTest.m_z ) continue; if ( ((( ptTest.m_z - pt.m_z ) > 0) && ( ptTest.m_z - pt.m_z ) > RESOURCE_Z_CHECK ) || ((( pt.m_z - ptTest.m_z ) < 0) && (( pt.m_z - ptTest.m_z ) < - RESOURCE_Z_CHECK ))) continue; if (( ptTest.m_z < ptElem[1].m_z ) || (( ptTest.m_z == ptElem[1].m_z ) && ( fElem[1] ))) continue; //DEBUG_ERR(("pMultiItem->GetDispID()%x\n",pMultiItem->GetDispID())); ptElem[1] = ptTest; fElem[1] = false; //DEBUG_ERR(("multi pItemDef->IsType( iType %d) %d\n",iType,pItemDef->IsType( iType ))); if ( pItemDef->IsType( iType ) ) { fElem[1] = true; //if ( ptElem[iRetElem].m_z > ptElem[1].m_z ) if ( ptElem[1].m_z > ptElem[iRetElem].m_z ) iRetElem = 1; } //DEBUG_ERR(( "DISPID: %x X %d Y %d Z %d\n", pMultiItem->GetDispID(), (pMultiItem->m_dx), (pMultiItem->m_dy), (pMultiItem->m_dz) )); } } } // STATIC - checks one 8x8 block const CGrayMapBlock * pMapBlock = GetMapBlock( pt ); ASSERT( pMapBlock ); size_t iStaticQty = pMapBlock->m_Statics.GetStaticQty(); if ( iStaticQty > 0 ) // no static items here. { const CUOStaticItemRec * pStatic = NULL; for ( size_t i = 0; i < iStaticQty; ++i, pStatic = NULL, Height = 0, pItemDef = NULL ) { pStatic = pMapBlock->m_Statics.GetStatic( i ); ptTest = CPointMap( pStatic->m_x + pMapBlock->m_x, pStatic->m_y + pMapBlock->m_y, pStatic->m_z, pt.m_map ); pItemDef = CItemBase::FindItemBase( pStatic->GetDispID() ); if ( pItemDef == NULL ) continue; //DEBUG_ERR(("pStatic->GetDispID() %d; name %s; pStatic->m_z %d\n",pStatic->GetDispID(),pItemDef->GetName(),pStatic->m_z)); Height = pItemDef->GetHeight(); if ( pItemDef->GetID() != pStatic->GetDispID() ) //not a parent item { pDupeDef = CItemBaseDupe::GetDupeRef(static_cast<ITEMID_TYPE>(pStatic->GetDispID())); if ( ! pDupeDef ) { g_Log.EventDebug("Failed to get non-parent reference (static) (DispID 0%x) (X: %d Y: %d Z: %d)\n",pStatic->GetDispID(),ptTest.m_x,ptTest.m_y,ptTest.m_z); Height = pItemDef->GetHeight(); } else Height = pDupeDef->GetHeight(); } ptTest.m_z = minimum(ptTest.m_z + Height, UO_SIZE_Z); //height + current position = the top point if ( pt.GetDist( ptTest ) > iDistance ) continue; if ( pt.GetDist( ptTest ) > iDistance ) continue; //if ( ptElem[2].m_z > pStatic->m_z ) if ( ptElem[2].m_z > ptTest.m_z ) continue; if ( ((( pStatic->m_z - pt.m_z ) > 0) && ( pStatic->m_z - pt.m_z ) > RESOURCE_Z_CHECK ) || ((( pt.m_z - pStatic->m_z ) < 0) && (( pt.m_z - pStatic->m_z ) < - RESOURCE_Z_CHECK ))) continue; if (( ptTest.m_z < ptElem[2].m_z ) || (( ptTest.m_z == ptElem[2].m_z ) && ( fElem[2] ))) continue; ptElem[2] = ptTest; fElem[2] = false; //DEBUG_ERR(("static pItemDef->IsType( iType %d) %d;pItemDef->GetType() %d;pItemDef->GetID() %d;pItemDef->GetDispID() %d\n",iType,pItemDef->IsType( iType ),pItemDef->GetType(),pItemDef->GetID(),pItemDef->GetDispID())); if ( pItemDef->IsType( iType ) ) { //DEBUG_ERR(("found %d; ptTest: %d,%d,%d\n",__LINE__,ptTest.m_x,ptTest.m_y,ptTest.m_z)); fElem[2] = true; //DEBUG_ERR(("ptElem[iRetElem].m_z %d, ptElem[2].m_z %d\n",ptElem[iRetElem].m_z,ptElem[2].m_z)); //if ( ptElem[iRetElem].m_z > ptElem[2].m_z ) if ( ptElem[2].m_z > ptElem[iRetElem].m_z ) iRetElem = 2; } } } // Check for appropriate terrain type CRectMap rect; rect.SetRect( pt.m_x - iDistance, pt.m_y - iDistance, pt.m_x + iDistance + 1, pt.m_y + iDistance + 1, pt.m_map); const CUOMapMeter * pMeter = NULL; for ( int x = rect.m_left; x < rect.m_right; ++x, pMeter = NULL ) { for ( int y = rect.m_top; y < rect.m_bottom; ++y, pMeter = NULL ) { ptTest = CPointMap(static_cast<WORD>(x), static_cast<WORD>(y), pt.m_z, pt.m_map); pMeter = GetMapMeter(ptTest); if ( !pMeter ) continue; if ( pt.GetDist( ptTest ) > iDistance ) continue; if ( ptElem[3].m_z > pMeter->m_z ) continue; //DEBUG_ERR(("(( pMeter->m_z (%d) - pt.m_z (%d) ) > 0) && ( pMeter->m_z (%d) - pt.m_z (%d) ) > RESOURCE_Z_CHECK (%d) >> %d\n",pMeter->m_z,pt.m_z,pMeter->m_z,pt.m_z,RESOURCE_Z_CHECK,(( pMeter->m_z - pt.m_z ) > 0) && ( pMeter->m_z - pt.m_z ) > RESOURCE_Z_CHECK)); //DEBUG_ERR(("(( pt.m_z (%d) - pMeter->m_z (%d) ) < 0) && (( pt.m_z (%d) - pMeter->m_z (%d) ) < - RESOURCE_Z_CHECK (%d) )) >> %d\n",pt.m_z,pMeter->m_z,pt.m_z,pMeter->m_z,- RESOURCE_Z_CHECK,((( pt.m_z - pMeter->m_z ) < 0) && (( pt.m_z - pMeter->m_z ) < - RESOURCE_Z_CHECK )))); if ( ((( pMeter->m_z - pt.m_z ) > 0) && ( pMeter->m_z - pt.m_z ) > RESOURCE_Z_CHECK ) || ((( pt.m_z - pMeter->m_z ) < 0) && (( pt.m_z - pMeter->m_z ) < - RESOURCE_Z_CHECK ))) continue; //DEBUG_ERR(("pMeter->m_z (%d) < ptElem[3].m_z (%d) >> %d\n",pMeter->m_z,ptElem[3].m_z,pMeter->m_z < ptElem[3].m_z)); if (( pMeter->m_z < ptElem[3].m_z ) || (( pMeter->m_z == ptElem[3].m_z ) && ( fElem[3] ))) continue; ptElem[3] = ptTest; fElem[3] = false; //DEBUG_ERR(("iType %x, TerrainType %x\n",iType,g_World.GetTerrainItemType( pMeter->m_wTerrainIndex ))); if ( iType == g_World.GetTerrainItemType( pMeter->m_wTerrainIndex ) ) { fElem[3] = true; //if ( ptElem[iRetElem].m_z > ptElem[3].m_z ) //DEBUG_ERR(("ptElem[3].m_z %d; ptElem[iRetElem].m_z %d\n",ptElem[3].m_z, ptElem[iRetElem].m_z)); if ( ptElem[3].m_z > ptElem[iRetElem].m_z ) iRetElem = 3; //DEBUG_ERR(("fElem3 %d %d\n",ptElem[3].m_z, fElem[3])); continue; } rect.SetRect( pt.m_x - iDistance, pt.m_y - iDistance, pt.m_x + iDistance + 1, pt.m_y + iDistance + 1, pt.m_map); } } /*CPointMap a; a.m_z = maximum( // priority dynamic->multi->static->terrain int iRetElem; if (( ptElem[0].m_z >= ptElem[1].m_z ) && ( fElem[0] )) iRetElem = 0; else if (( ptElem[1].m_z >= ptElem[2].m_z ) && ( fElem[1] )) iRetElem = 1; else if (( ptElem[2].m_z >= ptElem[3].m_z ) && ( fElem[2] )) iRetElem = 2; else if ( fElem[3] ) iRetElem = 3; else iRetElem = 4;*/ ASSERT(iRetElem < COUNTOF(ptElem)); if ( 0 != iRetElem && ptElem[0].m_z > ptElem[iRetElem].m_z ) iRetElem = 4; else if ( 1 != iRetElem && ptElem[1].m_z > ptElem[iRetElem].m_z ) iRetElem = 4; else if ( 2 != iRetElem && ptElem[2].m_z > ptElem[iRetElem].m_z ) iRetElem = 4; else if ( 3 != iRetElem && ptElem[3].m_z > ptElem[iRetElem].m_z ) iRetElem = 4; //DEBUG_ERR(("iRetElem %d; %d %d %d %d; %d %d %d ISVALID: %d\n",iRetElem,ptElem[1].m_z,ptElem[2].m_z,ptElem[3].m_z,ptElem[4].m_z,pt.m_x,pt.m_y,pt.m_z,ptElem[iRetElem].IsValidPoint())); //DEBUG_ERR(("X: %d Y: %d Z: %d\n",ptElem[iRetElem].m_x,ptElem[iRetElem].m_y,ptElem[iRetElem].m_z)); return ( ptElem[iRetElem] ); #undef RESOURCE_Z_CHECK }
CPointMap CWorld::FindItemTypeNearby(const CPointMap & pt, IT_TYPE iType, int iDistance, bool bCheckMulti, bool bLimitZ) { ADDTOCALLSTACK("CWorld::FindItemTypeNearby"); // Find the closest item of this type. // This does not mean that i can touch it. // ARGS: // iDistance = 2d distance to search. CPointMap ptFound; int iTestDistance; // Check dynamics first since they are the easiest. CWorldSearch Area( pt, iDistance ); for (;;) { CItem * pItem = Area.GetItem(); if ( pItem == NULL ) break; if ( ! pItem->IsType( iType ) && ! pItem->Item_GetDef()->IsType(iType) ) continue; if ( bLimitZ && ( pItem->GetTopPoint().m_z != pt.m_z )) continue; iTestDistance = pt.GetDist(pItem->GetTopPoint()); if ( iTestDistance > iDistance ) continue; ptFound = pItem->GetTopPoint(); iDistance = iTestDistance; // tighten up the search. if ( ! iDistance ) return( ptFound ); } // Check for appropriate terrain type CRectMap rect; rect.SetRect( pt.m_x - iDistance, pt.m_y - iDistance, pt.m_x + iDistance + 1, pt.m_y + iDistance + 1, pt.m_map); const CUOMapMeter * pMeter = NULL; for (int x = rect.m_left; x < rect.m_right; x++, pMeter = NULL ) { for ( int y = rect.m_top; y < rect.m_bottom; y++, pMeter = NULL ) { CPointMap ptTest(static_cast<WORD>(x), static_cast<WORD>(y), pt.m_z, pt.m_map); pMeter = GetMapMeter(ptTest); if ( !pMeter ) continue; if ( bLimitZ && ( pMeter->m_z != pt.m_z ) ) continue; ptTest.m_z = pMeter->m_z; if ( iType != g_World.GetTerrainItemType( pMeter->m_wTerrainIndex ) ) continue; iTestDistance = pt.GetDist(ptTest); if ( iTestDistance > iDistance ) break; ptFound = ptTest; iDistance = iTestDistance; // tighten up the search. if ( ! iDistance ) return( ptFound ); rect.SetRect( pt.m_x - iDistance, pt.m_y - iDistance, pt.m_x + iDistance + 1, pt.m_y + iDistance + 1, pt.m_map); } } // Check for statics rect.SetRect( pt.m_x - iDistance, pt.m_y - iDistance, pt.m_x + iDistance + 1, pt.m_y + iDistance + 1, pt.m_map); const CGrayMapBlock * pMapBlock = NULL; const CUOStaticItemRec * pStatic = NULL; const CItemBase * pItemDef = NULL; for (int x = rect.m_left; x < rect.m_right; x += UO_BLOCK_SIZE, pMapBlock = NULL ) { for ( int y = rect.m_top; y < rect.m_bottom; y += UO_BLOCK_SIZE, pMapBlock = NULL ) { CPointMap ptTest(static_cast<WORD>(x), static_cast<WORD>(y), pt.m_z, pt.m_map); pMapBlock = GetMapBlock( ptTest ); if ( !pMapBlock ) continue; size_t iQty = pMapBlock->m_Statics.GetStaticQty(); if ( iQty <= 0 ) continue; pStatic = NULL; pItemDef = NULL; for ( size_t i = 0; i < iQty; i++, pStatic = NULL, pItemDef = NULL ) { pStatic = pMapBlock->m_Statics.GetStatic( i ); if ( bLimitZ && ( pStatic->m_z != ptTest.m_z ) ) continue; // inside the range we want ? CPointMap ptStatic( pStatic->m_x+pMapBlock->m_x, pStatic->m_y+pMapBlock->m_y, pStatic->m_z, ptTest.m_map); iTestDistance = pt.GetDist(ptStatic); if ( iTestDistance > iDistance ) continue; ITEMID_TYPE idTile = pStatic->GetDispID(); // Check the script def for the item. pItemDef = CItemBase::FindItemBase( idTile ); if ( pItemDef == NULL ) continue; if ( ! pItemDef->IsType( iType )) continue; ptFound = ptStatic; iDistance = iTestDistance; if ( ! iDistance ) return( ptFound ); rect.SetRect( pt.m_x - iDistance, pt.m_y - iDistance, pt.m_x + iDistance + 1, pt.m_y + iDistance + 1, pt.m_map); } } } // Check for multi components if (bCheckMulti == true) { rect.SetRect( pt.m_x - iDistance, pt.m_y - iDistance, pt.m_x + iDistance + 1, pt.m_y + iDistance + 1, pt.m_map); for (int x = rect.m_left; x < rect.m_right; x++) { for (int y = rect.m_top; y < rect.m_bottom; y++) { CPointMap ptTest(static_cast<WORD>(x), static_cast<WORD>(y), pt.m_z, pt.m_map); CRegionLinks rlinks; size_t iRegionQty = ptTest.GetRegions(REGION_TYPE_MULTI, rlinks); if ( iRegionQty > 0 ) { for (size_t iRegion = 0; iRegion < iRegionQty; iRegion++) { CRegionBase* pRegion = rlinks.GetAt(iRegion); CItem* pItem = pRegion->GetResourceID().ItemFind(); if (pItem == NULL) continue; const CGrayMulti * pMulti = g_Cfg.GetMultiItemDefs(pItem); if (pMulti == NULL) continue; int x2 = ptTest.m_x - pItem->GetTopPoint().m_x; int y2 = ptTest.m_y - pItem->GetTopPoint().m_y; size_t iItemQty = pMulti->GetItemCount(); for (size_t iItem = 0; iItem < iItemQty; iItem++) { const CUOMultiItemRec2* pMultiItem = pMulti->GetItem(iItem); ASSERT(pMultiItem); if ( !pMultiItem->m_visible ) continue; if ( pMultiItem->m_dx != x2 || pMultiItem->m_dy != y2 ) continue; if ( bLimitZ && (pMultiItem->m_dz != ptTest.m_z)) continue; iTestDistance = pt.GetDist(ptTest); if (iTestDistance > iDistance) continue; ITEMID_TYPE idTile = pMultiItem->GetDispID(); // Check the script def for the item. pItemDef = CItemBase::FindItemBase(idTile); if (pItemDef == NULL || !pItemDef->IsType(iType)) continue; ptFound = ptTest; iDistance = iTestDistance; if ( !iDistance ) return( ptFound ); rect.SetRect( pt.m_x - iDistance, pt.m_y - iDistance, pt.m_x + iDistance + 1, pt.m_y + iDistance + 1, pt.m_map); } } } } } } return ptFound; }
void CWorld::GetHeightPoint2( const CPointMap & pt, CGrayMapBlockState & block, bool fHouseCheck ) { ADDTOCALLSTACK("CWorld::GetHeightPoint2"); // Height of statics at/above given coordinates // do gravity here for the z. DWORD wBlockThis = 0; const CGrayMapBlock * pMapBlock = GetMapBlock( pt ); if ( !pMapBlock ) { g_Log.EventWarn("GetMapBlock failed at %s.\n", pt.WriteUsed()); return; } { size_t iStaticQty = pMapBlock->m_Statics.GetStaticQty(); if ( iStaticQty > 0 ) // no static items here. { int x2 = pMapBlock->GetOffsetX(pt.m_x); int y2 = pMapBlock->GetOffsetY(pt.m_y); for ( size_t i = 0; i < iStaticQty; i++ ) { if ( ! pMapBlock->m_Statics.IsStaticPoint( i, x2, y2 )) continue; const CUOStaticItemRec * pStatic = pMapBlock->m_Statics.GetStatic( i ); signed char z = pStatic->m_z; if ( ! block.IsUsableZ(z,PLAYER_HEIGHT)) continue; // This static is at the coordinates in question. // enough room for me to stand here ? wBlockThis = 0; height_t zHeight = CItemBase::GetItemHeight( pStatic->GetDispID(), wBlockThis ); block.CheckTile( wBlockThis, z, zHeight, pStatic->GetDispID() + TERRAIN_QTY ); } } } // Any multi items here ? if ( fHouseCheck ) { CRegionLinks rlinks; size_t iRegionQty = pt.GetRegions( REGION_TYPE_MULTI, rlinks ); if ( iRegionQty > 0 ) { for ( size_t i = 0; i < iRegionQty; i++) { CRegionBase * pRegion = rlinks.GetAt(i); CItem * pItem = pRegion->GetResourceID().ItemFind(); if ( pItem != NULL ) { const CGrayMulti * pMulti = g_Cfg.GetMultiItemDefs(pItem); if ( pMulti ) { int x2 = pt.m_x - pItem->GetTopPoint().m_x; int y2 = pt.m_y - pItem->GetTopPoint().m_y; size_t iMultiQty = pMulti->GetItemCount(); for ( size_t j = 0; j < iMultiQty; j++ ) { const CUOMultiItemRec2 * pMultiItem = pMulti->GetItem(j); ASSERT(pMultiItem); if ( ! pMultiItem->m_visible ) continue; if ( pMultiItem->m_dx != x2 || pMultiItem->m_dy != y2 ) continue; signed char zitem = static_cast<signed char>( pItem->GetTopZ() + pMultiItem->m_dz ); if ( ! block.IsUsableZ(zitem,PLAYER_HEIGHT)) continue; wBlockThis = 0; height_t zHeight = CItemBase::GetItemHeight( pMultiItem->GetDispID(), wBlockThis ); block.CheckTile( wBlockThis, zitem, zHeight, pMultiItem->GetDispID() + TERRAIN_QTY ); } } } } } } { // Any dynamic items here ? // NOTE: This could just be an item that an NPC could just move ? CWorldSearch Area( pt ); for (;;) { CItem * pItem = Area.GetItem(); if ( pItem == NULL ) break; signed char zitem = pItem->GetTopZ(); if ( ! block.IsUsableZ(zitem,PLAYER_HEIGHT)) continue; // Invis items should not block ??? CItemBase * pItemDef = pItem->Item_GetDef(); ASSERT(pItemDef); // Get Attributes from ItemDef. If they are not set, get them from the static object (DISPID) wBlockThis = pItemDef->m_Can & (CAN_I_DOOR | CAN_I_WATER | CAN_I_CLIMB | CAN_I_BLOCK | CAN_I_PLATFORM); height_t zHeight = pItemDef->GetHeight(); DWORD wStaticBlockThis = 0; height_t zStaticHeight = CItemBase::GetItemHeight(pItem->GetDispID(), wStaticBlockThis); if (wBlockThis == 0) wBlockThis = wStaticBlockThis; if (zHeight == 0) zHeight = zStaticHeight; if ( !block.CheckTile( wBlockThis, zitem, zHeight, pItemDef->GetDispID() + TERRAIN_QTY ) ) { } } } // Check Terrain here. // Terrain height is screwed. Since it is related to all the terrain around it. { const CUOMapMeter * pMeter = pMapBlock->GetTerrain( UO_BLOCK_OFFSET(pt.m_x), UO_BLOCK_OFFSET(pt.m_y)); ASSERT(pMeter); if ( block.IsUsableZ(pMeter->m_z,0)) { if ( pMeter->m_wTerrainIndex == TERRAIN_HOLE ) wBlockThis = 0; else if ( pMeter->m_wTerrainIndex == TERRAIN_NULL ) // inter dungeon type. wBlockThis = CAN_I_BLOCK; else { CGrayTerrainInfo land( pMeter->m_wTerrainIndex ); if ( land.m_flags & UFLAG2_PLATFORM ) // Platform items should take precendence over non-platforms. wBlockThis = CAN_I_PLATFORM; else if ( land.m_flags & UFLAG1_WATER ) wBlockThis = CAN_I_WATER; else if ( land.m_flags & UFLAG1_DAMAGE ) wBlockThis = CAN_I_FIRE; else if ( land.m_flags & UFLAG1_BLOCK ) wBlockThis = CAN_I_BLOCK; else wBlockThis = CAN_I_PLATFORM; } block.CheckTile( wBlockThis, pMeter->m_z, 0, pMeter->m_wTerrainIndex ); } } if ( block.m_Bottom.m_z == UO_SIZE_MIN_Z ) { block.m_Bottom = block.m_Lowest; } }
bool CChar::CanSeeLOS_New( const CPointMap &ptDst, CPointMap *pptBlock, int iMaxDist, word flags, bool bCombatCheck ) const { ADDTOCALLSTACK("CChar::CanSeeLOS_New"); // WARNING: CanSeeLOS is an expensive function (lot of calculations but most importantly it has to read the UO files, and file I/O is slow). if ( !bCombatCheck && IsPriv(PRIV_GM) ) // If i'm checking the LOS during a combat, i don't want to shoot through the walls even if i'm a GM { WARNLOS(("GM Pass\n")); return true; } CPointMap ptSrc = GetTopPoint(); CPointMap ptNow(ptSrc); if ( ptSrc.m_map != ptDst.m_map ) // Different map return this->CanSeeLOS_New_Failed(pptBlock, ptNow); if ( ptSrc == ptDst ) // Same point ^^ return true; short iTotalZ = ptSrc.m_z + GetHeightMount(true); ptSrc.m_z = (char)minimum(iTotalZ, UO_SIZE_Z); //true - substract one from the height because of eyes height WARNLOS(("Total Z: %d\n", ptSrc.m_z)); int dx, dy, dz; dx = ptDst.m_x - ptSrc.m_x; dy = ptDst.m_y - ptSrc.m_y; dz = ptDst.m_z - ptSrc.m_z; float dist2d, dist3d; dist2d = sqrt((float)(dx*dx + dy*dy)); if ( dz ) dist3d = sqrt((float)(dist2d*dist2d + dz*dz)); else dist3d = dist2d; if ( APPROX(dist2d) > (float)iMaxDist ) { WARNLOS(("( APPROX(dist2d)(%f) > ((double)iMaxDist)(%f) ) --> NOLOS\n", APPROX(dist2d), (float)iMaxDist)); return CanSeeLOS_New_Failed(pptBlock, ptNow); } float dFactorX, dFactorY, dFactorZ; dFactorX = dx / dist3d; dFactorY = dy / dist3d; dFactorZ = dz / dist3d; float nPx, nPy, nPz; nPx = ptSrc.m_x; nPy = ptSrc.m_y; nPz = ptSrc.m_z; std::vector<CPointMap> path; for (;;) { if ( BETWEENPOINT(nPx, ptDst.m_x, ptSrc.m_x) && BETWEENPOINT(nPy, ptDst.m_y, ptSrc.m_y) && BETWEENPOINT(nPz, ptDst.m_z, ptSrc.m_z) ) { dx = (int)APPROX(nPx); dy = (int)APPROX(nPy); dz = (int)APPROX(nPz); // Add point to vector if ( !path.empty() ) { CPointMap ptEnd = path[path.size() - 1]; if ( ptEnd.m_x != dx || ptEnd.m_y != dy || ptEnd.m_z != dz ) path.emplace_back((word)dx, (word)dy, (char)dz, ptSrc.m_map); } else { path.emplace_back((word)dx, (word)dy, (char)dz, ptSrc.m_map); } WARNLOS(("PATH X:%d Y:%d Z:%d\n", dx, dy, dz)); nPx += dFactorX; nPy += dFactorY; nPz += dFactorZ; } else break; } if ( !path.empty() ) { if ( path[path.size() - 1] != ptDst ) path.emplace_back(ptDst.m_x, ptDst.m_y, ptDst.m_z, ptDst.m_map); } else { path.clear(); return CanSeeLOS_New_Failed(pptBlock, ptNow); } WARNLOS(("Path calculated %" PRIuSIZE_T "\n", path.size())); // Ok now we should loop through all the points and checking for maptile, staticx, items, multis. // If something is in the way and it has the wrong flags LOS return false const CServerMapBlock *pBlock = nullptr; // Block of the map (for statics) const CUOStaticItemRec *pStatic = nullptr; // Statics iterator (based on SphereMapBlock) const CSphereMulti *pMulti = nullptr; // Multi Def (multi check) const CUOMultiItemRec_HS *pMultiItem = nullptr; // Multi item iterator CRegion *pRegion = nullptr; // Nulti regions CRegionLinks rlinks; // Links to multi regions CItem *pItem = nullptr; CItemBase *pItemDef = nullptr; CItemBaseDupe *pDupeDef = nullptr; dword wTFlags = 0; height_t Height = 0; word terrainid = 0; bool bPath = true; bool bNullTerrain = false; CRegion *pSrcRegion = ptSrc.GetRegion(REGION_TYPE_AREA|REGION_TYPE_ROOM|REGION_TYPE_MULTI); CRegion *pNowRegion = nullptr; int lp_x = 0, lp_y = 0; short min_z = 0, max_z = 0; for (uint i = 0, pathSize = uint(path.size()); i < pathSize; lp_x = ptNow.m_x, lp_y = ptNow.m_y, pItemDef = nullptr, pStatic = nullptr, pMulti = nullptr, pMultiItem = nullptr, min_z = 0, max_z = 0, ++i ) { ptNow = path[i]; WARNLOS(("---------------------------------------------\n")); WARNLOS(("Point %d,%d,%d \n", ptNow.m_x, ptNow.m_y, ptNow.m_z)); pNowRegion = ptNow.GetRegion(REGION_TYPE_AREA|REGION_TYPE_ROOM|REGION_TYPE_MULTI); if ( (flags & LOS_NO_OTHER_REGION) && (pSrcRegion != pNowRegion) ) { WARNLOS(("flags & 0200 and path is leaving my region - BLOCK\n")); bPath = false; break; } if ( (flags & LOS_NC_MULTI) && ptNow.GetRegion(REGION_TYPE_MULTI) && (ptNow.GetRegion(REGION_TYPE_MULTI) != ptSrc.GetRegion(REGION_TYPE_MULTI)) ) { WARNLOS(("flags & 0400 and path is crossing another multi - BLOCK\n")); bPath = false; break; } if ( (lp_x != ptNow.m_x) || (lp_y != ptNow.m_y) ) { WARNLOS(("\tLoading new map block.\n")); pBlock = g_World.GetMapBlock(ptNow); } if ( !pBlock ) // something is wrong { WARNLOS(("GetMapBlock Failed\n")); bPath = false; break; } if ( !(flags & LOS_NB_TERRAIN) ) { if ( !((flags & LOS_NB_LOCAL_TERRAIN) && (pSrcRegion == pNowRegion)) ) { // ------ MapX.mul Check ---------- terrainid = pBlock->GetTerrain(UO_BLOCK_OFFSET(ptNow.m_x), UO_BLOCK_OFFSET(ptNow.m_y))->m_wTerrainIndex; WARNLOS(("Terrain %d\n", terrainid)); if ( (flags & LOS_FISHING) && (ptSrc.GetDist(ptNow) >= 2) && (g_World.GetTerrainItemType(terrainid) != IT_WATER) && (g_World.GetTerrainItemType(terrainid) != IT_NORMAL) ) { WARNLOS(("Terrain %d blocked - flags & LOS_FISHING, distance >= 2 and type of pItemDef is not IT_WATER\n", terrainid)); WARNLOS(("ptSrc: %d,%d,%d; ptNow: %d,%d,%d; terrainid: %d; terrainid type: %d\n", ptSrc.m_x, ptSrc.m_y, ptSrc.m_z, ptNow.m_x, ptNow.m_y, ptNow.m_z, terrainid, g_World.GetTerrainItemType(terrainid))); bPath = false; break; } //#define MAPTILEMIN minimum(minimum(minimum(pBlock->GetTerrain(0,0)->m_z, pBlock->GetTerrain(0,1)->m_z), pBlock->GetTerrain(1,0)->m_z), pBlock->GetTerrain(1,1)->m_z) //#define MAPTILEMAX maximum(maximum(maximum(pBlock->GetTerrain(0,0)->m_z, pBlock->GetTerrain(0,1)->m_z), pBlock->GetTerrain(1,0)->m_z), pBlock->GetTerrain(1,1)->m_z); //#define MAPTILEZ pBlock->GetTerrain(UO_BLOCK_OFFSET(ptNow.m_x), UO_BLOCK_OFFSET(ptNow.m_y))->m_z; if ( (terrainid != TERRAIN_HOLE) && (terrainid != 475) ) { if ( terrainid < 430 || terrainid > 437 ) { /*this stuff should do some checking for surrounding items: aaa aXa aaa min_z is determined as a minimum of all a/X terrain, where X is ptNow */ byte pos_x = UO_BLOCK_OFFSET(ptNow.m_x) > 1 ? UO_BLOCK_OFFSET(ptNow.m_x - 1) : 0; byte pos_y = UO_BLOCK_OFFSET(ptNow.m_y) > 1 ? UO_BLOCK_OFFSET(ptNow.m_y - 1) : 0; const byte defx = UO_BLOCK_OFFSET(ptNow.m_x); const byte defy = UO_BLOCK_OFFSET(ptNow.m_y); min_z = pBlock->GetTerrain(pos_x, pos_y)->m_z; max_z = pBlock->GetTerrain(defx, defy)->m_z; for ( byte posy = pos_y; (abs(defx - UO_BLOCK_OFFSET(pos_x)) <= 1 && pos_x <= 7); ++pos_x ) { for ( pos_y = posy; (abs(defy - UO_BLOCK_OFFSET(pos_y)) <= 1 && pos_y <= 7); ++pos_y ) { char terrain_z = pBlock->GetTerrain(pos_x, pos_y)->m_z; min_z = minimum(min_z, terrain_z); } } //min_z = MAPTILEZ; //max_z = MAPTILEZ; WARNLOS(("Terrain %d - m:%d M:%d\n", terrainid, min_z, max_z)); if ( CUOMapMeter::IsTerrainNull(terrainid) ) bNullTerrain = true; //what if there are some items on that hole? if ( (min_z <= ptNow.m_z && max_z >= ptNow.m_z) && (ptNow.m_x != ptDst.m_x || ptNow.m_y != ptDst.m_y || min_z > ptDst.m_z || max_z < ptDst.m_z) ) { WARNLOS(("Terrain %d - m:%d M:%d - block\n", terrainid, min_z, max_z)); bPath = false; break; } CUOTerrainInfo land(terrainid); if ( (land.m_flags & UFLAG1_WATER) && (flags & LOS_NC_WATER) ) bNullTerrain = true; } } //#undef MAPTILEMIN //#undef MAPTILEMAX //#undef MAPTILEZ } } // ------ StaticsX.mul Check -------- if ( !(flags & LOS_NB_STATIC) ) { if ( !((flags & LOS_NB_LOCAL_STATIC) && (pSrcRegion == pNowRegion)) ) { uint uiStaticMaxQty = pBlock->m_Statics.GetStaticQty(); for ( uint s = 0; s < uiStaticMaxQty; pStatic = nullptr, pItemDef = nullptr, ++s ) { pStatic = pBlock->m_Statics.GetStatic(s); if ( (pStatic->m_x + pBlock->m_x != ptNow.m_x) || (pStatic->m_y + pBlock->m_y != ptNow.m_y) ) continue; //Fix for Stacked items blocking view if ( (pStatic->m_x == ptDst.m_x) && (pStatic->m_y == ptDst.m_y) && (pStatic->m_z >= GetTopZ()) && (pStatic->m_z <= ptSrc.m_z) ) continue; pItemDef = CItemBase::FindItemBase(pStatic->GetDispID()); wTFlags = 0; Height = 0; bNullTerrain = false; if ( !pItemDef ) { WARNLOS(("STATIC - Cannot get pItemDef for item (0%x)\n", pStatic->GetDispID())); } else { if (pItemDef->Can(CAN_I_BLOCKLOS)) { WARNLOS(("pStatic blocked by CAN_I_BLOCKLOS")); bPath = false; break; } if ( (flags & LOS_FISHING) && (ptSrc.GetDist(ptNow) >= 2) && (pItemDef->GetType() != IT_WATER) && ( pItemDef->Can(CAN_I_DOOR | CAN_I_PLATFORM | CAN_I_BLOCK | CAN_I_CLIMB | CAN_I_FIRE | CAN_I_ROOF | CAN_I_BLOCKLOS | CAN_I_BLOCKLOS_HEIGHT)) ) { WARNLOS(("pStatic blocked - flags & 0800, distance >= 2 and type of pItemDef is not IT_WATER\n")); bPath = false; break; } wTFlags = pItemDef->GetTFlags(); Height = pItemDef->GetHeight(); if ( pItemDef->GetID() != pStatic->GetDispID() ) //not a parent item { WARNLOS(("Not a parent item (STATIC)\n")); pDupeDef = CItemBaseDupe::GetDupeRef((ITEMID_TYPE)(pStatic->GetDispID())); if ( !pDupeDef ) { g_Log.EventDebug("AdvancedLoS: Failed to get non-parent reference (static) (DispID 0%x) (X: %d Y: %d Z: %hhd M: %hhu)\n", pStatic->GetDispID(), ptNow.m_x, ptNow.m_y, pStatic->m_z, ptNow.m_map); } else { wTFlags = pDupeDef->GetTFlags(); Height = pDupeDef->GetHeight(); } } else { WARNLOS(("Parent item (STATIC)\n")); } Height = (wTFlags & UFLAG2_CLIMBABLE) ? Height / 2 : Height; if ( ((wTFlags & (UFLAG1_WALL|UFLAG1_BLOCK|UFLAG2_PLATFORM)) || (pItemDef->Can(CAN_I_BLOCKLOS_HEIGHT))) && !((wTFlags & UFLAG2_WINDOW) && (flags & LOS_NB_WINDOWS)) ) { WARNLOS(("pStatic %0x %d,%d,%d - %d\n", pStatic->GetDispID(), pStatic->m_x, pStatic->m_y, pStatic->m_z, Height)); min_z = pStatic->m_z; max_z = minimum(Height + min_z, UO_SIZE_Z); WARNLOS(("wTFlags(0%x)\n", wTFlags)); WARNLOS(("pStatic %0x Z check: %d,%d (Now: %d) (Dest: %d).\n", pStatic->GetDispID(), min_z, max_z, ptNow.m_z, ptDst.m_z)); if ( (min_z <= ptNow.m_z) && (max_z >= ptNow.m_z) ) { if ( ptNow.m_x != ptDst.m_x || ptNow.m_y != ptDst.m_y || min_z > ptDst.m_z || max_z < ptDst.m_z ) { WARNLOS(("pStatic blocked - m:%d M:%d\n", min_z, max_z)); bPath = false; break; } } } } } } } if ( !bPath ) break; // --------- In game items ---------- if ( !(flags & LOS_NB_DYNAMIC) ) { if ( !((flags & LOS_NB_LOCAL_DYNAMIC) && (pSrcRegion == pNowRegion)) ) { CWorldSearch AreaItems(ptNow, 0); for (;;) { pItem = AreaItems.GetItem(); if ( !pItem ) break; if ( pItem->GetUnkPoint().m_x != ptNow.m_x || pItem->GetUnkPoint().m_y != ptNow.m_y ) continue; if ( !CanSeeItem(pItem) ) continue; //Fix for Stacked items blocking view if ( (pItem->GetUnkPoint().m_x == ptDst.m_x) && (pItem->GetUnkPoint().m_y == ptDst.m_y) && (pItem->GetUnkPoint().m_z >= GetTopZ()) && (pItem->GetUnkPoint().m_z <= ptSrc.m_z) ) continue; pItemDef = static_cast<CItemBase*>(pItem->Base_GetDef()); wTFlags = 0; Height = 0; bNullTerrain = false; if ( !pItemDef ) { WARNLOS(("DYNAMIC - Cannot get pItemDef for item (0%x)\n", pItem->GetDispID())); } else { if (pItem->Can(CAN_I_BLOCKLOS)) { WARNLOS(("pItem blocked by CAN_I_BLOCKLOS")); bPath = false; break; } if ( (flags & LOS_FISHING) && (ptSrc.GetDist(ptNow) >= 2) && (pItem->GetType() != IT_WATER) && ( pItem->Can(CAN_I_DOOR | CAN_I_PLATFORM | CAN_I_BLOCK | CAN_I_CLIMB | CAN_I_FIRE | CAN_I_ROOF | CAN_I_BLOCKLOS | CAN_I_BLOCKLOS_HEIGHT) ) ) { WARNLOS(("pItem blocked - flags & 0800, distance >= 2 and type of pItemDef is not IT_WATER\n")); bPath = false; break; //return CanSeeLOS_New_Failed(pptBlock, ptNow); } wTFlags = pItemDef->GetTFlags(); Height = pItemDef->GetHeight(); if ( pItemDef->GetID() != pItem->GetDispID() ) //not a parent item { WARNLOS(("Not a parent item (DYNAMIC)\n")); pDupeDef = CItemBaseDupe::GetDupeRef((ITEMID_TYPE)(pItem->GetDispID())); if ( !pDupeDef ) { // Not an error: i have changed the DISPID of the item. CItemBase* pParentDef = CItemBase::FindItemBase(pItem->GetDispID()); if (pParentDef) { wTFlags = pParentDef->GetTFlags(); Height = pParentDef->GetHeight(); } else g_Log.EventDebug("AdvancedLoS: Failed to get reference (dynamic): non-dupe, baseless dispid (DispID 0%x) (X: %d Y: %d Z: %hhd M: %hhu)\n", pItem->GetDispID(), ptNow.m_x, ptNow.m_y, pItem->GetUnkZ(), ptNow.m_map); } else { // It's a dupe item wTFlags = pDupeDef->GetTFlags(); Height = pDupeDef->GetHeight(); } } else { WARNLOS(("Parent item (DYNAMIC)\n")); } Height = (wTFlags & UFLAG2_CLIMBABLE) ? Height / 2 : Height; if ( ((wTFlags & (UFLAG1_WALL|UFLAG1_BLOCK|UFLAG2_PLATFORM)) || pItem->Can(CAN_I_BLOCKLOS_HEIGHT)) && !((wTFlags & UFLAG2_WINDOW) && (flags & LOS_NB_WINDOWS)) ) { WARNLOS(("pItem %0x(%0x) %d,%d,%d - %d\n", (dword)pItem->GetUID(), pItem->GetDispID(), pItem->GetUnkPoint().m_x, pItem->GetUnkPoint().m_y, pItem->GetUnkPoint().m_z, Height)); min_z = pItem->GetUnkPoint().m_z; max_z = minimum(Height + min_z, UO_SIZE_Z); WARNLOS(("wTFlags(0%x)\n", wTFlags)); WARNLOS(("pItem %0x(%0x) Z check: %d,%d (Now: %d) (Dest: %d).\n", (dword)pItem->GetUID(), pItem->GetDispID(), min_z, max_z, ptNow.m_z, ptDst.m_z)); if ( min_z <= ptNow.m_z && max_z >= ptNow.m_z ) { if ( ptNow.m_x != ptDst.m_x || ptNow.m_y != ptDst.m_y || min_z > ptDst.m_z || max_z < ptDst.m_z ) { WARNLOS(("pItem blocked - m:%d M:%d\n", min_z, max_z)); bPath = false; break; } } } } } } } if ( !bPath ) break; // ----------- Multis --------------- if ( !(flags & LOS_NB_MULTI) ) { if ( !((flags & LOS_NB_LOCAL_MULTI) && (pSrcRegion == pNowRegion)) ) { size_t iQtyr = ptNow.GetRegions(REGION_TYPE_MULTI, &rlinks); if ( iQtyr > 0 ) { for ( size_t ii = 0; ii < iQtyr; pMulti = nullptr, ++ii, pItem = nullptr, pRegion = nullptr ) { pRegion = rlinks[ii]; if ( pRegion ) pItem = pRegion->GetResourceID().ItemFindFromResource(); if ( !pItem ) continue; pMulti = g_Cfg.GetMultiItemDefs(pItem); if ( !pMulti ) continue; uint iQty = pMulti->GetItemCount(); for ( uint iii = 0; iii < iQty; pItemDef = nullptr, pMultiItem = nullptr, ++iii ) { pMultiItem = pMulti->GetItem(iii); if ( !pMultiItem ) break; if ( !pMultiItem->m_visible ) continue; if ( (pMultiItem->m_dx + pItem->GetTopPoint().m_x != ptNow.m_x) || (pMultiItem->m_dy + pItem->GetTopPoint().m_y != ptNow.m_y) ) continue; pItemDef = CItemBase::FindItemBase(pMultiItem->GetDispID()); wTFlags = 0; Height = 0; bNullTerrain = false; if ( !pItemDef ) { WARNLOS(("MULTI - Cannot get pItemDef for item (0%x)\n", pMultiItem->GetDispID())); } else { if (pItemDef->Can(CAN_I_BLOCKLOS)) { WARNLOS(("pMultiItem blocked by CAN_I_BLOCKLOS")); bPath = false; break; } if ( (flags & LOS_FISHING) && (ptSrc.GetDist(ptNow) >= 2) && (pItemDef->GetType() != IT_WATER) && ( pItemDef->Can(CAN_I_DOOR | CAN_I_PLATFORM | CAN_I_BLOCK | CAN_I_CLIMB | CAN_I_FIRE | CAN_I_ROOF | CAN_I_BLOCKLOS | CAN_I_BLOCKLOS_HEIGHT) ) ) { WARNLOS(("pMultiItem blocked - flags & 0800, distance >= 2 and type of pItemDef is not IT_WATER\n")); bPath = false; break; //return CanSeeLOS_New_Failed(pptBlock, ptNow); } wTFlags = pItemDef->GetTFlags(); Height = pItemDef->GetHeight(); if ( pItemDef->GetID() != pMultiItem->GetDispID() ) //not a parent item { WARNLOS(("Not a parent item (MULTI)\n")); pDupeDef = CItemBaseDupe::GetDupeRef((ITEMID_TYPE)(pMultiItem->GetDispID())); if ( !pDupeDef ) { g_Log.EventDebug("AdvancedLoS: Failed to get non-parent reference (multi) (DispID 0%x) (X: %d Y: %d Z: %hhd M: %hhu)\n", pMultiItem->GetDispID(), ptNow.m_x, ptNow.m_y, pMultiItem->m_dz + pItem->GetTopPoint().m_z, ptNow.m_map); } else { wTFlags = pDupeDef->GetTFlags(); Height = pDupeDef->GetHeight(); } } else { WARNLOS(("Parent item (MULTI)\n")); } Height = (wTFlags & UFLAG2_CLIMBABLE) ? Height / 2 : Height; if ( ((wTFlags & (UFLAG1_WALL|UFLAG1_BLOCK|UFLAG2_PLATFORM) || pItemDef->Can(CAN_I_BLOCKLOS_HEIGHT))) && !((wTFlags & UFLAG2_WINDOW) && (flags & LOS_NB_WINDOWS)) ) { WARNLOS(("pMultiItem %0x %d,%d,%d - %d\n", pMultiItem->GetDispID(), pMultiItem->m_dx, pMultiItem->m_dy, pMultiItem->m_dz, Height)); min_z = (char)(pMultiItem->m_dz) + pItem->GetTopPoint().m_z; max_z = minimum(Height + min_z, UO_SIZE_Z); WARNLOS(("wTFlags(0%x)\n", wTFlags)); if ( min_z <= ptNow.m_z && max_z >= ptNow.m_z ) { if ( ptNow.m_x != ptDst.m_x || ptNow.m_y != ptDst.m_y || min_z > ptDst.m_z || max_z < ptDst.m_z ) { WARNLOS(("pMultiItem blocked - m:%d M:%d\n", min_z, max_z)); bPath = false; break; } } } } } if ( !bPath ) break; } } } } if ( bNullTerrain ) bPath = false; if ( !bPath ) break; } path.clear(); if ( !bPath ) return CanSeeLOS_New_Failed(pptBlock, ptNow); return true; }
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; }
bool CPointBase::r_WriteVal( LPCTSTR pszKey, CGString & sVal ) const { ADDTOCALLSTACK("CPointBase::r_WriteVal"); if ( !strnicmp( pszKey, "STATICS", 7 ) ) { pszKey += 7; const CGrayMapBlock * pBlock = g_World.GetMapBlock( *(this) ); if ( !pBlock ) return false; if ( *pszKey == '\0' ) { int iStaticQty = 0; for ( size_t i = 0; i < pBlock->m_Statics.GetStaticQty(); i++ ) { const CUOStaticItemRec * pStatic = pBlock->m_Statics.GetStatic( i ); CPointMap ptTest( pStatic->m_x+pBlock->m_x, pStatic->m_y+pBlock->m_y, pStatic->m_z, this->m_map ); if ( this->GetDist( ptTest ) > 0 ) continue; iStaticQty++; } sVal.FormatVal( iStaticQty ); return true; } SKIP_SEPARATORS( pszKey ); const CUOStaticItemRec * pStatic = NULL; int iStatic = 0; int type = 0; if ( !strnicmp( pszKey, "FINDID", 6 ) ) { pszKey += 6; SKIP_SEPARATORS( pszKey ); iStatic = Exp_GetVal( pszKey ); type = RES_GET_TYPE( iStatic ); if ( type == 0 ) type = RES_ITEMDEF; SKIP_SEPARATORS( pszKey ); } else { iStatic = Exp_GetVal( pszKey ); type = RES_GET_TYPE( iStatic ); } if ( type == RES_ITEMDEF ) { const CItemBase * pItemDef = CItemBase::FindItemBase(static_cast<ITEMID_TYPE>(RES_GET_INDEX(iStatic))); if ( !pItemDef ) { sVal.FormatVal( 0 ); return false; } for ( size_t i = 0; i < pBlock->m_Statics.GetStaticQty(); pStatic = NULL, i++ ) { pStatic = pBlock->m_Statics.GetStatic( i ); CPointMap ptTest( pStatic->m_x+pBlock->m_x, pStatic->m_y+pBlock->m_y, pStatic->m_z, this->m_map); if ( this->GetDist( ptTest ) > 0 ) continue; if ( pStatic->GetDispID() == pItemDef->GetDispID() ) break; } } else { for ( size_t i = 0; i < pBlock->m_Statics.GetStaticQty(); pStatic = NULL, i++ ) { pStatic = pBlock->m_Statics.GetStatic( i ); CPointMap ptTest( pStatic->m_x+pBlock->m_x, pStatic->m_y+pBlock->m_y, pStatic->m_z, this->m_map); if ( this->GetDist( ptTest ) > 0 ) continue; if ( iStatic == 0 ) break; iStatic--; } } if ( !pStatic ) { sVal.FormatHex(0); return true; } SKIP_SEPARATORS( pszKey ); if ( !*pszKey ) pszKey = "ID"; ITEMID_TYPE idTile = pStatic->GetDispID(); if ( !strnicmp( pszKey, "COLOR", 5 ) ) { sVal.FormatHex( pStatic->m_wHue ); return true; } else if ( !strnicmp( pszKey, "ID", 2 ) ) { sVal.FormatHex( idTile ); return true; } else if ( !strnicmp( pszKey, "Z", 1 ) ) { sVal.FormatVal( pStatic->m_z ); return true; } // Check the script def for the item. CItemBase * pItemDef = CItemBase::FindItemBase( idTile ); if ( pItemDef == NULL ) { DEBUG_ERR(("Must have ITEMDEF section for item ID 0%x\n", idTile )); return false; } return pItemDef->r_WriteVal( pszKey, sVal, &g_Serv ); } else if ( !strnicmp( pszKey, "COMPONENTS", 10) ) { pszKey += 10; CRegionLinks rlinks; const CRegionBase* pRegion = NULL; CItem* pItem = NULL; const CGrayMulti* pMulti = NULL; const CUOMultiItemRec2* pMultiItem = NULL; size_t iMultiQty = GetRegions(REGION_TYPE_MULTI, rlinks); if ( *pszKey == '\0' ) { int iComponentQty = 0; for (size_t i = 0; i < iMultiQty; i++) { pRegion = rlinks.GetAt(i); if (pRegion == NULL) continue; pItem = pRegion->GetResourceID().ItemFind(); if (pItem == NULL) continue; const CPointMap ptMulti = pItem->GetTopPoint(); pMulti = g_Cfg.GetMultiItemDefs(pItem); if (pMulti == NULL) continue; size_t iQty = pMulti->GetItemCount(); for (size_t ii = 0; ii < iQty; ii++) { pMultiItem = pMulti->GetItem(ii); if (pMultiItem == NULL) break; if (pMultiItem->m_visible == 0) continue; CPointMap ptTest(static_cast<WORD>(ptMulti.m_x + pMultiItem->m_dx), static_cast<WORD>(ptMulti.m_y + pMultiItem->m_dy), static_cast<signed char>(ptMulti.m_z + pMultiItem->m_dz), this->m_map); if (GetDist(ptTest) > 0) continue; iComponentQty++; } } sVal.FormatVal( iComponentQty ); return true; } SKIP_SEPARATORS( pszKey ); int iComponent = 0; int type = 0; if ( strnicmp( pszKey, "FINDID", 6 ) == 0 ) { pszKey += 6; SKIP_SEPARATORS( pszKey ); iComponent = Exp_GetVal( pszKey ); type = RES_GET_TYPE( iComponent ); if ( type == 0 ) type = RES_ITEMDEF; SKIP_SEPARATORS( pszKey ); } else { iComponent = Exp_GetVal( pszKey ); type = RES_GET_TYPE( iComponent ); } if ( type == RES_ITEMDEF ) { const CItemBase * pItemDef = CItemBase::FindItemBase(static_cast<ITEMID_TYPE>(RES_GET_INDEX(iComponent))); if ( pItemDef == NULL ) { sVal.FormatVal( 0 ); return false; } for (size_t i = 0; i < iMultiQty; i++) { pRegion = rlinks.GetAt(i); if (pRegion == NULL) continue; pItem = pRegion->GetResourceID().ItemFind(); if (pItem == NULL) continue; const CPointMap ptMulti = pItem->GetTopPoint(); pMulti = g_Cfg.GetMultiItemDefs(pItem); if (pMulti == NULL) continue; size_t iQty = pMulti->GetItemCount(); for (size_t ii = 0; ii < iQty; pMultiItem = NULL, ii++) { pMultiItem = pMulti->GetItem(ii); if (pMultiItem == NULL) break; if (pMultiItem->m_visible == 0) continue; CPointMap ptTest(static_cast<WORD>(ptMulti.m_x + pMultiItem->m_dx), static_cast<WORD>(ptMulti.m_y + pMultiItem->m_dy), static_cast<signed char>(ptMulti.m_z + pMultiItem->m_dz), this->m_map); if (GetDist(ptTest) > 0) continue; const CItemBase* pMultiItemDef = CItemBase::FindItemBase(pMultiItem->GetDispID()); if (pMultiItemDef != NULL && pMultiItemDef->GetDispID() == pItemDef->GetDispID()) break; } if (pMultiItem != NULL) break; } } else { for (size_t i = 0; i < iMultiQty; i++) { pRegion = rlinks.GetAt(i); if (pRegion == NULL) continue; pItem = pRegion->GetResourceID().ItemFind(); if (pItem == NULL) continue; const CPointMap ptMulti = pItem->GetTopPoint(); pMulti = g_Cfg.GetMultiItemDefs(pItem); if (pMulti == NULL) continue; size_t iQty = pMulti->GetItemCount(); for (size_t ii = 0; ii < iQty; pMultiItem = NULL, ii++) { pMultiItem = pMulti->GetItem(ii); if (pMultiItem == NULL) break; if (pMultiItem->m_visible == 0) continue; CPointMap ptTest(static_cast<WORD>(ptMulti.m_x + pMultiItem->m_dx), static_cast<WORD>(ptMulti.m_y + pMultiItem->m_dy), static_cast<signed char>(ptMulti.m_z + pMultiItem->m_dz), this->m_map); if (GetDist(ptTest) > 0) continue; if (iComponent == 0) break; iComponent--; } if (pMultiItem != NULL) break; } } if ( pMultiItem == NULL ) { sVal.FormatHex(0); return true; } SKIP_SEPARATORS( pszKey ); if ( !*pszKey ) pszKey = "ID"; ITEMID_TYPE idTile = pMultiItem->GetDispID(); if ( strnicmp( pszKey, "ID", 2 ) == 0 ) { sVal.FormatHex( idTile ); return true; } else if ( strnicmp( pszKey, "MULTI", 5 ) == 0 ) { pszKey += 5; if (*pszKey != '\0') { SKIP_SEPARATORS(pszKey); return pItem->r_WriteVal( pszKey, sVal, &g_Serv ); } sVal.FormatHex( pItem->GetUID() ); return true; } else if ( strnicmp( pszKey, "Z", 1 ) == 0 ) { sVal.FormatVal( pItem->GetTopZ() + pMultiItem->m_dz ); return true; } // Check the script def for the item. CItemBase * pItemDef = CItemBase::FindItemBase( idTile ); if ( pItemDef == NULL ) { DEBUG_ERR(("Must have ITEMDEF section for item ID 0%x\n", idTile )); return false; } return pItemDef->r_WriteVal( pszKey, sVal, &g_Serv ); } int index = FindTableHeadSorted( pszKey, sm_szLoadKeys, COUNTOF(sm_szLoadKeys)-1 ); if ( index < 0 ) return false; switch ( index ) { case PT_M: case PT_MAP: sVal.FormatVal(m_map); break; case PT_X: sVal.FormatVal(m_x); break; case PT_Y: sVal.FormatVal(m_y); break; case PT_Z: sVal.FormatVal(m_z); break; case PT_ISNEARTYPE: { pszKey += 10; SKIP_SEPARATORS( pszKey ); SKIP_ARGSEP( pszKey ); int iType = g_Cfg.ResourceGetIndexType( RES_TYPEDEF, pszKey ); int iDistance = 0; bool bCheckMulti = false; SKIP_IDENTIFIERSTRING( pszKey ); SKIP_SEPARATORS( pszKey ); SKIP_ARGSEP( pszKey ); if ( *pszKey ) iDistance = Exp_GetVal(pszKey); if ( *pszKey ) bCheckMulti = Exp_GetVal(pszKey) != 0; sVal.FormatVal( g_World.IsItemTypeNear(*this, static_cast<IT_TYPE>(iType), iDistance, bCheckMulti)); break; } case PT_REGION: { // Check that the syntax is correct. if ( pszKey[6] && pszKey[6] != '.' ) return false; CRegionWorld * pRegionTemp = dynamic_cast <CRegionWorld*>(this->GetRegion(REGION_TYPE_AREA | REGION_TYPE_MULTI)); if ( !pszKey[6] ) { // We're just checking if the reference is valid. sVal.FormatVal( pRegionTemp? 1:0 ); return true; } // We're trying to retrieve a property from the region. pszKey += 7; if ( pRegionTemp ) return pRegionTemp->r_WriteVal( pszKey, sVal, &g_Serv ); return false; } case PT_ROOM: { if ( pszKey[4] && pszKey[4] != '.' ) return false; CRegionBase * pRegionTemp = this->GetRegion( REGION_TYPE_ROOM ); if ( !pszKey[4] ) { sVal.FormatVal( pRegionTemp? 1:0 ); return true; } pszKey += 5; if ( pRegionTemp ) return pRegionTemp->r_WriteVal( pszKey, sVal, &g_Serv ); return false; } case PT_SECTOR: { if ( pszKey[6] == '.' ) { pszKey += 7; CSector * pSectorTemp = this->GetSector(); if (pSectorTemp) return pSectorTemp->r_WriteVal(pszKey, sVal, &g_Serv); } return false; } default: { const CUOMapMeter * pMeter = g_World.GetMapMeter(*this); if ( pMeter ) { switch( index ) { case PT_TYPE: { CItemTypeDef * pTypeDef = g_World.GetTerrainItemTypeDef( pMeter->m_wTerrainIndex ); if ( pTypeDef != NULL ) sVal = pTypeDef->GetResourceName(); else sVal = ""; } return true; case PT_TERRAIN: { pszKey += strlen(sm_szLoadKeys[index]); if ( *pszKey == '.' ) // do we have an argument? { SKIP_SEPARATORS( pszKey ); if ( !strnicmp( pszKey, "Z", 1 )) { sVal.FormatVal( pMeter->m_z ); return( true ); } return( false ); } else { sVal.FormatHex( pMeter->m_wTerrainIndex ); } } return true; } } return false; } } return true; }
bool CImportFile::ImportWSC( CScript & s, WORD wModeFlags ) { ADDTOCALLSTACK("CImportFile::ImportWSC"); // This file is a WSC or UOX world script file. IMPFLAGS_TYPE mode = IMPFLAGS_NOTHING; CGString sName; CItem * pItem = NULL; CChar * pChar = NULL; while ( s.ReadTextLine(true)) { if ( s.IsKeyHead( "SECTION WORLDITEM", 17 )) { CheckLast(); mode = IMPFLAGS_ITEMS; continue; } else if ( s.IsKeyHead( "SECTION CHARACTER", 17 )) { CheckLast(); mode = ( wModeFlags & IMPFLAGS_CHARS ) ? IMPFLAGS_CHARS : IMPFLAGS_NOTHING; continue; } else if ( s.GetKey()[0] == '{' ) { CheckLast(); continue; } else if ( s.GetKey()[0] == '}' ) { CheckLast(); mode = IMPFLAGS_NOTHING; continue; } else if ( mode == IMPFLAGS_NOTHING ) continue; else if ( s.GetKey()[0] == '\\' ) continue; // Parse the line. TCHAR* pKey = const_cast<TCHAR*>(strchr(s.GetKey(), ' ')); LPCTSTR pArg = NULL; if (pKey != NULL) { *pKey++ = '\0'; GETNONWHITESPACE(pKey); pArg = pKey; } else { pArg = ""; } if ( s.IsKey("SERIAL" )) { if ( m_pCurSer != NULL ) return( false ); DWORD dwSerial = ATOI( pArg ); if ( dwSerial == UID_UNUSED ) { DEBUG_ERR(( "Import:Bad serial number\n" )); break; } m_pCurSer = new CImportSer( dwSerial ); m_ListSer.InsertHead( m_pCurSer ); continue; } if ( s.IsKey("NAME" )) { sName = ( pArg[0] == '#' ) ? "" : pArg; if ( mode == IMPFLAGS_ITEMS ) continue; } if ( m_pCurSer == NULL ) { DEBUG_ERR(( "Import:No serial number\n" )); break; } if ( mode == IMPFLAGS_ITEMS ) // CItem. { if ( s.IsKey("ID" )) { if ( m_pCurObj != NULL ) return( false ); pItem = CItem::CreateTemplate(static_cast<ITEMID_TYPE>(ATOI(pArg))); pItem->SetName( sName ); m_pCurObj = pItem; m_pCurSer->m_pObj = pItem; continue; } if ( m_pCurObj == NULL ) { DEBUG_ERR(( "Import:Bad Item Key '%s'\n", s.GetKey())); break; } else if ( s.IsKey("CONT" )) { m_pCurSer->m_dwContSer = ATOI(pArg); } else if ( s.IsKey("LAYER" )) { m_pCurSer->m_layer = static_cast<LAYER_TYPE>(ATOI(pArg)); continue; } else if (pItem == NULL) { DEBUG_ERR(( "Import:Found '%s' before ID.\n", s.GetKey())); continue; } if ( s.IsKey("X" )) { CPointMap pt = pItem->GetTopPoint(); pt.m_x = static_cast<short>( ATOI(pArg) ); pItem->SetUnkPoint(pt); continue; } else if ( s.IsKey("Y" )) { CPointMap pt = pItem->GetTopPoint(); pt.m_y = static_cast<short>( ATOI(pArg) ); pItem->SetUnkPoint(pt); continue; } else if ( s.IsKey("Z" )) { CPointMap pt = pItem->GetTopPoint(); pt.m_z = static_cast<signed char>( ATOI(pArg) ); pItem->SetUnkPoint(pt); continue; } else if ( s.IsKey("COLOR" )) { pItem->SetHue( static_cast<HUE_TYPE>( ATOI(pArg) ) ); continue; } else if ( s.IsKey("AMOUNT" )) { pItem->SetAmount( ATOI(pArg)); continue; } else if ( s.IsKey("MOREX" )) { pItem->m_itNormal.m_morep.m_x = static_cast<short>(ATOI(pArg)); continue; } else if ( s.IsKey("MOREY" )) { pItem->m_itNormal.m_morep.m_y = static_cast<short>(ATOI(pArg)); continue; } else if ( s.IsKey("MOREZ" )) { pItem->m_itNormal.m_morep.m_z = static_cast<signed char>( ATOI(pArg) ); continue; } else if ( s.IsKey("MORE" )) { pItem->m_itNormal.m_more1 = ATOI(pArg); continue; } else if ( s.IsKey("MORE2" )) { pItem->m_itNormal.m_more2 = ATOI(pArg); continue; } else if ( s.IsKey("DYEABLE" )) { //if ( ATOI(pArg)) // pItem->m_pDef->m_Can |= CAN_I_DYE; continue; } else if ( s.IsKey("ATT" )) { // pItem->m_pDef->m_attackBase = ATOI(pArg); } else if ( s.IsKey("TYPE" )) { // ??? translate the type field. //int i = ATOI(pArg); } } if ( mode == IMPFLAGS_CHARS ) { if ( s.IsKey("NAME" )) { if ( m_pCurObj != NULL ) return( false ); pChar = CChar::CreateBasic( CREID_MAN ); pChar->SetName( sName ); m_pCurObj = pChar; m_pCurSer->m_pObj = pChar; continue; } if ( m_pCurObj == NULL ) { DEBUG_ERR(( "Import:Bad Item Key '%s'\n", s.GetKey())); break; } else if (pChar == NULL) { DEBUG_ERR(( "Import:Found '%s' before NAME.\n", s.GetKey())); continue; } if ( s.IsKey("X" )) { CPointMap pt = pChar->GetTopPoint(); pt.m_x = static_cast<signed short>(ATOI(pArg)); pChar->SetUnkPoint(pt); continue; } else if ( s.IsKey("Y" )) { CPointMap pt = pChar->GetTopPoint(); pt.m_y = static_cast<signed short>(ATOI(pArg)); pChar->SetUnkPoint(pt); continue; } else if ( s.IsKey("Z" )) { CPointMap pt = pChar->GetTopPoint(); pt.m_z = static_cast<signed char>(ATOI(pArg)); pChar->SetUnkPoint(pt); continue; } else if ( s.IsKey("BODY" )) { pChar->SetID(static_cast<CREID_TYPE>(ATOI(pArg))); continue; } else if ( s.IsKey("SKIN" )) { pChar->SetHue( static_cast<HUE_TYPE>( ATOI(pArg) )); continue; } else if ( s.IsKey("DIR" )) { pChar->m_dirFace = static_cast<DIR_TYPE>(ATOI(pArg)); if ( pChar->m_dirFace < 0 || pChar->m_dirFace >= DIR_QTY ) pChar->m_dirFace = DIR_SE; continue; } else if ( s.IsKey("XBODY" )) { pChar->m_prev_id = static_cast<CREID_TYPE>(ATOI(pArg)); continue; } else if ( s.IsKey("XSKIN" )) { pChar->m_prev_Hue = static_cast<HUE_TYPE>( ATOI(pArg) ); continue; } else if ( s.IsKey("FONT" )) { pChar->m_fonttype = static_cast<FONT_TYPE>(ATOI(pArg)); continue; } else if ( s.IsKey("KARMA" )) { pChar->Stat_SetBase(STAT_KARMA, static_cast<short>(ATOI(pArg))); continue; } else if ( s.IsKey("FAME" )) { pChar->Stat_SetBase(STAT_FAME, static_cast<short>(ATOI(pArg))); continue; } else if ( s.IsKey("TITLE" )) { pChar->m_sTitle = pArg; continue; } else if ( s.IsKey("STRENGTH" )) { pChar->Stat_SetBase(STAT_STR, static_cast<short>(ATOI(pArg))); } else if ( s.IsKey("DEXTERITY" )) { pChar->Stat_SetBase(STAT_DEX, static_cast<short>(ATOI(pArg))); } else if ( s.IsKey("INTELLIGENCE" )) { pChar->Stat_SetBase(STAT_INT, static_cast<short>(ATOI(pArg))); } else if ( s.IsKey("HITPOINTS" )) { pChar->Stat_SetVal(STAT_STR,static_cast<short>(ATOI(pArg))); } else if ( s.IsKey("STAMINA" )) { pChar->Stat_SetVal(STAT_DEX,static_cast<short>(ATOI(pArg))); } else if ( s.IsKey( "MANA" )) { pChar->Stat_SetVal(STAT_INT,static_cast<short>(ATOI(pArg))); } else if ( s.IsKeyHead( "SKILL", 5 )) { SKILL_TYPE skill = static_cast<SKILL_TYPE>(ATOI( &(s.GetKey()[5]))); if ( pChar->IsSkillBase(skill) && g_Cfg.m_SkillIndexDefs.IsValidIndex(skill) ) pChar->Skill_SetBase(skill, static_cast<WORD>(ATOI(pArg))); } else if ( s.IsKey("ACCOUNT" )) { // What if the account does not exist ? pChar->SetPlayerAccount( pArg ); } else if ( s.IsKey("KILLS" ) && pChar->m_pPlayer ) { pChar->m_pPlayer->m_wMurders = static_cast<WORD>(ATOI(pArg)); } else if ( s.IsKey("NPCAITYPE" )) { // Convert to proper NPC type. int i = ATOI( pArg ); switch ( i ) { case 0x01: pChar->SetNPCBrain( NPCBRAIN_HEALER ); break; case 0x02: pChar->SetNPCBrain( NPCBRAIN_MONSTER ); break; case 0x04: case 0x40: pChar->SetNPCBrain( NPCBRAIN_GUARD ); break; case 0x08: pChar->SetNPCBrain( NPCBRAIN_BANKER ); break; default: pChar->SetNPCBrain( pChar->GetNPCBrain( false )); break; } } continue; } } return( true ); }