[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
{
return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_MONSTER))
&& pl->isVisibleForOrDetect(m_creature,true);
&& pl->isVisibleForOrDetect(m_creature,m_creature,true);
}
void

View file

@ -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);
}

View file

@ -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;

View file

@ -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:

View file

@ -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)

View file

@ -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<MaNGOS::DynamicObjectUpdater, WorldTypeMapContainer > world_object_notifier(notifier);
TypeContainerVisitor<MaNGOS::DynamicObjectUpdater, GridTypeMapContainer > grid_object_notifier(notifier);
TypeContainerVisitor<MaNGOS::DynamicObjectUpdater, WorldTypeMapContainer > world_object_notifier(notifier);
TypeContainerVisitor<MaNGOS::DynamicObjectUpdater, GridTypeMapContainer > grid_object_notifier(notifier);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, world_object_notifier, *GetMap());
cell_lock->Visit(cell_lock, grid_object_notifier, *GetMap());
CellLock<GridReadGuard> 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);
}

View file

@ -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<DynamicObject> &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<DynamicObject> m_gridRef;
bool m_isActiveObject;
};
#endif

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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))

View file

@ -31,9 +31,11 @@ template<class T>
inline void
MaNGOS::VisibleNotifier::Visit(GridRefManager<T> &m)
{
WorldObject const* viewPoint = i_player.GetViewPoint();
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());
}
}
@ -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<>

View file

@ -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);
}
}

View file

@ -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)

View file

@ -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<uint64>(); // guid
recv_data.read_skip<uint32>(); // unk
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 */)

View file

@ -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)

View file

@ -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; }

View file

@ -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;

View file

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

View file

@ -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<Unit*>::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<uint64>& s64, GameObject* target)
}
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(!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<WorldObject*>& visibleNow);
template void Player::UpdateVisibilityOf(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(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, Player* 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(WorldObject const* viewPoint, Corpse* 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(WorldObject const* viewPoint, DynamicObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& 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);
}

View file

@ -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<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
void HandleStealthedUnitsDetection();

View file

@ -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)

View file

@ -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)

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)
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);

View file

@ -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

View file

@ -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;

View file

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