aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
authorlinencloth <none@none>2010-11-13 17:18:09 +0100
committerlinencloth <none@none>2010-11-13 17:18:09 +0100
commitbf888285aab32ae2571002f23dd217396b2f12d8 (patch)
treee13695f4909b7df4f218057126919321b4374f58 /src/server/game/Entities
parent995408f0a9e6512af53e7719799d332d487f84eb (diff)
Core:
- Redesigned stealth and invisibility handling - Implemented the handling of multiple stealth types - Implemented fake inebriation - The message deliverer no longer sends packets from a non-visible source - The server won't send that much garbage which just takes bandwith - It won't be possible to use cheats to detect invisible objects - Removed a lot of checks for the Z-coord - Fixes visibility problems happening while flying - Limited the grid activation range of creatures to use less resources - Implemented Shroud of Death - Implemented increased visibility range for active objects - Removed visibility check at spellhit (only sanctuary effects should prevent it) (And a lot of other changes...) Closes issue 4208 Closes issue 3049 Closes issue 2097 Closes issue 2198 Closes issue 2384 Closes issue 2197 Closes issue 2319 --HG-- branch : trunk
Diffstat (limited to 'src/server/game/Entities')
-rwxr-xr-xsrc/server/game/Entities/Corpse/Corpse.cpp5
-rwxr-xr-xsrc/server/game/Entities/Corpse/Corpse.h2
-rwxr-xr-xsrc/server/game/Entities/Creature/Creature.cpp94
-rwxr-xr-xsrc/server/game/Entities/Creature/Creature.h7
-rwxr-xr-xsrc/server/game/Entities/DynamicObject/DynamicObject.cpp6
-rwxr-xr-xsrc/server/game/Entities/DynamicObject/DynamicObject.h1
-rwxr-xr-xsrc/server/game/Entities/GameObject/GameObject.cpp67
-rwxr-xr-xsrc/server/game/Entities/GameObject/GameObject.h14
-rwxr-xr-xsrc/server/game/Entities/Object/Object.cpp256
-rwxr-xr-xsrc/server/game/Entities/Object/Object.h60
-rwxr-xr-xsrc/server/game/Entities/Pet/Pet.cpp2
-rwxr-xr-xsrc/server/game/Entities/Player/Player.cpp292
-rwxr-xr-xsrc/server/game/Entities/Player/Player.h17
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp130
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h37
15 files changed, 457 insertions, 533 deletions
diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp
index e773bb2d1b3..29a2b83e32d 100755
--- a/src/server/game/Entities/Corpse/Corpse.cpp
+++ b/src/server/game/Entities/Corpse/Corpse.cpp
@@ -210,11 +210,6 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields)
return true;
}
-bool Corpse::isVisibleForInState(Player const* u, bool inVisibleList) const
-{
- return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u->m_seer, World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
-}
-
bool Corpse::IsExpired(time_t t) const
{
if (m_type == CORPSE_BONES)
diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h
index 0ea164a90a4..98253fb49ef 100755
--- a/src/server/game/Entities/Corpse/Corpse.h
+++ b/src/server/game/Entities/Corpse/Corpse.h
@@ -73,8 +73,6 @@ class Corpse : public WorldObject, public GridObject<Corpse>
GridPair const& GetGrid() const { return m_grid; }
void SetGrid(GridPair const& grid) { m_grid = grid; }
- bool isVisibleForInState(Player const* u, bool inVisibleList) const;
-
Loot loot; // remove insignia ONLY at BG
Player* lootRecipient;
bool lootForBody;
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index dce2c968a84..6631de8bdd4 100755
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -802,6 +802,18 @@ bool Creature::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry,
LastUsedScriptID = GetCreatureInfo()->ScriptID;
}
+ // TODO: Replace with spell, handle from DB
+ if (isSpiritHealer())
+ {
+ m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST);
+ m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST);
+ }
+ else if(isSpiritGuide())
+ m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST | GHOST_VISIBILITY_ALIVE);
+
+ if (Entry == VISUAL_WAYPOINT)
+ SetVisibility(VISIBILITY_OFF);
+
return bResult;
}
@@ -1385,50 +1397,15 @@ void Creature::DeleteFromDB()
WorldDatabase.CommitTransaction(trans);
}
-bool Creature::canSeeOrDetect(Unit const* u, bool detect, bool /*inVisibleList*/, bool /*is3dDistance*/) const
+bool Creature::isVisibleForInState(WorldObject const* seer) const
{
- // not in world
- if (!IsInWorld() || !u->IsInWorld())
- return false;
-
- // all dead creatures/players not visible for any creatures
- if (!u->isAlive() || !isAlive())
- return false;
-
- // Always can see self
- if (u == this)
- return true;
-
- // phased visibility (both must phased in same way)
- if (!InSamePhase(u))
+ if (!Unit::isVisibleForInState(seer))
return false;
- // always seen by owner
- if (GetGUID() == u->GetCharmerOrOwnerGUID())
+ if (isAlive() || (m_isDeadByDefault && m_deathState == CORPSE) || m_corpseRemoveTime > time(NULL))
return true;
- if (u->GetVisibility() == VISIBILITY_OFF) //GM
- return false;
-
- // invisible aura
- if ((m_invisibilityMask || u->m_invisibilityMask) && !canDetectInvisibilityOf(u))
- return false;
-
- // unit got in stealth in this moment and must ignore old detected state
- //if (m_Visibility == VISIBILITY_GROUP_NO_DETECT)
- // return false;
-
- // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
- if (u->GetVisibility() == VISIBILITY_GROUP_STEALTH)
- {
- //do not know what is the use of this detect
- if (!detect || !canDetectStealthOf(u, GetDistance(u)))
- return false;
- }
-
- // Now check is target visible with LoS
- //return u->IsWithinLOS(GetPositionX(),GetPositionY(),GetPositionZ());
- return true;
+ return false;
}
bool Creature::canStartAttack(Unit const* who, bool force) const
@@ -1784,43 +1761,6 @@ SpellEntry const *Creature::reachWithSpellCure(Unit *pVictim)
return NULL;
}
-bool Creature::IsVisibleInGridForPlayer(Player const* pl) const
-{
- // gamemaster in GM mode see all, including ghosts
- if (pl->isGameMaster())
- return true;
-
- // Trigger shouldn't be visible for players
- //if (isTrigger())
- // return false;
- // Rat: this makes no sense, triggers are always sent to players, but with invisible model and can not be attacked or targeted!
-
- // Live player (or with not release body see live creatures or death creatures with corpse disappearing time > 0
- if (pl->isAlive() || pl->GetDeathTimer() > 0)
- {
- if (GetEntry() == VISUAL_WAYPOINT)
- return false;
- return (isAlive() || m_corpseRemoveTime > time(NULL) || (m_isDeadByDefault && m_deathState == CORPSE));
- }
-
- // Dead player see creatures near own corpse
- Corpse *corpse = pl->GetCorpse();
- if (corpse)
- {
- // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level
- if (corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO)))
- return true;
- }
-
- // Dead player see Spirit Healer or Spirit Guide
- if (isSpiritService())
- return true;
-
- // and not see any other
- return false;
-}
-
-
// select nearest hostile unit within the given distance (regardless of threat list).
Unit* Creature::SelectNearestTarget(float dist) const
{
@@ -1832,7 +1772,7 @@ Unit* Creature::SelectNearestTarget(float dist) const
Unit *target = NULL;
{
- if (dist == 0.0f || dist > MAX_VISIBILITY_DISTANCE)
+ if (dist == 0.0f)
dist = MAX_VISIBILITY_DISTANCE;
Trinity::NearestHostileUnitCheck u_check(this, dist);
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index fcfa9edf3e0..28f6d46d998 100755
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -437,7 +437,7 @@ class Creature : public Unit, public GridObject<Creature>
bool HasReactState(ReactStates state) const { return (m_reactState == state); }
void InitializeReactState()
{
- if (isTotem() || isTrigger() || GetCreatureType() == CREATURE_TYPE_CRITTER)
+ if (isTotem() || isTrigger() || GetCreatureType() == CREATURE_TYPE_CRITTER || isSpiritService())
SetReactState(REACT_PASSIVE);
else
SetReactState(REACT_AGGRESSIVE);
@@ -568,7 +568,6 @@ class Creature : public Unit, public GridObject<Creature>
CreatureSpellCooldowns m_CreatureCategoryCooldowns;
uint32 m_GlobalCooldown;
- bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const;
bool canStartAttack(Unit const* u, bool force) const;
float GetAttackDistance(Unit const* pl) const;
@@ -593,8 +592,6 @@ class Creature : public Unit, public GridObject<Creature>
Cell const& GetCurrentCell() const { return m_currentCell; }
void SetCurrentCell(Cell const& cell) { m_currentCell = cell; }
- bool IsVisibleInGridForPlayer(Player const* pl) const;
-
void RemoveCorpse(bool setSpawnTime = true);
bool isDeadByDefault() const { return m_isDeadByDefault; };
@@ -726,6 +723,8 @@ class Creature : public Unit, public GridObject<Creature>
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
uint32 guid_transport;
+
+ bool isVisibleForInState(WorldObject const* seer) const;
private:
//WaypointMovementGenerator vars
uint32 m_waypointID;
diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp
index bc0db5b8cc2..4f10b410b7a 100755
--- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp
+++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp
@@ -182,9 +182,3 @@ void DynamicObject::Delay(int32 delaytime)
{
SetDuration(GetDuration() - delaytime);
}
-
-bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const
-{
- return IsInWorld() && u->IsInWorld()
- && (IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false));
-}
diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.h b/src/server/game/Entities/DynamicObject/DynamicObject.h
index 80bba2772fe..5b662f4c6de 100755
--- a/src/server/game/Entities/DynamicObject/DynamicObject.h
+++ b/src/server/game/Entities/DynamicObject/DynamicObject.h
@@ -44,7 +44,6 @@ class DynamicObject : public WorldObject, public GridObject<DynamicObject>
uint64 GetCasterGUID() const { return GetUInt64Value(DYNAMICOBJECT_CASTER); }
float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); }
Unit* GetCaster() const;
- bool isVisibleForInState(Player const* u, 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); }
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 33dd0422ce8..bb79c2e0ea4 100755
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -227,6 +227,20 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa
case GAMEOBJECT_TYPE_FISHINGNODE:
SetGoAnimProgress(0);
break;
+ case GAMEOBJECT_TYPE_TRAP:
+ if (GetGOInfo()->trap.stealthed)
+ {
+ m_stealth.AddFlag( STEALTH_TRAP);
+ m_stealth.AddValue(STEALTH_TRAP, 300);
+ }
+
+ if (GetGOInfo()->trap.invisible)
+ {
+ m_invisibility.AddFlag( INVISIBILITY_TRAP);
+ m_invisibility.AddValue(INVISIBILITY_TRAP, 70);
+ }
+
+ break;
default:
SetGoAnimProgress(animprogress);
break;
@@ -810,56 +824,27 @@ void GameObject::SaveRespawnTime()
sObjectMgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime);
}
-bool GameObject::isVisibleForInState(Player const* u, bool inVisibleList) const
+bool GameObject::isAlwaysVisibleFor(WorldObject const* seer) const
{
- // Not in world
- if (!IsInWorld() || !u->IsInWorld())
- return false;
-
- // Transport always visible at this step implementation
- if (IsTransport() && IsInMap(u))
+ if (WorldObject::isAlwaysVisibleFor(seer))
return true;
- // quick check visibility false cases for non-GM-mode
- if (!u->isGameMaster())
- {
- // despawned and then not visible for non-GM in GM-mode
- if (!isSpawned())
- return false;
-
- // special invisibility cases
- if (GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && GetGOInfo()->trap.stealthed)
- {
- Unit *owner = GetOwner();
- if (owner && u->IsHostileTo(owner) && !canDetectTrap(u, GetDistance(u)))
- return false;
- }
- }
-
- // check distance
- return IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject() +
- (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
+ if (IsTransport())
+ return true;
+
+ return false;
}
-bool GameObject::canDetectTrap(Player const* u, float distance) const
+bool GameObject::isVisibleForInState(WorldObject const* seer) const
{
- if (u->hasUnitState(UNIT_STAT_STUNNED))
+ if (!WorldObject::isVisibleForInState(seer))
return false;
- if (distance < GetGOInfo()->size) //collision
- return true;
- if (!u->HasInArc(M_PI, this)) //behind
- return false;
- if (u->HasAuraType(SPELL_AURA_DETECT_STEALTH))
- return true;
- //Visible distance is modified by -Level Diff (every level diff = 0.25f in visible distance)
- float visibleDistance = (int32(u->getLevel()) - int32(GetOwner()->getLevel()))* 0.25f;
- //GetModifier for trap (miscvalue 1)
- //35y for aura 2836
- //WARNING: these values are guessed, may be not blizzlike
- visibleDistance += u->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DETECT, 1)* 0.5f;
+ // Despawned
+ if (!isSpawned())
+ return false;
- return distance < visibleDistance;
+ return true;
}
void GameObject::Respawn()
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 4ed40c7d6e9..e8c37cb34cd 100755
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -136,7 +136,7 @@ struct GameObjectInfo
uint32 serverOnly; //8
uint32 stealthed; //9
uint32 large; //10
- uint32 stealthAffected; //11
+ uint32 invisible; //11
uint32 openTextID; //12 can be used to replace castBarCaption?
uint32 closeTextID; //13
uint32 ignoreTotems; //14
@@ -733,8 +733,16 @@ class GameObject : public WorldObject, public GridObject<GameObject>
void TriggeringLinkedGameObject(uint32 trapEntry, Unit* target);
- bool isVisibleForInState(Player const* u, bool inVisibleList) const;
- bool canDetectTrap(Player const* u, float distance) const;
+ bool isAlwaysVisibleFor(WorldObject const* seer) const;
+ bool isVisibleForInState(WorldObject const* seer) const;
+
+ uint8 getLevelForTarget(WorldObject const* target) const
+ {
+ if (Unit* owner = GetOwner())
+ return owner->getLevelForTarget(target);
+
+ return 1;
+ }
GameObject* LookupFishingHoleAround(float range);
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 868443031ae..e7edea0b07f 100755
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1223,7 +1223,10 @@ WorldObject::WorldObject(): WorldLocation(),
m_isWorldObject(false), m_name(""), m_isActive(false), m_zoneScript(NULL),
m_transport(NULL), m_currMap(NULL), m_InstanceId(0),
m_phaseMask(PHASEMASK_NORMAL), m_notifyflags(0), m_executed_notifies(0)
-{}
+{
+ m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST);
+ m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
+}
void WorldObject::SetWorldObject(bool on)
{
@@ -1608,6 +1611,239 @@ void WorldObject::MonsterWhisper(const char* text, uint64 receiver, bool IsBossW
player->GetSession()->SendPacket(&data);
}
+bool WorldObject::isValid() const
+{
+ if (!IsInWorld())
+ return false;
+
+ return true;
+}
+
+float WorldObject::GetGridActivationRange() const
+{
+ if (ToPlayer())
+ return GetMap()->GetVisibilityRange();
+ else if (ToCreature())
+ return ToCreature()->m_SightDistance;
+ else
+ return 0.0f;
+}
+
+float WorldObject::GetVisibilityRange() const
+{
+ if (isActiveObject() && !ToPlayer())
+ return MAX_VISIBILITY_DISTANCE;
+ else
+ return GetMap()->GetVisibilityRange();
+}
+
+float WorldObject::GetSightRange(const WorldObject* target) const
+{
+ if (ToUnit())
+ {
+ if (ToPlayer())
+ {
+ if (target && target->isActiveObject())
+ return MAX_VISIBILITY_DISTANCE;
+ else
+ return GetMap()->GetVisibilityRange();
+ }
+ else if (ToCreature())
+ return ToCreature()->m_SightDistance;
+ else
+ return SIGHT_RANGE_UNIT;
+ }
+
+ return 0.0f;
+}
+
+bool WorldObject::canSeeOrDetect(WorldObject const* obj, bool ignoreStealth, bool distanceCheck) const
+{
+ if (this == obj)
+ return true;
+
+ if (!obj->isValid())
+ return false;
+
+ if (GetMap() != obj->GetMap())
+ return false;
+
+ if (!InSamePhase(obj))
+ return false;
+
+ if (obj->isAlwaysVisibleFor(this))
+ return true;
+
+ if (canSeeAlways(obj))
+ return true;
+
+ bool corpseCheck = false;
+ bool corpseVisibility = false;
+ if (distanceCheck)
+ {
+ if (const Player* thisPlayer = ToPlayer())
+ {
+ if (thisPlayer->isDead() && thisPlayer->GetHealth() > 0 && // Cheap way to check for ghost state
+ !(obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & GHOST_VISIBILITY_GHOST))
+ {
+ if (Corpse* corpse = thisPlayer->GetCorpse())
+ {
+ corpseCheck = true;
+ if (corpse->IsWithinDist(thisPlayer, GetSightRange(obj), false))
+ if (corpse->IsWithinDist(obj, GetSightRange(obj), false))
+ corpseVisibility = true;
+ }
+ }
+ }
+
+ if (!corpseCheck && !IsWithinDist(obj, GetSightRange(obj), false))
+ return false;
+ }
+
+ // GM visibility off or hidden NPC
+ if (!obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM))
+ {
+ // Stop checking other things for GMs
+ if (m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GM))
+ return true;
+ }
+ else
+ return m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GM) >= obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM);
+
+ // Ghost players, Spirit Healers, and some other NPCs
+ if (!corpseVisibility && !(obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GHOST)))
+ {
+ // Alive players can see dead players in some cases, but other objects can't do that
+ if (const Player* thisPlayer = ToPlayer())
+ {
+ if (const Player* objPlayer = obj->ToPlayer())
+ {
+ if (thisPlayer->GetTeam() != objPlayer->GetTeam() || !thisPlayer->IsGroupVisibleFor(objPlayer))
+ return false;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+
+ if (!obj->isVisibleForInState(this))
+ return false;
+
+ if (!canDetect(obj, ignoreStealth))
+ return false;
+
+ return true;
+}
+
+bool WorldObject::canDetect(WorldObject const* obj, bool ignoreStealth) const
+{
+ const WorldObject* seer = this;
+
+ // Pets don't have detection, they use the detection of their masters
+ if (const Unit* thisUnit = ToUnit())
+ if (Unit* controller = thisUnit->GetCharmerOrOwner())
+ seer = controller;
+
+ if (obj->isAlwaysDetectableFor(seer))
+ return true;
+
+ if (!seer->canDetectInvisibilityOf(obj))
+ return false;
+
+ if (!ignoreStealth && !seer->canDetectStealthOf(obj))
+ return false;
+
+ return true;
+}
+
+bool WorldObject::canDetectInvisibilityOf(WorldObject const* obj) const
+{
+ uint32 mask = obj->m_invisibility.GetFlags() & m_invisibilityDetect.GetFlags();
+
+ // Check for not detected types
+ if (mask != obj->m_invisibility.GetFlags())
+ return false;
+
+ // It isn't possible in invisibility to detect something that can't detect the invisible object
+ // (it's at least true for spell: 66)
+ // It seems like that only Units are affected by this check (couldn't see arena doors with preparation invisibility)
+ if (obj->ToUnit())
+ if ((m_invisibility.GetFlags() & obj->m_invisibilityDetect.GetFlags()) != m_invisibility.GetFlags())
+ return false;
+
+ for (uint32 i = 0; i < TOTAL_INVISIBILITY_TYPES; ++i)
+ {
+ if (!(mask & (1 << i)))
+ continue;
+
+ int32 objInvisibilityValue = obj->m_invisibility.GetValue(InvisibilityType(i));
+ int32 ownInvisibilityDetectValue = m_invisibilityDetect.GetValue(InvisibilityType(i));
+
+ // Too low value to detect
+ if (ownInvisibilityDetectValue < objInvisibilityValue)
+ return false;
+ }
+
+ return true;
+}
+
+bool WorldObject::canDetectStealthOf(WorldObject const* obj) const
+{
+ // Combat reach is the minimal distance (both in front and behind),
+ // and it is also used in the range calculation.
+ // One stealth point increases the visibility range by 0.3 yard.
+
+ if (!obj->m_stealth.GetFlags())
+ return true;
+
+ float distance = GetExactDist(obj);
+ float combatReach = 0.0f;
+
+ if (isType(TYPEMASK_UNIT))
+ combatReach = ((Unit*)this)->GetCombatReach();
+
+ if (distance < combatReach)
+ return true;
+
+ if (!HasInArc(M_PI, obj))
+ return false;
+
+ for (uint32 i = 0; i < TOTAL_STEALTH_TYPES; ++i)
+ {
+ if (!(obj->m_stealth.GetFlags() & (1 << i)))
+ continue;
+
+ if (isType(TYPEMASK_UNIT))
+ if (((Unit*)this)->HasAuraTypeWithMiscvalue(SPELL_AURA_DETECT_STEALTH, i))
+ return true;
+
+ // Starting points
+ int32 detectionValue = 30;
+
+ // Level difference: 5 point / level, starting from level 1.
+ // There may be spells for this and the starting points too, but
+ // not in the DBCs of the client.
+ detectionValue += int32(getLevelForTarget(obj) - 1) * 5;
+
+ // Apply modifiers
+ detectionValue += m_stealthDetect.GetValue(StealthType(i));
+ detectionValue -= obj->m_stealth.GetValue(StealthType(i));
+
+ // Calculate max distance
+ float visibilityRange = float(detectionValue) * 0.3f + combatReach;
+
+ if (visibilityRange > MAX_PLAYER_STEALTH_DETECT_RANGE)
+ visibilityRange = MAX_PLAYER_STEALTH_DETECT_RANGE;
+
+ if (distance > visibilityRange)
+ return false;
+ }
+
+ return true;
+}
+
void WorldObject::SendPlaySound(uint32 Sound, bool OnlySelf)
{
WorldPacket data(SMSG_PLAY_SOUND, 4);
@@ -1754,12 +1990,6 @@ void Unit::BuildHeartBeatMsg(WorldPacket *data) const
BuildMovementPacket(data);
}
-void WorldObject::SendMessageToSet(WorldPacket *data, bool /*fake*/)
-{
- Trinity::MessageDistDeliverer notifier(this, data, GetMap()->GetVisibilityDistance());
- VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier);
-}
-
void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*bToSelf*/)
{
Trinity::MessageDistDeliverer notifier(this, data, dist);
@@ -1768,8 +1998,8 @@ void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*
void WorldObject::SendMessageToSet(WorldPacket *data, Player const* skipped_rcvr)
{
- Trinity::MessageDistDeliverer notifier(this, data, GetMap()->GetVisibilityDistance(), false, skipped_rcvr);
- VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier);
+ Trinity::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr);
+ VisitNearbyWorldObject(GetVisibilityRange(), notifier);
}
void WorldObject::SendObjectDeSpawnAnim(uint64 guid)
@@ -2434,9 +2664,9 @@ void WorldObject::DestroyForNearbyPlayers()
return;
std::list<Player*> targets;
- Trinity::AnyPlayerInObjectRangeCheck check(this, GetMap()->GetVisibilityDistance());
+ Trinity::AnyPlayerInObjectRangeCheck check(this, GetVisibilityRange());
Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, targets, check);
- VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), searcher);
+ VisitNearbyWorldObject(GetVisibilityRange(), searcher);
for (std::list<Player*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
{
Player *plr = (*iter);
@@ -2459,7 +2689,7 @@ void WorldObject::UpdateObjectVisibility(bool /*forced*/)
{
//updates object's visibility for nearby players
Trinity::VisibleChangesNotifier notifier(*this);
- VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier);
+ VisitNearbyWorldObject(GetVisibilityRange(), notifier);
}
struct WorldObjectChangeAccumulator
@@ -2531,7 +2761,7 @@ void WorldObject::BuildUpdate(UpdateDataMapType& data_map)
TypeContainerVisitor<WorldObjectChangeAccumulator, WorldTypeMapContainer > player_notifier(notifier);
Map& map = *GetMap();
//we must build packets for all visible players
- cell.Visit(p, player_notifier, map, *this, map.GetVisibilityDistance());
+ cell.Visit(p, player_notifier, map, *this, GetVisibilityRange());
ClearUpdateMask(false);
}
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index b05b98f67b7..ff68bd3e9db 100755
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -34,7 +34,8 @@
#define CONTACT_DISTANCE 0.5f
#define INTERACTION_DISTANCE 5.0f
#define ATTACK_DISTANCE 5.0f
-#define MAX_VISIBILITY_DISTANCE 333.0f // max distance for visible object show, limited in 333 yards
+#define MAX_VISIBILITY_DISTANCE 500.0f // max distance for visible objects
+#define SIGHT_RANGE_UNIT 50.0f
#define DEFAULT_VISIBILITY_DISTANCE 90.0f // default visible distance, 90 yards on continents
#define DEFAULT_VISIBILITY_INSTANCE 120.0f // default visible distance in instances, 120 yards
#define DEFAULT_VISIBILITY_BGARENAS 180.0f // default visible distance in BG/Arenas, 180 yards
@@ -542,6 +543,30 @@ class GridObject
GridReference<T> m_gridRef;
};
+template <class T_VALUES, class T_FLAGS, class FLAG_TYPE, uint8 ARRAY_SIZE>
+class FlaggedValuesArray32
+{
+ public:
+ FlaggedValuesArray32()
+ {
+ memset(&m_values, 0x00, sizeof(T_VALUES) * ARRAY_SIZE);
+ m_flags = 0;
+ }
+
+ T_FLAGS GetFlags() const { return m_flags; }
+ bool HasFlag(FLAG_TYPE flag) const { return m_flags & (1 << flag); }
+ void AddFlag(FLAG_TYPE flag) { m_flags |= (1 << flag); }
+ void DelFlag(FLAG_TYPE flag) { m_flags &= ~(1 << flag); }
+
+ T_VALUES GetValue(FLAG_TYPE flag) const { return m_values[flag]; }
+ void SetValue(FLAG_TYPE flag, T_VALUES value) { m_values[flag] = value; }
+ void AddValue(FLAG_TYPE flag, T_VALUES value) { m_values[flag] += value; }
+
+ private:
+ T_VALUES m_values[ARRAY_SIZE];
+ T_FLAGS m_flags;
+};
+
class WorldObject : public Object, public WorldLocation
{
protected:
@@ -681,10 +706,12 @@ class WorldObject : public Object, public WorldLocation
virtual void CleanupsBeforeDelete(bool finalCleanup = true); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units
- virtual void SendMessageToSet(WorldPacket *data, bool self);
+ virtual void SendMessageToSet(WorldPacket *data, bool self) { SendMessageToSetInRange(data, GetVisibilityRange(), self); }
virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self);
virtual void SendMessageToSet(WorldPacket *data, Player const* skipped_rcvr);
+ virtual uint8 getLevelForTarget(WorldObject const* /*target*/) const { return 1; }
+
void MonsterSay(const char* text, uint32 language, uint64 TargetGuid);
void MonsterYell(const char* text, uint32 language, uint64 TargetGuid);
void MonsterTextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote = false);
@@ -704,11 +731,32 @@ class WorldObject : public Object, public WorldLocation
virtual void SaveRespawnTime() {}
void AddObjectToRemoveList();
- // main visibility check function in normal case (ignore grey zone distance check)
- bool isVisibleFor(Player const* u) const { return isVisibleForInState(u,false); }
+ virtual bool isValid() const;
+
+ virtual bool isAlwaysVisibleFor(WorldObject const* seer) const { return false; }
+ virtual bool canSeeAlways(WorldObject const* obj) const { return false; }
+ bool canDetect(WorldObject const* obj, bool ignoreStealth) const;
+
+ virtual bool isVisibleForInState(WorldObject const* seer) const { return true; }
+
+ bool canDetectInvisibilityOf(WorldObject const* obj) const;
+ bool canDetectStealthOf(WorldObject const* obj) const;
+
+ virtual bool isAlwaysDetectableFor(WorldObject const* seer) const { return false; }
+
+ float GetGridActivationRange() const;
+ float GetVisibilityRange() const;
+ float GetSightRange(const WorldObject* target = NULL) const;
+ bool canSeeOrDetect(WorldObject const* obj, bool ignoreStealth = false, bool distanceCheck = false) const;
+
+ FlaggedValuesArray32<int32, uint32, StealthType, TOTAL_STEALTH_TYPES> m_stealth;
+ FlaggedValuesArray32<int32, uint32, StealthType, TOTAL_STEALTH_TYPES> m_stealthDetect;
+
+ FlaggedValuesArray32<int32, uint32, InvisibilityType, TOTAL_INVISIBILITY_TYPES> m_invisibility;
+ FlaggedValuesArray32<int32, uint32, InvisibilityType, TOTAL_INVISIBILITY_TYPES> m_invisibilityDetect;
- // 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;
+ FlaggedValuesArray32<int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES> m_serverSideVisibility;
+ FlaggedValuesArray32<int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES> m_serverSideVisibilityDetect;
// Low Level Packets
void SendPlaySound(uint32 Sound, bool OnlySelf);
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index df482c40143..bf570ce0693 100755
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -506,7 +506,7 @@ void Pet::Update(uint32 diff)
{
// unsummon pet that lost owner
Player* owner = GetOwner();
- if (!owner || (!IsWithinDistInMap(owner, GetMap()->GetVisibilityDistance()) && !isPossessed()) || (isControlled() && !owner->GetPetGUID()))
+ if (!owner || (!IsWithinDistInMap(owner, GetMap()->GetVisibilityRange()) && !isPossessed()) || (isControlled() && !owner->GetPetGUID()))
//if (!owner || (!IsWithinDistInMap(owner, GetMap()->GetVisibilityDistance()) && (owner->GetCharmGUID() && (owner->GetCharmGUID() != GetGUID()))) || (isControlled() && !owner->GetPetGUID()))
{
Remove(PET_SAVE_NOT_IN_SLOT, true);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 07e56dafe89..02d6c4cebb0 100755
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -485,8 +485,6 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
m_swingErrorMsg = 0;
- m_DetectInvTimer = 1*IN_MILLISECONDS;
-
for (uint8 j = 0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j)
{
m_bgBattlegroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
@@ -1216,16 +1214,19 @@ void Player::SetDrunkValue(uint16 newDrunkenValue, uint32 itemId)
{
uint32 oldDrunkenState = Player::GetDrunkenstateByValue(m_drunk);
+ if (!newDrunkenValue && !HasAuraType(SPELL_AURA_MOD_FAKE_INEBRIATE))
+ m_invisibilityDetect.AddFlag(INVISIBILITY_DRUNK);
+ else
+ m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK);
+
+ m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, int32(newDrunkenValue - m_drunk) / 256);
+
m_drunk = newDrunkenValue;
SetUInt32Value(PLAYER_BYTES_3,(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFF0001) | (m_drunk & 0xFFFE));
uint32 newDrunkenState = Player::GetDrunkenstateByValue(m_drunk);
- // special drunk invisibility detection
- if (newDrunkenState >= DRUNKEN_DRUNK)
- m_detectInvisibilityMask |= (1<<6);
- else
- m_detectInvisibilityMask &= ~(1<<6);
+ UpdateObjectVisibility();
if (newDrunkenState == oldDrunkenState)
return;
@@ -1477,18 +1478,6 @@ void Player::Update(uint32 p_time)
//Handle Water/drowning
HandleDrowning(p_time);
- //Handle detect stealth players
- if (m_DetectInvTimer > 0)
- {
- if (p_time >= m_DetectInvTimer)
- {
- HandleStealthedUnitsDetection();
- m_DetectInvTimer = 3000;
- }
- else
- m_DetectInvTimer -= p_time;
- }
-
// Played time
if (now > m_Last_tick)
{
@@ -1526,7 +1515,7 @@ void Player::Update(uint32 p_time)
SendUpdateToOutOfRangeGroupMembers();
Pet* pet = GetPet();
- if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && !pet->isPossessed())
+ if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityRange()) && !pet->isPossessed())
//if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID())))
RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);
@@ -1907,7 +1896,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
if (!(options & TELE_TO_NOT_UNSUMMON_PET))
{
//same map, only remove pet if out of range for new position
- if (pet && !pet->IsWithinDist3d(x,y,z, GetMap()->GetVisibilityDistance()))
+ if (pet && !pet->IsWithinDist3d(x,y,z, GetMap()->GetVisibilityRange()))
UnsummonPetTemporaryIfAny();
}
@@ -2508,6 +2497,7 @@ void Player::SetGameMaster(bool on)
CombatStopWithPets();
SetPhaseMask(PHASEMASK_ANYWHERE,false); // see and visible in all phases
+ m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, GetSession()->GetSecurity());
}
else
{
@@ -2537,6 +2527,7 @@ void Player::SetGameMaster(bool on)
UpdateArea(m_areaUpdateId);
getHostileRefManager().setOnlineOfflineState(true);
+ m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER);
}
UpdateObjectVisibility();
@@ -2548,13 +2539,7 @@ void Player::SetGMVisible(bool on)
{
m_ExtraFlags &= ~PLAYER_EXTRA_GM_INVISIBLE; //remove flag
- // Reapply stealth/invisibility if active or show if not any
- if (HasAuraType(SPELL_AURA_MOD_STEALTH))
- SetVisibility(VISIBILITY_GROUP_STEALTH);
- //else if (HasAuraType(SPELL_AURA_MOD_INVISIBILITY))
- // SetVisibility(VISIBILITY_GROUP_INVISIBILITY);
- else
- SetVisibility(VISIBILITY_ON);
+ m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER);
}
else
{
@@ -2563,11 +2548,11 @@ void Player::SetGMVisible(bool on)
SetAcceptWhispers(false);
SetGameMaster(true);
- SetVisibility(VISIBILITY_OFF);
+ m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, GetSession()->GetSecurity());
}
}
-bool Player::IsGroupVisibleFor(Player* p) const
+bool Player::IsGroupVisibleFor(Player const* p) const
{
switch(sWorld.getIntConfig(CONFIG_GROUP_VISIBILITY))
{
@@ -6423,17 +6408,6 @@ void Player::SaveRecallPosition()
m_recallO = GetOrientation();
}
-void Player::SendMessageToSet(WorldPacket *data, bool self)
-{
- if (self)
- GetSession()->SendPacket(data);
-
- // we use World::GetMaxVisibleDistance() because i cannot see why not use a distance
- // update: replaced by GetMap()->GetVisibilityDistance()
- Trinity::MessageDistDeliverer notifier(this, data, GetMap()->GetVisibilityDistance());
- VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier);
-}
-
void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self)
{
if (self)
@@ -6459,8 +6433,8 @@ void Player::SendMessageToSet(WorldPacket *data, Player const* skipped_rcvr)
// we use World::GetMaxVisibleDistance() because i cannot see why not use a distance
// update: replaced by GetMap()->GetVisibilityDistance()
- Trinity::MessageDistDeliverer notifier(this, data, GetMap()->GetVisibilityDistance(), false, skipped_rcvr);
- VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier);
+ Trinity::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr);
+ VisitNearbyWorldObject(GetVisibilityRange(), notifier);
}
void Player::SendDirectMessage(WorldPacket *data)
@@ -19373,49 +19347,6 @@ void Player::SetRestBonus (float rest_bonus_new)
SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, uint32(m_rest_bonus));
}
-void Player::HandleStealthedUnitsDetection()
-{
- std::list<Unit*> stealthedUnits;
- Trinity::AnyStealthedCheck u_check;
- Trinity::UnitListSearcher<Trinity::AnyStealthedCheck > searcher(this, stealthedUnits, u_check);
- VisitNearbyObject(GetMap()->GetVisibilityDistance(), searcher);
-
- for (std::list<Unit*>::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i)
- {
- if ((*i) == this)
- continue;
-
- bool hasAtClient = HaveAtClient((*i));
- bool hasDetected = canSeeOrDetect(*i, true);
-
- if (hasDetected)
- {
- if (!hasAtClient)
- {
- (*i)->SendUpdateToPlayer(this);
- m_clientGUIDs.insert((*i)->GetGUID());
-
- #ifdef TRINITY_DEBUG
- if ((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES) == 0)
- sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i));
- #endif
-
- // target aura duration for caster show only if target exist at caster client
- // send data at target visibility change (adding to client)
- SendInitialVisiblePackets(*i);
- }
- }
- else
- {
- if (hasAtClient)
- {
- (*i)->DestroyForPlayer(this);
- m_clientGUIDs.erase((*i)->GetGUID());
- }
- }
- }
-}
-
bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= NULL*/, uint32 spellid /*= 0*/)
{
if (nodes.size() < 2)
@@ -20540,177 +20471,44 @@ WorldLocation Player::GetStartPosition() const
return WorldLocation(mapId, info->positionX, info->positionY, info->positionZ, 0);
}
-bool Player::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList, bool is3dDistance) const
+bool Player::isValid() const
{
- // Always can see self
- if (m_mover == u || this == u)
- return true;
-
- // Arena visibility before arena start
- if (InArena() && GetBattleground()->GetStatus() == STATUS_WAIT_JOIN)
- if (const Player* target = u->GetCharmerOrOwnerPlayerOrPlayerItself())
- return GetBGTeam() == target->GetBGTeam() && target->isGMVisible();
-
- // phased visibility (both must phased in same way)
- if (!InSamePhase(u))
+ if (!Unit::isValid())
return false;
- // player visible for other player if not logout and at same transport
- // including case when player is out of world
- bool at_same_transport =
- GetTransport() && u->GetTypeId() == TYPEID_PLAYER
- && !GetSession()->PlayerLogout() && !u->ToPlayer()->GetSession()->PlayerLogout()
- && !GetSession()->PlayerLoading() && !u->ToPlayer()->GetSession()->PlayerLoading()
- && GetTransport() == u->ToPlayer()->GetTransport();
-
- // not in world
- if (!at_same_transport && (!IsInWorld() || !u->IsInWorld()))
- return false;
-
- // forbidden to seen (at GM respawn command)
- //if (u->GetVisibility() == VISIBILITY_RESPAWN)
- // return false;
-
- Map& _map = *u->GetMap();
- // Grid dead/alive checks
- // non visible at grid for any stealth state
- if (!u->IsVisibleInGridForPlayer(this))
+ if (GetSession()->PlayerLogout() || GetSession()->PlayerLoading())
return false;
- // always seen by owner
- if (uint64 guid = u->GetCharmerOrOwnerGUID())
- if (GetGUID() == guid)
- return true;
-
- if (uint64 guid = GetUInt64Value(PLAYER_FARSIGHT))
- if (u->GetGUID() == guid)
- return true;
-
- // different visible distance checks
- if (isInFlight()) // what see player in flight
- {
- if (!m_seer->IsWithinDistInMap(u, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance))
- return false;
- }
- else if (!u->isAlive()) // distance for show body
- {
- if (!m_seer->IsWithinDistInMap(u, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance))
- return false;
- }
- else if (u->GetTypeId() == TYPEID_PLAYER) // distance for show player
- {
- // Players far than max visible distance for player or not in our map are not visible too
- if (!at_same_transport && !m_seer->IsWithinDistInMap(u, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
- return false;
- }
- else if (u->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 (!m_seer->IsWithinDistInMap(u, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance))
- return false;
- }
- else // distance for show creature
- {
- // Units farther than max visible distance for creature or not in our map are not visible too
- if (!m_seer->IsWithinDistInMap(u
- , u->isActiveObject() ? (MAX_VISIBILITY_DISTANCE - (inVisibleList ? 0.0f : World::GetVisibleUnitGreyDistance()))
- : (_map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))
- , is3dDistance))
- return false;
- }
-
- if (Unit* owner = u->GetCharmerOrOwnerOrSelf())
- {
- if (owner->GetVisibility() == VISIBILITY_OFF)
- {
- // GMs see any players, not higher GMs and all units
- if (isGameMaster())
- {
- if (owner->GetTypeId() == TYPEID_PLAYER)
- return owner->ToPlayer()->GetSession()->GetSecurity() <= GetSession()->GetSecurity();
- else
- return true;
- }
- return false;
- }
- }
-
- // GM's can see everyone with invisibilitymask with less or equal security level
- if (m_mover->m_invisibilityMask || u->m_invisibilityMask)
- {
- if (isGameMaster())
- {
- if (u->GetTypeId() == TYPEID_PLAYER)
- return u->ToPlayer()->GetSession()->GetSecurity() <= GetSession()->GetSecurity();
- else
- return true;
- }
-
- // player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting)
- if (!m_mover->canDetectInvisibilityOf(u))
- if (!(u->GetTypeId() == TYPEID_PLAYER && !IsHostileTo(u) && IsGroupVisibleFor(const_cast<Player*>(u->ToPlayer()))))
- return false;
- }
-
- // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible
- if (u->GetVisibility() == VISIBILITY_GROUP_STEALTH && !isGameMaster())
- {
- // if player is dead then he can't detect anyone in any cases
- //do not know what is the use of this detect
- // stealth and detected and visible for some seconds
- if (!isAlive())
- detect = false;
- if (m_DetectInvTimer < 300 || !HaveAtClient(u))
- if (!(u->GetTypeId() == TYPEID_PLAYER && !IsHostileTo(u) && IsGroupVisibleFor(const_cast<Player*>(u->ToPlayer()))))
- if (!detect || !m_mover->canDetectStealthOf(u, GetDistance(u)))
- return false;
- }
-
- // If use this server will be too laggy
- // Now check is target visible with LoS
- //return u->IsWithinLOS(GetPositionX(),GetPositionY(),GetPositionZ());
return true;
}
-bool Player::IsVisibleInGridForPlayer(Player const * pl) const
+bool Player::canSeeAlways(WorldObject const* obj) const
{
- // gamemaster in GM mode see all, including ghosts
- if (pl->isGameMaster() && GetSession()->GetSecurity() <= pl->GetSession()->GetSecurity())
+ if (Unit::canSeeAlways(obj))
return true;
- // It seems in battleground everyone sees everyone, except the enemy-faction ghosts
- if (InBattleground())
- {
- if (!(isAlive() || m_deathTimer > 0) && !IsFriendlyTo(pl))
- return false;
+ // Always can see self
+ if (m_mover == obj)
return true;
- }
- // Live player see live player or dead player with not realized corpse
- if (pl->isAlive() || pl->m_deathTimer > 0)
- {
- return isAlive() || m_deathTimer > 0;
- }
+ if (uint64 guid = GetUInt64Value(PLAYER_FARSIGHT))
+ if (obj->GetGUID() == guid)
+ return true;
+
+ return false;
+}
- // Ghost see other friendly ghosts, that's for sure
- if (!(isAlive() || m_deathTimer > 0) && IsFriendlyTo(pl))
+bool Player::isAlwaysDetectableFor(WorldObject const* seer) const
+{
+ if (Unit::isAlwaysDetectableFor(seer))
return true;
- // Dead player see live players near own corpse
- if (isAlive())
- {
- Corpse *corpse = pl->GetCorpse();
- if (corpse)
- {
- // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level
- if (corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO)))
- return true;
- }
- }
+ if (const Player* seerPlayer = seer->ToPlayer())
+ if (IsGroupVisibleFor(seerPlayer))
+ return true;
- // and not see any other
- return false;
-}
+ return false;
+ }
bool Player::IsVisibleGloballyFor(Player* u) const
{
@@ -20780,7 +20578,7 @@ void Player::UpdateVisibilityOf(WorldObject* target)
{
if (HaveAtClient(target))
{
- if (!target->isVisibleForInState(this, true))
+ if (!canSeeOrDetect(target, false, true))
{
if (target->GetTypeId() == TYPEID_UNIT)
BeforeVisibilityDestroy<Creature>(target->ToCreature(),this);
@@ -20796,7 +20594,7 @@ void Player::UpdateVisibilityOf(WorldObject* target)
}
else
{
- if (target->isVisibleForInState(this,false))
+ if (canSeeOrDetect(target, false, true))
{
//if (target->isType(TYPEMASK_UNIT) && ((Unit*)target)->m_Vehicle)
// UpdateVisibilityOf(((Unit*)target)->m_Vehicle);
@@ -20856,7 +20654,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& vi
{
if (HaveAtClient(target))
{
- if (!target->isVisibleForInState(this,true))
+ if (!canSeeOrDetect(target, false, true))
{
BeforeVisibilityDestroy<T>(target,this);
@@ -20871,7 +20669,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& vi
}
else //if (visibleNow.size() < 30 || target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->IsVehicle())
{
- if (target->isVisibleForInState(this,false))
+ if (canSeeOrDetect(target, false, true))
{
//if (target->isType(TYPEMASK_UNIT) && ((Unit*)target)->m_Vehicle)
// UpdateVisibilityOf(((Unit*)target)->m_Vehicle, data, visibleNow);
@@ -20902,7 +20700,7 @@ void Player::UpdateObjectVisibility(bool forced)
Unit::UpdateObjectVisibility(true);
// updates visibility of all objects around point of view for current player
Trinity::VisibleNotifier notifier(*this);
- m_seer->VisitNearbyObject(GetMap()->GetVisibilityDistance(), notifier);
+ m_seer->VisitNearbyObject(GetVisibilityRange(), notifier);
notifier.SendToSelf(); // send gathered data
}
}
@@ -20910,7 +20708,7 @@ void Player::UpdateObjectVisibility(bool forced)
void Player::UpdateVisibilityForPlayer()
{
Trinity::VisibleNotifier notifier(*this);
- m_seer->VisitNearbyObject(GetMap()->GetVisibilityDistance(), notifier);
+ m_seer->VisitNearbyObject(GetVisibilityRange(), notifier);
notifier.SendToSelf(); // send gathered data
}
@@ -21052,6 +20850,8 @@ void Player::SetGroup(Group *group, int8 subgroup)
m_group.link(group, this);
m_group.setSubGroup((uint8)subgroup);
}
+
+ UpdateObjectVisibility();
}
void Player::SendInitialPacketsBeforeAddToMap()
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index efed19af453..7e151769810 100755
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1706,7 +1706,7 @@ class Player : public Unit, public GridObject<Player>
void DuelComplete(DuelCompleteType type);
void SendDuelCountdown(uint32 counter);
- bool IsGroupVisibleFor(Player* p) const;
+ bool IsGroupVisibleFor(Player const* p) const;
bool IsInSameGroupWith(Player const* p) const;
bool IsInSameRaidWith(Player const* p) const { return p == this || (GetGroup() != NULL && GetGroup() == p->GetGroup()); }
void UninviteFromGroup();
@@ -1842,7 +1842,7 @@ class Player : public Unit, public GridObject<Player>
bool SetPosition(const Position &pos, bool teleport = false) { return SetPosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); }
void UpdateUnderwaterState(Map * m, float x, float y, float z);
- void SendMessageToSet(WorldPacket *data, bool self);// overwrite Object::SendMessageToSet
+ void SendMessageToSet(WorldPacket *data, bool self) {SendMessageToSetInRange(data, GetVisibilityRange(), self); };// overwrite Object::SendMessageToSet
void SendMessageToSetInRange(WorldPacket *data, float fist, bool self);// overwrite Object::SendMessageToSetInRange
void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only);
void SendMessageToSet(WorldPacket *data, Player const* skipped_rcvr);
@@ -2232,8 +2232,8 @@ class Player : public Unit, public GridObject<Player>
bool HaveAtClient(WorldObject const* u) const { return u == this || m_clientGUIDs.find(u->GetGUID()) != m_clientGUIDs.end(); }
- bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const;
- bool IsVisibleInGridForPlayer(Player const* pl) const;
+ bool isValid() const;
+
bool IsVisibleGloballyFor(Player* pl) const;
void SendInitialVisiblePackets(Unit* target);
@@ -2245,9 +2245,6 @@ class Player : public Unit, public GridObject<Player>
template<class T>
void UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow);
- // Stealth detection system
- void HandleStealthedUnitsDetection();
-
uint8 m_forced_speed_changes[MAX_MOVE_TYPE];
bool HasAtLoginFlag(AtLoginFlags f) const { return m_atLoginFlags & f; }
@@ -2623,6 +2620,10 @@ class Player : public Unit, public GridObject<Player>
DeclinedName *m_declinedname;
Runes *m_runes;
EquipmentSets m_EquipmentSets;
+
+ bool canSeeAlways(WorldObject const* obj) const;
+
+ bool isAlwaysDetectableFor(WorldObject const* seer) const;
private:
// internal common parts for CanStore/StoreItem functions
uint8 _CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool swap, Item *pSrcItem) const;
@@ -2673,8 +2674,6 @@ class Player : public Unit, public GridObject<Player>
bool m_bCanDelayTeleport;
bool m_bHasDelayedTeleport;
- uint32 m_DetectInvTimer;
-
// Temporary removed pet cache
uint32 m_temporaryUnsummonedPetNumber;
uint32 m_oldpetspell;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 47b35321847..84ff41a67dd 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -137,11 +137,8 @@ m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this)
m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0;
m_auraUpdateIterator = m_ownedAuras.end();
- m_Visibility = VISIBILITY_ON;
m_interruptMask = 0;
- m_detectInvisibilityMask = 0;
- m_invisibilityMask = 0;
m_transform = 0;
m_ShapeShiftFormSpellId = 0;
m_canModifyStats = false;
@@ -193,6 +190,8 @@ m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this)
m_cleanupDone = false;
m_duringRemoveFromWorld = false;
+
+ m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
}
Unit::~Unit()
@@ -4428,6 +4427,15 @@ bool Unit::HasAuraType(AuraType auraType) const
return (!m_modAuras[auraType].empty());
}
+bool Unit::HasAuraTypeWithCaster(AuraType auratype, uint64 caster) const
+{
+ AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
+ for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
+ if (caster == (*i)->GetCasterGUID())
+ return true;
+ return false;
+}
+
bool Unit::HasAuraTypeWithMiscvalue(AuraType auratype, int32 miscvalue) const
{
AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype);
@@ -11997,14 +12005,6 @@ bool Unit::canAttack(Unit const* target, bool force) const
if (!target->isAttackableByAOE() || target->hasUnitState(UNIT_STAT_DIED))
return false;
- // shaman totem quests: spell 8898, shaman can detect elementals but elementals cannot see shaman
- if (m_invisibilityMask || target->m_invisibilityMask)
- if (!canDetectInvisibilityOf(target) && !target->canDetectInvisibilityOf(this))
- return false;
-
- if (target->GetVisibility() == VISIBILITY_GROUP_STEALTH && !canDetectStealthOf(target, GetDistance(target)))
- return false;
-
if (m_vehicle)
if (IsOnVehicle(target) || m_vehicle->GetBase()->IsOnVehicle(target))
return false;
@@ -12116,98 +12116,36 @@ int32 Unit::ModifyPower(Powers power, int32 dVal)
return gain;
}
-bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList, bool is3dDistance) const
+bool Unit::isAlwaysVisibleFor(WorldObject const* seer) const
{
- if (!u || !IsInMap(u))
- return false;
-
- return u->canSeeOrDetect(this, detect, inVisibleList, is3dDistance);
-}
-
-bool Unit::canSeeOrDetect(Unit const* /*u*/, bool /*detect*/, bool /*inVisibleList*/, bool /*is3dDistance*/) const
-{
- return true;
-}
-
-bool Unit::canDetectInvisibilityOf(Unit const* u) const
-{
- if (m_invisibilityMask & u->m_invisibilityMask) // same group
+ if (WorldObject::isAlwaysVisibleFor(seer))
return true;
- AuraEffectList const& auras = u->GetAuraEffectsByType(SPELL_AURA_MOD_STALKED); // Hunter mark
- for (AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
- if ((*iter)->GetCasterGUID() == GetGUID())
- return true;
-
- if (uint32 mask = (m_detectInvisibilityMask & u->m_invisibilityMask))
- {
- for (uint8 i = 0; i < 10; ++i)
- {
- if (((1 << i) & mask) == 0)
- continue;
-
- // find invisibility level
- uint32 invLevel = 0;
- Unit::AuraEffectList const& iAuras = u->GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY);
- for (Unit::AuraEffectList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
- if (uint8((*itr)->GetMiscValue()) == i && int32(invLevel) < (*itr)->GetAmount())
- invLevel = (*itr)->GetAmount();
- // find invisibility detect level
- uint32 detectLevel = 0;
- if (i == 6 && GetTypeId() == TYPEID_PLAYER) // special drunk detection case
- {
- detectLevel = this->ToPlayer()->GetDrunkValue();
- }
- else
- {
- Unit::AuraEffectList const& dAuras = GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION);
- for (Unit::AuraEffectList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr)
- if (uint8((*itr)->GetMiscValue()) == i && int32(detectLevel) < (*itr)->GetAmount())
- detectLevel = (*itr)->GetAmount();
- }
-
- if (invLevel <= detectLevel)
- return true;
- }
- }
+ // Always seen by owner
+ if (uint64 guid = GetCharmerOrOwnerGUID())
+ if (seer->GetGUID() == guid)
+ return true;
return false;
}
-bool Unit::canDetectStealthOf(Unit const* target, float distance) const
+bool Unit::isAlwaysDetectableFor(WorldObject const* seer) const
{
- if (hasUnitState(UNIT_STAT_STUNNED))
- return false;
- if (distance < 0.24f) //collision
- return true;
- if (!HasInArc(M_PI, target)) //behind
- return false;
- if (HasAuraType(SPELL_AURA_DETECT_STEALTH))
+ if (WorldObject::isAlwaysDetectableFor(seer))
return true;
- AuraEffectList const &auras = target->GetAuraEffectsByType(SPELL_AURA_MOD_STALKED); // Hunter mark
- for (AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
- if ((*iter)->GetCasterGUID() == GetGUID())
- return true;
-
- //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5)
- float visibleDistance = 7.5f;
- //Visible distance is modified by -Level Diff (every level diff = 1.0f in visible distance)
- visibleDistance += float(getLevelForTarget(target)) - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH)/5.0f;
- //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia)
- //based on wowwiki every 5 mod we have 1 more level diff in calculation
- visibleDistance += (float)(GetTotalAuraModifier(SPELL_AURA_MOD_DETECT) - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL)) / 5.0f;
- visibleDistance = visibleDistance > MAX_PLAYER_STEALTH_DETECT_RANGE ? MAX_PLAYER_STEALTH_DETECT_RANGE : visibleDistance;
+ if (HasAuraTypeWithCaster(SPELL_AURA_MOD_STALKED, seer->GetGUID()))
+ return true;
- return distance < visibleDistance;
+ return false;
}
void Unit::SetVisibility(UnitVisibility x)
{
- m_Visibility = x;
-
- if (m_Visibility == VISIBILITY_GROUP_STEALTH)
- DestroyForNearbyPlayers();
+ if (x == VISIBILITY_OFF)
+ m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_GAMEMASTER);
+ else
+ m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER);
UpdateObjectVisibility();
}
@@ -12669,7 +12607,7 @@ Unit* Creature::SelectVictim()
{
--aura;
caster = (*aura)->GetCaster();
- if (caster && caster->IsInMap(this) && canAttack(caster) && caster->isInAccessiblePlaceFor(this->ToCreature()))
+ if (caster && canSeeOrDetect(caster, true) && canAttack(caster) && caster->isInAccessiblePlaceFor(this->ToCreature()))
{
target = caster;
break;
@@ -12742,15 +12680,18 @@ Unit* Creature::SelectVictim()
return target;
}
- if (m_invisibilityMask)
+
+ Unit::AuraEffectList const& iAuras = GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY);
+ if(!iAuras.empty())
{
- Unit::AuraEffectList const& iAuras = GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY);
for (Unit::AuraEffectList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
+ {
if ((*itr)->GetBase()->IsPermanent())
{
AI()->EnterEvadeMode();
break;
}
+ }
return NULL;
}
@@ -13093,11 +13034,6 @@ Creature* Unit::GetCreature(WorldObject& object, uint64 guid)
return object.GetMap()->GetCreature(guid);
}
-bool Unit::isVisibleForInState(Player const* u, bool inVisibleList) const
-{
- return u->canSeeOrDetect(this, false, inVisibleList, false);
-}
-
uint32 Unit::GetCreatureType() const
{
if (GetTypeId() == TYPEID_PLAYER)
@@ -16182,7 +16118,7 @@ void Unit::UpdateObjectVisibility(bool forced)
WorldObject::UpdateObjectVisibility(true);
// call MoveInLineOfSight for nearby creatures
Trinity::AIRelocationNotifier notifier(*this);
- VisitNearbyObject(GetMap()->GetVisibilityDistance(), notifier);
+ VisitNearbyObject(GetVisibilityRange(), notifier);
}
}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 5432568289a..b7f0cc36ba4 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -542,12 +542,8 @@ enum DamageEffectType
enum UnitVisibility
{
- VISIBILITY_OFF = 0, // absolute, not detectable, GM-like, can see all other
- VISIBILITY_ON = 1,
- VISIBILITY_GROUP_STEALTH = 2, // detect chance, seen and can see group members
- //VISIBILITY_GROUP_INVISIBILITY = 3, // invisibility, can see and can be seen only another invisible unit or invisible detection unit, set only if not stealthed, and in checks not used (mask used instead)
- //VISIBILITY_GROUP_NO_DETECT = 4, // state just at stealth apply for update Grid state. Don't remove, otherwise stealth spells will break
- VISIBILITY_RESPAWN = 5 // special totally not detectable visibility for force delete object at respawn command
+ VISIBILITY_OFF = 0,
+ VISIBILITY_ON = 1
};
// Value masks for UNIT_FIELD_FLAGS
@@ -1083,7 +1079,7 @@ enum PlayerTotemType
// delay time next attack to prevent client attack animation problems
#define ATTACK_DISPLAY_DELAY 200
-#define MAX_PLAYER_STEALTH_DETECT_RANGE 45.0f // max distance for detection targets by player
+#define MAX_PLAYER_STEALTH_DETECT_RANGE 30.0f // max distance for detection targets by player
struct SpellProcEventEntry; // used only privately
@@ -1194,7 +1190,7 @@ class Unit : public WorldObject
bool IsVehicle() const { return m_unitTypeMask & UNIT_MASK_VEHICLE; }
uint8 getLevel() const { return uint8(GetUInt32Value(UNIT_FIELD_LEVEL)); }
- virtual uint8 getLevelForTarget(Unit const* /*target*/) const { return getLevel(); }
+ uint8 getLevelForTarget(WorldObject const* /*target*/) const { return getLevel(); }
void SetLevel(uint8 lvl);
uint8 getRace() const { return GetByteValue(UNIT_FIELD_BYTES_0, 0); }
uint32 getRaceMask() const { return 1 << (getRace()-1); }
@@ -1640,6 +1636,7 @@ class Unit : public WorldObject
uint32 GetAuraCount(uint32 spellId) const;
bool HasAura(uint32 spellId, uint64 caster = 0, uint8 reqEffMask = 0) const;
bool HasAuraType(AuraType auraType) const;
+ bool HasAuraTypeWithCaster(AuraType auratype, uint64 caster) const;
bool HasAuraTypeWithMiscvalue(AuraType auratype, int32 miscvalue) const;
bool HasAuraTypeWithAffectMask(AuraType auratype, SpellEntry const * affectedSpell) const;
bool HasAuraTypeWithValue(AuraType auratype, int32 value) const;
@@ -1717,8 +1714,6 @@ class Unit : public WorldObject
uint32 m_addDmgOnce;
uint64 m_SummonSlot[MAX_SUMMON_SLOT];
uint64 m_ObjectSlot[4];
- uint32 m_detectInvisibilityMask;
- uint32 m_invisibilityMask;
uint32 m_ShapeShiftFormSpellId;
ShapeshiftForm m_form;
@@ -1768,22 +1763,16 @@ class Unit : public WorldObject
void SetFacingToObject(WorldObject* pObject);
// Visibility system
- UnitVisibility GetVisibility() const { return m_Visibility; }
+ UnitVisibility GetVisibility() const { return (m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM) > SEC_PLAYER) ? VISIBILITY_OFF : VISIBILITY_ON; }
void SetVisibility(UnitVisibility x);
// common function for visibility checks for player/creatures with detection code
- virtual bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const = 0;
- bool isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const;
- bool canDetectInvisibilityOf(Unit const* u) const;
- bool canDetectStealthOf(Unit const* u, float distance) const;
+
+ bool isValid() const { return WorldObject::isValid(); }
+
void SetPhaseMask(uint32 newPhaseMask, bool update);// overwrite WorldObject::SetPhaseMask
void UpdateObjectVisibility(bool forced = true);
- // virtual functions for all world objects types
- bool isVisibleForInState(Player const* u, bool inVisibleList) const;
- // function for low level grid visibility checks in player/creature cases
- virtual bool IsVisibleInGridForPlayer(Player const* pl) const = 0;
-
SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY];
// Threat related methods
@@ -2074,6 +2063,12 @@ class Unit : public WorldObject
uint32 m_unitTypeMask;
+ bool isAlwaysVisibleFor(WorldObject const* seer) const;
+ bool canSeeAlways(WorldObject const* obj) const { return WorldObject::canSeeAlways(obj); }
+
+ bool isVisibleForInState(WorldObject const* seer) const { return WorldObject::isVisibleForInState(seer); };
+
+ bool isAlwaysDetectableFor(WorldObject const* seer) const;
private:
bool IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry const * procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const *& spellProcEvent);
bool HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
@@ -2104,8 +2099,6 @@ class Unit : public WorldObject
Spell* m_currentSpells[CURRENT_MAX_SPELL];
- UnitVisibility m_Visibility;
-
Diminishing m_Diminishing;
// Manage all Units threatening us
// ThreatManager m_ThreatManager;