bool CClient::CanHear( const CObjBaseTemplate * pSrc, TALKMODE_TYPE mode ) const { ADDTOCALLSTACK("CClient::CanHear"); // can we hear this text or sound. if ( !IsConnectTypePacket() ) return false; if ( !pSrc || (mode == TALKMODE_BROADCAST) ) return true; if ( !m_pChar ) return false; if ( IsPriv(PRIV_HEARALL) && pSrc->IsChar() && ((mode == TALKMODE_SYSTEM) || (mode == TALKMODE_SAY) || (mode == TALKMODE_WHISPER) || (mode == TALKMODE_YELL)) ) { const CChar *pCharSrc = dynamic_cast<const CChar *>(pSrc); ASSERT(pCharSrc); if ( pCharSrc && pCharSrc->m_pClient ) { if ( pCharSrc->GetPrivLevel() <= GetPrivLevel() ) return true; } } return m_pChar->CanHear(pSrc, mode); }
bool CClient::CanHear( const CObjBaseTemplate * pSrc, TALKMODE_TYPE mode ) const { ADDTOCALLSTACK("CClient::CanHear"); // can we hear this text or sound. if ( !IsConnectTypePacket() ) return( false ); if ( mode == TALKMODE_BROADCAST || pSrc == NULL ) return( true ); if ( m_pChar == NULL ) return( false ); if ( IsPriv( PRIV_HEARALL ) && pSrc->IsChar()&& ( mode == TALKMODE_SYSTEM || mode == TALKMODE_SAY || mode == TALKMODE_WHISPER || mode == TALKMODE_YELL )) { const CChar * pCharSrc = dynamic_cast <const CChar*> ( pSrc ); ASSERT(pCharSrc); if ( pCharSrc && pCharSrc->IsClient()) { if ( pCharSrc->GetPrivLevel() <= GetPrivLevel()) { return( true ); } } } return( m_pChar->CanHear( pSrc, mode )); }
bool CClient::CanInstantLogOut() const { ADDTOCALLSTACK("CClient::CanInstantLogOut"); if ( g_Serv.IsLoading()) // or exiting. return( true ); if ( ! g_Cfg.m_iClientLingerTime ) return true; if ( IsPriv( PRIV_GM )) return true; if ( m_pChar == NULL ) return( true ); if ( m_pChar->IsStatFlag(STATF_DEAD)) return( true ); const CRegionWorld * pArea = m_pChar->GetRegion(); if ( pArea == NULL ) return( true ); if ( pArea->IsFlag( REGION_FLAG_INSTA_LOGOUT )) return( true ); const CRegionBase * pRoom = m_pChar->GetRoom(); //Allows Room flag to work! if ( pRoom != NULL && pRoom->IsFlag( REGION_FLAG_INSTA_LOGOUT )) //sanity check for null rooms // Can C++ guarantee short-circuit evaluation for CRegionBase ? return( true ); return( false ); }
bool CChar::FollowersUpdate( CChar * pChar, short iFollowerSlots, bool bCheckOnly ) { ADDTOCALLSTACK("CChar::FollowersUpdate"); // Attemp to update followers on this character based on pChar // bSustract = true for pet's release, shrink, etc ... // This is supossed to be called only when OF_PetSlots is enabled, so no need to check it here. if ( !bCheckOnly && IsTrigUsed(TRIGGER_FOLLOWERSUPDATE) ) { CScriptTriggerArgs Args; Args.m_iN1 = (iFollowerSlots > 0) ? 0 : 1; Args.m_iN2 = abs(iFollowerSlots); if ( OnTrigger(CTRIG_FollowersUpdate, pChar, &Args) == TRIGRET_RET_TRUE ) return false; iFollowerSlots = static_cast<short>(Args.m_iN2); } short iCurFollower = static_cast<short>(GetDefNum("CURFOLLOWER", true, true)); short iMaxFollower = static_cast<short>(GetDefNum("MAXFOLLOWER", true, true)); short iSetFollower = iCurFollower + iFollowerSlots; if ( (iSetFollower > iMaxFollower) && !IsPriv(PRIV_GM) ) return false; if ( !bCheckOnly ) { SetDefNum("CURFOLLOWER", maximum(iSetFollower, 0)); UpdateStatsFlag(); } return true; }
bool CClient::CanSee( const CObjBaseTemplate * pObj ) const { ADDTOCALLSTACK("CClient::CanSee"); // Can player see item b if ( m_pChar == NULL || pObj == NULL ) return false; if (!IsPriv(PRIV_ALLSHOW) && pObj->IsChar()) { const CChar *pChar = static_cast<const CChar*>(pObj); if (pChar->IsDisconnected()) return false; } return( m_pChar->CanSee( pObj )); }
bool CClient::CanInstantLogOut() const { ADDTOCALLSTACK("CClient::CanInstantLogOut"); if ( g_Serv.IsLoading() ) return true; if ( !g_Cfg.m_iClientLingerTime || IsPriv(PRIV_GM) ) return true; if ( !m_pChar || m_pChar->IsStatFlag(STATF_DEAD) ) return true; if ( !m_pChar->m_pArea || m_pChar->m_pArea->IsFlag(REGION_FLAG_INSTA_LOGOUT) ) return true; if ( m_pChar->m_pRoom && m_pChar->m_pRoom->IsFlag(REGION_FLAG_INSTA_LOGOUT) ) return true; return false; }
bool CClient::CanInstantLogOut() const { ADDTOCALLSTACK("CClient::CanInstantLogOut"); if ( g_Serv.IsLoading() ) // or exiting. return true; if ( !g_Cfg.m_iClientLingerTime || IsPriv(PRIV_GM) ) return true; if ( !m_pChar || m_pChar->IsStatFlag(STATF_DEAD) ) return true; const CRegionWorld *pArea = m_pChar->GetRegion(); if ( !pArea || pArea->IsFlag(REGION_FLAG_INSTA_LOGOUT) ) return true; const CRegionBase *pRoom = m_pChar->GetRoom(); if ( pRoom && pRoom->IsFlag(REGION_FLAG_INSTA_LOGOUT) ) return true; return false; }
bool CClient::CanHear(const CObjBaseTemplate *pSrc, TALKMODE_TYPE mode) const { ADDTOCALLSTACK("CClient::CanHear"); // can we hear this text or sound. if ( !IsConnectTypePacket() ) return false; if ( !pSrc ) return true; if ( !m_pChar ) return false; if ( IsPriv(PRIV_HEARALL) && pSrc->IsChar() && ((mode == TALKMODE_SAY) || (mode == TALKMODE_WHISPER) || (mode == TALKMODE_YELL)) ) { const CChar *pChar = static_cast<const CChar *>(pSrc); if ( GetPrivLevel() >= pChar->GetPrivLevel() ) return true; } return m_pChar->CanHear(pSrc, mode); }
bool CClient::r_WriteVal( LPCTSTR pszKey, CGString & sVal, CTextConsole * pSrc ) { ADDTOCALLSTACK("CClient::r_WriteVal"); EXC_TRY("WriteVal"); int index; if ( !strnicmp("CTAG.", pszKey, 5) ) // CTAG.xxx - client tag { if ( pszKey[4] != '.' ) return( false ); pszKey += 5; CVarDefCont *vardef = m_TagDefs.GetKey(pszKey); sVal = vardef ? vardef->GetValStr() : ""; return true; } if ( !strnicmp("CTAG0.", pszKey, 6) ) // CTAG0.xxx - client tag { if ( pszKey[5] != '.' ) return( false ); pszKey += 6; CVarDefCont *vardef = m_TagDefs.GetKey(pszKey); sVal = vardef ? vardef->GetValStr() : "0"; return true; } if ( !strnicmp( "TARGP", pszKey, 5 ) && ( pszKey[5] == '\0' || pszKey[5] == '.' ) ) index = CC_TARGP; else if ( !strnicmp( "SCREENSIZE", pszKey, 10 ) && ( pszKey[10] == '\0' || pszKey[10] == '.' ) ) index = CC_SCREENSIZE; else if ( !strnicmp( "REPORTEDCLIVER", pszKey, 14 ) && ( pszKey[14] == '\0' || pszKey[14] == '.' ) ) index = CC_REPORTEDCLIVER; else index = FindTableSorted( pszKey, sm_szLoadKeys, COUNTOF(sm_szLoadKeys)-1 ); switch (index) { case CC_ALLMOVE: sVal.FormatVal( IsPriv( PRIV_ALLMOVE )); break; case CC_ALLSHOW: sVal.FormatVal( IsPriv( PRIV_ALLSHOW )); break; case CC_CLIENTIS3D: sVal.FormatVal( GetNetState()->isClient3D() ); break; case CC_CLIENTISKR: sVal.FormatVal( GetNetState()->isClientKR() ); break; case CC_CLIENTISSA: sVal.FormatVal( GetNetState()->isClientSA() ); break; case CC_CLIENTVERSION: { TCHAR szVersion[ 128 ]; sVal = m_Crypt.WriteClientVer( szVersion ); } break; case CC_DEBUG: sVal.FormatVal( IsPriv( PRIV_DEBUG )); break; case CC_DETAIL: sVal.FormatVal( IsPriv( PRIV_DETAIL )); break; case CC_GM: // toggle your GM status on/off sVal.FormatVal( IsPriv( PRIV_GM )); break; case CC_HEARALL: sVal.FormatVal( IsPriv( PRIV_HEARALL )); break; case CC_LASTEVENT: sVal.FormatLLVal( m_timeLastEvent.GetTimeRaw() ); break; case CC_PRIVSHOW: // Show my priv title. sVal.FormatVal( ! IsPriv( PRIV_PRIV_NOSHOW )); break; case CC_REPORTEDCLIVER: { pszKey += strlen(sm_szLoadKeys[index]); GETNONWHITESPACE( pszKey ); int iCliVer = (GetNetState()->getReportedVersion() & 0xFFFFFF0); if ( pszKey[0] != '\0' ) iCliVer = GetNetState()->getReportedVersion(); TCHAR szVersion[128]; sVal = CCrypt::WriteClientVerString( iCliVer, szVersion ); } break; case CC_SCREENSIZE: { if ( pszKey[10] == '.' ) { pszKey += strlen(sm_szLoadKeys[index]); SKIP_SEPARATORS(pszKey); if ( !strnicmp("X", pszKey, 1) ) sVal.Format( "%lu", m_ScreenSize.x ); else if ( !strnicmp("Y", pszKey, 1) ) sVal.Format( "%lu", m_ScreenSize.y ); else return( false ); } else sVal.Format( "%lu,%lu", m_ScreenSize.x, m_ScreenSize.y ); } break; case CC_TARG: sVal.FormatHex(m_Targ_UID); break; case CC_TARGP: if ( pszKey[5] == '.' ) { return m_Targ_p.r_WriteVal( pszKey+6, sVal ); } sVal = m_Targ_p.WriteUsed(); break; case CC_TARGPROP: sVal.FormatHex(m_Prop_UID); break; case CC_TARGPRV: sVal.FormatHex(m_Targ_PrvUID); break; case CC_TARGTXT: sVal = m_Targ_Text; break; default: return( CScriptObj::r_WriteVal( pszKey, sVal, pSrc )); } return true; EXC_CATCH; EXC_DEBUG_START; EXC_ADD_KEYRET(pSrc); EXC_DEBUG_END; return false; }
bool CChar::Use_Item_Web( CItem * pItemWeb ) { ADDTOCALLSTACK("CChar::Use_Item_Web"); // IT_WEB // IT_EQ_STUCK // Try to break out of the web. // Or just try to damage it. // // RETURN: true = held in place. // false = walk thru it. if ( GetDispID() == CREID_GIANT_SPIDER || !pItemWeb || !pItemWeb->IsTopLevel() || IsStatFlag(STATF_DEAD|STATF_Insubstantial) || IsPriv(PRIV_GM) ) return false; // just walk through it // Try to break it. int iStr = pItemWeb->m_itWeb.m_Hits_Cur; if ( iStr == 0 ) iStr = pItemWeb->m_itWeb.m_Hits_Cur = 60 + Calc_GetRandVal(250); // Since broken webs become spider silk, we should get out of here now if we aren't in a web. CItem *pFlag = LayerFind(LAYER_FLAG_Stuck); if ( CanMove(pItemWeb, false) ) { if ( pFlag ) pFlag->Delete(); return false; } if ( pFlag ) { if ( pFlag->IsTimerSet() ) // don't allow me to try to damage it too often return true; } int iDmg = pItemWeb->OnTakeDamage(Stat_GetAdjusted(STAT_STR), this); switch ( iDmg ) { case 0: // damage blocked case 1: // web survived default: // unknown if ( GetTopPoint() == pItemWeb->GetTopPoint() ) // is character still stuck on the web? break; case 2: // web turned into silk case INT_MAX: // web destroyed if ( pFlag ) pFlag->Delete(); return false; } // Stuck in it still. if ( !pFlag ) { if ( iDmg < 0 ) return false; // First time message. pFlag = CItem::CreateBase(ITEMID_WEB1_1); ASSERT(pFlag); pFlag->SetAttr(ATTR_DECAY); pFlag->SetType(IT_EQ_STUCK); pFlag->m_uidLink = pItemWeb->GetUID(); pFlag->SetTimeout(pItemWeb->GetTimerDAdjusted()); LayerAdd(pFlag, LAYER_FLAG_Stuck); } else { if ( iDmg < 0 ) { pFlag->Delete(); return false; } SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SWEB_STUCK), pItemWeb->GetName()); } return true; }
int CChar::Do_Use_Item(CItem *pItem, bool fLink) { ADDTOCALLSTACK("CChar::Do_Use_Item"); if (!pItem) return false; if (m_pNPC && (IsTrigUsed(TRIGGER_DCLICK) || IsTrigUsed(TRIGGER_ITEMDCLICK))) // for players, DClick was called before this function { if (pItem->OnTrigger(ITRIG_DCLICK, this) == TRIGRET_RET_TRUE) return false; } CItemSpawn *pSpawn = static_cast<CItemSpawn *>(pItem->m_uidSpawnItem.ItemFind()); if (pSpawn) pSpawn->DelObj(pItem->GetUID()); // remove this item from it's spawn when DClicks it int fAction = true; switch(pItem->GetType()) { case IT_ITEM_STONE: { // Give them this item if (pItem->m_itItemStone.m_wAmount == USHRT_MAX) { SysMessageDefault(DEFMSG_MSG_IT_IS_DEAD); return true; } if (pItem->m_itItemStone.m_wRegenTime) { if (pItem->IsTimerSet()) { SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_MSG_STONEREG_TIME), pItem->GetTimerDiff() / TICK_PER_SEC); return true; } pItem->SetTimeout(pItem->m_itItemStone.m_wRegenTime * TICK_PER_SEC); } ItemBounce(CItem::CreateTemplate(pItem->m_itItemStone.m_ItemID, GetPackSafe(), this)); if (pItem->m_itItemStone.m_wAmount != 0) { pItem->m_itItemStone.m_wAmount--; if (pItem->m_itItemStone.m_wAmount == 0) pItem->m_itItemStone.m_wAmount = USHRT_MAX; } return true; } case IT_SEED: return Use_Seed(pItem, NULL); case IT_BEDROLL: return Use_BedRoll(pItem); case IT_KINDLING: return Use_Kindling(pItem); case IT_SPINWHEEL: { if (fLink) return false; // Just make them spin pItem->SetAnim(static_cast<ITEMID_TYPE>(pItem->GetID() + 1), 2 * TICK_PER_SEC); SysMessageDefault(DEFMSG_ITEMUSE_SPINWHEEL); return true; } case IT_TRAIN_DUMMY: { if (fLink) return false; Use_Train_Dummy(pItem, true); return true; } case IT_TRAIN_PICKPOCKET: { if (fLink) return false; Use_Train_PickPocketDip(pItem, true); return true; } case IT_ARCHERY_BUTTE: { if (fLink) return false; Use_Train_ArcheryButte(pItem, true); return true; } case IT_LOOM: { if (fLink) return false; SysMessageDefault(DEFMSG_ITEMUSE_LOOM); return true; } case IT_BEE_HIVE: { if (fLink) return false; // Get honey from it ITEMID_TYPE id = ITEMID_NOTHING; if (!pItem->m_itBeeHive.m_honeycount) SysMessageDefault(DEFMSG_ITEMUSE_BEEHIVE); else { switch(Calc_GetRandVal(3)) { case 1: id = ITEMID_JAR_HONEY; break; case 2: id = ITEMID_BEE_WAX; break; } } if (id) { ItemBounce(CItem::CreateScript(id, this)); pItem->m_itBeeHive.m_honeycount--; } else { SysMessageDefault(DEFMSG_ITEMUSE_BEEHIVE_STING); OnTakeDamage(Calc_GetRandVal(5), this, DAMAGE_POISON | DAMAGE_GENERAL); } pItem->SetTimeout(15 * 60 * TICK_PER_SEC); return true; } case IT_MUSICAL: { if (!Skill_Wait(SKILL_MUSICIANSHIP)) { m_Act_Targ = pItem->GetUID(); Skill_Start(SKILL_MUSICIANSHIP); } break; } case IT_CROPS: case IT_FOLIAGE: { // Pick cotton/hay/etc fAction = pItem->Plant_Use(this); break; } case IT_FIGURINE: { // Create the creature here if (Use_Figurine(pItem) != NULL) pItem->Delete(); return true; } case IT_TRAP: case IT_TRAP_ACTIVE: { // Activate the trap (plus any linked traps) int iDmg = pItem->Use_Trap(); if (CanTouch(pItem->GetTopLevelObj()->GetTopPoint())) OnTakeDamage(iDmg, NULL, DAMAGE_HIT_BLUNT | DAMAGE_GENERAL); break; } case IT_SWITCH: { // Switches can be linked to gates and doors and such. // Flip the switch graphic. pItem->SetSwitchState(); break; } case IT_PORT_LOCKED: if (!fLink && !IsPriv(PRIV_GM)) { SysMessageDefault(DEFMSG_ITEMUSE_PORT_LOCKED); return true; } case IT_PORTCULIS: // Open a metal gate vertically pItem->Use_Portculis(); break; case IT_DOOR_LOCKED: if (!ContentFindKeyFor(pItem)) { SysMessageDefault(DEFMSG_MSG_KEY_DOORLOCKED); if (!pItem->IsTopLevel()) return false; if (pItem->IsAttr(ATTR_MAGIC)) // show it's magic face { ITEMID_TYPE id = (GetDispID() & DOOR_NORTHSOUTH) ? ITEMID_DOOR_MAGIC_SI_NS : ITEMID_DOOR_MAGIC_SI_EW; CItem *pFace = CItem::CreateBase(id); ASSERT(pFace); pFace->MoveToDecay(pItem->GetTopPoint(), 4 * TICK_PER_SEC); } if (!IsPriv(PRIV_GM)) return true; } case IT_DOOR_OPEN: case IT_DOOR: { bool fOpen = pItem->Use_DoorNew(fLink); if (fLink || !fOpen) // don't link if we are just closing the door return true; } break; case IT_SHIP_PLANK: { // Close the plank if I'm inside the ship if (m_pArea->IsFlag(REGION_FLAG_SHIP) && m_pArea->GetResourceID() == pItem->m_uidLink) { if (pItem->m_itShipPlank.m_itSideType == IT_SHIP_SIDE_LOCKED && !ContentFindKeyFor(pItem)) { SysMessageDefault(DEFMSG_ITEMUSE_SHIPSIDE); return true; } return pItem->Ship_Plank(false); } else if (pItem->IsTopLevel()) { // Teleport to plank if I'm outside the ship CPointMap pntTarg = pItem->GetTopPoint(); pntTarg.m_z++; Spell_Teleport(pntTarg, true, false, false); } return true; } case IT_SHIP_SIDE_LOCKED: if (!ContentFindKeyFor(pItem)) { SysMessageDefault(DEFMSG_ITEMUSE_SHIPSIDE); return true; } case IT_SHIP_SIDE: // Open the plank pItem->Ship_Plank(true); return true; case IT_GRAIN: case IT_GRASS: case IT_GARBAGE: case IT_FRUIT: case IT_FOOD: case IT_FOOD_RAW: case IT_MEAT_RAW: { if (fLink) return false; Use_Eat(pItem); return true; } case IT_POTION: case IT_DRINK: case IT_PITCHER: case IT_WATER_WASH: case IT_BOOZE: { if (fLink) return false; Use_Drink(pItem); return true; } case IT_LIGHT_OUT: // can the light be lit? case IT_LIGHT_LIT: // can the light be doused? fAction = pItem->Use_Light(); break; case IT_CLOTHING: case IT_ARMOR: case IT_ARMOR_LEATHER: case IT_SHIELD: case IT_WEAPON_MACE_CROOK: case IT_WEAPON_MACE_PICK: case IT_WEAPON_MACE_SMITH: case IT_WEAPON_MACE_SHARP: case IT_WEAPON_SWORD: case IT_WEAPON_FENCE: case IT_WEAPON_BOW: case IT_WEAPON_AXE: case IT_WEAPON_XBOW: case IT_WEAPON_MACE_STAFF: case IT_JEWELRY: case IT_WEAPON_THROWING: { if (fLink) return false; return ItemEquip(pItem); } case IT_WEB: { if (fLink) return false; Use_Item_Web(pItem); return true; } case IT_SPY_GLASS: { if (fLink) return false; // Spyglass will tell you the moon phases static LPCTSTR const sm_sPhases[8] = { g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M1), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M2), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M3), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M4), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M5), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M6), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M7), g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_M8) }; SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_TR), sm_sPhases[g_World.GetMoonPhase(false)]); SysMessagef(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SPYGLASS_FE), sm_sPhases[g_World.GetMoonPhase(true)]); if (m_pArea && m_pArea->IsFlag(REGION_FLAG_SHIP)) ObjMessage(pItem->Use_SpyGlass(this), this); return true; } case IT_SEXTANT: { if (fLink) return false; if ((GetTopPoint().m_map <= 1) && (GetTopPoint().m_x > UO_SIZE_X_REAL)) // dungeons and T2A lands ObjMessage(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SEXTANT_T2A), this); else { TCHAR *pszMsg = Str_GetTemp(); sprintf(pszMsg, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SEXTANT), m_pArea->GetName(), pItem->Use_Sextant(GetTopPoint())); ObjMessage(pszMsg, this); } return true; } default: fAction = false; } return fAction | MASK_RETURN_FOLLOW_LINKS; }
CChar * CChar::Use_Figurine( CItem * pItem, bool bCheckFollowerSlots ) { ADDTOCALLSTACK("CChar::Use_Figurine"); // NOTE: The figurine is NOT destroyed. bool bCreatedNewNpc = false; if ( !pItem ) return NULL; if ( pItem->m_uidLink.IsValidUID() && pItem->m_uidLink.IsChar() && pItem->m_uidLink != GetUID() && !IsPriv(PRIV_GM) ) { SysMessageDefault(DEFMSG_MSG_FIGURINE_NOTYOURS); return NULL; } // Create a new NPC if there's no one linked to this figurine CChar *pPet = pItem->m_itFigurine.m_UID.CharFind(); if ( !pPet ) { CREID_TYPE id = pItem->m_itFigurine.m_ID; if ( !id ) { id = CItemBase::FindCharTrack(pItem->GetID()); if ( !id ) { DEBUG_ERR(("FIGURINE id 0%x, no creature\n", pItem->GetDispID())); return NULL; } } bCreatedNewNpc = true; pPet = CreateNPC(id); ASSERT(pPet); pPet->SetName(pItem->GetName()); if ( pItem->GetHue() ) { pPet->m_prev_Hue = pItem->GetHue(); pPet->SetHue(pItem->GetHue()); } } if ( bCheckFollowerSlots && IsSetOF(OF_PetSlots) ) { if ( !FollowersUpdate(pPet, static_cast<short>(maximum(1, pPet->GetDefNum("FOLLOWERSLOTS", true, true))), true) ) { SysMessageDefault(DEFMSG_PETSLOTS_TRY_CONTROL); if ( bCreatedNewNpc ) pPet->Delete(); return NULL; } } if ( pPet->IsDisconnected() ) pPet->StatFlag_Clear(STATF_Ridden); // pull the creature out of IDLE space pItem->m_itFigurine.m_UID.InitUID(); pPet->m_dirFace = m_dirFace; pPet->NPC_PetSetOwner(this); pPet->MoveToChar(pItem->GetTopLevelObj()->GetTopPoint()); pPet->Update(); pPet->Skill_Start(SKILL_NONE); // was NPCACT_RIDDEN pPet->SoundChar(CRESND_RAND1); return pPet; }
bool CChar::CanSeeLOS( const CPointMap &ptDst, CPointMap *pptBlock, int iMaxDist, word wFlags, bool bCombatCheck ) const { ADDTOCALLSTACK("CChar::CanSeeLOS"); // 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 ( (m_pPlayer && (g_Cfg.m_iAdvancedLos & ADVANCEDLOS_PLAYER)) || (m_pNPC && (g_Cfg.m_iAdvancedLos & ADVANCEDLOS_NPC)) ) return CanSeeLOS_New(ptDst, pptBlock, iMaxDist, wFlags); // Max distance of iMaxDist // Line of sight check // NOTE: if not blocked. pptBlock is undefined. // 3D LOS later - real LOS, i.e. we can't shoot through the floor, but can shoot through the hole in it 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 return true; CPointMap ptSrc = GetTopPoint(); int iDist = ptSrc.GetDist(ptDst); if ( iDist > iMaxDist ) { blocked: if ( pptBlock ) *pptBlock = ptSrc; return false; // blocked } // Walk towards the object. If any spot is too far above our heads then we can not see what's behind it. int iDistTry = 0; while ( --iDist >= 0 ) { DIR_TYPE dir = ptSrc.GetDir(ptDst); dword dwBlockFlags; if ( dir % 2 && !IsSetEF(EF_NoDiagonalCheckLOS) ) // test only diagonal dirs { CPointMap ptTest = ptSrc; DIR_TYPE dirTest1 = (DIR_TYPE)(dir - 1); // get 1st ortogonal DIR_TYPE dirTest2 = (DIR_TYPE)(dir + 1); // get 2nd ortogonal if ( dirTest2 == DIR_QTY ) // roll over dirTest2 = DIR_N; ptTest.Move(dirTest1); dwBlockFlags = CAN_C_SWIM|CAN_C_WALK|CAN_C_FLY; char z = g_World.GetHeightPoint2(ptTest, dwBlockFlags, true); short zDiff = (short)(abs(z - ptTest.m_z)); if ( (zDiff > PLAYER_HEIGHT) || (dwBlockFlags & (CAN_I_BLOCK|CAN_I_DOOR)) ) // blocked { ptTest = ptSrc; ptTest.Move(dirTest2); { dwBlockFlags = CAN_C_SWIM|CAN_C_WALK|CAN_C_FLY; z = g_World.GetHeightPoint2(ptTest, dwBlockFlags, true); zDiff = (short)(abs(z - ptTest.m_z)); if ( zDiff > PLAYER_HEIGHT ) goto blocked; if ( dwBlockFlags & (CAN_I_BLOCK|CAN_I_DOOR) ) { ptSrc = ptTest; goto blocked; } } } ptTest.m_z = z; } if ( iDist ) { ptSrc.Move(dir); // NOTE: The dir is very coarse and can change slightly. dwBlockFlags = CAN_C_SWIM|CAN_C_WALK|CAN_C_FLY; char z = g_World.GetHeightPoint2(ptSrc, dwBlockFlags, true); short zDiff = (short)(abs(z - ptSrc.m_z)); if ( (zDiff > PLAYER_HEIGHT) || (dwBlockFlags & (CAN_I_BLOCK|CAN_I_DOOR)) || (iDistTry > iMaxDist) ) goto blocked; ptSrc.m_z = z; ++iDistTry; } } if ( abs(ptSrc.m_z - ptDst.m_z) >= 20 ) return false; return true; // made it all the way to the object with no obstructions. }
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_WriteVal(LPCTSTR pszKey, CGString &sVal, CTextConsole *pSrc) { ADDTOCALLSTACK("CClient::r_WriteVal"); EXC_TRY("WriteVal"); if ( !strnicmp("CTAG.", pszKey, 5) ) { if ( pszKey[4] != '.' ) return false; pszKey += 5; CVarDefCont *pVar = m_TagDefs.GetKey(pszKey); sVal = pVar ? pVar->GetValStr() : ""; return true; } if ( !strnicmp("CTAG0.", pszKey, 6) ) { if ( pszKey[5] != '.' ) return false; pszKey += 6; CVarDefCont *pVar = m_TagDefs.GetKey(pszKey); sVal = pVar ? pVar->GetValStr() : "0"; return true; } int index; if ( !strnicmp("TARGP", pszKey, 5) && ((pszKey[5] == '\0') || (pszKey[5] == '.')) ) index = CC_TARGP; else if ( !strnicmp("SCREENSIZE", pszKey, 10) && ((pszKey[10] == '\0') || (pszKey[10] == '.')) ) index = CC_SCREENSIZE; else if ( !strnicmp("REPORTEDCLIVER", pszKey, 14) && ((pszKey[14] == '\0') || (pszKey[14] == '.')) ) index = CC_REPORTEDCLIVER; else index = FindTableSorted(pszKey, sm_szLoadKeys, COUNTOF(sm_szLoadKeys) - 1); switch ( index ) { case CC_ALLMOVE: sVal.FormatVal(IsPriv(PRIV_ALLMOVE)); break; case CC_ALLSHOW: sVal.FormatVal(IsPriv(PRIV_ALLSHOW)); break; case CC_CLIENTIS3D: sVal.FormatVal(m_NetState->isClient3D()); break; case CC_CLIENTISKR: sVal.FormatVal(m_NetState->isClientKR()); break; case CC_CLIENTISSA: sVal.FormatVal(m_NetState->isClientEnhanced()); break; case CC_CLIENTVERSION: { TCHAR szVersion[128]; sVal = m_Crypt.WriteClientVerString(m_Crypt.GetClientVer(), szVersion); break; } case CC_DEBUG: sVal.FormatVal(IsPriv(PRIV_DEBUG)); break; case CC_DETAIL: sVal.FormatVal(IsPriv(PRIV_DETAIL)); break; case CC_GM: sVal.FormatVal(IsPriv(PRIV_GM)); break; case CC_HEARALL: sVal.FormatVal(IsPriv(PRIV_HEARALL)); break; case CC_LASTEVENT: sVal.FormatLLVal(m_timeLastEvent.GetTimeRaw()); break; case CC_PRIVSHOW: sVal.FormatVal(!IsPriv(PRIV_PRIV_NOSHOW)); break; case CC_REPORTEDCLIVER: { pszKey += 14; GETNONWHITESPACE(pszKey); DWORD dwCliVer = m_NetState->getReportedVersion(); if ( pszKey[0] == '\0' ) { // Return full version string (eg: 5.0.2d) TCHAR szVersion[128]; sVal = CCrypt::WriteClientVerString(dwCliVer, szVersion); } else { // Return raw version number (eg: 5.0.2d = 5000204) sVal.FormatUVal(dwCliVer); } break; } case CC_SCREENSIZE: { if ( pszKey[10] == '.' ) { pszKey += 10; SKIP_SEPARATORS(pszKey); if ( !strnicmp("X", pszKey, 1) ) sVal.Format("%hu", m_ScreenSize.x); else if ( !strnicmp("Y", pszKey, 1) ) sVal.Format("%hu", m_ScreenSize.y); else return false; } else sVal.Format("%hu,%hu", m_ScreenSize.x, m_ScreenSize.y); break; } case CC_TARG: sVal.FormatHex(m_Targ_UID); break; case CC_TARGP: { if ( pszKey[5] == '.' ) return m_Targ_p.r_WriteVal(pszKey + 6, sVal); sVal = m_Targ_p.WriteUsed(); break; } case CC_TARGPROP: sVal.FormatHex(m_Prop_UID); break; case CC_TARGPRV: sVal.FormatHex(m_Targ_PrvUID); break; case CC_TARGTXT: sVal = m_Targ_Text; break; default: return CScriptObj::r_WriteVal(pszKey, sVal, pSrc); } return true; EXC_CATCH; EXC_DEBUG_START; EXC_ADD_KEYRET(pSrc); EXC_DEBUG_END; return false; }
bool CClient::r_LoadVal( CScript & s ) { ADDTOCALLSTACK("CClient::r_LoadVal"); EXC_TRY("LoadVal"); if ( GetAccount() == NULL ) return( false ); LPCTSTR pszKey = s.GetKey(); if ( s.IsKeyHead( "CTAG.", 5 ) || s.IsKeyHead( "CTAG0.", 6 ) ) { bool fZero = s.IsKeyHead( "CTAG0.", 6 ); bool fQuoted = false; pszKey = pszKey + (fZero ? 6 : 5); m_TagDefs.SetStr( pszKey, fQuoted, s.GetArgStr( &fQuoted ), fZero ); return( true ); } switch ( FindTableSorted( pszKey, sm_szLoadKeys, COUNTOF(sm_szLoadKeys)-1 )) { case CC_ALLMOVE: addRemoveAll(true, false); GetAccount()->TogPrivFlags( PRIV_ALLMOVE, s.GetArgStr() ); if ( IsSetOF( OF_Command_Sysmsgs ) ) m_pChar->SysMessage( IsPriv(PRIV_ALLMOVE)? "Allmove ON" : "Allmove OFF" ); addPlayerView(NULL); break; case CC_ALLSHOW: addRemoveAll(false, true); GetAccount()->TogPrivFlags( PRIV_ALLSHOW, s.GetArgStr() ); if ( IsSetOF( OF_Command_Sysmsgs ) ) m_pChar->SysMessage( IsPriv(PRIV_ALLSHOW)? "Allshow ON" : "Allshow OFF" ); addPlayerView(NULL); break; case CC_DEBUG: addRemoveAll(true, false); GetAccount()->TogPrivFlags( PRIV_DEBUG, s.GetArgStr() ); if ( IsSetOF( OF_Command_Sysmsgs ) ) m_pChar->SysMessage( IsPriv(PRIV_DEBUG)? "Debug ON" : "Debug OFF" ); addPlayerView(NULL); break; case CC_DETAIL: GetAccount()->TogPrivFlags( PRIV_DETAIL, s.GetArgStr() ); if ( IsSetOF( OF_Command_Sysmsgs ) ) m_pChar->SysMessage( IsPriv(PRIV_DETAIL)? "Detail ON" : "Detail OFF" ); break; case CC_GM: // toggle your GM status on/off if ( GetPrivLevel() >= PLEVEL_GM ) { GetAccount()->TogPrivFlags( PRIV_GM, s.GetArgStr() ); m_pChar->ResendTooltip(); if ( IsSetOF( OF_Command_Sysmsgs ) ) m_pChar->SysMessage( IsPriv(PRIV_GM)? "GM ON" : "GM OFF" ); } break; case CC_HEARALL: GetAccount()->TogPrivFlags( PRIV_HEARALL, s.GetArgStr() ); if ( IsSetOF( OF_Command_Sysmsgs ) ) m_pChar->SysMessage( IsPriv(PRIV_HEARALL)? "Hearall ON" : "Hearall OFF" ); break; case CC_PRIVSHOW: // Hide my priv title. if ( GetPrivLevel() >= PLEVEL_Counsel ) { if ( ! s.HasArgs()) { GetAccount()->TogPrivFlags( PRIV_PRIV_NOSHOW, NULL ); } else if ( s.GetArgVal() ) { GetAccount()->ClearPrivFlags( PRIV_PRIV_NOSHOW ); } else { GetAccount()->SetPrivFlags( PRIV_PRIV_NOSHOW ); } m_pChar->ResendTooltip(); if ( IsSetOF( OF_Command_Sysmsgs ) ) m_pChar->SysMessage( IsPriv(PRIV_PRIV_NOSHOW)? "Privshow OFF" : "Privshow ON" ); } break; case CC_TARG: m_Targ_UID = s.GetArgVal(); break; case CC_TARGP: m_Targ_p.Read( s.GetArgRaw()); if ( !m_Targ_p.IsValidPoint() ) { m_Targ_p.ValidatePoint(); SysMessagef( "Invalid point: %s", s.GetArgStr() ); } break; case CC_TARGPROP: m_Prop_UID = s.GetArgVal(); break; case CC_TARGPRV: m_Targ_PrvUID = s.GetArgVal(); break; default: return( false ); } return true; EXC_CATCH; EXC_DEBUG_START; EXC_ADD_SCRIPT; EXC_DEBUG_END; return false; }
bool CClient::Cmd_Use_Item( CItem *pItem, bool fTestTouch, bool fScript ) { ADDTOCALLSTACK("CClient::Cmd_Use_Item"); // Assume we can see the target. // called from Event_DoubleClick if ( !pItem ) return false; if ( pItem->m_Can & CAN_I_FORCEDC ) fTestTouch = false; if ( fTestTouch ) { if ( !fScript ) { CItemContainer *pContainer = dynamic_cast<CItemContainer *>(pItem->GetParent()); if ( pContainer ) { // protect from ,snoop - disallow picking from not opened containers bool isInOpenedContainer = false; if ( pContainer->GetType() == IT_EQ_TRADE_WINDOW ) isInOpenedContainer = true; else { CClient::OpenedContainerMap_t::iterator itContainerFound = m_openedContainers.find(pContainer->GetUID().GetPrivateUID()); if ( itContainerFound != m_openedContainers.end() ) { DWORD dwTopContainerUID = (((*itContainerFound).second).first).first; DWORD dwTopMostContainerUID = (((*itContainerFound).second).first).second; CPointMap ptOpenedContainerPosition = ((*itContainerFound).second).second; const CObjBaseTemplate *pObjTop = pItem->GetTopLevelObj(); const CObjBase *pObjParent = pContainer->GetParentObj(); DWORD dwTopContainerUID_ToCheck = 0; if ( pObjParent ) dwTopContainerUID_ToCheck = pObjParent->GetUID().GetPrivateUID(); else dwTopContainerUID_ToCheck = pObjTop->GetUID().GetPrivateUID(); if ( (dwTopMostContainerUID == pObjTop->GetUID().GetPrivateUID()) && (dwTopContainerUID == dwTopContainerUID_ToCheck) ) { if ( pObjTop->IsChar() ) { // probably a pickup check from pack if pCharTop != this? isInOpenedContainer = true; } else { const CItem *pItemTop = static_cast<const CItem *>(pObjTop); if ( pItemTop && (pItemTop->IsType(IT_SHIP_HOLD) || pItemTop->IsType(IT_SHIP_HOLD_LOCK)) && (pItemTop->GetTopPoint().GetRegion(REGION_TYPE_MULTI) == m_pChar->GetTopPoint().GetRegion(REGION_TYPE_MULTI)) ) isInOpenedContainer = true; else if ( ptOpenedContainerPosition.GetDist(pObjTop->GetTopPoint()) <= 3 ) isInOpenedContainer = true; } } } } if ( !isInOpenedContainer ) { SysMessageDefault(DEFMSG_REACH_UNABLE); return false; } } } // CanTouch handles priv level compares for chars if ( !m_pChar->CanUse(pItem, false) ) { if ( !m_pChar->CanTouch(pItem) ) SysMessage((m_pChar->IsStatFlag(STATF_DEAD)) ? g_Cfg.GetDefaultMsg(DEFMSG_REACH_GHOST) : g_Cfg.GetDefaultMsg(DEFMSG_REACH_FAIL)); else SysMessageDefault(DEFMSG_REACH_UNABLE); return false; } } if ( IsTrigUsed(TRIGGER_DCLICK) || IsTrigUsed(TRIGGER_ITEMDCLICK) ) { if ( pItem->OnTrigger(ITRIG_DCLICK, m_pChar) == TRIGRET_RET_TRUE ) return true; } CItemBase *pItemDef = pItem->Item_GetDef(); bool bIsEquipped = pItem->IsItemEquipped(); if ( pItemDef->IsTypeEquippable() && !bIsEquipped && pItemDef->GetEquipLayer() ) { bool bMustEquip = true; if ( pItem->IsTypeSpellbook() ) bMustEquip = false; else if ( (pItem->IsType(IT_LIGHT_OUT) || pItem->IsType(IT_LIGHT_LIT)) && !pItem->IsItemInContainer() ) bMustEquip = false; if ( bMustEquip ) { if ( !m_pChar->CanMove(pItem) ) return false; if ( !m_pChar->CanCarry(pItem) ) { SysMessageDefault(DEFMSG_MSG_HEAVY); return false; } if ( !m_pChar->ItemEquip(pItem, NULL, true) ) return false; } } CItemSpawn *pSpawn = static_cast<CItemSpawn *>(pItem->m_uidSpawnItem.ItemFind()); // remove this item from its spawn when players DClick it from ground, no other way to take it out. if ( pSpawn ) pSpawn->DelObj(pItem->GetUID()); SetTargMode(); m_Targ_PrvUID = m_Targ_UID; m_Targ_UID = pItem->GetUID(); m_tmUseItem.m_pParent = pItem->GetParent(); // store item location to check later if it was not moved // Use types of items (specific to client) switch ( pItem->GetType() ) { case IT_TRACKER: { if ( !m_pChar->Skill_Tracking(pItem->m_uidLink) ) { if ( pItem->m_uidLink.IsValidUID() ) SysMessageDefault(DEFMSG_TRACKING_UNABLE); addTarget(CLIMODE_TARG_LINK, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_TRACKER_ATTUNE)); } return true; } case IT_SHAFT: case IT_FEATHER: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_bolts"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_bolts")); } case IT_FISH_POLE: // Just be near water ? addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_FISHING_PROMT), true); return true; case IT_DEED: addTargetDeed(pItem); return true; case IT_EQ_BANK_BOX: case IT_EQ_VENDOR_BOX: if ( !fScript ) g_Log.Event(LOGL_WARN|LOGM_CHEAT, "%lx:Cheater '%s' is using 3rd party tools to open bank box\n", GetSocketID(), m_pAccount->GetName()); return false; case IT_CONTAINER_LOCKED: case IT_SHIP_HOLD_LOCK: if ( !m_pChar->GetContainerCreate(LAYER_PACK)->ContentFindKeyFor(pItem) ) { SysMessageDefault(DEFMSG_ITEMUSE_LOCKED); if ( !IsPriv(PRIV_GM) ) return false; } case IT_CORPSE: case IT_SHIP_HOLD: case IT_CONTAINER: case IT_TRASH_CAN: { CItemContainer *pPack = static_cast<CItemContainer *>(pItem); if ( !pPack ) return false; if ( !m_pChar->Skill_Snoop_Check(pPack) ) { if ( !addContainerSetup(pPack) ) return false; } const CItemCorpse *pCorpseItem = static_cast<const CItemCorpse *>(pPack); if ( m_pChar->CheckCorpseCrime(pCorpseItem, true, true) ) SysMessageDefault(DEFMSG_LOOT_CRIMINAL_ACT); return true; } case IT_GAME_BOARD: { if ( !pItem->IsTopLevel() ) { SysMessageDefault(DEFMSG_ITEMUSE_GAMEBOARD_FAIL); return false; } CItemContainer *pBoard = static_cast<CItemContainer *>(pItem); ASSERT(pBoard); pBoard->Game_Create(); addContainerSetup(pBoard); return true; } case IT_BBOARD: addBulletinBoard(static_cast<CItemContainer *>(pItem)); return true; case IT_SIGN_GUMP: { GUMP_TYPE gumpid = pItemDef->m_ttContainer.m_gumpid; if ( !gumpid ) return false; addGumpTextDisp(pItem, gumpid, pItem->GetName(), pItem->IsIndividualName() ? pItem->GetName() : NULL); return true; } case IT_BOOK: case IT_MESSAGE: { if ( !addBookOpen(pItem) ) SysMessageDefault(DEFMSG_ITEMUSE_BOOK_FAIL); return true; } case IT_STONE_GUILD: case IT_STONE_TOWN: return true; case IT_POTION: { if ( !m_pChar->CanMove(pItem) ) { SysMessageDefault(DEFMSG_ITEMUSE_POTION_FAIL); return false; } if ( RES_GET_INDEX(pItem->m_itPotion.m_Type) == SPELL_Poison ) { // If we click directly on poison potion, we will drink poison and get ill. // To use it on Poisoning skill, the skill will request to target the potion. m_pChar->OnSpellEffect(SPELL_Poison, m_pChar, pItem->m_itSpell.m_spelllevel, NULL); return true; } if ( RES_GET_INDEX(pItem->m_itPotion.m_Type) == SPELL_Explosion ) { // Throw explosion potion if ( !m_pChar->ItemPickup(pItem, 1) ) // put the potion in our hand return false; pItem->m_itPotion.m_tick = 4; // countdown to explode pItem->m_itPotion.m_ignited = 1; // ignite it pItem->m_uidLink = m_pChar->GetUID(); pItem->SetTimeout(TICK_PER_SEC); m_tmUseItem.m_pParent = pItem->GetParent(); addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_SELECT_POTION_TARGET), true, true, pItem->m_itPotion.m_tick * TICK_PER_SEC); return true; } m_pChar->Use_Drink(pItem); return true; } case IT_ANIM_ACTIVE: SysMessage(g_Cfg.GetDefaultMsg(DEFMSG_ITEM_IN_USE)); return false; case IT_CLOCK: addObjMessage(m_pChar->GetTopSector()->GetLocalGameTime(), pItem); return true; case IT_SPAWN_ITEM: case IT_SPAWN_CHAR: { pSpawn = static_cast<CItemSpawn *>(pItem); if ( !pSpawn ) return false; if ( pSpawn->m_currentSpawned ) { SysMessageDefault(DEFMSG_ITEMUSE_SPAWN_NEG); pSpawn->KillChildren(); // Removing existing objects spawned from it ( RESET ). } else { SysMessageDefault(DEFMSG_ITEMUSE_SPAWN_RESET); pSpawn->OnTick(true); // Forcing the spawn to work and create some objects ( START ). } return true; } case IT_SHRINE: { if ( m_pChar->OnSpellEffect(SPELL_Resurrection, m_pChar, 1000, pItem) ) return true; SysMessageDefault(DEFMSG_ITEMUSE_SHRINE); return true; } case IT_SHIP_TILLER: pItem->Speak(g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_TILLERMAN), HUE_TEXT_DEF, TALKMODE_SAY, FONT_NORMAL); return true; case IT_WAND: case IT_SCROLL: { SPELL_TYPE spell = static_cast<SPELL_TYPE>(RES_GET_INDEX(pItem->m_itWeapon.m_spell)); CSpellDef *pSpellDef = g_Cfg.GetSpellDef(spell); if ( !pSpellDef ) return false; if ( IsSetMagicFlags(MAGICF_PRECAST) && !pSpellDef->IsSpellType(SPELLFLAG_NOPRECAST) ) { int skill; if ( !pSpellDef->GetPrimarySkill(&skill, NULL) ) return false; m_tmSkillMagery.m_Spell = spell; // m_atMagery.m_Spell m_pChar->m_atMagery.m_Spell = spell; m_pChar->Skill_Start(static_cast<SKILL_TYPE>(skill)); return true; } return Cmd_Skill_Magery(spell, pItem); } case IT_RUNE: { if ( !m_pChar->CanMove(pItem, true) ) return false; addPromptConsole(CLIMODE_PROMPT_NAME_RUNE, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_RUNE_NAME), pItem->GetUID()); return true; } case IT_CARPENTRY: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_carpentry"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_carpentry")); } case IT_FORGE: // Solve for the combination of this item with another. addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_FORGE)); return true; case IT_ORE: return m_pChar->Skill_Mining_Smelt(pItem, NULL); case IT_INGOT: return Cmd_Skill_Smith(pItem); case IT_KEY: case IT_KEYRING: { if ( pItem->GetTopLevelObj() != m_pChar && !m_pChar->IsPriv(PRIV_GM) ) { SysMessageDefault(DEFMSG_ITEMUSE_KEY_FAIL); return false; } addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_KEY_PROMT), false, true); return true; } case IT_BANDAGE: // SKILL_HEALING, or SKILL_VETERINARY addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_BANDAGE_PROMT), false, false); return true; case IT_BANDAGE_BLOOD: // Clean the bandages. case IT_COTTON: // use on a spinning wheel. case IT_WOOL: // use on a spinning wheel. case IT_YARN: // Use this on a loom. case IT_THREAD: // Use this on a loom. case IT_COMM_CRYSTAL: addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_TARGET_PROMT), false, false); return true; case IT_CARPENTRY_CHOP: case IT_LOCKPICK: // Use on a locked thing. case IT_SCISSORS: addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_TARGET_PROMT), false, true); return true; case IT_WEAPON_MACE_PICK: if ( bIsEquipped || !IsSetOF(OF_NoDClickTarget) ) { // Mine at the location TCHAR *pszTemp = Str_GetTemp(); sprintf(pszTemp, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_MACEPICK_TARG), pItem->GetName()); addTarget(CLIMODE_TARG_USE_ITEM, pszTemp, true, true); return true; } case IT_WEAPON_SWORD: case IT_WEAPON_FENCE: case IT_WEAPON_AXE: case IT_WEAPON_MACE_SHARP: case IT_WEAPON_MACE_STAFF: case IT_WEAPON_MACE_SMITH: { if ( bIsEquipped || !IsSetOF(OF_NoDClickTarget) ) addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_WEAPON_PROMT), false, true); return true; } case IT_WEAPON_MACE_CROOK: if ( bIsEquipped || !IsSetOF(OF_NoDClickTarget) ) addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_CROOK_PROMT), false, true); return true; case IT_FISH: SysMessageDefault(DEFMSG_ITEMUSE_FISH_FAIL); return true; case IT_TELESCOPE: SysMessageDefault(DEFMSG_ITEMUSE_TELESCOPE); return true; case IT_MAP: addDrawMap(static_cast<CItemMap *>(pItem)); return true; case IT_CANNON_BALL: { TCHAR *pszTemp = Str_GetTemp(); sprintf(pszTemp, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_CBALL_PROMT), pItem->GetName()); addTarget(CLIMODE_TARG_USE_ITEM, pszTemp); return true; } case IT_CANNON_MUZZLE: { if ( !m_pChar->CanUse(pItem, false) ) return false; // Make sure the cannon is loaded. if ( !(pItem->m_itCannon.m_Load & 1) ) { addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_CANNON_POWDER)); return true; } if ( !(pItem->m_itCannon.m_Load & 2) ) { addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_CANNON_SHOT)); return true; } addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_CANNON_TARG), false, true); return true; } case IT_CRYSTAL_BALL: // Gaze into the crystal ball. return true; case IT_SEED: case IT_PITCHER_EMPTY: { TCHAR *pszTemp = Str_GetTemp(); sprintf(pszTemp, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_PITCHER_TARG), pItem->GetName()); addTarget(CLIMODE_TARG_USE_ITEM, pszTemp, true); return true; } case IT_SPELLBOOK: addSpellbookOpen(pItem); return true; case IT_SPELLBOOK_NECRO: addSpellbookOpen(pItem, 101); return true; case IT_SPELLBOOK_PALA: addSpellbookOpen(pItem, 201); return true; case IT_SPELLBOOK_BUSHIDO: addSpellbookOpen(pItem, 401); return true; case IT_SPELLBOOK_NINJITSU: addSpellbookOpen(pItem, 501); return true; case IT_SPELLBOOK_ARCANIST: addSpellbookOpen(pItem, 601); return true; case IT_SPELLBOOK_MYSTIC: addSpellbookOpen(pItem, 678); return true; case IT_SPELLBOOK_BARD: addSpellbookOpen(pItem, 701); return true; case IT_HAIR_DYE: { if ( !m_pChar->LayerFind(LAYER_BEARD) && !m_pChar->LayerFind(LAYER_HAIR) ) { SysMessageDefault(DEFMSG_ITEMUSE_DYE_NOHAIR); return true; } Dialog_Setup(CLIMODE_DIALOG, g_Cfg.ResourceGetIDType(RES_DIALOG, "d_hair_dye"), 0, pItem); return true; } case IT_DYE: addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_DYE_VAT)); return true; case IT_DYE_VAT: addTarget(CLIMODE_TARG_USE_ITEM, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_DYE_TARG), false, true); return true; case IT_MORTAR: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_alchemy"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_alchemy")); } case IT_CARTOGRAPHY: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_cartography"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_cartography")); } case IT_COOKING: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_cooking"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_cooking")); } case IT_TINKER_TOOLS: { if ( IsTrigUsed(TRIGGER_SKILLMENU) ) { CScriptTriggerArgs args("sm_tinker"); if ( m_pChar->OnTrigger("@SkillMenu", m_pChar, &args) == TRIGRET_RET_TRUE ) return true; } return Cmd_Skill_Menu(g_Cfg.ResourceGetIDType(RES_SKILLMENU, "sm_tinker")); } case IT_SEWING_KIT: { TCHAR *pszTemp = Str_GetTemp(); sprintf(pszTemp, g_Cfg.GetDefaultMsg(DEFMSG_ITEMUSE_SEWKIT_PROMT), pItem->GetName()); addTarget(CLIMODE_TARG_USE_ITEM, pszTemp); return true; } case IT_SCROLL_BLANK: Cmd_Skill_Inscription(); return true; default: { // An NPC could use it this way. if ( m_pChar->Use_Item(pItem) ) return true; break; } } SysMessageDefault(DEFMSG_ITEMUSE_CANTTHINK); return false; }
bool CChar::Use_Seed( CItem * pSeed, CPointMap * pPoint ) { ADDTOCALLSTACK("CChar::Use_Seed"); // Use the seed at the current point on the ground or some new point that i can touch. // IT_SEED from IT_FRUIT ASSERT(pSeed); CPointMap pt; if ( pPoint ) pt = *pPoint; else if ( pSeed->IsTopLevel() ) pt = pSeed->GetTopPoint(); else pt = GetTopPoint(); if ( !CanTouch(pt) ) { SysMessageDefault(DEFMSG_MSG_SEED_REACH); return false; } // is there soil here ? IT_DIRT if ( !IsPriv(PRIV_GM) && !g_World.IsItemTypeNear(pt, IT_DIRT, 0, false) ) { SysMessageDefault(DEFMSG_MSG_SEED_TARGSOIL); return(false); } const CItemBase *pItemDef = pSeed->Item_GetDef(); ITEMID_TYPE idReset = static_cast<ITEMID_TYPE>(RES_GET_INDEX(pItemDef->m_ttFruit.m_idReset)); if ( idReset == 0 ) { SysMessageDefault(DEFMSG_MSG_SEED_NOGOOD); return false; } // Already a plant here ? CWorldSearch AreaItems(pt); for (;;) { CItem *pItem = AreaItems.GetItem(); if ( !pItem ) break; if ( pItem->IsType(IT_TREE) || pItem->IsType(IT_FOLIAGE) ) // there's already a tree here { SysMessageDefault(DEFMSG_MSG_SEED_ATREE); return false; } if ( pItem->IsType(IT_CROPS) ) // there's already a plant here pItem->Delete(); } // plant it and consume the seed. CItem *pPlant = CItem::CreateScript(idReset, this); ASSERT(pPlant); pPlant->MoveToUpdate(pt); if ( pPlant->IsType(IT_CROPS) || pPlant->IsType(IT_FOLIAGE) ) { pPlant->m_itCrop.m_ReapFruitID = pSeed->GetID(); pPlant->Plant_CropReset(); } else { pPlant->SetDecayTime(10 * g_Cfg.m_iDecay_Item); } pSeed->ConsumeAmount(); return true; }