/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef TRINITYCORE_AREATRIGGER_H #define TRINITYCORE_AREATRIGGER_H #include "Object.h" #include "GridObject.h" #include "MapObject.h" #include "AreaTriggerTemplate.h" class AuraEffect; class AreaTriggerAI; class SpellInfo; class Unit; namespace G3D { class Vector2; class Vector3; } namespace Movement { template class Spline; } enum class AreaTriggerFieldFlags : uint32 { None = 0x0000, HeightIgnoresScale = 0x0001, WowLabsCircle = 0x0002, CanLoop = 0x0004, AbsoluteOrientation = 0x0008, DynamicShape = 0x0010, Attached = 0x0020, FaceMovementDir = 0x0040, FollowsTerrain = 0x0080, Unknown1025 = 0x0100, AlwaysExterior = 0x0200, HasPlayers = 0x0400, }; DEFINE_ENUM_FLAG(AreaTriggerFieldFlags); enum class AreaTriggerPathType : int32 { Spline = 0, Orbit = 1, None = 2, MovementScript = 3 }; enum class AreaTriggerExitReason : uint8 { NotInside = 0, // Unit leave areatrigger ByExpire = 1 // On areatrigger despawn }; class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject, public MapObject { public: AreaTrigger(); ~AreaTrigger(); protected: void BuildValuesCreate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const override; void BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const override; void ClearUpdateMask(bool remove) override; public: void BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::Mask const& requestedObjectMask, UF::AreaTriggerData::Mask const& requestedAreaTriggerMask, Player const* target) const; struct ValuesUpdateForPlayerWithMaskSender // sender compatible with MessageDistDeliverer { explicit ValuesUpdateForPlayerWithMaskSender(AreaTrigger const* owner) : Owner(owner) { } AreaTrigger const* Owner; UF::ObjectData::Base ObjectMask; UF::AreaTriggerData::Base AreaTriggerMask; void operator()(Player const* player) const; }; void AddToWorld() override; void RemoveFromWorld() override; void AI_Initialize(); void AI_Destroy(); AreaTriggerAI* AI() { return _ai.get(); } bool IsCustom() const { return _areaTriggerTemplate->Id.IsCustom; } bool IsServerSide() const { return _areaTriggerTemplate->Flags.HasFlag(AreaTriggerFlag::IsServerSide); } bool IsStaticSpawn() const { return _spawnId != 0; } bool HasActionSetFlag(AreaTriggerActionSetFlag flag) const { return _areaTriggerTemplate->ActionSetFlags.HasFlag(flag); } bool IsNeverVisibleFor(WorldObject const* seer, bool allowServersideObjects = false) const override; Position const& GetStationaryPosition() const override { return _stationaryPosition; } void RelocateStationaryPosition(Position const& pos) { _stationaryPosition.Relocate(pos); } void PlaySpellVisual(uint32 spellVisualId) const; private: bool Create(AreaTriggerCreatePropertiesId areaTriggerCreatePropertiesId, Map* map, Position const& pos, int32 duration, AreaTriggerSpawn const* spawnData = nullptr, Unit* caster = nullptr, Unit* target = nullptr, SpellCastVisual spellVisual = { 0, 0 }, SpellInfo const* spellInfo = nullptr, Spell* spell = nullptr, AuraEffect const* aurEff = nullptr); public: static AreaTrigger* CreateAreaTrigger(AreaTriggerCreatePropertiesId areaTriggerCreatePropertiesId, Position const& pos, int32 duration, Unit* caster, Unit* target, SpellCastVisual spellVisual = { 0, 0 }, SpellInfo const* spellInfo = nullptr, Spell* spell = nullptr, AuraEffect const* aurEff = nullptr); static ObjectGuid CreateNewMovementForceId(Map* map, uint32 areaTriggerId); bool LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap, bool allowDuplicate); void Update(uint32 diff) override; void Remove(); bool IsRemoved() const { return _isRemoved; } uint32 GetSpellId() const { return m_areaTriggerData->SpellID; } AuraEffect const* GetAuraEffect() const { return _aurEff; } uint32 GetTimeSinceCreated() const; EnumFlag GetAreaTriggerFlags() const { return static_cast(*m_areaTriggerData->Flags); } bool HasAreaTriggerFlag(AreaTriggerFieldFlags flag) const { return GetAreaTriggerFlags().HasFlag(flag); } void SetAreaTriggerFlag(AreaTriggerFieldFlags flag) { SetUpdateFieldFlagValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::Flags), uint32(flag)); } void RemoveAreaTriggerFlag(AreaTriggerFieldFlags flag) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::Flags), uint32(flag)); } void ReplaceAllAreaTriggerFlags(AreaTriggerFieldFlags flag) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::Flags), uint32(flag)); } float CalcCurrentScale() const; void SetOverrideScaleCurve(float overrideScale); void SetOverrideScaleCurve(std::array const& points, Optional startTimeOffset = {}, CurveInterpolationMode interpolation = CurveInterpolationMode::Linear); void ClearOverrideScaleCurve(); void SetExtraScaleCurve(float extraScale); void SetExtraScaleCurve(std::array const& points, Optional startTimeOffset = {}, CurveInterpolationMode interpolation = CurveInterpolationMode::Linear); void ClearExtraScaleCurve(); void SetOverrideMoveCurve(float x, float y, float z); void SetOverrideMoveCurve(std::array const& xCurvePoints, std::array const& yCurvePoints, std::array const& zCurvePoints, Optional startTimeOffset = {}, CurveInterpolationMode interpolation = CurveInterpolationMode::Linear); void ClearOverrideMoveCurve(); uint32 GetTimeToTarget() const { return m_areaTriggerData->TimeToTarget; } void SetTimeToTarget(uint32 timeToTarget) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::TimeToTarget), timeToTarget); } uint32 GetTimeToTargetScale() const { return m_areaTriggerData->TimeToTargetScale; } void SetTimeToTargetScale(uint32 timeToTargetScale) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::TimeToTargetScale), timeToTargetScale); } uint32 GetTimeToTargetExtraScale() const { return m_areaTriggerData->TimeToTargetExtraScale; } void SetTimeToTargetExtraScale(uint32 timeToTargetExtraScale) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::TimeToTargetExtraScale), timeToTargetExtraScale); } uint32 GetTimeToTargetPos() const { return m_areaTriggerData->TimeToTargetPos; } void SetTimeToTargetPos(uint32 timeToTargetPos) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::TimeToTargetPos), timeToTargetPos); } void SetSpellVisual(SpellCastVisual const& visual); int32 GetDuration() const { return _duration; } int32 GetTotalDuration() const { return _totalDuration; } void SetDuration(int32 newDuration); void Delay(int32 delaytime) { SetDuration(GetDuration() - delaytime); } GuidUnorderedSet const& GetInsideUnits() const { return _insideUnits; } AreaTriggerCreateProperties const* GetCreateProperties() const { return _areaTriggerCreateProperties; } AreaTriggerTemplate const* GetTemplate() const { return _areaTriggerTemplate; } uint32 GetScriptId() const; ObjectGuid GetCreatorGUID() const override { return GetCasterGuid(); } ObjectGuid GetOwnerGUID() const override { return GetCasterGuid(); } ObjectGuid const& GetCasterGuid() const { return m_areaTriggerData->Caster; } Unit* GetCaster() const; Unit* GetTarget() const; uint32 GetFaction() const override; void SetShape(AreaTriggerShapeInfo const& shape); float GetMaxSearchRadius() const; void InitSplineOffsets(std::vector const& offsets, Optional overrideSpeed = {}, Optional speedIsTimeInSeconds = {}); void InitSplines(std::vector const& splinePoints, Optional overrideSpeed = {}, Optional speedIsTimeInSeconds = {}); bool HasSplines() const { return _spline != nullptr; } ::Movement::Spline const& GetSpline() const { return *_spline; } uint32 GetElapsedTimeForMovement() const; void InitOrbit(AreaTriggerOrbitInfo const& orbit, Optional overrideSpeed = {}, Optional speedIsTimeInSeconds = {}); bool HasOrbit() const { return m_areaTriggerData->PathData.Is(); } UF::AreaTriggerOrbit const& GetOrbit() const { return *m_areaTriggerData->PathData.Get(); } bool HasOverridePosition() const; void UpdateShape(); void HandleUnitExit(Unit* unit); UF::UpdateField m_areaTriggerData; protected: void _UpdateDuration(int32 newDuration); float GetProgress() const; struct ScaleCurveData { uint32 StartTimeOffset = 0; CurveInterpolationMode Mode = CurveInterpolationMode::Linear; using Points = std::array; std::variant Curve; }; float GetScaleCurveProgress(UF::ScaleCurve const& scaleCurve, uint32 timeTo) const; float GetScaleCurveValueAtProgress(UF::ScaleCurve const& scaleCurve, float x) const; float GetScaleCurveValue(UF::ScaleCurve const& scaleCurve, uint32 timeTo) const; void SetScaleCurve(UF::MutableFieldReference scaleCurveMutator, float constantValue); void SetScaleCurve(UF::MutableFieldReference scaleCurveMutator, std::array const& points, Optional startTimeOffset, CurveInterpolationMode interpolation); void ClearScaleCurve(UF::MutableFieldReference scaleCurveMutator); void SetScaleCurve(UF::MutableFieldReference scaleCurveMutator, Optional const& curve); void UpdateTargetList(); void SearchUnits(std::vector& targetList, float radius, bool check3D); void SearchUnitInSphere(UF::AreaTriggerSphere const& sphere, std::vector& targetList); void SearchUnitInBox(UF::AreaTriggerBox const& box, std::vector& targetList); void SearchUnitInPolygon(UF::AreaTriggerPolygon const& polygon, std::vector& targetList); void SearchUnitInCylinder(UF::AreaTriggerCylinder const& cylinder, std::vector& targetList); void SearchUnitInDisk(UF::AreaTriggerDisk const& disk, std::vector& targetList); void SearchUnitInBoundedPlane(UF::AreaTriggerBoundedPlane const& boundedPlane, std::vector& targetList); void HandleUnitEnterExit(std::vector const& targetList, AreaTriggerExitReason exitMode = AreaTriggerExitReason::NotInside); void HandleUnitEnter(Unit* unit); void HandleUnitExitInternal(Unit* unit, AreaTriggerExitReason exitMode = AreaTriggerExitReason::NotInside); void DoActions(Unit* unit); void UndoActions(Unit* unit); void UpdatePolygonVertices(); void UpdateOrbitPosition(); void UpdateSplinePosition(Movement::Spline& spline); void UpdateOverridePosition(); Position const* GetOrbitCenterPosition() const; Position CalculateOrbitPosition() const; void UpdateHasPlayersFlag(); void DebugVisualizePosition(); // Debug purpose only ObjectGuid::LowType _spawnId; ObjectGuid _targetGuid; AuraEffect const* _aurEff; Position _stationaryPosition; int32 _duration; int32 _totalDuration; float _verticesUpdatePreviousOrientation; bool _isRemoved; std::vector _polygonVertices; std::unique_ptr<::Movement::Spline> _spline; bool _reachedDestination; int32 _lastSplineIndex; AreaTriggerCreateProperties const* _areaTriggerCreateProperties; AreaTriggerTemplate const* _areaTriggerTemplate; GuidUnorderedSet _insideUnits; std::unique_ptr _ai; }; #endif