[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.
This commit is contained in:
VladimirMangos 2009-08-26 08:18:30 +04:00
parent db1c9924a9
commit 45dd7140b5
28 changed files with 228 additions and 144 deletions

View file

@ -141,7 +141,7 @@ bool
AggressorAI::IsVisible(Unit *pl) const AggressorAI::IsVisible(Unit *pl) const
{ {
return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_MONSTER)) return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_MONSTER))
&& pl->isVisibleForOrDetect(m_creature,true); && pl->isVisibleForOrDetect(m_creature,m_creature,true);
} }
void void

View file

@ -227,7 +227,7 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields)
return true; 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);
} }

View file

@ -74,7 +74,7 @@ class Corpse : public WorldObject
GridPair const& GetGrid() const { return m_grid; } GridPair const& GetGrid() const { return m_grid; }
void SetGrid(GridPair const& grid) { m_grid = 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 Loot loot; // remove insignia ONLY at BG
Player* lootRecipient; Player* lootRecipient;

View file

@ -681,7 +681,7 @@ class MANGOS_DLL_SPEC Creature : public Unit
void SetDeadByDefault (bool death_state) { m_isDeadByDefault = death_state; } 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); void SetActiveObjectState(bool on);
protected: protected:

View file

@ -1116,7 +1116,7 @@ void CreatureEventAI::UpdateAI(const uint32 diff)
bool CreatureEventAI::IsVisible(Unit *pl) const bool CreatureEventAI::IsVisible(Unit *pl) const
{ {
return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_MONSTER)) 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) inline Unit* CreatureEventAI::SelectUnit(AttackingTarget target, uint32 position)

View file

@ -25,8 +25,9 @@
#include "GridNotifiers.h" #include "GridNotifiers.h"
#include "CellImpl.h" #include "CellImpl.h"
#include "GridNotifiersImpl.h" #include "GridNotifiersImpl.h"
#include "SpellMgr.h"
DynamicObject::DynamicObject() : WorldObject() DynamicObject::DynamicObject() : WorldObject(), m_isActiveObject(false)
{ {
m_objectType |= TYPEMASK_DYNAMICOBJECT; m_objectType |= TYPEMASK_DYNAMICOBJECT;
m_objectTypeId = TYPEID_DYNAMICOBJECT; m_objectTypeId = TYPEID_DYNAMICOBJECT;
@ -81,6 +82,11 @@ bool DynamicObject::Create( uint32 guidlow, Unit *caster, uint32 spellId, uint32
m_radius = radius; m_radius = radius;
m_effIndex = effIndex; m_effIndex = effIndex;
m_spellId = spellId; 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; return true;
} }
@ -107,20 +113,24 @@ void DynamicObject::Update(uint32 p_time)
else else
deleteThis = true; deleteThis = true;
// TODO: make a timer and update this in larger intervals // have radius and work as persistent effect
CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); if(m_radius)
Cell cell(p); {
cell.data.Part.reserved = ALL_DISTRICT; // TODO: make a timer and update this in larger intervals
cell.SetNoCreate(); 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<MaNGOS::DynamicObjectUpdater, WorldTypeMapContainer > world_object_notifier(notifier); TypeContainerVisitor<MaNGOS::DynamicObjectUpdater, WorldTypeMapContainer > world_object_notifier(notifier);
TypeContainerVisitor<MaNGOS::DynamicObjectUpdater, GridTypeMapContainer > grid_object_notifier(notifier); TypeContainerVisitor<MaNGOS::DynamicObjectUpdater, GridTypeMapContainer > grid_object_notifier(notifier);
CellLock<GridReadGuard> cell_lock(cell, p); CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, world_object_notifier, *GetMap()); cell_lock->Visit(cell_lock, world_object_notifier, *GetMap());
cell_lock->Visit(cell_lock, grid_object_notifier, *GetMap()); cell_lock->Visit(cell_lock, grid_object_notifier, *GetMap());
}
if(deleteThis) if(deleteThis)
{ {
@ -143,7 +153,15 @@ void DynamicObject::Delay(int32 delaytime)
(*iunit)->DelayAura(m_spellId, m_effIndex, 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);
} }

