TrinityCore
Loading...
Searching...
No Matches
AreaTrigger.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "AreaTrigger.h"
19#include "AreaTriggerAI.h"
21#include "AreaTriggerPackets.h"
22#include "CellImpl.h"
23#include "Chat.h"
24#include "Containers.h"
25#include "CreatureAISelector.h"
26#include "DB2Stores.h"
27#include "G3DPosition.hpp"
28#include "GameTime.h"
29#include "GridNotifiersImpl.h"
30#include "Language.h"
31#include "Log.h"
32#include "MapUtils.h"
33#include "Object.h"
34#include "ObjectAccessor.h"
35#include "ObjectMgr.h"
36#include "PhasingHandler.h"
37#include "Player.h"
38#include "RestMgr.h"
39#include "SpellInfo.h"
40#include "SpellMgr.h"
41#include "Spline.h"
42#include "Transport.h"
43#include "Unit.h"
44#include "UpdateData.h"
45#include "ZoneScript.h"
46#include "advstd.h"
47#include <G3D/AABox.h>
48#include <G3D/Box.h>
49#include <G3D/CollisionDetection.h>
50#include <G3D/CoordinateFrame.h>
51#include <G3D/Cylinder.h>
52#include <G3D/Quat.h>
53#include <bit>
54
56{
57 None,
58 Moved,
60};
61
68
75
76AreaTrigger::AreaTrigger() : WorldObject(false), MapObject(), _spawnId(0), _aurEff(nullptr),
77 _duration(0), _totalDuration(0), _verticesUpdatePreviousRotation(),
78 _isRemoved(false), _reachedDestination(true),
79 _areaTriggerCreateProperties(nullptr), _areaTriggerTemplate(nullptr)
80{
82
84
86}
87
91
93{
95 if (!IsInWorld())
96 {
97 if (m_zoneScript)
99
101 if (_spawnId)
102 GetMap()->GetAreaTriggerBySpawnIdStore().insert(std::make_pair(_spawnId, this));
103
105 }
106}
107
109{
111 if (IsInWorld())
112 {
113 if (m_zoneScript)
115
116 _isRemoved = true;
117
118 if (Unit* caster = GetCaster())
119 caster->_UnregisterAreaTrigger(this);
120
121 _ai->OnRemove();
122
123 // Handle removal of all units, calling OnUnitExit & deleting auras if needed
125
127
128 if (IsStaticSpawn())
129 Trinity::Containers::MultimapErasePair(GetMap()->GetAreaTriggerBySpawnIdStore(), _spawnId, this);
131 }
132}
133
134void AreaTrigger::PlaySpellVisual(uint32 spellVisualId) const
135{
137 packet.AreaTriggerGUID = GetGUID();
138 packet.SpellVisualID = spellVisualId;
139 SendMessageToSet(packet.Write(), false);
140}
141
142bool AreaTrigger::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*/)
143{
144 _targetGuid = target ? target->GetGUID() : ObjectGuid::Empty;
145 _aurEff = aurEff;
146
147 SetMap(map);
148 Relocate(pos);
150 if (!IsPositionValid())
151 {
152 TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})) not created. Invalid coordinates (X: {} Y: {})", areaTriggerCreatePropertiesId.Id, uint32(areaTriggerCreatePropertiesId.IsCustom), GetPositionX(), GetPositionY());
153 return false;
154 }
155
156 _areaTriggerCreateProperties = sAreaTriggerDataStore->GetAreaTriggerCreateProperties(areaTriggerCreatePropertiesId);
158 {
159 TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})) not created. Invalid areatrigger create properties id", areaTriggerCreatePropertiesId.Id, uint32(areaTriggerCreatePropertiesId.IsCustom));
160 return false;
161 }
162
164
166
167 _Create(ObjectGuid::Create<HighGuid::AreaTrigger>(GetMapId(), GetTemplate() ? GetTemplate()->Id.Id : 0, GetMap()->GenerateLowGuid<HighGuid::AreaTrigger>()));
168
169 if (GetTemplate())
171
172 SetObjectScale(1.0f);
173 SetDuration(duration);
174
176
177 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
178 if (caster)
179 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::Caster), caster->GetGUID());
180 if (spell)
181 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::CreatingEffectGUID), spell->m_castId);
182 if (spellInfo && !IsStaticSpawn())
183 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::SpellID), spellInfo->Id);
184
185 SpellInfo const* spellForVisuals = spellInfo;
186 if (GetCreateProperties()->SpellForVisuals)
187 {
188 spellForVisuals = sSpellMgr->GetSpellInfo(*GetCreateProperties()->SpellForVisuals, DIFFICULTY_NONE);
189
190 if (spellForVisuals)
191 spellVisual.SpellXSpellVisualID = caster ? caster->GetCastSpellXSpellVisualId(spellForVisuals) : spellForVisuals->GetSpellXSpellVisualId();
192 }
193 if (spellForVisuals)
194 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::SpellForVisuals), spellForVisuals->Id);
195
196 SetSpellVisual(spellVisual);
197 if (!IsStaticSpawn())
198 {
199 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTargetScale), GetCreateProperties()->TimeToTargetScale != 0 ? GetCreateProperties()->TimeToTargetScale : *m_areaTriggerData->Duration);
200 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTargetPos), *m_areaTriggerData->Duration);
201 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTargetShape), *m_areaTriggerData->Duration);
202 }
203 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::BoundsRadius2D), GetCreateProperties()->Shape.GetMaxSearchRadius());
204 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::DecalPropertiesID), GetCreateProperties()->DecalPropertiesId);
205 if (IsServerSide())
206 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::DecalPropertiesID), 24); // Blue decal, for .debug areatrigger visibility
207
208 SetOverrideCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve), 1.0f);
209
210 if (caster && spellInfo)
211 {
212 if (Player const* modOwner = caster->GetSpellModOwner())
213 {
214 float multiplier = 1.0f;
215 int32 flat = 0;
216 modOwner->GetSpellModValues(spellInfo, SpellModOp::Radius, spell, *m_areaTriggerData->BoundsRadius2D, &flat, &multiplier);
217 if (multiplier != 1.0f)
218 {
219 OverrideCurveData overrideScale;
220 overrideScale.Curve = multiplier;
221 SetOverrideCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OverrideScaleCurve), overrideScale);
222 }
223 }
224 }
225
226 auto visualAnim = areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim);
227 if (GetCreateProperties()->AnimId != -1)
228 SetUpdateFieldValue(visualAnim.ModifyValue(&UF::VisualAnim::AnimationDataID, 0), GetCreateProperties()->AnimId);
229 SetUpdateFieldValue(visualAnim.ModifyValue(&UF::VisualAnim::AnimKitID), GetCreateProperties()->AnimKitId);
231 SetUpdateFieldValue(visualAnim.ModifyValue(&UF::VisualAnim::IsDecay), true);
232
233 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::PositionalSoundKitID), GetCreateProperties()->PositionalSoundKitId);
234
236 {
248 return fieldFlags;
249 }();
250 ReplaceAllAreaTriggerFlags(fieldFlags);
251
254
255 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ScaleCurveId), GetCreateProperties()->ScaleCurveId);
256 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::FacingCurveId), GetCreateProperties()->FacingCurveId);
257 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::MorphCurveId), GetCreateProperties()->MorphCurveId);
258 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::MoveCurveId), GetCreateProperties()->MoveCurveId);
259
260 if (caster)
262 else if (IsStaticSpawn() && spawnData)
263 {
264 if (spawnData->phaseUseFlags || spawnData->phaseId || spawnData->phaseGroup)
266 }
267
268 if (target && aurEff)
269 {
273 }
274
275 // movement on transport of areatriggers on unit is handled by themself
276 TransportBase* transport = nullptr;
277 if (caster)
278 {
279 transport = m_movementInfo.transport.guid.IsEmpty() ? caster->GetTransport() : nullptr;
280 if (transport)
281 {
282 // This object must be added to transport before adding to map for the client to properly display it
283 transport->AddPassenger(this, transport->GetPositionOffsetTo(pos));
284 }
285 }
286
287 if (!IsStaticSpawn())
289
290 std::visit([&]<typename MovementType>(MovementType const& movement)
291 {
292 if constexpr (std::is_same_v<MovementType, AreaTriggerOrbitInfo>)
293 {
294 AreaTriggerOrbitInfo orbit = movement;
296 orbit.PathTarget = target->GetGUID();
297 else
298 orbit.Center = pos;
299
300 this->InitOrbit(orbit);
301 }
302 else if constexpr (std::is_same_v<MovementType, AreaTriggerCreateProperties::SplineInfo>)
303 this->InitSplineOffsets(movement);
304 else if constexpr (std::is_same_v<MovementType, std::monostate>)
306 else
307 static_assert(Trinity::dependant_false_v<MovementType>, "Unsupported movement type");
309
311
312 SetRollPitchYaw(GetCreateProperties()->RollPitchYaw, GetCreateProperties()->TargetRollPitchYaw);
313
315
317
318 // Calculate initial position and rotation
319 {
320 auto [_, movedPos, movedRot] = CalculateWorldPositionAndRotation();
321 Relocate(movedPos);
322 _rotation = { movedRot.x, movedRot.y, movedRot.z, movedRot.w };
323 }
324
325 UpdateShape();
326
327 if (!IsStaticSpawn())
328 {
329 if (!GetMap()->AddToMap(this))
330 {
331 // Returning false will cause the object to be deleted - remove from transport
332 if (transport)
333 transport->RemovePassenger(this);
334 return false;
335 }
336 }
337
338 if (caster)
339 caster->_RegisterAreaTrigger(this);
340
341 _ai->OnCreate(spell);
342
343 return true;
344}
345
346AreaTrigger* 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*/)
347{
348 AreaTrigger* at = new AreaTrigger();
349 if (!at->Create(areaTriggerCreatePropertiesId, caster->GetMap(), pos, duration, nullptr, caster, target, spellVisual, spellInfo, spell, aurEff))
350 {
351 delete at;
352 return nullptr;
353 }
354
355 return at;
356}
357
359{
360 return ObjectGuid::Create<HighGuid::AreaTrigger>(map->GetId(), areaTriggerId, map->GenerateLowGuid<HighGuid::AreaTrigger>());
361}
362
363bool AreaTrigger::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool /*addToMap*/, bool /*allowDuplicate*/)
364{
365 _spawnId = spawnId;
366
367 AreaTriggerSpawn const* spawnData = sAreaTriggerDataStore->GetAreaTriggerSpawn(spawnId);
368 if (!spawnData)
369 return false;
370
371 AreaTriggerCreateProperties const* createProperties = sAreaTriggerDataStore->GetAreaTriggerCreateProperties(spawnData->Id);
372 if (!createProperties)
373 return false;
374
375 return Create(spawnData->Id, map, spawnData->spawnPoint, -1, spawnData);
376}
377
379{
381
382 if (!IsStaticSpawn())
384
385 if (GetDuration() != -1)
386 {
387 if (GetDuration() > int32(diff))
389 else
390 {
391 Remove(); // expired
392 return;
393 }
394 }
395
396 _ai->OnUpdate(diff);
397
399}
400
402{
403 if (IsInWorld())
404 {
405 AddObjectToRemoveList(); // calls RemoveFromWorld
406 }
407}
408
410{
412 if (now >= *m_areaTriggerData->CreationTime)
413 return now - *m_areaTriggerData->CreationTime;
414 return 0;
415}
416
422
423void AreaTrigger::SetOverrideScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
424{
427}
428
434
440
441void AreaTrigger::SetExtraScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
442{
445}
446
452
453void AreaTrigger::SetOverrideMoveCurve(float x, float y, float z)
454{
455 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
456 SetOverrideCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveX), x);
457 SetOverrideCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveY), y);
458 SetOverrideCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveZ), z);
460}
461
462void AreaTrigger::SetOverrideMoveCurve(std::array<DBCPosition2D, 2> const& xCurvePoints, std::array<DBCPosition2D, 2> const& yCurvePoints,
463 std::array<DBCPosition2D, 2> const& zCurvePoints, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
464{
465 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
466 SetOverrideCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveX), xCurvePoints, startTimeOffset, interpolation);
467 SetOverrideCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveY), yCurvePoints, startTimeOffset, interpolation);
468 SetOverrideCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveZ), zCurvePoints, startTimeOffset, interpolation);
470}
471
480
485
486void AreaTrigger::SetOverrideShapeCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
487{
489}
490
495
497{
499
501 SetUpdateFieldValue(spellVisualMutator.ModifyValue(&UF::SpellCastVisual::ScriptVisualID), visual.ScriptVisualID);
502}
503
504void AreaTrigger::SetRollPitchYaw(float roll, float pitch, float yaw,
505 Optional<float> targetRoll, Optional<float> targetPitch, Optional<float> targetYaw)
506{
507 TaggedPosition<Position::XYZ> rollPitchYaw = { roll, pitch, yaw };
508 Optional<TaggedPosition<Position::XYZ>> targetRollPitchYaw;
509
510 if (targetRoll && targetPitch && targetYaw)
511 targetRollPitchYaw.emplace(*targetRoll, *targetPitch, *targetYaw);
512
513 SetRollPitchYaw(rollPitchYaw, targetRollPitchYaw);
514}
515
517{
518 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
519
520 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::RollPitchYaw), rollPitchYaw);
521 if (targetRollPitchYaw)
522 {
523 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TargetRollPitchYaw, 0), *targetRollPitchYaw);
525 }
526 else
527 {
530 }
531}
532
534{
535 _duration = newDuration;
536 _totalDuration = newDuration;
537
538 // negative duration (permanent areatrigger) sent as 0
540}
541
543{
544 _duration = newDuration;
545
546 // should be sent in object create packets only
548 {
550 const_cast<UF::AreaTriggerData&>(*m_areaTriggerData).ClearChanged(&UF::AreaTriggerData::Duration);
551 });
552}
553
555{
556 float scale = 1.0f;
557 if (m_areaTriggerData->OverrideScaleCurve->OverrideActive)
558 scale *= std::max(GetOverrideCurveValue(*m_areaTriggerData->OverrideScaleCurve, m_areaTriggerData->TimeToTargetScale), 0.000001f);
559 else if (m_areaTriggerData->ScaleCurveId)
560 scale *= std::max(sDB2Manager.GetCurveValueAt(m_areaTriggerData->ScaleCurveId, GetScaleProgress()), 0.000001f);
561
562 scale *= std::max(GetOverrideCurveValue(*m_areaTriggerData->ExtraScaleCurve, m_areaTriggerData->TimeToTargetExtraScale), 0.000001f);
563
564 return scale;
565}
566
567float AreaTrigger::GetOverrideCurveProgress(UF::OverrideCurve const& overrideCurve, uint32 timeTo) const
568{
569 if (!timeTo)
570 return 1.0f;
571
572 return std::clamp(float(GetTimeSinceCreated() - overrideCurve.StartTimeOffset) / float(timeTo), 0.0f, 1.0f);
573}
574
575float AreaTrigger::GetOverrideCurveValueAtProgress(UF::OverrideCurve const& overrideCurve, float x) const
576{
577 ASSERT(*overrideCurve.OverrideActive, "OverrideCurve must be active to evaluate it");
578
579 // unpack ParameterCurve
580 if (*overrideCurve.ParameterCurve & 1u)
581 return advstd::bit_cast<float>(*overrideCurve.ParameterCurve & ~1u);
582
583 std::array<DBCPosition2D, 2> points;
584 for (std::size_t i = 0; i < overrideCurve.Points.size(); ++i)
585 points[i] = { .X = overrideCurve.Points[i].Pos.GetPositionX(), .Y = overrideCurve.Points[i].Pos.GetPositionY() };
586
587 CurveInterpolationMode mode = CurveInterpolationMode(*overrideCurve.ParameterCurve >> 1 & 0xF);
588 std::size_t pointCount = *overrideCurve.ParameterCurve >> 24 & 0xFF;
589
590 return sDB2Manager.GetCurveValueAt(mode, std::span(points.begin(), pointCount), x);
591}
592
593float AreaTrigger::GetOverrideCurveValue(UF::OverrideCurve const& overrideCurve, uint32 timeTo) const
594{
595 return GetOverrideCurveValueAtProgress(overrideCurve, GetOverrideCurveProgress(overrideCurve, timeTo));
596}
597
599{
600 OverrideCurveData curveTemplate;
601 curveTemplate.Curve = constantValue;
602 SetOverrideCurve(overrideCurveMutator, curveTemplate);
603}
604
605void AreaTrigger::SetOverrideCurve(UF::MutableFieldReference<UF::OverrideCurve, false> overrideCurveMutator, std::array<DBCPosition2D, 2> const& points,
606 Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
607{
608 OverrideCurveData curveTemplate;
609 curveTemplate.StartTimeOffset = startTimeOffset.value_or(GetTimeSinceCreated());
610 curveTemplate.Mode = interpolation;
611 curveTemplate.Curve = points;
612
613 SetOverrideCurve(overrideCurveMutator, curveTemplate);
614}
615
617{
618 SetOverrideCurve(overrideCurveMutator, {});
619}
620
622{
623 if (!curve)
624 {
625 SetUpdateFieldValue(overrideCurveMutator.ModifyValue(&UF::OverrideCurve::OverrideActive), false);
626 return;
627 }
628
629 SetUpdateFieldValue(overrideCurveMutator.ModifyValue(&UF::OverrideCurve::OverrideActive), true);
630 SetUpdateFieldValue(overrideCurveMutator.ModifyValue(&UF::OverrideCurve::StartTimeOffset), curve->StartTimeOffset);
631
633 // ParameterCurve packing information
634 // (not_using_points & 1) | ((interpolation_mode & 0xF) << 1) | ((first_point_offset & 0x7FFFF) << 5) | ((point_count & 0xFF) << 24)
635 // if not_using_points is set then the entire field is simply read as a float (ignoring that lowest bit)
636
637 if (float const* simpleFloat = std::get_if<float>(&curve->Curve))
638 {
639 uint32 packedCurve = advstd::bit_cast<uint32>(*simpleFloat);
640 packedCurve |= 1;
641
642 SetUpdateFieldValue(overrideCurveMutator.ModifyValue(&UF::OverrideCurve::ParameterCurve), packedCurve);
643
644 // clear points
645 for (std::size_t i = 0; i < UF::size<decltype(UF::OverrideCurve::Points)>(); ++i)
646 SetUpdateFieldValue(overrideCurveMutator.ModifyValue(&UF::OverrideCurve::Points, i), point);
647 }
648 else if (OverrideCurveData::Points const* curvePoints = std::get_if<OverrideCurveData::Points>(&curve->Curve))
649 {
650 CurveInterpolationMode mode = curve->Mode;
651 if ((*curvePoints)[1].X < (*curvePoints)[0].X)
653
654 switch (mode)
655 {
657 // catmullrom requires at least 4 points, impossible here
659 break;
663 // bezier requires more than 2 points, impossible here
665 break;
666 default:
667 break;
668 }
669
670 uint32 pointCount = 2;
672 pointCount = 1;
673
674 uint32 packedCurve = (uint32(mode) << 1) | (pointCount << 24);
675 SetUpdateFieldValue(overrideCurveMutator.ModifyValue(&UF::OverrideCurve::ParameterCurve), packedCurve);
676
677 for (std::size_t i = 0; i < curvePoints->size(); ++i)
678 {
679 point.Pos.Relocate((*curvePoints)[i].X, (*curvePoints)[i].Y);
680 SetUpdateFieldValue(overrideCurveMutator.ModifyValue(&UF::OverrideCurve::Points, i), point);
681 }
682 }
683}
684
686{
687 std::vector<Unit*> targetList;
688
689 m_areaTriggerData->ShapeData.Visit([&]<typename ShapeType>(ShapeType const& shape)
690 {
691 if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerSphere>)
692 this->SearchUnitInSphere(shape, targetList);
693 else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerBox>)
694 this->SearchUnitInBox(shape, targetList);
695 else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerPolygon>)
696 this->SearchUnitInPolygon(shape, targetList);
697 else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerCylinder>)
698 this->SearchUnitInCylinder(shape, targetList);
699 else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerDisk>)
700 this->SearchUnitInDisk(shape, targetList);
701 else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerBoundedPlane>)
702 this->SearchUnitInBoundedPlane(shape, targetList);
703 });
704
705 if (GetTemplate())
706 {
707 ConditionContainer const* conditions = sConditionMgr->GetConditionsForAreaTrigger(GetTemplate()->Id.Id, GetTemplate()->Id.IsCustom);
708 Trinity::Containers::EraseIf(targetList, [this, conditions](Unit const* target)
709 {
710 if (GetCasterGuid() == target->GetGUID())
711 {
712 if (HasActionSetFlag(AreaTriggerActionSetFlag::NotTriggeredbyCaster))
713 return true;
714 }
715 else
716 {
717 if (HasActionSetFlag(AreaTriggerActionSetFlag::OnlyTriggeredByCaster))
718 return true;
719
720 if (HasActionSetFlag(AreaTriggerActionSetFlag::CreatorsPartyOnly))
721 {
722 Unit* caster = GetCaster();
723 if (!caster)
724 return true;
725
726 if (!caster->IsInRaidWith(target))
727 return true;
728 }
729 }
730
731 if (Player const* player = target->ToPlayer())
732 {
733 switch (player->getDeathState())
734 {
735 case DEAD:
736 if (!HasActionSetFlag(AreaTriggerActionSetFlag::AllowWhileGhost))
737 return true;
738 break;
739 case CORPSE:
740 if (!HasActionSetFlag(AreaTriggerActionSetFlag::AllowWhileDead))
741 return true;
742 break;
743 default:
744 break;
745 }
746 }
747
749 return true;
750
751 if (conditions)
752 return !sConditionMgr->IsObjectMeetToConditions(target, *conditions);
753
754 return false;
755 });
756 }
757
758 HandleUnitEnterExit(targetList);
759}
760
761void AreaTrigger::SearchUnits(std::vector<Unit*>& targetList, float radius, bool check3D)
762{
763 Trinity::AnyUnitInObjectRangeCheck check(this, radius, check3D, false);
764 if (IsStaticSpawn())
765 {
768 }
769 else
770 {
772 Cell::VisitAllObjects(this, searcher, GetMaxSearchRadius());
773 }
774}
775
776void AreaTrigger::SearchUnitInSphere(UF::AreaTriggerSphere const& sphere, std::vector<Unit*>& targetList)
777{
778 float progress = GetShapeProgress();
779 if (m_areaTriggerData->MorphCurveId)
780 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
781
782 float scale = CalcCurrentScale();
783 float radius = G3D::lerp(sphere.Radius, sphere.RadiusTarget, progress) * scale;
784
785 SearchUnits(targetList, radius, true);
786
787 Trinity::Containers::EraseIf(targetList, [this, radius](Unit const* unit) -> bool
788 {
789 return !unit->IsWithinDist(this, radius);
790 });
791}
792
793void AreaTrigger::SearchUnitInBox(UF::AreaTriggerBox const& box, std::vector<Unit*>& targetList)
794{
795 float progress = GetShapeProgress();
796 if (m_areaTriggerData->MorphCurveId)
797 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
798
799 float scale = CalcCurrentScale();
800 float extentsX = G3D::lerp(box.Extents->Pos.GetPositionX(), box.ExtentsTarget->Pos.GetPositionX(), progress) * scale;
801 float extentsY = G3D::lerp(box.Extents->Pos.GetPositionY(), box.ExtentsTarget->Pos.GetPositionY(), progress) * scale;
802 float extentsZ = G3D::lerp(box.Extents->Pos.GetPositionZ(), box.ExtentsTarget->Pos.GetPositionZ(), progress) * scale;
803 float radius = std::sqrt(extentsX * extentsX + extentsY * extentsY + extentsZ * extentsZ);
804
805 SearchUnits(targetList, radius, false);
806
807 if (targetList.empty())
808 return;
809
810 G3D::Box rotatedBox = G3D::CoordinateFrame(G3D::Quat(_rotation.x, _rotation.y, _rotation.z, _rotation.w), PositionToVector3(GetPosition()))
811 .toWorldSpace(G3D::AABox({ -extentsX, -extentsY, -extentsZ }, { extentsX, extentsY, extentsZ }));
812
813 Trinity::Containers::EraseIf(targetList, [&rotatedBox](Unit const* unit) -> bool
814 {
815 return !rotatedBox.contains(PositionToVector3(*unit));
816 });
817
818#ifdef TRINITY_DEBUG
819 // DebugVisualizeShape
820 if (Player* caster = Object::ToPlayer(GetCaster()); caster && caster->isDebugAreaTriggers)
821 for (int32 corner = 0; corner < 8; ++corner)
822 caster->SummonCreature(1, Vector3ToPosition(rotatedBox.corner(corner)), TEMPSUMMON_TIMED_DESPAWN, 50ms);
823#endif
824}
825
826void AreaTrigger::SearchUnitInPolygon(UF::AreaTriggerPolygon const& polygon, std::vector<Unit*>& targetList)
827{
828 float progress = GetShapeProgress();
829 if (m_areaTriggerData->MorphCurveId)
830 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
831
832 float height = G3D::lerp(polygon.Height, polygon.HeightTarget, progress);
833 float minZ = GetPositionZ() - height;
834 float maxZ = GetPositionZ() + height;
835
836 SearchUnits(targetList, GetMaxSearchRadius(), false);
837
838 if (targetList.empty())
839 return;
840
841 Trinity::Containers::EraseIf(targetList, [this, minZ, maxZ](Unit const* unit) -> bool
842 {
843 return unit->GetPositionZ() < minZ
844 || unit->GetPositionZ() > maxZ
845 || !unit->IsInPolygon2D(*this, _polygonVertices);
846 });
847
848#ifdef TRINITY_DEBUG
849 // DebugVisualizeShape
850 if (Player* caster = Object::ToPlayer(GetCaster()); caster && caster->isDebugAreaTriggers)
851 {
852 for (Position const& vertex : _polygonVertices)
853 {
854 G3D::Vector3 pos = PositionToVector3(GetPosition()) + PositionToVector3(vertex);
855 caster->SummonCreature(1, Vector3ToPosition(pos + G3D::Vector3(0, 0, -height)), TEMPSUMMON_TIMED_DESPAWN, 50ms);
856 caster->SummonCreature(1, Vector3ToPosition(pos + G3D::Vector3(0, 0, +height)), TEMPSUMMON_TIMED_DESPAWN, 50ms);
857 }
858 }
859#endif
860}
861
862void AreaTrigger::SearchUnitInCylinder(UF::AreaTriggerCylinder const& cylinder, std::vector<Unit*>& targetList)
863{
864 float progress = GetShapeProgress();
865 if (m_areaTriggerData->MorphCurveId)
866 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
867
868 float scale = CalcCurrentScale();
869 float radius = G3D::lerp(cylinder.Radius, cylinder.RadiusTarget, progress) * scale;
870 float height = G3D::lerp(cylinder.Height, cylinder.HeightTarget, progress);
872 height *= scale;
873
874 float zOffset = G3D::lerp(cylinder.LocationZOffset, cylinder.LocationZOffsetTarget, progress) * scale;
875
876 SearchUnits(targetList, std::sqrt(radius * radius + height * height), false);
877
878 if (targetList.empty())
879 return;
880
881 G3D::Cylinder rotatedCylinder = G3D::CoordinateFrame(G3D::Quat(_rotation.x, _rotation.y, _rotation.z, _rotation.w), PositionToVector3(GetPosition()))
882 .toWorldSpace(G3D::Cylinder(
883 { 0.0f, 0.0f, 0.0f + zOffset },
884 { 0.0f, 0.0f, 0.0f + zOffset + height },
885 radius));
886
887 Trinity::Containers::EraseIf(targetList, [&rotatedCylinder](Unit const* unit) -> bool
888 {
889 return !rotatedCylinder.contains(PositionToVector3(*unit));
890 });
891
892#ifdef TRINITY_DEBUG
893 // DebugVisualizeShape
894 if (Player* caster = Object::ToPlayer(GetCaster()); caster && caster->isDebugAreaTriggers)
895 for (int32 end = 0; end < 2; ++end)
896 caster->SummonCreature(1, Vector3ToPosition(rotatedCylinder.point(end)), TEMPSUMMON_TIMED_DESPAWN, 50ms);
897#endif
898}
899
900void AreaTrigger::SearchUnitInDisk(UF::AreaTriggerDisk const& disk, std::vector<Unit*>& targetList)
901{
902 float progress = GetShapeProgress();
903 if (m_areaTriggerData->MorphCurveId)
904 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
905
906 float scale = CalcCurrentScale();
907 float innerRadius = G3D::lerp(disk.InnerRadius, disk.InnerRadiusTarget, progress) * scale;
908 float outerRadius = G3D::lerp(disk.OuterRadius, disk.OuterRadiusTarget, progress) * scale;
909 float height = G3D::lerp(disk.Height, disk.HeightTarget, progress);
911 height *= scale;
912
913 float zOffset = G3D::lerp(disk.LocationZOffset, disk.LocationZOffsetTarget, progress) * scale;
914
915 SearchUnits(targetList, std::sqrt(outerRadius * outerRadius + height * height), false);
916
917 if (targetList.empty())
918 return;
919
920 G3D::Cylinder innerCylinder = G3D::CoordinateFrame(G3D::Quat(_rotation.x, _rotation.y, _rotation.z, _rotation.w), PositionToVector3(GetPosition()))
921 .toWorldSpace(G3D::Cylinder(
922 { 0.0f, 0.0f, 0.0f + zOffset },
923 { 0.0f, 0.0f, 0.0f + zOffset + height },
924 innerRadius));
925
926 G3D::Cylinder outerCylinder(innerCylinder.point(0), innerCylinder.point(1), outerRadius);
927
928 Trinity::Containers::EraseIf(targetList, [&innerCylinder, &outerCylinder](Unit const* unit) -> bool
929 {
930 G3D::Vector3 position = PositionToVector3(*unit);
931 return innerCylinder.contains(position) || !outerCylinder.contains(position);
932 });
933
934#ifdef TRINITY_DEBUG
935 // DebugVisualizeShape
936 if (Player* caster = Object::ToPlayer(GetCaster()); caster && caster->isDebugAreaTriggers)
937 for (int32 end = 0; end < 2; ++end)
938 caster->SummonCreature(1, Vector3ToPosition(innerCylinder.point(end)), TEMPSUMMON_TIMED_DESPAWN, 50ms);
939#endif
940}
941
942void AreaTrigger::SearchUnitInBoundedPlane(UF::AreaTriggerBoundedPlane const& boundedPlane, std::vector<Unit*>& targetList)
943{
944 float progress = GetShapeProgress();
945 if (m_areaTriggerData->MorphCurveId)
946 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
947
948 float scale = CalcCurrentScale();
949 float extentsY = G3D::lerp(boundedPlane.ExtentsY, boundedPlane.ExtentsTargetY, progress) * scale;
950 float extentsZ = G3D::lerp(boundedPlane.ExtentsZ, boundedPlane.ExtentsTargetZ, progress) * scale;
951 float radius = std::sqrt(extentsY * extentsY + extentsZ * extentsZ);
952
953 SearchUnits(targetList, radius, false);
954
955 if (targetList.empty())
956 return;
957
958 G3D::CoordinateFrame coordinateFrame = G3D::CoordinateFrame(G3D::Quat(_rotation.x, _rotation.y, _rotation.z, _rotation.w), PositionToVector3(GetPosition()));
959
960 G3D::Vector3 corners[4] =
961 {
962 coordinateFrame.pointToWorldSpace(G3D::Vector3(0.0f, -extentsY, -extentsZ)),
963 coordinateFrame.pointToWorldSpace(G3D::Vector3(0.0f, extentsY, -extentsZ)),
964 coordinateFrame.pointToWorldSpace(G3D::Vector3(0.0f, -extentsY, extentsZ)),
965 coordinateFrame.pointToWorldSpace(G3D::Vector3(0.0f, extentsY, extentsZ))
966 };
967
968 Trinity::Containers::EraseIf(targetList, [&corners](Unit const* unit) -> bool
969 {
970 G3D::Vector3 closestPoint = G3D::CollisionDetection::closestPointToRectangle(corners[0], corners[1], corners[2], corners[3], PositionToVector3(*unit));
971 return !unit->IsInDist(closestPoint.x, closestPoint.y, closestPoint.z, unit->GetCombatReach());
972 });
973
974#ifdef TRINITY_DEBUG
975 // DebugVisualizeShape
976 if (Player* caster = Object::ToPlayer(GetCaster()); caster && caster->isDebugAreaTriggers)
977 for (G3D::Vector3 const& corner : corners)
978 caster->SummonCreature(1, Vector3ToPosition(corner), TEMPSUMMON_TIMED_DESPAWN, 50ms);
979#endif
980}
981
982void AreaTrigger::HandleUnitEnterExit(std::vector<Unit*> const& newTargetList, AreaTriggerExitReason exitMode)
983{
984 GuidUnorderedSet exitUnits(std::move(_insideUnits));
985
986 std::vector<Unit*> enteringUnits;
987
988 for (Unit* unit : newTargetList)
989 {
990 if (exitUnits.erase(unit->GetGUID()) == 0) // erase(key_type) returns number of elements erased
991 enteringUnits.push_back(unit);
992
993 _insideUnits.insert(unit->GetGUID());
994 }
995
996 // Handle after _insideUnits have been reinserted so we can use GetInsideUnits() in hooks
997 for (Unit* unit : enteringUnits)
998 HandleUnitEnter(unit);
999
1000 for (ObjectGuid const& exitUnitGuid : exitUnits)
1001 if (Unit* leavingUnit = ObjectAccessor::GetUnit(*this, exitUnitGuid))
1002 HandleUnitExitInternal(leavingUnit, exitMode);
1003
1005
1006 if (IsStaticSpawn())
1007 setActive(!_insideUnits.empty());
1008}
1009
1011{
1012 if (Player* player = unit->ToPlayer())
1013 {
1014 if (player->isDebugAreaTriggers)
1016
1017 player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_ENTER, GetEntry(), 1);
1018
1019 if (GetTemplate()->ActionSetId)
1020 player->UpdateCriteria(CriteriaType::EnterAreaTriggerWithActionSet, GetTemplate()->ActionSetId);
1021 }
1022
1023 DoActions(unit);
1024
1025 _ai->OnUnitEnter(unit);
1026
1027 // OnUnitEnter script can despawn this areatrigger or teleport player to a different map
1028 if (!IsInWorld() || !IsInMap(unit))
1029 return;
1030
1031 // Register areatrigger in Unit after actions/scripts to allow them to determine
1032 // if the unit is in one or more areatriggers with the same id
1033 // without forcing every script to have additional logic excluding this areatrigger
1034 unit->EnterAreaTrigger(this);
1035}
1036
1038{
1040
1041 if (Player* player = unit->ToPlayer())
1042 {
1043 if (player->isDebugAreaTriggers)
1045
1046 if (canTriggerOnExit)
1047 {
1048 player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_EXIT, GetEntry(), 1);
1049
1050 if (GetTemplate()->ActionSetId)
1051 player->UpdateCriteria(CriteriaType::LeaveAreaTriggerWithActionSet, GetTemplate()->ActionSetId);
1052 }
1053 }
1054
1055 UndoActions(unit);
1056
1057 // OnUnitExit script can teleport player to another map, causing it to attempt to exit the areatrigger again (from Unit::ExitAllAreaTriggers)
1058 unit->ExitAreaTrigger(this);
1059
1060 if (canTriggerOnExit)
1061 _ai->OnUnitExit(unit, exitMode);
1062}
1063
1065{
1066 _insideUnits.erase(unit->GetGUID());
1067
1069
1071}
1072
1074{
1075 if (_spawnId)
1076 {
1077 if (AreaTriggerSpawn const* spawn = ASSERT_NOTNULL(sAreaTriggerDataStore->GetAreaTriggerSpawn(_spawnId)))
1078 {
1079 if (spawn->scriptId)
1080 return spawn->scriptId;
1081 }
1082 }
1083
1084 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
1085 return createProperties->ScriptId;
1086
1087 return 0;
1088}
1089
1091{
1092 return ObjectAccessor::GetUnit(*this, GetCasterGuid());
1093}
1094
1096{
1097 return ObjectAccessor::GetUnit(*this, _targetGuid);
1098}
1099
1101{
1102 if (Unit const* caster = GetCaster())
1103 return caster->GetFaction();
1104
1105 return 0;
1106}
1107
1109{
1110 std::visit([this]<typename ShapeType>(ShapeType const& shapeData)
1111 {
1112 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
1113
1114 if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::Sphere>)
1115 {
1117 auto sphere = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerSphere>);
1118 SetUpdateFieldValue(sphere.ModifyValue(&UF::AreaTriggerSphere::Radius), shapeData.Radius);
1119 SetUpdateFieldValue(sphere.ModifyValue(&UF::AreaTriggerSphere::RadiusTarget), shapeData.RadiusTarget);
1120 }
1121 else if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::Box>)
1122 {
1124 auto box = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerBox>);
1125 SetUpdateFieldValue(box.ModifyValue(&UF::AreaTriggerBox::Extents), shapeData.Extents);
1126 SetUpdateFieldValue(box.ModifyValue(&UF::AreaTriggerBox::ExtentsTarget), shapeData.ExtentsTarget);
1127 }
1128 else if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::Polygon>)
1129 {
1130 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), uint8(shapeData.Type));
1131 auto polygon = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerPolygon>);
1132 auto vertices = polygon.ModifyValue(&UF::AreaTriggerPolygon::Vertices);
1134 for (TaggedPosition<XY> const& vertex : shapeData.PolygonVertices)
1135 AddDynamicUpdateFieldValue(vertices) = vertex;
1136 auto verticesTarget = polygon.ModifyValue(&UF::AreaTriggerPolygon::VerticesTarget);
1137 ClearDynamicUpdateFieldValues(verticesTarget);
1138 for (TaggedPosition<XY> const& vertex : shapeData.PolygonVerticesTarget)
1139 AddDynamicUpdateFieldValue(verticesTarget) = vertex;
1140 SetUpdateFieldValue(polygon.ModifyValue(&UF::AreaTriggerPolygon::Height), shapeData.Height);
1141 SetUpdateFieldValue(polygon.ModifyValue(&UF::AreaTriggerPolygon::HeightTarget), shapeData.HeightTarget);
1142 }
1143 else if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::Cylinder>)
1144 {
1146 auto cylinder = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerCylinder>);
1147 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::Radius), shapeData.Radius);
1148 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::RadiusTarget), shapeData.RadiusTarget);
1149 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::Height), shapeData.Height);
1150 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::HeightTarget), shapeData.HeightTarget);
1151 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::LocationZOffset), shapeData.LocationZOffset);
1152 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::LocationZOffsetTarget), shapeData.LocationZOffsetTarget);
1153 }
1154 else if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::Disk>)
1155 {
1157 auto disk = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerDisk>);
1158 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::InnerRadius), shapeData.InnerRadius);
1159 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::InnerRadiusTarget), shapeData.InnerRadiusTarget);
1160 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::OuterRadius), shapeData.OuterRadius);
1161 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::OuterRadiusTarget), shapeData.OuterRadiusTarget);
1162 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::Height), shapeData.Height);
1163 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::HeightTarget), shapeData.HeightTarget);
1164 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::LocationZOffset), shapeData.LocationZOffset);
1165 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::LocationZOffsetTarget), shapeData.LocationZOffsetTarget);
1166 }
1167 else if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::BoundedPlane>)
1168 {
1170 auto boundedPlane = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerBoundedPlane>);
1171 SetUpdateFieldValue(boundedPlane.ModifyValue(&UF::AreaTriggerBoundedPlane::ExtentsY), shapeData.ExtentsY);
1172 SetUpdateFieldValue(boundedPlane.ModifyValue(&UF::AreaTriggerBoundedPlane::ExtentsZ), shapeData.ExtentsZ);
1173 SetUpdateFieldValue(boundedPlane.ModifyValue(&UF::AreaTriggerBoundedPlane::ExtentsTargetY), shapeData.ExtentsTargetY);
1174 SetUpdateFieldValue(boundedPlane.ModifyValue(&UF::AreaTriggerBoundedPlane::ExtentsTargetZ), shapeData.ExtentsTargetZ);
1175 }
1176 else
1177 static_assert(Trinity::dependant_false_v<ShapeType>, "Unsupported shape type");
1178 }, shape.Data);
1179
1180 if (IsInWorld())
1182}
1183
1185{
1186 return *m_areaTriggerData->BoundsRadius2D * CalcCurrentScale();
1187}
1188
1190{
1191 UF::AreaTriggerPolygon const* shape = m_areaTriggerData->ShapeData.Get<UF::AreaTriggerPolygon>();
1192
1193 // No need to recalculate, orientation didn't change
1195 return;
1196
1197 _polygonVertices.assign(shape->Vertices.begin(), shape->Vertices.end());
1198 if (!shape->VerticesTarget.empty())
1199 {
1200 float progress = GetShapeProgress();
1201 if (m_areaTriggerData->MorphCurveId)
1202 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
1203
1204 for (std::size_t i = 0; i < _polygonVertices.size(); ++i)
1205 {
1206 Position& vertex = _polygonVertices[i];
1207 Position const& vertexTarget = shape->VerticesTarget[i].Pos;
1208
1209 vertex.m_positionX = G3D::lerp(vertex.GetPositionX(), vertexTarget.GetPositionX(), progress);
1210 vertex.m_positionY = G3D::lerp(vertex.GetPositionY(), vertexTarget.GetPositionY(), progress);
1211 }
1212 }
1213
1214 G3D::Matrix3 rotationMatrix(G3D::Quat(_rotation.x, _rotation.y, _rotation.z, _rotation.w));
1215
1216 // This is needed to rotate the vertices, following orientation
1217 for (Position& vertice : _polygonVertices)
1218 {
1219 G3D::Vector3 transformed = rotationMatrix * PositionToVector3(vertice);
1220 vertice.Relocate(transformed.x, transformed.y);
1221 }
1222
1224}
1225
1227{
1228 return m_areaTriggerData->OverrideMoveCurveX->OverrideActive
1229 && m_areaTriggerData->OverrideMoveCurveY->OverrideActive
1230 && m_areaTriggerData->OverrideMoveCurveZ->OverrideActive;
1231}
1232
1238
1239bool UnitFitToActionRequirement(Unit* unit, Unit* caster, AreaTriggerAction const& action)
1240{
1241 switch (action.TargetType)
1242 {
1244 {
1245 return caster->IsValidAssistTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID()));
1246 }
1248 {
1249 return caster->IsValidAttackTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID()));
1250 }
1252 {
1253 return caster->IsInRaidWith(unit);
1254 }
1256 {
1257 return caster->IsInPartyWith(unit);
1258 }
1260 {
1261 return unit->GetGUID() == caster->GetGUID();
1262 }
1264 default:
1265 break;
1266 }
1267
1268 return true;
1269}
1270
1272{
1273 Unit* caster = IsStaticSpawn() ? unit : GetCaster();
1274
1275 if (caster && GetTemplate())
1276 {
1277 for (AreaTriggerAction const& action : GetTemplate()->Actions)
1278 {
1279 if (IsStaticSpawn() || UnitFitToActionRequirement(unit, caster, action))
1280 {
1281 switch (action.ActionType)
1282 {
1284 caster->CastSpell(unit, action.Param, CastSpellExtraArgs(TRIGGERED_FULL_MASK)
1285 .SetOriginalCastId(m_areaTriggerData->CreatingEffectGUID->IsCast() ? *m_areaTriggerData->CreatingEffectGUID : ObjectGuid::Empty));
1286 break;
1288 caster->AddAura(action.Param, unit);
1289 break;
1291 {
1292 if (WorldSafeLocsEntry const* safeLoc = sObjectMgr->GetWorldSafeLoc(action.Param))
1293 {
1294 if (Player* player = caster->ToPlayer())
1295 {
1296 if (player->GetMapId() != safeLoc->Loc.GetMapId())
1297 {
1298 if (WorldSafeLocsEntry const* instanceEntrance = player->GetInstanceEntrance(safeLoc->Loc.GetMapId()))
1299 safeLoc = instanceEntrance;
1300 }
1301 player->TeleportTo(safeLoc->Loc);
1302 }
1303 }
1304 break;
1305 }
1307 if (Player* player = caster->ToPlayer())
1308 {
1309 player->GetRestMgr().SetInnTrigger(InnAreaTrigger{ .IsDBC = false });
1310 player->GetRestMgr().SetRestFlag(REST_FLAG_IN_TAVERN);
1311 }
1312 break;
1313 default:
1314 break;
1315 }
1316 }
1317 }
1318 }
1319}
1320
1322{
1323 if (GetTemplate())
1324 {
1325 for (AreaTriggerAction const& action : GetTemplate()->Actions)
1326 {
1327 switch (action.ActionType)
1328 {
1330 [[fallthrough]];
1332 unit->RemoveAurasDueToSpell(action.Param, GetCasterGuid());
1333 break;
1335 if (Player* player = unit->ToPlayer())
1336 player->GetRestMgr().SetInnTrigger(std::nullopt);
1337 break;
1338 default:
1339 break;
1340 }
1341 }
1342 }
1343}
1344
1346{
1347 auto [movementUpdateResult, newPosition, newRotation] = CalculateWorldPositionAndRotation();
1348
1350 if (Unit* target = GetTarget())
1351 RelocateStationaryPosition(target->GetPosition());
1352
1353 Position oldPosition = GetPosition();
1354 QuaternionData oldRotation = std::exchange(_rotation, { newRotation.x, newRotation.y, newRotation.z, newRotation.w });
1355
1356 if (newPosition != oldPosition)
1357 {
1358 GetMap()->AreaTriggerRelocation(this, newPosition.GetPositionX(), newPosition.GetPositionY(), newPosition.GetPositionZ(), newPosition.GetOrientation());
1359 }
1360 else
1361 {
1362 SetOrientation(newPosition.GetOrientation());
1363 if (oldRotation != _rotation)
1364 UpdateShape();
1365 }
1366
1367#ifdef TRINITY_DEBUG
1368 if (movementUpdateResult != MovementUpdateResult::None)
1370#endif
1371
1372 if (movementUpdateResult == MovementUpdateResult::Arrived)
1373 {
1375 _ai->OnDestinationReached();
1376
1377 _reachedDestination = true;
1378 }
1379}
1380
1382{
1383 auto [status, localPosition, localRotation] = CalculateLocalPositionAndRotation();
1384 MovementUpdateWorldResult worldResult {
1385 .Status = status,
1386 .Position = Vector3ToPosition(localPosition),
1387 .Rotation = G3D::Quat::fromYPRAngles(localRotation.z, localRotation.y, localRotation.x)
1388 };
1389
1391 {
1392 if (Unit* target = GetTarget())
1393 {
1394 worldResult.Position = target->GetPositionWithOffset(worldResult.Position);
1395
1397 worldResult.Rotation = G3D::Quat::fromAxisAngleRotation(G3D::Vector3::unitZ(), target->GetOrientation()) * worldResult.Rotation;
1398
1399 if (worldResult.Status == MovementUpdateResult::None)
1400 worldResult.Status = MovementUpdateResult::Moved;
1401 }
1402 }
1403 else if (TransportBase const* transport = GetTransport())
1404 {
1405 worldResult.Position = transport->GetPositionWithOffset(worldResult.Position);
1406
1408 worldResult.Rotation = G3D::Quat::fromAxisAngleRotation(G3D::Vector3::unitZ(), transport->GetTransportOrientation()) * worldResult.Rotation;
1409 }
1410 else
1411 worldResult.Position = GetMovementOrigin().GetPositionWithOffset(worldResult.Position);
1412
1413 worldResult.Rotation.toYPRAngles(localRotation.z, localRotation.y, localRotation.x);
1414 worldResult.Position.SetOrientation(localRotation.z);
1415
1416 return worldResult;
1417}
1418
1428
1430{
1432
1433 if (m_areaTriggerData->TargetRollPitchYaw.has_value())
1434 {
1435 float progress = GetShapeProgress();
1436 if (m_areaTriggerData->MorphCurveId)
1437 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
1438
1439 result.Rotation += PositionToVector3(m_areaTriggerData->RollPitchYaw->Pos)
1440 .lerp(PositionToVector3(m_areaTriggerData->TargetRollPitchYaw->Pos), progress);
1441 }
1442 else
1443 result.Rotation += PositionToVector3(m_areaTriggerData->RollPitchYaw->Pos);
1444
1445 if (HasOverridePosition())
1446 {
1448
1449 float progress = GetOverridePosProgress();
1450 result.Position.x = GetOverrideCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveX, progress);
1451 result.Position.y = GetOverrideCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveY, progress);
1452 result.Position.z = GetOverrideCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveZ, progress);
1453
1455 result.Position = PositionToVector3(GetMovementOrigin().GetPositionOffsetTo(Vector3ToPosition(result.Position)));
1456 }
1457
1458 return result;
1459}
1460
1461void AreaTrigger::InitSplineOffsets(std::vector<Position> const& offsets, Optional<float> overrideSpeed /*= {}*/, Optional<bool> speedIsTimeInSeconds /*= {}*/)
1462{
1463 float angleSin = std::sin(GetOrientation());
1464 float angleCos = std::cos(GetOrientation());
1465
1466 // This is needed to rotate the spline, following caster orientation
1467 std::vector<G3D::Vector3> rotatedPoints;
1468 rotatedPoints.resize(offsets.size());
1469 for (std::size_t i = 0; i < offsets.size(); ++i)
1470 {
1471 Position const& offset = offsets[i];
1472 rotatedPoints[i].x = GetPositionX() + (offset.GetPositionX() * angleCos - offset.GetPositionY() * angleSin);
1473 rotatedPoints[i].y = GetPositionY() + (offset.GetPositionY() * angleCos + offset.GetPositionX() * angleSin);
1474 rotatedPoints[i].z = GetPositionZ();
1475
1476 UpdateAllowedPositionZ(rotatedPoints[i].x, rotatedPoints[i].y, rotatedPoints[i].z);
1477 rotatedPoints[i].z += offset.GetPositionZ();
1478 }
1479
1480 InitSplines(rotatedPoints, overrideSpeed, speedIsTimeInSeconds);
1481}
1482
1483void AreaTrigger::InitSplines(std::vector<G3D::Vector3> const& splinePoints, Optional<float> overrideSpeed /*= {}*/, Optional<bool> speedIsTimeInSeconds /*= {}*/)
1484{
1485 if (splinePoints.size() < 2)
1486 return;
1487
1488 _spline = std::make_unique<::Movement::Spline<float>>();
1489 _reachedDestination = false;
1490
1491 std::vector<G3D::Vector3> offsets(splinePoints.size());
1492 for (std::size_t i = 0; i < splinePoints.size(); ++i)
1493 offsets[i] = PositionToVector3(GetStationaryPosition().GetPositionOffsetTo(Vector3ToPosition(splinePoints[i])));
1494
1495 _spline->init_spline(offsets.data(), offsets.size(), offsets.size() > 2 ? ::Movement::SplineBase::ModeCatmullrom : ::Movement::SplineBase::ModeLinear, _stationaryPosition.GetOrientation());
1496 _spline->initLengths();
1497
1498 float speed = overrideSpeed.value_or(GetCreateProperties()->Speed);
1499 if (speed <= 0.0f)
1500 speed = 1.0f;
1501
1502 uint32 timeToTarget = (speedIsTimeInSeconds.value_or(GetCreateProperties()->SpeedIsTime)
1503 ? speed
1504 : _spline->length() / speed) * static_cast<float>(IN_MILLISECONDS);
1505
1506 if (!timeToTarget)
1507 {
1508 _spline.reset();
1509 return;
1510 }
1511
1512 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
1513 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTarget), timeToTarget);
1515
1518 auto pathData = areaTriggerData.ModifyValue(&UF::AreaTriggerData::PathData, UF::VariantCase<UF::AreaTriggerSplineCalculator>);
1520 auto points = pathData.ModifyValue(&UF::AreaTriggerSplineCalculator::Points);
1521
1524 {
1525 for (G3D::Vector3 const& point : _spline->getPoints())
1526 AddDynamicUpdateFieldValue(points) = GetStationaryPosition().GetPositionWithOffset(Vector3ToPosition(point));
1527 }
1528 else
1529 {
1530 for (G3D::Vector3 const& point : _spline->getPoints())
1531 AddDynamicUpdateFieldValue(points) = Vector3ToPosition(point);
1532 }
1533}
1534
1536{
1538 if (now >= *m_areaTriggerData->MovementStartTime)
1539 return now - *m_areaTriggerData->MovementStartTime;
1540 return 0;
1541}
1542
1543void AreaTrigger::InitOrbit(AreaTriggerOrbitInfo const& orbit, Optional<float> overrideSpeed /*= {}*/, Optional<bool> speedIsTimeInSeconds /*= {}*/)
1544{
1545 // Circular movement requires either a center position or an attached unit
1546 ASSERT(orbit.Center.has_value() || orbit.PathTarget.has_value());
1547
1548 float speed = overrideSpeed.value_or(GetCreateProperties()->Speed);
1549 if (speed <= 0.0f)
1550 speed = 1.0f;
1551
1552 uint32 timeToTarget = (speedIsTimeInSeconds.value_or(GetCreateProperties()->SpeedIsTime)
1553 ? speed
1554 : static_cast<uint32>(orbit.Radius * 2.0f * static_cast<float>(M_PI) / speed)) * static_cast<float>(IN_MILLISECONDS);
1555
1556 if (!timeToTarget)
1557 return;
1558
1559 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
1560 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTarget), timeToTarget);
1562 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OrbitPathTarget), orbit.PathTarget.value_or(ObjectGuid::Empty));
1563 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ZOffset), orbit.ZOffset);
1564 if (orbit.CanLoop)
1566 else
1568
1571 auto pathData = areaTriggerData.ModifyValue(&UF::AreaTriggerData::PathData, UF::VariantCase<UF::AreaTriggerOrbit>);
1573 SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerOrbit::Radius), orbit.Radius);
1577
1578 Position center = orbit.Center.value_or(Position());
1579 if (orbit.Center)
1581 center = attachedTo->GetPositionOffsetTo(*orbit.Center);
1582
1583 SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerOrbit::Center), center);
1584}
1585
1587{
1588 float currentTimePercent = std::clamp(float(GetElapsedTimeForMovement()) / float(GetTimeToTarget()), 0.0f, 1.0f);
1589 bool reachedDestination = currentTimePercent >= 1.0f;
1590
1591 if (m_areaTriggerData->MoveCurveId)
1592 {
1593 float progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MoveCurveId, currentTimePercent);
1594 if (progress < 0.f || progress > 1.f)
1595 {
1596 AreaTriggerCreateProperties const* createProperties = GetCreateProperties();
1597 TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (Id: {}, AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})) has wrong progress ({}) caused by curve calculation (MoveCurveId: {})",
1598 GetEntry(), createProperties->Id.Id, uint32(createProperties->Id.IsCustom), progress, *m_areaTriggerData->MoveCurveId);
1599 }
1600 else
1601 currentTimePercent = progress;
1602 }
1603
1604 int32 lastPositionIndex = 0;
1605 float percentFromLastPoint = 0;
1606 _spline->computeIndex(currentTimePercent, lastPositionIndex, percentFromLastPoint);
1607
1608 G3D::Vector3 currentPosition;
1609 _spline->evaluate_percent(lastPositionIndex, percentFromLastPoint, currentPosition);
1610
1611 float orientation = 0.0f;
1612 if (m_areaTriggerData->FacingCurveId)
1613 orientation += sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetShapeProgress());
1614
1616 {
1617 G3D::Vector3 derivative;
1618 _spline->evaluate_derivative(lastPositionIndex, percentFromLastPoint, derivative);
1619 if (derivative.x != 0.0f || derivative.y != 0.0f)
1620 orientation += std::atan2(derivative.y, derivative.x);
1621 }
1622
1623 return {
1624 .Status = reachedDestination ? MovementUpdateResult::Arrived : MovementUpdateResult::Moved,
1625 .Position = currentPosition,
1626 .Rotation = G3D::Vector3(0.0f, 0.0f, orientation)
1627 };
1628}
1629
1631{
1632 uint32 movementTime = GetElapsedTimeForMovement();
1633 uint32 timeToTarget = GetTimeToTarget() + orbit.ExtraTimeForBlending;
1634 bool firstLoop = true;
1636 {
1637 // remove ExtraTimeForBlending if not on first loop
1638 if (movementTime > timeToTarget)
1639 {
1640 timeToTarget -= orbit.ExtraTimeForBlending;
1641 movementTime = (movementTime - orbit.ExtraTimeForBlending) % timeToTarget;
1642 firstLoop = false;
1643 }
1644 }
1645
1646 float pathProgress = float(movementTime) / float(timeToTarget);
1647 if (m_areaTriggerData->MoveCurveId)
1648 pathProgress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MoveCurveId, pathProgress);
1649
1650 // We already made one circle and can't loop
1652 pathProgress = std::min(1.f, pathProgress);
1653
1654 float radius = orbit.Radius;
1655 if (firstLoop && G3D::fuzzyNe(orbit.BlendFromRadius, radius))
1656 {
1657 float blendCurve = std::clamp((orbit.BlendFromRadius - radius) / radius, 1.0f, 4.0f);
1658 float blendProgress = std::clamp(std::abs(4.0f * pathProgress / blendCurve), 0.0f, 1.0f);
1659 radius = G3D::lerp(orbit.BlendFromRadius, radius, blendProgress);
1660 }
1661
1662 float angle = 2.0f * float(M_PI) * pathProgress;
1663
1664 // Adapt angle depending of circle direction
1665 if (!orbit.CounterClockwise)
1666 angle *= -1;
1667
1668 angle += orbit.InitialAngle;
1669
1670 G3D::Vector3 position =
1671 {
1672 radius * std::cos(angle),
1673 radius * std::sin(angle),
1674 m_areaTriggerData->ZOffset
1675 };
1676
1677 float orientation = 0.0f;
1678 if (m_areaTriggerData->FacingCurveId)
1679 orientation = sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetShapeProgress());
1680
1682 {
1683 orientation += angle;
1684 orientation += orbit.CounterClockwise ? float(M_PI_4) : -float(M_PI_4);
1685 }
1686
1687 return {
1689 .Position = position,
1690 .Rotation = G3D::Vector3(0.0f, 0.0f, orientation)
1691 };
1692}
1693
1695{
1696 float orientation = 0.0f;
1697 if (m_areaTriggerData->FacingCurveId)
1698 orientation = sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetShapeProgress());
1699
1701 orientation += *m_areaTriggerData->Facing;
1702
1703 return {
1705 .Position = G3D::Vector3::zero(),
1706 .Rotation = G3D::Vector3(0.0f, 0.0f, orientation)
1707 };
1708}
1709
1711{
1713 Position const& operator()(UF::AreaTriggerOrbit const& orbit) const
1714 {
1715 if (!at->m_areaTriggerData->OrbitPathTarget->IsEmpty())
1716 {
1717 if (WorldObject const* pathTarget = ObjectAccessor::GetWorldObject(*at, *at->m_areaTriggerData->OrbitPathTarget))
1718 return *pathTarget;
1719 return at->GetStationaryPosition();
1720 }
1721
1722 return orbit.Center->Pos;
1723 }
1724 Position const& operator()(std::monostate) const { return at->GetStationaryPosition(); }
1725 Position const& operator()(UF::AreaTriggerMovementScript const& script) const { return script.Center->Pos; }
1726
1728};
1729
1731{
1732 return m_areaTriggerData->PathData.Visit(AreaTriggerMovementOriginVisitor{ this });
1733}
1734
1736{
1739 || (*m_areaTriggerData->OverrideScaleCurve->OverrideActive && !(*m_areaTriggerData->OverrideScaleCurve->ParameterCurve & 1))
1740 || *m_areaTriggerData->ScaleCurveId
1741 || (*m_areaTriggerData->ExtraScaleCurve->OverrideActive && !(*m_areaTriggerData->ExtraScaleCurve->ParameterCurve & 1))
1743 && (!(*m_areaTriggerData->OverrideMoveCurveX->ParameterCurve & 1)
1744 || !(*m_areaTriggerData->OverrideMoveCurveY->ParameterCurve & 1)
1745 || !(*m_areaTriggerData->OverrideMoveCurveZ->ParameterCurve & 1)))
1746 || (m_areaTriggerData->TargetRollPitchYaw.has_value() && *m_areaTriggerData->RollPitchYaw != *m_areaTriggerData->TargetRollPitchYaw)
1747 || GetCreateProperties()->Shape.IsDynamic())
1749 else
1751}
1752
1754{
1755 if (std::ranges::any_of(_insideUnits, [](ObjectGuid const& guid) { return guid.IsPlayer(); }))
1757 else
1759}
1760
1762{
1763 if (Unit* caster = GetCaster())
1764 if (Player* player = caster->ToPlayer())
1765 if (player->isDebugAreaTriggers)
1766 player->SummonCreature(1, *this, TEMPSUMMON_TIMED_DESPAWN, 250ms);
1767}
1768
1770{
1771 AI_Destroy();
1773 _ai->OnInitialize();
1774}
1775
1777{
1778 _ai.reset();
1779}
1780
1781bool AreaTrigger::IsNeverVisibleFor(WorldObject const* seer, bool allowServersideObjects) const
1782{
1783 if (WorldObject::IsNeverVisibleFor(seer, allowServersideObjects))
1784 return true;
1785
1786 if (IsServerSide() && !allowServersideObjects)
1787 {
1788 if (Player const* seerPlayer = seer->ToPlayer())
1789 return !seerPlayer->isDebugAreaTriggers;
1790
1791 return true;
1792 }
1793
1794 return false;
1795}
1796
1798{
1799 m_objectData->WriteCreate(flags, data, target, this);
1800 m_areaTriggerData->WriteCreate(flags, data, target, this);
1801}
1802
1804{
1806
1808 m_objectData->WriteUpdate(flags, data, target, this);
1809
1811 m_areaTriggerData->WriteUpdate(flags, data, target, this);
1812}
1813
1815 UF::AreaTriggerData::Mask const& requestedAreaTriggerMask, Player const* target, bool ignoreNestedChangesMask) const
1816{
1819 if (requestedObjectMask.IsAnySet())
1820 valuesMask.Set(TYPEID_OBJECT);
1821
1822 if (requestedAreaTriggerMask.IsAnySet())
1823 valuesMask.Set(TYPEID_AREATRIGGER);
1824
1825 ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
1826 std::size_t sizePos = buffer.wpos();
1827 buffer << uint32(0);
1829 buffer << uint32(valuesMask.GetBlock(0));
1830
1831 if (valuesMask[TYPEID_OBJECT])
1832 m_objectData->WriteUpdate(requestedObjectMask, buffer, target, this, ignoreNestedChangesMask);
1833
1834 if (valuesMask[TYPEID_AREATRIGGER])
1835 m_areaTriggerData->WriteUpdate(requestedAreaTriggerMask, buffer, target, this, ignoreNestedChangesMask);
1836
1837 buffer.put<uint32>(sizePos, buffer.wpos() - sizePos - 4);
1838
1839 data->AddUpdateBlock();
1840}
1841
1843{
1844 UpdateData udata(Owner->GetMapId());
1845 WorldPacket packet;
1846
1848
1849 udata.BuildPacket(&packet);
1850 player->SendDirectMessage(&packet);
1851}
1852
#define sAreaTriggerDataStore
@ AREATRIGGER_ACTION_ADDAURA
@ AREATRIGGER_ACTION_TELEPORT
@ AREATRIGGER_ACTION_TAVERN
@ AREATRIGGER_ACTION_CAST
@ AREATRIGGER_ACTION_USER_ENEMY
@ AREATRIGGER_ACTION_USER_ANY
@ AREATRIGGER_ACTION_USER_FRIEND
@ AREATRIGGER_ACTION_USER_CASTER
@ AREATRIGGER_ACTION_USER_RAID
@ AREATRIGGER_ACTION_USER_PARTY
MovementUpdateResult
bool UnitFitToActionRequirement(Unit *unit, Unit *caster, AreaTriggerAction const &action)
AreaTriggerFieldFlags
Definition AreaTrigger.h:44
AreaTriggerPathType
Definition AreaTrigger.h:62
AreaTriggerExitReason
Definition AreaTrigger.h:70
@ IN_MILLISECONDS
Definition Common.h:38
#define M_PI
Definition Common.h:118
#define M_PI_4
Definition Common.h:122
std::vector< Condition > ConditionContainer
#define sConditionMgr
#define sDB2Manager
Definition DB2Stores.h:579
CurveInterpolationMode
Definition DBCEnums.h:923
@ DIFFICULTY_NONE
Definition DBCEnums.h:936
@ LeaveAreaTriggerWithActionSet
@ EnterAreaTriggerWithActionSet
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
uint16 flags
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:74
#define ASSERT
Definition Errors.h:72
@ LANG_DEBUG_AREATRIGGER_ENTITY_LEFT
Definition Language.h:1028
@ LANG_DEBUG_AREATRIGGER_ENTITY_ENTERED
Definition Language.h:1027
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
@ TEMPSUMMON_TIMED_DESPAWN
std::unordered_set< ObjectGuid > GuidUnorderedSet
Definition ObjectGuid.h:435
@ TYPEID_OBJECT
Definition ObjectGuid.h:38
@ TYPEID_AREATRIGGER
Definition ObjectGuid.h:49
#define sObjectMgr
Definition ObjectMgr.h:1873
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ QUEST_OBJECTIVE_AREA_TRIGGER_EXIT
Definition QuestDef.h:374
@ QUEST_OBJECTIVE_AREA_TRIGGER_ENTER
Definition QuestDef.h:373
@ REST_FLAG_IN_TAVERN
Definition RestMgr.h:54
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
#define sSpellMgr
Definition SpellMgr.h:812
EnumFlag< AreaTriggerCreatePropertiesFlag > Flags
AreaTriggerCreatePropertiesId Id
std::variant< std::monostate, SplineInfo, AreaTriggerOrbitInfo > Movement
AreaTriggerTemplate const * Template
std::vector< AreaTriggerAction > Actions
AreaTriggerTemplate const * GetTemplate() const
MovementUpdateLocalResult CalculateLocalSplinePositionAndRotation() const
MovementUpdateWorldResult CalculateWorldPositionAndRotation() const
AreaTriggerCreateProperties const * _areaTriggerCreateProperties
bool HasAreaTriggerFlag(AreaTriggerFieldFlags flag) const
void UpdatePositionAndRotation()
void UpdateTargetList()
void UndoActions(Unit *unit)
MovementUpdateLocalResult CalculateLocalPositionAndRotation() const
void SetOverrideCurve(UF::MutableFieldReference< UF::OverrideCurve, false > overrideCurveMutator, float constantValue)
std::vector< Position > _polygonVertices
ObjectGuid::LowType _spawnId
void DebugVisualizePosition()
bool HasActionSetFlag(AreaTriggerActionSetFlag flag) const
float GetShapeProgress() const
QuaternionData _rotation
int32 _duration
float GetOverrideCurveValueAtProgress(UF::OverrideCurve const &overrideCurve, float x) const
uint32 GetTimeSinceCreated() const
float GetOverrideCurveProgress(UF::OverrideCurve const &overrideCurve, uint32 timeTo) const
float CalcCurrentScale() const
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)
void UpdatePolygonVertices()
void BuildValuesUpdateForPlayerWithMask(UpdateData *data, UF::ObjectData::Mask const &requestedObjectMask, UF::AreaTriggerData::Mask const &requestedAreaTriggerMask, Player const *target, bool ignoreNestedChangesMask) const
float GetOverrideCurveValue(UF::OverrideCurve const &overrideCurve, uint32 timeTo) const
uint32 GetScriptId() const
Position const & GetMovementOrigin() const
void ClearOverrideScaleCurve()
uint32 GetFaction() const override
ObjectGuid const & GetCasterGuid() const
void RelocateStationaryPosition(Position const &pos)
MovementUpdateLocalResult CalculateLocalOrbitPositionAndRotation(UF::AreaTriggerOrbit const &orbit) const
bool _reachedDestination
void HandleUnitEnterExit(std::vector< Unit * > const &targetList, AreaTriggerExitReason exitMode=AreaTriggerExitReason::NotInside)
void ClearValuesChangesMask() override
Position _stationaryPosition
void HandleUnitEnter(Unit *unit)
float GetMaxSearchRadius() const
float GetOverridePosProgress() const
void InitSplines(std::vector< G3D::Vector3 > const &splinePoints, Optional< float > overrideSpeed={}, Optional< bool > speedIsTimeInSeconds={})
Position const & GetStationaryPosition() const override
std::unique_ptr< AreaTriggerAI > _ai
ObjectGuid _targetGuid
void SearchUnitInSphere(UF::AreaTriggerSphere const &sphere, std::vector< Unit * > &targetList)
bool IsServerSide() const
void ClearOverrideMoveCurve()
void SearchUnits(std::vector< Unit * > &targetList, float radius, bool check3D)
void SearchUnitInBoundedPlane(UF::AreaTriggerBoundedPlane const &boundedPlane, std::vector< Unit * > &targetList)
UF::UpdateField< UF::AreaTriggerData, int32(WowCS::EntityFragment::CGObject), TYPEID_AREATRIGGER > m_areaTriggerData
QuaternionData _verticesUpdatePreviousRotation
void SetAreaTriggerFlag(AreaTriggerFieldFlags flag)
void ClearOverrideCurve(UF::MutableFieldReference< UF::OverrideCurve, false > overrideCurveMutator)
void SetShape(AreaTriggerShapeInfo const &shape)
MovementUpdateLocalResult CalculateLocalStationaryPositionAndRotation() const
uint32 GetTimeToTarget() const
void AddToWorld() override
void BuildValuesUpdate(UF::UpdateFieldFlag flags, ByteBuffer &data, Player const *target) const override
void Update(uint32 diff) override
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool allowDuplicate)
GuidUnorderedSet _insideUnits
static ObjectGuid CreateNewMovementForceId(Map *map, uint32 areaTriggerId)
bool IsStaticSpawn() const
void SearchUnitInBox(UF::AreaTriggerBox const &box, std::vector< Unit * > &targetList)
void PlaySpellVisual(uint32 spellVisualId) const
void SearchUnitInDisk(UF::AreaTriggerDisk const &disk, std::vector< Unit * > &targetList)
void InitOrbit(AreaTriggerOrbitInfo const &orbit, Optional< float > overrideSpeed={}, Optional< bool > speedIsTimeInSeconds={})
void ClearExtraScaleCurve()
void AI_Initialize()
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)
Unit * GetTarget() const
void SetOverrideShapeCurve(float overrideShape)
uint32 GetElapsedTimeForMovement() const
AreaTriggerTemplate const * _areaTriggerTemplate
void RemoveAreaTriggerFlag(AreaTriggerFieldFlags flag)
void SetOverrideMoveCurve(float x, float y, float z)
float GetScaleProgress() const
void SetOverrideScaleCurve(float overrideScale)
void HandleUnitExitInternal(Unit *unit, AreaTriggerExitReason exitMode=AreaTriggerExitReason::NotInside)
bool IsCustom() const
AuraEffect const * _aurEff
void SetDuration(int32 newDuration)
void _UpdateDuration(int32 newDuration)
void SetRollPitchYaw(float roll, float pitch, float yaw, Optional< float > targetRoll={}, Optional< float > targetPitch={}, Optional< float > targetYaw={})
void DoActions(Unit *unit)
void ReplaceAllAreaTriggerFlags(AreaTriggerFieldFlags flag)
void SetSpellVisual(SpellCastVisual const &visual)
void HandleUnitExit(Unit *unit)
void SetExtraScaleCurve(float extraScale)
void SearchUnitInPolygon(UF::AreaTriggerPolygon const &polygon, std::vector< Unit * > &targetList)
void RemoveFromWorld() override
void InitSplineOffsets(std::vector< Position > const &offsets, Optional< float > overrideSpeed={}, Optional< bool > speedIsTimeInSeconds={})
int32 GetDuration() const
AreaTriggerCreateProperties const * GetCreateProperties() const
bool HasOverridePosition() const
void UpdateHasPlayersFlag()
int32 _totalDuration
void UpdateDynamicShapeFlag()
std::unique_ptr<::Movement::Spline< float > > _spline
Unit * GetCaster() const
void ClearOverrideShapeCurve()
bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects) const override
void BuildValuesCreate(UF::UpdateFieldFlag flags, ByteBuffer &data, Player const *target) const override
void SearchUnitInCylinder(UF::AreaTriggerCylinder const &cylinder, std::vector< Unit * > &targetList)
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
void SetUpdateFieldValue(UF::UpdateFieldPrivateSetter< T > setter, typename UF::UpdateFieldPrivateSetter< T >::value_type value)
Definition BaseEntity.h:221
WowCS::EntityFragmentsHolder m_entityFragments
Definition BaseEntity.h:353
void RemoveOptionalUpdateFieldValue(UF::OptionalUpdateFieldSetter< T > setter)
Definition BaseEntity.h:291
UF::UpdateFieldHolder m_values
Definition BaseEntity.h:205
bool IsInWorld() const
Definition BaseEntity.h:158
void _Create(ObjectGuid const &guid)
Definition BaseEntity.h:218
CreateObjectBits m_updateFlag
Definition BaseEntity.h:352
void ClearDynamicUpdateFieldValues(UF::DynamicUpdateFieldSetter< T > setter)
Definition BaseEntity.h:263
UF::DynamicUpdateFieldSetter< T >::insert_result AddDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter< T > setter)
Definition BaseEntity.h:242
ByteBuffer & PrepareValuesUpdateBuffer(UpdateData *data) const
void DoWithSuppressingObjectUpdates(Action &&action)
Definition BaseEntity.h:336
TypeID m_objectTypeId
Definition BaseEntity.h:351
virtual UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const
size_t wpos() const
Definition ByteBuffer.h:462
void put(std::size_t pos, T value)
Definition ByteBuffer.h:261
void PSendSysMessage(char const *fmt, Args &&... args)
Definition Chat.h:62
Definition Map.h:227
MapStoredObjectTypesContainer & GetObjectsStore()
Definition Map.h:463
AreaTriggerBySpawnIdContainer & GetAreaTriggerBySpawnIdStore()
Definition Map.h:474
ObjectGuid::LowType GenerateLowGuid()
Definition Map.h:564
void AreaTriggerRelocation(AreaTrigger *at, float x, float y, float z, float orientation)
Definition Map.cpp:1149
Difficulty GetDifficultyID() const
Definition Map.h:363
uint32 GetId() const
Definition Map.cpp:3288
static ObjectGuid const Empty
Definition ObjectGuid.h:314
bool IsEmpty() const
Definition ObjectGuid.h:362
bool IsPlayer() const
Definition ObjectGuid.h:369
uint64 LowType
Definition ObjectGuid.h:321
Player * ToPlayer()
Definition Object.h:126
uint32 GetEntry() const
Definition Object.h:89
void BuildEntityFragmentsForValuesUpdateForPlayerWithMask(ByteBuffer &data, EnumFlag< UF::UpdateFieldFlag > flags) const
Definition Object.cpp:113
void SetEntry(uint32 entry)
Definition Object.h:90
virtual void ClearValuesChangesMask()
Definition Object.cpp:130
virtual void SetObjectScale(float scale)
Definition Object.h:93
UF::UpdateField< UF::ObjectData, int32(WowCS::EntityFragment::CGObject), TYPEID_OBJECT > m_objectData
Definition Object.h:161
static void InheritPhaseShift(WorldObject *target, WorldObject const *source)
static void InitDbPhaseShift(PhaseShift &phaseShift, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId)
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6193
bool isDebugAreaTriggers
Definition Player.h:2850
uint32 GetSpellXSpellVisualId(WorldObject const *caster=nullptr, WorldObject const *viewer=nullptr) const
uint32 const Id
Definition SpellInfo.h:328
Definition Spell.h:277
ObjectGuid m_castId
Definition Spell.h:604
virtual Position GetPositionOffsetTo(Position const &endPos) const =0
This method transforms supplied global coordinates into local offsets.
virtual void AddPassenger(WorldObject *passenger, Position const &offset)=0
virtual TransportBase * RemovePassenger(WorldObject *passenger)=0
std::vector< T >::const_iterator begin() const
std::vector< T >::const_iterator end() const
void ClearChanged(UpdateField< T, BlockBit, Bit >(Derived::*))
Mask const & GetChangesMask() const
static constexpr std::size_t size()
MutableFieldReference< T, false > ModifyValue(UpdateField< T, BlockBit, Bit >(Derived::*field))
void ClearChangesMask(UpdateField< T, BlockBit, Bit >(Derived::*field))
bool HasChanged(uint32 index) const
Definition BaseEntity.h:83
uint32 GetChangedObjectTypeMask() const
Definition BaseEntity.h:81
Definition Unit.h:647
uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const override
Definition Unit.cpp:14656
void _RegisterAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5474
void EnterAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5542
Aura * AddAura(uint32 spellId, Unit *target)
Definition Unit.cpp:12344
float GetCombatReach() const override
Definition Unit.h:717
void ExitAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5547
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:12272
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:12253
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3992
bool BuildPacket(WorldPacket *packet)
void AddUpdateBlock()
Definition UpdateData.h:46
constexpr uint32 GetBlock(uint32 index) const
Definition UpdateMask.h:59
constexpr void Set(uint32 index)
Definition UpdateMask.h:91
constexpr uint32 GetMapId() const
Definition Position.h:216
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition Object.cpp:1099
Map * GetMap() const
Definition Object.h:411
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition Object.cpp:709
void AddToWorld() override
Definition Object.cpp:363
void RemoveFromWorld() override
Definition Object.cpp:369
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2222
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2329
PhaseShift & GetPhaseShift()
Definition Object.h:310
void SetZoneScript()
Definition Object.cpp:1389
TransportBase * GetTransport() const
Definition Object.h:537
void setActive(bool isActiveObject)
Definition Object.cpp:274
ZoneScript * m_zoneScript
Definition Object.h:584
virtual bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects) const
Definition Object.h:605
virtual void SetMap(Map *map)
Definition Object.cpp:1149
void AddObjectToRemoveList()
Definition Object.cpp:1179
void UpdatePositionData()
Definition Object.cpp:344
Player * GetSpellModOwner() const
Definition Object.cpp:1646
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2487
MovementInfo m_movementInfo
Definition Object.h:548
bool IsWithinDist(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:494
bool IsInMap(WorldObject const *obj) const
Definition Object.cpp:467
virtual void Update(uint32 diff)
Definition Object.cpp:243
virtual void OnAreaTriggerRemove(AreaTrigger *areaTrigger)
Definition ZoneScript.h:83
virtual void OnAreaTriggerCreate(AreaTrigger *areaTrigger)
Definition ZoneScript.h:82
AreaTriggerAI * SelectAreaTriggerAI(AreaTrigger *at)
uint32 GetGameTimeMS()
Definition GameTime.cpp:57
TC_GAME_API WorldObject * GetWorldObject(WorldObject const &, ObjectGuid const &)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
constexpr void EraseIf(Container &c, Predicate p)
Definition Containers.h:283
void MultimapErasePair(M &multimap, typename M::key_type const &key, typename M::mapped_type const &value)
Definition MapUtils.h:57
UpdateFieldFlag
Definition UpdateField.h:37
std::conditional_t< std::is_base_of_v< HasChangesMaskTag, T >, MutableFieldReferenceWithChangesMask< T, PublicSet >, MutableFieldReferenceNoChangesMask< T, PublicSet > > MutableFieldReference
AreaTriggerActionUserTypes TargetType
Position const & operator()(UF::AreaTriggerOrbit const &orbit) const
Position const & operator()(UF::AreaTriggerSplineCalculator const &) const
Position const & operator()(UF::AreaTriggerMovementScript const &script) const
Position const & operator()(std::monostate) const
Optional< TaggedPosition< Position::XYZ > > Center
Optional< ObjectGuid > PathTarget
AreaTrigger::MovementUpdateLocalResult operator()(UF::AreaTriggerOrbit const &orbit) const
AreaTrigger::MovementUpdateLocalResult operator()(UF::AreaTriggerSplineCalculator const &) const
AreaTrigger::MovementUpdateLocalResult operator()(UF::AreaTriggerMovementScript const &) const
AreaTrigger::MovementUpdateLocalResult operator()(std::monostate) const
std::variant< Sphere, Box, Polygon, Cylinder, Disk, BoundedPlane > Data
AreaTriggerCreatePropertiesId Id
CurveInterpolationMode Mode
std::variant< float, Points > Curve
std::array< DBCPosition2D, 2 > Points
void operator()(Player const *player) const
CastSpellExtraArgs & SetOriginalCastId(ObjectGuid const &castId)
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius)
Definition CellImpl.h:150
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius)
Definition CellImpl.h:160
struct MovementInfo::TransportInfo transport
constexpr void SetOrientation(float orientation)
Definition Position.h:82
constexpr float GetPositionX() const
Definition Position.h:87
constexpr Position()
Definition Position.h:31
constexpr float GetPositionY() const
Definition Position.h:88
Position GetPositionWithOffset(Position const &offset) const
Definition Position.cpp:61
Position GetPositionOffsetTo(Position const &endPos) const
Definition Position.cpp:47
float m_positionX
Definition Position.h:64
float m_positionY
Definition Position.h:65
bool IsInPolygon2D(Position const &polygonOrigin, std::span< Position const > vertices) const
Definition Position.cpp:104
bool IsPositionValid() const
Definition Position.cpp:42
constexpr void Relocate(float x, float y)
Definition Position.h:74
constexpr Position GetPosition() const
Definition Position.h:95
constexpr bool IsInDist(float x, float y, float z, float dist) const
Definition Position.h:155
constexpr float GetOrientation() const
Definition Position.h:90
constexpr float GetPositionZ() const
Definition Position.h:89
uint8 phaseUseFlags
Definition SpawnData.h:137
uint32 phaseId
Definition SpawnData.h:138
Position spawnPoint
Definition SpawnData.h:136
uint32 phaseGroup
Definition SpawnData.h:139
uint32 SpellXSpellVisualID
Position Pos
Definition Position.h:254
bool Insert(ValueType< ObjectType > object)
bool Remove(ValueType< ObjectType > object)
UpdateField< float, 0, 2 > ExtentsZ
UpdateField< float, 0, 1 > ExtentsY
UpdateField< float, 0, 3 > ExtentsTargetY
UpdateField< float, 0, 4 > ExtentsTargetZ
UpdateField< TaggedPosition< Position::XYZ >, 0, 1 > Extents
UpdateField< TaggedPosition< Position::XYZ >, 0, 2 > ExtentsTarget
UpdateField< float, 0, 5 > LocationZOffset
UpdateField< float, 0, 6 > LocationZOffsetTarget
UpdateField< float, 0, 4 > HeightTarget
UpdateField< float, 0, 2 > RadiusTarget
UpdateField< float, 0, 3 > Height
UpdateField< float, 0, 1 > Radius
UpdateField< UF::OverrideCurve, 0, 5 > OverrideMoveCurveZ
VariantUpdateField< 32, 36, UF::AreaTriggerSplineCalculator, UF::AreaTriggerOrbit, UF::AreaTriggerMovementScript > PathData
UpdateField< uint32, 32, 33 > MoveCurveId
UpdateField< int32, 0, 22 > PositionalSoundKitID
UpdateField< UF::VisualAnim, 0, 28 > VisualAnim
UpdateField< ObjectGuid, 0, 20 > OrbitPathTarget
UpdateField< uint32, 0, 30 > FacingCurveId
UpdateField< UF::SpellCastVisual, 0, 16 > SpellVisual
UpdateField< float, 0, 17 > BoundsRadius2D
UpdateField< UF::OverrideCurve, 0, 3 > OverrideMoveCurveX
UpdateField< float, 32, 34 > Facing
UpdateField< uint8, 32, 37 > ShapeType
UpdateField< UF::OverrideCurve, 0, 1 > OverrideScaleCurve
UpdateField< UF::OverrideCurve, 0, 6 > OverrideShapeCurve
UpdateField< uint32, 0, 12 > TimeToTargetPos
UpdateField< int32, 32, 36 > PathType
UpdateField< float, 0, 25 > ZOffset
UpdateField< UF::OverrideCurve, 0, 2 > ExtraScaleCurve
OptionalUpdateField< TaggedPosition< Position::XYZ >, 0, 26 > TargetRollPitchYaw
UpdateField< uint32, 0, 31 > MorphCurveId
UpdateField< int32, 0, 15 > SpellForVisuals
UpdateField< uint32, 0, 8 > Duration
UpdateField< uint32, 0, 29 > ScaleCurveId
VariantUpdateField< 32, 37, UF::AreaTriggerSphere, UF::AreaTriggerBox, UF::AreaTriggerPolygon, UF::AreaTriggerCylinder, UF::AreaTriggerDisk, UF::AreaTriggerBoundedPlane > ShapeData
UpdateField< uint32, 0, 18 > DecalPropertiesID
UpdateField< uint32, 0, 13 > TimeToTargetShape
UpdateField< uint32, 0, 10 > TimeToTargetScale
UpdateField< uint32, 0, 9 > TimeToTarget
UpdateField< uint32, 0, 24 > CreationTime
UpdateField< int32, 0, 14 > SpellID
UpdateField< uint32, 0, 23 > MovementStartTime
UpdateField< ObjectGuid, 0, 19 > CreatingEffectGUID
UpdateField< UF::OverrideCurve, 0, 4 > OverrideMoveCurveY
UpdateField< ObjectGuid, 0, 7 > Caster
UpdateField< TaggedPosition< Position::XYZ >, 0, 21 > RollPitchYaw
UpdateField< float, 0, 4 > OuterRadiusTarget
UpdateField< float, 0, 7 > LocationZOffset
UpdateField< float, 0, 5 > Height
UpdateField< float, 0, 1 > InnerRadius
UpdateField< float, 0, 8 > LocationZOffsetTarget
UpdateField< float, 0, 2 > InnerRadiusTarget
UpdateField< float, 0, 6 > HeightTarget
UpdateField< float, 0, 3 > OuterRadius
UpdateField< TaggedPosition< Position::XYZ >, 0, 2 > Center
UpdateField< float, 0, 5 > BlendFromRadius
UpdateField< bool, 0, 1 > CounterClockwise
UpdateField< float, 0, 3 > Radius
UpdateField< float, 0, 4 > InitialAngle
UpdateField< int32, 0, 6 > ExtraTimeForBlending
UpdateField< TaggedPosition< Position::XYZ >, 0, 2 > Center
DynamicUpdateField< TaggedPosition< Position::XY >, 0, 2 > VerticesTarget
UpdateField< float, 0, 3 > Height
UpdateField< float, 0, 4 > HeightTarget
DynamicUpdateField< TaggedPosition< Position::XY >, 0, 1 > Vertices
UpdateField< float, 0, 2 > RadiusTarget
UpdateField< float, 0, 1 > Radius
UpdateField< bool, 0, 1 > Linear
DynamicUpdateField< TaggedPosition< Position::XYZ >, 0, 2 > Points
UpdateField< uint32, 0, 2 > StartTimeOffset
UpdateFieldArray< TaggedPosition< Position::XY >, 2, 4, 5 > Points
UpdateField< uint32, 0, 3 > ParameterCurve
UpdateField< bool, 0, 1 > OverrideActive
UpdateField< uint32, 0, 3 > AnimKitID
OptionalUpdateField< int16, 0, 2 > AnimationDataID
UpdateField< bool, 0, 1 > IsDecay
void Add(EntityFragment fragment, bool update, void const *data=nullptr)