From 45dd7140b5640bc8a41e4f7d89e70b2c15278706 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Wed, 26 Aug 2009 08:18:30 +0400 Subject: [PATCH] [8422] Implement far sight like spells work for long distance. * Added basic infrastructure for visibility update in case difference player and current view point. Just for note: seletect additional arg way beacuse repeatable search object will slow but store pointer will not safe, so use middle case: get view point pointer early as possible at visibility updates. * Implement dynamic object and creature activisation while it's target of far sight spell effect * Use this for SPELL_AURA_BIND_SIGHT, SPELL_AURA_FAR_SIGHT and SPELL_EFFECT_ADD_FARSIGHT. * Note2: some spyglass like spells let look _around_ at long distance, this hard implement in current grid loading system Without additional changes and not implemented (you will see empty area without creatures in likes case) * Also fixed warning spam at CMSG_MOVE_SET_CAN_FLY_ACK receive by use proper packet sructure reading. --- src/game/AggressorAI.cpp | 2 +- src/game/Corpse.cpp | 4 +- src/game/Corpse.h | 2 +- src/game/Creature.h | 2 +- src/game/CreatureEventAI.cpp | 2 +- src/game/DynamicObject.cpp | 46 +++++++++++++------ src/game/DynamicObject.h | 7 +-- src/game/GameObject.cpp | 4 +- src/game/GameObject.h | 2 +- src/game/GridNotifiers.cpp | 35 +++++++++------ src/game/GridNotifiers.h | 6 +-- src/game/GridNotifiersImpl.h | 19 +++++--- src/game/Group.cpp | 2 +- src/game/GuardAI.cpp | 2 +- src/game/MiscHandler.cpp | 12 ++--- src/game/Object.cpp | 10 +++++ src/game/Object.h | 6 ++- src/game/ObjectAccessor.cpp | 86 ++++++++++++++++++++++-------------- src/game/ObjectAccessor.h | 1 + src/game/PetAI.cpp | 2 +- src/game/Player.cpp | 48 +++++++++++++++----- src/game/Player.h | 7 +-- src/game/Spell.cpp | 6 +-- src/game/SpellEffects.cpp | 11 +++-- src/game/TotemAI.cpp | 2 +- src/game/Unit.cpp | 38 +++++++--------- src/game/Unit.h | 6 +-- src/shared/revision_nr.h | 2 +- 28 files changed, 228 insertions(+), 144 deletions(-) diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp index c1a544d5d..4d1b9c427 100644 --- a/src/game/AggressorAI.cpp +++ b/src/game/AggressorAI.cpp @@ -141,7 +141,7 @@ bool AggressorAI::IsVisible(Unit *pl) const { return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_MONSTER)) - && pl->isVisibleForOrDetect(m_creature,true); + && pl->isVisibleForOrDetect(m_creature,m_creature,true); } void diff --git a/src/game/Corpse.cpp b/src/game/Corpse.cpp index 3115a9473..17f76c74d 100644 --- a/src/game/Corpse.cpp +++ b/src/game/Corpse.cpp @@ -227,7 +227,7 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields) return true; } -bool Corpse::isVisibleForInState(Player const* u, bool inVisibleList) const +bool Corpse::isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const { - return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u, World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); + return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(viewPoint, World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); } diff --git a/src/game/Corpse.h b/src/game/Corpse.h index c044b339e..b0fc146ed 100644 --- a/src/game/Corpse.h +++ b/src/game/Corpse.h @@ -74,7 +74,7 @@ class Corpse : public WorldObject GridPair const& GetGrid() const { return m_grid; } void SetGrid(GridPair const& grid) { m_grid = grid; } - bool isVisibleForInState(Player const* u, bool inVisibleList) const; + bool isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const; Loot loot; // remove insignia ONLY at BG Player* lootRecipient; diff --git a/src/game/Creature.h b/src/game/Creature.h index 94743f54e..ede6c61dc 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -681,7 +681,7 @@ class MANGOS_DLL_SPEC Creature : public Unit void SetDeadByDefault (bool death_state) { m_isDeadByDefault = death_state; } - bool isActiveObject() const { return m_isActiveObject; } + bool isActiveObject() const { return m_isActiveObject || HasAuraType(SPELL_AURA_BIND_SIGHT) || HasAuraType(SPELL_AURA_FAR_SIGHT); } void SetActiveObjectState(bool on); protected: diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index c2df6c436..e70b153ff 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -1116,7 +1116,7 @@ void CreatureEventAI::UpdateAI(const uint32 diff) bool CreatureEventAI::IsVisible(Unit *pl) const { return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_MONSTER)) - && pl->isVisibleForOrDetect(m_creature,true); + && pl->isVisibleForOrDetect(m_creature,m_creature,true); } inline Unit* CreatureEventAI::SelectUnit(AttackingTarget target, uint32 position) diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp index bf81f6dc6..584e89af9 100644 --- a/src/game/DynamicObject.cpp +++ b/src/game/DynamicObject.cpp @@ -25,8 +25,9 @@ #include "GridNotifiers.h" #include "CellImpl.h" #include "GridNotifiersImpl.h" +#include "SpellMgr.h" -DynamicObject::DynamicObject() : WorldObject() +DynamicObject::DynamicObject() : WorldObject(), m_isActiveObject(false) { m_objectType |= TYPEMASK_DYNAMICOBJECT; m_objectTypeId = TYPEID_DYNAMICOBJECT; @@ -81,6 +82,11 @@ bool DynamicObject::Create( uint32 guidlow, Unit *caster, uint32 spellId, uint32 m_radius = radius; m_effIndex = effIndex; m_spellId = spellId; + + // set to active for far sight case + if(SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId)) + m_isActiveObject = IsSpellHaveEffect(spellEntry,SPELL_EFFECT_ADD_FARSIGHT); + return true; } @@ -107,20 +113,24 @@ void DynamicObject::Update(uint32 p_time) else deleteThis = true; - // TODO: make a timer and update this in larger intervals - CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); + // have radius and work as persistent effect + if(m_radius) + { + // TODO: make a timer and update this in larger intervals + CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); - MaNGOS::DynamicObjectUpdater notifier(*this, caster); + MaNGOS::DynamicObjectUpdater notifier(*this, caster); - TypeContainerVisitor world_object_notifier(notifier); - TypeContainerVisitor grid_object_notifier(notifier); + TypeContainerVisitor world_object_notifier(notifier); + TypeContainerVisitor grid_object_notifier(notifier); - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *GetMap()); - cell_lock->Visit(cell_lock, grid_object_notifier, *GetMap()); + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_object_notifier, *GetMap()); + cell_lock->Visit(cell_lock, grid_object_notifier, *GetMap()); + } if(deleteThis) { @@ -143,7 +153,15 @@ void DynamicObject::Delay(int32 delaytime) (*iunit)->DelayAura(m_spellId, m_effIndex, delaytime); } -bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const +bool DynamicObject::isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const { - return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u, World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); + if(!IsInWorld() || !u->IsInWorld()) + return false; + + // always seen by owner + if(GetCasterGUID()==u->GetGUID()) + return true; + + // normal case + return IsWithinDistInMap(viewPoint, World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); } diff --git a/src/game/DynamicObject.h b/src/game/DynamicObject.h index 3db328055..066361b8c 100644 --- a/src/game/DynamicObject.h +++ b/src/game/DynamicObject.h @@ -46,7 +46,7 @@ class DynamicObject : public WorldObject void AddAffected(Unit *unit) { m_affected.insert(unit); } void RemoveAffected(Unit *unit) { m_affected.erase(unit); } void Delay(int32 delaytime); - bool isVisibleForInState(Player const* u, bool inVisibleList) const; + bool isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const; void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); } void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); } @@ -56,15 +56,16 @@ class DynamicObject : public WorldObject GridReference &GetGridRef() { return m_gridRef; } - bool isActiveObject() const { return false; } + bool isActiveObject() const { return m_isActiveObject; } protected: uint32 m_spellId; uint32 m_effIndex; int32 m_aliveDuration; time_t m_nextThinkTime; - float m_radius; + float m_radius; // radius apply persistent effect, 0 = no persistent effect AffectedSet m_affected; private: GridReference m_gridRef; + bool m_isActiveObject; }; #endif diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index ad8c23ea6..6ddd5a22a 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -690,7 +690,7 @@ void GameObject::SaveRespawnTime() objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime); } -bool GameObject::isVisibleForInState(Player const* u, bool inVisibleList) const +bool GameObject::isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const { // Not in world if(!IsInWorld() || !u->IsInWorld()) @@ -717,7 +717,7 @@ bool GameObject::isVisibleForInState(Player const* u, bool inVisibleList) const } // check distance - return IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject() + + return IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); } diff --git a/src/game/GameObject.h b/src/game/GameObject.h index 25ce83d6e..11d9b3160 100644 --- a/src/game/GameObject.h +++ b/src/game/GameObject.h @@ -670,7 +670,7 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject void TriggeringLinkedGameObject( uint32 trapEntry, Unit* target); - bool isVisibleForInState(Player const* u, bool inVisibleList) const; + bool isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const; GameObject* LookupFishingHoleAround(float range); diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp index 1aefbcb4a..5ff6d5d79 100644 --- a/src/game/GridNotifiers.cpp +++ b/src/game/GridNotifiers.cpp @@ -30,13 +30,16 @@ using namespace MaNGOS; void MaNGOS::PlayerNotifier::Visit(PlayerMapType &m) { + WorldObject const* viewPoint = i_player.GetViewPoint(); + for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - if( iter->getSource() == &i_player ) + Player* player = iter->getSource(); + if( player == &i_player ) continue; - iter->getSource()->UpdateVisibilityOf(&i_player); - i_player.UpdateVisibilityOf(iter->getSource()); + player->UpdateVisibilityOf(player->GetViewPoint(),&i_player); + i_player.UpdateVisibilityOf(viewPoint,player); } } @@ -45,24 +48,28 @@ VisibleChangesNotifier::Visit(PlayerMapType &m) { for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - if(iter->getSource() == &i_object) + Player* player = iter->getSource(); + if(player == &i_object) continue; - iter->getSource()->UpdateVisibilityOf(&i_object); + player->UpdateVisibilityOf(player->GetViewPoint(),&i_object); } } void VisibleNotifier::Visit(PlayerMapType &m) { + WorldObject const* viewPoint = i_player.GetViewPoint(); + for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - if( iter->getSource() == &i_player ) + Player* player = iter->getSource(); + if( player == &i_player ) continue; - iter->getSource()->UpdateVisibilityOf(&i_player); - i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_data_updates,i_visibleNow); - i_clientGUIDs.erase(iter->getSource()->GetGUID()); + player->UpdateVisibilityOf(player->GetViewPoint(),&i_player); + i_player.UpdateVisibilityOf(viewPoint,player,i_data,i_data_updates,i_visibleNow); + i_clientGUIDs.erase(player->GetGUID()); } } @@ -77,8 +84,9 @@ VisibleNotifier::Notify() { if(i_clientGUIDs.find((*itr)->GetGUID())!=i_clientGUIDs.end()) { - (*itr)->UpdateVisibilityOf(&i_player); - i_player.UpdateVisibilityOf((*itr),i_data,i_data_updates,i_visibleNow); + // ignore far sight case + (*itr)->UpdateVisibilityOf((*itr),&i_player); + i_player.UpdateVisibilityOf(&i_player,(*itr),i_data,i_data_updates,i_visibleNow); i_clientGUIDs.erase((*itr)->GetGUID()); } } @@ -121,9 +129,8 @@ VisibleNotifier::Notify() if(!IS_PLAYER_GUID(*iter)) continue; - Player* plr = ObjectAccessor::GetPlayer(i_player,*iter); - if(plr) - plr->UpdateVisibilityOf(&i_player); + if (Player* plr = ObjectAccessor::GetPlayer(i_player,*iter)) + plr->UpdateVisibilityOf(plr->GetViewPoint(),&i_player); } } diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index ae34ed7e0..32454762d 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -778,7 +778,7 @@ namespace MaNGOS return u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u) - && u->isVisibleForOrDetect(i_funit, false); + && u->isVisibleForOrDetect(i_funit,i_funit,false); } private: WorldObject const* i_obj; @@ -827,7 +827,7 @@ namespace MaNGOS bool operator()(Unit* u) { if( u->isTargetableForAttack() && i_obj->IsWithinDistInMap(u, i_range) && - !i_funit->IsFriendlyTo(u) && u->isVisibleForOrDetect(i_funit,false) ) + !i_funit->IsFriendlyTo(u) && u->isVisibleForOrDetect(i_funit,i_funit,false) ) { i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check return true; @@ -863,7 +863,7 @@ namespace MaNGOS return false; if(u->GetTypeId()==TYPEID_UNIT && ((Creature*)u)->isTotem()) return false; - if (!i_hitHidden && !u->isVisibleForOrDetect(i_funit, false)) + if (!i_hitHidden && !u->isVisibleForOrDetect(i_funit, i_funit, false)) return false; if(( i_targetForPlayer ? !i_funit->IsFriendlyTo(u) : i_funit->IsHostileTo(u) )&& i_obj->IsWithinDistInMap(u, i_range)) diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h index 583732a65..8d2433ce3 100644 --- a/src/game/GridNotifiersImpl.h +++ b/src/game/GridNotifiersImpl.h @@ -31,9 +31,11 @@ template inline void MaNGOS::VisibleNotifier::Visit(GridRefManager &m) { + WorldObject const* viewPoint = i_player.GetViewPoint(); + for(typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) { - i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_data_updates,i_visibleNow); + i_player.UpdateVisibilityOf(viewPoint,iter->getSource(),i_data,i_data_updates,i_visibleNow); i_clientGUIDs.erase(iter->getSource()->GetGUID()); } } @@ -64,10 +66,10 @@ MaNGOS::PlayerRelocationNotifier::Visit(PlayerMapType &m) } } -inline void PlayerCreatureRelocationWorker(Player* pl, Creature* c) +inline void PlayerCreatureRelocationWorker(Player* pl, WorldObject const* viewPoint, Creature* c) { // update creature visibility at player/creature move - pl->UpdateVisibilityOf(c); + pl->UpdateVisibilityOf(viewPoint,c); // Creature AI reaction if(!c->hasUnitState(UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING)) @@ -98,9 +100,11 @@ MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m) if(!i_player.isAlive() || i_player.isInFlight()) return; + WorldObject const* viewPoint = i_player.GetViewPoint(); + for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - if( iter->getSource()->isAlive()) - PlayerCreatureRelocationWorker(&i_player,iter->getSource()); + if (iter->getSource()->isAlive()) + PlayerCreatureRelocationWorker(&i_player,viewPoint,iter->getSource()); } template<> @@ -111,8 +115,9 @@ MaNGOS::CreatureRelocationNotifier::Visit(PlayerMapType &m) return; for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - if( iter->getSource()->isAlive() && !iter->getSource()->isInFlight()) - PlayerCreatureRelocationWorker(iter->getSource(), &i_creature); + if (Player* player = iter->getSource()) + if (player->isAlive() && !player->isInFlight()) + PlayerCreatureRelocationWorker(player, player->GetViewPoint(), &i_creature); } template<> diff --git a/src/game/Group.cpp b/src/game/Group.cpp index 2513f0ac3..5c83df614 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -973,7 +973,7 @@ void Group::UpdatePlayerOutOfRange(Player* pPlayer) for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { player = itr->getSource(); - if (player && player != pPlayer && !pPlayer->isVisibleFor(player)) + if (player && player != pPlayer && !pPlayer->isVisibleFor(player,player->GetViewPoint())) player->GetSession()->SendPacket(&data); } } diff --git a/src/game/GuardAI.cpp b/src/game/GuardAI.cpp index 5dcbb5a23..e87f5812b 100644 --- a/src/game/GuardAI.cpp +++ b/src/game/GuardAI.cpp @@ -126,7 +126,7 @@ void GuardAI::UpdateAI(const uint32 /*diff*/) bool GuardAI::IsVisible(Unit *pl) const { return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_GUARDER)) - && pl->isVisibleForOrDetect(m_creature,true); + && pl->isVisibleForOrDetect(m_creature,m_creature,true); } void GuardAI::AttackStart(Unit *u) diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index fc797944b..e8f907f90 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -1456,13 +1456,15 @@ void WorldSession::HandleMoveSetCanFlyAckOpcode( WorldPacket & recv_data ) sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK"); //recv_data.hexlike(); - uint64 guid; - uint32 unk; - uint32 flags; + recv_data.read_skip(); // guid + recv_data.read_skip(); // unk - recv_data >> guid >> unk >> flags; + MovementInfo movementInfo; + ReadMovementInfo(recv_data, &movementInfo); - _player->m_movementInfo.SetMovementFlags(MovementFlags(flags)); + recv_data.read_skip(); // unk2 + + _player->m_movementInfo.SetMovementFlags(movementInfo.GetMovementFlags()); } void WorldSession::HandleRequestPetInfoOpcode( WorldPacket & /*recv_data */) diff --git a/src/game/Object.cpp b/src/game/Object.cpp index e370e4be7..16017389a 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1359,6 +1359,16 @@ bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const return (( angle >= lborder ) && ( angle <= rborder )); } +bool WorldObject::isInFrontInMap(WorldObject const* target, float distance, float arc) const +{ + return IsWithinDistInMap(target, distance) && HasInArc( arc, target ); +} + +bool WorldObject::isInBackInMap(WorldObject const* target, float distance, float arc) const +{ + return IsWithinDistInMap(target, distance) && !HasInArc( 2 * M_PI - arc, target ); +} + void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const { if(distance == 0) diff --git a/src/game/Object.h b/src/game/Object.h index 1a697fe1d..265d184a7 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -445,6 +445,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object float GetAngle( const WorldObject* obj ) const; float GetAngle( const float x, const float y ) const; bool HasInArc( const float arcangle, const WorldObject* obj ) const; + bool isInFrontInMap(WorldObject const* target,float distance, float arc = M_PI) const; + bool isInBackInMap(WorldObject const* target, float distance, float arc = M_PI) const; virtual void CleanupsBeforeDelete(); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units @@ -471,10 +473,10 @@ class MANGOS_DLL_SPEC WorldObject : public Object void AddObjectToRemoveList(); // main visibility check function in normal case (ignore grey zone distance check) - bool isVisibleFor(Player const* u) const { return isVisibleForInState(u,false); } + bool isVisibleFor(Player const* u, WorldObject const* viewPoint) const { return isVisibleForInState(u,viewPoint,false); } // low level function for visibility change code, must be define in all main world object subclasses - virtual bool isVisibleForInState(Player const* u, bool inVisibleList) const = 0; + virtual bool isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const = 0; void SetMap(Map * map); Map * GetMap() const { ASSERT(m_currMap); return m_currMap; } diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index 58c220f8e..79b9d9c02 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -90,43 +90,61 @@ ObjectAccessor::GetCorpse(WorldObject const &u, uint64 guid) return ret; } +WorldObject* ObjectAccessor::GetWorldObject(WorldObject const &p, uint64 guid) +{ + switch(GUID_HIPART(guid)) + { + case HIGHGUID_PLAYER: return FindPlayer(guid); + case HIGHGUID_GAMEOBJECT: return p.GetMap()->GetGameObject(guid); + case HIGHGUID_UNIT: return p.GetMap()->GetCreature(guid); + case HIGHGUID_PET: return GetPet(guid); + case HIGHGUID_VEHICLE: return GetVehicle(guid); + case HIGHGUID_DYNAMICOBJECT:return p.GetMap()->GetDynamicObject(guid); + case HIGHGUID_TRANSPORT: return NULL; + case HIGHGUID_CORPSE: return GetCorpse(p,guid); + case HIGHGUID_MO_TRANSPORT: return NULL; + default: break; + } + + return NULL; +} + Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const &p, uint64 guid, uint32 typemask) { - Object *obj = NULL; - - if(typemask & TYPEMASK_PLAYER) + switch(GUID_HIPART(guid)) { - obj = FindPlayer(guid); - if(obj) - return obj; - } - - if(typemask & TYPEMASK_UNIT) - { - obj = GetCreatureOrPetOrVehicle(p,guid); - if(obj) - return obj; - } - - if(typemask & TYPEMASK_GAMEOBJECT) - { - obj = p.GetMap()->GetGameObject(guid); - if(obj) - return obj; - } - - if(typemask & TYPEMASK_DYNAMICOBJECT) - { - obj = p.GetMap()->GetDynamicObject(guid); - if(obj) - return obj; - } - - if(typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER) - { - obj = ((Player const &)p).GetItemByGuid( guid ); - if(obj) - return obj; + case HIGHGUID_ITEM: + if(typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER) + return ((Player const &)p).GetItemByGuid( guid ); + break; + case HIGHGUID_PLAYER: + if(typemask & TYPEMASK_PLAYER) + return FindPlayer(guid); + break; + case HIGHGUID_GAMEOBJECT: + if(typemask & TYPEMASK_GAMEOBJECT) + return p.GetMap()->GetGameObject(guid); + break; + case HIGHGUID_UNIT: + if(typemask & TYPEMASK_UNIT) + return p.GetMap()->GetCreature(guid); + break; + case HIGHGUID_PET: + if(typemask & TYPEMASK_UNIT) + return GetPet(guid); + break; + case HIGHGUID_VEHICLE: + if(typemask & TYPEMASK_UNIT) + return GetVehicle(guid); + break; + case HIGHGUID_DYNAMICOBJECT: + if(typemask & TYPEMASK_DYNAMICOBJECT) + return p.GetMap()->GetDynamicObject(guid); + break; + case HIGHGUID_TRANSPORT: + case HIGHGUID_CORPSE: + case HIGHGUID_MO_TRANSPORT: + break; } return NULL; diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index 6ed1b26cf..cf223ebc9 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -142,6 +142,7 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::SingletonIsWithinDist(u,sWorld.getConfig(CONFIG_SIGHT_GUARDER)) - && u->isVisibleForOrDetect(m_creature,true); + && u->isVisibleForOrDetect(m_creature,m_creature,true); } void PetAI::UpdateAllies() diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 51bb78d16..d1f59bb9f 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -16794,13 +16794,15 @@ void Player::HandleStealthedUnitsDetection() cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap()); cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap()); + WorldObject const* viewPoint = GetViewPoint(); + for (std::list::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i) { if((*i)==this) continue; bool hasAtClient = HaveAtClient((*i)); - bool hasDetected = (*i)->isVisibleForOrDetect(this, true); + bool hasDetected = (*i)->isVisibleForOrDetect(this, viewPoint, true); if (hasDetected) { @@ -17884,6 +17886,17 @@ void Player::ReportedAfkBy(Player* reporter) } } +WorldObject const* Player::GetViewPoint() const +{ + if(uint64 far_sight = GetFarSight()) + { + WorldObject const* viewPoint = ObjectAccessor::GetWorldObject(*this,far_sight); + return viewPoint ? viewPoint : this; // always expected not NULL + } + else + return this; +} + bool Player::IsVisibleInGridForPlayer( Player* pl ) const { // gamemaster in GM mode see all, including ghosts @@ -17949,11 +17962,11 @@ bool Player::IsVisibleGloballyFor( Player* u ) const return true; } -void Player::UpdateVisibilityOf(WorldObject* target) +void Player::UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* target) { if(HaveAtClient(target)) { - if(!target->isVisibleForInState(this, true)) + if(!target->isVisibleForInState(this, viewPoint, true)) { target->DestroyForPlayer(this); m_clientGUIDs.erase(target->GetGUID()); @@ -17966,7 +17979,7 @@ void Player::UpdateVisibilityOf(WorldObject* target) } else { - if(target->isVisibleForInState(this,false)) + if(target->isVisibleForInState(this, viewPoint, false)) { target->SendUpdateToPlayer(this); if(target->GetTypeId()!=TYPEID_GAMEOBJECT||!((GameObject*)target)->IsTransport()) @@ -18002,11 +18015,11 @@ inline void UpdateVisibilityOf_helper(std::set& s64, GameObject* target) } template -void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow) +void Player::UpdateVisibilityOf(WorldObject const* viewPoint, T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow) { if(HaveAtClient(target)) { - if(!target->isVisibleForInState(this,true)) + if(!target->isVisibleForInState(this,viewPoint,true)) { target->BuildOutOfRangeUpdateBlock(&data); m_clientGUIDs.erase(target->GetGUID()); @@ -18019,7 +18032,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& } else { - if(target->isVisibleForInState(this,false)) + if(target->isVisibleForInState(this,viewPoint,false)) { visibleNow.insert(target); target->BuildUpdate(data_updates); @@ -18034,11 +18047,11 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& } } -template void Player::UpdateVisibilityOf(Player* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); -template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); -template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); -template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); -template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); +template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, Player* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); +template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, Creature* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); +template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, Corpse* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); +template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, GameObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); +template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, DynamicObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); void Player::InitPrimaryProfessions() { @@ -20566,3 +20579,14 @@ bool Player::HasMovementFlag( MovementFlags f ) const { return m_movementInfo.HasMovementFlag(f); } + +void Player::SetFarSightGUID( uint64 guid ) +{ + if(GetFarSight()==guid) + return; + + SetUInt64Value(PLAYER_FARSIGHT, guid); + + // need triggering load grids around new view point + ObjectAccessor::UpdateVisibilityForPlayer(this); +} diff --git a/src/game/Player.h b/src/game/Player.h index 0782088e2..f314fd36f 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -2084,7 +2084,7 @@ class MANGOS_DLL_SPEC Player : public Unit void ExitVehicle(Vehicle *vehicle); uint64 GetFarSight() const { return GetUInt64Value(PLAYER_FARSIGHT); } - void SetFarSightGUID(uint64 guid) { SetUInt64Value(PLAYER_FARSIGHT, guid); } + void SetFarSightGUID(uint64 guid); // Transports Transport * GetTransport() const { return m_transport; } @@ -2122,13 +2122,14 @@ class MANGOS_DLL_SPEC Player : public Unit bool HaveAtClient(WorldObject const* u) { return u==this || m_clientGUIDs.find(u->GetGUID())!=m_clientGUIDs.end(); } + WorldObject const* GetViewPoint() const; bool IsVisibleInGridForPlayer(Player* pl) const; bool IsVisibleGloballyFor(Player* pl) const; - void UpdateVisibilityOf(WorldObject* target); + void UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* target); template - void UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); + void UpdateVisibilityOf(WorldObject const* viewPoint,T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set& visibleNow); // Stealth detection system void HandleStealthedUnitsDetection(); diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 1c745f496..24b155e62 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -1194,7 +1194,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) { // for delayed spells ignore not visible explicit target if (m_spellInfo->speed > 0.0f && unit == m_targets.getUnitTarget() && - !unit->isVisibleForOrDetect(m_caster,false)) + !unit->isVisibleForOrDetect(m_caster,m_caster,false)) { realCaster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE); return; @@ -1204,9 +1204,9 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) if (!(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_BREAK_STEALTH)) unit->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - // can cause back attack (if detected) + // can cause back attack (if detected), stealth removed at Spell::cast if spell break it if (!(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO) && !IsPositiveSpell(m_spellInfo->Id) && - m_caster->isVisibleForOrDetect(unit,false)) // stealth removed at Spell::cast if spell break it + m_caster->isVisibleForOrDetect(unit,unit,false)) { // use speedup check to avoid re-remove after above lines if (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_BREAK_STEALTH) diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index b323738f3..93fd6dc03 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -3634,10 +3634,14 @@ void Spell::EffectPickPocket(uint32 /*i*/) void Spell::EffectAddFarsight(uint32 i) { - float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return; + int32 duration = GetSpellDuration(m_spellInfo); DynamicObject* dynObj = new DynamicObject; - if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, radius)) + + // set radius to 0: spell not expected to work as persistent aura + if(!dynObj->Create(objmgr.GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, i, m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, duration, 0)) { delete dynObj; return; @@ -3646,8 +3650,7 @@ void Spell::EffectAddFarsight(uint32 i) dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002); m_caster->AddDynObject(dynObj); m_caster->GetMap()->Add(dynObj); - if(m_caster->GetTypeId() == TYPEID_PLAYER) - ((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID()); + ((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID()); } void Spell::EffectSummonWild(uint32 i) diff --git a/src/game/TotemAI.cpp b/src/game/TotemAI.cpp index 6b1344140..b826bef03 100644 --- a/src/game/TotemAI.cpp +++ b/src/game/TotemAI.cpp @@ -76,7 +76,7 @@ TotemAI::UpdateAI(const uint32 /*diff*/) // Search victim if no, not attackable, or out of range, or friendly (possible in case duel end) if( !victim || !victim->isTargetableForAttack() || !m_creature->IsWithinDistInMap(victim, max_range) || - m_creature->IsFriendlyTo(victim) || !victim->isVisibleForOrDetect(m_creature,false) ) + m_creature->IsFriendlyTo(victim) || !victim->isVisibleForOrDetect(m_creature,m_creature,false) ) { CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(),m_creature->GetPositionY())); Cell cell(p); diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index c66325b6b..802c949f1 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -3193,21 +3193,11 @@ Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const return NULL; } -bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const -{ - return IsWithinDistInMap(target, distance) && HasInArc( arc, target ); -} - void Unit::SetInFront(Unit const* target) { SetOrientation(GetAngle(target)); } -bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const -{ - return IsWithinDistInMap(target, distance) && !HasInArc( 2 * M_PI - arc, target ); -} - bool Unit::isInAccessablePlaceFor(Creature const* c) const { if(IsInWater()) @@ -9272,7 +9262,7 @@ int32 Unit::ModifyPower(Powers power, int32 dVal) return gain; } -bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList, bool is3dDistance) const +bool Unit::isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, bool detect, bool inVisibleList, bool is3dDistance) const { if(!u) return false; @@ -9319,16 +9309,20 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList, if(GetCharmerOrOwnerGUID()==u->GetGUID()) return true; + // always seen by far sight caster + if( u->GetTypeId()==TYPEID_PLAYER && ((Player*)u)->GetFarSight()==GetGUID()) + return true; + // different visible distance checks if(u->isInFlight()) // what see player in flight { // use object grey distance for all (only see objects any way) - if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance)) + if (!IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance)) return false; } else if(!isAlive()) // distance for show body { - if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance)) + if (!IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance)) return false; } else if(GetTypeId()==TYPEID_PLAYER) // distance for show player @@ -9336,26 +9330,26 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList, if(u->GetTypeId()==TYPEID_PLAYER) { // Players far than max visible distance for player or not in our map are not visible too - if (!at_same_transport && !IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) + if (!at_same_transport && !IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) return false; } else { // Units far than max visible distance for creature or not in our map are not visible too - if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) + if (!IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) return false; } } else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed { // Pet/charmed far than max visible distance for player or not in our map are not visible too - if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) + if (!IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) return false; } else // distance for show creature { // Units far than max visible distance for creature or not in our map are not visible too - if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) + if (!IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) return false; } @@ -9463,7 +9457,7 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList, float visibleDistance = (u->GetTypeId() == TYPEID_PLAYER) ? MAX_PLAYER_STEALTH_DETECT_RANGE : ((Creature const*)u)->GetAttackDistance(this); //Always invisible from back (when stealth detection is on), also filter max distance cases - bool isInFront = u->isInFrontInMap(this, visibleDistance); + bool isInFront = viewPoint->isInFrontInMap(this, visibleDistance); if(!isInFront) return false; @@ -9490,13 +9484,13 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList, visibleDistance = visibleDistance > MAX_PLAYER_STEALTH_DETECT_RANGE ? MAX_PLAYER_STEALTH_DETECT_RANGE : visibleDistance; // recheck new distance - if(visibleDistance <= 0 || !IsWithinDist(u,visibleDistance)) + if(visibleDistance <= 0 || !IsWithinDist(viewPoint,visibleDistance)) return false; } // Now check is target visible with LoS float ox,oy,oz; - u->GetPosition(ox,oy,oz); + viewPoint->GetPosition(ox,oy,oz); return IsWithinLOS(ox,oy,oz); } @@ -10203,9 +10197,9 @@ Unit* Unit::GetUnit(WorldObject& object, uint64 guid) return ObjectAccessor::GetUnit(object,guid); } -bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const +bool Unit::isVisibleForInState( Player const* u, WorldObject const* viewPoint, bool inVisibleList ) const { - return isVisibleForOrDetect(u, false, inVisibleList, false); + return isVisibleForOrDetect(u, viewPoint, false, inVisibleList, false); } uint32 Unit::GetCreatureType() const diff --git a/src/game/Unit.h b/src/game/Unit.h index cbd827e97..30875044d 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1310,21 +1310,19 @@ class MANGOS_DLL_SPEC Unit : public WorldObject float GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const; void SetBaseWeaponDamage(WeaponAttackType attType ,WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; } - bool isInFrontInMap(Unit const* target,float distance, float arc = M_PI) const; void SetInFront(Unit const* target); - bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const; // Visibility system UnitVisibility GetVisibility() const { return m_Visibility; } void SetVisibility(UnitVisibility x); // common function for visibility checks for player/creatures with detection code - bool isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const; + bool isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, bool detect, bool inVisibleList = false, bool is3dDistance = true) const; bool canDetectInvisibilityOf(Unit const* u) const; void SetPhaseMask(uint32 newPhaseMask, bool update);// overwrite WorldObject::SetPhaseMask // virtual functions for all world objects types - bool isVisibleForInState(Player const* u, bool inVisibleList) const; + bool isVisibleForInState(Player const* u, WorldObject const* viewPoint, bool inVisibleList) const; // function for low level grid visibility checks in player/creature cases virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b870107c0..7037ab7b2 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "8421" + #define REVISION_NR "8422" #endif // __REVISION_NR_H__