View file

@ -46,7 +46,7 @@ class DynamicObject : public WorldObject
void AddAffected(Unit *unit) { m_affected.insert(unit); } void AddAffected(Unit *unit) { m_affected.insert(unit); }
void RemoveAffected(Unit *unit) { m_affected.erase(unit); } void RemoveAffected(Unit *unit) { m_affected.erase(unit); }
void Delay(int32 delaytime); 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 Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); } void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
@ -56,15 +56,16 @@ class DynamicObject : public WorldObject
GridReference<DynamicObject> &GetGridRef() { return m_gridRef; } GridReference<DynamicObject> &GetGridRef() { return m_gridRef; }
bool isActiveObject() const { return false; } bool isActiveObject() const { return m_isActiveObject; }
protected: protected:
uint32 m_spellId; uint32 m_spellId;
uint32 m_effIndex; uint32 m_effIndex;
int32 m_aliveDuration; int32 m_aliveDuration;
time_t m_nextThinkTime; time_t m_nextThinkTime;
float m_radius; float m_radius; // radius apply persistent effect, 0 = no persistent effect
AffectedSet m_affected; AffectedSet m_affected;
private: private:
GridReference<DynamicObject> m_gridRef; GridReference<DynamicObject> m_gridRef;
bool m_isActiveObject;
}; };
#endif #endif

View file

@ -690,7 +690,7 @@ void GameObject::SaveRespawnTime()
objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime); 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 // Not in world
if(!IsInWorld() || !u->IsInWorld()) if(!IsInWorld() || !u->IsInWorld())
@ -717,7 +717,7 @@ bool GameObject::isVisibleForInState(Player const* u, bool inVisibleList) const
} }
// check distance // check distance
return IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject() + return IsWithinDistInMap(viewPoint,World::GetMaxVisibleDistanceForObject() +
(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
} }

View file

@ -670,7 +670,7 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject
void TriggeringLinkedGameObject( uint32 trapEntry, Unit* target); 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); GameObject* LookupFishingHoleAround(float range);

View file

@ -30,13 +30,16 @@ using namespace MaNGOS;
void void
MaNGOS::PlayerNotifier::Visit(PlayerMapType &m) MaNGOS::PlayerNotifier::Visit(PlayerMapType &m)
{ {
WorldObject const* viewPoint = i_player.GetViewPoint();
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
{ {
if( iter->getSource() == &i_player ) Player* player = iter->getSource();
if( player == &i_player )
continue; continue;
iter->getSource()->UpdateVisibilityOf(&i_player); player->UpdateVisibilityOf(player->GetViewPoint(),&i_player);
i_player.UpdateVisibilityOf(iter->getSource()); i_player.UpdateVisibilityOf(viewPoint,player);
} }
} }
@ -45,24 +48,28 @@ VisibleChangesNotifier::Visit(PlayerMapType &m)
{ {
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
{ {
if(iter->getSource() == &i_object) Player* player = iter->getSource();
if(player == &i_object)
continue; continue;
iter->getSource()->UpdateVisibilityOf(&i_object); player->UpdateVisibilityOf(player->GetViewPoint(),&i_object);
} }
} }
void void
VisibleNotifier::Visit(PlayerMapType &m) VisibleNotifier::Visit(PlayerMapType &m)
{ {
WorldObject const* viewPoint = i_player.GetViewPoint();
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
{ {
if( iter->getSource() == &i_player ) Player* player = iter->getSource();
if( player == &i_player )
continue; continue;
iter->getSource()->UpdateVisibilityOf(&i_player); player->UpdateVisibilityOf(player->GetViewPoint(),&i_player);
i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_data_updates,i_visibleNow); i_player.UpdateVisibilityOf(viewPoint,player,i_data,i_data_updates,i_visibleNow);
i_clientGUIDs.erase(iter->getSource()->GetGUID()); i_clientGUIDs.erase(player->GetGUID());
} }
} }
@ -77,8 +84,9 @@ VisibleNotifier::Notify()
{ {
if(i_clientGUIDs.find((*itr)->GetGUID())!=i_clientGUIDs.end()) if(i_clientGUIDs.find((*itr)->GetGUID())!=i_clientGUIDs.end())
{ {
(*itr)->UpdateVisibilityOf(&i_player); // ignore far sight case
i_player.UpdateVisibilityOf((*itr),i_data,i_data_updates,i_visibleNow); (*itr)->UpdateVisibilityOf((*itr),&i_player);
i_player.UpdateVisibilityOf(&i_player,(*itr),i_data,i_data_updates,i_visibleNow);
i_clientGUIDs.erase((*itr)->GetGUID()); i_clientGUIDs.erase((*itr)->GetGUID());
} }
} }
@ -121,9 +129,8 @@ VisibleNotifier::Notify()
if(!IS_PLAYER_GUID(*iter)) if(!IS_PLAYER_GUID(*iter))
continue; continue;
Player* plr = ObjectAccessor::GetPlayer(i_player,*iter); if (Player* plr = ObjectAccessor::GetPlayer(i_player,*iter))
if(plr) plr->UpdateVisibilityOf(plr->GetViewPoint(),&i_player);
plr->UpdateVisibilityOf(&i_player);
} }
} }

