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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user