- 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:
linencloth
2010-11-13 17:18:09 +01:00
parent 995408f0a9
commit bf888285aa
36 changed files with 780 additions and 791 deletions
+33 -97
View File
@@ -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);
}
}
+15 -22
View File
@@ -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;