View file

@ -778,7 +778,7 @@ namespace MaNGOS
return u->isAlive() return u->isAlive()
&& i_obj->IsWithinDistInMap(u, i_range) && i_obj->IsWithinDistInMap(u, i_range)
&& !i_funit->IsFriendlyTo(u) && !i_funit->IsFriendlyTo(u)
&& u->isVisibleForOrDetect(i_funit, false); && u->isVisibleForOrDetect(i_funit,i_funit,false);
} }
private: private:
WorldObject const* i_obj; WorldObject const* i_obj;
@ -827,7 +827,7 @@ namespace MaNGOS
bool operator()(Unit* u) bool operator()(Unit* u)
{ {
if( u->isTargetableForAttack() && i_obj->IsWithinDistInMap(u, i_range) && 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 i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check
return true; return true;
@ -863,7 +863,7 @@ namespace MaNGOS
return false; return false;
if(u->GetTypeId()==TYPEID_UNIT && ((Creature*)u)->isTotem()) if(u->GetTypeId()==TYPEID_UNIT && ((Creature*)u)->isTotem())
return false; return false;
if (!i_hitHidden && !u->isVisibleForOrDetect(i_funit, false)) if (!i_hitHidden && !u->isVisibleForOrDetect(i_funit, i_funit, false))
return false; return false;
if(( i_targetForPlayer ? !i_funit->IsFriendlyTo(u) : i_funit->IsHostileTo(u) )&& i_obj->IsWithinDistInMap(u, i_range)) if(( i_targetForPlayer ? !i_funit->IsFriendlyTo(u) : i_funit->IsHostileTo(u) )&& i_obj->IsWithinDistInMap(u, i_range))

View file

@ -31,9 +31,11 @@ template<class T>
inline void inline void
MaNGOS::VisibleNotifier::Visit(GridRefManager<T> &m) MaNGOS::VisibleNotifier::Visit(GridRefManager<T> &m)
{ {
WorldObject const* viewPoint = i_player.GetViewPoint();
for(typename GridRefManager<T>::iterator iter = m.begin(); iter != m.end(); ++iter) for(typename GridRefManager<T>::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()); 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 // update creature visibility at player/creature move
pl->UpdateVisibilityOf(c); pl->UpdateVisibilityOf(viewPoint,c);
// Creature AI reaction // Creature AI reaction
if(!c->hasUnitState(UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING)) 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()) if(!i_player.isAlive() || i_player.isInFlight())
return; return;
WorldObject const* viewPoint = i_player.GetViewPoint();
for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
if( iter->getSource()->isAlive()) if (iter->getSource()->isAlive())
PlayerCreatureRelocationWorker(&i_player,iter->getSource()); PlayerCreatureRelocationWorker(&i_player,viewPoint,iter->getSource());
} }
template<> template<>
@ -111,8 +115,9 @@ MaNGOS::CreatureRelocationNotifier::Visit(PlayerMapType &m)
return; return;
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
if( iter->getSource()->isAlive() && !iter->getSource()->isInFlight()) if (Player* player = iter->getSource())
PlayerCreatureRelocationWorker(iter->getSource(), &i_creature); if (player->isAlive() && !player->isInFlight())
PlayerCreatureRelocationWorker(player, player->GetViewPoint(), &i_creature);
} }
template<> template<>

