diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 28cf03979..dba56ac80 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1670,6 +1670,11 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo if (thisPlayer->GetViewpoint()) viewpoint = thisPlayer->GetViewpoint(); + + if (thisPlayer->GetFarSightDistance() && !thisPlayer->isInFront(obj)) + { + return false; + } } // Xinef: check reversely obj vs viewpoint, object could be a gameObject which overrides _IsWithinDist function to include gameobject size diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 6c5f9a843..1cbfb4c54 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -919,7 +919,7 @@ public: [[nodiscard]] float GetGridActivationRange() const; [[nodiscard]] float GetVisibilityRange() const; - float GetSightRange(const WorldObject* target = nullptr) const; + virtual float GetSightRange(const WorldObject* target = nullptr) const; //bool CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth = false, bool distanceCheck = false) const; bool CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth = false, bool distanceCheck = false, bool checkAlert = false) const; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 76e9809cc..1864aedaf 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -15154,3 +15154,29 @@ void Player::SetServerSideVisibilityDetect(ServerSideVisibilityType type, Accoun m_serverSideVisibilityDetect.SetValue(type, sec); } + +void Player::SetFarSightDistance(float radius) +{ + _farSightDistance = radius; +} + +void Player::ResetFarSightDistance() +{ + _farSightDistance.reset(); +} + +Optional Player::GetFarSightDistance() const +{ + return _farSightDistance; +} + +float Player::GetSightRange(const WorldObject* target) const +{ + float sightRange = WorldObject::GetSightRange(target); + if (_farSightDistance) + { + sightRange += *_farSightDistance; + } + + return sightRange; +} diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index d36394d84..1acc01913 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -17,6 +17,7 @@ #include "KillRewarder.h" #include "MapReference.h" #include "ObjectMgr.h" +#include "Optional.h" #include "PetDefines.h" #include "PlayerTaxi.h" #include "QuestDef.h" @@ -2521,7 +2522,13 @@ public: std::string GetMapAreaAndZoneString(); std::string GetCoordsMapAreaAndZoneString(); -protected: + void SetFarSightDistance(float radius); + void ResetFarSightDistance(); + Optional GetFarSightDistance() const; + + float GetSightRange(const WorldObject* target = nullptr) const override; + + protected: // Gamemaster whisper whitelist WhisperListContainer WhisperList; @@ -2874,6 +2881,8 @@ private: Creature* m_CinematicObject; WorldLocation _corpseLocation; + + Optional _farSightDistance = { }; }; void AddItemsSetItem(Player* player, Item* item); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e7ddf9f29..08976f1e3 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -19173,8 +19173,13 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel GetMap()->CreatureRelocation(ToCreature(), x, y, z, orientation); } else if (turn) + { UpdateOrientation(orientation); + if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetFarSightDistance()) + UpdateObjectVisibility(false); + } + return (relocated || turn); } @@ -19687,24 +19692,31 @@ void Unit::ExecuteDelayedUnitRelocationEvent() if (active->IsVehicle()) active = player; - float dx = active->m_last_notify_position.GetPositionX() - active->GetPositionX(); - float dy = active->m_last_notify_position.GetPositionY() - active->GetPositionY(); - float dz = active->m_last_notify_position.GetPositionZ() - active->GetPositionZ(); - float distsq = dx * dx + dy * dy + dz * dz; + if (!player->GetFarSightDistance()) + { + float dx = active->m_last_notify_position.GetPositionX() - active->GetPositionX(); + float dy = active->m_last_notify_position.GetPositionY() - active->GetPositionY(); + float dz = active->m_last_notify_position.GetPositionZ() - active->GetPositionZ(); + float distsq = dx * dx + dy * dy + dz * dz; - float mindistsq = DynamicVisibilityMgr::GetReqMoveDistSq(active->FindMap()->GetEntry()->map_type); - if (distsq < mindistsq) - return; + float mindistsq = DynamicVisibilityMgr::GetReqMoveDistSq(active->FindMap()->GetEntry()->map_type); + if (distsq < mindistsq) + return; - active->m_last_notify_position.Relocate(active->GetPositionX(), active->GetPositionY(), active->GetPositionZ()); + active->m_last_notify_position.Relocate(active->GetPositionX(), active->GetPositionY(), active->GetPositionZ()); + } } Acore::PlayerRelocationNotifier relocateNoLarge(*player, false); // visit only objects which are not large; default distance Cell::VisitAllObjects(viewPoint, relocateNoLarge, player->GetSightRange() + VISIBILITY_INC_FOR_GOBJECTS); relocateNoLarge.SendToSelf(); - Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance - Cell::VisitAllObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE); - relocateLarge.SendToSelf(); + + if (!player->GetFarSightDistance()) + { + Acore::PlayerRelocationNotifier relocateLarge(*player, true); // visit only large objects; maximum distance + Cell::VisitAllObjects(viewPoint, relocateLarge, MAX_VISIBILITY_DISTANCE); + relocateLarge.SendToSelf(); + } this->AddToNotify(NOTIFY_AI_RELOCATION); } diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index 6f7886ba3..3960f6560 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -19,10 +19,12 @@ void VisibleNotifier::Visit(GameObjectMapType& m) { for (GameObjectMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { - if (i_largeOnly != iter->GetSource()->IsVisibilityOverridden()) + GameObject* go = iter->GetSource(); + if (i_largeOnly != go->IsVisibilityOverridden()) continue; - vis_guids.erase(iter->GetSource()->GetGUID()); - i_player.UpdateVisibilityOf(iter->GetSource(), i_data, i_visibleNow); + + vis_guids.erase(go->GetGUID()); + i_player.UpdateVisibilityOf(go, i_data, i_visibleNow); } } @@ -61,8 +63,10 @@ void VisibleNotifier::SendToSelf() for (GuidUnorderedSet::const_iterator it = vis_guids.begin(); it != vis_guids.end(); ++it) { if (WorldObject* obj = ObjectAccessor::GetWorldObject(i_player, *it)) + { if (i_largeOnly != obj->IsVisibilityOverridden()) continue; + } // pussywizard: static transports are removed only in RemovePlayerFromMap and here if can no longer detect (eg. phase changed) if ((*it).IsTransport()) @@ -92,6 +96,7 @@ void VisibleNotifier::SendToSelf() { if (i_largeOnly != (*it)->IsVisibilityOverridden()) continue; + i_player.GetInitialVisiblePackets(*it); } } diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 1e5f0e1f4..0683477ae 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -13,6 +13,7 @@ #include "GameObject.h" #include "Object.h" #include "ObjectGridLoader.h" +#include "Optional.h" #include "Player.h" #include "Spell.h" #include "Unit.h" @@ -34,7 +35,8 @@ namespace Acore bool i_largeOnly; UpdateData i_data; - VisibleNotifier(Player& player, bool gobjOnly, bool largeOnly) : i_player(player), vis_guids(player.m_clientGUIDs), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly), i_largeOnly(largeOnly) + VisibleNotifier(Player& player, bool gobjOnly, bool largeOnly) : + i_player(player), vis_guids(player.m_clientGUIDs), i_visibleNow(player.m_newVisible), i_gobjOnly(gobjOnly), i_largeOnly(largeOnly) { i_visibleNow.clear(); } @@ -57,7 +59,7 @@ namespace Acore struct PlayerRelocationNotifier : public VisibleNotifier { - PlayerRelocationNotifier(Player& player, bool largeOnly) : VisibleNotifier(player, false, largeOnly) {} + PlayerRelocationNotifier(Player& player, bool largeOnly): VisibleNotifier(player, false, largeOnly) { } template void Visit(GridRefManager& m) { VisibleNotifier::Visit(m); } void Visit(PlayerMapType&); diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h index b116a629f..b06ee1082 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h +++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h @@ -27,6 +27,7 @@ inline void Acore::VisibleNotifier::Visit(GridRefManager& m) { if (i_largeOnly != iter->GetSource()->IsVisibilityOverridden()) continue; + vis_guids.erase(iter->GetSource()->GetGUID()); i_player.UpdateVisibilityOf(iter->GetSource(), i_data, i_visibleNow); } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 29518982d..6ecce88a0 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -125,7 +125,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] = &AuraEffect::HandleModPowerCost, // 73 SPELL_AURA_MOD_POWER_COST_SCHOOL &AuraEffect::HandleNoImmediateEffect, // 74 SPELL_AURA_REFLECT_SPELLS_SCHOOL implemented in Unit::SpellHitResult &AuraEffect::HandleNoImmediateEffect, // 75 SPELL_AURA_MOD_LANGUAGE - &AuraEffect::HandleNoImmediateEffect, // 76 SPELL_AURA_FAR_SIGHT + &AuraEffect::HandleFarSight, // 76 SPELL_AURA_FAR_SIGHT &AuraEffect::HandleModMechanicImmunity, // 77 SPELL_AURA_MECHANIC_IMMUNITY &AuraEffect::HandleAuraMounted, // 78 SPELL_AURA_MOUNTED &AuraEffect::HandleModDamagePercentDone, // 79 SPELL_AURA_MOD_DAMAGE_PERCENT_DONE @@ -5476,6 +5476,32 @@ void AuraEffect::HandleBindSight(AuraApplication const* aurApp, uint8 mode, bool caster->ToPlayer()->SetViewpoint(target, apply); } +void AuraEffect::HandleFarSight(AuraApplication const* /*aurApp*/, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + { + return; + } + + Unit* caster = GetCaster(); + if (!caster || caster->GetTypeId() != TYPEID_PLAYER) + { + return; + } + + Player* player = caster->ToPlayer(); + if (apply) + { + player->SetFarSightDistance(m_spellInfo->GetMaxRange()); + } + else + { + player->ResetFarSightDistance(); + } + + caster->UpdateObjectVisibility(!apply); +} + void AuraEffect::HandleForceReaction(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index b46bbb13c..11e504bd1 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -287,6 +287,7 @@ public: void HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleChannelDeathItem(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleBindSight(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleFarSight(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleForceReaction(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraEmpathy(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModFaction(AuraApplication const* aurApp, uint8 mode, bool apply) const;