diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ae39a51a1..a4b3f2996 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -13550,8 +13550,13 @@ uint32 Player::CalculateTalentsPoints() const return uint32(talentPointsForLevel * sWorld->getRate(RATE_TALENT)); } -bool Player::canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell) const +bool Player::canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell) { + if (!sScriptMgr->OnCanPlayerFlyInZone(this, mapid,zone,bySpell)) + { + return false; + } + // continent checked in SpellInfo::CheckLocation at cast and area update uint32 v_map = GetVirtualMapForMapAndZone(mapid, zone); if (v_map == 571 && !bySpell->HasAttribute(SPELL_ATTR7_IGNORES_COLD_WEATHER_FLYING_REQUIREMENT)) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 8cb516504..19063e44a 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2299,7 +2299,7 @@ public: } void HandleFall(MovementInfo const& movementInfo); - [[nodiscard]] bool canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell) const; + [[nodiscard]] bool canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell); void SetClientControl(Unit* target, bool allowMove, bool packetOnly = false); diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp index 68edcca99..de924a6c6 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp @@ -74,6 +74,21 @@ void ScriptMgr::OnPlayerReleasedGhost(Player* player) }); } +bool ScriptMgr::OnCanPlayerFlyInZone(Player* player, uint32 mapId, uint32 zoneId, SpellInfo const* bySpell) +{ + auto ret = IsValidBoolScript([player, mapId, zoneId, bySpell](PlayerScript* script) + { + return !script->OnCanPlayerFlyInZone(player, mapId, zoneId, bySpell); + }); + + if (ret && *ret) + { + return false; + } + + return true; +} + void ScriptMgr::OnPVPKill(Player* killer, Player* killed) { ExecuteScript([&](PlayerScript* script) diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 5c66b2a8d..088d6b4cc 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -1472,6 +1472,16 @@ public: */ virtual void OnQuestAbandon(Player* /*player*/, uint32 /*questId*/) { } + /** + * @brief This hook called before other CanFlyChecks are applied + * + * @param player Contains information about the Player + * @param mapId Contains information about the current map id + * @param zoneId Contains information about the current zone + * @param bySpell Contains information about the spell that invoked the check + */ + [[nodiscard]] virtual bool OnCanPlayerFlyInZone(Player* /*player*/, uint32 /*mapId*/, uint32 /*zoneId*/, SpellInfo const* /*bySpell*/) { return true; } + // Passive Anticheat System virtual void AnticheatSetSkipOnePacketForASH(Player* /*player*/, bool /*apply*/) { } virtual void AnticheatSetCanFlybyServer(Player* /*player*/, bool /*apply*/) { } @@ -2436,6 +2446,7 @@ public: /* PlayerScript */ bool CanSendErrorAlreadyLooted(Player* player); void OnAfterCreatureLoot(Player* player); void OnAfterCreatureLootMoney(Player* player); + bool OnCanPlayerFlyInZone(Player* player, uint32 mapId, uint32 zoneId, SpellInfo const* bySpell); // Anti cheat void AnticheatSetSkipOnePacketForASH(Player* player, bool apply); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 84e107db8..bdab02384 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1470,7 +1470,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const return SPELL_CAST_OK; } -SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player /*= nullptr*/, bool strict /*= true*/) const +SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player* player /*= nullptr*/, bool strict /*= true*/) const { // normal case if (AreaGroupId > 0) diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index dc300600b..06450274f 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -474,7 +474,7 @@ public: bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const; SpellCastResult CheckShapeshift(uint32 form) const; - SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = nullptr, bool strict = true) const; + SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player* player = nullptr, bool strict = true) const; SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const; SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = nullptr) const; bool CheckTargetCreatureType(Unit const* target) const;