View file

@ -973,7 +973,7 @@ void Group::UpdatePlayerOutOfRange(Player* pPlayer)
for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{ {
player = itr->getSource(); player = itr->getSource();
if (player && player != pPlayer && !pPlayer->isVisibleFor(player)) if (player && player != pPlayer && !pPlayer->isVisibleFor(player,player->GetViewPoint()))
player->GetSession()->SendPacket(&data); player->GetSession()->SendPacket(&data);
} }
} }

View file

@ -126,7 +126,7 @@ void GuardAI::UpdateAI(const uint32 /*diff*/)
bool GuardAI::IsVisible(Unit *pl) const bool GuardAI::IsVisible(Unit *pl) const
{ {
return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_GUARDER)) 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) void GuardAI::AttackStart(Unit *u)

View file

@ -1456,13 +1456,15 @@ void WorldSession::HandleMoveSetCanFlyAckOpcode( WorldPacket & recv_data )
sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK"); sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK");
//recv_data.hexlike(); //recv_data.hexlike();
uint64 guid; recv_data.read_skip<uint64>(); // guid
uint32 unk; recv_data.read_skip<uint32>(); // unk
uint32 flags;
recv_data >> guid >> unk >> flags; MovementInfo movementInfo;
ReadMovementInfo(recv_data, &movementInfo);
_player->m_movementInfo.SetMovementFlags(MovementFlags(flags)); recv_data.read_skip<uint32>(); // unk2
_player->m_movementInfo.SetMovementFlags(movementInfo.GetMovementFlags());
} }
void WorldSession::HandleRequestPetInfoOpcode( WorldPacket & /*recv_data */) void WorldSession::HandleRequestPetInfoOpcode( WorldPacket & /*recv_data */)

View file

