Core:
- Redesigned stealth and invisibility handling - Implemented the handling of multiple stealth types - Implemented fake inebriation - The message deliverer no longer sends packets from a non-visible source - The server won't send that much garbage which just takes bandwith - It won't be possible to use cheats to detect invisible objects - Removed a lot of checks for the Z-coord - Fixes visibility problems happening while flying - Limited the grid activation range of creatures to use less resources - Implemented Shroud of Death - Implemented increased visibility range for active objects - Removed visibility check at spellhit (only sanctuary effects should prevent it) (And a lot of other changes...) Closes issue 4208 Closes issue 3049 Closes issue 2097 Closes issue 2198 Closes issue 2384 Closes issue 2197 Closes issue 2319 --HG-- branch : trunk
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
if (!Unit::isVisibleForInState(seer))
|
||||
return false;
|
||||
|
||||
// all dead creatures/players not visible for any creatures
|
||||
if (!u->isAlive() || !isAlive())
|
||||
return false;
|
||||
|
||||
// Always can see self
|
||||
if (u == this)
|
||||
if (isAlive() || (m_isDeadByDefault && m_deathState == CORPSE) || m_corpseRemoveTime > time(NULL))
|
||||
return true;
|
||||
|
||||
// phased visibility (both must phased in same way)
|
||||
if (!InSamePhase(u))
|
||||
return false;
|
||||
|
||||
// always seen by owner
|
||||
if (GetGUID() == u->GetCharmerOrOwnerGUID())
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -226,6 +226,20 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa
|
||||
break;
|
||||
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);
|
||||
@@ -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
|
||||
|
||||
// Despawned
|
||||
if (!isSpawned())
|
||||
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;
|
||||
|
||||
return distance < visibleDistance;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameObject::Respawn()
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
// low level function for visibility change code, must be define in all main world object subclasses
|
||||
virtual bool isVisibleForInState(Player const* u, bool inVisibleList) const = 0;
|
||||
virtual bool 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;
|
||||
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,178 +20471,45 @@ 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()))
|
||||
if (GetSession()->PlayerLogout() || GetSession()->PlayerLoading())
|
||||
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))
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
// Ghost see other friendly ghosts, that's for sure
|
||||
if (!(isAlive() || m_deathTimer > 0) && IsFriendlyTo(pl))
|
||||
// Always can see self
|
||||
if (m_mover == obj)
|
||||
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 (uint64 guid = GetUInt64Value(PLAYER_FARSIGHT))
|
||||
if (obj->GetGUID() == guid)
|
||||
return true;
|
||||
|
||||
// and not see any other
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Player::isAlwaysDetectableFor(WorldObject const* seer) const
|
||||
{
|
||||
if (Unit::isAlwaysDetectableFor(seer))
|
||||
return true;
|
||||
|
||||
if (const Player* seerPlayer = seer->ToPlayer())
|
||||
if (IsGroupVisibleFor(seerPlayer))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Player::IsVisibleGloballyFor(Player* u) const
|
||||
{
|
||||
if (!u)
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
|
||||
// Always seen by owner
|
||||
if (uint64 guid = GetCharmerOrOwnerGUID())
|
||||
if (seer->GetGUID() == guid)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if (HasAuraTypeWithCaster(SPELL_AURA_MOD_STALKED, seer->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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Trinity::ObjectUpdater, GridTypeMapContainer> &gridVisitor, TypeContainerVisitor<Trinity::ObjectUpdater, WorldTypeMapContainer> &worldVisitor)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 players at tick
|
||||
for (m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
|
||||
{
|
||||
Player* plr = m_mapRefIter->getSource();
|
||||
if (plr && plr->IsInWorld())
|
||||
plr->Update(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()));
|
||||
// update players at tick
|
||||
plr->Update(t_diff);
|
||||
|
||||
// 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);
|
||||
|
||||
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;
|
||||
WorldObject* obj = *m_activeNonPlayersIter;
|
||||
++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;
|
||||
|
||||
if (!obj->IsInWorld())
|
||||
continue;
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
{
|
||||
// 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 (!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);
|
||||
|
||||
// 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->m_invisibility.DelFlag(type);
|
||||
}
|
||||
|
||||
target->UpdateObjectVisibility();
|
||||
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
|
||||
{
|
||||
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))
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
else if (m_MaxVisibleDistanceInBGArenas > 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)
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user