diff options
Diffstat (limited to 'src')
35 files changed, 777 insertions, 790 deletions
diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp index cc2f21d24c5..b16d23b04f1 100755 --- a/src/server/game/AI/CoreAI/GuardAI.cpp +++ b/src/server/game/AI/CoreAI/GuardAI.cpp @@ -125,7 +125,7 @@ void GuardAI::UpdateAI(const uint32 /*diff*/) bool GuardAI::IsVisible(Unit *pl) const { return me->IsWithinDist(pl,sWorld.getFloatConfig(CONFIG_SIGHT_GUARDER)) - && pl->isVisibleForOrDetect(me,true); + && me->canSeeOrDetect(pl); } void GuardAI::JustDied(Unit *killer) diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp index 7110bdc1ad8..c20fb2b249e 100755 --- a/src/server/game/AI/CoreAI/TotemAI.cpp +++ b/src/server/game/AI/CoreAI/TotemAI.cpp @@ -77,7 +77,7 @@ TotemAI::UpdateAI(const uint32 /*diff*/) // Search victim if no, not attackable, or out of range, or friendly (possible in case duel end) if (!victim || !victim->isTargetableForAttack() || !me->IsWithinDistInMap(victim, max_range) || - me->IsFriendlyTo(victim) || !victim->isVisibleForOrDetect(me,false)) + me->IsFriendlyTo(victim) || !me->canSeeOrDetect(victim)) { victim = NULL; Trinity::NearestAttackableUnitInObjectRangeCheck u_check(me, me, max_range); diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index e773bb2d1b3..29a2b83e32d 100755 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -210,11 +210,6 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields) return true; } -bool Corpse::isVisibleForInState(Player const* u, bool inVisibleList) const -{ - return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u->m_seer, World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); -} - bool Corpse::IsExpired(time_t t) const { if (m_type == CORPSE_BONES) diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h index 0ea164a90a4..98253fb49ef 100755 --- a/src/server/game/Entities/Corpse/Corpse.h +++ b/src/server/game/Entities/Corpse/Corpse.h @@ -73,8 +73,6 @@ class Corpse : public WorldObject, public GridObject<Corpse> GridPair const& GetGrid() const { return m_grid; } void SetGrid(GridPair const& grid) { m_grid = grid; } - bool isVisibleForInState(Player const* u, bool inVisibleList) const; - Loot loot; // remove insignia ONLY at BG Player* lootRecipient; bool lootForBody; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index dce2c968a84..6631de8bdd4 100755 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -802,6 +802,18 @@ bool Creature::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, LastUsedScriptID = GetCreatureInfo()->ScriptID; } + // TODO: Replace with spell, handle from DB + if (isSpiritHealer()) + { + m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); + m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); + } + else if(isSpiritGuide()) + m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST | GHOST_VISIBILITY_ALIVE); + + if (Entry == VISUAL_WAYPOINT) + SetVisibility(VISIBILITY_OFF); + return bResult; } @@ -1385,50 +1397,15 @@ void Creature::DeleteFromDB() WorldDatabase.CommitTransaction(trans); } -bool Creature::canSeeOrDetect(Unit const* u, bool detect, bool /*inVisibleList*/, bool /*is3dDistance*/) const +bool Creature::isVisibleForInState(WorldObject const* seer) const { - // not in world - if (!IsInWorld() || !u->IsInWorld()) - return false; - - // all dead creatures/players not visible for any creatures - if (!u->isAlive() || !isAlive()) - return false; - - // Always can see self - if (u == this) - return true; - - // phased visibility (both must phased in same way) - if (!InSamePhase(u)) + if (!Unit::isVisibleForInState(seer)) return false; - // always seen by owner - if (GetGUID() == u->GetCharmerOrOwnerGUID()) + if (isAlive() || (m_isDeadByDefault && m_deathState == CORPSE) || m_corpseRemoveTime > time(NULL)) return true; - if (u->GetVisibility() == VISIBILITY_OFF) //GM - return false; - - // invisible aura - if ((m_invisibilityMask || u->m_invisibilityMask) && !canDetectInvisibilityOf(u)) - return false; - - // unit got in stealth in this moment and must ignore old detected state - //if (m_Visibility == VISIBILITY_GROUP_NO_DETECT) - // return false; - - // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible - if (u->GetVisibility() == VISIBILITY_GROUP_STEALTH) - { - //do not know what is the use of this detect - if (!detect || !canDetectStealthOf(u, GetDistance(u))) - return false; - } - - // Now check is target visible with LoS - //return u->IsWithinLOS(GetPositionX(),GetPositionY(),GetPositionZ()); - return true; + return false; } bool Creature::canStartAttack(Unit const* who, bool force) const @@ -1784,43 +1761,6 @@ SpellEntry const *Creature::reachWithSpellCure(Unit *pVictim) return NULL; } -bool Creature::IsVisibleInGridForPlayer(Player const* pl) const -{ - // gamemaster in GM mode see all, including ghosts - if (pl->isGameMaster()) - return true; - - // Trigger shouldn't be visible for players - //if (isTrigger()) - // return false; - // Rat: this makes no sense, triggers are always sent to players, but with invisible model and can not be attacked or targeted! - - // Live player (or with not release body see live creatures or death creatures with corpse disappearing time > 0 - if (pl->isAlive() || pl->GetDeathTimer() > 0) - { - if (GetEntry() == VISUAL_WAYPOINT) - return false; - return (isAlive() || m_corpseRemoveTime > time(NULL) || (m_isDeadByDefault && m_deathState == CORPSE)); - } - - // Dead player see creatures near own corpse - Corpse *corpse = pl->GetCorpse(); - if (corpse) - { - // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level - if (corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO))) - return true; - } - - // Dead player see Spirit Healer or Spirit Guide - if (isSpiritService()) - return true; - - // and not see any other - return false; -} - - // select nearest hostile unit within the given distance (regardless of threat list). Unit* Creature::SelectNearestTarget(float dist) const { @@ -1832,7 +1772,7 @@ Unit* Creature::SelectNearestTarget(float dist) const Unit *target = NULL; { - if (dist == 0.0f || dist > MAX_VISIBILITY_DISTANCE) + if (dist == 0.0f) dist = MAX_VISIBILITY_DISTANCE; Trinity::NearestHostileUnitCheck u_check(this, dist); diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index fcfa9edf3e0..28f6d46d998 100755 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -437,7 +437,7 @@ class Creature : public Unit, public GridObject<Creature> bool HasReactState(ReactStates state) const { return (m_reactState == state); } void InitializeReactState() { - if (isTotem() || isTrigger() || GetCreatureType() == CREATURE_TYPE_CRITTER) + if (isTotem() || isTrigger() || GetCreatureType() == CREATURE_TYPE_CRITTER || isSpiritService()) SetReactState(REACT_PASSIVE); else SetReactState(REACT_AGGRESSIVE); @@ -568,7 +568,6 @@ class Creature : public Unit, public GridObject<Creature> CreatureSpellCooldowns m_CreatureCategoryCooldowns; uint32 m_GlobalCooldown; - bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const; bool canStartAttack(Unit const* u, bool force) const; float GetAttackDistance(Unit const* pl) const; @@ -593,8 +592,6 @@ class Creature : public Unit, public GridObject<Creature> Cell const& GetCurrentCell() const { return m_currentCell; } void SetCurrentCell(Cell const& cell) { m_currentCell = cell; } - bool IsVisibleInGridForPlayer(Player const* pl) const; - void RemoveCorpse(bool setSpawnTime = true); bool isDeadByDefault() const { return m_isDeadByDefault; }; @@ -726,6 +723,8 @@ class Creature : public Unit, public GridObject<Creature> uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable uint32 guid_transport; + + bool isVisibleForInState(WorldObject const* seer) const; private: //WaypointMovementGenerator vars uint32 m_waypointID; diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index bc0db5b8cc2..4f10b410b7a 100755 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -182,9 +182,3 @@ void DynamicObject::Delay(int32 delaytime) { SetDuration(GetDuration() - delaytime); } - -bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const -{ - return IsInWorld() && u->IsInWorld() - && (IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false)); -} diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.h b/src/server/game/Entities/DynamicObject/DynamicObject.h index 80bba2772fe..5b662f4c6de 100755 --- a/src/server/game/Entities/DynamicObject/DynamicObject.h +++ b/src/server/game/Entities/DynamicObject/DynamicObject.h @@ -44,7 +44,6 @@ class DynamicObject : public WorldObject, public GridObject<DynamicObject> uint64 GetCasterGUID() const { return GetUInt64Value(DYNAMICOBJECT_CASTER); } float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); } Unit* GetCaster() const; - bool isVisibleForInState(Player const* u, bool inVisibleList) const; void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); } void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); } diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 33dd0422ce8..bb79c2e0ea4 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -227,6 +227,20 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa case GAMEOBJECT_TYPE_FISHINGNODE: SetGoAnimProgress(0); break; + case GAMEOBJECT_TYPE_TRAP: + if (GetGOInfo()->trap.stealthed) + { + m_stealth.AddFlag( STEALTH_TRAP); + m_stealth.AddValue(STEALTH_TRAP, 300); + } + + if (GetGOInfo()->trap.invisible) + { + m_invisibility.AddFlag( INVISIBILITY_TRAP); + m_invisibility.AddValue(INVISIBILITY_TRAP, 70); + } + + break; default: SetGoAnimProgress(animprogress); break; @@ -810,56 +824,27 @@ void GameObject::SaveRespawnTime() sObjectMgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime); } -bool GameObject::isVisibleForInState(Player const* u, bool inVisibleList) const +bool GameObject::isAlwaysVisibleFor(WorldObject const* seer) const { - // Not in world - if (!IsInWorld() || !u->IsInWorld()) - return false; - - // Transport always visible at this step implementation - if (IsTransport() && IsInMap(u)) + if (WorldObject::isAlwaysVisibleFor(seer)) return true; - // quick check visibility false cases for non-GM-mode - if (!u->isGameMaster()) - { - // despawned and then not visible for non-GM in GM-mode - if (!isSpawned()) - return false; - - // special invisibility cases - if (GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && GetGOInfo()->trap.stealthed) - { - Unit *owner = GetOwner(); - if (owner && u->IsHostileTo(owner) && !canDetectTrap(u, GetDistance(u))) - return false; - } - } - - // check distance - return IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject() + - (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false); + if (IsTransport()) + return true; + + return false; } -bool GameObject::canDetectTrap(Player const* u, float distance) const +bool GameObject::isVisibleForInState(WorldObject const* seer) const { - if (u->hasUnitState(UNIT_STAT_STUNNED)) + if (!WorldObject::isVisibleForInState(seer)) return false; - if (distance < GetGOInfo()->size) //collision - return true; - if (!u->HasInArc(M_PI, this)) //behind - return false; - if (u->HasAuraType(SPELL_AURA_DETECT_STEALTH)) - return true; - //Visible distance is modified by -Level Diff (every level diff = 0.25f in visible distance) - float visibleDistance = (int32(u->getLevel()) - int32(GetOwner()->getLevel()))* 0.25f; - //GetModifier for trap (miscvalue 1) - //35y for aura 2836 - //WARNING: these values are guessed, may be not blizzlike - visibleDistance += u->GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_DETECT, 1)* 0.5f; + // Despawned + if (!isSpawned()) + return false; - return distance < visibleDistance; + return true; } void GameObject::Respawn() diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 4ed40c7d6e9..e8c37cb34cd 100755 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -136,7 +136,7 @@ struct GameObjectInfo uint32 serverOnly; //8 uint32 stealthed; //9 uint32 large; //10 - uint32 stealthAffected; //11 + uint32 invisible; //11 uint32 openTextID; //12 can be used to replace castBarCaption? uint32 closeTextID; //13 uint32 ignoreTotems; //14 @@ -733,8 +733,16 @@ class GameObject : public WorldObject, public GridObject<GameObject> void TriggeringLinkedGameObject(uint32 trapEntry, Unit* target); - bool isVisibleForInState(Player const* u, bool inVisibleList) const; - bool canDetectTrap(Player const* u, float distance) const; + bool isAlwaysVisibleFor(WorldObject const* seer) const; + bool isVisibleForInState(WorldObject const* seer) const; + + uint8 getLevelForTarget(WorldObject const* target) const + { + if (Unit* owner = GetOwner()) + return owner->getLevelForTarget(target); + + return 1; + } GameObject* LookupFishingHoleAround(float range); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 868443031ae..e7edea0b07f 100755 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1223,7 +1223,10 @@ WorldObject::WorldObject(): WorldLocation(), m_isWorldObject(false), m_name(""), m_isActive(false), m_zoneScript(NULL), m_transport(NULL), m_currMap(NULL), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_notifyflags(0), m_executed_notifies(0) -{} +{ + m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST); + m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); +} void WorldObject::SetWorldObject(bool on) { @@ -1608,6 +1611,239 @@ void WorldObject::MonsterWhisper(const char* text, uint64 receiver, bool IsBossW player->GetSession()->SendPacket(&data); } +bool WorldObject::isValid() const +{ + if (!IsInWorld()) + return false; + + return true; +} + +float WorldObject::GetGridActivationRange() const +{ + if (ToPlayer()) + return GetMap()->GetVisibilityRange(); + else if (ToCreature()) + return ToCreature()->m_SightDistance; + else + return 0.0f; +} + +float WorldObject::GetVisibilityRange() const +{ + if (isActiveObject() && !ToPlayer()) + return MAX_VISIBILITY_DISTANCE; + else + return GetMap()->GetVisibilityRange(); +} + +float WorldObject::GetSightRange(const WorldObject* target) const +{ + if (ToUnit()) + { + if (ToPlayer()) + { + if (target && target->isActiveObject()) + return MAX_VISIBILITY_DISTANCE; + else + return GetMap()->GetVisibilityRange(); + } + else if (ToCreature()) + return ToCreature()->m_SightDistance; + else + return SIGHT_RANGE_UNIT; + } + + return 0.0f; +} + +bool WorldObject::canSeeOrDetect(WorldObject const* obj, bool ignoreStealth, bool distanceCheck) const +{ + if (this == obj) + return true; + + if (!obj->isValid()) + return false; + + if (GetMap() != obj->GetMap()) + return false; + + if (!InSamePhase(obj)) + return false; + + if (obj->isAlwaysVisibleFor(this)) + return true; + + if (canSeeAlways(obj)) + return true; + + bool corpseCheck = false; + bool corpseVisibility = false; + if (distanceCheck) + { + if (const Player* thisPlayer = ToPlayer()) + { + if (thisPlayer->isDead() && thisPlayer->GetHealth() > 0 && // Cheap way to check for ghost state + !(obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & GHOST_VISIBILITY_GHOST)) + { + if (Corpse* corpse = thisPlayer->GetCorpse()) + { + corpseCheck = true; + if (corpse->IsWithinDist(thisPlayer, GetSightRange(obj), false)) + if (corpse->IsWithinDist(obj, GetSightRange(obj), false)) + corpseVisibility = true; + } + } + } + + if (!corpseCheck && !IsWithinDist(obj, GetSightRange(obj), false)) + return false; + } + + // GM visibility off or hidden NPC + if (!obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM)) + { + // Stop checking other things for GMs + if (m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GM)) + return true; + } + else + return m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GM) >= obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM); + + // Ghost players, Spirit Healers, and some other NPCs + if (!corpseVisibility && !(obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GHOST))) + { + // Alive players can see dead players in some cases, but other objects can't do that + if (const Player* thisPlayer = ToPlayer()) + { + if (const Player* objPlayer = obj->ToPlayer()) + { + if (thisPlayer->GetTeam() != objPlayer->GetTeam() || !thisPlayer->IsGroupVisibleFor(objPlayer)) + return false; + } + else + return false; + } + else + return false; + } + + if (!obj->isVisibleForInState(this)) + return false; + + if (!canDetect(obj, ignoreStealth)) + return false; + + return true; +} + +bool WorldObject::canDetect(WorldObject const* obj, bool ignoreStealth) const +{ + const WorldObject* seer = this; + + // Pets don't have detection, they use the detection of their masters + if (const Unit* thisUnit = ToUnit()) + if (Unit* controller = thisUnit->GetCharmerOrOwner()) + seer = controller; + + if (obj->isAlwaysDetectableFor(seer)) + return true; + + if (!seer->canDetectInvisibilityOf(obj)) + return false; + + if (!ignoreStealth && !seer->canDetectStealthOf(obj)) + return false; + + return true; +} + +bool WorldObject::canDetectInvisibilityOf(WorldObject const* obj) const +{ + uint32 mask = obj->m_invisibility.GetFlags() & m_invisibilityDetect.GetFlags(); + + // Check for not detected types + if (mask != obj->m_invisibility.GetFlags()) + return false; + + // It isn't possible in invisibility to detect something that can't detect the invisible object + // (it's at least true for spell: 66) + // It seems like that only Units are affected by this check (couldn't see arena doors with preparation invisibility) + if (obj->ToUnit()) + if ((m_invisibility.GetFlags() & obj->m_invisibilityDetect.GetFlags()) != m_invisibility.GetFlags()) + return false; + + for (uint32 i = 0; i < TOTAL_INVISIBILITY_TYPES; ++i) + { + if (!(mask & (1 << i))) + continue; + + int32 objInvisibilityValue = obj->m_invisibility.GetValue(InvisibilityType(i)); + int32 ownInvisibilityDetectValue = m_invisibilityDetect.GetValue(InvisibilityType(i)); + + // Too low value to detect + if (ownInvisibilityDetectValue < objInvisibilityValue) + return false; + } + + return true; +} + +bool WorldObject::canDetectStealthOf(WorldObject const* obj) const +{ + // Combat reach is the minimal distance (both in front and behind), + // and it is also used in the range calculation. + // One stealth point increases the visibility range by 0.3 yard. + + if (!obj->m_stealth.GetFlags()) + return true; + + float distance = GetExactDist(obj); + float combatReach = 0.0f; + + if (isType(TYPEMASK_UNIT)) + combatReach = ((Unit*)this)->GetCombatReach(); + + if (distance < combatReach) + return true; + + if (!HasInArc(M_PI, obj)) + return false; + + for (uint32 i = 0; i < TOTAL_STEALTH_TYPES; ++i) + { + if (!(obj->m_stealth.GetFlags() & (1 << i))) + continue; + + if (isType(TYPEMASK_UNIT)) + if (((Unit*)this)->HasAuraTypeWithMiscvalue(SPELL_AURA_DETECT_STEALTH, i)) + return true; + + // Starting points + int32 detectionValue = 30; + + // Level difference: 5 point / level, starting from level 1. + // There may be spells for this and the starting points too, but + // not in the DBCs of the client. + detectionValue += int32(getLevelForTarget(obj) - 1) * 5; + + // Apply modifiers + detectionValue += m_stealthDetect.GetValue(StealthType(i)); + detectionValue -= obj->m_stealth.GetValue(StealthType(i)); + + // Calculate max distance + float visibilityRange = float(detectionValue) * 0.3f + combatReach; + + if (visibilityRange > MAX_PLAYER_STEALTH_DETECT_RANGE) + visibilityRange = MAX_PLAYER_STEALTH_DETECT_RANGE; + + if (distance > visibilityRange) + return false; + } + + return true; +} + void WorldObject::SendPlaySound(uint32 Sound, bool OnlySelf) { WorldPacket data(SMSG_PLAY_SOUND, 4); @@ -1754,12 +1990,6 @@ void Unit::BuildHeartBeatMsg(WorldPacket *data) const BuildMovementPacket(data); } -void WorldObject::SendMessageToSet(WorldPacket *data, bool /*fake*/) -{ - Trinity::MessageDistDeliverer notifier(this, data, GetMap()->GetVisibilityDistance()); - VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier); -} - void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*bToSelf*/) { Trinity::MessageDistDeliverer notifier(this, data, dist); @@ -1768,8 +1998,8 @@ void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /* void WorldObject::SendMessageToSet(WorldPacket *data, Player const* skipped_rcvr) { - Trinity::MessageDistDeliverer notifier(this, data, GetMap()->GetVisibilityDistance(), false, skipped_rcvr); - VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier); + Trinity::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr); + VisitNearbyWorldObject(GetVisibilityRange(), notifier); } void WorldObject::SendObjectDeSpawnAnim(uint64 guid) @@ -2434,9 +2664,9 @@ void WorldObject::DestroyForNearbyPlayers() return; std::list<Player*> targets; - Trinity::AnyPlayerInObjectRangeCheck check(this, GetMap()->GetVisibilityDistance()); + Trinity::AnyPlayerInObjectRangeCheck check(this, GetVisibilityRange()); Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(this, targets, check); - VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), searcher); + VisitNearbyWorldObject(GetVisibilityRange(), searcher); for (std::list<Player*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter) { Player *plr = (*iter); @@ -2459,7 +2689,7 @@ void WorldObject::UpdateObjectVisibility(bool /*forced*/) { //updates object's visibility for nearby players Trinity::VisibleChangesNotifier notifier(*this); - VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier); + VisitNearbyWorldObject(GetVisibilityRange(), notifier); } struct WorldObjectChangeAccumulator @@ -2531,7 +2761,7 @@ void WorldObject::BuildUpdate(UpdateDataMapType& data_map) TypeContainerVisitor<WorldObjectChangeAccumulator, WorldTypeMapContainer > player_notifier(notifier); Map& map = *GetMap(); //we must build packets for all visible players - cell.Visit(p, player_notifier, map, *this, map.GetVisibilityDistance()); + cell.Visit(p, player_notifier, map, *this, GetVisibilityRange()); ClearUpdateMask(false); } diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index b05b98f67b7..ff68bd3e9db 100755 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -34,7 +34,8 @@ #define CONTACT_DISTANCE 0.5f #define INTERACTION_DISTANCE 5.0f #define ATTACK_DISTANCE 5.0f -#define MAX_VISIBILITY_DISTANCE 333.0f // max distance for visible object show, limited in 333 yards +#define MAX_VISIBILITY_DISTANCE 500.0f // max distance for visible objects +#define SIGHT_RANGE_UNIT 50.0f #define DEFAULT_VISIBILITY_DISTANCE 90.0f // default visible distance, 90 yards on continents #define DEFAULT_VISIBILITY_INSTANCE 120.0f // default visible distance in instances, 120 yards #define DEFAULT_VISIBILITY_BGARENAS 180.0f // default visible distance in BG/Arenas, 180 yards @@ -542,6 +543,30 @@ class GridObject GridReference<T> m_gridRef; }; +template <class T_VALUES, class T_FLAGS, class FLAG_TYPE, uint8 ARRAY_SIZE> +class FlaggedValuesArray32 +{ + public: + FlaggedValuesArray32() + { + memset(&m_values, 0x00, sizeof(T_VALUES) * ARRAY_SIZE); + m_flags = 0; + } + + T_FLAGS GetFlags() const { return m_flags; } + bool HasFlag(FLAG_TYPE flag) const { return m_flags & (1 << flag); } + void AddFlag(FLAG_TYPE flag) { m_flags |= (1 << flag); } + void DelFlag(FLAG_TYPE flag) { m_flags &= ~(1 << flag); } + + T_VALUES GetValue(FLAG_TYPE flag) const { return m_values[flag]; } + void SetValue(FLAG_TYPE flag, T_VALUES value) { m_values[flag] = value; } + void AddValue(FLAG_TYPE flag, T_VALUES value) { m_values[flag] += value; } + + private: + T_VALUES m_values[ARRAY_SIZE]; + T_FLAGS m_flags; +}; + class WorldObject : public Object, public WorldLocation { protected: @@ -681,10 +706,12 @@ class WorldObject : public Object, public WorldLocation virtual void CleanupsBeforeDelete(bool finalCleanup = true); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units - virtual void SendMessageToSet(WorldPacket *data, bool self); + virtual void SendMessageToSet(WorldPacket *data, bool self) { SendMessageToSetInRange(data, GetVisibilityRange(), self); } virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self); virtual void SendMessageToSet(WorldPacket *data, Player const* skipped_rcvr); + virtual uint8 getLevelForTarget(WorldObject const* /*target*/) const { return 1; } + void MonsterSay(const char* text, uint32 language, uint64 TargetGuid); void MonsterYell(const char* text, uint32 language, uint64 TargetGuid); void MonsterTextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote = false); @@ -704,11 +731,32 @@ class WorldObject : public Object, public WorldLocation virtual void SaveRespawnTime() {} void AddObjectToRemoveList(); - // main visibility check function in normal case (ignore grey zone distance check) - bool isVisibleFor(Player const* u) const { return isVisibleForInState(u,false); } + virtual bool isValid() const; + + virtual bool isAlwaysVisibleFor(WorldObject const* seer) const { return false; } + virtual bool canSeeAlways(WorldObject const* obj) const { return false; } + bool canDetect(WorldObject const* obj, bool ignoreStealth) const; + + virtual bool isVisibleForInState(WorldObject const* seer) const { return true; } + + bool canDetectInvisibilityOf(WorldObject const* obj) const; + bool canDetectStealthOf(WorldObject const* obj) const; + + virtual bool isAlwaysDetectableFor(WorldObject const* seer) const { return false; } + + float GetGridActivationRange() const; + float GetVisibilityRange() const; + float GetSightRange(const WorldObject* target = NULL) const; + bool canSeeOrDetect(WorldObject const* obj, bool ignoreStealth = false, bool distanceCheck = false) const; + + FlaggedValuesArray32<int32, uint32, StealthType, TOTAL_STEALTH_TYPES> m_stealth; + FlaggedValuesArray32<int32, uint32, StealthType, TOTAL_STEALTH_TYPES> m_stealthDetect; + + FlaggedValuesArray32<int32, uint32, InvisibilityType, TOTAL_INVISIBILITY_TYPES> m_invisibility; + FlaggedValuesArray32<int32, uint32, InvisibilityType, TOTAL_INVISIBILITY_TYPES> m_invisibilityDetect; - // low level function for visibility change code, must be define in all main world object subclasses - virtual bool isVisibleForInState(Player const* u, bool inVisibleList) const = 0; + FlaggedValuesArray32<int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES> m_serverSideVisibility; + FlaggedValuesArray32<int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES> m_serverSideVisibilityDetect; // Low Level Packets void SendPlaySound(uint32 Sound, bool OnlySelf); diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index df482c40143..bf570ce0693 100755 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -506,7 +506,7 @@ void Pet::Update(uint32 diff) { // unsummon pet that lost owner Player* owner = GetOwner(); - if (!owner || (!IsWithinDistInMap(owner, GetMap()->GetVisibilityDistance()) && !isPossessed()) || (isControlled() && !owner->GetPetGUID())) + if (!owner || (!IsWithinDistInMap(owner, GetMap()->GetVisibilityRange()) && !isPossessed()) || (isControlled() && !owner->GetPetGUID())) //if (!owner || (!IsWithinDistInMap(owner, GetMap()->GetVisibilityDistance()) && (owner->GetCharmGUID() && (owner->GetCharmGUID() != GetGUID()))) || (isControlled() && !owner->GetPetGUID())) { Remove(PET_SAVE_NOT_IN_SLOT, true); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 07e56dafe89..02d6c4cebb0 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -485,8 +485,6 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_swingErrorMsg = 0; - m_DetectInvTimer = 1*IN_MILLISECONDS; - for (uint8 j = 0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j) { m_bgBattlegroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; @@ -1216,16 +1214,19 @@ void Player::SetDrunkValue(uint16 newDrunkenValue, uint32 itemId) { uint32 oldDrunkenState = Player::GetDrunkenstateByValue(m_drunk); + if (!newDrunkenValue && !HasAuraType(SPELL_AURA_MOD_FAKE_INEBRIATE)) + m_invisibilityDetect.AddFlag(INVISIBILITY_DRUNK); + else + m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK); + + m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, int32(newDrunkenValue - m_drunk) / 256); + m_drunk = newDrunkenValue; SetUInt32Value(PLAYER_BYTES_3,(GetUInt32Value(PLAYER_BYTES_3) & 0xFFFF0001) | (m_drunk & 0xFFFE)); uint32 newDrunkenState = Player::GetDrunkenstateByValue(m_drunk); - // special drunk invisibility detection - if (newDrunkenState >= DRUNKEN_DRUNK) - m_detectInvisibilityMask |= (1<<6); - else - m_detectInvisibilityMask &= ~(1<<6); + UpdateObjectVisibility(); if (newDrunkenState == oldDrunkenState) return; @@ -1477,18 +1478,6 @@ void Player::Update(uint32 p_time) //Handle Water/drowning HandleDrowning(p_time); - //Handle detect stealth players - if (m_DetectInvTimer > 0) - { - if (p_time >= m_DetectInvTimer) - { - HandleStealthedUnitsDetection(); - m_DetectInvTimer = 3000; - } - else - m_DetectInvTimer -= p_time; - } - // Played time if (now > m_Last_tick) { @@ -1526,7 +1515,7 @@ void Player::Update(uint32 p_time) SendUpdateToOutOfRangeGroupMembers(); Pet* pet = GetPet(); - if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && !pet->isPossessed()) + if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityRange()) && !pet->isPossessed()) //if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID()))) RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true); @@ -1907,7 +1896,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!(options & TELE_TO_NOT_UNSUMMON_PET)) { //same map, only remove pet if out of range for new position - if (pet && !pet->IsWithinDist3d(x,y,z, GetMap()->GetVisibilityDistance())) + if (pet && !pet->IsWithinDist3d(x,y,z, GetMap()->GetVisibilityRange())) UnsummonPetTemporaryIfAny(); } @@ -2508,6 +2497,7 @@ void Player::SetGameMaster(bool on) CombatStopWithPets(); SetPhaseMask(PHASEMASK_ANYWHERE,false); // see and visible in all phases + m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, GetSession()->GetSecurity()); } else { @@ -2537,6 +2527,7 @@ void Player::SetGameMaster(bool on) UpdateArea(m_areaUpdateId); getHostileRefManager().setOnlineOfflineState(true); + m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER); } UpdateObjectVisibility(); @@ -2548,13 +2539,7 @@ void Player::SetGMVisible(bool on) { m_ExtraFlags &= ~PLAYER_EXTRA_GM_INVISIBLE; //remove flag - // Reapply stealth/invisibility if active or show if not any - if (HasAuraType(SPELL_AURA_MOD_STEALTH)) - SetVisibility(VISIBILITY_GROUP_STEALTH); - //else if (HasAuraType(SPELL_AURA_MOD_INVISIBILITY)) - // SetVisibility(VISIBILITY_GROUP_INVISIBILITY); - else - SetVisibility(VISIBILITY_ON); + m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER); } else { @@ -2563,11 +2548,11 @@ void Player::SetGMVisible(bool on) SetAcceptWhispers(false); SetGameMaster(true); - SetVisibility(VISIBILITY_OFF); + m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, GetSession()->GetSecurity()); } } -bool Player::IsGroupVisibleFor(Player* p) const +bool Player::IsGroupVisibleFor(Player const* p) const { switch(sWorld.getIntConfig(CONFIG_GROUP_VISIBILITY)) { @@ -6423,17 +6408,6 @@ void Player::SaveRecallPosition() m_recallO = GetOrientation(); } -void Player::SendMessageToSet(WorldPacket *data, bool self) -{ - if (self) - GetSession()->SendPacket(data); - - // we use World::GetMaxVisibleDistance() because i cannot see why not use a distance - // update: replaced by GetMap()->GetVisibilityDistance() - Trinity::MessageDistDeliverer notifier(this, data, GetMap()->GetVisibilityDistance()); - VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier); -} - void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self) { if (self) @@ -6459,8 +6433,8 @@ void Player::SendMessageToSet(WorldPacket *data, Player const* skipped_rcvr) // we use World::GetMaxVisibleDistance() because i cannot see why not use a distance // update: replaced by GetMap()->GetVisibilityDistance() - Trinity::MessageDistDeliverer notifier(this, data, GetMap()->GetVisibilityDistance(), false, skipped_rcvr); - VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier); + Trinity::MessageDistDeliverer notifier(this, data, GetVisibilityRange(), false, skipped_rcvr); + VisitNearbyWorldObject(GetVisibilityRange(), notifier); } void Player::SendDirectMessage(WorldPacket *data) @@ -19373,49 +19347,6 @@ void Player::SetRestBonus (float rest_bonus_new) SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, uint32(m_rest_bonus)); } -void Player::HandleStealthedUnitsDetection() -{ - std::list<Unit*> stealthedUnits; - Trinity::AnyStealthedCheck u_check; - Trinity::UnitListSearcher<Trinity::AnyStealthedCheck > searcher(this, stealthedUnits, u_check); - VisitNearbyObject(GetMap()->GetVisibilityDistance(), searcher); - - for (std::list<Unit*>::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i) - { - if ((*i) == this) - continue; - - bool hasAtClient = HaveAtClient((*i)); - bool hasDetected = canSeeOrDetect(*i, true); - - if (hasDetected) - { - if (!hasAtClient) - { - (*i)->SendUpdateToPlayer(this); - m_clientGUIDs.insert((*i)->GetGUID()); - - #ifdef TRINITY_DEBUG - if ((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES) == 0) - sLog.outDebug("Object %u (Type: %u) is detected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i)); - #endif - - // target aura duration for caster show only if target exist at caster client - // send data at target visibility change (adding to client) - SendInitialVisiblePackets(*i); - } - } - else - { - if (hasAtClient) - { - (*i)->DestroyForPlayer(this); - m_clientGUIDs.erase((*i)->GetGUID()); - } - } - } -} - bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= NULL*/, uint32 spellid /*= 0*/) { if (nodes.size() < 2) @@ -20540,177 +20471,44 @@ WorldLocation Player::GetStartPosition() const return WorldLocation(mapId, info->positionX, info->positionY, info->positionZ, 0); } -bool Player::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList, bool is3dDistance) const +bool Player::isValid() const { - // Always can see self - if (m_mover == u || this == u) - return true; - - // Arena visibility before arena start - if (InArena() && GetBattleground()->GetStatus() == STATUS_WAIT_JOIN) - if (const Player* target = u->GetCharmerOrOwnerPlayerOrPlayerItself()) - return GetBGTeam() == target->GetBGTeam() && target->isGMVisible(); - - // phased visibility (both must phased in same way) - if (!InSamePhase(u)) + if (!Unit::isValid()) return false; - // player visible for other player if not logout and at same transport - // including case when player is out of world - bool at_same_transport = - GetTransport() && u->GetTypeId() == TYPEID_PLAYER - && !GetSession()->PlayerLogout() && !u->ToPlayer()->GetSession()->PlayerLogout() - && !GetSession()->PlayerLoading() && !u->ToPlayer()->GetSession()->PlayerLoading() - && GetTransport() == u->ToPlayer()->GetTransport(); - - // not in world - if (!at_same_transport && (!IsInWorld() || !u->IsInWorld())) - return false; - - // forbidden to seen (at GM respawn command) - //if (u->GetVisibility() == VISIBILITY_RESPAWN) - // return false; - - Map& _map = *u->GetMap(); - // Grid dead/alive checks - // non visible at grid for any stealth state - if (!u->IsVisibleInGridForPlayer(this)) + if (GetSession()->PlayerLogout() || GetSession()->PlayerLoading()) return false; - // always seen by owner - if (uint64 guid = u->GetCharmerOrOwnerGUID()) - if (GetGUID() == guid) - return true; - - if (uint64 guid = GetUInt64Value(PLAYER_FARSIGHT)) - if (u->GetGUID() == guid) - return true; - - // different visible distance checks - if (isInFlight()) // what see player in flight - { - if (!m_seer->IsWithinDistInMap(u, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance)) - return false; - } - else if (!u->isAlive()) // distance for show body - { - if (!m_seer->IsWithinDistInMap(u, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), is3dDistance)) - return false; - } - else if (u->GetTypeId() == TYPEID_PLAYER) // distance for show player - { - // Players far than max visible distance for player or not in our map are not visible too - if (!at_same_transport && !m_seer->IsWithinDistInMap(u, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) - return false; - } - else if (u->GetCharmerOrOwnerGUID()) // distance for show pet/charmed - { - // Pet/charmed far than max visible distance for player or not in our map are not visible too - if (!m_seer->IsWithinDistInMap(u, _map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f), is3dDistance)) - return false; - } - else // distance for show creature - { - // Units farther than max visible distance for creature or not in our map are not visible too - if (!m_seer->IsWithinDistInMap(u - , u->isActiveObject() ? (MAX_VISIBILITY_DISTANCE - (inVisibleList ? 0.0f : World::GetVisibleUnitGreyDistance())) - : (_map.GetVisibilityDistance() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)) - , is3dDistance)) - return false; - } - - if (Unit* owner = u->GetCharmerOrOwnerOrSelf()) - { - if (owner->GetVisibility() == VISIBILITY_OFF) - { - // GMs see any players, not higher GMs and all units - if (isGameMaster()) - { - if (owner->GetTypeId() == TYPEID_PLAYER) - return owner->ToPlayer()->GetSession()->GetSecurity() <= GetSession()->GetSecurity(); - else - return true; - } - return false; - } - } - - // GM's can see everyone with invisibilitymask with less or equal security level - if (m_mover->m_invisibilityMask || u->m_invisibilityMask) - { - if (isGameMaster()) - { - if (u->GetTypeId() == TYPEID_PLAYER) - return u->ToPlayer()->GetSession()->GetSecurity() <= GetSession()->GetSecurity(); - else - return true; - } - - // player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting) - if (!m_mover->canDetectInvisibilityOf(u)) - if (!(u->GetTypeId() == TYPEID_PLAYER && !IsHostileTo(u) && IsGroupVisibleFor(const_cast<Player*>(u->ToPlayer())))) - return false; - } - - // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible - if (u->GetVisibility() == VISIBILITY_GROUP_STEALTH && !isGameMaster()) - { - // if player is dead then he can't detect anyone in any cases - //do not know what is the use of this detect - // stealth and detected and visible for some seconds - if (!isAlive()) - detect = false; - if (m_DetectInvTimer < 300 || !HaveAtClient(u)) - if (!(u->GetTypeId() == TYPEID_PLAYER && !IsHostileTo(u) && IsGroupVisibleFor(const_cast<Player*>(u->ToPlayer())))) - if (!detect || !m_mover->canDetectStealthOf(u, GetDistance(u))) - return false; - } - - // If use this server will be too laggy - // Now check is target visible with LoS - //return u->IsWithinLOS(GetPositionX(),GetPositionY(),GetPositionZ()); return true; } -bool Player::IsVisibleInGridForPlayer(Player const * pl) const +bool Player::canSeeAlways(WorldObject const* obj) const { - // gamemaster in GM mode see all, including ghosts - if (pl->isGameMaster() && GetSession()->GetSecurity() <= pl->GetSession()->GetSecurity()) + if (Unit::canSeeAlways(obj)) return true; - // It seems in battleground everyone sees everyone, except the enemy-faction ghosts - if (InBattleground()) - { - if (!(isAlive() || m_deathTimer > 0) && !IsFriendlyTo(pl)) - return false; + // Always can see self + if (m_mover == obj) return true; - } - // Live player see live player or dead player with not realized corpse - if (pl->isAlive() || pl->m_deathTimer > 0) - { - return isAlive() || m_deathTimer > 0; - } + if (uint64 guid = GetUInt64Value(PLAYER_FARSIGHT)) + if (obj->GetGUID() == guid) + return true; + + return false; +} - // Ghost see other friendly ghosts, that's for sure - if (!(isAlive() || m_deathTimer > 0) && IsFriendlyTo(pl)) +bool Player::isAlwaysDetectableFor(WorldObject const* seer) const +{ + if (Unit::isAlwaysDetectableFor(seer)) return true; - // Dead player see live players near own corpse - if (isAlive()) - { - Corpse *corpse = pl->GetCorpse(); - if (corpse) - { - // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level - if (corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO))) - return true; - } - } + if (const Player* seerPlayer = seer->ToPlayer()) + if (IsGroupVisibleFor(seerPlayer)) + return true; - // and not see any other - return false; -} + return false; + } bool Player::IsVisibleGloballyFor(Player* u) const { @@ -20780,7 +20578,7 @@ void Player::UpdateVisibilityOf(WorldObject* target) { if (HaveAtClient(target)) { - if (!target->isVisibleForInState(this, true)) + if (!canSeeOrDetect(target, false, true)) { if (target->GetTypeId() == TYPEID_UNIT) BeforeVisibilityDestroy<Creature>(target->ToCreature(),this); @@ -20796,7 +20594,7 @@ void Player::UpdateVisibilityOf(WorldObject* target) } else { - if (target->isVisibleForInState(this,false)) + if (canSeeOrDetect(target, false, true)) { //if (target->isType(TYPEMASK_UNIT) && ((Unit*)target)->m_Vehicle) // UpdateVisibilityOf(((Unit*)target)->m_Vehicle); @@ -20856,7 +20654,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& vi { if (HaveAtClient(target)) { - if (!target->isVisibleForInState(this,true)) + if (!canSeeOrDetect(target, false, true)) { BeforeVisibilityDestroy<T>(target,this); @@ -20871,7 +20669,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& vi } else //if (visibleNow.size() < 30 || target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->IsVehicle()) { - if (target->isVisibleForInState(this,false)) + if (canSeeOrDetect(target, false, true)) { //if (target->isType(TYPEMASK_UNIT) && ((Unit*)target)->m_Vehicle) // UpdateVisibilityOf(((Unit*)target)->m_Vehicle, data, visibleNow); @@ -20902,7 +20700,7 @@ void Player::UpdateObjectVisibility(bool forced) Unit::UpdateObjectVisibility(true); // updates visibility of all objects around point of view for current player Trinity::VisibleNotifier notifier(*this); - m_seer->VisitNearbyObject(GetMap()->GetVisibilityDistance(), notifier); + m_seer->VisitNearbyObject(GetVisibilityRange(), notifier); notifier.SendToSelf(); // send gathered data } } @@ -20910,7 +20708,7 @@ void Player::UpdateObjectVisibility(bool forced) void Player::UpdateVisibilityForPlayer() { Trinity::VisibleNotifier notifier(*this); - m_seer->VisitNearbyObject(GetMap()->GetVisibilityDistance(), notifier); + m_seer->VisitNearbyObject(GetVisibilityRange(), notifier); notifier.SendToSelf(); // send gathered data } @@ -21052,6 +20850,8 @@ void Player::SetGroup(Group *group, int8 subgroup) m_group.link(group, this); m_group.setSubGroup((uint8)subgroup); } + + UpdateObjectVisibility(); } void Player::SendInitialPacketsBeforeAddToMap() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index efed19af453..7e151769810 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1706,7 +1706,7 @@ class Player : public Unit, public GridObject<Player> void DuelComplete(DuelCompleteType type); void SendDuelCountdown(uint32 counter); - bool IsGroupVisibleFor(Player* p) const; + bool IsGroupVisibleFor(Player const* p) const; bool IsInSameGroupWith(Player const* p) const; bool IsInSameRaidWith(Player const* p) const { return p == this || (GetGroup() != NULL && GetGroup() == p->GetGroup()); } void UninviteFromGroup(); @@ -1842,7 +1842,7 @@ class Player : public Unit, public GridObject<Player> bool SetPosition(const Position &pos, bool teleport = false) { return SetPosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); } void UpdateUnderwaterState(Map * m, float x, float y, float z); - void SendMessageToSet(WorldPacket *data, bool self);// overwrite Object::SendMessageToSet + void SendMessageToSet(WorldPacket *data, bool self) {SendMessageToSetInRange(data, GetVisibilityRange(), self); };// overwrite Object::SendMessageToSet void SendMessageToSetInRange(WorldPacket *data, float fist, bool self);// overwrite Object::SendMessageToSetInRange void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only); void SendMessageToSet(WorldPacket *data, Player const* skipped_rcvr); @@ -2232,8 +2232,8 @@ class Player : public Unit, public GridObject<Player> bool HaveAtClient(WorldObject const* u) const { return u == this || m_clientGUIDs.find(u->GetGUID()) != m_clientGUIDs.end(); } - bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const; - bool IsVisibleInGridForPlayer(Player const* pl) const; + bool isValid() const; + bool IsVisibleGloballyFor(Player* pl) const; void SendInitialVisiblePackets(Unit* target); @@ -2245,9 +2245,6 @@ class Player : public Unit, public GridObject<Player> template<class T> void UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow); - // Stealth detection system - void HandleStealthedUnitsDetection(); - uint8 m_forced_speed_changes[MAX_MOVE_TYPE]; bool HasAtLoginFlag(AtLoginFlags f) const { return m_atLoginFlags & f; } @@ -2623,6 +2620,10 @@ class Player : public Unit, public GridObject<Player> DeclinedName *m_declinedname; Runes *m_runes; EquipmentSets m_EquipmentSets; + + bool canSeeAlways(WorldObject const* obj) const; + + bool isAlwaysDetectableFor(WorldObject const* seer) const; private: // internal common parts for CanStore/StoreItem functions uint8 _CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool swap, Item *pSrcItem) const; @@ -2673,8 +2674,6 @@ class Player : public Unit, public GridObject<Player> bool m_bCanDelayTeleport; bool m_bHasDelayedTeleport; - uint32 m_DetectInvTimer; - // Temporary removed pet cache uint32 m_temporaryUnsummonedPetNumber; uint32 m_oldpetspell; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 47b35321847..84ff41a67dd 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -137,11 +137,8 @@ m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this) m_ObjectSlot[0] = m_ObjectSlot[1] = m_ObjectSlot[2] = m_ObjectSlot[3] = 0; m_auraUpdateIterator = m_ownedAuras.end(); - m_Visibility = VISIBILITY_ON; m_interruptMask = 0; - m_detectInvisibilityMask = 0; - m_invisibilityMask = 0; m_transform = 0; m_ShapeShiftFormSpellId = 0; m_canModifyStats = false; @@ -193,6 +190,8 @@ m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this) m_cleanupDone = false; m_duringRemoveFromWorld = false; + + m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); } Unit::~Unit() @@ -4428,6 +4427,15 @@ bool Unit::HasAuraType(AuraType auraType) const return (!m_modAuras[auraType].empty()); } +bool Unit::HasAuraTypeWithCaster(AuraType auratype, uint64 caster) const +{ + AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); + for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) + if (caster == (*i)->GetCasterGUID()) + return true; + return false; +} + bool Unit::HasAuraTypeWithMiscvalue(AuraType auratype, int32 miscvalue) const { AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); @@ -11997,14 +12005,6 @@ bool Unit::canAttack(Unit const* target, bool force) const if (!target->isAttackableByAOE() || target->hasUnitState(UNIT_STAT_DIED)) return false; - // shaman totem quests: spell 8898, shaman can detect elementals but elementals cannot see shaman - if (m_invisibilityMask || target->m_invisibilityMask) - if (!canDetectInvisibilityOf(target) && !target->canDetectInvisibilityOf(this)) - return false; - - if (target->GetVisibility() == VISIBILITY_GROUP_STEALTH && !canDetectStealthOf(target, GetDistance(target))) - return false; - if (m_vehicle) if (IsOnVehicle(target) || m_vehicle->GetBase()->IsOnVehicle(target)) return false; @@ -12116,98 +12116,36 @@ int32 Unit::ModifyPower(Powers power, int32 dVal) return gain; } -bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList, bool is3dDistance) const +bool Unit::isAlwaysVisibleFor(WorldObject const* seer) const { - if (!u || !IsInMap(u)) - return false; - - return u->canSeeOrDetect(this, detect, inVisibleList, is3dDistance); -} - -bool Unit::canSeeOrDetect(Unit const* /*u*/, bool /*detect*/, bool /*inVisibleList*/, bool /*is3dDistance*/) const -{ - return true; -} - -bool Unit::canDetectInvisibilityOf(Unit const* u) const -{ - if (m_invisibilityMask & u->m_invisibilityMask) // same group + if (WorldObject::isAlwaysVisibleFor(seer)) return true; - AuraEffectList const& auras = u->GetAuraEffectsByType(SPELL_AURA_MOD_STALKED); // Hunter mark - for (AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) - if ((*iter)->GetCasterGUID() == GetGUID()) - return true; - - if (uint32 mask = (m_detectInvisibilityMask & u->m_invisibilityMask)) - { - for (uint8 i = 0; i < 10; ++i) - { - if (((1 << i) & mask) == 0) - continue; - - // find invisibility level - uint32 invLevel = 0; - Unit::AuraEffectList const& iAuras = u->GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY); - for (Unit::AuraEffectList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr) - if (uint8((*itr)->GetMiscValue()) == i && int32(invLevel) < (*itr)->GetAmount()) - invLevel = (*itr)->GetAmount(); - // find invisibility detect level - uint32 detectLevel = 0; - if (i == 6 && GetTypeId() == TYPEID_PLAYER) // special drunk detection case - { - detectLevel = this->ToPlayer()->GetDrunkValue(); - } - else - { - Unit::AuraEffectList const& dAuras = GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION); - for (Unit::AuraEffectList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr) - if (uint8((*itr)->GetMiscValue()) == i && int32(detectLevel) < (*itr)->GetAmount()) - detectLevel = (*itr)->GetAmount(); - } - - if (invLevel <= detectLevel) - return true; - } - } + // Always seen by owner + if (uint64 guid = GetCharmerOrOwnerGUID()) + if (seer->GetGUID() == guid) + return true; return false; } -bool Unit::canDetectStealthOf(Unit const* target, float distance) const +bool Unit::isAlwaysDetectableFor(WorldObject const* seer) const { - if (hasUnitState(UNIT_STAT_STUNNED)) - return false; - if (distance < 0.24f) //collision - return true; - if (!HasInArc(M_PI, target)) //behind - return false; - if (HasAuraType(SPELL_AURA_DETECT_STEALTH)) + if (WorldObject::isAlwaysDetectableFor(seer)) return true; - AuraEffectList const &auras = target->GetAuraEffectsByType(SPELL_AURA_MOD_STALKED); // Hunter mark - for (AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) - if ((*iter)->GetCasterGUID() == GetGUID()) - return true; - - //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5) - float visibleDistance = 7.5f; - //Visible distance is modified by -Level Diff (every level diff = 1.0f in visible distance) - visibleDistance += float(getLevelForTarget(target)) - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH)/5.0f; - //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) - //based on wowwiki every 5 mod we have 1 more level diff in calculation - visibleDistance += (float)(GetTotalAuraModifier(SPELL_AURA_MOD_DETECT) - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL)) / 5.0f; - visibleDistance = visibleDistance > MAX_PLAYER_STEALTH_DETECT_RANGE ? MAX_PLAYER_STEALTH_DETECT_RANGE : visibleDistance; + if (HasAuraTypeWithCaster(SPELL_AURA_MOD_STALKED, seer->GetGUID())) + return true; - return distance < visibleDistance; + return false; } void Unit::SetVisibility(UnitVisibility x) { - m_Visibility = x; - - if (m_Visibility == VISIBILITY_GROUP_STEALTH) - DestroyForNearbyPlayers(); + if (x == VISIBILITY_OFF) + m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_GAMEMASTER); + else + m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER); UpdateObjectVisibility(); } @@ -12669,7 +12607,7 @@ Unit* Creature::SelectVictim() { --aura; caster = (*aura)->GetCaster(); - if (caster && caster->IsInMap(this) && canAttack(caster) && caster->isInAccessiblePlaceFor(this->ToCreature())) + if (caster && canSeeOrDetect(caster, true) && canAttack(caster) && caster->isInAccessiblePlaceFor(this->ToCreature())) { target = caster; break; @@ -12742,15 +12680,18 @@ Unit* Creature::SelectVictim() return target; } - if (m_invisibilityMask) + + Unit::AuraEffectList const& iAuras = GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY); + if(!iAuras.empty()) { - Unit::AuraEffectList const& iAuras = GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY); for (Unit::AuraEffectList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr) + { if ((*itr)->GetBase()->IsPermanent()) { AI()->EnterEvadeMode(); break; } + } return NULL; } @@ -13093,11 +13034,6 @@ Creature* Unit::GetCreature(WorldObject& object, uint64 guid) return object.GetMap()->GetCreature(guid); } -bool Unit::isVisibleForInState(Player const* u, bool inVisibleList) const -{ - return u->canSeeOrDetect(this, false, inVisibleList, false); -} - uint32 Unit::GetCreatureType() const { if (GetTypeId() == TYPEID_PLAYER) @@ -16182,7 +16118,7 @@ void Unit::UpdateObjectVisibility(bool forced) WorldObject::UpdateObjectVisibility(true); // call MoveInLineOfSight for nearby creatures Trinity::AIRelocationNotifier notifier(*this); - VisitNearbyObject(GetMap()->GetVisibilityDistance(), notifier); + VisitNearbyObject(GetVisibilityRange(), notifier); } } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 5432568289a..b7f0cc36ba4 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -542,12 +542,8 @@ enum DamageEffectType enum UnitVisibility { - VISIBILITY_OFF = 0, // absolute, not detectable, GM-like, can see all other - VISIBILITY_ON = 1, - VISIBILITY_GROUP_STEALTH = 2, // detect chance, seen and can see group members - //VISIBILITY_GROUP_INVISIBILITY = 3, // invisibility, can see and can be seen only another invisible unit or invisible detection unit, set only if not stealthed, and in checks not used (mask used instead) - //VISIBILITY_GROUP_NO_DETECT = 4, // state just at stealth apply for update Grid state. Don't remove, otherwise stealth spells will break - VISIBILITY_RESPAWN = 5 // special totally not detectable visibility for force delete object at respawn command + VISIBILITY_OFF = 0, + VISIBILITY_ON = 1 }; // Value masks for UNIT_FIELD_FLAGS @@ -1083,7 +1079,7 @@ enum PlayerTotemType // delay time next attack to prevent client attack animation problems #define ATTACK_DISPLAY_DELAY 200 -#define MAX_PLAYER_STEALTH_DETECT_RANGE 45.0f // max distance for detection targets by player +#define MAX_PLAYER_STEALTH_DETECT_RANGE 30.0f // max distance for detection targets by player struct SpellProcEventEntry; // used only privately @@ -1194,7 +1190,7 @@ class Unit : public WorldObject bool IsVehicle() const { return m_unitTypeMask & UNIT_MASK_VEHICLE; } uint8 getLevel() const { return uint8(GetUInt32Value(UNIT_FIELD_LEVEL)); } - virtual uint8 getLevelForTarget(Unit const* /*target*/) const { return getLevel(); } + uint8 getLevelForTarget(WorldObject const* /*target*/) const { return getLevel(); } void SetLevel(uint8 lvl); uint8 getRace() const { return GetByteValue(UNIT_FIELD_BYTES_0, 0); } uint32 getRaceMask() const { return 1 << (getRace()-1); } @@ -1640,6 +1636,7 @@ class Unit : public WorldObject uint32 GetAuraCount(uint32 spellId) const; bool HasAura(uint32 spellId, uint64 caster = 0, uint8 reqEffMask = 0) const; bool HasAuraType(AuraType auraType) const; + bool HasAuraTypeWithCaster(AuraType auratype, uint64 caster) const; bool HasAuraTypeWithMiscvalue(AuraType auratype, int32 miscvalue) const; bool HasAuraTypeWithAffectMask(AuraType auratype, SpellEntry const * affectedSpell) const; bool HasAuraTypeWithValue(AuraType auratype, int32 value) const; @@ -1717,8 +1714,6 @@ class Unit : public WorldObject uint32 m_addDmgOnce; uint64 m_SummonSlot[MAX_SUMMON_SLOT]; uint64 m_ObjectSlot[4]; - uint32 m_detectInvisibilityMask; - uint32 m_invisibilityMask; uint32 m_ShapeShiftFormSpellId; ShapeshiftForm m_form; @@ -1768,22 +1763,16 @@ class Unit : public WorldObject void SetFacingToObject(WorldObject* pObject); // Visibility system - UnitVisibility GetVisibility() const { return m_Visibility; } + UnitVisibility GetVisibility() const { return (m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM) > SEC_PLAYER) ? VISIBILITY_OFF : VISIBILITY_ON; } void SetVisibility(UnitVisibility x); // common function for visibility checks for player/creatures with detection code - virtual bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const = 0; - bool isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList = false, bool is3dDistance = true) const; - bool canDetectInvisibilityOf(Unit const* u) const; - bool canDetectStealthOf(Unit const* u, float distance) const; + + bool isValid() const { return WorldObject::isValid(); } + void SetPhaseMask(uint32 newPhaseMask, bool update);// overwrite WorldObject::SetPhaseMask void UpdateObjectVisibility(bool forced = true); - // virtual functions for all world objects types - bool isVisibleForInState(Player const* u, bool inVisibleList) const; - // function for low level grid visibility checks in player/creature cases - virtual bool IsVisibleInGridForPlayer(Player const* pl) const = 0; - SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY]; // Threat related methods @@ -2074,6 +2063,12 @@ class Unit : public WorldObject uint32 m_unitTypeMask; + bool isAlwaysVisibleFor(WorldObject const* seer) const; + bool canSeeAlways(WorldObject const* obj) const { return WorldObject::canSeeAlways(obj); } + + bool isVisibleForInState(WorldObject const* seer) const { return WorldObject::isVisibleForInState(seer); }; + + bool isAlwaysDetectableFor(WorldObject const* seer) const; private: bool IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura * aura, SpellEntry const * procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const *& spellProcEvent); bool HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* triggeredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); @@ -2104,8 +2099,6 @@ class Unit : public WorldObject Spell* m_currentSpells[CURRENT_MAX_SPELL]; - UnitVisibility m_Visibility; - Diminishing m_Diminishing; // Manage all Units threatening us // ThreatManager m_ThreatManager; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index 663743e2c2e..2bb846c9533 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -117,7 +117,7 @@ inline void CreatureUnitRelocationWorker(Creature* c, Unit* u) return; if (c->HasReactState(REACT_AGGRESSIVE) && !c->hasUnitState(UNIT_STAT_SIGHTLESS)) - if (c->_IsWithinDist(u, c->m_SightDistance, true) && c->IsAIEnabled) + if (c->IsAIEnabled && c->canSeeOrDetect(u, false, true)) c->AI()->MoveInLineOfSight_Safe(u); } @@ -249,7 +249,7 @@ MessageDistDeliverer::Visit(PlayerMapType &m) if (!target->InSamePhase(i_phaseMask)) continue; - if (target->GetExactDistSq(i_source) > i_distSq) + if (target->GetExactDist2dSq(i_source) > i_distSq) continue; // Send packet to all who are sharing the player's vision @@ -274,7 +274,7 @@ MessageDistDeliverer::Visit(CreatureMapType &m) if (!iter->getSource()->InSamePhase(i_phaseMask)) continue; - if (iter->getSource()->GetExactDistSq(i_source) > i_distSq) + if (iter->getSource()->GetExactDist2dSq(i_source) > i_distSq) continue; // Send packet to all who are sharing the creature's vision @@ -296,7 +296,7 @@ MessageDistDeliverer::Visit(DynamicObjectMapType &m) if (!iter->getSource()->InSamePhase(i_phaseMask)) continue; - if (iter->getSource()->GetExactDistSq(i_source) > i_distSq) + if (iter->getSource()->GetExactDist2dSq(i_source) > i_distSq) continue; if (IS_PLAYER_GUID(iter->getSource()->GetCasterGUID())) diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 10f9e90b63e..f0a6337ec52 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -143,6 +143,9 @@ namespace Trinity if (plr == i_source || (team && plr->GetTeam() != team) || skipped_receiver == plr) return; + if (!plr->HaveAtClient(i_source)) + return; + plr->GetSession()->SendPacket(i_message); } }; @@ -809,7 +812,7 @@ namespace Trinity return u->isAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u) - && u->isVisibleForOrDetect(i_funit, false); + && u->canSeeOrDetect(i_funit); } private: WorldObject const* i_obj; @@ -871,7 +874,7 @@ namespace Trinity bool operator()(Unit* u) { if (u->isTargetableForAttack() && i_obj->IsWithinDistInMap(u, i_range) && - !i_funit->IsFriendlyTo(u) && u->isVisibleForOrDetect(i_funit,false)) + !i_funit->IsFriendlyTo(u) && u->canSeeOrDetect(i_funit)) { i_range = i_obj->GetDistance(u); // use found unit range as new range limit for next check return true; @@ -957,10 +960,12 @@ namespace Trinity bool operator()(Unit* u) { return !u->isAlive(); } }; + /* struct AnyStealthedCheck { bool operator()(Unit* u) { return u->GetVisibility() == VISIBILITY_GROUP_STEALTH; } }; + */ // Creature checks @@ -1002,6 +1007,9 @@ namespace Trinity if (!me->IsWithinDistInMap(u, m_range)) return false; + if (!me->canSeeOrDetect(u)) + return false; + if (m_force) { if (!me->canAttack(u)) diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h index ad84384b0f9..9f2ff9be790 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h +++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h @@ -42,8 +42,8 @@ Trinity::VisibleNotifier::Visit(GridRefManager<T> &m) inline void Trinity::ObjectUpdater::Visit(CreatureMapType &m) { - for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) - if (iter->getSource()->IsInWorld() && !iter->getSource()->isSpiritService()) + for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + if (iter->getSource()->IsInWorld()) iter->getSource()->Update(i_timeDiff); } diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp index 604bb57b758..4ee7fd69f76 100755 --- a/src/server/game/Grids/ObjectGridLoader.cpp +++ b/src/server/game/Grids/ObjectGridLoader.cpp @@ -103,8 +103,6 @@ template<> void addUnitState(Creature *obj, CellPair const& cell_pair) Cell cell(cell_pair); obj->SetCurrentCell(cell); - if (obj->isSpiritService()) - obj->setDeathState(DEAD); } template <class T> diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 54a4779e06f..11561e9341a 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1147,9 +1147,9 @@ void Group::UpdatePlayerOutOfRange(Player* pPlayer) for (GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { - player = itr->getSource(); - if (player && player != pPlayer && !pPlayer->isVisibleFor(player)) - player->GetSession()->SendPacket(&data); + if (player = itr->getSource()) + if (!player->canSeeOrDetect(pPlayer)) + player->GetSession()->SendPacket(&data); } } diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index fc2b5ecb080..184e85b6c04 100755 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -415,7 +415,7 @@ bool Map::Add(Player *player) SendInitTransports(player); player->m_clientGUIDs.clear(); - player->UpdateObjectVisibility(true); + player->UpdateObjectVisibility(false); sScriptMgr.OnPlayerEnterMap(this, player); return true; @@ -466,16 +466,43 @@ bool Map::loaded(const GridPair &p) const return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord)); } -void Map::Update(const uint32 &t_diff) +void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Trinity::ObjectUpdater, GridTypeMapContainer> &gridVisitor, TypeContainerVisitor<Trinity::ObjectUpdater, WorldTypeMapContainer> &worldVisitor) { - /// update players at tick - for (m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter) + CellPair standing_cell(Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY())); + + // Check for correctness of standing_cell, it also avoids problems with update_cell + if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) + return; + + // the overloaded operators handle range checking + // so there's no need for range checking inside the loop + CellPair begin_cell(standing_cell), end_cell(standing_cell); + //lets update mobs/objects in ALL visible cells around object! + CellArea area = Cell::CalculateCellArea(*obj, obj->GetGridActivationRange()); + area.ResizeBorders(begin_cell, end_cell); + + for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) { - Player* plr = m_mapRefIter->getSource(); - if (plr && plr->IsInWorld()) - plr->Update(t_diff); + for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) + { + // marked cells are those that have been visited + // don't visit the same cell twice + uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; + if (isCellMarked(cell_id)) + continue; + + markCell(cell_id); + CellPair pair(x,y); + Cell cell(pair); + cell.data.Part.reserved = CENTER_DISTRICT; + cell.Visit(pair, gridVisitor, *this); + cell.Visit(pair, worldVisitor, *this); + } } +} +void Map::Update(const uint32 &t_diff) +{ /// update active cells around players and active objects resetMarkedCells(); @@ -494,87 +521,22 @@ void Map::Update(const uint32 &t_diff) if (!plr->IsInWorld()) continue; - CellPair standing_cell(Trinity::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY())); - - // Check for correctness of standing_cell, it also avoids problems with update_cell - if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - continue; - - // the overloaded operators handle range checking - // so ther's no need for range checking inside the loop - CellPair begin_cell(standing_cell), end_cell(standing_cell); - //lets update mobs/objects in ALL visible cells around player! - CellArea area = Cell::CalculateCellArea(*plr, GetVisibilityDistance()); - area.ResizeBorders(begin_cell, end_cell); + // update players at tick + plr->Update(t_diff); - for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) - { - for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) - { - // marked cells are those that have been visited - // don't visit the same cell twice - uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; - if (!isCellMarked(cell_id)) - { - markCell(cell_id); - CellPair pair(x,y); - Cell cell(pair); - cell.data.Part.reserved = CENTER_DISTRICT; - //cell.SetNoCreate(); - cell.Visit(pair, grid_object_update, *this); - cell.Visit(pair, world_object_update, *this); - } - } - } + VisitNearbyCellsOf(plr, grid_object_update, world_object_update); } - // non-player active objects - if (!m_activeNonPlayers.empty()) + // non-player active objects, increasing iterator in the loop in case of object removal + for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();) { - for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();) - { - // skip not in world - WorldObject* obj = *m_activeNonPlayersIter; - - // step before processing, in this case if Map::Remove remove next object we correctly - // step to next-next, and if we step to end() then newly added objects can wait next update. - ++m_activeNonPlayersIter; - - if (!obj->IsInWorld()) - continue; - - CellPair standing_cell(Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY())); + WorldObject* obj = *m_activeNonPlayersIter; + ++m_activeNonPlayersIter; - // Check for correctness of standing_cell, it also avoids problems with update_cell - if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) - continue; - - // the overloaded operators handle range checking - // so ther's no need for range checking inside the loop - CellPair begin_cell(standing_cell), end_cell(standing_cell); - begin_cell << 1; begin_cell -= 1; // upper left - end_cell >> 1; end_cell += 1; // lower right + if (!obj->IsInWorld()) + continue; - for (uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x) - { - for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y) - { - // marked cells are those that have been visited - // don't visit the same cell twice - uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x; - if (!isCellMarked(cell_id)) - { - markCell(cell_id); - CellPair pair(x,y); - Cell cell(pair); - cell.data.Part.reserved = CENTER_DISTRICT; - //cell.SetNoCreate(); - cell.Visit(pair, grid_object_update, *this); - cell.Visit(pair, world_object_update, *this); - } - } - } - } + VisitNearbyCellsOf(obj, grid_object_update, world_object_update); } ///- Process necessary scripts @@ -635,7 +597,7 @@ void Map::ProcessRelocationNotifies(const uint32 & diff) Cell cell(pair); cell.SetNoCreate(); - Trinity::DelayedUnitRelocation cell_relocation(cell, pair, *this, GetVisibilityDistance()); + Trinity::DelayedUnitRelocation cell_relocation(cell, pair, *this, MAX_VISIBILITY_DISTANCE); TypeContainerVisitor<Trinity::DelayedUnitRelocation, GridTypeMapContainer > grid_object_relocation(cell_relocation); TypeContainerVisitor<Trinity::DelayedUnitRelocation, WorldTypeMapContainer > world_object_relocation(cell_relocation); Visit(cell, grid_object_relocation); @@ -1881,7 +1843,7 @@ void Map::UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair) cell.SetNoCreate(); Trinity::VisibleChangesNotifier notifier(*obj); TypeContainerVisitor<Trinity::VisibleChangesNotifier, WorldTypeMapContainer > player_notifier(notifier); - cell.Visit(cellpair, player_notifier, *this, *obj, GetVisibilityDistance()); + cell.Visit(cellpair, player_notifier, *this, *obj, obj->GetVisibilityRange()); } void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair) @@ -1892,8 +1854,8 @@ void Map::UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpai cell.SetNoCreate(); TypeContainerVisitor<Trinity::VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier); TypeContainerVisitor<Trinity::VisibleNotifier, GridTypeMapContainer > grid_notifier(notifier); - cell.Visit(cellpair, world_notifier, *this, *player, GetVisibilityDistance()); - cell.Visit(cellpair, grid_notifier, *this, *player, GetVisibilityDistance()); + cell.Visit(cellpair, world_notifier, *this, *player, player->GetVisibilityRange()); + cell.Visit(cellpair, grid_notifier, *this, *player, player->GetVisibilityRange()); // send data notifier.SendToSelf(); @@ -2117,7 +2079,7 @@ bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); //we must find visible range in cells so we unload only non-visible cells... - float viewDist = GetVisibilityDistance(); + float viewDist = GetVisibilityRange(); int cell_range = (int)ceilf(viewDist / SIZE_OF_GRID_CELL) + 1; cell_min << cell_range; diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 534115e7e0d..0bff446b67d 100755 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -50,6 +50,7 @@ struct Position; class Battleground; class MapInstanced; class InstanceMap; +namespace Trinity { struct ObjectUpdater; } struct ScriptAction { @@ -269,9 +270,10 @@ class Map : public GridRefManager<NGridType> template<class T> void Add(T *); template<class T> void Remove(T *, bool); + void VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Trinity::ObjectUpdater, GridTypeMapContainer> &gridVisitor, TypeContainerVisitor<Trinity::ObjectUpdater, WorldTypeMapContainer> &worldVisitor); virtual void Update(const uint32&); - float GetVisibilityDistance() const { return m_VisibleDistance; } + float GetVisibilityRange() const { return m_VisibleDistance; } //function for setting up visibility distance for maps on per-type/per-Id basis virtual void InitVisibilityDistance(); diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 0e87bd388e9..859b7ad4aaf 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -980,6 +980,46 @@ enum SpellCastResult SPELL_CAST_OK = 255 // custom value, don't must be send to client }; +enum StealthType +{ + STEALTH_GENERAL = 0, + STEALTH_TRAP = 1, + + TOTAL_STEALTH_TYPES = 2 +}; + +enum InvisibilityType +{ + INVISIBILITY_GENERAL = 0, + INVISIBILITY_UNK1 = 1, + INVISIBILITY_UNK2 = 2, + INVISIBILITY_TRAP = 3, + INVISIBILITY_UNK4 = 4, + INVISIBILITY_UNK5 = 5, + INVISIBILITY_DRUNK = 6, + INVISIBILITY_UNK7 = 7, + INVISIBILITY_UNK8 = 8, + INVISIBILITY_UNK9 = 9, + INVISIBILITY_UNK10 = 10, + INVISIBILITY_UNK11 = 11, + + TOTAL_INVISIBILITY_TYPES = 12 +}; + +enum ServerSideVisibilityType +{ + SERVERSIDE_VISIBILITY_GM = 0, + SERVERSIDE_VISIBILITY_GHOST = 1, + + TOTAL_SERVERSIDE_VISIBILITY_TYPES = 2 +}; + +enum GhostVisibilityType +{ + GHOST_VISIBILITY_ALIVE = 0x1, + GHOST_VISIBILITY_GHOST = 0x2 +}; + // Spell aura states enum AuraState { // (C) used in caster aura state (T) used in target aura state diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index aedb4d2c303..e23906b355e 100755 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -71,9 +71,9 @@ enum AuraType SPELL_AURA_MOD_DAMAGE_TAKEN = 14, SPELL_AURA_DAMAGE_SHIELD = 15, SPELL_AURA_MOD_STEALTH = 16, - SPELL_AURA_MOD_DETECT = 17, + SPELL_AURA_MOD_STEALTH_DETECT = 17, SPELL_AURA_MOD_INVISIBILITY = 18, - SPELL_AURA_MOD_INVISIBILITY_DETECTION = 19, + SPELL_AURA_MOD_INVISIBILITY_DETECT = 19, SPELL_AURA_OBS_MOD_HEALTH = 20, //20,21 unofficial SPELL_AURA_OBS_MOD_POWER = 21, SPELL_AURA_MOD_RESISTANCE = 22, @@ -358,7 +358,7 @@ enum AuraType SPELL_AURA_SCHOOL_HEAL_ABSORB = 301, SPELL_AURA_302 = 302, SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE = 303, - SPELL_AURA_304 = 304, + SPELL_AURA_MOD_FAKE_INEBRIATE = 304, SPELL_AURA_MOD_MINIMUM_SPEED = 305, SPELL_AURA_306 = 306, SPELL_AURA_HEAL_ABSORB_TEST = 307, diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 40f8f10c8f1..796a26f6fc8 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -69,9 +69,9 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, // 14 SPELL_AURA_MOD_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus &AuraEffect::HandleNoImmediateEffect, // 15 SPELL_AURA_DAMAGE_SHIELD implemented in Unit::DoAttackDamage &AuraEffect::HandleModStealth, // 16 SPELL_AURA_MOD_STEALTH - &AuraEffect::HandleNoImmediateEffect, // 17 SPELL_AURA_MOD_DETECT implement in GameObject::canDetectTrap and Unit::canDetectStealthOf - &AuraEffect::HandleInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY - &AuraEffect::HandleInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION + &AuraEffect::HandleModStealthDetect, // 17 SPELL_AURA_MOD_DETECT + &AuraEffect::HandleModInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY + &AuraEffect::HandleModInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION &AuraEffect::HandleNoImmediateEffect, // 20 SPELL_AURA_OBS_MOD_HEALTH implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, // 21 SPELL_AURA_OBS_MOD_POWER implemented in AuraEffect::PeriodicTick &AuraEffect::HandleAuraModResistance, // 22 SPELL_AURA_MOD_RESISTANCE @@ -206,7 +206,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED &AuraEffect::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance &AuraEffect::HandleNoImmediateEffect, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT - &AuraEffect::HandleNoImmediateEffect, //154 SPELL_AURA_MOD_STEALTH_LEVEL + &AuraEffect::HandleModStealthLevel, //154 SPELL_AURA_MOD_STEALTH_LEVEL &AuraEffect::HandleNoImmediateEffect, //155 SPELL_AURA_MOD_WATER_BREATHING &AuraEffect::HandleNoImmediateEffect, //156 SPELL_AURA_MOD_REPUTATION_GAIN &AuraEffect::HandleNULL, //157 SPELL_AURA_PET_DAMAGE_MULTI @@ -356,7 +356,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //301 SPELL_AURA_SCHOOL_HEAL_ABSORB implemented in Unit::CalcHealAbsorb &AuraEffect::HandleNULL, //302 0 spells in 3.3.5 &AuraEffect::HandleNoImmediateEffect, //303 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus - &AuraEffect::HandleUnused, //304 clientside + &AuraEffect::HandleAuraModFakeInebriation, //304 SPELL_AURA_MOD_DRUNK &AuraEffect::HandleAuraModIncreaseSpeed, //305 SPELL_AURA_MOD_MINIMUM_SPEED &AuraEffect::HandleNULL, //306 0 spells in 3.3.5 &AuraEffect::HandleNULL, //307 0 spells in 3.3.5 @@ -2685,40 +2685,40 @@ void AuraEffect::HandleShapeshiftBoosts(Unit * target, bool apply) const /*** VISIBILITY & PHASES ***/ /**************************************/ -void AuraEffect::HandleInvisibilityDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModInvisibilityDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit * target = aurApp->GetTarget(); + InvisibilityType type = InvisibilityType(GetMiscValue()); if (apply) { - target->m_detectInvisibilityMask |= (1 << GetMiscValue()); + target->m_invisibilityDetect.AddFlag(type); + target->m_invisibilityDetect.AddValue(type, GetAmount()); } else { - // recalculate value at modifier remove (current aura already removed) - target->m_detectInvisibilityMask = 0; - Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION); - for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - target->m_detectInvisibilityMask |= (1 << GetMiscValue()); + if (!target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY_DETECT)) + target->m_invisibilityDetect.DelFlag(type); + + target->m_invisibilityDetect.AddValue(type, -GetAmount()); } - if (target->GetTypeId() == TYPEID_PLAYER) - target->UpdateObjectVisibility(); + + target->UpdateObjectVisibility(); } -void AuraEffect::HandleInvisibility(AuraApplication const * aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModInvisibility(AuraApplication const * aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit * target = aurApp->GetTarget(); + InvisibilityType type = InvisibilityType(GetMiscValue()); if (apply) { - target->m_invisibilityMask |= (1 << GetMiscValue()); - if (mode & AURA_EFFECT_HANDLE_REAL) { // drop flag at invisibiliy in bg @@ -2729,23 +2729,49 @@ void AuraEffect::HandleInvisibility(AuraApplication const * aurApp, uint8 mode, if (target->GetTypeId() == TYPEID_PLAYER) target->SetFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); - target->UpdateObjectVisibility(); + target->m_invisibility.AddFlag(type); + target->m_invisibility.AddValue(type, GetAmount()); + } + else + { + if (!target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY)) + { + // if not have different invisibility auras. + // remove glow vision + if (target->GetTypeId() == TYPEID_PLAYER) + target->RemoveFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); + + target->m_invisibility.DelFlag(type); + } + + target->m_invisibility.AddValue(type, -GetAmount()); + } + + target->UpdateObjectVisibility(); +} + +void AuraEffect::HandleModStealthDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit * target = aurApp->GetTarget(); + StealthType type = StealthType(GetMiscValue()); + + if (apply) + { + target->m_stealthDetect.AddFlag(type); + target->m_stealthDetect.AddValue(type, GetAmount()); } else { - // recalculate value at modifier remove (current aura already removed) - target->m_invisibilityMask = 0; - Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY); - for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - target->m_invisibilityMask |= (1 << GetMiscValue()); - - // if not have different invisibility auras. - // remove glow vision - if (!target->m_invisibilityMask && target->GetTypeId() == TYPEID_PLAYER) - target->RemoveFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); - - target->UpdateObjectVisibility(); + if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH_DETECT)) + target->m_stealthDetect.DelFlag(type); + + target->m_stealthDetect.AddValue(type, -GetAmount()); } + + target->UpdateObjectVisibility(); } void AuraEffect::HandleModStealth(AuraApplication const * aurApp, uint8 mode, bool apply) const @@ -2754,6 +2780,7 @@ void AuraEffect::HandleModStealth(AuraApplication const * aurApp, uint8 mode, bo return; Unit * target = aurApp->GetTarget(); + StealthType type = StealthType(GetMiscValue()); if (apply) { @@ -2763,23 +2790,44 @@ void AuraEffect::HandleModStealth(AuraApplication const * aurApp, uint8 mode, bo target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); } + target->m_stealth.AddFlag( type); + target->m_stealth.AddValue(type, GetAmount()); + target->SetStandFlags(UNIT_STAND_FLAGS_CREEP); if (target->GetTypeId() == TYPEID_PLAYER) target->SetFlag(PLAYER_FIELD_BYTES2, 0x2000); - - // apply only if not in GM invisibility (and overwrite invisibility state) - if (target->GetVisibility() != VISIBILITY_OFF) - target->SetVisibility(VISIBILITY_GROUP_STEALTH); } - else if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) // if last SPELL_AURA_MOD_STEALTH + else { - target->RemoveStandFlags(UNIT_STAND_FLAGS_CREEP); - if (target->GetTypeId() == TYPEID_PLAYER) - target->RemoveFlag(PLAYER_FIELD_BYTES2, 0x2000); + target->m_stealth.AddValue(type, -GetAmount()); - if (target->GetVisibility() != VISIBILITY_OFF) - target->SetVisibility(VISIBILITY_ON); + if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) // if last SPELL_AURA_MOD_STEALTH + { + target->m_stealth.DelFlag(type); + + target->RemoveStandFlags(UNIT_STAND_FLAGS_CREEP); + if (target->GetTypeId() == TYPEID_PLAYER) + target->RemoveFlag(PLAYER_FIELD_BYTES2, 0x2000); + } } + + target->UpdateObjectVisibility(); +} + +void AuraEffect::HandleModStealthLevel(AuraApplication const * aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit * target = aurApp->GetTarget(); + StealthType type = StealthType(GetMiscValue()); + + if (apply) + target->m_stealth.AddValue(type, GetAmount()); + else + target->m_stealth.AddValue(type, -GetAmount()); + + target->UpdateObjectVisibility(); } void AuraEffect::HandleSpiritOfRedemption(AuraApplication const * aurApp, uint8 mode, bool apply) const @@ -2823,12 +2871,19 @@ void AuraEffect::HandleAuraGhost(AuraApplication const * aurApp, uint8 mode, boo return; if (apply) + { target->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST); + target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); + target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); + } else { if (target->HasAuraType(SPELL_AURA_GHOST)) return; + target->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST); + target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); + target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); } } @@ -3315,9 +3370,9 @@ void AuraEffect::HandleFeignDeath(AuraApplication const * aurApp, uint8 mode, bo */ UnitList targets; - Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetMap()->GetVisibilityDistance()); + Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetMap()->GetVisibilityRange()); Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, targets, u_check); - target->VisitNearbyObject(target->GetMap()->GetVisibilityDistance(), searcher); + target->VisitNearbyObject(target->GetMap()->GetVisibilityRange(), searcher); for (UnitList::iterator iter = targets.begin(); iter != targets.end(); ++iter) { if (!(*iter)->hasUnitState(UNIT_STAT_CASTING)) @@ -3601,11 +3656,11 @@ void AuraEffect::HandleAuraModStalked(AuraApplication const * aurApp, uint8 mode else { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(GetAuraType())) - return; - - target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT); + if (!target->HasAuraType(GetAuraType())) + target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT); } + + target->UpdateObjectVisibility(); } void AuraEffect::HandleAuraUntrackable(AuraApplication const * aurApp, uint8 mode, bool apply) const @@ -4022,7 +4077,7 @@ void AuraEffect::HandleModPossessPet(AuraApplication const * aurApp, uint8 mode, { pet->RemoveCharmedBy(caster); - if (!pet->IsWithinDistInMap(caster, pet->GetMap()->GetVisibilityDistance())) + if (!pet->IsWithinDistInMap(caster, pet->GetMap()->GetVisibilityRange())) pet->Remove(PET_SAVE_NOT_IN_SLOT, true); else { @@ -6349,6 +6404,46 @@ void AuraEffect::HandleAuraOpenStable(AuraApplication const * aurApp, uint8 mode // client auto close stable dialog at !apply aura } +void AuraEffect::HandleAuraModFakeInebriation(AuraApplication const * aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit* target = aurApp->GetTarget(); + + if (apply) + { + target->m_invisibilityDetect.AddFlag( INVISIBILITY_DRUNK); + target->m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, GetAmount()); + + if (target->GetTypeId() == TYPEID_PLAYER) + { + int32 oldval = target->ToPlayer()->GetInt32Value(PLAYER_FAKE_INEBRIATION); + target->ToPlayer()->SetInt32Value(PLAYER_FAKE_INEBRIATION, oldval + GetAmount()); + } + } + else + { + bool removeDetect = !target->HasAuraType(SPELL_AURA_MOD_FAKE_INEBRIATE); + + target->m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, -GetAmount()); + + if (target->GetTypeId() == TYPEID_PLAYER) + { + int32 oldval = target->ToPlayer()->GetInt32Value(PLAYER_FAKE_INEBRIATION); + target->ToPlayer()->SetInt32Value(PLAYER_FAKE_INEBRIATION, oldval - GetAmount()); + + if (removeDetect) + removeDetect = !target->ToPlayer()->GetDrunkValue(); + } + + if (removeDetect) + target->m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK); + } + + target->UpdateObjectVisibility(); +} + void AuraEffect::HandleAuraSetVehicle(AuraApplication const * aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 0673bee0185..3612d9ad6be 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -108,9 +108,11 @@ class AuraEffect // aura type not have immediate effect at add/remove and handled by ID in other code place } // visibility & phases - void HandleInvisibilityDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const; - void HandleInvisibility(AuraApplication const * aurApp, uint8 mode, bool apply) const; + void HandleModInvisibilityDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const; + void HandleModInvisibility(AuraApplication const * aurApp, uint8 mode, bool apply) const; void HandleModStealth(AuraApplication const * aurApp, uint8 mode, bool apply) const; + void HandleModStealthLevel(AuraApplication const * aurApp, uint8 mode, bool apply) const; + void HandleModStealthDetect(AuraApplication const * aurApp, uint8 mode, bool apply) const; void HandleSpiritOfRedemption(AuraApplication const * aurApp, uint8 mode, bool apply) const; void HandleAuraGhost(AuraApplication const * aurApp, uint8 mode, bool apply) const; void HandlePhase(AuraApplication const * aurApp, uint8 mode, bool apply) const; @@ -257,6 +259,7 @@ class AuraEffect void HandleAuraLinked(AuraApplication const * aurApp, uint8 mode, bool apply) const; void HandleAuraOpenStable(AuraApplication const * aurApp, uint8 mode, bool apply) const; void HandleAuraSetVehicle(AuraApplication const * aurApp, uint8 mode, bool apply) const; + void HandleAuraModFakeInebriation(AuraApplication const * aurApp, uint8 mode, bool apply) const; }; #endif
\ No newline at end of file diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 53514bd622e..f912a6f20b5 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1396,18 +1396,6 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool if (!m_caster->IsFriendlyTo(unit)) { - // reset damage to 0 if target has Invisibility and isn't visible for caster - // I do not think this is a correct way to fix it. Sanctuary effect should make all delayed spells invalid - // for delayed spells ignore not visible explicit target - if (m_spellInfo->speed > 0.0f && unit == m_targets.getUnitTarget() - && (unit->m_invisibilityMask || m_caster->m_invisibilityMask) - && !m_caster->canSeeOrDetect(unit, true)) - { - // that was causing CombatLog errors - // return SPELL_MISS_EVADE; - return SPELL_MISS_MISS; // miss = do not send anything here - } - unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL); //TODO: This is a hack. But we do not know what types of stealth should be interrupted by CC if ((m_customAttr & SPELL_ATTR_CU_AURA_CC) && unit->IsControlledByPlayer()) @@ -1793,7 +1781,7 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin break; while ((m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE && !m_caster->isInFrontInMap(*next, max_range)) - || !m_caster->canSeeOrDetect(*next, false) + || !m_caster->canSeeOrDetect(*next) || !cur->IsWithinLOSInMap(*next)) { ++next; @@ -3118,9 +3106,7 @@ void Spell::cast(bool skipCheck) { // three check: prepare, cast (m_casttime > 0), hit (delayed) if (m_casttime && target->isAlive() - && (target->m_invisibilityMask || m_caster->m_invisibilityMask - || target->GetVisibility() == VISIBILITY_GROUP_STEALTH) - && !target->IsFriendlyTo(m_caster) && !m_caster->canSeeOrDetect(target, true)) + && !target->IsFriendlyTo(m_caster) && !m_caster->canSeeOrDetect(target)) { SendCastResult(SPELL_FAILED_BAD_TARGETS); SendInterrupted(0); @@ -4846,8 +4832,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (target->hasUnitState(UNIT_STAT_UNATTACKABLE)) return SPELL_FAILED_BAD_TARGETS; - if (!m_IsTriggeredSpell && (target->HasAuraType(SPELL_AURA_MOD_STEALTH) - || target->m_invisibilityMask) && !m_caster->canSeeOrDetect(target, true)) + if (!m_IsTriggeredSpell && !m_caster->canSeeOrDetect(target)) return SPELL_FAILED_BAD_TARGETS; if (m_caster->GetTypeId() == TYPEID_PLAYER) @@ -6014,7 +5999,7 @@ SpellCastResult Spell::CheckItems() TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck>, GridTypeMapContainer > object_checker(checker); Map& map = *m_caster->GetMap(); - cell.Visit(p, object_checker, map, *m_caster, map.GetVisibilityDistance()); + cell.Visit(p, object_checker, map, *m_caster, m_caster->GetVisibilityRange()); if (!ok) return SPELL_FAILED_REQUIRES_SPELL_FOCUS; diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 2a74e21f817..e7edb82a4c7 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -752,7 +752,7 @@ namespace Trinity { Unit *target = (Unit*)itr->getSource(); - if (!target->InSamePhase(i_source)) + if (!i_source->canSeeOrDetect(target, true)) continue; switch (i_TargetType) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index b0e7557a0ed..b2fc0ec4032 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -5327,9 +5327,9 @@ void Spell::EffectSanctuary(SpellEffIndex /*effIndex*/) return; std::list<Unit*> targets; - Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, m_caster->GetMap()->GetVisibilityDistance()); + Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(unitTarget, unitTarget, m_caster->GetMap()->GetVisibilityRange()); Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(unitTarget, targets, u_check); - unitTarget->VisitNearbyObject(m_caster->GetMap()->GetVisibilityDistance(), searcher); + unitTarget->VisitNearbyObject(m_caster->GetMap()->GetVisibilityRange(), searcher); for (std::list<Unit*>::iterator iter = targets.begin(); iter != targets.end(); ++iter) { if (!(*iter)->hasUnitState(UNIT_STAT_CASTING)) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 2c7790de35c..30fd869def1 100755 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -79,11 +79,6 @@ volatile uint32 World::m_worldLoopCounter = 0; float World::m_MaxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE; float World::m_MaxVisibleDistanceInInstances = DEFAULT_VISIBILITY_INSTANCE; float World::m_MaxVisibleDistanceInBGArenas = DEFAULT_VISIBILITY_BGARENAS; -float World::m_MaxVisibleDistanceForObject = DEFAULT_VISIBILITY_DISTANCE; - -float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE; -float World::m_VisibleUnitGreyDistance = 0; -float World::m_VisibleObjectGreyDistance = 0; int32 World::m_visibility_notify_periodOnContinents = DEFAULT_VISIBILITY_NOTIFY_PERIOD; int32 World::m_visibility_notify_periodInInstances = DEFAULT_VISIBILITY_NOTIFY_PERIOD; @@ -1057,19 +1052,6 @@ void World::LoadConfigSettings(bool reload) if (m_int_configs[CONFIG_GUILD_BANK_EVENT_LOG_COUNT] < GUILD_BANKLOG_MAX_RECORDS) m_int_configs[CONFIG_GUILD_BANK_EVENT_LOG_COUNT] = GUILD_BANKLOG_MAX_RECORDS; - m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1); - if (m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) - { - sLog.outError("Visibility.Distance.Grey.Unit can't be greater %f",MAX_VISIBILITY_DISTANCE); - m_VisibleUnitGreyDistance = MAX_VISIBILITY_DISTANCE; - } - m_VisibleObjectGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Object", 10); - if (m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE) - { - sLog.outError("Visibility.Distance.Grey.Object can't be greater %f",MAX_VISIBILITY_DISTANCE); - m_VisibleObjectGreyDistance = MAX_VISIBILITY_DISTANCE; - } - //visibility on continents m_MaxVisibleDistanceOnContinents = sConfig.GetFloatDefault("Visibility.Distance.Continents", DEFAULT_VISIBILITY_DISTANCE); if (m_MaxVisibleDistanceOnContinents < 45*sWorld.getRate(RATE_CREATURE_AGGRO)) @@ -1077,10 +1059,10 @@ void World::LoadConfigSettings(bool reload) sLog.outError("Visibility.Distance.Continents can't be less max aggro radius %f", 45*sWorld.getRate(RATE_CREATURE_AGGRO)); m_MaxVisibleDistanceOnContinents = 45*sWorld.getRate(RATE_CREATURE_AGGRO); } - else if (m_MaxVisibleDistanceOnContinents + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) + else if (m_MaxVisibleDistanceOnContinents > MAX_VISIBILITY_DISTANCE) { - sLog.outError("Visibility.Distance.Continents can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); - m_MaxVisibleDistanceOnContinents = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance; + sLog.outError("Visibility.Distance.Continents can't be greater %f",MAX_VISIBILITY_DISTANCE); + m_MaxVisibleDistanceOnContinents = MAX_VISIBILITY_DISTANCE; } //visibility in instances @@ -1090,10 +1072,10 @@ void World::LoadConfigSettings(bool reload) sLog.outError("Visibility.Distance.Instances can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO)); m_MaxVisibleDistanceInInstances = 45*sWorld.getRate(RATE_CREATURE_AGGRO); } - else if (m_MaxVisibleDistanceInInstances + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) + else if (m_MaxVisibleDistanceInInstances > MAX_VISIBILITY_DISTANCE) { - sLog.outError("Visibility.Distance.Instances can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); - m_MaxVisibleDistanceInInstances = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance; + sLog.outError("Visibility.Distance.Instances can't be greater %f",MAX_VISIBILITY_DISTANCE); + m_MaxVisibleDistanceInInstances = MAX_VISIBILITY_DISTANCE; } //visibility in BG/Arenas @@ -1103,28 +1085,10 @@ void World::LoadConfigSettings(bool reload) sLog.outError("Visibility.Distance.BGArenas can't be less max aggro radius %f",45*sWorld.getRate(RATE_CREATURE_AGGRO)); m_MaxVisibleDistanceInBGArenas = 45*sWorld.getRate(RATE_CREATURE_AGGRO); } - else if (m_MaxVisibleDistanceInBGArenas + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) - { - sLog.outError("Visibility.Distance.BGArenas can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance); - m_MaxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance; - } - - m_MaxVisibleDistanceForObject = sConfig.GetFloatDefault("Visibility.Distance.Object", DEFAULT_VISIBILITY_DISTANCE); - if (m_MaxVisibleDistanceForObject < INTERACTION_DISTANCE) - { - sLog.outError("Visibility.Distance.Object can't be less max aggro radius %f",float(INTERACTION_DISTANCE)); - m_MaxVisibleDistanceForObject = INTERACTION_DISTANCE; - } - else if (m_MaxVisibleDistanceForObject + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE) - { - sLog.outError("Visibility.Distance.Object can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance); - m_MaxVisibleDistanceForObject = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance; - } - m_MaxVisibleDistanceInFlight = sConfig.GetFloatDefault("Visibility.Distance.InFlight", DEFAULT_VISIBILITY_DISTANCE); - if (m_MaxVisibleDistanceInFlight + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE) + else if (m_MaxVisibleDistanceInBGArenas > MAX_VISIBILITY_DISTANCE) { - sLog.outError("Visibility.Distance.InFlight can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance); - m_MaxVisibleDistanceInFlight = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance; + sLog.outError("Visibility.Distance.BGArenas can't be greater %f",MAX_VISIBILITY_DISTANCE); + m_MaxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE; } m_visibility_notify_periodOnContinents = sConfig.GetIntDefault("Visibility.Notify.Period.OnContinents", DEFAULT_VISIBILITY_NOTIFY_PERIOD); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 1dd06725768..92e53e7ef82 100755 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -705,11 +705,6 @@ class World static float GetMaxVisibleDistanceOnContinents() { return m_MaxVisibleDistanceOnContinents; } static float GetMaxVisibleDistanceInInstances() { return m_MaxVisibleDistanceInInstances; } static float GetMaxVisibleDistanceInBGArenas() { return m_MaxVisibleDistanceInBGArenas; } - static float GetMaxVisibleDistanceForObject() { return m_MaxVisibleDistanceForObject; } - - static float GetMaxVisibleDistanceInFlight() { return m_MaxVisibleDistanceInFlight; } - static float GetVisibleUnitGreyDistance() { return m_VisibleUnitGreyDistance; } - static float GetVisibleObjectGreyDistance() { return m_VisibleObjectGreyDistance; } static int32 GetVisibilityNotifyPeriodOnContinents(){ return m_visibility_notify_periodOnContinents; } static int32 GetVisibilityNotifyPeriodInInstances() { return m_visibility_notify_periodInInstances; } @@ -801,11 +796,6 @@ class World static float m_MaxVisibleDistanceOnContinents; static float m_MaxVisibleDistanceInInstances; static float m_MaxVisibleDistanceInBGArenas; - static float m_MaxVisibleDistanceForObject; - - static float m_MaxVisibleDistanceInFlight; - static float m_VisibleUnitGreyDistance; - static float m_VisibleObjectGreyDistance; static int32 m_visibility_notify_periodOnContinents; static int32 m_visibility_notify_periodInInstances; diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 80bca7e28e8..820a36f5481 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -517,6 +517,46 @@ class spell_gen_animal_blood : public SpellScriptLoader } }; +class spell_gen_shroud_of_death : public SpellScriptLoader +{ + public: + spell_gen_shroud_of_death() : SpellScriptLoader("spell_gen_shroud_of_death") { } + + class spell_gen_shroud_of_deathAuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_shroud_of_deathAuraScript) + + void HandleEffectApply(AuraEffect const * /*aurEff*/, AuraApplication const * aurApp, AuraEffectHandleModes /*mode*/) + { + if (Unit* target = aurApp->GetTarget()) + { + target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); + target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); + } + } + + void HandleEffectRemove(AuraEffect const * /*aurEff*/, AuraApplication const * aurApp, AuraEffectHandleModes /*mode*/) + { + if (Unit* target = aurApp->GetTarget()) + { + target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); + target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); + } + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_gen_shroud_of_deathAuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_gen_shroud_of_deathAuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript *GetAuraScript() const + { + return new spell_gen_shroud_of_deathAuraScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_aura_of_anger(); @@ -530,4 +570,5 @@ void AddSC_generic_spell_scripts() new spell_creature_permanent_feign_death(); new spell_pvp_trinket_wotf_shared_cd(); new spell_gen_animal_blood(); + new spell_gen_shroud_of_death(); } diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 770da7decf0..3f6f6d75636 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1409,37 +1409,12 @@ GM.TicketSystem.ChanceOfGMSurvey = 50 # Max limited by active player zone: ~ 333 # Min limit is max aggro radius (45) * Rate.Creature.Aggro # -# Visibility.Distance.Object -# Visible distance for gameobject, dynobject, bodies, corpses, bones -# Min limit is iteraction distance (5) -# -# Visibility.Distance.InFlight -# Visible distance for player in flight -# Min limit is 0 (not show any objects) -# -# Visibility.Distance.Grey.Unit -# Visibility grey distance for creatures/players (fast changing objects) -# addition to appropriate object type Visibility.Distance.* use in case -# visibility removing to object (except corpse around distances) -# If D is distance and G is grey distance then object -# make visible if distance to it <= D -# but make non visible if distance > D+G -# Default: 1 (yard) -# -# Visibility.Distance.Grey.Object -# Visibility grey distance for dynobjects/gameobjects/corpses/creatures -# Default: 10 (yards) -# ############################################################################### Visibility.GroupMode = 1 Visibility.Distance.Continents = 90 Visibility.Distance.Instances = 120 Visibility.Distance.BGArenas = 180 -Visibility.Distance.Object = 100 -Visibility.Distance.InFlight = 100 -Visibility.Distance.Grey.Unit = 1 -Visibility.Distance.Grey.Object = 10 Visibility.Notify.Period.OnContinents = 1000 Visibility.Notify.Period.InInstances = 1000 |