@ -1359,6 +1359,16 @@ bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
return (( angle >= lborder ) && ( angle <= rborder )); 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 void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const
{ {
if(distance == 0) if(distance == 0)

View file

@ -445,6 +445,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object
float GetAngle( const WorldObject* obj ) const; float GetAngle( const WorldObject* obj ) const;
float GetAngle( const float x, const float y ) const; float GetAngle( const float x, const float y ) const;
bool HasInArc( const float arcangle, const WorldObject* obj ) 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 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(); void AddObjectToRemoveList();
// main visibility check function in normal case (ignore grey zone distance check) // 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 // 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); void SetMap(Map * map);
Map * GetMap() const { ASSERT(m_currMap); return m_currMap; } Map * GetMap() const { ASSERT(m_currMap); return m_currMap; }

View file

@ -90,43 +90,61 @@ ObjectAccessor::GetCorpse(WorldObject const &u, uint64 guid)
return ret; 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* ObjectAccessor::GetObjectByTypeMask(WorldObject const &p, uint64 guid, uint32 typemask)
{ {
Object *obj = NULL; switch(GUID_HIPART(guid))
if(typemask & TYPEMASK_PLAYER)
{ {
obj = FindPlayer(guid); case HIGHGUID_ITEM:
if(obj) if(typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER)
return obj; return ((Player const &)p).GetItemByGuid( guid );
} break;
case HIGHGUID_PLAYER:
if(typemask & TYPEMASK_UNIT) if(typemask & TYPEMASK_PLAYER)
{ return FindPlayer(guid);
obj = GetCreatureOrPetOrVehicle(p,guid); break;
if(obj) case HIGHGUID_GAMEOBJECT:
return obj; if(typemask & TYPEMASK_GAMEOBJECT)
} return p.GetMap()->GetGameObject(guid);
break;
if(typemask & TYPEMASK_GAMEOBJECT) case HIGHGUID_UNIT:
{ if(typemask & TYPEMASK_UNIT)
obj = p.GetMap()->GetGameObject(guid); return p.GetMap()->GetCreature(guid);
if(obj) break;
return obj; case HIGHGUID_PET:
} if(typemask & TYPEMASK_UNIT)
return GetPet(guid);
if(typemask & TYPEMASK_DYNAMICOBJECT) break;
{ case HIGHGUID_VEHICLE:
obj = p.GetMap()->GetDynamicObject(guid); if(typemask & TYPEMASK_UNIT)
if(obj) return GetVehicle(guid);
return obj; break;
} case HIGHGUID_DYNAMICOBJECT:
if(typemask & TYPEMASK_DYNAMICOBJECT)
if(typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER) return p.GetMap()->GetDynamicObject(guid);
{ break;
obj = ((Player const &)p).GetItemByGuid( guid ); case HIGHGUID_TRANSPORT:
if(obj) case HIGHGUID_CORPSE:
return obj; case HIGHGUID_MO_TRANSPORT:
break;
} }
return NULL; return NULL;

View file

@ -142,6 +142,7 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor,
else return NULL; else return NULL;
} }
static WorldObject* GetWorldObject(WorldObject const &, uint64);
static Object* GetObjectByTypeMask(WorldObject const &, uint64, uint32 typemask); static Object* GetObjectByTypeMask(WorldObject const &, uint64, uint32 typemask);
static Creature* GetCreatureOrPetOrVehicle(WorldObject const &, uint64); static Creature* GetCreatureOrPetOrVehicle(WorldObject const &, uint64);
static Unit* GetUnit(WorldObject const &, uint64); static Unit* GetUnit(WorldObject const &, uint64);

View file

@ -307,7 +307,7 @@ void PetAI::UpdateAI(const uint32 diff)
bool PetAI::_isVisible(Unit *u) const bool PetAI::_isVisible(Unit *u) const
{ {
return m_creature->IsWithinDist(u,sWorld.getConfig(CONFIG_SIGHT_GUARDER)) return m_creature->IsWithinDist(u,sWorld.getConfig(CONFIG_SIGHT_GUARDER))
&& u->isVisibleForOrDetect(m_creature,true); && u->isVisibleForOrDetect(m_creature,m_creature,true);
} }
void PetAI::UpdateAllies() void PetAI::UpdateAllies()

View file

@ -16794,13 +16794,15 @@ void Player::HandleStealthedUnitsDetection()
cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap()); cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap());
cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap()); cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap());
WorldObject const* viewPoint = GetViewPoint();
for (std::list<Unit*>::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i) for (std::list<Unit*>::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i)
{ {
if((*i)==this) if((*i)==this)
continue; continue;
bool hasAtClient = HaveAtClient((*i)); bool hasAtClient = HaveAtClient((*i));
bool hasDetected = (*i)->isVisibleForOrDetect(this, true); bool hasDetected = (*i)->isVisibleForOrDetect(this, viewPoint, true);
if (hasDetected) 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 bool Player::IsVisibleInGridForPlayer( Player* pl ) const
{ {
// gamemaster in GM mode see all, including ghosts // gamemaster in GM mode see all, including ghosts
@ -17949,11 +17962,11 @@ bool Player::IsVisibleGloballyFor( Player* u ) const
return true; return true;
} }
void Player::UpdateVisibilityOf(WorldObject* target) void Player::UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* target)
{ {
if(HaveAtClient(target)) if(HaveAtClient(target))
{ {
if(!target->isVisibleForInState(this, true)) if(!target->isVisibleForInState(this, viewPoint, true))
{ {
target->DestroyForPlayer(this); target->DestroyForPlayer(this);
m_clientGUIDs.erase(target->GetGUID()); m_clientGUIDs.erase(target->GetGUID());
@ -17966,7 +17979,7 @@ void Player::UpdateVisibilityOf(WorldObject* target)
} }
else else
{ {
if(target->isVisibleForInState(this,false)) if(target->isVisibleForInState(this, viewPoint, false))
{ {
target->SendUpdateToPlayer(this); target->SendUpdateToPlayer(this);
if(target->GetTypeId()!=TYPEID_GAMEOBJECT||!((GameObject*)target)->IsTransport()) if(target->GetTypeId()!=TYPEID_GAMEOBJECT||!((GameObject*)target)->IsTransport())
@ -18002,11 +18015,11 @@ inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, GameObject* target)
} }
template<class T> template<class T>
void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow) void Player::UpdateVisibilityOf(WorldObject const* viewPoint, T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow)
{ {
if(HaveAtClient(target)) if(HaveAtClient(target))
{ {
if(!target->isVisibleForInState(this,true)) if(!target->isVisibleForInState(this,viewPoint,true))
{ {
target->BuildOutOfRangeUpdateBlock(&data); target->BuildOutOfRangeUpdateBlock(&data);
m_clientGUIDs.erase(target->GetGUID()); m_clientGUIDs.erase(target->GetGUID());
@ -18019,7 +18032,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType&
} }
else else
{ {
if(target->isVisibleForInState(this,false)) if(target->isVisibleForInState(this,viewPoint,false))
{ {
visibleNow.insert(target); visibleNow.insert(target);
target->BuildUpdate(data_updates); 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<WorldObject*>& visibleNow); template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, Player* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow); template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, Creature* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow); template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, Corpse* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow); template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, GameObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow); template void Player::UpdateVisibilityOf(WorldObject const* viewPoint, DynamicObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
void Player::InitPrimaryProfessions() void Player::InitPrimaryProfessions()
{ {
@ -20566,3 +20579,14 @@ bool Player::HasMovementFlag( MovementFlags f ) const
{ {
return m_movementInfo.HasMovementFlag(f); 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);
}

View file

@ -2084,7 +2084,7 @@ class MANGOS_DLL_SPEC Player : public Unit
void ExitVehicle(Vehicle *vehicle); void ExitVehicle(Vehicle *vehicle);
uint64 GetFarSight() const { return GetUInt64Value(PLAYER_FARSIGHT); } uint64 GetFarSight() const { return GetUInt64Value(PLAYER_FARSIGHT); }
void SetFarSightGUID(uint64 guid) { SetUInt64Value(PLAYER_FARSIGHT, guid); } void SetFarSightGUID(uint64 guid);
// Transports // Transports
Transport * GetTransport() const { return m_transport; } 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(); } 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 IsVisibleInGridForPlayer(Player* pl) const;
bool IsVisibleGloballyFor(Player* pl) const; bool IsVisibleGloballyFor(Player* pl) const;
void UpdateVisibilityOf(WorldObject* target); void UpdateVisibilityOf(WorldObject const* viewPoint, WorldObject* target);
template<class T> template<class T>
void UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow); void UpdateVisibilityOf(WorldObject const* viewPoint,T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
// Stealth detection system // Stealth detection system
void HandleStealthedUnitsDetection(); void HandleStealthedUnitsDetection();

View file

@ -1194,7 +1194,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
{ {
// for delayed spells ignore not visible explicit target // for delayed spells ignore not visible explicit target
if (m_spellInfo->speed > 0.0f && unit == m_targets.getUnitTarget() && 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); realCaster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);
return; return;
@ -1204,9 +1204,9 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
if (!(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_BREAK_STEALTH)) if (!(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_BREAK_STEALTH))
unit->RemoveSpellsCausingAura(SPELL_AURA_MOD_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) && 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 // use speedup check to avoid re-remove after above lines
if (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_BREAK_STEALTH) if (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_BREAK_STEALTH)

View file

@ -3634,10 +3634,14 @@ void Spell::EffectPickPocket(uint32 /*i*/)
void Spell::EffectAddFarsight(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); int32 duration = GetSpellDuration(m_spellInfo);
DynamicObject* dynObj = new DynamicObject; 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; delete dynObj;
return; return;
@ -3646,8 +3650,7 @@ void Spell::EffectAddFarsight(uint32 i)
dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002); dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
m_caster->AddDynObject(dynObj); m_caster->AddDynObject(dynObj);
m_caster->GetMap()->Add(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) void Spell::EffectSummonWild(uint32 i)

View file

@ -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) // Search victim if no, not attackable, or out of range, or friendly (possible in case duel end)
if( !victim || if( !victim ||
!victim->isTargetableForAttack() || !m_creature->IsWithinDistInMap(victim, max_range) || !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())); CellPair p(MaNGOS::ComputeCellPair(m_creature->GetPositionX(),m_creature->GetPositionY()));
Cell cell(p); Cell cell(p);

View file

@ -3193,21 +3193,11 @@ Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const
return NULL; 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) void Unit::SetInFront(Unit const* target)
{ {
SetOrientation(GetAngle(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 bool Unit::isInAccessablePlaceFor(Creature const* c) const
{ {
if(IsInWater()) if(IsInWater())
@ -9272,7 +9262,7 @@ int32 Unit::ModifyPower(Powers power, int32 dVal)
return gain; 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) if(!u)
return false; return false;
@ -9319,16 +9309,20 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList,
if(GetCharmerOrOwnerGUID()==u->GetGUID()) if(GetCharmerOrOwnerGUID()==u->GetGUID())
return true; return true;
// always seen by far sight caster
if( u->GetTypeId()==TYPEID_PLAYER && ((Player*)u)->GetFarSight()==GetGUID())
return true;
// different visible distance checks // different visible distance checks
if(u->isInFlight()) // what see player in flight if(u->isInFlight()) // what see player in flight
{ {
// use object grey distance for all (only see objects any way) // 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; return false;
} }
else if(!isAlive()) // distance for show body 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; return false;
} }
else if(GetTypeId()==TYPEID_PLAYER) // distance for show player 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) if(u->GetTypeId()==TYPEID_PLAYER)
{ {
// Players far than max visible distance for player or not in our map are not visible too // 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; return false;
} }
else else
{ {
// Units far than max visible distance for creature or not in our map are not visible too // 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; return false;
} }
} }
else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed 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 // 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; return false;
} }
else // distance for show creature else // distance for show creature
{ {
// Units far than max visible distance for creature or not in our map are not visible too // 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; 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); 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 //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) if(!isInFront)
return false; 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; visibleDistance = visibleDistance > MAX_PLAYER_STEALTH_DETECT_RANGE ? MAX_PLAYER_STEALTH_DETECT_RANGE : visibleDistance;
// recheck new distance // recheck new distance
if(visibleDistance <= 0 || !IsWithinDist(u,visibleDistance)) if(visibleDistance <= 0 || !IsWithinDist(viewPoint,visibleDistance))
return false; return false;
} }
// Now check is target visible with LoS // Now check is target visible with LoS
float ox,oy,oz; float ox,oy,oz;
u->GetPosition(ox,oy,oz); viewPoint->GetPosition(ox,oy,oz);
return IsWithinLOS(ox,oy,oz); return IsWithinLOS(ox,oy,oz);
} }
@ -10203,9 +10197,9 @@ Unit* Unit::GetUnit(WorldObject& object, uint64 guid)
return ObjectAccessor::GetUnit(object,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 uint32 Unit::GetCreatureType() const

View file

@ -1310,21 +1310,19 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
float GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const; float GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const;
void SetBaseWeaponDamage(WeaponAttackType attType ,WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; } 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); void SetInFront(Unit const* target);
bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const;
// Visibility system // Visibility system
UnitVisibility GetVisibility() const { return m_Visibility; } UnitVisibility GetVisibility() const { return m_Visibility; }
void SetVisibility(UnitVisibility x); void SetVisibility(UnitVisibility x);
// common function for visibility checks for player/creatures with detection code // 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; bool canDetectInvisibilityOf(Unit const* u) const;
void SetPhaseMask(uint32 newPhaseMask, bool update);// overwrite WorldObject::SetPhaseMask void SetPhaseMask(uint32 newPhaseMask, bool update);// overwrite WorldObject::SetPhaseMask
// virtual functions for all world objects types // 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 // function for low level grid visibility checks in player/creature cases
virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0; virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0;

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "8421" #define REVISION_NR "8422"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__