TrinityCore
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 "GridNotifiersImpl.h"
28#include "Language.h"
29#include "Log.h"
30#include "Object.h"
31#include "ObjectAccessor.h"
32#include "ObjectMgr.h"
33#include "PhasingHandler.h"
34#include "Player.h"
35#include "ScriptMgr.h"
36#include "SpellInfo.h"
37#include "SpellMgr.h"
38#include "Spline.h"
39#include "Transport.h"
40#include "Unit.h"
41#include "UpdateData.h"
42#include "ZoneScript.h"
43#include "advstd.h"
44#include <bit>
45
46AreaTrigger::AreaTrigger() : WorldObject(false), MapObject(), _spawnId(0), _aurEff(nullptr),
47 _duration(0), _totalDuration(0), _timeSinceCreated(0), _verticesUpdatePreviousOrientation(std::numeric_limits<float>::infinity()),
48 _isRemoved(false), _reachedDestination(true), _lastSplineIndex(0), _movementTime(0),
49 _areaTriggerCreateProperties(nullptr), _areaTriggerTemplate(nullptr)
50{
53
56}
57
59{
60}
61
63{
65 if (!IsInWorld())
66 {
67 if (m_zoneScript)
69
71 if (_spawnId)
72 GetMap()->GetAreaTriggerBySpawnIdStore().insert(std::make_pair(_spawnId, this));
73
75 }
76}
77
79{
81 if (IsInWorld())
82 {
83 if (m_zoneScript)
85
86 _isRemoved = true;
87
88 if (Unit* caster = GetCaster())
89 caster->_UnregisterAreaTrigger(this);
90
91 _ai->OnRemove();
92
93 // Handle removal of all units, calling OnUnitExit & deleting auras if needed
95
97
98 if (IsStaticSpawn())
99 Trinity::Containers::MultimapErasePair(GetMap()->GetAreaTriggerBySpawnIdStore(), _spawnId, this);
101 }
102}
103
104bool 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*/)
105{
106 _targetGuid = target ? target->GetGUID() : ObjectGuid::Empty;
107 _aurEff = aurEff;
108
109 SetMap(map);
110 Relocate(pos);
112 if (!IsPositionValid())
113 {
114 TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})) not created. Invalid coordinates (X: {} Y: {})", areaTriggerCreatePropertiesId.Id, uint32(areaTriggerCreatePropertiesId.IsCustom), GetPositionX(), GetPositionY());
115 return false;
116 }
117
118 _areaTriggerCreateProperties = sAreaTriggerDataStore->GetAreaTriggerCreateProperties(areaTriggerCreatePropertiesId);
120 {
121 TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})) not created. Invalid areatrigger create properties id", areaTriggerCreatePropertiesId.Id, uint32(areaTriggerCreatePropertiesId.IsCustom));
122 return false;
123 }
124
126
128
129 Object::_Create(ObjectGuid::Create<HighGuid::AreaTrigger>(GetMapId(), GetTemplate() ? GetTemplate()->Id.Id : 0, GetMap()->GenerateLowGuid<HighGuid::AreaTrigger>()));
130
131 if (GetTemplate())
132 SetEntry(GetTemplate()->Id.Id);
133
134 SetObjectScale(1.0f);
135 SetDuration(duration);
136
138
139 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
140 if (caster)
141 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::Caster), caster->GetGUID());
142 if (spell)
143 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::CreatingEffectGUID), spell->m_castId);
144 if (spellInfo && !IsStaticSpawn())
145 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::SpellID), spellInfo->Id);
146 if (spellInfo)
147 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::SpellForVisuals), spellInfo->Id);
149 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::SpellVisual).ModifyValue(&UF::SpellCastVisual::ScriptVisualID), spellVisual.ScriptVisualID);
150 if (!IsStaticSpawn())
151 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTargetScale), GetCreateProperties()->TimeToTargetScale != 0 ? GetCreateProperties()->TimeToTargetScale : *m_areaTriggerData->Duration);
152 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::BoundsRadius2D), GetCreateProperties()->Shape.GetMaxSearchRadius());
153 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::DecalPropertiesID), GetCreateProperties()->DecalPropertiesId);
154 if (IsServerSide())
155 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::DecalPropertiesID), 24); // Blue decal, for .debug areatrigger visibility
156
158 SetScaleCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve), extraScaleCurve);
159
160 if (caster)
161 {
162 if (Player const* modOwner = caster->GetSpellModOwner())
163 {
164 float multiplier = 1.0f;
165 int32 flat = 0;
166 modOwner->GetSpellModValues(spellInfo, SpellModOp::Radius, spell, *m_areaTriggerData->BoundsRadius2D, &flat, &multiplier);
167 if (multiplier != 1.0f)
168 {
169 AreaTriggerScaleCurveTemplate overrideScale;
170 overrideScale.Curve = multiplier;
171 SetScaleCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OverrideScaleCurve), overrideScale);
172 }
173 }
174 }
175
177 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::AnimKitID), GetCreateProperties()->AnimKitId);
179 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::Field_C), true);
180
181 if (caster)
183 else if (IsStaticSpawn() && spawnData)
184 {
185 if (spawnData->phaseUseFlags || spawnData->phaseId || spawnData->phaseGroup)
187 }
188
191
192 if (!IsStaticSpawn())
194
195 UpdateShape();
196
198
199 if (GetCreateProperties()->OrbitInfo)
200 {
203 orbit.PathTarget = target->GetGUID();
204 else
205 orbit.Center = pos;
206
207 InitOrbit(orbit, timeToTarget);
208 }
209 else if (GetCreateProperties()->HasSplines())
210 {
211 InitSplineOffsets(GetCreateProperties()->SplinePoints, timeToTarget);
212 }
213
214 // movement on transport of areatriggers on unit is handled by themself
215 TransportBase* transport = nullptr;
216 if (caster)
217 {
218 transport = m_movementInfo.transport.guid.IsEmpty() ? caster->GetTransport() : nullptr;
219 if (transport)
220 {
221 float x, y, z, o;
222 pos.GetPosition(x, y, z, o);
223 transport->CalculatePassengerOffset(x, y, z, &o);
225
226 // This object must be added to transport before adding to map for the client to properly display it
227 transport->AddPassenger(this);
228 }
229 }
230
232
233 // Relocate areatriggers with circular movement again
234 if (HasOrbit())
236
237 if (!IsStaticSpawn())
238 {
239 if (!GetMap()->AddToMap(this))
240 {
241 // Returning false will cause the object to be deleted - remove from transport
242 if (transport)
243 transport->RemovePassenger(this);
244 return false;
245 }
246 }
247
248 if (caster)
249 caster->_RegisterAreaTrigger(this);
250
251 _ai->OnCreate(spell ? spell : nullptr);
252
253 return true;
254}
255
256AreaTrigger* 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*/)
257{
258 AreaTrigger* at = new AreaTrigger();
259 if (!at->Create(areaTriggerCreatePropertiesId, caster->GetMap(), pos, duration, nullptr, caster, target, spellVisual, spellInfo, spell, aurEff))
260 {
261 delete at;
262 return nullptr;
263 }
264
265 return at;
266}
267
269{
270 return ObjectGuid::Create<HighGuid::AreaTrigger>(map->GetId(), areaTriggerId, map->GenerateLowGuid<HighGuid::AreaTrigger>());
271}
272
273bool AreaTrigger::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool /*addToMap*/, bool /*allowDuplicate*/)
274{
275 _spawnId = spawnId;
276
277 AreaTriggerSpawn const* spawnData = sAreaTriggerDataStore->GetAreaTriggerSpawn(spawnId);
278 if (!spawnData)
279 return false;
280
281 AreaTriggerCreateProperties const* createProperties = sAreaTriggerDataStore->GetAreaTriggerCreateProperties(spawnData->Id);
282 if (!createProperties)
283 return false;
284
285 SpellInfo const* spellInfo = nullptr;
286 SpellCastVisual spellVisual;
287 if (spawnData->SpellForVisuals)
288 {
289 spellInfo = sSpellMgr->GetSpellInfo(*spawnData->SpellForVisuals, DIFFICULTY_NONE);
290
291 if (spellInfo)
292 spellVisual.SpellXSpellVisualID = spellInfo->GetSpellXSpellVisualId();
293 }
294
295 return Create(spawnData->Id, map, spawnData->spawnPoint, -1, spawnData, nullptr, nullptr, spellVisual, spellInfo);
296}
297
299{
301 _timeSinceCreated += diff;
302
303 if (!IsStaticSpawn())
304 {
305 // "If" order matter here, Orbit > Attached > Splines
307 {
309 }
310 else if (HasOrbit())
311 {
313 }
315 {
316 if (Unit* target = GetTarget())
317 {
318 float orientation = 0.0f;
319 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
320 if (createProperties->FacingCurveId)
321 orientation = sDB2Manager.GetCurveValueAt(createProperties->FacingCurveId, GetProgress());
322
324 orientation += target->GetOrientation();
325
326 GetMap()->AreaTriggerRelocation(this, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), orientation);
327 }
328 }
329 else if (HasSplines())
330 {
332 }
333 else
334 {
335 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
336 {
337 if (createProperties->FacingCurveId)
338 {
339 float orientation = sDB2Manager.GetCurveValueAt(createProperties->FacingCurveId, GetProgress());
341 orientation += GetStationaryO();
342
343 SetOrientation(orientation);
344 }
345 }
346
347 UpdateShape();
348 }
349 }
350
351 if (GetDuration() != -1)
352 {
353 if (GetDuration() > int32(diff))
355 else
356 {
357 Remove(); // expired
358 return;
359 }
360 }
361
362 _ai->OnUpdate(diff);
363
365}
366
368{
369 if (IsInWorld())
370 {
371 AddObjectToRemoveList(); // calls RemoveFromWorld
372 }
373}
374
375void AreaTrigger::SetOverrideScaleCurve(float overrideScale)
376{
378}
379
380void AreaTrigger::SetOverrideScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
381{
383}
384
386{
388}
389
391{
393}
394
395void AreaTrigger::SetExtraScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
396{
397 SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve), points, startTimeOffset, interpolation);
398}
399
401{
403}
404
405void AreaTrigger::SetOverrideMoveCurve(float x, float y, float z)
406{
410}
411
412void AreaTrigger::SetOverrideMoveCurve(std::array<DBCPosition2D, 2> const& xCurvePoints, std::array<DBCPosition2D, 2> const& yCurvePoints,
413 std::array<DBCPosition2D, 2> const& zCurvePoints, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
414{
415 SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveX), xCurvePoints, startTimeOffset, interpolation);
416 SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveY), yCurvePoints, startTimeOffset, interpolation);
417 SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveZ), zCurvePoints, startTimeOffset, interpolation);
418}
419
421{
425}
426
428{
429 _duration = newDuration;
430 _totalDuration = newDuration;
431
432 // negative duration (permanent areatrigger) sent as 0
434}
435
437{
438 _duration = newDuration;
439
440 // should be sent in object create packets only
442 {
444 const_cast<UF::AreaTriggerData&>(*m_areaTriggerData).ClearChanged(&UF::AreaTriggerData::Duration);
445 });
446}
447
449{
450 float scale = 1.0f;
451 if (m_areaTriggerData->OverrideScaleCurve->OverrideActive)
452 scale *= std::max(GetScaleCurveValue(*m_areaTriggerData->OverrideScaleCurve, m_areaTriggerData->TimeToTargetScale), 0.000001f);
453 else if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
454 if (createProperties->ScaleCurveId)
455 scale *= std::max(sDB2Manager.GetCurveValueAt(createProperties->ScaleCurveId, GetScaleCurveProgress(*m_areaTriggerData->OverrideScaleCurve, m_areaTriggerData->TimeToTargetScale)), 0.000001f);
456
457 scale *= std::max(GetScaleCurveValue(*m_areaTriggerData->ExtraScaleCurve, m_areaTriggerData->TimeToTargetExtraScale), 0.000001f);
458
459 return scale;
460}
461
463{
464 if (_totalDuration <= 0)
465 return 1.0f;
466
467 return std::clamp(float(GetTimeSinceCreated()) / float(GetTotalDuration()), 0.0f, 1.0f);
468}
469
470float AreaTrigger::GetScaleCurveProgress(UF::ScaleCurve const& scaleCurve, uint32 timeTo) const
471{
472 if (!timeTo)
473 return 0.0f;
474
475 return std::clamp(float(GetTimeSinceCreated() - scaleCurve.StartTimeOffset) / float(timeTo), 0.0f, 1.0f);
476}
477
478float AreaTrigger::GetScaleCurveValueAtProgress(UF::ScaleCurve const& scaleCurve, float x) const
479{
480 ASSERT(*scaleCurve.OverrideActive, "ScaleCurve must be active to evaluate it");
481
482 // unpack ParameterCurve
483 if (*scaleCurve.ParameterCurve & 1u)
484 return advstd::bit_cast<float>(*scaleCurve.ParameterCurve & ~1u);
485
486 std::array<DBCPosition2D, 2> points;
487 for (std::size_t i = 0; i < scaleCurve.Points.size(); ++i)
488 points[i] = { .X = scaleCurve.Points[i].Pos.GetPositionX(), .Y = scaleCurve.Points[i].Pos.GetPositionY() };
489
490 CurveInterpolationMode mode = CurveInterpolationMode(*scaleCurve.ParameterCurve >> 1 & 0x7);
491 std::size_t pointCount = *scaleCurve.ParameterCurve >> 24 & 0xFF;
492
493 return sDB2Manager.GetCurveValueAt(mode, std::span(points.begin(), pointCount), x);
494}
495
496float AreaTrigger::GetScaleCurveValue(UF::ScaleCurve const& scaleCurve, uint32 timeTo) const
497{
498 return GetScaleCurveValueAtProgress(scaleCurve, GetScaleCurveProgress(scaleCurve, timeTo));
499}
500
502{
503 AreaTriggerScaleCurveTemplate curveTemplate;
504 curveTemplate.Curve = constantValue;
505 SetScaleCurve(scaleCurveMutator, curveTemplate);
506}
507
508void AreaTrigger::SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false> scaleCurveMutator, std::array<DBCPosition2D, 2> const& points,
509 Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
510{
512 curve.Mode = interpolation;
513 curve.Points = points;
514
515 AreaTriggerScaleCurveTemplate curveTemplate;
516 curveTemplate.StartTimeOffset = startTimeOffset.value_or(GetTimeSinceCreated());
517 curveTemplate.Curve = curve;
518
519 SetScaleCurve(scaleCurveMutator, curveTemplate);
520}
521
523{
524 SetScaleCurve(scaleCurveMutator, {});
525}
526
528{
529 if (!curve)
530 {
532 return;
533 }
534
536 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::StartTimeOffset), curve->StartTimeOffset);
537
538 Position point;
539 // ParameterCurve packing information
540 // (not_using_points & 1) | ((interpolation_mode & 0x7) << 1) | ((first_point_offset & 0xFFFFF) << 4) | ((point_count & 0xFF) << 24)
541 // if not_using_points is set then the entire field is simply read as a float (ignoring that lowest bit)
542
543 if (float const* simpleFloat = std::get_if<float>(&curve->Curve))
544 {
545 uint32 packedCurve = advstd::bit_cast<uint32>(*simpleFloat);
546 packedCurve |= 1;
547
548 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::ParameterCurve), packedCurve);
549
550 // clear points
551 for (std::size_t i = 0; i < UF::size<decltype(UF::ScaleCurve::Points)>(); ++i)
552 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::Points, i), point);
553 }
554 else if (AreaTriggerScaleCurvePointsTemplate const* curvePoints = std::get_if<AreaTriggerScaleCurvePointsTemplate>(&curve->Curve))
555 {
556 CurveInterpolationMode mode = curvePoints->Mode;
557 if (curvePoints->Points[1].X < curvePoints->Points[0].X)
559
560 switch (mode)
561 {
563 // catmullrom requires at least 4 points, impossible here
565 break;
569 // bezier requires more than 2 points, impossible here
571 break;
572 default:
573 break;
574 }
575
576 uint32 pointCount = 2;
578 pointCount = 1;
579
580 uint32 packedCurve = (uint32(mode) << 1) | (pointCount << 24);
581 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::ParameterCurve), packedCurve);
582
583 for (std::size_t i = 0; i < curvePoints->Points.size(); ++i)
584 {
585 point.Relocate(curvePoints->Points[i].X, curvePoints->Points[i].Y);
586 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::Points, i), point);
587 }
588 }
589}
590
592{
593 std::vector<Unit*> targetList;
594
595 switch (_shape.Type)
596 {
598 SearchUnitInSphere(targetList);
599 break;
601 SearchUnitInBox(targetList);
602 break;
604 SearchUnitInPolygon(targetList);
605 break;
607 SearchUnitInCylinder(targetList);
608 break;
610 SearchUnitInDisk(targetList);
611 break;
613 SearchUnitInBoundedPlane(targetList);
614 break;
615 default:
616 break;
617 }
618
619 if (GetTemplate())
620 {
621 if (ConditionContainer const* conditions = sConditionMgr->GetConditionsForAreaTrigger(GetTemplate()->Id.Id, GetTemplate()->Id.IsCustom))
622 {
623 Trinity::Containers::EraseIf(targetList, [conditions](Unit const* target)
624 {
625 return !sConditionMgr->IsObjectMeetToConditions(target, *conditions);
626 });
627 }
628 }
629
630 HandleUnitEnterExit(targetList);
631}
632
633void AreaTrigger::SearchUnits(std::vector<Unit*>& targetList, float radius, bool check3D)
634{
635 Trinity::AnyUnitInObjectRangeCheck check(this, radius, check3D);
636 if (IsStaticSpawn())
637 {
640 }
641 else
642 {
644 Cell::VisitAllObjects(this, searcher, GetMaxSearchRadius());
645 }
646}
647
648void AreaTrigger::SearchUnitInSphere(std::vector<Unit*>& targetList)
649{
650 float progress = GetProgress();
651 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
652 if (createProperties->MorphCurveId)
653 progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress);
654
655 float scale = CalcCurrentScale();
656 float radius = G3D::lerp(_shape.SphereDatas.Radius, _shape.SphereDatas.RadiusTarget, progress) * scale;
657
658 SearchUnits(targetList, radius, true);
659}
660
661void AreaTrigger::SearchUnitInBox(std::vector<Unit*>& targetList)
662{
663 float progress = GetProgress();
664 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
665 if (createProperties->MorphCurveId)
666 progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress);
667
668 float scale = CalcCurrentScale();
669 float extentsX = G3D::lerp(_shape.BoxDatas.Extents[0], _shape.BoxDatas.ExtentsTarget[0], progress) * scale;
670 float extentsY = G3D::lerp(_shape.BoxDatas.Extents[1], _shape.BoxDatas.ExtentsTarget[1], progress) * scale;
671 float extentsZ = G3D::lerp(_shape.BoxDatas.Extents[2], _shape.BoxDatas.ExtentsTarget[2], progress) * scale;
672 float radius = std::sqrt(extentsX * extentsX + extentsY * extentsY);
673
674 SearchUnits(targetList, radius, false);
675
676 Position const& boxCenter = GetPosition();
677 Trinity::Containers::EraseIf(targetList, [boxCenter, extentsX, extentsY, extentsZ](Unit const* unit) -> bool
678 {
679 return !unit->IsWithinBox(boxCenter, extentsX, extentsY, extentsZ / 2);
680 });
681}
682
683void AreaTrigger::SearchUnitInPolygon(std::vector<Unit*>& targetList)
684{
685 float progress = GetProgress();
686 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
687 if (createProperties->MorphCurveId)
688 progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress);
689
690 float height = G3D::lerp(_shape.PolygonDatas.Height, _shape.PolygonDatas.HeightTarget, progress);
691 float minZ = GetPositionZ() - height;
692 float maxZ = GetPositionZ() + height;
693
694 SearchUnits(targetList, GetMaxSearchRadius(), false);
695
696 Trinity::Containers::EraseIf(targetList, [this, minZ, maxZ](Unit const* unit) -> bool
697 {
698 return unit->GetPositionZ() < minZ
699 || unit->GetPositionZ() > maxZ
700 || !CheckIsInPolygon2D(unit);
701 });
702}
703
704void AreaTrigger::SearchUnitInCylinder(std::vector<Unit*>& targetList)
705{
706 float progress = GetProgress();
707 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
708 if (createProperties->MorphCurveId)
709 progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress);
710
711 float scale = CalcCurrentScale();
712 float radius = G3D::lerp(_shape.CylinderDatas.Radius, _shape.CylinderDatas.RadiusTarget, progress) * scale;
713 float height = G3D::lerp(_shape.CylinderDatas.Height, _shape.CylinderDatas.HeightTarget, progress);
714 if (!m_areaTriggerData->HeightIgnoresScale)
715 height *= scale;
716
717 float minZ = GetPositionZ() - height;
718 float maxZ = GetPositionZ() + height;
719
720 SearchUnits(targetList, radius, false);
721
722 Trinity::Containers::EraseIf(targetList, [minZ, maxZ](Unit const* unit) -> bool
723 {
724 return unit->GetPositionZ() < minZ
725 || unit->GetPositionZ() > maxZ;
726 });
727}
728
729void AreaTrigger::SearchUnitInDisk(std::vector<Unit*>& targetList)
730{
731 float progress = GetProgress();
732 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
733 if (createProperties->MorphCurveId)
734 progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress);
735
736 float scale = CalcCurrentScale();
737 float innerRadius = G3D::lerp(_shape.DiskDatas.InnerRadius, _shape.DiskDatas.InnerRadiusTarget, progress) * scale;
738 float outerRadius = G3D::lerp(_shape.DiskDatas.OuterRadius, _shape.DiskDatas.OuterRadiusTarget, progress) * scale;
739 float height = G3D::lerp(_shape.DiskDatas.Height, _shape.DiskDatas.HeightTarget, progress);
740 if (!m_areaTriggerData->HeightIgnoresScale)
741 height *= scale;
742
743 float minZ = GetPositionZ() - height;
744 float maxZ = GetPositionZ() + height;
745
746 SearchUnits(targetList, outerRadius, false);
747
748 Trinity::Containers::EraseIf(targetList, [this, innerRadius, minZ, maxZ](Unit const* unit) -> bool
749 {
750 return unit->IsInDist2d(this, innerRadius) || unit->GetPositionZ() < minZ || unit->GetPositionZ() > maxZ;
751 });
752}
753
754void AreaTrigger::SearchUnitInBoundedPlane(std::vector<Unit*>& targetList)
755{
756 float progress = GetProgress();
757 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
758 if (createProperties->MorphCurveId)
759 progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress);
760
761 float scale = CalcCurrentScale();
762 float extentsX = G3D::lerp(_shape.BoundedPlaneDatas.Extents[0], _shape.BoundedPlaneDatas.ExtentsTarget[0], progress) * scale;
763 float extentsY = G3D::lerp(_shape.BoundedPlaneDatas.Extents[1], _shape.BoundedPlaneDatas.ExtentsTarget[1], progress) * scale;
764 float radius = std::sqrt(extentsX * extentsX + extentsY * extentsY);
765
766 SearchUnits(targetList, radius, false);
767
768 Position const& boxCenter = GetPosition();
769 Trinity::Containers::EraseIf(targetList, [boxCenter, extentsX, extentsY](Unit const* unit) -> bool
770 {
771 return !unit->IsWithinBox(boxCenter, extentsX, extentsY, MAP_SIZE);
772 });
773}
774
775void AreaTrigger::HandleUnitEnterExit(std::vector<Unit*> const& newTargetList)
776{
777 GuidUnorderedSet exitUnits(std::move(_insideUnits));
778
779 std::vector<Unit*> enteringUnits;
780
781 for (Unit* unit : newTargetList)
782 {
783 if (exitUnits.erase(unit->GetGUID()) == 0) // erase(key_type) returns number of elements erased
784 enteringUnits.push_back(unit);
785
786 _insideUnits.insert(unit->GetGUID());
787 }
788
789 // Handle after _insideUnits have been reinserted so we can use GetInsideUnits() in hooks
790 for (Unit* unit : enteringUnits)
791 {
792 if (Player* player = unit->ToPlayer())
793 {
794 if (player->isDebugAreaTriggers)
796
797 player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_ENTER, GetEntry(), 1);
798 }
799
800 DoActions(unit);
801
802 _ai->OnUnitEnter(unit);
803 }
804
805 for (ObjectGuid const& exitUnitGuid : exitUnits)
806 {
807 if (Unit* leavingUnit = ObjectAccessor::GetUnit(*this, exitUnitGuid))
808 {
809 if (Player* player = leavingUnit->ToPlayer())
810 {
811 if (player->isDebugAreaTriggers)
813
814 player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_EXIT, GetEntry(), 1);
815 }
816
817 UndoActions(leavingUnit);
818
819 _ai->OnUnitExit(leavingUnit);
820 }
821 }
822
825 std::count_if(_insideUnits.begin(), _insideUnits.end(), [](ObjectGuid const& guid) { return guid.IsPlayer(); }));
826}
827
829{
831}
832
834{
835 if (_spawnId)
836 {
837 if (AreaTriggerSpawn const* spawn = ASSERT_NOTNULL(sAreaTriggerDataStore->GetAreaTriggerSpawn(_spawnId)))
838 {
839 if (spawn->scriptId)
840 return spawn->scriptId;
841 }
842 }
843
844 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
845 return createProperties->ScriptId;
846
847 return 0;
848}
849
851{
852 return ObjectAccessor::GetUnit(*this, GetCasterGuid());
853}
854
856{
858}
859
861{
862 if (Unit const* caster = GetCaster())
863 return caster->GetFaction();
864
865 return 0;
866}
867
869{
870 return *m_areaTriggerData->BoundsRadius2D * CalcCurrentScale();
871}
872
874{
875 AreaTriggerCreateProperties const* createProperties = GetCreateProperties();
876 AreaTriggerShapeInfo const& shape = GetShape();
877 float newOrientation = GetOrientation();
878
879 // No need to recalculate, orientation didn't change
880 if (G3D::fuzzyEq(_verticesUpdatePreviousOrientation, newOrientation) && shape.PolygonVerticesTarget.empty())
881 return;
882
883 _polygonVertices.assign(shape.PolygonVertices.begin(), shape.PolygonVertices.end());
884 if (!shape.PolygonVerticesTarget.empty())
885 {
886 float progress = GetProgress();
887 if (createProperties->MorphCurveId)
888 progress = sDB2Manager.GetCurveValueAt(createProperties->MorphCurveId, progress);
889
890 for (std::size_t i = 0; i < _polygonVertices.size(); ++i)
891 {
892 Position& vertex = _polygonVertices[i];
893 Position const& vertexTarget = shape.PolygonVerticesTarget[i].Pos;
894
895 vertex.m_positionX = G3D::lerp(vertex.GetPositionX(), vertexTarget.GetPositionX(), progress);
896 vertex.m_positionY = G3D::lerp(vertex.GetPositionY(), vertexTarget.GetPositionY(), progress);
897 }
898 }
899
900 float angleSin = std::sin(newOrientation);
901 float angleCos = std::cos(newOrientation);
902
903 // This is needed to rotate the vertices, following orientation
904 for (Position& vertice : _polygonVertices)
905 {
906 float x = vertice.GetPositionX() * angleCos - vertice.GetPositionY() * angleSin;
907 float y = vertice.GetPositionY() * angleCos + vertice.GetPositionX() * angleSin;
908 vertice.Relocate(x, y);
909 }
910
911 _verticesUpdatePreviousOrientation = newOrientation;
912}
913
915{
916 float testX = pos->GetPositionX();
917 float testY = pos->GetPositionY();
918
919 //this method uses the ray tracing algorithm to determine if the point is in the polygon
920 bool locatedInPolygon = false;
921
922 for (std::size_t vertex = 0; vertex < _polygonVertices.size(); ++vertex)
923 {
924 std::size_t nextVertex;
925
926 //repeat loop for all sets of points
927 if (vertex == (_polygonVertices.size() - 1))
928 {
929 //if i is the last vertex, let j be the first vertex
930 nextVertex = 0;
931 }
932 else
933 {
934 //for all-else, let j=(i+1)th vertex
935 nextVertex = vertex + 1;
936 }
937
938 float vertX_i = GetPositionX() + _polygonVertices[vertex].GetPositionX();
939 float vertY_i = GetPositionY() + _polygonVertices[vertex].GetPositionY();
940 float vertX_j = GetPositionX() + _polygonVertices[nextVertex].GetPositionX();
941 float vertY_j = GetPositionY() + _polygonVertices[nextVertex].GetPositionY();
942
943 // following statement checks if testPoint.Y is below Y-coord of i-th vertex
944 bool belowLowY = vertY_i > testY;
945 // following statement checks if testPoint.Y is below Y-coord of i+1-th vertex
946 bool belowHighY = vertY_j > testY;
947
948 /* following statement is true if testPoint.Y satisfies either (only one is possible)
949 -->(i).Y < testPoint.Y < (i+1).Y OR
950 -->(i).Y > testPoint.Y > (i+1).Y
951
952 (Note)
953 Both of the conditions indicate that a point is located within the edges of the Y-th coordinate
954 of the (i)-th and the (i+1)- th vertices of the polygon. If neither of the above
955 conditions is satisfied, then it is assured that a semi-infinite horizontal line draw
956 to the right from the testpoint will NOT cross the line that connects vertices i and i+1
957 of the polygon
958 */
959 bool withinYsEdges = belowLowY != belowHighY;
960
961 if (withinYsEdges)
962 {
963 // this is the slope of the line that connects vertices i and i+1 of the polygon
964 float slopeOfLine = (vertX_j - vertX_i) / (vertY_j - vertY_i);
965
966 // this looks up the x-coord of a point lying on the above line, given its y-coord
967 float pointOnLine = (slopeOfLine* (testY - vertY_i)) + vertX_i;
968
969 //checks to see if x-coord of testPoint is smaller than the point on the line with the same y-coord
970 bool isLeftToLine = testX < pointOnLine;
971
972 if (isLeftToLine)
973 {
974 //this statement changes true to false (and vice-versa)
975 locatedInPolygon = !locatedInPolygon;
976 }//end if (isLeftToLine)
977 }//end if (withinYsEdges
978 }
979
980 return locatedInPolygon;
981}
982
984{
985 return m_areaTriggerData->OverrideMoveCurveX->OverrideActive
986 && m_areaTriggerData->OverrideMoveCurveY->OverrideActive
987 && m_areaTriggerData->OverrideMoveCurveZ->OverrideActive;
988}
989
991{
992 if (_shape.IsPolygon())
994}
995
996bool UnitFitToActionRequirement(Unit* unit, Unit* caster, AreaTriggerAction const& action)
997{
998 switch (action.TargetType)
999 {
1001 {
1002 return caster->IsValidAssistTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID()));
1003 }
1005 {
1006 return caster->IsValidAttackTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID()));
1007 }
1009 {
1010 return caster->IsInRaidWith(unit);
1011 }
1013 {
1014 return caster->IsInPartyWith(unit);
1015 }
1017 {
1018 return unit->GetGUID() == caster->GetGUID();
1019 }
1021 default:
1022 break;
1023 }
1024
1025 return true;
1026}
1027
1029{
1030 Unit* caster = IsStaticSpawn() ? unit : GetCaster();
1031
1032 if (caster && GetTemplate())
1033 {
1034 for (AreaTriggerAction const& action : GetTemplate()->Actions)
1035 {
1036 if (IsStaticSpawn() || UnitFitToActionRequirement(unit, caster, action))
1037 {
1038 switch (action.ActionType)
1039 {
1041 caster->CastSpell(unit, action.Param, CastSpellExtraArgs(TRIGGERED_FULL_MASK)
1042 .SetOriginalCastId(m_areaTriggerData->CreatingEffectGUID->IsCast() ? *m_areaTriggerData->CreatingEffectGUID : ObjectGuid::Empty));
1043 break;
1045 caster->AddAura(action.Param, unit);
1046 break;
1048 {
1049 if (WorldSafeLocsEntry const* safeLoc = sObjectMgr->GetWorldSafeLoc(action.Param))
1050 {
1051 if (Player* player = caster->ToPlayer())
1052 {
1053 if (player->GetMapId() != safeLoc->Loc.GetMapId())
1054 {
1055 if (WorldSafeLocsEntry const* instanceEntrance = player->GetInstanceEntrance(safeLoc->Loc.GetMapId()))
1056 safeLoc = instanceEntrance;
1057 }
1058 player->TeleportTo(safeLoc->Loc);
1059 }
1060 }
1061 break;
1062 }
1063 default:
1064 break;
1065 }
1066 }
1067 }
1068 }
1069}
1070
1072{
1073 if (GetTemplate())
1074 for (AreaTriggerAction const& action : GetTemplate()->Actions)
1075 if (action.ActionType == AREATRIGGER_ACTION_CAST || action.ActionType == AREATRIGGER_ACTION_ADDAURA)
1076 unit->RemoveAurasDueToSpell(action.Param, GetCasterGuid());
1077}
1078
1079void AreaTrigger::InitSplineOffsets(std::vector<Position> const& offsets, uint32 timeToTarget)
1080{
1081 float angleSin = std::sin(GetOrientation());
1082 float angleCos = std::cos(GetOrientation());
1083
1084 // This is needed to rotate the spline, following caster orientation
1085 std::vector<G3D::Vector3> rotatedPoints;
1086 rotatedPoints.reserve(offsets.size());
1087 for (Position const& offset : offsets)
1088 {
1089 float x = GetPositionX() + (offset.GetPositionX() * angleCos - offset.GetPositionY() * angleSin);
1090 float y = GetPositionY() + (offset.GetPositionY() * angleCos + offset.GetPositionX() * angleSin);
1091 float z = GetPositionZ();
1092
1093 UpdateAllowedPositionZ(x, y, z);
1094 z += offset.GetPositionZ();
1095
1096 rotatedPoints.emplace_back(x, y, z);
1097 }
1098
1099 InitSplines(std::move(rotatedPoints), timeToTarget);
1100}
1101
1102void AreaTrigger::InitSplines(std::vector<G3D::Vector3> splinePoints, uint32 timeToTarget)
1103{
1104 if (splinePoints.size() < 2)
1105 return;
1106
1107 _movementTime = 0;
1108
1109 _spline = std::make_unique<::Movement::Spline<int32>>();
1110 _spline->init_spline(&splinePoints[0], splinePoints.size(), ::Movement::SplineBase::ModeLinear);
1111 _spline->initLengths();
1112
1113 // should be sent in object create packets only
1115 {
1117 const_cast<UF::AreaTriggerData&>(*m_areaTriggerData).ClearChanged(&UF::AreaTriggerData::TimeToTarget);
1118 });
1119
1120 if (IsInWorld())
1121 {
1123 {
1125 reshape.TriggerGUID = GetGUID();
1126 SendMessageToSet(reshape.Write(), true);
1127 }
1128
1130 reshape.TriggerGUID = GetGUID();
1131 reshape.AreaTriggerSpline.emplace();
1132 reshape.AreaTriggerSpline->ElapsedTimeForMovement = GetElapsedTimeForMovement();
1133 reshape.AreaTriggerSpline->TimeToTarget = timeToTarget;
1134 for (G3D::Vector3 const& vec : splinePoints)
1135 reshape.AreaTriggerSpline->Points.emplace_back(vec.x, vec.y, vec.z);
1136
1137 SendMessageToSet(reshape.Write(), true);
1138 }
1139
1140 _reachedDestination = false;
1141}
1142
1144{
1145 return bool(_spline);
1146}
1147
1149{
1150 // Circular movement requires either a center position or an attached unit
1151 ASSERT(orbit.Center.has_value() || orbit.PathTarget.has_value());
1152
1153 // should be sent in object create packets only
1155 {
1157 const_cast<UF::AreaTriggerData&>(*m_areaTriggerData).ClearChanged(&UF::AreaTriggerData::TimeToTarget);
1158 });
1159
1161
1162 _orbitInfo = orbit;
1163
1164 _orbitInfo->TimeToTarget = timeToTarget;
1165 _orbitInfo->ElapsedTimeForMovement = 0;
1166
1167 if (IsInWorld())
1168 {
1170 reshape.TriggerGUID = GetGUID();
1171 reshape.AreaTriggerOrbit = _orbitInfo;
1172
1173 SendMessageToSet(reshape.Write(), true);
1174 }
1175}
1176
1178{
1179 return _orbitInfo.has_value();
1180}
1181
1183{
1184 if (!_orbitInfo)
1185 return nullptr;
1186
1187 if (_orbitInfo->PathTarget)
1188 if (WorldObject* center = ObjectAccessor::GetWorldObject(*this, *_orbitInfo->PathTarget))
1189 return center;
1190
1191 if (_orbitInfo->Center)
1192 return &_orbitInfo->Center->Pos;
1193
1194 return nullptr;
1195}
1196
1198{
1200 if (!centerPos)
1201 return GetPosition();
1202
1203 AreaTriggerCreateProperties const* createProperties = GetCreateProperties();
1204 AreaTriggerOrbitInfo const& cmi = *_orbitInfo;
1205
1206 // AreaTrigger make exactly "Duration / TimeToTarget" loops during his life time
1207 float pathProgress = float(cmi.ElapsedTimeForMovement) / float(cmi.TimeToTarget);
1208 if (createProperties && createProperties->MoveCurveId)
1209 pathProgress = sDB2Manager.GetCurveValueAt(createProperties->MoveCurveId, pathProgress);
1210
1211 // We already made one circle and can't loop
1212 if (!cmi.CanLoop)
1213 pathProgress = std::min(1.f, pathProgress);
1214
1215 float radius = cmi.Radius;
1216 if (G3D::fuzzyNe(cmi.BlendFromRadius, radius))
1217 {
1218 float blendCurve = (cmi.BlendFromRadius - radius) / radius;
1219 // 4.f Defines four quarters
1220 blendCurve = RoundToInterval(blendCurve, 1.f, 4.f) / 4.f;
1221 float blendProgress = std::min(1.f, pathProgress / blendCurve);
1222 radius = G3D::lerp(cmi.BlendFromRadius, cmi.Radius, blendProgress);
1223 }
1224
1225 // Adapt Path progress depending of circle direction
1226 if (!cmi.CounterClockwise)
1227 pathProgress *= -1;
1228
1229 float angle = cmi.InitialAngle + 2.f * float(M_PI) * pathProgress;
1230 float x = centerPos->GetPositionX() + (radius * std::cos(angle));
1231 float y = centerPos->GetPositionY() + (radius * std::sin(angle));
1232 float z = centerPos->GetPositionZ() + cmi.ZOffset;
1233
1234 float orientation = 0.0f;
1235 if (createProperties && createProperties->FacingCurveId)
1236 orientation = sDB2Manager.GetCurveValueAt(createProperties->FacingCurveId, GetProgress());
1237
1239 {
1240 orientation += angle;
1241 orientation += cmi.CounterClockwise ? float(M_PI_4) : -float(M_PI_4);
1242 }
1243
1244 return { x, y, z, orientation };
1245}
1246
1248{
1249 if (_orbitInfo->StartDelay > GetElapsedTimeForMovement())
1250 return;
1251
1252 _orbitInfo->ElapsedTimeForMovement = GetElapsedTimeForMovement() - _orbitInfo->StartDelay;
1253
1255
1257#ifdef TRINITY_DEBUG
1259#endif
1260}
1261
1263{
1265 return;
1266
1267 _movementTime += diff;
1268
1270 {
1271 _reachedDestination = true;
1272 _lastSplineIndex = int32(_spline->last());
1273
1274 G3D::Vector3 lastSplinePosition = _spline->getPoint(_lastSplineIndex);
1275 GetMap()->AreaTriggerRelocation(this, lastSplinePosition.x, lastSplinePosition.y, lastSplinePosition.z, GetOrientation());
1276#ifdef TRINITY_DEBUG
1278#endif
1279
1280 _ai->OnSplineIndexReached(_lastSplineIndex);
1281 _ai->OnDestinationReached();
1282 return;
1283 }
1284
1285 float currentTimePercent = float(_movementTime) / float(GetTimeToTarget());
1286
1287 if (currentTimePercent <= 0.f)
1288 return;
1289
1290 AreaTriggerCreateProperties const* createProperties = GetCreateProperties();
1291 if (createProperties && createProperties->MoveCurveId)
1292 {
1293 float progress = sDB2Manager.GetCurveValueAt(createProperties->MoveCurveId, currentTimePercent);
1294 if (progress < 0.f || progress > 1.f)
1295 {
1296 TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (Id: {}, AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})) has wrong progress ({}) caused by curve calculation (MoveCurveId: {})",
1297 GetEntry(), createProperties->Id.Id, uint32(createProperties->Id.IsCustom), progress, createProperties->MoveCurveId);
1298 }
1299 else
1300 currentTimePercent = progress;
1301 }
1302
1303 int lastPositionIndex = 0;
1304 float percentFromLastPoint = 0;
1305 _spline->computeIndex(currentTimePercent, lastPositionIndex, percentFromLastPoint);
1306
1307 G3D::Vector3 currentPosition;
1308 _spline->evaluate_percent(lastPositionIndex, percentFromLastPoint, currentPosition);
1309
1310 float orientation = GetStationaryO();
1311 if (createProperties && createProperties->FacingCurveId)
1312 orientation += sDB2Manager.GetCurveValueAt(createProperties->FacingCurveId, GetProgress());
1313
1315 {
1316 G3D::Vector3 derivative;
1317 _spline->evaluate_derivative(lastPositionIndex, percentFromLastPoint, derivative);
1318 if (derivative.x != 0.0f || derivative.y != 0.0f)
1319 orientation += std::atan2(derivative.y, derivative.x);
1320 }
1321
1322 GetMap()->AreaTriggerRelocation(this, currentPosition.x, currentPosition.y, currentPosition.z, orientation);
1323#ifdef TRINITY_DEBUG
1325#endif
1326
1327 if (_lastSplineIndex != lastPositionIndex)
1328 {
1329 _lastSplineIndex = lastPositionIndex;
1330 _ai->OnSplineIndexReached(_lastSplineIndex);
1331 }
1332}
1333
1335{
1336 float progress = GetScaleCurveProgress(*m_areaTriggerData->OverrideMoveCurveX, m_areaTriggerData->TimeToTargetPos);
1337
1338 float x = GetScaleCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveX, progress);
1339 float y = GetScaleCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveY, progress);
1340 float z = GetScaleCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveZ, progress);
1341 float orientation = GetOrientation();
1342
1343 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
1344 {
1345 if (createProperties->FacingCurveId)
1346 {
1347 orientation = sDB2Manager.GetCurveValueAt(createProperties->FacingCurveId, GetProgress());
1349 orientation += GetStationaryO();
1350 }
1351 }
1352
1353 GetMap()->AreaTriggerRelocation(this, x, y, z, orientation);
1354}
1355
1357{
1358 if (Unit* caster = GetCaster())
1359 if (Player* player = caster->ToPlayer())
1360 if (player->isDebugAreaTriggers)
1361 player->SummonCreature(1, *this, TEMPSUMMON_TIMED_DESPAWN, Milliseconds(GetTimeToTarget()));
1362}
1363
1365{
1366 AI_Destroy();
1368 _ai->OnInitialize();
1369}
1370
1372{
1373 _ai.reset();
1374}
1375
1376bool AreaTrigger::IsNeverVisibleFor(WorldObject const* seer, bool allowServersideObjects) const
1377{
1378 if (WorldObject::IsNeverVisibleFor(seer, allowServersideObjects))
1379 return true;
1380
1381 if (IsServerSide() && !allowServersideObjects)
1382 {
1383 if (Player const* seerPlayer = seer->ToPlayer())
1384 return !seerPlayer->isDebugAreaTriggers;
1385
1386 return true;
1387 }
1388
1389 return false;
1390}
1391
1392void AreaTrigger::BuildValuesCreate(ByteBuffer* data, Player const* target) const
1393{
1395 std::size_t sizePos = data->wpos();
1396 *data << uint32(0);
1397 *data << uint8(flags);
1398 m_objectData->WriteCreate(*data, flags, this, target);
1399 m_areaTriggerData->WriteCreate(*data, flags, this, target);
1400 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
1401}
1402
1403void AreaTrigger::BuildValuesUpdate(ByteBuffer* data, Player const* target) const
1404{
1406 std::size_t sizePos = data->wpos();
1407 *data << uint32(0);
1409
1411 m_objectData->WriteUpdate(*data, flags, this, target);
1412
1414 m_areaTriggerData->WriteUpdate(*data, flags, this, target);
1415
1416 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
1417}
1418
1420 UF::AreaTriggerData::Mask const& requestedAreaTriggerMask, Player const* target) const
1421{
1423 if (requestedObjectMask.IsAnySet())
1424 valuesMask.Set(TYPEID_OBJECT);
1425
1426 if (requestedAreaTriggerMask.IsAnySet())
1427 valuesMask.Set(TYPEID_AREATRIGGER);
1428
1429 ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
1430 std::size_t sizePos = buffer.wpos();
1431 buffer << uint32(0);
1432 buffer << uint32(valuesMask.GetBlock(0));
1433
1434 if (valuesMask[TYPEID_OBJECT])
1435 m_objectData->WriteUpdate(buffer, requestedObjectMask, true, this, target);
1436
1437 if (valuesMask[TYPEID_AREATRIGGER])
1438 m_areaTriggerData->WriteUpdate(buffer, requestedAreaTriggerMask, true, this, target);
1439
1440 buffer.put<uint32>(sizePos, buffer.wpos() - sizePos - 4);
1441
1442 data->AddUpdateBlock();
1443}
1444
1446{
1447 UpdateData udata(Owner->GetMapId());
1448 WorldPacket packet;
1449
1451
1452 udata.BuildPacket(&packet);
1453 player->SendDirectMessage(&packet);
1454}
1455
1457{
1460}
#define sAreaTriggerDataStore
@ AREATRIGGER_ACTION_ADDAURA
@ AREATRIGGER_ACTION_TELEPORT
@ 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
bool UnitFitToActionRequirement(Unit *unit, Unit *caster, AreaTriggerAction const &action)
Actions
#define M_PI
Definition: Common.h:115
#define M_PI_4
Definition: Common.h:119
std::vector< Condition > ConditionContainer
Definition: ConditionMgr.h:290
#define sConditionMgr
Definition: ConditionMgr.h:365
#define sDB2Manager
Definition: DB2Stores.h:538
CurveInterpolationMode
Definition: DBCEnums.h:862
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
uint16 flags
Definition: DisableMgr.cpp:49
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
#define ASSERT
Definition: Errors.h:68
#define MAP_SIZE
Definition: GridDefines.h:57
@ LANG_DEBUG_AREATRIGGER_ENTITY_LEFT
Definition: Language.h:1019
@ LANG_DEBUG_AREATRIGGER_ENTITY_ENTERED
Definition: Language.h:1018
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
@ TEMPSUMMON_TIMED_DESPAWN
Definition: ObjectDefines.h:65
std::unordered_set< ObjectGuid > GuidUnorderedSet
Definition: ObjectGuid.h:396
@ TYPEID_OBJECT
Definition: ObjectGuid.h:35
@ TYPEID_AREATRIGGER
Definition: ObjectGuid.h:46
@ TYPEMASK_AREATRIGGER
Definition: ObjectGuid.h:66
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
@ QUEST_OBJECTIVE_AREA_TRIGGER_EXIT
Definition: QuestDef.h:352
@ QUEST_OBJECTIVE_AREA_TRIGGER_ENTER
Definition: QuestDef.h:351
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
Definition: SpellDefines.h:266
#define sSpellMgr
Definition: SpellMgr.h:849
T RoundToInterval(T &num, T floor, T ceil)
Definition: Util.h:97
Position const centerPos
EnumFlag< AreaTriggerCreatePropertiesFlag > Flags
AreaTriggerCreatePropertiesId Id
Optional< AreaTriggerOrbitInfo > OrbitInfo
AreaTriggerTemplate const * Template
Optional< AreaTriggerScaleCurveTemplate > ExtraScale
AreaTriggerTemplate const * GetTemplate() const
AreaTriggerCreateProperties const * _areaTriggerCreateProperties
Definition: AreaTrigger.h:233
bool HasSplines() const
void UpdateTargetList()
bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects=false) const override
void ClearUpdateMask(bool remove) override
void UndoActions(Unit *unit)
bool _isRemoved
Definition: AreaTrigger.h:220
std::vector< Position > _polygonVertices
Definition: AreaTrigger.h:224
ObjectGuid::LowType _spawnId
Definition: AreaTrigger.h:208
void DebugVisualizePosition()
int32 _duration
Definition: AreaTrigger.h:216
void InitSplineOffsets(std::vector< Position > const &offsets, uint32 timeToTarget)
void AI_Destroy()
uint32 GetTimeSinceCreated() const
Definition: AreaTrigger.h:101
float CalcCurrentScale() const
void InitOrbit(AreaTriggerOrbitInfo const &orbit, uint32 timeToTarget)
uint32 _timeSinceCreated
Definition: AreaTrigger.h:218
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()
uint32 GetScriptId() const
float GetStationaryO() const override
Definition: AreaTrigger.h:85
void ClearOverrideScaleCurve()
float GetScaleCurveValue(UF::ScaleCurve const &scaleCurve, uint32 timeTo) const
AreaTriggerShapeInfo const & GetShape() const
Definition: AreaTrigger.h:149
uint32 GetFaction() const override
void HandleUnitEnterExit(std::vector< Unit * > const &targetList)
ObjectGuid const & GetCasterGuid() const
Definition: AreaTrigger.h:143
void RelocateStationaryPosition(Position const &pos)
Definition: AreaTrigger.h:86
bool _reachedDestination
Definition: AreaTrigger.h:227
int32 GetTotalDuration() const
Definition: AreaTrigger.h:131
float GetMaxSearchRadius() const
void UpdateOverridePosition()
void SearchUnitInBoundedPlane(std::vector< Unit * > &targetList)
void BuildValuesCreate(ByteBuffer *data, Player const *target) const override
UF::UpdateField< UF::AreaTriggerData, 0, TYPEID_AREATRIGGER > m_areaTriggerData
Definition: AreaTrigger.h:167
std::unique_ptr< AreaTriggerAI > _ai
Definition: AreaTrigger.h:237
uint32 _movementTime
Definition: AreaTrigger.h:229
ObjectGuid _targetGuid
Definition: AreaTrigger.h:210
bool IsServerSide() const
Definition: AreaTrigger.h:77
void ClearScaleCurve(UF::MutableFieldReference< UF::ScaleCurve, false > scaleCurveMutator)
void ClearOverrideMoveCurve()
Position const * GetOrbitCenterPosition() const
void SearchUnits(std::vector< Unit * > &targetList, float radius, bool check3D)
float GetScaleCurveProgress(UF::ScaleCurve const &scaleCurve, uint32 timeTo) const
void BuildValuesUpdateForPlayerWithMask(UpdateData *data, UF::ObjectData::Mask const &requestedObjectMask, UF::AreaTriggerData::Mask const &requestedAreaTriggerMask, Player const *target) const
uint32 GetTimeToTarget() const
Definition: AreaTrigger.h:118
void AddToWorld() override
Definition: AreaTrigger.cpp:62
float GetProgress() const
int32 _lastSplineIndex
Definition: AreaTrigger.h:228
void InitSplines(std::vector< G3D::Vector3 > splinePoints, uint32 timeToTarget)
void Update(uint32 diff) override
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool allowDuplicate)
GuidUnorderedSet _insideUnits
Definition: AreaTrigger.h:235
static ObjectGuid CreateNewMovementForceId(Map *map, uint32 areaTriggerId)
bool IsStaticSpawn() const
Definition: AreaTrigger.h:78
bool CheckIsInPolygon2D(Position const *pos) const
void UpdateSplinePosition(uint32 diff)
void SearchUnitInCylinder(std::vector< Unit * > &targetList)
void ClearExtraScaleCurve()
void SearchUnitInDisk(std::vector< Unit * > &targetList)
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
std::unique_ptr<::Movement::Spline< int32 > > _spline
Definition: AreaTrigger.h:225
void SearchUnitInPolygon(std::vector< Unit * > &targetList)
uint32 GetElapsedTimeForMovement() const
Definition: AreaTrigger.h:157
AreaTriggerTemplate const * _areaTriggerTemplate
Definition: AreaTrigger.h:234
void SetOverrideMoveCurve(float x, float y, float z)
void SearchUnitInSphere(std::vector< Unit * > &targetList)
void SetOverrideScaleCurve(float overrideScale)
Optional< AreaTriggerOrbitInfo > _orbitInfo
Definition: AreaTrigger.h:231
void UpdateShape()
bool IsCustom() const
Definition: AreaTrigger.h:76
AuraEffect const * _aurEff
Definition: AreaTrigger.h:212
void UpdateOrbitPosition(uint32 diff)
void SetScaleCurve(UF::MutableFieldReference< UF::ScaleCurve, false > scaleCurveMutator, float constantValue)
void SetDuration(int32 newDuration)
void _UpdateDuration(int32 newDuration)
void DoActions(Unit *unit)
float GetScaleCurveValueAtProgress(UF::ScaleCurve const &scaleCurve, float x) const
void SetExtraScaleCurve(float extraScale)
void BuildValuesUpdate(ByteBuffer *data, Player const *target) const override
void RemoveFromWorld() override
Definition: AreaTrigger.cpp:78
Position CalculateOrbitPosition() const
int32 GetDuration() const
Definition: AreaTrigger.h:130
bool HasOrbit() const
AreaTriggerCreateProperties const * GetCreateProperties() const
Definition: AreaTrigger.h:137
bool HasOverridePosition() const
int32 _totalDuration
Definition: AreaTrigger.h:217
Unit * GetCaster() const
void SearchUnitInBox(std::vector< Unit * > &targetList)
float _verticesUpdatePreviousOrientation
Definition: AreaTrigger.h:219
AreaTriggerShapeInfo _shape
Definition: AreaTrigger.h:215
size_t wpos() const
Definition: ByteBuffer.h:412
void put(std::size_t pos, T value)
Definition: ByteBuffer.h:220
void PSendSysMessage(const char *fmt, Args &&... args)
Definition: Chat.h:57
constexpr bool HasFlag(T flag) const
Definition: EnumFlag.h:106
Definition: Map.h:189
MapStoredObjectTypesContainer & GetObjectsStore()
Definition: Map.h:422
AreaTriggerBySpawnIdContainer & GetAreaTriggerBySpawnIdStore()
Definition: Map.h:433
ObjectGuid::LowType GenerateLowGuid()
Definition: Map.h:519
void AreaTriggerRelocation(AreaTrigger *at, float x, float y, float z, float orientation)
Definition: Map.cpp:1171
Difficulty GetDifficultyID() const
Definition: Map.h:324
uint32 GetId() const
Definition: Map.cpp:3228
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:319
uint64 LowType
Definition: ObjectGuid.h:278
uint16 m_objectType
Definition: Object.h:401
ObjectGuid const & GetGUID() const
Definition: Object.h:160
bool IsInWorld() const
Definition: Object.h:154
UF::UpdateField< UF::ObjectData, 0, TYPEID_OBJECT > m_objectData
Definition: Object.h:267
CreateObjectBits m_updateFlag
Definition: Object.h:404
virtual void ClearUpdateMask(bool remove)
Definition: Object.cpp:790
void SetUpdateFieldValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type value)
Definition: Object.h:287
uint32 GetEntry() const
Definition: Object.h:161
UF::UpdateFieldHolder m_values
Definition: Object.h:266
void _Create(ObjectGuid const &guid)
Definition: Object.cpp:101
ByteBuffer & PrepareValuesUpdateBuffer(UpdateData *data) const
Definition: Object.cpp:225
void DoWithSuppressingObjectUpdates(Action &&action)
Definition: Object.h:381
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void SetEntry(uint32 entry)
Definition: Object.h:162
virtual void SetObjectScale(float scale)
Definition: Object.h:165
virtual UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const
Definition: Object.cpp:770
TypeID m_objectTypeId
Definition: Object.h:403
static Player * ToPlayer(Object *o)
Definition: Object.h:213
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:6324
uint32 GetSpellXSpellVisualId(WorldObject const *caster=nullptr, WorldObject const *viewer=nullptr) const
Definition: SpellInfo.cpp:4363
uint32 const Id
Definition: SpellInfo.h:325
Definition: Spell.h:255
ObjectGuid m_castId
Definition: Spell.h:568
virtual TransportBase * RemovePassenger(WorldObject *passenger)=0
virtual void CalculatePassengerOffset(float &x, float &y, float &z, float *o=nullptr) const =0
This method transforms supplied global coordinates into local offsets.
virtual void AddPassenger(WorldObject *passenger)=0
bool Remove(KEY_TYPE const &handle)
bool Insert(KEY_TYPE const &handle, SPECIFIC_TYPE *obj)
void ClearChanged(UpdateField< T, BlockBit, Bit >(Derived::*))
Definition: UpdateField.h:572
Mask const & GetChangesMask() const
Definition: UpdateField.h:605
static constexpr std::size_t size()
Definition: UpdateField.h:780
MutableFieldReference< T, false > ModifyValue(UpdateField< T, BlockBit, Bit >(Derived::*field))
Definition: UpdateField.h:683
void ClearChangesMask(UpdateField< T, BlockBit, Bit >(Derived::*field))
Definition: UpdateField.h:690
bool HasChanged(uint32 index) const
Definition: UpdateField.h:701
uint32 GetChangedObjectTypeMask() const
Definition: UpdateField.h:696
Definition: Unit.h:627
void _RegisterAreaTrigger(AreaTrigger *areaTrigger)
Definition: Unit.cpp:5315
Aura * AddAura(uint32 spellId, Unit *target)
Definition: Unit.cpp:11618
bool IsInRaidWith(Unit const *unit) const
Definition: Unit.cpp:11546
bool IsInPartyWith(Unit const *unit) const
Definition: Unit.cpp:11527
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3831
bool BuildPacket(WorldPacket *packet)
Definition: UpdateData.cpp:40
void AddUpdateBlock()
Definition: UpdateData.h:49
uint32 GetBlock(uint32 index) const
Definition: UpdateMask.h:53
void Set(uint32 index)
Definition: UpdateMask.h:84
constexpr uint32 GetMapId() const
Definition: Position.h:201
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition: Object.cpp:1744
Map * GetMap() const
Definition: Object.h:624
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition: Object.cpp:1371
void AddToWorld() override
Definition: Object.cpp:1011
void RemoveFromWorld() override
Definition: Object.cpp:1017
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:2991
PhaseShift & GetPhaseShift()
Definition: Object.h:523
void SetZoneScript()
Definition: Object.cpp:2011
TransportBase * GetTransport() const
Definition: Object.h:750
ZoneScript * m_zoneScript
Definition: Object.h:800
virtual void SetMap(Map *map)
Definition: Object.cpp:1794
void AddObjectToRemoveList()
Definition: Object.cpp:1824
void UpdatePositionData()
Definition: Object.cpp:992
Player * GetSpellModOwner() const
Definition: Object.cpp:2272
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:3144
MovementInfo m_movementInfo
Definition: Object.h:761
virtual bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects=false) const
Definition: Object.h:821
virtual void Update(uint32 diff)
Definition: Object.cpp:898
Optional< AreaTriggerSplineInfo > AreaTriggerSpline
Optional< AreaTriggerOrbitInfo > AreaTriggerOrbit
virtual void OnAreaTriggerRemove(AreaTrigger *areaTrigger)
Definition: ZoneScript.h:78
virtual void OnAreaTriggerCreate(AreaTrigger *areaTrigger)
Definition: ZoneScript.h:77
AreaTriggerAI * SelectAreaTriggerAI(AreaTrigger *at)
Definition: wmo.h:163
TC_GAME_API WorldObject * GetWorldObject(WorldObject const &, ObjectGuid const &)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
void MultimapErasePair(M< K, V, Rest... > &multimap, K const &key, V const &value)
Definition: MapUtils.h:39
void EraseIf(Container &c, Predicate p)
Definition: Containers.h:279
UpdateFieldFlag
Definition: UpdateField.h:34
STL namespace.
AreaTriggerActionUserTypes TargetType
Optional< TaggedPosition< Position::XYZ > > Center
Optional< ObjectGuid > PathTarget
std::array< DBCPosition2D, 2 > Points
std::variant< float, AreaTriggerScaleCurvePointsTemplate > Curve
struct AreaTriggerShapeInfo::@199::@203 BoxDatas
struct AreaTriggerShapeInfo::@199::@207 BoundedPlaneDatas
std::vector< TaggedPosition< Position::XY > > PolygonVertices
AreaTriggerShapeType Type
struct AreaTriggerShapeInfo::@199::@202 SphereDatas
std::vector< TaggedPosition< Position::XY > > PolygonVerticesTarget
struct AreaTriggerShapeInfo::@199::@205 CylinderDatas
struct AreaTriggerShapeInfo::@199::@204 PolygonDatas
struct AreaTriggerShapeInfo::@199::@206 DiskDatas
Optional< int32 > SpellForVisuals
AreaTriggerCreatePropertiesId Id
void operator()(Player const *player) const
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:203
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:191
bool Stationary
Definition: Object.h:88
bool AreaTrigger
Definition: Object.h:94
struct MovementInfo::TransportInfo transport
constexpr void SetOrientation(float orientation)
Definition: Position.h:71
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
constexpr bool IsInDist2d(float x, float y, float dist) const
Definition: Position.h:140
float m_positionX
Definition: Position.h:53
float m_positionY
Definition: Position.h:54
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
bool IsPositionValid() const
Definition: Position.cpp:42
bool IsWithinBox(Position const &center, float xradius, float yradius, float zradius) const
Definition: Position.cpp:65
constexpr void Relocate(float x, float y)
Definition: Position.h:63
constexpr Position GetPosition() const
Definition: Position.h:84
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
uint8 phaseUseFlags
Definition: SpawnData.h:106
uint32 phaseId
Definition: SpawnData.h:107
Position spawnPoint
Definition: SpawnData.h:105
uint32 phaseGroup
Definition: SpawnData.h:108
uint32 ScriptVisualID
Definition: SpellDefines.h:505
uint32 SpellXSpellVisualID
Definition: SpellDefines.h:504
UpdateField< UF::ScaleCurve, 0, 3 > OverrideScaleCurve
UpdateField< UF::ScaleCurve, 0, 7 > OverrideMoveCurveZ
UpdateField< UF::VisualAnim, 0, 25 > VisualAnim
UpdateField< ObjectGuid, 0, 22 > OrbitPathTarget
UpdateField< ObjectGuid, 0, 8 > Caster
UpdateField< UF::SpellCastVisual, 0, 16 > SpellVisual
UpdateField< float, 0, 17 > BoundsRadius2D
UpdateField< uint32, 0, 11 > TimeToTargetScale
UpdateField< UF::ScaleCurve, 0, 6 > OverrideMoveCurveY
UpdateField< int32, 0, 15 > SpellForVisuals
UpdateField< uint32, 0, 18 > DecalPropertiesID
UpdateField< uint32, 0, 21 > NumPlayersInside
UpdateField< UF::ScaleCurve, 0, 5 > OverrideMoveCurveX
UpdateField< int32, 0, 14 > SpellID
UpdateField< uint32, 0, 10 > TimeToTarget
UpdateField< ObjectGuid, 0, 19 > CreatingEffectGUID
UpdateField< uint32, 0, 9 > Duration
UpdateField< uint32, 0, 20 > NumUnitsInside
UpdateField< UF::ScaleCurve, 0, 4 > ExtraScaleCurve
std::enable_if_t< std::is_base_of_v< HasChangesMaskTag, U >, std::conditional_t< std::is_base_of_v< IsUpdateFieldStructureTag, V >, MutableFieldReference< V, PublicSet >, std::conditional_t< std::is_base_of_v< IsUpdateFieldHolderTag, V >, MutableNestedFieldReference< V, PublicSet >, std::conditional_t< PublicSet, UpdateFieldPublicSetter< V >, UpdateFieldSetter< V > > > > > ModifyValue(UpdateField< V, BlockBit, Bit >(T::*field))
Definition: UpdateField.h:262
UpdateFieldArray< TaggedPosition< Position::XY >, 2, 4, 5 > Points
UpdateField< uint32, 0, 3 > ParameterCurve
UpdateField< uint32, 0, 2 > StartTimeOffset
UpdateField< bool, 0, 1 > OverrideActive
UpdateField< uint32, 0, 3 > AnimKitID
UpdateField< bool, 0, 1 > Field_C
UpdateField< uint32, 0, 2 > AnimationDataID