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 "ScriptMgr.h"
40#include "SpellInfo.h"
41#include "SpellMgr.h"
42#include "Spline.h"
43#include "Transport.h"
44#include "Unit.h"
45#include "UpdateData.h"
46#include "ZoneScript.h"
47#include "advstd.h"
48#include <bit>
49
50AreaTrigger::AreaTrigger() : WorldObject(false), MapObject(), _spawnId(0), _aurEff(nullptr),
51 _duration(0), _totalDuration(0), _verticesUpdatePreviousOrientation(std::numeric_limits<float>::infinity()),
52 _isRemoved(false), _reachedDestination(true), _lastSplineIndex(0),
53 _areaTriggerCreateProperties(nullptr), _areaTriggerTemplate(nullptr)
54{
56
58
60}
61
65
67{
69 if (!IsInWorld())
70 {
71 if (m_zoneScript)
73
75 if (_spawnId)
76 GetMap()->GetAreaTriggerBySpawnIdStore().insert(std::make_pair(_spawnId, this));
77
79 }
80}
81
83{
85 if (IsInWorld())
86 {
87 if (m_zoneScript)
89
90 _isRemoved = true;
91
92 if (Unit* caster = GetCaster())
93 caster->_UnregisterAreaTrigger(this);
94
95 _ai->OnRemove();
96
97 // Handle removal of all units, calling OnUnitExit & deleting auras if needed
99
101
102 if (IsStaticSpawn())
103 Trinity::Containers::MultimapErasePair(GetMap()->GetAreaTriggerBySpawnIdStore(), _spawnId, this);
105 }
106}
107
108void AreaTrigger::PlaySpellVisual(uint32 spellVisualId) const
109{
111 packet.AreaTriggerGUID = GetGUID();
112 packet.SpellVisualID = spellVisualId;
113 SendMessageToSet(packet.Write(), false);
114}
115
116bool 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*/)
117{
118 _targetGuid = target ? target->GetGUID() : ObjectGuid::Empty;
119 _aurEff = aurEff;
120
121 SetMap(map);
122 Relocate(pos);
124 if (!IsPositionValid())
125 {
126 TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})) not created. Invalid coordinates (X: {} Y: {})", areaTriggerCreatePropertiesId.Id, uint32(areaTriggerCreatePropertiesId.IsCustom), GetPositionX(), GetPositionY());
127 return false;
128 }
129
130 _areaTriggerCreateProperties = sAreaTriggerDataStore->GetAreaTriggerCreateProperties(areaTriggerCreatePropertiesId);
132 {
133 TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})) not created. Invalid areatrigger create properties id", areaTriggerCreatePropertiesId.Id, uint32(areaTriggerCreatePropertiesId.IsCustom));
134 return false;
135 }
136
138
140
141 _Create(ObjectGuid::Create<HighGuid::AreaTrigger>(GetMapId(), GetTemplate() ? GetTemplate()->Id.Id : 0, GetMap()->GenerateLowGuid<HighGuid::AreaTrigger>()));
142
143 if (GetTemplate())
145
146 SetObjectScale(1.0f);
147 SetDuration(duration);
148
150
151 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
152 if (caster)
153 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::Caster), caster->GetGUID());
154 if (spell)
155 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::CreatingEffectGUID), spell->m_castId);
156 if (spellInfo && !IsStaticSpawn())
157 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::SpellID), spellInfo->Id);
158
159 SpellInfo const* spellForVisuals = spellInfo;
160 if (GetCreateProperties()->SpellForVisuals)
161 {
162 spellForVisuals = sSpellMgr->GetSpellInfo(*GetCreateProperties()->SpellForVisuals, DIFFICULTY_NONE);
163
164 if (spellForVisuals)
165 spellVisual.SpellXSpellVisualID = caster ? caster->GetCastSpellXSpellVisualId(spellForVisuals) : spellForVisuals->GetSpellXSpellVisualId();
166 }
167 if (spellForVisuals)
168 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::SpellForVisuals), spellForVisuals->Id);
169
170 SetSpellVisual(spellVisual);
171 if (!IsStaticSpawn())
172 {
173 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTargetScale), GetCreateProperties()->TimeToTargetScale != 0 ? GetCreateProperties()->TimeToTargetScale : *m_areaTriggerData->Duration);
174 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTargetPos), *m_areaTriggerData->Duration);
175 }
176 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::BoundsRadius2D), GetCreateProperties()->Shape.GetMaxSearchRadius());
177 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::DecalPropertiesID), GetCreateProperties()->DecalPropertiesId);
178 if (IsServerSide())
179 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::DecalPropertiesID), 24); // Blue decal, for .debug areatrigger visibility
180
181 SetScaleCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve), 1.0f);
182
183 if (caster && spellInfo)
184 {
185 if (Player const* modOwner = caster->GetSpellModOwner())
186 {
187 float multiplier = 1.0f;
188 int32 flat = 0;
189 modOwner->GetSpellModValues(spellInfo, SpellModOp::Radius, spell, *m_areaTriggerData->BoundsRadius2D, &flat, &multiplier);
190 if (multiplier != 1.0f)
191 {
192 ScaleCurveData overrideScale;
193 overrideScale.Curve = multiplier;
194 SetScaleCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OverrideScaleCurve), overrideScale);
195 }
196 }
197 }
198
199 if (GetCreateProperties()->AnimId != -1)
200 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::AnimationDataID, 0), GetCreateProperties()->AnimId);
201 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::AnimKitID), GetCreateProperties()->AnimKitId);
203 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::IsDecay), true);
204
206 {
218 return fieldFlags;
219 }();
220 ReplaceAllAreaTriggerFlags(fieldFlags);
221
224
225 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ScaleCurveId), GetCreateProperties()->ScaleCurveId);
226 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::FacingCurveId), GetCreateProperties()->FacingCurveId);
227 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::MorphCurveId), GetCreateProperties()->MorphCurveId);
228 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::MoveCurveId), GetCreateProperties()->MoveCurveId);
229
230 if (caster)
232 else if (IsStaticSpawn() && spawnData)
233 {
234 if (spawnData->phaseUseFlags || spawnData->phaseId || spawnData->phaseGroup)
236 }
237
238 if (target && aurEff)
239 {
243 }
244
245 if (!IsStaticSpawn())
247
248 UpdateShape();
249
250 std::visit([&]<typename MovementType>(MovementType const& movement)
251 {
252 if constexpr (std::is_same_v<MovementType, AreaTriggerOrbitInfo>)
253 {
254 AreaTriggerOrbitInfo orbit = movement;
256 orbit.PathTarget = target->GetGUID();
257 else
258 orbit.Center = pos;
259
260 this->InitOrbit(orbit);
261 }
262 else if constexpr (std::is_same_v<MovementType, AreaTriggerCreateProperties::SplineInfo>)
263 this->InitSplineOffsets(movement);
264 else if constexpr (std::is_same_v<MovementType, std::monostate>)
266 else
267 static_assert(Trinity::dependant_false_v<MovementType>, "Unsupported movement type");
269
271
272 // movement on transport of areatriggers on unit is handled by themself
273 TransportBase* transport = nullptr;
274 if (caster)
275 {
276 transport = m_movementInfo.transport.guid.IsEmpty() ? caster->GetTransport() : nullptr;
277 if (transport)
278 {
279 // This object must be added to transport before adding to map for the client to properly display it
280 transport->AddPassenger(this, transport->GetPositionOffsetTo(pos));
281 }
282 }
283
285
286 // Relocate areatriggers with circular movement again
287 if (HasOrbit())
289
290 if (!IsStaticSpawn())
291 {
292 if (!GetMap()->AddToMap(this))
293 {
294 // Returning false will cause the object to be deleted - remove from transport
295 if (transport)
296 transport->RemovePassenger(this);
297 return false;
298 }
299 }
300
301 if (caster)
302 caster->_RegisterAreaTrigger(this);
303
304 _ai->OnCreate(spell);
305
306 return true;
307}
308
309AreaTrigger* 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*/)
310{
311 AreaTrigger* at = new AreaTrigger();
312 if (!at->Create(areaTriggerCreatePropertiesId, caster->GetMap(), pos, duration, nullptr, caster, target, spellVisual, spellInfo, spell, aurEff))
313 {
314 delete at;
315 return nullptr;
316 }
317
318 return at;
319}
320
322{
323 return ObjectGuid::Create<HighGuid::AreaTrigger>(map->GetId(), areaTriggerId, map->GenerateLowGuid<HighGuid::AreaTrigger>());
324}
325
326bool AreaTrigger::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool /*addToMap*/, bool /*allowDuplicate*/)
327{
328 _spawnId = spawnId;
329
330 AreaTriggerSpawn const* spawnData = sAreaTriggerDataStore->GetAreaTriggerSpawn(spawnId);
331 if (!spawnData)
332 return false;
333
334 AreaTriggerCreateProperties const* createProperties = sAreaTriggerDataStore->GetAreaTriggerCreateProperties(spawnData->Id);
335 if (!createProperties)
336 return false;
337
338 return Create(spawnData->Id, map, spawnData->spawnPoint, -1, spawnData);
339}
340
342{
344
345 if (!IsStaticSpawn())
346 {
347 // "If" order matter here, Orbit > Attached > Splines
349 {
351 }
352 else if (HasOrbit())
353 {
355 }
357 {
358 if (Unit* target = GetTarget())
359 {
360 float orientation = 0.0f;
361 if (m_areaTriggerData->FacingCurveId)
362 orientation = sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetProgress());
363
365 orientation += target->GetOrientation();
366
367 GetMap()->AreaTriggerRelocation(this, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), orientation);
368 }
369 }
370 else if (HasSplines())
371 {
373 }
374 else
375 {
376 if (m_areaTriggerData->FacingCurveId)
377 {
378 float orientation = sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetProgress());
380 orientation += m_areaTriggerData->Facing;
381
382 SetOrientation(orientation);
383 }
384
385 UpdateShape();
386 }
387 }
388
389 if (GetDuration() != -1)
390 {
391 if (GetDuration() > int32(diff))
393 else
394 {
395 Remove(); // expired
396 return;
397 }
398 }
399
400 _ai->OnUpdate(diff);
401
403}
404
406{
407 if (IsInWorld())
408 {
409 AddObjectToRemoveList(); // calls RemoveFromWorld
410 }
411}
412
414{
416 if (now >= *m_areaTriggerData->CreationTime)
417 return now - *m_areaTriggerData->CreationTime;
418 return 0;
419}
420
425
426void AreaTrigger::SetOverrideScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
427{
429}
430
435
440
441void AreaTrigger::SetExtraScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
442{
443 SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve), points, startTimeOffset, interpolation);
444}
445
450
457
458void AreaTrigger::SetOverrideMoveCurve(std::array<DBCPosition2D, 2> const& xCurvePoints, std::array<DBCPosition2D, 2> const& yCurvePoints,
459 std::array<DBCPosition2D, 2> const& zCurvePoints, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
460{
461 SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveX), xCurvePoints, startTimeOffset, interpolation);
462 SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveY), yCurvePoints, startTimeOffset, interpolation);
463 SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveZ), zCurvePoints, startTimeOffset, interpolation);
464}
465
472
474{
476
478 SetUpdateFieldValue(spellVisualMutator.ModifyValue(&UF::SpellCastVisual::ScriptVisualID), visual.ScriptVisualID);
479}
480
482{
483 _duration = newDuration;
484 _totalDuration = newDuration;
485
486 // negative duration (permanent areatrigger) sent as 0
488}
489
491{
492 _duration = newDuration;
493
494 // should be sent in object create packets only
496 {
498 const_cast<UF::AreaTriggerData&>(*m_areaTriggerData).ClearChanged(&UF::AreaTriggerData::Duration);
499 });
500}
501
503{
504 float scale = 1.0f;
505 if (m_areaTriggerData->OverrideScaleCurve->OverrideActive)
506 scale *= std::max(GetScaleCurveValue(*m_areaTriggerData->OverrideScaleCurve, m_areaTriggerData->TimeToTargetScale), 0.000001f);
507 else if (m_areaTriggerData->ScaleCurveId)
508 scale *= std::max(sDB2Manager.GetCurveValueAt(m_areaTriggerData->ScaleCurveId, GetScaleCurveProgress(*m_areaTriggerData->OverrideScaleCurve, m_areaTriggerData->TimeToTargetScale)), 0.000001f);
509
510 scale *= std::max(GetScaleCurveValue(*m_areaTriggerData->ExtraScaleCurve, m_areaTriggerData->TimeToTargetExtraScale), 0.000001f);
511
512 return scale;
513}
514
516{
517 if (_totalDuration <= 0)
518 return 1.0f;
519
520 return std::clamp(float(GetTimeSinceCreated()) / float(GetTotalDuration()), 0.0f, 1.0f);
521}
522
523float AreaTrigger::GetScaleCurveProgress(UF::ScaleCurve const& scaleCurve, uint32 timeTo) const
524{
525 if (!timeTo)
526 return 0.0f;
527
528 return std::clamp(float(GetTimeSinceCreated() - scaleCurve.StartTimeOffset) / float(timeTo), 0.0f, 1.0f);
529}
530
531float AreaTrigger::GetScaleCurveValueAtProgress(UF::ScaleCurve const& scaleCurve, float x) const
532{
533 ASSERT(*scaleCurve.OverrideActive, "ScaleCurve must be active to evaluate it");
534
535 // unpack ParameterCurve
536 if (*scaleCurve.ParameterCurve & 1u)
537 return advstd::bit_cast<float>(*scaleCurve.ParameterCurve & ~1u);
538
539 std::array<DBCPosition2D, 2> points;
540 for (std::size_t i = 0; i < scaleCurve.Points.size(); ++i)
541 points[i] = { .X = scaleCurve.Points[i].Pos.GetPositionX(), .Y = scaleCurve.Points[i].Pos.GetPositionY() };
542
543 CurveInterpolationMode mode = CurveInterpolationMode(*scaleCurve.ParameterCurve >> 1 & 0x7);
544 std::size_t pointCount = *scaleCurve.ParameterCurve >> 24 & 0xFF;
545
546 return sDB2Manager.GetCurveValueAt(mode, std::span(points.begin(), pointCount), x);
547}
548
549float AreaTrigger::GetScaleCurveValue(UF::ScaleCurve const& scaleCurve, uint32 timeTo) const
550{
551 return GetScaleCurveValueAtProgress(scaleCurve, GetScaleCurveProgress(scaleCurve, timeTo));
552}
553
555{
556 ScaleCurveData curveTemplate;
557 curveTemplate.Curve = constantValue;
558 SetScaleCurve(scaleCurveMutator, curveTemplate);
559}
560
561void AreaTrigger::SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false> scaleCurveMutator, std::array<DBCPosition2D, 2> const& points,
562 Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation)
563{
564 ScaleCurveData curveTemplate;
565 curveTemplate.StartTimeOffset = startTimeOffset.value_or(GetTimeSinceCreated());
566 curveTemplate.Mode = interpolation;
567 curveTemplate.Curve = points;
568
569 SetScaleCurve(scaleCurveMutator, curveTemplate);
570}
571
573{
574 SetScaleCurve(scaleCurveMutator, {});
575}
576
578{
579 if (!curve)
580 {
581 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::OverrideActive), false);
582 return;
583 }
584
585 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::OverrideActive), true);
586 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::StartTimeOffset), curve->StartTimeOffset);
587
588 Position point;
589 // ParameterCurve packing information
590 // (not_using_points & 1) | ((interpolation_mode & 0x7) << 1) | ((first_point_offset & 0xFFFFF) << 4) | ((point_count & 0xFF) << 24)
591 // if not_using_points is set then the entire field is simply read as a float (ignoring that lowest bit)
592
593 if (float const* simpleFloat = std::get_if<float>(&curve->Curve))
594 {
595 uint32 packedCurve = advstd::bit_cast<uint32>(*simpleFloat);
596 packedCurve |= 1;
597
598 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::ParameterCurve), packedCurve);
599
600 // clear points
601 for (std::size_t i = 0; i < UF::size<decltype(UF::ScaleCurve::Points)>(); ++i)
602 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::Points, i), point);
603 }
604 else if (ScaleCurveData::Points const* curvePoints = std::get_if<ScaleCurveData::Points>(&curve->Curve))
605 {
606 CurveInterpolationMode mode = curve->Mode;
607 if ((*curvePoints)[1].X < (*curvePoints)[0].X)
609
610 switch (mode)
611 {
613 // catmullrom requires at least 4 points, impossible here
615 break;
619 // bezier requires more than 2 points, impossible here
621 break;
622 default:
623 break;
624 }
625
626 uint32 pointCount = 2;
628 pointCount = 1;
629
630 uint32 packedCurve = (uint32(mode) << 1) | (pointCount << 24);
631 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::ParameterCurve), packedCurve);
632
633 for (std::size_t i = 0; i < curvePoints->size(); ++i)
634 {
635 point.Relocate((*curvePoints)[i].X, (*curvePoints)[i].Y);
636 SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::Points, i), point);
637 }
638 }
639}
640
642{
643 std::vector<Unit*> targetList;
644
645 m_areaTriggerData->ShapeData.Visit([&]<typename ShapeType>(ShapeType const& shape)
646 {
647 if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerSphere>)
648 this->SearchUnitInSphere(shape, targetList);
649 else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerBox>)
650 this->SearchUnitInBox(shape, targetList);
651 else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerPolygon>)
652 this->SearchUnitInPolygon(shape, targetList);
653 else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerCylinder>)
654 this->SearchUnitInCylinder(shape, targetList);
655 else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerDisk>)
656 this->SearchUnitInDisk(shape, targetList);
657 else if constexpr (std::is_same_v<ShapeType, UF::AreaTriggerBoundedPlane>)
658 this->SearchUnitInBoundedPlane(shape, targetList);
659 });
660
661 if (GetTemplate())
662 {
663 ConditionContainer const* conditions = sConditionMgr->GetConditionsForAreaTrigger(GetTemplate()->Id.Id, GetTemplate()->Id.IsCustom);
664 Trinity::Containers::EraseIf(targetList, [this, conditions](Unit const* target)
665 {
666 if (GetCasterGuid() == target->GetGUID())
667 {
668 if (HasActionSetFlag(AreaTriggerActionSetFlag::NotTriggeredbyCaster))
669 return true;
670 }
671 else
672 {
673 if (HasActionSetFlag(AreaTriggerActionSetFlag::OnlyTriggeredByCaster))
674 return true;
675
676 if (HasActionSetFlag(AreaTriggerActionSetFlag::CreatorsPartyOnly))
677 {
678 Unit* caster = GetCaster();
679 if (!caster)
680 return true;
681
682 if (!caster->IsInRaidWith(target))
683 return true;
684 }
685 }
686
687 if (Player const* player = target->ToPlayer())
688 {
689 switch (player->getDeathState())
690 {
691 case DEAD:
692 if (!HasActionSetFlag(AreaTriggerActionSetFlag::AllowWhileGhost))
693 return true;
694 break;
695 case CORPSE:
696 if (!HasActionSetFlag(AreaTriggerActionSetFlag::AllowWhileDead))
697 return true;
698 break;
699 default:
700 break;
701 }
702 }
703
705 return true;
706
707 if (conditions)
708 return !sConditionMgr->IsObjectMeetToConditions(target, *conditions);
709
710 return false;
711 });
712 }
713
714 HandleUnitEnterExit(targetList);
715}
716
717void AreaTrigger::SearchUnits(std::vector<Unit*>& targetList, float radius, bool check3D)
718{
719 Trinity::AnyUnitInObjectRangeCheck check(this, radius, check3D, false);
720 if (IsStaticSpawn())
721 {
724 }
725 else
726 {
728 Cell::VisitAllObjects(this, searcher, GetMaxSearchRadius());
729 }
730}
731
732void AreaTrigger::SearchUnitInSphere(UF::AreaTriggerSphere const& sphere, std::vector<Unit*>& targetList)
733{
734 float progress = GetProgress();
735 if (m_areaTriggerData->MorphCurveId)
736 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
737
738 float scale = CalcCurrentScale();
739 float radius = G3D::lerp(sphere.Radius, sphere.RadiusTarget, progress) * scale;
740
741 SearchUnits(targetList, radius, true);
742}
743
744void AreaTrigger::SearchUnitInBox(UF::AreaTriggerBox const& box, std::vector<Unit*>& targetList)
745{
746 float progress = GetProgress();
747 if (m_areaTriggerData->MorphCurveId)
748 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
749
750 float scale = CalcCurrentScale();
751 float extentsX = G3D::lerp(box.Extents->Pos.GetPositionX(), box.ExtentsTarget->Pos.GetPositionX(), progress) * scale;
752 float extentsY = G3D::lerp(box.Extents->Pos.GetPositionY(), box.ExtentsTarget->Pos.GetPositionY(), progress) * scale;
753 float extentsZ = G3D::lerp(box.Extents->Pos.GetPositionZ(), box.ExtentsTarget->Pos.GetPositionZ(), progress) * scale;
754 float radius = std::sqrt(extentsX * extentsX + extentsY * extentsY);
755
756 SearchUnits(targetList, radius, false);
757
758 Position const& boxCenter = GetPosition();
759 Trinity::Containers::EraseIf(targetList, [boxCenter, extentsX, extentsY, extentsZ](Unit const* unit) -> bool
760 {
761 return !unit->IsWithinBox(boxCenter, extentsX, extentsY, extentsZ / 2);
762 });
763}
764
765void AreaTrigger::SearchUnitInPolygon(UF::AreaTriggerPolygon const& polygon, std::vector<Unit*>& targetList)
766{
767 float progress = GetProgress();
768 if (m_areaTriggerData->MorphCurveId)
769 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
770
771 float height = G3D::lerp(polygon.Height, polygon.HeightTarget, progress);
772 float minZ = GetPositionZ() - height;
773 float maxZ = GetPositionZ() + height;
774
775 SearchUnits(targetList, GetMaxSearchRadius(), false);
776
777 Trinity::Containers::EraseIf(targetList, [this, minZ, maxZ](Unit const* unit) -> bool
778 {
779 return unit->GetPositionZ() < minZ
780 || unit->GetPositionZ() > maxZ
781 || !unit->IsInPolygon2D(*this, _polygonVertices);
782 });
783}
784
785void AreaTrigger::SearchUnitInCylinder(UF::AreaTriggerCylinder const& cylinder, std::vector<Unit*>& targetList)
786{
787 float progress = GetProgress();
788 if (m_areaTriggerData->MorphCurveId)
789 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
790
791 float scale = CalcCurrentScale();
792 float radius = G3D::lerp(cylinder.Radius, cylinder.RadiusTarget, progress) * scale;
793 float height = G3D::lerp(cylinder.Height, cylinder.HeightTarget, progress);
795 height *= scale;
796
797 float minZ = GetPositionZ() - height;
798 float maxZ = GetPositionZ() + height;
799
800 SearchUnits(targetList, radius, false);
801
802 Trinity::Containers::EraseIf(targetList, [minZ, maxZ](Unit const* unit) -> bool
803 {
804 return unit->GetPositionZ() < minZ
805 || unit->GetPositionZ() > maxZ;
806 });
807}
808
809void AreaTrigger::SearchUnitInDisk(UF::AreaTriggerDisk const& disk, std::vector<Unit*>& targetList)
810{
811 float progress = GetProgress();
812 if (m_areaTriggerData->MorphCurveId)
813 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
814
815 float scale = CalcCurrentScale();
816 float innerRadius = G3D::lerp(disk.InnerRadius, disk.InnerRadiusTarget, progress) * scale;
817 float outerRadius = G3D::lerp(disk.OuterRadius, disk.OuterRadiusTarget, progress) * scale;
818 float height = G3D::lerp(disk.Height, disk.HeightTarget, progress);
820 height *= scale;
821
822 float minZ = GetPositionZ() - height;
823 float maxZ = GetPositionZ() + height;
824
825 SearchUnits(targetList, outerRadius, false);
826
827 Trinity::Containers::EraseIf(targetList, [this, innerRadius, minZ, maxZ](Unit const* unit) -> bool
828 {
829 return unit->IsInDist2d(this, innerRadius) || unit->GetPositionZ() < minZ || unit->GetPositionZ() > maxZ;
830 });
831}
832
833void AreaTrigger::SearchUnitInBoundedPlane(UF::AreaTriggerBoundedPlane const& boundedPlane, std::vector<Unit*>& targetList)
834{
835 float progress = GetProgress();
836 if (m_areaTriggerData->MorphCurveId)
837 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
838
839 float scale = CalcCurrentScale();
840 float extentsX = G3D::lerp(boundedPlane.Extents->Pos.GetPositionX(), boundedPlane.ExtentsTarget->Pos.GetPositionX(), progress) * scale;
841 float extentsY = G3D::lerp(boundedPlane.Extents->Pos.GetPositionY(), boundedPlane.ExtentsTarget->Pos.GetPositionY(), progress) * scale;
842 float radius = std::sqrt(extentsX * extentsX + extentsY * extentsY);
843
844 SearchUnits(targetList, radius, false);
845
846 Position const& boxCenter = GetPosition();
847 Trinity::Containers::EraseIf(targetList, [boxCenter, extentsX, extentsY](Unit const* unit) -> bool
848 {
849 return !unit->IsWithinBox(boxCenter, extentsX, extentsY, MAP_SIZE);
850 });
851}
852
853void AreaTrigger::HandleUnitEnterExit(std::vector<Unit*> const& newTargetList, AreaTriggerExitReason exitMode)
854{
855 GuidUnorderedSet exitUnits(std::move(_insideUnits));
856
857 std::vector<Unit*> enteringUnits;
858
859 for (Unit* unit : newTargetList)
860 {
861 if (exitUnits.erase(unit->GetGUID()) == 0) // erase(key_type) returns number of elements erased
862 enteringUnits.push_back(unit);
863
864 _insideUnits.insert(unit->GetGUID());
865 }
866
867 // Handle after _insideUnits have been reinserted so we can use GetInsideUnits() in hooks
868 for (Unit* unit : enteringUnits)
869 HandleUnitEnter(unit);
870
871 for (ObjectGuid const& exitUnitGuid : exitUnits)
872 if (Unit* leavingUnit = ObjectAccessor::GetUnit(*this, exitUnitGuid))
873 HandleUnitExitInternal(leavingUnit, exitMode);
874
876
877 if (IsStaticSpawn())
878 setActive(!_insideUnits.empty());
879}
880
882{
883 if (Player* player = unit->ToPlayer())
884 {
885 if (player->isDebugAreaTriggers)
887
888 player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_ENTER, GetEntry(), 1);
889
890 if (GetTemplate()->ActionSetId)
891 player->UpdateCriteria(CriteriaType::EnterAreaTriggerWithActionSet, GetTemplate()->ActionSetId);
892 }
893
894 DoActions(unit);
895
896 _ai->OnUnitEnter(unit);
897
898 // OnUnitEnter script can despawn this areatrigger or teleport player to a different map
899 if (!IsInWorld() || !IsInMap(unit))
900 return;
901
902 // Register areatrigger in Unit after actions/scripts to allow them to determine
903 // if the unit is in one or more areatriggers with the same id
904 // without forcing every script to have additional logic excluding this areatrigger
905 unit->EnterAreaTrigger(this);
906}
907
909{
911
912 if (Player* player = unit->ToPlayer())
913 {
914 if (player->isDebugAreaTriggers)
916
917 if (canTriggerOnExit)
918 {
919 player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_EXIT, GetEntry(), 1);
920
921 if (GetTemplate()->ActionSetId)
922 player->UpdateCriteria(CriteriaType::LeaveAreaTriggerWithActionSet, GetTemplate()->ActionSetId);
923 }
924 }
925
926 UndoActions(unit);
927
928 // OnUnitExit script can teleport player to another map, causing it to attempt to exit the areatrigger again (from Unit::ExitAllAreaTriggers)
929 unit->ExitAreaTrigger(this);
930
931 if (canTriggerOnExit)
932 _ai->OnUnitExit(unit, exitMode);
933}
934
936{
937 _insideUnits.erase(unit->GetGUID());
938
940
942}
943
945{
946 if (_spawnId)
947 {
948 if (AreaTriggerSpawn const* spawn = ASSERT_NOTNULL(sAreaTriggerDataStore->GetAreaTriggerSpawn(_spawnId)))
949 {
950 if (spawn->scriptId)
951 return spawn->scriptId;
952 }
953 }
954
955 if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties())
956 return createProperties->ScriptId;
957
958 return 0;
959}
960
962{
963 return ObjectAccessor::GetUnit(*this, GetCasterGuid());
964}
965
967{
969}
970
972{
973 if (Unit const* caster = GetCaster())
974 return caster->GetFaction();
975
976 return 0;
977}
978
980{
981 std::visit([this]<typename ShapeType>(ShapeType const& shapeData)
982 {
983 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
984
985 if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::Sphere>)
986 {
987 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 0);
988 auto sphere = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerSphere>);
989 SetUpdateFieldValue(sphere.ModifyValue(&UF::AreaTriggerSphere::Radius), shapeData.Radius);
990 SetUpdateFieldValue(sphere.ModifyValue(&UF::AreaTriggerSphere::RadiusTarget), shapeData.RadiusTarget);
991 }
992 else if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::Box>)
993 {
994 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 1);
995 auto box = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerBox>);
996 SetUpdateFieldValue(box.ModifyValue(&UF::AreaTriggerBox::Extents), shapeData.Extents);
997 SetUpdateFieldValue(box.ModifyValue(&UF::AreaTriggerBox::ExtentsTarget), shapeData.ExtentsTarget);
998 }
999 else if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::Polygon>)
1000 {
1001 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 3);
1002 auto polygon = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerPolygon>);
1003 auto vertices = polygon.ModifyValue(&UF::AreaTriggerPolygon::Vertices);
1005 for (TaggedPosition<XY> const& vertex : shapeData.PolygonVertices)
1006 AddDynamicUpdateFieldValue(vertices) = vertex;
1007 auto verticesTarget = polygon.ModifyValue(&UF::AreaTriggerPolygon::VerticesTarget);
1008 ClearDynamicUpdateFieldValues(verticesTarget);
1009 for (TaggedPosition<XY> const& vertex : shapeData.PolygonVerticesTarget)
1010 AddDynamicUpdateFieldValue(verticesTarget) = vertex;
1011 SetUpdateFieldValue(polygon.ModifyValue(&UF::AreaTriggerPolygon::Height), shapeData.Height);
1012 SetUpdateFieldValue(polygon.ModifyValue(&UF::AreaTriggerPolygon::HeightTarget), shapeData.HeightTarget);
1013 }
1014 else if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::Cylinder>)
1015 {
1016 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 4);
1017 auto cylinder = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerCylinder>);
1018 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::Radius), shapeData.Radius);
1019 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::RadiusTarget), shapeData.RadiusTarget);
1020 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::Height), shapeData.Height);
1021 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::HeightTarget), shapeData.HeightTarget);
1022 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::LocationZOffset), shapeData.LocationZOffset);
1023 SetUpdateFieldValue(cylinder.ModifyValue(&UF::AreaTriggerCylinder::LocationZOffsetTarget), shapeData.LocationZOffsetTarget);
1024 }
1025 else if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::Disk>)
1026 {
1027 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 7);
1028 auto disk = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerDisk>);
1029 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::InnerRadius), shapeData.InnerRadius);
1030 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::InnerRadiusTarget), shapeData.InnerRadiusTarget);
1031 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::OuterRadius), shapeData.OuterRadius);
1032 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::OuterRadiusTarget), shapeData.OuterRadiusTarget);
1033 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::Height), shapeData.Height);
1034 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::HeightTarget), shapeData.HeightTarget);
1035 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::LocationZOffset), shapeData.LocationZOffset);
1036 SetUpdateFieldValue(disk.ModifyValue(&UF::AreaTriggerDisk::LocationZOffsetTarget), shapeData.LocationZOffsetTarget);
1037 }
1038 else if constexpr (std::is_same_v<ShapeType, AreaTriggerShapeInfo::BoundedPlane>)
1039 {
1040 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeType), 8);
1041 auto boundedPlane = areaTriggerData.ModifyValue(&UF::AreaTriggerData::ShapeData, UF::VariantCase<UF::AreaTriggerBoundedPlane>);
1042 SetUpdateFieldValue(boundedPlane.ModifyValue(&UF::AreaTriggerBoundedPlane::Extents), shapeData.Extents);
1043 SetUpdateFieldValue(boundedPlane.ModifyValue(&UF::AreaTriggerBoundedPlane::ExtentsTarget), shapeData.ExtentsTarget);
1044 }
1045 else
1046 static_assert(Trinity::dependant_false_v<ShapeType>, "Unsupported shape type");
1047 }, shape.Data);
1048}
1049
1051{
1052 return *m_areaTriggerData->BoundsRadius2D * CalcCurrentScale();
1053}
1054
1056{
1057 UF::AreaTriggerPolygon const* shape = m_areaTriggerData->ShapeData.Get<UF::AreaTriggerPolygon>();
1058 float newOrientation = GetOrientation();
1059
1060 // No need to recalculate, orientation didn't change
1061 if (G3D::fuzzyEq(_verticesUpdatePreviousOrientation, newOrientation) && shape->VerticesTarget.empty())
1062 return;
1063
1064 _polygonVertices.assign(shape->Vertices.begin(), shape->Vertices.end());
1065 if (!shape->VerticesTarget.empty())
1066 {
1067 float progress = GetProgress();
1068 if (m_areaTriggerData->MorphCurveId)
1069 progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MorphCurveId, progress);
1070
1071 for (std::size_t i = 0; i < _polygonVertices.size(); ++i)
1072 {
1073 Position& vertex = _polygonVertices[i];
1074 Position const& vertexTarget = shape->VerticesTarget[i].Pos;
1075
1076 vertex.m_positionX = G3D::lerp(vertex.GetPositionX(), vertexTarget.GetPositionX(), progress);
1077 vertex.m_positionY = G3D::lerp(vertex.GetPositionY(), vertexTarget.GetPositionY(), progress);
1078 }
1079 }
1080
1081 float angleSin = std::sin(newOrientation);
1082 float angleCos = std::cos(newOrientation);
1083
1084 // This is needed to rotate the vertices, following orientation
1085 for (Position& vertice : _polygonVertices)
1086 {
1087 float x = vertice.GetPositionX() * angleCos - vertice.GetPositionY() * angleSin;
1088 float y = vertice.GetPositionY() * angleCos + vertice.GetPositionX() * angleSin;
1089 vertice.Relocate(x, y);
1090 }
1091
1092 _verticesUpdatePreviousOrientation = newOrientation;
1093}
1094
1096{
1097 return m_areaTriggerData->OverrideMoveCurveX->OverrideActive
1098 && m_areaTriggerData->OverrideMoveCurveY->OverrideActive
1099 && m_areaTriggerData->OverrideMoveCurveZ->OverrideActive;
1100}
1101
1107
1108bool UnitFitToActionRequirement(Unit* unit, Unit* caster, AreaTriggerAction const& action)
1109{
1110 switch (action.TargetType)
1111 {
1113 {
1114 return caster->IsValidAssistTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID()));
1115 }
1117 {
1118 return caster->IsValidAttackTarget(unit, sSpellMgr->GetSpellInfo(action.Param, caster->GetMap()->GetDifficultyID()));
1119 }
1121 {
1122 return caster->IsInRaidWith(unit);
1123 }
1125 {
1126 return caster->IsInPartyWith(unit);
1127 }
1129 {
1130 return unit->GetGUID() == caster->GetGUID();
1131 }
1133 default:
1134 break;
1135 }
1136
1137 return true;
1138}
1139
1141{
1142 Unit* caster = IsStaticSpawn() ? unit : GetCaster();
1143
1144 if (caster && GetTemplate())
1145 {
1146 for (AreaTriggerAction const& action : GetTemplate()->Actions)
1147 {
1148 if (IsStaticSpawn() || UnitFitToActionRequirement(unit, caster, action))
1149 {
1150 switch (action.ActionType)
1151 {
1153 caster->CastSpell(unit, action.Param, CastSpellExtraArgs(TRIGGERED_FULL_MASK)
1154 .SetOriginalCastId(m_areaTriggerData->CreatingEffectGUID->IsCast() ? *m_areaTriggerData->CreatingEffectGUID : ObjectGuid::Empty));
1155 break;
1157 caster->AddAura(action.Param, unit);
1158 break;
1160 {
1161 if (WorldSafeLocsEntry const* safeLoc = sObjectMgr->GetWorldSafeLoc(action.Param))
1162 {
1163 if (Player* player = caster->ToPlayer())
1164 {
1165 if (player->GetMapId() != safeLoc->Loc.GetMapId())
1166 {
1167 if (WorldSafeLocsEntry const* instanceEntrance = player->GetInstanceEntrance(safeLoc->Loc.GetMapId()))
1168 safeLoc = instanceEntrance;
1169 }
1170 player->TeleportTo(safeLoc->Loc);
1171 }
1172 }
1173 break;
1174 }
1176 if (Player* player = caster->ToPlayer())
1177 {
1178 player->GetRestMgr().SetInnTrigger(InnAreaTrigger{ .IsDBC = false });
1179 player->GetRestMgr().SetRestFlag(REST_FLAG_IN_TAVERN);
1180 }
1181 break;
1182 default:
1183 break;
1184 }
1185 }
1186 }
1187 }
1188}
1189
1191{
1192 if (GetTemplate())
1193 {
1194 for (AreaTriggerAction const& action : GetTemplate()->Actions)
1195 {
1196 switch (action.ActionType)
1197 {
1199 [[fallthrough]];
1201 unit->RemoveAurasDueToSpell(action.Param, GetCasterGuid());
1202 break;
1204 if (Player* player = unit->ToPlayer())
1205 player->GetRestMgr().SetInnTrigger(std::nullopt);
1206 break;
1207 default:
1208 break;
1209}
1210 }
1211 }
1212}
1213
1214void AreaTrigger::InitSplineOffsets(std::vector<Position> const& offsets, Optional<float> overrideSpeed /*= {}*/, Optional<bool> speedIsTimeInSeconds /*= {}*/)
1215{
1216 float angleSin = std::sin(GetOrientation());
1217 float angleCos = std::cos(GetOrientation());
1218
1219 // This is needed to rotate the spline, following caster orientation
1220 std::vector<G3D::Vector3> rotatedPoints;
1221 rotatedPoints.resize(offsets.size());
1222 for (std::size_t i = 0; i < offsets.size(); ++i)
1223 {
1224 Position const& offset = offsets[i];
1225 rotatedPoints[i].x = GetPositionX() + (offset.GetPositionX() * angleCos - offset.GetPositionY() * angleSin);
1226 rotatedPoints[i].y = GetPositionY() + (offset.GetPositionY() * angleCos + offset.GetPositionX() * angleSin);
1227 rotatedPoints[i].z = GetPositionZ();
1228
1229 UpdateAllowedPositionZ(rotatedPoints[i].x, rotatedPoints[i].y, rotatedPoints[i].z);
1230 rotatedPoints[i].z += offset.GetPositionZ();
1231 }
1232
1233 InitSplines(rotatedPoints, overrideSpeed, speedIsTimeInSeconds);
1234}
1235
1236void AreaTrigger::InitSplines(std::vector<G3D::Vector3> const& splinePoints, Optional<float> overrideSpeed /*= {}*/, Optional<bool> speedIsTimeInSeconds /*= {}*/)
1237{
1238 if (splinePoints.size() < 2)
1239 return;
1240
1241 std::unique_ptr<Movement::Spline<float>> spline = std::make_unique<::Movement::Spline<float>>();
1242 spline->init_spline(splinePoints.data(), splinePoints.size(), ::Movement::SplineBase::ModeLinear, _stationaryPosition.GetOrientation());
1243 spline->initLengths();
1244
1245 float speed = overrideSpeed.value_or(GetCreateProperties()->Speed);
1246 if (speed <= 0.0f)
1247 speed = 1.0f;
1248
1249 uint32 timeToTarget = (speedIsTimeInSeconds.value_or(GetCreateProperties()->SpeedIsTime)
1250 ? speed
1251 : spline->length() / speed) * static_cast<float>(IN_MILLISECONDS);
1252
1253 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
1254 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTarget), timeToTarget);
1256
1258 auto pathData = areaTriggerData.ModifyValue(&UF::AreaTriggerData::PathData, UF::VariantCase<UF::AreaTriggerSplineCalculator>);
1259 SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerSplineCalculator::Catmullrom), spline->getPointCount() >= 4);
1260 auto points = pathData.ModifyValue(&UF::AreaTriggerSplineCalculator::Points);
1262 for (G3D::Vector3 const& point : spline->getPoints())
1263 AddDynamicUpdateFieldValue(points) = Vector3ToPosition(point);
1264
1265 _reachedDestination = false;
1266 _spline = std::move(spline);
1267}
1268
1270{
1272 if (now >= *m_areaTriggerData->MovementStartTime)
1273 return now - *m_areaTriggerData->MovementStartTime;
1274 return 0;
1275}
1276
1277void AreaTrigger::InitOrbit(AreaTriggerOrbitInfo const& orbit, Optional<float> overrideSpeed /*= {}*/, Optional<bool> speedIsTimeInSeconds /*= {}*/)
1278{
1279 // Circular movement requires either a center position or an attached unit
1280 ASSERT(orbit.Center.has_value() || orbit.PathTarget.has_value());
1281
1282 float speed = overrideSpeed.value_or(GetCreateProperties()->Speed);
1283 if (speed <= 0.0f)
1284 speed = 1.0f;
1285
1286 uint32 timeToTarget = (speedIsTimeInSeconds.value_or(GetCreateProperties()->SpeedIsTime)
1287 ? speed
1288 : static_cast<uint32>(orbit.Radius * 2.0f * static_cast<float>(M_PI) / speed)) * static_cast<float>(IN_MILLISECONDS);
1289
1290 auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData);
1291 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTarget), timeToTarget);
1293 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OrbitPathTarget), orbit.PathTarget.value_or(ObjectGuid::Empty));
1294 SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ZOffset), orbit.ZOffset);
1295 if (orbit.CanLoop)
1297 else
1299
1301 auto pathData = areaTriggerData.ModifyValue(&UF::AreaTriggerData::PathData, UF::VariantCase<UF::AreaTriggerOrbit>);
1303 SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerOrbit::Center), orbit.Center.value_or(Position()));
1304 SetUpdateFieldValue(pathData.ModifyValue(&UF::AreaTriggerOrbit::Radius), orbit.Radius);
1308}
1309
1311{
1312 UF::AreaTriggerOrbit const* orbit = m_areaTriggerData->PathData.Get<UF::AreaTriggerOrbit>();
1313 if (!orbit)
1314 return nullptr;
1315
1316 if (!m_areaTriggerData->OrbitPathTarget->IsEmpty())
1317 if (WorldObject* center = ObjectAccessor::GetWorldObject(*this, *m_areaTriggerData->OrbitPathTarget))
1318 return center;
1319
1320 return &orbit->Center->Pos;
1321}
1322
1324{
1326 if (!centerPos)
1327 return GetPosition();
1328
1329 UF::AreaTriggerOrbit const& cmi = *m_areaTriggerData->PathData.Get<UF::AreaTriggerOrbit>();
1330
1331 // AreaTrigger make exactly "Duration / TimeToTarget" loops during his life time
1332 float pathProgress = float(GetElapsedTimeForMovement() + *cmi.ExtraTimeForBlending) / float(GetTimeToTarget());
1333 if (m_areaTriggerData->MoveCurveId)
1334 pathProgress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MoveCurveId, pathProgress);
1335
1336 // We already made one circle and can't loop
1338 pathProgress = std::min(1.f, pathProgress);
1339
1340 float radius = cmi.Radius;
1341 if (pathProgress <= 1.0f && G3D::fuzzyNe(cmi.BlendFromRadius, radius))
1342 {
1343 float blendCurve = (cmi.BlendFromRadius - radius) / radius;
1344 RoundToInterval(blendCurve, 1.f, 4.f);
1345 float blendProgress = std::min(1.f, pathProgress / blendCurve * 0.63661975f);
1346 radius = G3D::lerp(cmi.BlendFromRadius, radius, blendProgress);
1347 }
1348
1349 // Adapt Path progress depending of circle direction
1350 if (!cmi.CounterClockwise)
1351 pathProgress *= -1;
1352
1353 float angle = cmi.InitialAngle + 2.f * float(M_PI) * pathProgress;
1354 float x = centerPos->GetPositionX() + (radius * std::cos(angle));
1355 float y = centerPos->GetPositionY() + (radius * std::sin(angle));
1356 float z = centerPos->GetPositionZ() + *m_areaTriggerData->ZOffset;
1357
1358 float orientation = 0.0f;
1359 if (m_areaTriggerData->FacingCurveId)
1360 orientation = sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetProgress());
1361
1363 {
1364 orientation += angle;
1365 orientation += cmi.CounterClockwise ? float(M_PI_4) : -float(M_PI_4);
1366 }
1367
1368 return { x, y, z, orientation };
1369}
1370
1372{
1374
1376#ifdef TRINITY_DEBUG
1378#endif
1379}
1380
1382{
1384 return;
1385
1386 float currentTimePercent = std::clamp(float(GetElapsedTimeForMovement()) / float(GetTimeToTarget()), 0.0f, 1.0f);
1387 _reachedDestination = currentTimePercent >= 1.0f;
1388
1389 if (m_areaTriggerData->MoveCurveId)
1390 {
1391 float progress = sDB2Manager.GetCurveValueAt(m_areaTriggerData->MoveCurveId, currentTimePercent);
1392 if (progress < 0.f || progress > 1.f)
1393 {
1394 AreaTriggerCreateProperties const* createProperties = GetCreateProperties();
1395 TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (Id: {}, AreaTriggerCreatePropertiesId: (Id: {}, IsCustom: {})) has wrong progress ({}) caused by curve calculation (MoveCurveId: {})",
1396 GetEntry(), createProperties->Id.Id, uint32(createProperties->Id.IsCustom), progress, *m_areaTriggerData->MoveCurveId);
1397 }
1398 else
1399 currentTimePercent = progress;
1400 }
1401
1402 int32 lastPositionIndex = 0;
1403 float percentFromLastPoint = 0;
1404 spline.computeIndex(currentTimePercent, lastPositionIndex, percentFromLastPoint);
1405
1406 G3D::Vector3 currentPosition;
1407 spline.evaluate_percent(lastPositionIndex, percentFromLastPoint, currentPosition);
1408
1409 float orientation = _stationaryPosition.GetOrientation();
1410 if (m_areaTriggerData->FacingCurveId)
1411 orientation += sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetProgress());
1412
1414 {
1415 G3D::Vector3 derivative;
1416 spline.evaluate_derivative(lastPositionIndex, percentFromLastPoint, derivative);
1417 if (derivative.x != 0.0f || derivative.y != 0.0f)
1418 orientation += std::atan2(derivative.y, derivative.x);
1419 }
1420
1421 GetMap()->AreaTriggerRelocation(this, currentPosition.x, currentPosition.y, currentPosition.z, orientation);
1422#ifdef TRINITY_DEBUG
1424#endif
1425
1426 if (_lastSplineIndex != lastPositionIndex || _reachedDestination)
1427 {
1428 _lastSplineIndex = lastPositionIndex;
1429 _ai->OnSplineIndexReached(_lastSplineIndex - _spline->first() /*translate to index of the input array used for AreaTrigger::InitSplines*/);
1431 {
1432 _ai->OnDestinationReached();
1433 _spline = nullptr;
1435 }
1436 }
1437}
1438
1440{
1441 float progress = GetScaleCurveProgress(*m_areaTriggerData->OverrideMoveCurveX, m_areaTriggerData->TimeToTargetPos);
1442
1443 float x = GetScaleCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveX, progress);
1444 float y = GetScaleCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveY, progress);
1445 float z = GetScaleCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveZ, progress);
1446 float orientation = GetOrientation();
1447
1448 if (m_areaTriggerData->FacingCurveId)
1449 {
1450 orientation = sDB2Manager.GetCurveValueAt(m_areaTriggerData->FacingCurveId, GetProgress());
1452 orientation += m_areaTriggerData->Facing;
1453 }
1454
1455 GetMap()->AreaTriggerRelocation(this, x, y, z, orientation);
1456}
1457
1459{
1460 if (std::ranges::any_of(_insideUnits, [](ObjectGuid const& guid) { return guid.IsPlayer(); }))
1462 else
1464}
1465
1467{
1468 if (Unit* caster = GetCaster())
1469 if (Player* player = caster->ToPlayer())
1470 if (player->isDebugAreaTriggers)
1471 player->SummonCreature(1, *this, TEMPSUMMON_TIMED_DESPAWN, Milliseconds(GetTimeToTarget()));
1472}
1473
1475{
1476 AI_Destroy();
1478 _ai->OnInitialize();
1479}
1480
1482{
1483 _ai.reset();
1484}
1485
1486bool AreaTrigger::IsNeverVisibleFor(WorldObject const* seer, bool allowServersideObjects) const
1487{
1488 if (WorldObject::IsNeverVisibleFor(seer, allowServersideObjects))
1489 return true;
1490
1491 if (IsServerSide() && !allowServersideObjects)
1492 {
1493 if (Player const* seerPlayer = seer->ToPlayer())
1494 return !seerPlayer->isDebugAreaTriggers;
1495
1496 return true;
1497 }
1498
1499 return false;
1500}
1501
1503{
1504 m_objectData->WriteCreate(flags, data, target, this);
1505 m_areaTriggerData->WriteCreate(flags, data, target, this);
1506}
1507
1509{
1511
1513 m_objectData->WriteUpdate(flags, data, target, this);
1514
1516 m_areaTriggerData->WriteUpdate(flags, data, target, this);
1517}
1518
1520 UF::AreaTriggerData::Mask const& requestedAreaTriggerMask, Player const* target, bool ignoreNestedChangesMask) const
1521{
1524 if (requestedObjectMask.IsAnySet())
1525 valuesMask.Set(TYPEID_OBJECT);
1526
1527 if (requestedAreaTriggerMask.IsAnySet())
1528 valuesMask.Set(TYPEID_AREATRIGGER);
1529
1530 ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
1531 std::size_t sizePos = buffer.wpos();
1532 buffer << uint32(0);
1534 buffer << uint32(valuesMask.GetBlock(0));
1535
1536 if (valuesMask[TYPEID_OBJECT])
1537 m_objectData->WriteUpdate(requestedObjectMask, buffer, target, this, ignoreNestedChangesMask);
1538
1539 if (valuesMask[TYPEID_AREATRIGGER])
1540 m_areaTriggerData->WriteUpdate(requestedAreaTriggerMask, buffer, target, this, ignoreNestedChangesMask);
1541
1542 buffer.put<uint32>(sizePos, buffer.wpos() - sizePos - 4);
1543
1544 data->AddUpdateBlock();
1545}
1546
1548{
1549 UpdateData udata(Owner->GetMapId());
1550 WorldPacket packet;
1551
1553
1554 udata.BuildPacket(&packet);
1555 player->SendDirectMessage(&packet);
1556}
1557
#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
bool UnitFitToActionRequirement(Unit *unit, Unit *caster, AreaTriggerAction const &action)
AreaTriggerFieldFlags
Definition AreaTrigger.h:43
AreaTriggerExitReason
Definition AreaTrigger.h:69
@ 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:569
CurveInterpolationMode
Definition DBCEnums.h:921
@ DIFFICULTY_NONE
Definition DBCEnums.h:933
@ LeaveAreaTriggerWithActionSet
@ EnterAreaTriggerWithActionSet
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
uint16 flags
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:82
#define ASSERT
Definition Errors.h:80
#define MAP_SIZE
Definition GridDefines.h:57
@ 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:190
@ 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:1885
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ QUEST_OBJECTIVE_AREA_TRIGGER_EXIT
Definition QuestDef.h:378
@ QUEST_OBJECTIVE_AREA_TRIGGER_ENTER
Definition QuestDef.h:377
@ REST_FLAG_IN_TAVERN
Definition RestMgr.h:54
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
#define sSpellMgr
Definition SpellMgr.h:812
T RoundToInterval(T &num, T floor, T ceil)
Definition Util.h:97
Position const centerPos
EnumFlag< AreaTriggerCreatePropertiesFlag > Flags
AreaTriggerCreatePropertiesId Id
std::variant< std::monostate, SplineInfo, AreaTriggerOrbitInfo > Movement
AreaTriggerTemplate const * Template
std::vector< AreaTriggerAction > Actions
AreaTriggerTemplate const * GetTemplate() const
AreaTriggerCreateProperties const * _areaTriggerCreateProperties
bool HasAreaTriggerFlag(AreaTriggerFieldFlags flag) const
bool HasSplines() const
void UpdateTargetList()
bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects=false) const override
void UndoActions(Unit *unit)
std::vector< Position > _polygonVertices
ObjectGuid::LowType _spawnId
void DebugVisualizePosition()
bool HasActionSetFlag(AreaTriggerActionSetFlag flag) const
int32 _duration
uint32 GetTimeSinceCreated() 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
uint32 GetScriptId() const
void ClearOverrideScaleCurve()
float GetScaleCurveValue(UF::ScaleCurve const &scaleCurve, uint32 timeTo) const
uint32 GetFaction() const override
ObjectGuid const & GetCasterGuid() const
void RelocateStationaryPosition(Position const &pos)
bool _reachedDestination
void HandleUnitEnterExit(std::vector< Unit * > const &targetList, AreaTriggerExitReason exitMode=AreaTriggerExitReason::NotInside)
void ClearValuesChangesMask() override
int32 GetTotalDuration() const
void UpdateSplinePosition(Movement::Spline< float > &spline)
Position _stationaryPosition
void HandleUnitEnter(Unit *unit)
float GetMaxSearchRadius() const
void UpdateOverridePosition()
void InitSplines(std::vector< G3D::Vector3 > const &splinePoints, Optional< float > overrideSpeed={}, Optional< bool > speedIsTimeInSeconds={})
std::unique_ptr< AreaTriggerAI > _ai
ObjectGuid _targetGuid
void SearchUnitInSphere(UF::AreaTriggerSphere const &sphere, std::vector< Unit * > &targetList)
bool IsServerSide() const
void ClearScaleCurve(UF::MutableFieldReference< UF::ScaleCurve, false > scaleCurveMutator)
void ClearOverrideMoveCurve()
Position const * GetOrbitCenterPosition() const
void SearchUnits(std::vector< Unit * > &targetList, float radius, bool check3D)
void SearchUnitInBoundedPlane(UF::AreaTriggerBoundedPlane const &boundedPlane, std::vector< Unit * > &targetList)
float GetScaleCurveProgress(UF::ScaleCurve const &scaleCurve, uint32 timeTo) const
UF::UpdateField< UF::AreaTriggerData, int32(WowCS::EntityFragment::CGObject), TYPEID_AREATRIGGER > m_areaTriggerData
void SetAreaTriggerFlag(AreaTriggerFieldFlags flag)
void UpdateOrbitPosition()
void SetShape(AreaTriggerShapeInfo const &shape)
uint32 GetTimeToTarget() const
void AddToWorld() override
float GetProgress() const
int32 _lastSplineIndex
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
uint32 GetElapsedTimeForMovement() const
AreaTriggerTemplate const * _areaTriggerTemplate
void RemoveAreaTriggerFlag(AreaTriggerFieldFlags flag)
void SetOverrideMoveCurve(float x, float y, float z)
void SetOverrideScaleCurve(float overrideScale)
void HandleUnitExitInternal(Unit *unit, AreaTriggerExitReason exitMode=AreaTriggerExitReason::NotInside)
bool IsCustom() const
AuraEffect const * _aurEff
void SetScaleCurve(UF::MutableFieldReference< UF::ScaleCurve, false > scaleCurveMutator, float constantValue)
void SetDuration(int32 newDuration)
void _UpdateDuration(int32 newDuration)
void DoActions(Unit *unit)
void ReplaceAllAreaTriggerFlags(AreaTriggerFieldFlags flag)
float GetScaleCurveValueAtProgress(UF::ScaleCurve const &scaleCurve, float x) const
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={})
Position CalculateOrbitPosition() const
int32 GetDuration() const
bool HasOrbit() const
AreaTriggerCreateProperties const * GetCreateProperties() const
bool HasOverridePosition() const
void UpdateHasPlayersFlag()
int32 _totalDuration
std::unique_ptr<::Movement::Spline< float > > _spline
Unit * GetCaster() const
float _verticesUpdatePreviousOrientation
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
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:461
void put(std::size_t pos, T value)
Definition ByteBuffer.h:260
void PSendSysMessage(char const *fmt, Args &&... args)
Definition Chat.h:62
Definition Map.h:225
MapStoredObjectTypesContainer & GetObjectsStore()
Definition Map.h:458
AreaTriggerBySpawnIdContainer & GetAreaTriggerBySpawnIdStore()
Definition Map.h:469
ObjectGuid::LowType GenerateLowGuid()
Definition Map.h:558
void AreaTriggerRelocation(AreaTrigger *at, float x, float y, float z, float orientation)
Definition Map.cpp:1141
Difficulty GetDifficultyID() const
Definition Map.h:360
uint32 GetId() const
Definition Map.cpp:3257
void computeIndex(float t, index_type &out_idx, float &out_u) const
Definition SplineImpl.h:63
void evaluate_derivative(float t, Vector3 &hermite) const
Definition SplineImpl.h:28
void evaluate_percent(float t, Vector3 &c) const
Definition SplineImpl.h:20
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:6283
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:635
uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const override
Definition Unit.cpp:14509
void _RegisterAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5455
void EnterAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5523
Aura * AddAura(uint32 spellId, Unit *target)
Definition Unit.cpp:12249
void ExitAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5528
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:12177
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:12158
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3974
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:1094
Map * GetMap() const
Definition Object.h:411
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition Object.cpp:711
void AddToWorld() override
Definition Object.cpp:365
void RemoveFromWorld() override
Definition Object.cpp:371
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2324
PhaseShift & GetPhaseShift()
Definition Object.h:310
void SetZoneScript()
Definition Object.cpp:1384
TransportBase * GetTransport() const
Definition Object.h:537
void setActive(bool isActiveObject)
Definition Object.cpp:276
ZoneScript * m_zoneScript
Definition Object.h:584
virtual void SetMap(Map *map)
Definition Object.cpp:1144
void AddObjectToRemoveList()
Definition Object.cpp:1174
void UpdatePositionData()
Definition Object.cpp:346
Player * GetSpellModOwner() const
Definition Object.cpp:1641
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2482
MovementInfo m_movementInfo
Definition Object.h:548
virtual bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects=false) const
Definition Object.h:605
bool IsInMap(WorldObject const *obj) const
Definition Object.cpp:469
virtual void Update(uint32 diff)
Definition Object.cpp:245
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
STL namespace.
AreaTriggerActionUserTypes TargetType
Optional< TaggedPosition< Position::XYZ > > Center
Optional< ObjectGuid > PathTarget
std::variant< Sphere, Box, Polygon, Cylinder, Disk, BoundedPlane > Data
AreaTriggerCreatePropertiesId Id
std::variant< float, Points > Curve
CurveInterpolationMode Mode
std::array< DBCPosition2D, 2 > Points
void operator()(Player const *player) const
CastSpellExtraArgs & SetOriginalCastId(ObjectGuid const &castId)
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
struct MovementInfo::TransportInfo transport
constexpr void SetOrientation(float orientation)
Definition Position.h:82
constexpr float GetPositionX() const
Definition Position.h:87
constexpr float GetPositionY() const
Definition Position.h:88
constexpr bool IsInDist2d(float x, float y, float dist) const
Definition Position.h:151
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
bool IsWithinBox(Position const &boxOrigin, float length, float width, float height) const
Definition Position.cpp:68
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
bool Insert(ValueType< ObjectType > object)
bool Remove(ValueType< ObjectType > object)
UpdateField< TaggedPosition< Position::XY >, 0, 1 > Extents
UpdateField< TaggedPosition< Position::XY >, 0, 2 > ExtentsTarget
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::ScaleCurve, 0, 4 > OverrideMoveCurveY
VariantUpdateField< 32, 36, UF::AreaTriggerSplineCalculator, UF::AreaTriggerOrbit, UF::AreaTriggerMovementScript > PathData
UpdateField< uint32, 32, 33 > MoveCurveId
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< float, 32, 34 > Facing
UpdateField< UF::ScaleCurve, 0, 5 > OverrideMoveCurveZ
UpdateField< uint8, 32, 37 > ShapeType
UpdateField< uint32, 0, 12 > TimeToTargetPos
UpdateField< int32, 32, 36 > PathType
UpdateField< float, 0, 25 > ZOffset
UpdateField< uint32, 0, 31 > MorphCurveId
UpdateField< UF::ScaleCurve, 0, 1 > OverrideScaleCurve
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< UF::ScaleCurve, 0, 3 > OverrideMoveCurveX
UpdateField< uint32, 0, 18 > DecalPropertiesID
UpdateField< UF::ScaleCurve, 0, 2 > ExtraScaleCurve
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< ObjectGuid, 0, 7 > Caster
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< 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 > Catmullrom
DynamicUpdateField< TaggedPosition< Position::XYZ >, 0, 2 > Points
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
OptionalUpdateField< int16, 0, 2 > AnimationDataID
UpdateField< bool, 0, 1 > IsDecay
void Add(EntityFragment fragment, bool update, void const *data=nullptr)