- 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
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
-2
View File
@@ -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;
+17 -77
View File
@@ -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);
+3 -4
View File
@@ -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);
+243 -13
View File
@@ -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);
}
+54 -6
View File
@@ -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);
+1 -1
View File
@@ -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);
+47 -247
View File
@@ -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()
+8 -9
View File
@@ -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;
+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;
@@ -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>
+3 -3
View File
@@ -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);
}
}
+51 -89
View File
@@ -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;
+3 -1
View File
@@ -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,
+140 -45
View File
@@ -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
+4 -19
View File
@@ -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;
+1 -1
View File
@@ -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)
+2 -2
View File
@@ -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))
+9 -45
View File
@@ -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);
-10
View File
@@ -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