aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/AI/CoreAI/GuardAI.cpp2
-rwxr-xr-xsrc/server/game/AI/CoreAI/TotemAI.cpp2
-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
-rwxr-xr-xsrc/server/game/Grids/Notifiers/GridNotifiers.cpp8
-rwxr-xr-xsrc/server/game/Grids/Notifiers/GridNotifiers.h12
-rwxr-xr-xsrc/server/game/Grids/Notifiers/GridNotifiersImpl.h4
-rwxr-xr-xsrc/server/game/Grids/ObjectGridLoader.cpp2
-rwxr-xr-xsrc/server/game/Groups/Group.cpp6
-rwxr-xr-xsrc/server/game/Maps/Map.cpp136
-rwxr-xr-xsrc/server/game/Maps/Map.h4
-rwxr-xr-xsrc/server/game/Miscellaneous/SharedDefines.h40
-rwxr-xr-xsrc/server/game/Spells/Auras/SpellAuraDefines.h6
-rwxr-xr-xsrc/server/game/Spells/Auras/SpellAuraEffects.cpp189
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h7
-rwxr-xr-xsrc/server/game/Spells/Spell.cpp23
-rwxr-xr-xsrc/server/game/Spells/Spell.h2
-rwxr-xr-xsrc/server/game/Spells/SpellEffects.cpp4
-rwxr-xr-xsrc/server/game/World/World.cpp54
-rwxr-xr-xsrc/server/game/World/World.h10
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp41
-rw-r--r--src/server/worldserver/worldserver.conf.dist25
35 files changed, 777 insertions, 790 deletions
diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp
index cc2f21d24c5..b16d23b04f1 100755
--- a/src/server/game/AI/CoreAI/GuardAI.cpp
+++ b/src/server/game/AI/CoreAI/GuardAI.cpp
@@ -125,7 +125,7 @@ void GuardAI::UpdateAI(const uint32 /*diff*/)
bool GuardAI::IsVisible(Unit *pl) const
{
return me->IsWithinDist(pl,sWorld.getFloatConfig(CONFIG_SIGHT_GUARDER))
- && pl->isVisibleForOrDetect(me,true);
+ && me->canSeeOrDetect(pl);
}
void GuardAI::JustDied(Unit *killer)
diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp
index 7110bdc1ad8..c20fb2b249e 100755
--- a/src/server/game/AI/CoreAI/TotemAI.cpp
+++ b/src/server/game/AI/CoreAI/TotemAI.cpp
@@ -77,7 +77,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() || !me->IsWithinDistInMap(victim, max_range) ||
- me->IsFriendlyTo(victim) || !victim->isVisibleForOrDetect(me,false))
+ me->IsFriendlyTo(victim) || !me->canSeeOrDetect(victim))
{
victim = NULL;
Trinity::NearestAttackableUnitInObjectRangeCheck u_check(me, me, max_range);
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;
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
index 663743e2c2e..2bb846c9533 100755
--- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp
@@ -117,7 +117,7 @@ inline void CreatureUnitRelocationWorker(Creature* c, Unit* u)
return;
if (c->HasReactState(REACT_AGGRESSIVE) && !c->hasUnitState(UNIT_STAT_SIGHTLESS))
- if (c->_IsWithinDist(u, c->m_SightDistance, true) && c->IsAIEnabled)
+ if (c->IsAIEnabled && c->canSeeOrDetect(u, false, true))
c->AI()->MoveInLineOfSight_Safe(u);
}
@@ -249,7 +249,7 @@ MessageDistDeliverer::Visit(PlayerMapType &m)
if (!target->InSamePhase(i_phaseMask))
continue;
- if (target->GetExactDistSq(i_source) > i_distSq)
+ if (target->GetExactDist2dSq(i_source) > i_distSq)
continue;
// Send packet to all who are sharing the player's vision
@@ -274,7 +274,7 @@ MessageDistDeliverer::Visit(CreatureMapType &m)
if (!iter->getSource()->InSamePhase(i_phaseMask))
continue;
- if (iter->getSource()->GetExactDistSq(i_source) > i_distSq)
+ if (iter->getSource()->GetExactDist2dSq(i_source) > i_distSq)
continue;
// Send packet to all who are sharing the creature's vision
@@ -296,7 +296,7 @@ MessageDistDeliverer::Visit(DynamicObjectMapType &m)
if (!iter->getSource()->InSamePhase(i_phaseMask))
continue;
- if (iter->getSource()->GetExactDistSq(i_source) > i_distSq)
+ if (iter->getSource()->GetExactDist2dSq(i_source) > i_distSq)
continue;
if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID()))
diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h
index 10f9e90b63e..f0a6337ec52 100755
--- a/src/server/game/Grids/Notifiers/GridNotifiers.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiers.h
@@ -143,6 +143,9 @@ namespace Trinity
if (plr == i_source || (team && plr->GetTeam() != team) || skipped_receiver == plr)
return;
+ if (!plr->HaveAtClient(i_source))
+ return;
+
plr->GetSession()->SendPacket(i_message);
}
};
@@ -809,7 +812,7 @@ namespace Trinity
return u->isAlive()
&& i_obj->IsWithinDistInMap(u, i_range)
&& !i_funit->IsFriendlyTo(u)
- && u->isVisibleForOrDetect(i_funit, false);
+ && u->canSeeOrDetect(i_funit);
}
private:
WorldObject const* i_obj;
@@ -871,7 +874,7 @@ namespace Trinity
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->canSeeOrDetect(i_funit))
{
i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check
return true;
@@ -957,10 +960,12 @@ namespace Trinity
bool operator()(Unit* u) { return !u->isAlive(); }
};
+ /*
struct AnyStealthedCheck
{
bool operator()(Unit* u) { return u->GetVisibility() == VISIBILITY_GROUP_STEALTH; }
};
+ */
// Creature checks
@@ -1002,6 +1007,9 @@ namespace Trinity
if (!me->IsWithinDistInMap(u, m_range))
return false;
+ if (!me->canSeeOrDetect(u))
+ return false;
+
if (m_force)
{
if (!me->canAttack(u))
diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
index ad84384b0f9..9f2ff9be790 100755
--- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
+++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h
@@ -42,8 +42,8 @@ Trinity::VisibleNotifier::Visit(GridRefManager<T> &m)
inline void
Trinity::ObjectUpdater::Visit(CreatureMapType &m)
{
- for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
- if (iter->getSource()->IsInWorld() && !iter->getSource()->isSpiritService())
+ for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
+ if (iter->getSource()->IsInWorld())
iter->getSource()->Update(i_timeDiff);
}
diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp
index 604bb57b758..4ee7fd69f76 100755
--- a/src/server/game/Grids/ObjectGridLoader.cpp
+++ b/src/server/game/Grids/ObjectGridLoader.cpp
@@ -103,8 +103,6 @@ template<> void addUnitState(Creature *obj, CellPair const& cell_pair)
Cell cell(cell_pair);
obj->SetCurrentCell(cell);
- if (obj->isSpiritService())
- obj->setDeathState(DEAD);
}
template <class T>
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 54a4779e06f..11561e9341a 100755
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1147,9 +1147,9 @@ void Group::UpdatePlayerOutOfRange(Player* pPlayer)
for (GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{
- player = itr->getSource();
- if (player && player != pPlayer && !pPlayer->isVisibleFor(player))
- player->GetSession()->SendPacket(&data);
+ if (player = itr->getSource())
+ if (!player->canSeeOrDetect(pPlayer))
+ player->GetSession()->SendPacket(&data);
}
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index fc2b5ecb080..184e85b6c04 100755
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -415,7 +415,7 @@ bool Map::Add(Player *player)
SendInitTransports(player);
player->m_clientGUIDs.clear();
- player->UpdateObjectVisibility(true);
+ player->UpdateObjectVisibility(false);
sScriptMgr.OnPlayerEnterMap(this, player);
return true;
@@ -466,16 +466,43 @@ bool Map::loaded(const GridPair &p) const
return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord));
}
-void Map::Update(const uint32 &t_diff)
+void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Trinity::ObjectUpdater, GridTypeMapContainer> &gridVisitor, TypeContainerVisitor<Trinity::ObjectUpdater, WorldTypeMapContainer> &worldVisitor)
{
- /// update players at tick
- for (m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
+ CellPair standing_cell(Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));
+
+ // Check for correctness of standing_cell, it also avoids problems with update_cell
+ if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+ return;
+
+ // the overloaded operators handle range checking
+ // so there's no need for range checking inside the loop
+ CellPair begin_cell(standing_cell), end_cell(standing_cell);
+ //lets update mobs/objects in ALL visible cells around object!
+ CellArea area = Cell::CalculateCellArea(*obj, obj->GetGridActivationRange());
+ area.ResizeBorders(begin_cell, end_cell);
+
+ for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
{
- Player* plr = m_mapRefIter->getSource();
- if (plr && plr->IsInWorld())
- plr->Update(t_diff);
+ for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
+ {
+ // marked cells are those that have been visited
+ // don't visit the same cell twice
+ uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+ if (isCellMarked(cell_id))
+ continue;
+
+ markCell(cell_id);
+ CellPair pair(x,y);
+ Cell cell(pair);
+ cell.data.Part.reserved = CENTER_DISTRICT;
+ cell.Visit(pair, gridVisitor, *this);
+ cell.Visit(pair, worldVisitor, *this);
+ }
}
+}
+void Map::Update(const uint32 &t_diff)
+{
/// update active cells around players and active objects
resetMarkedCells();
@@ -494,87 +521,22 @@ void Map::Update(const uint32 &t_diff)
if (!plr->IsInWorld())
continue;
- CellPair standing_cell(Trinity::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY()));
-
- // Check for correctness of standing_cell, it also avoids problems with update_cell
- if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
- continue;
-
- // the overloaded operators handle range checking
- // so ther's no need for range checking inside the loop
- CellPair begin_cell(standing_cell), end_cell(standing_cell);
- //lets update mobs/objects in ALL visible cells around player!
- CellArea area = Cell::CalculateCellArea(*plr, GetVisibilityDistance());
- area.ResizeBorders(begin_cell, end_cell);
+ // update players at tick
+ plr->Update(t_diff);
- for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
- {
- for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
- {
- // marked cells are those that have been visited
- // don't visit the same cell twice
- uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
- if (!isCellMarked(cell_id))
- {
- markCell(cell_id);
- CellPair pair(x,y);
- Cell cell(pair);
- cell.data.Part.reserved = CENTER_DISTRICT;
- //cell.SetNoCreate();
- cell.Visit(pair, grid_object_update, *this);
- cell.Visit(pair, world_object_update, *this);
- }
- }
- }
+ VisitNearbyCellsOf(plr, grid_object_update, world_object_update);
}
- // non-player active objects
- if (!m_activeNonPlayers.empty())
+ // non-player active objects, increasing iterator in the loop in case of object removal
+ for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();)
{
- for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();)
- {
- // skip not in world
- WorldObject* obj = *m_activeNonPlayersIter;
-
- // step before processing, in this case if Map::Remove remove next object we correctly
- // step to next-next, and if we step to end() then newly added objects can wait next update.
- ++m_activeNonPlayersIter;
-
- if (!obj->IsInWorld())
- continue;
-
- CellPair standing_cell(Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));
+ WorldObject* obj = *m_activeNonPlayersIter;
+ ++m_activeNonPlayersIter;
- // Check for correctness of standing_cell, it also avoids problems with update_cell
- if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
- continue;
-
- // the overloaded operators handle range checking
- // so ther's no need for range checking inside the loop
- CellPair begin_cell(standing_cell), end_cell(standing_cell);
- begin_cell << 1; begin_cell -= 1; // upper left
- end_cell >> 1; end_cell += 1; // lower right
+ if (!obj->IsInWorld())
+ continue;
- for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
- {
- for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
- {
- // marked cells are those that have been visited
- // don't visit the same cell twice
- uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
- if (!isCellMarked(cell_id))
- {
- markCell(cell_id);
- CellPair pair(x,y);
- Cell cell(pair);
- cell.data.Part.reserved = CENTER_DISTRICT;
- //cell.SetNoCreate();
- cell.Visit(pair, grid_object_update, *this);
- cell.Visit(pair, world_object_update, *this);
- }
- }
- }
- }
+ VisitNearbyCellsOf(obj, grid_object_update, world_object_update);
}
///- Process necessary scripts
@@ -635,7 +597,7 @@ void Map::ProcessRelocationNotifies(const uint32 & diff)
Cell cell(pair);
cell.SetNoCreate();
- Trinity::DelayedUnitRelocation cell_relocation(cell, pair, *this, GetVisibilityDistance());
+ Trinity::DelayedUnitRelocation cell_relocation(cell, pair, *this, MAX_VISIBILITY_DISTANCE);
TypeContainerVisitor<Trinity::DelayedUnitRelocation, GridTypeMapContainer > grid_object_relocation(cell_relocation);
TypeContainerVisitor<Trinity::DelayedUnitRelocation, WorldTypeMapContainer > world_object_relocation(cell_relocation);
Visit(cell, grid_object_relocation);
@@ -1881,7 +1843,7 @@ void Map::UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair)
cell.SetNoCreate();
Trinity::VisibleChangesNotifier notifier(*obj);
TypeContainerVisitor<Trinity::VisibleChangesNotifier, WorldTypeMapContainer > player_notifier(notifier);
- cell.Visit(cellpair, player_notifier, *this, *obj, GetVisibilityDistance());
+ cell.Visit(cellpair, player_notifier, *this, *obj, obj->GetVisibilityRange());
}
void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair)
@@ -1892,8 +1854,8 @@ void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpai
cell.SetNoCreate();
TypeContainerVisitor<Trinity::VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier);
TypeContainerVisitor<Trinity::VisibleNotifier, GridTypeMapContainer > grid_notifier(notifier);
- cell.Visit(cellpair, world_notifier, *this, *player, GetVisibilityDistance());
- cell.Visit(cellpair, grid_notifier, *this, *player, GetVisibilityDistance());
+ cell.Visit(cellpair, world_notifier, *this, *player, player->GetVisibilityRange());
+ cell.Visit(cellpair, grid_notifier, *this, *player, player->GetVisibilityRange());
// send data
notifier.SendToSelf();
@@ -2117,7 +2079,7 @@ bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const
CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
//we must find visible range in cells so we unload only non-visible cells...
- float viewDist = GetVisibilityDistance();
+ float viewDist = GetVisibilityRange();
int cell_range = (int)ceilf(viewDist / SIZE_OF_GRID_CELL) + 1;
cell_min << cell_range;
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 534115e7e0d..0bff446b67d 100755
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -50,6 +50,7 @@ struct Position;
class Battleground;
class MapInstanced;
class InstanceMap;
+namespace Trinity { struct ObjectUpdater; }
struct ScriptAction
{
@@ -269,9 +270,10 @@ class Map : public GridRefManager<NGridType>
template<class T> void Add(T *);
template<class T> void Remove(T *, bool);
+ void VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Trinity::ObjectUpdater, GridTypeMapContainer> &gridVisitor, TypeContainerVisitor<Trinity::ObjectUpdater, WorldTypeMapContainer> &worldVisitor);
virtual void Update(const uint32&);
- float GetVisibilityDistance() const { return m_VisibleDistance; }
+ float GetVisibilityRange() const { return m_VisibleDistance; }
//function for setting up visibility distance for maps on per-type/per-Id basis
virtual void InitVisibilityDistance();
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 0e87bd388e9..859b7ad4aaf 100755
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -980,6 +980,46 @@ enum SpellCastResult
SPELL_CAST_OK = 255 // custom value, don't must be send to client
};
+enum StealthType
+{
+ STEALTH_GENERAL = 0,
+ STEALTH_TRAP = 1,
+
+ TOTAL_STEALTH_TYPES = 2
+};
+
+enum InvisibilityType
+{
+ INVISIBILITY_GENERAL = 0,
+ INVISIBILITY_UNK1 = 1,
+ INVISIBILITY_UNK2 = 2,
+ INVISIBILITY_TRAP = 3,
+ INVISIBILITY_UNK4 = 4,
+ INVISIBILITY_UNK5 = 5,
+ INVISIBILITY_DRUNK = 6,
+ INVISIBILITY_UNK7 = 7,
+ INVISIBILITY_UNK8 = 8,
+ INVISIBILITY_UNK9 = 9,
+ INVISIBILITY_UNK10 = 10,
+ INVISIBILITY_UNK11 = 11,
+
+ TOTAL_INVISIBILITY_TYPES = 12
+};
+
+enum ServerSideVisibilityType
+{
+ SERVERSIDE_VISIBILITY_GM = 0,
+ SERVERSIDE_VISIBILITY_GHOST = 1,
+
+ TOTAL_SERVERSIDE_VISIBILITY_TYPES = 2
+};
+
+enum GhostVisibilityType
+{
+ GHOST_VISIBILITY_ALIVE = 0x1,
+ GHOST_VISIBILITY_GHOST = 0x2
+};
+
// Spell aura states
enum AuraState
{ // (C) used in caster aura state (T) used in target aura state
diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h
index aedb4d2c303..e23906b355e 100755
--- a/src/server/game/Spells/Auras/SpellAuraDefines.h
+++ b/src/server/game/Spells/Auras/SpellAuraDefines.h
@@ -71,9 +71,9 @@ enum AuraType
SPELL_AURA_MOD_DAMAGE_TAKEN = 14,
SPELL_AURA_DAMAGE_SHIELD = 15,
SPELL_AURA_MOD_STEALTH = 16,
- SPELL_AURA_MOD_DETECT = 17,
+ SPELL_AURA_MOD_STEALTH_DETECT = 17,
SPELL_AURA_MOD_INVISIBILITY = 18,
- SPELL_AURA_MOD_INVISIBILITY_DETECTION = 19,
+ SPELL_AURA_MOD_INVISIBILITY_DETECT = 19,
SPELL_AURA_OBS_MOD_HEALTH = 20, //20,21 unofficial
SPELL_AURA_OBS_MOD_POWER = 21,
SPELL_AURA_MOD_RESISTANCE = 22,
@@ -358,7 +358,7 @@ enum AuraType
SPELL_AURA_SCHOOL_HEAL_ABSORB = 301,
SPELL_AURA_302 = 302,
SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE = 303,
- SPELL_AURA_304 = 304,
+ SPELL_AURA_MOD_FAKE_INEBRIATE = 304,
SPELL_AURA_MOD_MINIMUM_SPEED = 305,
SPELL_AURA_306 = 306,
SPELL_AURA_HEAL_ABSORB_TEST = 307,
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 40f8f10c8f1..796a26f6fc8 100755
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -69,9 +69,9 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNoImmediateEffect, // 14 SPELL_AURA_MOD_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
&AuraEffect::HandleNoImmediateEffect, // 15 SPELL_AURA_DAMAGE_SHIELD implemented in Unit::DoAttackDamage
&AuraEffect::HandleModStealth, // 16 SPELL_AURA_MOD_STEALTH
- &AuraEffect::HandleNoImmediateEffect, // 17 SPELL_AURA_MOD_DETECT implement in GameObject::canDetectTrap and Unit::canDetectStealthOf
- &AuraEffect::HandleInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY
- &AuraEffect::HandleInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION
+ &AuraEffect::HandleModStealthDetect, // 17 SPELL_AURA_MOD_DETECT
+ &AuraEffect::HandleModInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY
+ &AuraEffect::HandleModInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION
&AuraEffect::HandleNoImmediateEffect, // 20 SPELL_AURA_OBS_MOD_HEALTH implemented in AuraEffect::PeriodicTick
&AuraEffect::HandleNoImmediateEffect, // 21 SPELL_AURA_OBS_MOD_POWER implemented in AuraEffect::PeriodicTick
&AuraEffect::HandleAuraModResistance, // 22 SPELL_AURA_MOD_RESISTANCE
@@ -206,7 +206,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED
&AuraEffect::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance
&AuraEffect::HandleNoImmediateEffect, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT
- &AuraEffect::HandleNoImmediateEffect, //154 SPELL_AURA_MOD_STEALTH_LEVEL
+ &AuraEffect::HandleModStealthLevel, //154 SPELL_AURA_MOD_STEALTH_LEVEL
&AuraEffect::HandleNoImmediateEffect, //155 SPELL_AURA_MOD_WATER_BREATHING
&AuraEffect::HandleNoImmediateEffect, //156 SPELL_AURA_MOD_REPUTATION_GAIN
&AuraEffect::HandleNULL, //157 SPELL_AURA_PET_DAMAGE_MULTI
@@ -356,7 +356,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNoImmediateEffect, //301 SPELL_AURA_SCHOOL_HEAL_ABSORB implemented in Unit::CalcHealAbsorb
&AuraEffect::HandleNULL, //302 0 spells in 3.3.5
&AuraEffect::HandleNoImmediateEffect, //303 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus
- &AuraEffect::HandleUnused, //304 clientside
+ &AuraEffect::HandleAuraModFakeInebriation, //304 SPELL_AURA_MOD_DRUNK
&AuraEffect::HandleAuraModIncreaseSpeed, //305 SPELL_AURA_MOD_MINIMUM_SPEED
&AuraEffect::HandleNULL, //306 0 spells in 3.3.5
&AuraEffect::HandleNULL, //307 0 spells in 3.3.5
@@ -2685,40 +2685,40 @@ void AuraEffect::HandleShapeshiftBoosts(Unit * target, bool apply) const
/*** VISIBILITY & PHASES ***/
/**************************************/
-void AuraEffect::HandleInvisibilityDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const
+void AuraEffect::HandleModInvisibilityDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const
{
if (!(mode & AURA_EFFECT_HANDLE_REAL))
return;
Unit * target = aurApp->GetTarget();
+ InvisibilityType type = InvisibilityType(GetMiscValue());
if (apply)
{
- target->m_detectInvisibilityMask |= (1 << GetMiscValue());
+ target->m_invisibilityDetect.AddFlag(type);
+ target->m_invisibilityDetect.AddValue(type, GetAmount());
}
else
{
- // recalculate value at modifier remove (current aura already removed)
- target->m_detectInvisibilityMask = 0;
- Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION);
- for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- target->m_detectInvisibilityMask |= (1 << GetMiscValue());
+ if (!target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY_DETECT))
+ target->m_invisibilityDetect.DelFlag(type);
+
+ target->m_invisibilityDetect.AddValue(type, -GetAmount());
}
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->UpdateObjectVisibility();
+
+ target->UpdateObjectVisibility();
}
-void AuraEffect::HandleInvisibility(AuraApplication const * aurApp, uint8 mode, bool apply) const
+void AuraEffect::HandleModInvisibility(AuraApplication const * aurApp, uint8 mode, bool apply) const
{
if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK))
return;
Unit * target = aurApp->GetTarget();
+ InvisibilityType type = InvisibilityType(GetMiscValue());
if (apply)
{
- target->m_invisibilityMask |= (1 << GetMiscValue());
-
if (mode & AURA_EFFECT_HANDLE_REAL)
{
// drop flag at invisibiliy in bg
@@ -2729,23 +2729,49 @@ void AuraEffect::HandleInvisibility(AuraApplication const * aurApp, uint8 mode,
if (target->GetTypeId() == TYPEID_PLAYER)
target->SetFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
- target->UpdateObjectVisibility();
+ target->m_invisibility.AddFlag(type);
+ target->m_invisibility.AddValue(type, GetAmount());
+ }
+ else
+ {
+ if (!target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY))
+ {
+ // if not have different invisibility auras.
+ // remove glow vision
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ target->RemoveFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
+
+ target->m_invisibility.DelFlag(type);
+ }
+
+ target->m_invisibility.AddValue(type, -GetAmount());
+ }
+
+ target->UpdateObjectVisibility();
+}
+
+void AuraEffect::HandleModStealthDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const
+{
+ if (!(mode & AURA_EFFECT_HANDLE_REAL))
+ return;
+
+ Unit * target = aurApp->GetTarget();
+ StealthType type = StealthType(GetMiscValue());
+
+ if (apply)
+ {
+ target->m_stealthDetect.AddFlag(type);
+ target->m_stealthDetect.AddValue(type, GetAmount());
}
else
{
- // recalculate value at modifier remove (current aura already removed)
- target->m_invisibilityMask = 0;
- Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY);
- for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- target->m_invisibilityMask |= (1 << GetMiscValue());
-
- // if not have different invisibility auras.
- // remove glow vision
- if (!target->m_invisibilityMask && target->GetTypeId() == TYPEID_PLAYER)
- target->RemoveFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
-
- target->UpdateObjectVisibility();
+ if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH_DETECT))
+ target->m_stealthDetect.DelFlag(type);
+
+ target->m_stealthDetect.AddValue(type, -GetAmount());
}
+
+ target->UpdateObjectVisibility();
}
void AuraEffect::HandleModStealth(AuraApplication const * aurApp, uint8 mode, bool apply) const
@@ -2754,6 +2780,7 @@ void AuraEffect::HandleModStealth(AuraApplication const * aurApp, uint8 mode, bo
return;
Unit * target = aurApp->GetTarget();
+ StealthType type = StealthType(GetMiscValue());
if (apply)
{
@@ -2763,23 +2790,44 @@ void AuraEffect::HandleModStealth(AuraApplication const * aurApp, uint8 mode, bo
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
}
+ target->m_stealth.AddFlag( type);
+ target->m_stealth.AddValue(type, GetAmount());
+
target->SetStandFlags(UNIT_STAND_FLAGS_CREEP);
if (target->GetTypeId() == TYPEID_PLAYER)
target->SetFlag(PLAYER_FIELD_BYTES2, 0x2000);
-
- // apply only if not in GM invisibility (and overwrite invisibility state)
- if (target->GetVisibility() != VISIBILITY_OFF)
- target->SetVisibility(VISIBILITY_GROUP_STEALTH);
}
- else if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) // if last SPELL_AURA_MOD_STEALTH
+ else
{
- target->RemoveStandFlags(UNIT_STAND_FLAGS_CREEP);
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->RemoveFlag(PLAYER_FIELD_BYTES2, 0x2000);
+ target->m_stealth.AddValue(type, -GetAmount());
- if (target->GetVisibility() != VISIBILITY_OFF)
- target->SetVisibility(VISIBILITY_ON);
+ if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) // if last SPELL_AURA_MOD_STEALTH
+ {
+ target->m_stealth.DelFlag(type);
+
+ target->RemoveStandFlags(UNIT_STAND_FLAGS_CREEP);
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ target->RemoveFlag(PLAYER_FIELD_BYTES2, 0x2000);
+ }
}
+
+ target->UpdateObjectVisibility();
+}
+
+void AuraEffect::HandleModStealthLevel(AuraApplication const * aurApp, uint8 mode, bool apply) const
+{
+ if (!(mode & AURA_EFFECT_HANDLE_REAL))
+ return;
+
+ Unit * target = aurApp->GetTarget();
+ StealthType type = StealthType(GetMiscValue());
+
+ if (apply)
+ target->m_stealth.AddValue(type, GetAmount());
+ else
+ target->m_stealth.AddValue(type, -GetAmount());
+
+ target->UpdateObjectVisibility();
}
void AuraEffect::HandleSpiritOfRedemption(AuraApplication const * aurApp, uint8 mode, bool apply) const
@@ -2823,12 +2871,19 @@ void AuraEffect::HandleAuraGhost(AuraApplication const * aurApp, uint8 mode, boo
return;
if (apply)
+ {
target->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST);
+ target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST);
+ target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST);
+ }
else
{
if (target->HasAuraType(SPELL_AURA_GHOST))
return;
+
target->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST);
+ target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
+ target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
}
}
@@ -3315,9 +3370,9 @@ void AuraEffect::HandleFeignDeath(AuraApplication const * aurApp, uint8 mode, bo
*/
UnitList targets;
- Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetMap()->GetVisibilityDistance());
+ Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetMap()->GetVisibilityRange());
Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, targets, u_check);
- target->VisitNearbyObject(target->GetMap()->GetVisibilityDistance(), searcher);
+ target->VisitNearbyObject(target->GetMap()->GetVisibilityRange(), searcher);
for (UnitList::iterator iter = targets.begin(); iter != targets.end(); ++iter)
{
if (!(*iter)->hasUnitState(UNIT_STAT_CASTING))
@@ -3601,11 +3656,11 @@ void AuraEffect::HandleAuraModStalked(AuraApplication const * aurApp, uint8 mode
else
{
// do not remove unit flag if there are more than this auraEffect of that kind on unit on unit
- if (target->HasAuraType(GetAuraType()))
- return;
-
- target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT);
+ if (!target->HasAuraType(GetAuraType()))
+ target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT);
}
+
+ target->UpdateObjectVisibility();
}
void AuraEffect::HandleAuraUntrackable(AuraApplication const * aurApp, uint8 mode, bool apply) const
@@ -4022,7 +4077,7 @@ void AuraEffect::HandleModPossessPet(AuraApplication const * aurApp, uint8 mode,
{
pet->RemoveCharmedBy(caster);
- if (!pet->IsWithinDistInMap(caster, pet->GetMap()->GetVisibilityDistance()))
+ if (!pet->IsWithinDistInMap(caster, pet->GetMap()->GetVisibilityRange()))
pet->Remove(PET_SAVE_NOT_IN_SLOT, true);
else
{
@@ -6349,6 +6404,46 @@ void AuraEffect::HandleAuraOpenStable(AuraApplication const * aurApp, uint8 mode
// client auto close stable dialog at !apply aura
}
+void AuraEffect::HandleAuraModFakeInebriation(AuraApplication const * aurApp, uint8 mode, bool apply) const
+{
+ if (!(mode & AURA_EFFECT_HANDLE_REAL))
+ return;
+
+ Unit* target = aurApp->GetTarget();
+
+ if (apply)
+ {
+ target->m_invisibilityDetect.AddFlag( INVISIBILITY_DRUNK);
+ target->m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, GetAmount());
+
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ {
+ int32 oldval = target->ToPlayer()->GetInt32Value(PLAYER_FAKE_INEBRIATION);
+ target->ToPlayer()->SetInt32Value(PLAYER_FAKE_INEBRIATION, oldval + GetAmount());
+ }
+ }
+ else
+ {
+ bool removeDetect = !target->HasAuraType(SPELL_AURA_MOD_FAKE_INEBRIATE);
+
+ target->m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, -GetAmount());
+
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ {
+ int32 oldval = target->ToPlayer()->GetInt32Value(PLAYER_FAKE_INEBRIATION);
+ target->ToPlayer()->SetInt32Value(PLAYER_FAKE_INEBRIATION, oldval - GetAmount());
+
+ if (removeDetect)
+ removeDetect = !target->ToPlayer()->GetDrunkValue();
+ }
+
+ if (removeDetect)
+ target->m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK);
+ }
+
+ target->UpdateObjectVisibility();
+}
+
void AuraEffect::HandleAuraSetVehicle(AuraApplication const * aurApp, uint8 mode, bool apply) const
{
if (!(mode & AURA_EFFECT_HANDLE_REAL))
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h
index 0673bee0185..3612d9ad6be 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.h
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.h
@@ -108,9 +108,11 @@ class AuraEffect
// aura type not have immediate effect at add/remove and handled by ID in other code place
}
// visibility & phases
- void HandleInvisibilityDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const;
- void HandleInvisibility(AuraApplication const * aurApp, uint8 mode, bool apply) const;
+ void HandleModInvisibilityDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const;
+ void HandleModInvisibility(AuraApplication const * aurApp, uint8 mode, bool apply) const;
void HandleModStealth(AuraApplication const * aurApp, uint8 mode, bool apply) const;
+ void HandleModStealthLevel(AuraApplication const * aurApp, uint8 mode, bool apply) const;
+ void HandleModStealthDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const;
void HandleSpiritOfRedemption(AuraApplication const * aurApp, uint8 mode, bool apply) const;
void HandleAuraGhost(AuraApplication const * aurApp, uint8 mode, bool apply) const;
void HandlePhase(AuraApplication const * aurApp, uint8 mode, bool apply) const;
@@ -257,6 +259,7 @@ class AuraEffect
void HandleAuraLinked(AuraApplication const * aurApp, uint8 mode, bool apply) const;
void HandleAuraOpenStable(AuraApplication const * aurApp, uint8 mode, bool apply) const;
void HandleAuraSetVehicle(AuraApplication const * aurApp, uint8 mode, bool apply) const;
+ void HandleAuraModFakeInebriation(AuraApplication const * aurApp, uint8 mode, bool apply) const;
};
#endif \ No newline at end of file
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 53514bd622e..f912a6f20b5 100755
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1396,18 +1396,6 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool
if (!m_caster->IsFriendlyTo(unit))
{
- // reset damage to 0 if target has Invisibility and isn't visible for caster
- // I do not think this is a correct way to fix it. Sanctuary effect should make all delayed spells invalid
- // for delayed spells ignore not visible explicit target
- if (m_spellInfo->speed > 0.0f && unit == m_targets.getUnitTarget()
- && (unit->m_invisibilityMask || m_caster->m_invisibilityMask)
- && !m_caster->canSeeOrDetect(unit, true))
- {
- // that was causing CombatLog errors
- // return SPELL_MISS_EVADE;
- return SPELL_MISS_MISS; // miss = do not send anything here
- }
-
unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL);
//TODO: This is a hack. But we do not know what types of stealth should be interrupted by CC
if ((m_customAttr & SPELL_ATTR_CU_AURA_CC) && unit->IsControlledByPlayer())
@@ -1793,7 +1781,7 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin
break;
while ((m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE
&& !m_caster->isInFrontInMap(*next, max_range))
- || !m_caster->canSeeOrDetect(*next, false)
+ || !m_caster->canSeeOrDetect(*next)
|| !cur->IsWithinLOSInMap(*next))
{
++next;
@@ -3118,9 +3106,7 @@ void Spell::cast(bool skipCheck)
{
// three check: prepare, cast (m_casttime > 0), hit (delayed)
if (m_casttime && target->isAlive()
- && (target->m_invisibilityMask || m_caster->m_invisibilityMask
- || target->GetVisibility() == VISIBILITY_GROUP_STEALTH)
- && !target->IsFriendlyTo(m_caster) && !m_caster->canSeeOrDetect(target, true))
+ && !target->IsFriendlyTo(m_caster) && !m_caster->canSeeOrDetect(target))
{
SendCastResult(SPELL_FAILED_BAD_TARGETS);
SendInterrupted(0);
@@ -4846,8 +4832,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (target->hasUnitState(UNIT_STAT_UNATTACKABLE))
return SPELL_FAILED_BAD_TARGETS;
- if (!m_IsTriggeredSpell && (target->HasAuraType(SPELL_AURA_MOD_STEALTH)
- || target->m_invisibilityMask) && !m_caster->canSeeOrDetect(target, true))
+ if (!m_IsTriggeredSpell && !m_caster->canSeeOrDetect(target))
return SPELL_FAILED_BAD_TARGETS;
if (m_caster->GetTypeId() == TYPEID_PLAYER)
@@ -6014,7 +5999,7 @@ SpellCastResult Spell::CheckItems()
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck>, GridTypeMapContainer > object_checker(checker);
Map& map = *m_caster->GetMap();
- cell.Visit(p, object_checker, map, *m_caster, map.GetVisibilityDistance());
+ cell.Visit(p, object_checker, map, *m_caster, m_caster->GetVisibilityRange());
if (!ok)
return SPELL_FAILED_REQUIRES_SPELL_FOCUS;
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 2a74e21f817..e7edb82a4c7 100755
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -752,7 +752,7 @@ namespace Trinity
{
Unit *target = (Unit*)itr->getSource();
- if (!target->InSamePhase(i_source))
+ if (!i_source->canSeeOrDetect(target, true))
continue;
switch (i_TargetType)
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index b0e7557a0ed..b2fc0ec4032 100755
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -5327,9 +5327,9 @@ void Spell::EffectSanctuary(SpellEffIndex /*effIndex*/)
return;
std::list<Unit*> targets;
- Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, m_caster->GetMap()->GetVisibilityDistance());
+ Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, m_caster->GetMap()->GetVisibilityRange());
Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(unitTarget, targets, u_check);
- unitTarget->VisitNearbyObject(m_caster->GetMap()->GetVisibilityDistance(), searcher);
+ unitTarget->VisitNearbyObject(m_caster->GetMap()->GetVisibilityRange(), searcher);
for (std::list<Unit*>::iterator iter = targets.begin(); iter != targets.end(); ++iter)
{
if (!(*iter)->hasUnitState(UNIT_STAT_CASTING))
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 2c7790de35c..30fd869def1 100755
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -79,11 +79,6 @@ volatile uint32 World::m_worldLoopCounter = 0;
float World::m_MaxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE;
float World::m_MaxVisibleDistanceInInstances = DEFAULT_VISIBILITY_INSTANCE;
float World::m_MaxVisibleDistanceInBGArenas = DEFAULT_VISIBILITY_BGARENAS;
-float World::m_MaxVisibleDistanceForObject = DEFAULT_VISIBILITY_DISTANCE;
-
-float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE;
-float World::m_VisibleUnitGreyDistance = 0;
-float World::m_VisibleObjectGreyDistance = 0;
int32 World::m_visibility_notify_periodOnContinents = DEFAULT_VISIBILITY_NOTIFY_PERIOD;
int32 World::m_visibility_notify_periodInInstances = DEFAULT_VISIBILITY_NOTIFY_PERIOD;
@@ -1057,19 +1052,6 @@ void World::LoadConfigSettings(bool reload)
if (m_int_configs[CONFIG_GUILD_BANK_EVENT_LOG_COUNT] < GUILD_BANKLOG_MAX_RECORDS)
m_int_configs[CONFIG_GUILD_BANK_EVENT_LOG_COUNT] = GUILD_BANKLOG_MAX_RECORDS;
- m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
- if (m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
- {
- sLog.outError("Visibility.Distance.Grey.Unit can't be greater %f",MAX_VISIBILITY_DISTANCE);
- m_VisibleUnitGreyDistance = MAX_VISIBILITY_DISTANCE;
- }
- m_VisibleObjectGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Object", 10);
- if (m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
- {
- sLog.outError("Visibility.Distance.Grey.Object can't be greater %f",MAX_VISIBILITY_DISTANCE);
- m_VisibleObjectGreyDistance = MAX_VISIBILITY_DISTANCE;
- }
-
//visibility on continents
m_MaxVisibleDistanceOnContinents = sConfig.GetFloatDefault("Visibility.Distance.Continents", DEFAULT_VISIBILITY_DISTANCE);
if (m_MaxVisibleDistanceOnContinents < 45*sWorld.getRate(RATE_CREATURE_AGGRO))
@@ -1077,10 +1059,10 @@ void World::LoadConfigSettings(bool reload)
sLog.outError("Visibility.Distance.Continents can't be less max aggro radius %f", 45*sWorld.getRate(RATE_CREATURE_AGGRO));
m_MaxVisibleDistanceOnContinents = 45*sWorld.getRate(RATE_CREATURE_AGGRO);
}
- else if (m_MaxVisibleDistanceOnContinents + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
+ else if (m_MaxVisibleDistanceOnContinents > MAX_VISIBILITY_DISTANCE)
{
- sLog.outError("Visibility.Distance.Continents can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
- m_MaxVisibleDistanceOnContinents = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
+ sLog.outError("Visibility.Distance.Continents can't be greater %f",MAX_VISIBILITY_DISTANCE);
+ m_MaxVisibleDistanceOnContinents = MAX_VISIBILITY_DISTANCE;
}
//visibility in instances
@@ -1090,10 +1072,10 @@ void World::LoadConfigSettings(bool reload)
sLog.outError("Visibility.Distance.Instances can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO));
m_MaxVisibleDistanceInInstances = 45*sWorld.getRate(RATE_CREATURE_AGGRO);
}
- else if (m_MaxVisibleDistanceInInstances + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
+ else if (m_MaxVisibleDistanceInInstances > MAX_VISIBILITY_DISTANCE)
{
- sLog.outError("Visibility.Distance.Instances can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
- m_MaxVisibleDistanceInInstances = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
+ sLog.outError("Visibility.Distance.Instances can't be greater %f",MAX_VISIBILITY_DISTANCE);
+ m_MaxVisibleDistanceInInstances = MAX_VISIBILITY_DISTANCE;
}
//visibility in BG/Arenas
@@ -1103,28 +1085,10 @@ void World::LoadConfigSettings(bool reload)
sLog.outError("Visibility.Distance.BGArenas can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO));
m_MaxVisibleDistanceInBGArenas = 45*sWorld.getRate(RATE_CREATURE_AGGRO);
}
- else if (m_MaxVisibleDistanceInBGArenas + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
- {
- sLog.outError("Visibility.Distance.BGArenas can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
- m_MaxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
- }
-
- m_MaxVisibleDistanceForObject = sConfig.GetFloatDefault("Visibility.Distance.Object", DEFAULT_VISIBILITY_DISTANCE);
- if (m_MaxVisibleDistanceForObject < INTERACTION_DISTANCE)
- {
- sLog.outError("Visibility.Distance.Object can't be less max aggro radius %f",float(INTERACTION_DISTANCE));
- m_MaxVisibleDistanceForObject = INTERACTION_DISTANCE;
- }
- else if (m_MaxVisibleDistanceForObject + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
- {
- sLog.outError("Visibility.Distance.Object can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance);
- m_MaxVisibleDistanceForObject = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance;
- }
- m_MaxVisibleDistanceInFlight = sConfig.GetFloatDefault("Visibility.Distance.InFlight", DEFAULT_VISIBILITY_DISTANCE);
- if (m_MaxVisibleDistanceInFlight + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
+ else if (m_MaxVisibleDistanceInBGArenas > MAX_VISIBILITY_DISTANCE)
{
- sLog.outError("Visibility.Distance.InFlight can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance);
- m_MaxVisibleDistanceInFlight = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance;
+ sLog.outError("Visibility.Distance.BGArenas can't be greater %f",MAX_VISIBILITY_DISTANCE);
+ m_MaxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE;
}
m_visibility_notify_periodOnContinents = sConfig.GetIntDefault("Visibility.Notify.Period.OnContinents", DEFAULT_VISIBILITY_NOTIFY_PERIOD);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 1dd06725768..92e53e7ef82 100755
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -705,11 +705,6 @@ class World
static float GetMaxVisibleDistanceOnContinents() { return m_MaxVisibleDistanceOnContinents; }
static float GetMaxVisibleDistanceInInstances() { return m_MaxVisibleDistanceInInstances; }
static float GetMaxVisibleDistanceInBGArenas() { return m_MaxVisibleDistanceInBGArenas; }
- static float GetMaxVisibleDistanceForObject() { return m_MaxVisibleDistanceForObject; }
-
- static float GetMaxVisibleDistanceInFlight() { return m_MaxVisibleDistanceInFlight; }
- static float GetVisibleUnitGreyDistance() { return m_VisibleUnitGreyDistance; }
- static float GetVisibleObjectGreyDistance() { return m_VisibleObjectGreyDistance; }
static int32 GetVisibilityNotifyPeriodOnContinents(){ return m_visibility_notify_periodOnContinents; }
static int32 GetVisibilityNotifyPeriodInInstances() { return m_visibility_notify_periodInInstances; }
@@ -801,11 +796,6 @@ class World
static float m_MaxVisibleDistanceOnContinents;
static float m_MaxVisibleDistanceInInstances;
static float m_MaxVisibleDistanceInBGArenas;
- static float m_MaxVisibleDistanceForObject;
-
- static float m_MaxVisibleDistanceInFlight;
- static float m_VisibleUnitGreyDistance;
- static float m_VisibleObjectGreyDistance;
static int32 m_visibility_notify_periodOnContinents;
static int32 m_visibility_notify_periodInInstances;
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 80bca7e28e8..820a36f5481 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -517,6 +517,46 @@ class spell_gen_animal_blood : public SpellScriptLoader
}
};
+class spell_gen_shroud_of_death : public SpellScriptLoader
+{
+ public:
+ spell_gen_shroud_of_death() : SpellScriptLoader("spell_gen_shroud_of_death") { }
+
+ class spell_gen_shroud_of_deathAuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gen_shroud_of_deathAuraScript)
+
+ void HandleEffectApply(AuraEffect const * /*aurEff*/, AuraApplication const * aurApp, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* target = aurApp->GetTarget())
+ {
+ target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST);
+ target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST);
+ }
+ }
+
+ void HandleEffectRemove(AuraEffect const * /*aurEff*/, AuraApplication const * aurApp, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* target = aurApp->GetTarget())
+ {
+ target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
+ target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_gen_shroud_of_deathAuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ OnEffectRemove += AuraEffectRemoveFn(spell_gen_shroud_of_deathAuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript *GetAuraScript() const
+ {
+ return new spell_gen_shroud_of_deathAuraScript();
+ }
+};
+
void AddSC_generic_spell_scripts()
{
new spell_gen_aura_of_anger();
@@ -530,4 +570,5 @@ void AddSC_generic_spell_scripts()
new spell_creature_permanent_feign_death();
new spell_pvp_trinket_wotf_shared_cd();
new spell_gen_animal_blood();
+ new spell_gen_shroud_of_death();
}
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 770da7decf0..3f6f6d75636 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1409,37 +1409,12 @@ GM.TicketSystem.ChanceOfGMSurvey = 50
# Max limited by active player zone: ~ 333
# Min limit is max aggro radius (45) * Rate.Creature.Aggro
#
-# Visibility.Distance.Object
-# Visible distance for gameobject, dynobject, bodies, corpses, bones
-# Min limit is iteraction distance (5)
-#
-# Visibility.Distance.InFlight
-# Visible distance for player in flight
-# Min limit is 0 (not show any objects)
-#
-# Visibility.Distance.Grey.Unit
-# Visibility grey distance for creatures/players (fast changing objects)
-# addition to appropriate object type Visibility.Distance.* use in case
-# visibility removing to object (except corpse around distances)
-# If D is distance and G is grey distance then object
-# make visible if distance to it <= D
-# but make non visible if distance > D+G
-# Default: 1 (yard)
-#
-# Visibility.Distance.Grey.Object
-# Visibility grey distance for dynobjects/gameobjects/corpses/creatures
-# Default: 10 (yards)
-#
###############################################################################
Visibility.GroupMode = 1
Visibility.Distance.Continents = 90
Visibility.Distance.Instances = 120
Visibility.Distance.BGArenas = 180
-Visibility.Distance.Object = 100
-Visibility.Distance.InFlight = 100
-Visibility.Distance.Grey.Unit = 1
-Visibility.Distance.Grey.Object = 10
Visibility.Notify.Period.OnContinents = 1000
Visibility.Notify.Period.InInstances = 1000