diff options
author | Shauren <shauren.trinity@gmail.com> | 2023-10-01 18:56:35 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2023-10-01 18:56:35 +0200 |
commit | c676d1477239aec4d0b235a410e5627a7070a86e (patch) | |
tree | 2b5b119de0bef124dffb18a61fb4c2b90e53e51d /src | |
parent | 2037749ddd1d0dd7a0113d3f86e21a3a1d2425b1 (diff) |
Core/AreaTriggers: Implement missing functionality
* Scale curves are now taken into account when searching for units inside
* Implemented SpellModOp::Radius for areatrigger radius
* Implemented OverrideMoveCurve updatefields - overrides areatrigger position
* Implemented FacingCurve and AREATRIGGER_FLAG_HAS_ABSOLUTE_ORIENTATION
* Implemented ***Target fields for all shape types
* Fixed facing calculation for areatriggers with spline movement
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/AreaTrigger/AreaTrigger.cpp | 396 | ||||
-rw-r--r-- | src/server/game/Entities/AreaTrigger/AreaTrigger.h | 61 | ||||
-rw-r--r-- | src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.cpp | 18 | ||||
-rw-r--r-- | src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 9 | ||||
-rw-r--r-- | src/server/game/Globals/AreaTriggerDataStore.cpp | 7 |
7 files changed, 385 insertions, 110 deletions
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index a17a4f4cc82..8ceeab3b22e 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -43,8 +43,8 @@ #include "advstd.h" #include <bit> -AreaTrigger::AreaTrigger() : WorldObject(false), MapObject(), _spawnId(0), _aurEff(nullptr), _maxSearchRadius(0.0f), - _duration(0), _totalDuration(0), _timeSinceCreated(0), _previousCheckOrientation(std::numeric_limits<float>::infinity()), +AreaTrigger::AreaTrigger() : WorldObject(false), MapObject(), _spawnId(0), _aurEff(nullptr), + _duration(0), _totalDuration(0), _timeSinceCreated(0), _verticesUpdatePreviousOrientation(std::numeric_limits<float>::infinity()), _isRemoved(false), _reachedDestination(true), _lastSplineIndex(0), _movementTime(0), _areaTriggerCreateProperties(nullptr), _areaTriggerTemplate(nullptr) { @@ -101,13 +101,14 @@ void AreaTrigger::RemoveFromWorld() } } -bool AreaTrigger::Create(uint32 areaTriggerCreatePropertiesId, Unit* caster, Unit* target, SpellInfo const* spellInfo, Position const& pos, int32 duration, SpellCastVisual spellVisual, Spell const* spell, AuraEffect const* aurEff) +bool AreaTrigger::Create(uint32 areaTriggerCreatePropertiesId, Unit* caster, Unit* target, SpellInfo const* spellInfo, Position const& pos, int32 duration, SpellCastVisual spellVisual, Spell* spell, AuraEffect const* aurEff) { _targetGuid = target ? target->GetGUID() : ObjectGuid::Empty; _aurEff = aurEff; SetMap(caster->GetMap()); Relocate(pos); + RelocateStationaryPosition(pos); if (!IsPositionValid()) { TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (areaTriggerCreatePropertiesId {}) not created. Invalid coordinates (X: {} Y: {})", areaTriggerCreatePropertiesId, GetPositionX(), GetPositionY()); @@ -135,7 +136,6 @@ bool AreaTrigger::Create(uint32 areaTriggerCreatePropertiesId, Unit* caster, Uni SetObjectScale(1.0f); _shape = GetCreateProperties()->Shape; - _maxSearchRadius = GetCreateProperties()->GetMaxSearchRadius(); auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData); SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::Caster), caster->GetGUID()); @@ -147,11 +147,24 @@ bool AreaTrigger::Create(uint32 areaTriggerCreatePropertiesId, Unit* caster, Uni SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::SpellVisual).ModifyValue(&UF::SpellCastVisual::SpellXSpellVisualID), spellVisual.SpellXSpellVisualID); SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::SpellVisual).ModifyValue(&UF::SpellCastVisual::ScriptVisualID), spellVisual.ScriptVisualID); SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::TimeToTargetScale), GetCreateProperties()->TimeToTargetScale != 0 ? GetCreateProperties()->TimeToTargetScale : *m_areaTriggerData->Duration); - SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::BoundsRadius2D), GetMaxSearchRadius()); + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::BoundsRadius2D), GetCreateProperties()->GetMaxSearchRadius()); SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::DecalPropertiesID), GetCreateProperties()->DecalPropertiesId); SetScaleCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve), GetCreateProperties()->ExtraScale); + if (Player const* modOwner = caster->GetSpellModOwner()) + { + float multiplier = 1.0f; + int32 flat = 0; + modOwner->GetSpellModValues(spellInfo, SpellModOp::Radius, spell, *m_areaTriggerData->BoundsRadius2D, &flat, &multiplier); + if (multiplier != 1.0f) + { + AreaTriggerScaleCurveTemplate overrideScale; + overrideScale.Curve = multiplier; + SetScaleCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::OverrideScaleCurve), overrideScale); + } + } + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::AnimationDataID), GetCreateProperties()->AnimId); SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::AnimKitID), GetCreateProperties()->AnimKitId); if (GetTemplate() && GetTemplate()->HasFlag(AREATRIGGER_FLAG_UNK3)) @@ -220,7 +233,7 @@ bool AreaTrigger::Create(uint32 areaTriggerCreatePropertiesId, Unit* caster, Uni return true; } -AreaTrigger* AreaTrigger::CreateAreaTrigger(uint32 areaTriggerCreatePropertiesId, Unit* caster, Unit* target, SpellInfo const* spellInfo, Position const& pos, int32 duration, SpellCastVisual spellVisual, Spell const* spell /*= nullptr*/, AuraEffect const* aurEff /*= nullptr*/) +AreaTrigger* AreaTrigger::CreateAreaTrigger(uint32 areaTriggerCreatePropertiesId, Unit* caster, Unit* target, SpellInfo const* spellInfo, Position const& pos, int32 duration, SpellCastVisual spellVisual, Spell* spell /*= nullptr*/, AuraEffect const* aurEff /*= nullptr*/) { AreaTrigger* at = new AreaTrigger(); if (!at->Create(areaTriggerCreatePropertiesId, caster, target, spellInfo, pos, duration, spellVisual, spell, aurEff)) @@ -256,6 +269,7 @@ bool AreaTrigger::CreateServer(Map* map, AreaTriggerTemplate const* areaTriggerT { SetMap(map); Relocate(position.spawnPoint); + RelocateStationaryPosition(position.spawnPoint); if (!IsPositionValid()) { TC_LOG_ERROR("entities.areatrigger", "AreaTriggerServer (id {}) not created. Invalid coordinates (X: {} Y: {})", @@ -274,8 +288,9 @@ bool AreaTrigger::CreateServer(Map* map, AreaTriggerTemplate const* areaTriggerT SetObjectScale(1.0f); SetDuration(-1); + _shape = position.Shape; + auto areaTriggerData = m_values.ModifyValue(&AreaTrigger::m_areaTriggerData); - SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::BoundsRadius2D), GetMaxSearchRadius()); if (position.SpellForVisuals) { SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(*position.SpellForVisuals, DIFFICULTY_NONE); @@ -284,6 +299,7 @@ bool AreaTrigger::CreateServer(Map* map, AreaTriggerTemplate const* areaTriggerT SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::SpellVisual).ModifyValue(&UF::SpellCastVisual::ScriptVisualID), 0); } + SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::BoundsRadius2D), _shape.GetMaxSearchRadius()); if (IsServerSide()) SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::DecalPropertiesID), 24); // blue decal, for .debug areatrigger visibility @@ -291,9 +307,6 @@ bool AreaTrigger::CreateServer(Map* map, AreaTriggerTemplate const* areaTriggerT SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::AnimationDataID), -1); - _shape = position.Shape; - _maxSearchRadius = _shape.GetMaxSearchRadius(); - if (position.phaseUseFlags || position.phaseId || position.phaseGroup) PhasingHandler::InitDbPhaseShift(GetPhaseShift(), position.phaseUseFlags, position.phaseId, position.phaseGroup); @@ -314,17 +327,45 @@ void AreaTrigger::Update(uint32 diff) if (!IsServerSide()) { // "If" order matter here, Orbit > Attached > Splines - if (HasOrbit()) + if (HasOverridePosition()) + { + UpdateOverridePosition(); + } + else if (HasOrbit()) { UpdateOrbitPosition(diff); } else if (GetTemplate() && GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_ATTACHED)) { if (Unit* target = GetTarget()) - GetMap()->AreaTriggerRelocation(this, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation()); + { + float orientation = 0.0f; + if (GetCreateProperties()->FacingCurveId) + orientation = sDB2Manager.GetCurveValueAt(GetCreateProperties()->FacingCurveId, GetProgress()); + + if (!GetTemplate() || !GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_ABSOLUTE_ORIENTATION)) + orientation += target->GetOrientation(); + + GetMap()->AreaTriggerRelocation(this, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), orientation); + } } - else + else if (HasSplines()) + { UpdateSplinePosition(diff); + } + else + { + if (GetCreateProperties()->FacingCurveId) + { + float orientation = sDB2Manager.GetCurveValueAt(GetCreateProperties()->FacingCurveId, GetProgress()); + if (!GetTemplate() || !GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_ABSOLUTE_ORIENTATION)) + orientation += GetStationaryO(); + + SetOrientation(orientation); + } + + UpdateShape(); + } } if (GetDuration() != -1) @@ -351,6 +392,58 @@ void AreaTrigger::Remove() } } +void AreaTrigger::SetOverrideScaleCurve(float overrideScale) +{ + SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideScaleCurve), overrideScale); +} + +void AreaTrigger::SetOverrideScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation) +{ + SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideScaleCurve), points, startTimeOffset, interpolation); +} + +void AreaTrigger::ClearOverrideScaleCurve() +{ + ClearScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideScaleCurve)); +} + +void AreaTrigger::SetExtraScaleCurve(float extraScale) +{ + SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve), extraScale); +} + +void AreaTrigger::SetExtraScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation) +{ + SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve), points, startTimeOffset, interpolation); +} + +void AreaTrigger::ClearExtraScaleCurve() +{ + ClearScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve)); +} + +void AreaTrigger::SetOverrideMoveCurve(float x, float y, float z) +{ + SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveX), x); + SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveY), y); + SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveZ), z); +} + +void AreaTrigger::SetOverrideMoveCurve(std::array<DBCPosition2D, 2> const& xCurvePoints, std::array<DBCPosition2D, 2> const& yCurvePoints, + std::array<DBCPosition2D, 2> const& zCurvePoints, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation) +{ + SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveX), xCurvePoints, startTimeOffset, interpolation); + SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveY), yCurvePoints, startTimeOffset, interpolation); + SetScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveZ), zCurvePoints, startTimeOffset, interpolation); +} + +void AreaTrigger::ClearOverrideMoveCurve() +{ + ClearScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveX)); + ClearScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveY)); + ClearScaleCurve(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::OverrideMoveCurveZ)); +} + void AreaTrigger::SetDuration(int32 newDuration) { _duration = newDuration; @@ -372,18 +465,43 @@ void AreaTrigger::_UpdateDuration(int32 newDuration) }); } +float AreaTrigger::CalcCurrentScale() const +{ + float scale = 1.0f; + if (m_areaTriggerData->OverrideScaleCurve->OverrideActive) + scale *= std::max(GetScaleCurveValue(*m_areaTriggerData->OverrideScaleCurve, m_areaTriggerData->TimeToTargetScale), 0.000001f); + else if (AreaTriggerCreateProperties const* createProperties = GetCreateProperties()) + if (createProperties->ScaleCurveId) + scale *= std::max(sDB2Manager.GetCurveValueAt(createProperties->ScaleCurveId, GetScaleCurveProgress(*m_areaTriggerData->OverrideScaleCurve, m_areaTriggerData->TimeToTargetScale)), 0.000001f); + + scale *= std::max(GetScaleCurveValue(*m_areaTriggerData->ExtraScaleCurve, m_areaTriggerData->TimeToTargetExtraScale), 0.000001f); + + return scale; +} + float AreaTrigger::GetProgress() const { - return GetTimeSinceCreated() < GetTimeToTargetScale() ? float(GetTimeSinceCreated()) / float(GetTimeToTargetScale()) : 1.0f; + if (_totalDuration <= 0) + return 1.0f; + + return std::clamp(float(GetTimeSinceCreated()) / float(GetTotalDuration()), 0.0f, 1.0f); } -float AreaTrigger::GetScaleCurveValue(UF::ScaleCurve const& scaleCurve, float x) const +float AreaTrigger::GetScaleCurveProgress(UF::ScaleCurve const& scaleCurve, uint32 timeTo) const +{ + if (!timeTo) + return 0.0f; + + return std::clamp(float(GetTimeSinceCreated() - scaleCurve.StartTimeOffset) / float(timeTo), 0.0f, 1.0f); +} + +float AreaTrigger::GetScaleCurveValueAtProgress(UF::ScaleCurve const& scaleCurve, float x) const { ASSERT(*scaleCurve.OverrideActive, "ScaleCurve must be active to evaluate it"); // unpack ParameterCurve - if (*scaleCurve.ParameterCurve & 1) - return advstd::bit_cast<float>(*scaleCurve.ParameterCurve & ~1); + if (*scaleCurve.ParameterCurve & 1u) + return advstd::bit_cast<float>(*scaleCurve.ParameterCurve & ~1u); std::array<DBCPosition2D, 2> points; for (std::size_t i = 0; i < scaleCurve.Points.size(); ++i) @@ -395,7 +513,38 @@ float AreaTrigger::GetScaleCurveValue(UF::ScaleCurve const& scaleCurve, float x) return sDB2Manager.GetCurveValueAt(mode, std::span(points.begin(), pointCount), x); } -void AreaTrigger::SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false>&& scaleCurveMutator, Optional<AreaTriggerScaleCurveTemplate> const& curve) +float AreaTrigger::GetScaleCurveValue(UF::ScaleCurve const& scaleCurve, uint32 timeTo) const +{ + return GetScaleCurveValueAtProgress(scaleCurve, GetScaleCurveProgress(scaleCurve, timeTo)); +} + +void AreaTrigger::SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false> scaleCurveMutator, float constantValue) +{ + AreaTriggerScaleCurveTemplate curveTemplate; + curveTemplate.Curve = constantValue; + SetScaleCurve(scaleCurveMutator, curveTemplate); +} + +void AreaTrigger::SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false> scaleCurveMutator, std::array<DBCPosition2D, 2> const& points, + Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation) +{ + AreaTriggerScaleCurvePointsTemplate curve; + curve.Mode = interpolation; + curve.Points = points; + + AreaTriggerScaleCurveTemplate curveTemplate; + curveTemplate.StartTimeOffset = startTimeOffset.value_or(GetTimeSinceCreated()); + curveTemplate.Curve = curve; + + SetScaleCurve(scaleCurveMutator, curveTemplate); +} + +void AreaTrigger::ClearScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false> scaleCurveMutator) +{ + SetScaleCurve(scaleCurveMutator, {}); +} + +void AreaTrigger::SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false> scaleCurveMutator, Optional<AreaTriggerScaleCurveTemplate> const& curve) { if (!curve) { @@ -491,10 +640,10 @@ void AreaTrigger::UpdateTargetList() { if (ConditionContainer const* conditions = sConditionMgr->GetConditionsForAreaTrigger(GetTemplate()->Id.Id, GetTemplate()->Id.IsServerSide)) { - targetList.erase(std::remove_if(targetList.begin(), targetList.end(), [conditions](Unit* target) + Trinity::Containers::EraseIf(targetList, [conditions](Unit const* target) { return !sConditionMgr->IsObjectMeetToConditions(target, *conditions); - }), targetList.end()); + }); } } @@ -518,106 +667,123 @@ void AreaTrigger::SearchUnits(std::vector<Unit*>& targetList, float radius, bool void AreaTrigger::SearchUnitInSphere(std::vector<Unit*>& targetList) { - float radius = _shape.SphereDatas.Radius; - if (GetTemplate() && GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_DYNAMIC_SHAPE)) - { - if (GetCreateProperties()->MorphCurveId) - { - radius = G3D::lerp(_shape.SphereDatas.Radius, - _shape.SphereDatas.RadiusTarget, - sDB2Manager.GetCurveValueAt(GetCreateProperties()->MorphCurveId, GetProgress())); - } - } + float progress = GetProgress(); + if (GetCreateProperties()->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(GetCreateProperties()->MorphCurveId, progress); + + float scale = CalcCurrentScale(); + float radius = G3D::lerp(_shape.SphereDatas.Radius, _shape.SphereDatas.RadiusTarget, progress) * scale; SearchUnits(targetList, radius, true); } void AreaTrigger::SearchUnitInBox(std::vector<Unit*>& targetList) { - SearchUnits(targetList, GetMaxSearchRadius(), false); + float progress = GetProgress(); + if (GetCreateProperties()->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(GetCreateProperties()->MorphCurveId, progress); - Position const& boxCenter = GetPosition(); - float extentsX = _shape.BoxDatas.Extents[0]; - float extentsY = _shape.BoxDatas.Extents[1]; - float extentsZ = _shape.BoxDatas.Extents[2]; + float scale = CalcCurrentScale(); + float extentsX = G3D::lerp(_shape.BoxDatas.Extents[0], _shape.BoxDatas.ExtentsTarget[0], progress) * scale; + float extentsY = G3D::lerp(_shape.BoxDatas.Extents[1], _shape.BoxDatas.ExtentsTarget[1], progress) * scale; + float extentsZ = G3D::lerp(_shape.BoxDatas.Extents[2], _shape.BoxDatas.ExtentsTarget[2], progress) * scale; + float radius = std::sqrt(extentsX * extentsX + extentsY * extentsY); + + SearchUnits(targetList, radius, false); - targetList.erase(std::remove_if(targetList.begin(), targetList.end(), [boxCenter, extentsX, extentsY, extentsZ](Unit* unit) -> bool + Position const& boxCenter = GetPosition(); + Trinity::Containers::EraseIf(targetList, [boxCenter, extentsX, extentsY, extentsZ](Unit const* unit) -> bool { - return !unit->IsWithinBox(boxCenter, extentsX, extentsY, extentsZ/2); - }), targetList.end()); + return !unit->IsWithinBox(boxCenter, extentsX, extentsY, extentsZ / 2); + }); } void AreaTrigger::SearchUnitInPolygon(std::vector<Unit*>& targetList) { - SearchUnits(targetList, GetMaxSearchRadius(), false); + float progress = GetProgress(); + if (GetCreateProperties()->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(GetCreateProperties()->MorphCurveId, progress); - float height = _shape.PolygonDatas.Height; + float height = G3D::lerp(_shape.PolygonDatas.Height, _shape.PolygonDatas.HeightTarget, progress); float minZ = GetPositionZ() - height; float maxZ = GetPositionZ() + height; - targetList.erase(std::remove_if(targetList.begin(), targetList.end(), [this, minZ, maxZ](Unit* unit) -> bool + SearchUnits(targetList, GetMaxSearchRadius(), false); + + Trinity::Containers::EraseIf(targetList, [this, minZ, maxZ](Unit const* unit) -> bool { - return !CheckIsInPolygon2D(unit) - || unit->GetPositionZ() < minZ - || unit->GetPositionZ() > maxZ; - }), targetList.end()); + return unit->GetPositionZ() < minZ + || unit->GetPositionZ() > maxZ + || !CheckIsInPolygon2D(unit); + }); } void AreaTrigger::SearchUnitInCylinder(std::vector<Unit*>& targetList) { - SearchUnits(targetList, GetMaxSearchRadius(), false); + float progress = GetProgress(); + if (GetCreateProperties()->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(GetCreateProperties()->MorphCurveId, progress); + + float scale = CalcCurrentScale(); + float radius = G3D::lerp(_shape.CylinderDatas.Radius, _shape.CylinderDatas.RadiusTarget, progress) * scale; + float height = G3D::lerp(_shape.CylinderDatas.Height, _shape.CylinderDatas.HeightTarget, progress); + if (!m_areaTriggerData->HeightIgnoresScale) + height *= scale; - float height = _shape.CylinderDatas.Height; float minZ = GetPositionZ() - height; float maxZ = GetPositionZ() + height; - targetList.erase(std::remove_if(targetList.begin(), targetList.end(), [minZ, maxZ](Unit* unit) -> bool + SearchUnits(targetList, radius, false); + + Trinity::Containers::EraseIf(targetList, [minZ, maxZ](Unit const* unit) -> bool { return unit->GetPositionZ() < minZ || unit->GetPositionZ() > maxZ; - }), targetList.end()); + }); } void AreaTrigger::SearchUnitInDisk(std::vector<Unit*>& targetList) { - float innerRadius = _shape.DiskDatas.InnerRadius; - float outerRadius = _shape.DiskDatas.OuterRadius; - float height = _shape.DiskDatas.Height; - - if (GetTemplate() && GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_DYNAMIC_SHAPE)) - { - float progress = GetProgress(); - if (GetCreateProperties()->MorphCurveId) - progress = sDB2Manager.GetCurveValueAt(GetCreateProperties()->MorphCurveId, progress); + float progress = GetProgress(); + if (GetCreateProperties()->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(GetCreateProperties()->MorphCurveId, progress); - innerRadius = G3D::lerp(_shape.DiskDatas.InnerRadius, _shape.DiskDatas.InnerRadiusTarget, progress); - outerRadius = G3D::lerp(_shape.DiskDatas.OuterRadius, _shape.DiskDatas.OuterRadiusTarget, progress); - height = G3D::lerp(_shape.DiskDatas.Height, _shape.DiskDatas.HeightTarget, progress); - } - - SearchUnits(targetList, outerRadius, false); + float scale = CalcCurrentScale(); + float innerRadius = G3D::lerp(_shape.DiskDatas.InnerRadius, _shape.DiskDatas.InnerRadiusTarget, progress) * scale; + float outerRadius = G3D::lerp(_shape.DiskDatas.OuterRadius, _shape.DiskDatas.OuterRadiusTarget, progress) * scale; + float height = G3D::lerp(_shape.DiskDatas.Height, _shape.DiskDatas.HeightTarget, progress); + if (!m_areaTriggerData->HeightIgnoresScale) + height *= scale; float minZ = GetPositionZ() - height; float maxZ = GetPositionZ() + height; - targetList.erase(std::remove_if(targetList.begin(), targetList.end(), [this, innerRadius, minZ, maxZ](Unit const* unit) -> bool + SearchUnits(targetList, outerRadius, false); + + Trinity::Containers::EraseIf(targetList, [this, innerRadius, minZ, maxZ](Unit const* unit) -> bool { return unit->IsInDist2d(this, innerRadius) || unit->GetPositionZ() < minZ || unit->GetPositionZ() > maxZ; - }), targetList.end()); + }); } void AreaTrigger::SearchUnitInBoundedPlane(std::vector<Unit*>& targetList) { - SearchUnits(targetList, GetMaxSearchRadius(), false); + float progress = GetProgress(); + if (GetCreateProperties()->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(GetCreateProperties()->MorphCurveId, progress); - Position const& boxCenter = GetPosition(); - float extentsX = _shape.BoxDatas.Extents[0]; - float extentsY = _shape.BoxDatas.Extents[1]; + float scale = CalcCurrentScale(); + float extentsX = G3D::lerp(_shape.BoundedPlaneDatas.Extents[0], _shape.BoundedPlaneDatas.ExtentsTarget[0], progress) * scale; + float extentsY = G3D::lerp(_shape.BoundedPlaneDatas.Extents[1], _shape.BoundedPlaneDatas.ExtentsTarget[1], progress) * scale; + float radius = std::sqrt(extentsX * extentsX + extentsY * extentsY); - targetList.erase(std::remove_if(targetList.begin(), targetList.end(), [boxCenter, extentsX, extentsY](Unit const* unit) -> bool + SearchUnits(targetList, radius, false); + + Position const& boxCenter = GetPosition(); + Trinity::Containers::EraseIf(targetList, [boxCenter, extentsX, extentsY](Unit const* unit) -> bool { return !unit->IsWithinBox(boxCenter, extentsX, extentsY, MAP_SIZE); - }), targetList.end()); + }); } void AreaTrigger::HandleUnitEnterExit(std::vector<Unit*> const& newTargetList) @@ -707,15 +873,35 @@ uint32 AreaTrigger::GetFaction() const return 0; } -void AreaTrigger::UpdatePolygonOrientation() +float AreaTrigger::GetMaxSearchRadius() const +{ + return *m_areaTriggerData->BoundsRadius2D * CalcCurrentScale(); +} + +void AreaTrigger::UpdatePolygonVertices() { float newOrientation = GetOrientation(); // No need to recalculate, orientation didn't change - if (G3D::fuzzyEq(_previousCheckOrientation, newOrientation)) + if (G3D::fuzzyEq(_verticesUpdatePreviousOrientation, newOrientation) && GetCreateProperties()->PolygonVerticesTarget.empty()) return; _polygonVertices.assign(GetCreateProperties()->PolygonVertices.begin(), GetCreateProperties()->PolygonVertices.end()); + if (!GetCreateProperties()->PolygonVerticesTarget.empty()) + { + float progress = GetProgress(); + if (GetCreateProperties()->MorphCurveId) + progress = sDB2Manager.GetCurveValueAt(GetCreateProperties()->MorphCurveId, progress); + + for (std::size_t i = 0; i < _polygonVertices.size(); ++i) + { + Position& vertex = _polygonVertices[i]; + Position const& vertexTarget = GetCreateProperties()->PolygonVerticesTarget[i].Pos; + + vertex.m_positionX = G3D::lerp(vertex.GetPositionX(), vertexTarget.GetPositionX(), progress); + vertex.m_positionY = G3D::lerp(vertex.GetPositionY(), vertexTarget.GetPositionY(), progress); + } + } float angleSin = std::sin(newOrientation); float angleCos = std::cos(newOrientation); @@ -728,7 +914,7 @@ void AreaTrigger::UpdatePolygonOrientation() vertice.Relocate(x, y); } - _previousCheckOrientation = newOrientation; + _verticesUpdatePreviousOrientation = newOrientation; } bool AreaTrigger::CheckIsInPolygon2D(Position const* pos) const @@ -800,10 +986,17 @@ bool AreaTrigger::CheckIsInPolygon2D(Position const* pos) const return locatedInPolygon; } +bool AreaTrigger::HasOverridePosition() const +{ + return m_areaTriggerData->OverrideMoveCurveX->OverrideActive + && m_areaTriggerData->OverrideMoveCurveY->OverrideActive + && m_areaTriggerData->OverrideMoveCurveZ->OverrideActive; +} + void AreaTrigger::UpdateShape() { if (_shape.IsPolygon()) - UpdatePolygonOrientation(); + UpdatePolygonVertices(); } bool UnitFitToActionRequirement(Unit* unit, Unit* caster, AreaTriggerAction const& action) @@ -1017,6 +1210,8 @@ Position AreaTrigger::CalculateOrbitPosition() const // AreaTrigger make exactly "Duration / TimeToTarget" loops during his life time float pathProgress = float(cmi.ElapsedTimeForMovement) / float(cmi.TimeToTarget); + if (GetCreateProperties()->MoveCurveId) + pathProgress = sDB2Manager.GetCurveValueAt(GetCreateProperties()->MoveCurveId, pathProgress); // We already made one circle and can't loop if (!cmi.CanLoop) @@ -1041,7 +1236,17 @@ Position AreaTrigger::CalculateOrbitPosition() const float y = centerPos->GetPositionY() + (radius * std::sin(angle)); float z = centerPos->GetPositionZ() + cmi.ZOffset; - return { x, y, z, angle }; + float orientation = 0.0f; + if (GetCreateProperties()->FacingCurveId) + orientation = sDB2Manager.GetCurveValueAt(GetCreateProperties()->FacingCurveId, GetProgress()); + + if (!GetTemplate() || !GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_ABSOLUTE_ORIENTATION)) + { + orientation += angle; + orientation += cmi.CounterClockwise ? float(M_PI_4) : -float(M_PI_4); + } + + return { x, y, z, orientation }; } void AreaTrigger::UpdateOrbitPosition(uint32 /*diff*/) @@ -1064,9 +1269,6 @@ void AreaTrigger::UpdateSplinePosition(uint32 diff) if (_reachedDestination) return; - if (!HasSplines()) - return; - _movementTime += diff; if (_movementTime >= GetTimeToTarget()) @@ -1096,7 +1298,7 @@ void AreaTrigger::UpdateSplinePosition(uint32 diff) if (progress < 0.f || progress > 1.f) { TC_LOG_ERROR("entities.areatrigger", "AreaTrigger (Id: {}, AreaTriggerCreatePropertiesId: {}) has wrong progress ({}) caused by curve calculation (MoveCurveId: {})", - GetEntry(), GetCreateProperties()->Id, progress, GetCreateProperties()->MorphCurveId); + GetEntry(), GetCreateProperties()->Id, progress, GetCreateProperties()->MoveCurveId); } else currentTimePercent = progress; @@ -1109,11 +1311,16 @@ void AreaTrigger::UpdateSplinePosition(uint32 diff) G3D::Vector3 currentPosition; _spline->evaluate_percent(lastPositionIndex, percentFromLastPoint, currentPosition); - float orientation = GetOrientation(); - if (GetTemplate() && GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_FACE_MOVEMENT_DIR)) + float orientation = GetStationaryO(); + if (GetCreateProperties()->FacingCurveId) + orientation += sDB2Manager.GetCurveValueAt(GetCreateProperties()->FacingCurveId, GetProgress()); + + if (GetTemplate() && !GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_ABSOLUTE_ORIENTATION) && GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_FACE_MOVEMENT_DIR)) { - G3D::Vector3 const& nextPoint = _spline->getPoint(lastPositionIndex + 1); - orientation = GetAbsoluteAngle(nextPoint.x, nextPoint.y); + G3D::Vector3 derivative; + _spline->evaluate_derivative(lastPositionIndex, percentFromLastPoint, derivative); + if (derivative.x != 0.0f || derivative.y != 0.0f) + orientation += std::atan2(derivative.y, derivative.x); } GetMap()->AreaTriggerRelocation(this, currentPosition.x, currentPosition.y, currentPosition.z, orientation); @@ -1128,6 +1335,25 @@ void AreaTrigger::UpdateSplinePosition(uint32 diff) } } +void AreaTrigger::UpdateOverridePosition() +{ + float progress = GetScaleCurveProgress(*m_areaTriggerData->OverrideMoveCurveX, m_areaTriggerData->TimeToTargetPos); + + float x = GetScaleCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveX, progress); + float y = GetScaleCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveY, progress); + float z = GetScaleCurveValueAtProgress(*m_areaTriggerData->OverrideMoveCurveZ, progress); + float orientation = GetOrientation(); + + if (GetCreateProperties()->FacingCurveId) + { + orientation = sDB2Manager.GetCurveValueAt(GetCreateProperties()->FacingCurveId, GetProgress()); + if (!GetTemplate() || !GetTemplate()->HasFlag(AREATRIGGER_FLAG_HAS_ABSOLUTE_ORIENTATION)) + orientation += GetStationaryO(); + } + + GetMap()->AreaTriggerRelocation(this, x, y, z, orientation); +} + void AreaTrigger::DebugVisualizePosition() { if (Unit* caster = GetCaster()) diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.h b/src/server/game/Entities/AreaTrigger/AreaTrigger.h index ccb83e22c4f..b6bc632c417 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.h +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.h @@ -77,12 +77,18 @@ class TC_GAME_API AreaTrigger : public WorldObject, public GridObject<AreaTrigge bool IsNeverVisibleFor(WorldObject const* seer, bool allowServersideObjects = false) const override; + float GetStationaryX() const override { return _stationaryPosition.GetPositionX(); } + float GetStationaryY() const override { return _stationaryPosition.GetPositionY(); } + float GetStationaryZ() const override { return _stationaryPosition.GetPositionZ(); } + float GetStationaryO() const override { return _stationaryPosition.GetOrientation(); } + void RelocateStationaryPosition(Position const& pos) { _stationaryPosition.Relocate(pos); } + private: - bool Create(uint32 areaTriggerCreatePropertiesId, Unit* caster, Unit* target, SpellInfo const* spellInfo, Position const& pos, int32 duration, SpellCastVisual spellVisual, Spell const* spell, AuraEffect const* aurEff); + bool Create(uint32 areaTriggerCreatePropertiesId, Unit* caster, Unit* target, SpellInfo const* spellInfo, Position const& pos, int32 duration, SpellCastVisual spellVisual, Spell* spell, AuraEffect const* aurEff); bool CreateServer(Map* map, AreaTriggerTemplate const* areaTriggerTemplate, AreaTriggerSpawn const& position); public: - static AreaTrigger* CreateAreaTrigger(uint32 areaTriggerCreatePropertiesId, Unit* caster, Unit* target, SpellInfo const* spellInfo, Position const& pos, int32 duration, SpellCastVisual spellVisual, Spell const* spell = nullptr, AuraEffect const* aurEff = nullptr); + static AreaTrigger* CreateAreaTrigger(uint32 areaTriggerCreatePropertiesId, Unit* caster, Unit* target, SpellInfo const* spellInfo, Position const& pos, int32 duration, SpellCastVisual spellVisual, Spell* spell = nullptr, AuraEffect const* aurEff = nullptr); static ObjectGuid CreateNewMovementForceId(Map* map, uint32 areaTriggerId); bool LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap, bool allowDuplicate); @@ -92,8 +98,34 @@ class TC_GAME_API AreaTrigger : public WorldObject, public GridObject<AreaTrigge uint32 GetSpellId() const { return m_areaTriggerData->SpellID; } AuraEffect const* GetAuraEffect() const { return _aurEff; } uint32 GetTimeSinceCreated() const { return _timeSinceCreated; } + + void SetHeightIgnoresScale(bool heightIgnoresScale) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::HeightIgnoresScale), heightIgnoresScale); } + + void SetOverrideScaleCurve(float overrideScale); + void SetOverrideScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset = {}, CurveInterpolationMode interpolation = CurveInterpolationMode::Linear); + void ClearOverrideScaleCurve(); + + void SetExtraScaleCurve(float extraScale); + void SetExtraScaleCurve(std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset = {}, CurveInterpolationMode interpolation = CurveInterpolationMode::Linear); + void ClearExtraScaleCurve(); + + void SetOverrideMoveCurve(float x, float y, float z); + void SetOverrideMoveCurve(std::array<DBCPosition2D, 2> const& xCurvePoints, std::array<DBCPosition2D, 2> const& yCurvePoints, std::array<DBCPosition2D, 2> const& zCurvePoints, + Optional<uint32> startTimeOffset = {}, CurveInterpolationMode interpolation = CurveInterpolationMode::Linear); + void ClearOverrideMoveCurve(); + uint32 GetTimeToTarget() const { return m_areaTriggerData->TimeToTarget; } + void SetTimeToTarget(uint32 timeToTarget) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::TimeToTarget), timeToTarget); } + uint32 GetTimeToTargetScale() const { return m_areaTriggerData->TimeToTargetScale; } + void SetTimeToTargetScale(uint32 timeToTargetScale) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::TimeToTargetScale), timeToTargetScale); } + + uint32 GetTimeToTargetExtraScale() const { return m_areaTriggerData->TimeToTargetExtraScale; } + void SetTimeToTargetExtraScale(uint32 timeToTargetExtraScale) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::TimeToTargetExtraScale), timeToTargetExtraScale); } + + uint32 GetTimeToTargetPos() const { return m_areaTriggerData->TimeToTargetPos; } + void SetTimeToTargetPos(uint32 timeToTargetPos) { SetUpdateFieldValue(m_values.ModifyValue(&AreaTrigger::m_areaTriggerData).ModifyValue(&UF::AreaTriggerData::TimeToTargetPos), timeToTargetPos); } + int32 GetDuration() const { return _duration; } int32 GetTotalDuration() const { return _totalDuration; } void SetDuration(int32 newDuration); @@ -113,7 +145,7 @@ class TC_GAME_API AreaTrigger : public WorldObject, public GridObject<AreaTrigge uint32 GetFaction() const override; AreaTriggerShapeInfo const& GetShape() const { return _shape; } - float GetMaxSearchRadius() const { return _maxSearchRadius; } + float GetMaxSearchRadius() const; Position const& GetRollPitchYaw() const { return _rollPitchYaw; } Position const& GetTargetRollPitchYaw() const { return _targetRollPitchYaw; } void InitSplineOffsets(std::vector<Position> const& offsets, uint32 timeToTarget); @@ -124,7 +156,9 @@ class TC_GAME_API AreaTrigger : public WorldObject, public GridObject<AreaTrigge void InitOrbit(AreaTriggerOrbitInfo const& orbit, uint32 timeToTarget); bool HasOrbit() const; - Optional<AreaTriggerOrbitInfo> const& GetCircularMovementInfo() const { return _orbitInfo; } + Optional<AreaTriggerOrbitInfo> const& GetOrbit() const { return _orbitInfo; } + + bool HasOverridePosition() const; void UpdateShape(); @@ -132,10 +166,18 @@ class TC_GAME_API AreaTrigger : public WorldObject, public GridObject<AreaTrigge protected: void _UpdateDuration(int32 newDuration); + + float CalcCurrentScale() const; + float GetProgress() const; - float GetScaleCurveValue(UF::ScaleCurve const& scaleCurve, float x) const; - void SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false>&& scaleCurveMutator, Optional<AreaTriggerScaleCurveTemplate> const& curve); + float GetScaleCurveProgress(UF::ScaleCurve const& scaleCurve, uint32 timeTo) const; + float GetScaleCurveValueAtProgress(UF::ScaleCurve const& scaleCurve, float x) const; + float GetScaleCurveValue(UF::ScaleCurve const& scaleCurve, uint32 timeTo) const; + void SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false> scaleCurveMutator, float constantValue); + void SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false> scaleCurveMutator, std::array<DBCPosition2D, 2> const& points, Optional<uint32> startTimeOffset, CurveInterpolationMode interpolation); + void ClearScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false> scaleCurveMutator); + void SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false> scaleCurveMutator, Optional<AreaTriggerScaleCurveTemplate> const& curve); void UpdateTargetList(); void SearchUnits(std::vector<Unit*>& targetList, float radius, bool check3D); @@ -151,9 +193,10 @@ class TC_GAME_API AreaTrigger : public WorldObject, public GridObject<AreaTrigge void DoActions(Unit* unit); void UndoActions(Unit* unit); - void UpdatePolygonOrientation(); + void UpdatePolygonVertices(); void UpdateOrbitPosition(uint32 diff); void UpdateSplinePosition(uint32 diff); + void UpdateOverridePosition(); Position const* GetOrbitCenterPosition() const; Position CalculateOrbitPosition() const; @@ -166,12 +209,12 @@ class TC_GAME_API AreaTrigger : public WorldObject, public GridObject<AreaTrigge AuraEffect const* _aurEff; + Position _stationaryPosition; AreaTriggerShapeInfo _shape; - float _maxSearchRadius; int32 _duration; int32 _totalDuration; uint32 _timeSinceCreated; - float _previousCheckOrientation; + float _verticesUpdatePreviousOrientation; bool _isRemoved; Position _rollPitchYaw; diff --git a/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.cpp b/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.cpp index c1917919be8..906d48437f7 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.cpp @@ -42,13 +42,17 @@ float AreaTriggerShapeInfo::GetMaxSearchRadius() const case AREATRIGGER_TYPE_SPHERE: return std::max(SphereDatas.Radius, SphereDatas.RadiusTarget); case AREATRIGGER_TYPE_BOX: - return std::sqrt(BoxDatas.Extents[0] * BoxDatas.Extents[0] + BoxDatas.Extents[1] * BoxDatas.Extents[1]); + return std::sqrt(std::max( + BoxDatas.Extents[0] * BoxDatas.Extents[0] + BoxDatas.Extents[1] * BoxDatas.Extents[1], + BoxDatas.ExtentsTarget[0] * BoxDatas.ExtentsTarget[0] + BoxDatas.ExtentsTarget[1] * BoxDatas.ExtentsTarget[1])); case AREATRIGGER_TYPE_CYLINDER: return std::max(CylinderDatas.Radius, CylinderDatas.RadiusTarget); case AREATRIGGER_TYPE_DISK: return std::max(DiskDatas.OuterRadius, DiskDatas.OuterRadiusTarget); case AREATRIGGER_TYPE_BOUNDED_PLANE: - return std::sqrt(BoundedPlaneDatas.Extents[0] * BoundedPlaneDatas.Extents[0] / 4 + BoundedPlaneDatas.Extents[1] * BoundedPlaneDatas.Extents[1] / 4); + return std::sqrt(std::max( + BoundedPlaneDatas.Extents[0] * BoundedPlaneDatas.Extents[0] / 4 + BoundedPlaneDatas.Extents[1] * BoundedPlaneDatas.Extents[1] / 4, + BoundedPlaneDatas.ExtentsTarget[0] * BoundedPlaneDatas.ExtentsTarget[0] / 4 + BoundedPlaneDatas.ExtentsTarget[1] * BoundedPlaneDatas.ExtentsTarget[1] / 4)); default: break; } @@ -102,13 +106,11 @@ float AreaTriggerCreateProperties::GetMaxSearchRadius() const Position center(0.0f, 0.0f); float maxSearchRadius = 0.0f; - for (TaggedPosition<Position::XY> const& vertice : PolygonVertices) - { - float pointDist = center.GetExactDist2d(vertice); + for (TaggedPosition<Position::XY> const& vertex : PolygonVertices) + maxSearchRadius = std::max(maxSearchRadius, center.GetExactDist2d(vertex)); - if (pointDist > maxSearchRadius) - maxSearchRadius = pointDist; - } + for (TaggedPosition<Position::XY> const& vertex : PolygonVerticesTarget) + maxSearchRadius = std::max(maxSearchRadius, center.GetExactDist2d(vertex)); return maxSearchRadius; } diff --git a/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h b/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h index ac1a68aa1a6..735a6413e48 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h +++ b/src/server/game/Entities/AreaTrigger/AreaTriggerTemplate.h @@ -30,7 +30,7 @@ enum AreaTriggerFlags { - AREATRIGGER_FLAG_HAS_ABSOLUTE_ORIENTATION = 0x00001, // NYI + AREATRIGGER_FLAG_HAS_ABSOLUTE_ORIENTATION = 0x00001, AREATRIGGER_FLAG_HAS_DYNAMIC_SHAPE = 0x00002, // Implemented for Spheres & Disks AREATRIGGER_FLAG_HAS_ATTACHED = 0x00004, AREATRIGGER_FLAG_HAS_FACE_MOVEMENT_DIR = 0x00008, diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 39b83cf62a1..3678284124f 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -579,7 +579,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, CreateObjectBits flags, Playe // *data << *areaTrigger->GetMovementScript(); // AreaTriggerMovementScriptInfo if (hasOrbit) - *data << *areaTrigger->GetCircularMovementInfo(); + *data << *areaTrigger->GetOrbit(); } if (flags.GameObject) diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d68fc26cf3a..90e3e7816c4 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -409,6 +409,7 @@ Unit::~Unit() ASSERT(m_removedAuras.empty()); ASSERT(m_gameObj.empty()); ASSERT(m_dynObj.empty()); + ASSERT(m_areaTrigger.empty()); ASSERT(!m_unitMovedByMe || (m_unitMovedByMe == this)); ASSERT(!m_playerMovingMe || (m_playerMovingMe == this)); } @@ -5244,7 +5245,7 @@ void Unit::_RegisterAreaTrigger(AreaTrigger* areaTrigger) void Unit::_UnregisterAreaTrigger(AreaTrigger* areaTrigger) { - m_areaTrigger.erase(std::remove(m_areaTrigger.begin(), m_areaTrigger.end(), areaTrigger)); + std::erase(m_areaTrigger, areaTrigger); if (GetTypeId() == TYPEID_UNIT && IsAIEnabled()) ToCreature()->AI()->JustUnregisteredAreaTrigger(areaTrigger); } @@ -5267,8 +5268,6 @@ std::vector<AreaTrigger*> Unit::GetAreaTriggers(uint32 spellId) const void Unit::RemoveAreaTrigger(uint32 spellId) { - if (m_areaTrigger.empty()) - return; for (AreaTriggerList::iterator i = m_areaTrigger.begin(); i != m_areaTrigger.end();) { AreaTrigger* areaTrigger = *i; @@ -5284,8 +5283,6 @@ void Unit::RemoveAreaTrigger(uint32 spellId) void Unit::RemoveAreaTrigger(AuraEffect const* aurEff) { - if (m_areaTrigger.empty()) - return; for (AreaTrigger* areaTrigger : m_areaTrigger) { if (areaTrigger->GetAuraEffect() == aurEff) @@ -5299,7 +5296,7 @@ void Unit::RemoveAreaTrigger(AuraEffect const* aurEff) void Unit::RemoveAllAreaTriggers() { while (!m_areaTrigger.empty()) - m_areaTrigger.front()->Remove(); + m_areaTrigger.back()->Remove(); } void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const* log) diff --git a/src/server/game/Globals/AreaTriggerDataStore.cpp b/src/server/game/Globals/AreaTriggerDataStore.cpp index b1cf3db98cd..3cb2943229a 100644 --- a/src/server/game/Globals/AreaTriggerDataStore.cpp +++ b/src/server/game/Globals/AreaTriggerDataStore.cpp @@ -238,6 +238,13 @@ void AreaTriggerDataStore::LoadAreaTriggerTemplates() createProperties.PolygonVertices = std::move(verticesByCreateProperties[createProperties.Id]); createProperties.PolygonVerticesTarget = std::move(verticesTargetByCreateProperties[createProperties.Id]); + if (!createProperties.PolygonVerticesTarget.empty() && createProperties.PolygonVertices.size() != createProperties.PolygonVerticesTarget.size()) + { + TC_LOG_ERROR("sql.sql", "Table `areatrigger_create_properties_polygon_vertex` has invalid target vertices, either all or none vertices must have a corresponding target vertex (AreaTriggerCreatePropertiesId: {}).", + createProperties.Id); + createProperties.PolygonVerticesTarget.clear(); + } + createProperties.SplinePoints = std::move(splinesByCreateProperties[createProperties.Id]); _areaTriggerCreateProperties[createProperties.Id] = createProperties; |