Core/AreaTriggers: Update areatrigger scalecurve handling with latest research

This commit is contained in:
Shauren
2023-07-17 19:52:25 +02:00
parent 38440996ee
commit 361fe56bc8
7 changed files with 185 additions and 118 deletions

View File

@@ -386,7 +386,7 @@ typedef std::unordered_map<uint32, std::vector<ArtifactPowerEntry const*>> Artif
typedef std::unordered_map<uint32, std::vector<uint32>> ArtifactPowerLinksContainer;
typedef std::unordered_map<std::pair<uint32, uint8>, ArtifactPowerRankEntry const*> ArtifactPowerRanksContainer;
typedef ChrSpecializationEntry const* ChrSpecializationByIndexContainer[MAX_CLASSES + 1][MAX_SPECIALIZATIONS];
typedef std::unordered_map<uint32 /*curveID*/, std::vector<CurvePointEntry const*>> CurvePointsContainer;
typedef std::unordered_map<uint32 /*curveID*/, std::vector<DBCPosition2D>> CurvePointsContainer;
typedef std::map<std::tuple<uint32, uint8, uint8, uint8>, EmotesTextSoundEntry const*> EmotesTextSoundContainer;
typedef std::unordered_map<uint32, std::vector<uint32>> FactionTeamContainer;
typedef std::unordered_map<uint32, HeirloomEntry const*> HeirloomItemsContainer;
@@ -1205,12 +1205,20 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul
for (CurrencyContainerEntry const* currencyContainer : sCurrencyContainerStore)
_currencyContainers.emplace(currencyContainer->CurrencyTypesID, currencyContainer);
for (CurvePointEntry const* curvePoint : sCurvePointStore)
if (sCurveStore.LookupEntry(curvePoint->CurveID))
_curvePoints[curvePoint->CurveID].push_back(curvePoint);
{
std::unordered_map<uint32 /*curveID*/, std::vector<CurvePointEntry const*>> unsortedPoints;
for (CurvePointEntry const* curvePoint : sCurvePointStore)
if (sCurveStore.LookupEntry(curvePoint->CurveID))
unsortedPoints[curvePoint->CurveID].push_back(curvePoint);
for (auto itr = _curvePoints.begin(); itr != _curvePoints.end(); ++itr)
std::sort(itr->second.begin(), itr->second.end(), [](CurvePointEntry const* point1, CurvePointEntry const* point2) { return point1->OrderIndex < point2->OrderIndex; });
for (auto& [curveId, curvePoints] : unsortedPoints)
{
std::sort(curvePoints.begin(), curvePoints.end(), [](CurvePointEntry const* point1, CurvePointEntry const* point2) { return point1->OrderIndex < point2->OrderIndex; });
std::vector<DBCPosition2D>& points = _curvePoints[curveId];
points.resize(curvePoints.size());
std::transform(curvePoints.begin(), curvePoints.end(), points.begin(), [](CurvePointEntry const* point) { return point->Pos; });
}
}
for (EmotesTextSoundEntry const* emoteTextSound : sEmotesTextSoundStore)
_emoteTextSounds[EmotesTextSoundContainer::key_type(emoteTextSound->EmotesTextID, emoteTextSound->RaceID, emoteTextSound->SexID, emoteTextSound->ClassID)] = emoteTextSound;
@@ -2126,24 +2134,13 @@ CurrencyContainerEntry const* DB2Manager::GetCurrencyContainerForCurrencyQuantit
std::pair<float, float> DB2Manager::GetCurveXAxisRange(uint32 curveId) const
{
if (std::vector<CurvePointEntry const*> const* points = Trinity::Containers::MapGetValuePtr(_curvePoints, curveId))
return { points->front()->Pos.X, points->back()->Pos.X };
if (std::vector<DBCPosition2D> const* points = Trinity::Containers::MapGetValuePtr(_curvePoints, curveId))
return { points->front().X, points->back().X };
return { 0.0f, 0.0f };
}
enum class CurveInterpolationMode : uint8
{
Linear = 0,
Cosine = 1,
CatmullRom = 2,
Bezier3 = 3,
Bezier4 = 4,
Bezier = 5,
Constant = 6,
};
static CurveInterpolationMode DetermineCurveType(CurveEntry const* curve, std::vector<CurvePointEntry const*> const& points)
static CurveInterpolationMode DetermineCurveType(CurveEntry const* curve, std::vector<DBCPosition2D> const& points)
{
switch (curve->Type)
{
@@ -2182,91 +2179,96 @@ float DB2Manager::GetCurveValueAt(uint32 curveId, float x) const
return 0.0f;
CurveEntry const* curve = sCurveStore.AssertEntry(curveId);
std::vector<CurvePointEntry const*> const& points = itr->second;
std::vector<DBCPosition2D> const& points = itr->second;
if (points.empty())
return 0.0f;
switch (DetermineCurveType(curve, points))
return GetCurveValueAt(DetermineCurveType(curve, points), points, x);
}
float DB2Manager::GetCurveValueAt(CurveInterpolationMode mode, std::span<DBCPosition2D const> points, float x) const
{
switch (mode)
{
case CurveInterpolationMode::Linear:
{
std::size_t pointIndex = 0;
while (pointIndex < points.size() && points[pointIndex]->Pos.X <= x)
while (pointIndex < points.size() && points[pointIndex].X <= x)
++pointIndex;
if (!pointIndex)
return points[0]->Pos.Y;
return points[0].Y;
if (pointIndex >= points.size())
return points.back()->Pos.Y;
float xDiff = points[pointIndex]->Pos.X - points[pointIndex - 1]->Pos.X;
return points.back().Y;
float xDiff = points[pointIndex].X - points[pointIndex - 1].X;
if (xDiff == 0.0)
return points[pointIndex]->Pos.Y;
return (((x - points[pointIndex - 1]->Pos.X) / xDiff) * (points[pointIndex]->Pos.Y - points[pointIndex - 1]->Pos.Y)) + points[pointIndex - 1]->Pos.Y;
return points[pointIndex].Y;
return (((x - points[pointIndex - 1].X) / xDiff) * (points[pointIndex].Y - points[pointIndex - 1].Y)) + points[pointIndex - 1].Y;
}
case CurveInterpolationMode::Cosine:
{
std::size_t pointIndex = 0;
while (pointIndex < points.size() && points[pointIndex]->Pos.X <= x)
while (pointIndex < points.size() && points[pointIndex].X <= x)
++pointIndex;
if (!pointIndex)
return points[0]->Pos.Y;
return points[0].Y;
if (pointIndex >= points.size())
return points.back()->Pos.Y;
float xDiff = points[pointIndex]->Pos.X - points[pointIndex - 1]->Pos.X;
return points.back().Y;
float xDiff = points[pointIndex].X - points[pointIndex - 1].X;
if (xDiff == 0.0)
return points[pointIndex]->Pos.Y;
return ((points[pointIndex]->Pos.Y - points[pointIndex - 1]->Pos.Y) * (1.0f - std::cos((x - points[pointIndex - 1]->Pos.X) / xDiff * float(M_PI))) * 0.5f) + points[pointIndex - 1]->Pos.Y;
return points[pointIndex].Y;
return ((points[pointIndex].Y - points[pointIndex - 1].Y) * (1.0f - std::cos((x - points[pointIndex - 1].X) / xDiff * float(M_PI))) * 0.5f) + points[pointIndex - 1].Y;
}
case CurveInterpolationMode::CatmullRom:
{
std::size_t pointIndex = 1;
while (pointIndex < points.size() && points[pointIndex]->Pos.X <= x)
while (pointIndex < points.size() && points[pointIndex].X <= x)
++pointIndex;
if (pointIndex == 1)
return points[1]->Pos.Y;
return points[1].Y;
if (pointIndex >= points.size() - 1)
return points[points.size() - 2]->Pos.Y;
float xDiff = points[pointIndex]->Pos.X - points[pointIndex - 1]->Pos.X;
return points[points.size() - 2].Y;
float xDiff = points[pointIndex].X - points[pointIndex - 1].X;
if (xDiff == 0.0)
return points[pointIndex]->Pos.Y;
return points[pointIndex].Y;
float mu = (x - points[pointIndex - 1]->Pos.X) / xDiff;
float a0 = -0.5f * points[pointIndex - 2]->Pos.Y + 1.5f * points[pointIndex - 1]->Pos.Y - 1.5f * points[pointIndex]->Pos.Y + 0.5f * points[pointIndex + 1]->Pos.Y;
float a1 = points[pointIndex - 2]->Pos.Y - 2.5f * points[pointIndex - 1]->Pos.Y + 2.0f * points[pointIndex]->Pos.Y - 0.5f * points[pointIndex + 1]->Pos.Y;
float a2 = -0.5f * points[pointIndex - 2]->Pos.Y + 0.5f * points[pointIndex]->Pos.Y;
float a3 = points[pointIndex - 1]->Pos.Y;
float mu = (x - points[pointIndex - 1].X) / xDiff;
float a0 = -0.5f * points[pointIndex - 2].Y + 1.5f * points[pointIndex - 1].Y - 1.5f * points[pointIndex].Y + 0.5f * points[pointIndex + 1].Y;
float a1 = points[pointIndex - 2].Y - 2.5f * points[pointIndex - 1].Y + 2.0f * points[pointIndex].Y - 0.5f * points[pointIndex + 1].Y;
float a2 = -0.5f * points[pointIndex - 2].Y + 0.5f * points[pointIndex].Y;
float a3 = points[pointIndex - 1].Y;
return a0 * mu * mu * mu + a1 * mu * mu + a2 * mu + a3;
}
case CurveInterpolationMode::Bezier3:
{
float xDiff = points[2]->Pos.X - points[0]->Pos.X;
float xDiff = points[2].X - points[0].X;
if (xDiff == 0.0)
return points[1]->Pos.Y;
float mu = (x - points[0]->Pos.X) / xDiff;
return ((1.0f - mu) * (1.0f - mu) * points[0]->Pos.Y) + (1.0f - mu) * 2.0f * mu * points[1]->Pos.Y + mu * mu * points[2]->Pos.Y;
return points[1].Y;
float mu = (x - points[0].X) / xDiff;
return ((1.0f - mu) * (1.0f - mu) * points[0].Y) + (1.0f - mu) * 2.0f * mu * points[1].Y + mu * mu * points[2].Y;
}
case CurveInterpolationMode::Bezier4:
{
float xDiff = points[3]->Pos.X - points[0]->Pos.X;
float xDiff = points[3].X - points[0].X;
if (xDiff == 0.0)
return points[1]->Pos.Y;
float mu = (x - points[0]->Pos.X) / xDiff;
return (1.0f - mu) * (1.0f - mu) * (1.0f - mu) * points[0]->Pos.Y
+ 3.0f * mu * (1.0f - mu) * (1.0f - mu) * points[1]->Pos.Y
+ 3.0f * mu * mu * (1.0f - mu) * points[2]->Pos.Y
+ mu * mu * mu * points[3]->Pos.Y;
return points[1].Y;
float mu = (x - points[0].X) / xDiff;
return (1.0f - mu) * (1.0f - mu) * (1.0f - mu) * points[0].Y
+ 3.0f * mu * (1.0f - mu) * (1.0f - mu) * points[1].Y
+ 3.0f * mu * mu * (1.0f - mu) * points[2].Y
+ mu * mu * mu * points[3].Y;
}
case CurveInterpolationMode::Bezier:
{
float xDiff = points.back()->Pos.X - points[0]->Pos.X;
float xDiff = points.back().X - points[0].X;
if (xDiff == 0.0f)
return points.back()->Pos.Y;
return points.back().Y;
std::vector<float> tmp(points.size());
for (std::size_t i = 0; i < points.size(); ++i)
tmp[i] = points[i]->Pos.Y;
tmp[i] = points[i].Y;
float mu = (x - points[0]->Pos.X) / xDiff;
float mu = (x - points[0].X) / xDiff;
int32 i = int32(points.size()) - 1;
while (i > 0)
{
@@ -2280,7 +2282,7 @@ float DB2Manager::GetCurveValueAt(uint32 curveId, float x) const
return tmp[0];
}
case CurveInterpolationMode::Constant:
return points[0]->Pos.Y;
return points[0].Y;
default:
break;
}

View File

@@ -25,6 +25,7 @@
#include "advstd.h"
#include <map>
#include <set>
#include <span>
#include <vector>
// temporary hack until includes are sorted out (don't want to pull in Windows.h)
@@ -439,6 +440,7 @@ public:
CurrencyContainerEntry const* GetCurrencyContainerForCurrencyQuantity(uint32 currencyId, int32 quantity) const;
std::pair<float, float> GetCurveXAxisRange(uint32 curveId) const;
float GetCurveValueAt(uint32 curveId, float x) const;
float GetCurveValueAt(CurveInterpolationMode mode, std::span<DBCPosition2D const> points, float x) const;
EmotesTextSoundEntry const* GetTextSoundEmoteFor(uint32 emote, uint8 race, uint8 gender, uint8 class_) const;
float EvaluateExpectedStat(ExpectedStatType stat, uint32 level, int32 expansion, uint32 contentTuningId, Classes unitClass, int32 mythicPlusMilestoneSeason) const;
std::vector<uint32> const* GetFactionTeamList(uint32 faction) const;

View File

@@ -750,6 +750,17 @@ enum Curves
CURVE_ID_AZERITE_EMPOWERED_ITEM_RESPEC_COST = 6785
};
enum class CurveInterpolationMode : uint8
{
Linear = 0,
Cosine = 1,
CatmullRom = 2,
Bezier3 = 3,
Bezier4 = 4,
Bezier = 5,
Constant = 6,
};
enum Difficulty : uint8
{
DIFFICULTY_NONE = 0,

View File

@@ -39,6 +39,7 @@
#include "Transport.h"
#include "Unit.h"
#include "UpdateData.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()),
@@ -139,22 +140,7 @@ bool AreaTrigger::Create(uint32 areaTriggerCreatePropertiesId, Unit* caster, Uni
SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::BoundsRadius2D), GetMaxSearchRadius());
SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::DecalPropertiesID), GetCreateProperties()->DecalPropertiesId);
if (GetCreateProperties()->ExtraScale.Data.Structured.StartTimeOffset)
SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve).ModifyValue(&UF::ScaleCurve::StartTimeOffset), GetCreateProperties()->ExtraScale.Data.Structured.StartTimeOffset);
if (GetCreateProperties()->ExtraScale.Data.Structured.Points[0] || GetCreateProperties()->ExtraScale.Data.Structured.Points[1])
{
Position point(GetCreateProperties()->ExtraScale.Data.Structured.Points[0], GetCreateProperties()->ExtraScale.Data.Structured.Points[1]);
SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve).ModifyValue(&UF::ScaleCurve::Points, 0), point);
}
if (GetCreateProperties()->ExtraScale.Data.Structured.Points[2] || GetCreateProperties()->ExtraScale.Data.Structured.Points[3])
{
Position point(GetCreateProperties()->ExtraScale.Data.Structured.Points[2], GetCreateProperties()->ExtraScale.Data.Structured.Points[3]);
SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve).ModifyValue(&UF::ScaleCurve::Points, 1), point);
}
if (GetCreateProperties()->ExtraScale.Data.Raw[5])
SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve).ModifyValue(&UF::ScaleCurve::ParameterCurve), GetCreateProperties()->ExtraScale.Data.Raw[5]);
if (GetCreateProperties()->ExtraScale.Data.Structured.OverrideActive)
SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve).ModifyValue(&UF::ScaleCurve::OverrideActive), GetCreateProperties()->ExtraScale.Data.Structured.OverrideActive);
SetScaleCurve(areaTriggerData.ModifyValue(&UF::AreaTriggerData::ExtraScaleCurve), GetCreateProperties()->ExtraScale);
SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::AnimationDataID), GetCreateProperties()->AnimId);
SetUpdateFieldValue(areaTriggerData.ModifyValue(&UF::AreaTriggerData::VisualAnim).ModifyValue(&UF::VisualAnim::AnimKitID), GetCreateProperties()->AnimKitId);
@@ -372,6 +358,88 @@ float AreaTrigger::GetProgress() const
return GetTimeSinceCreated() < GetTimeToTargetScale() ? float(GetTimeSinceCreated()) / float(GetTimeToTargetScale()) : 1.0f;
}
float AreaTrigger::GetScaleCurveValue(UF::ScaleCurve const& scaleCurve, float x) const
{
ASSERT(*scaleCurve.OverrideActive, "ScaleCurve must be active to evaluate it");
// unpack ParameterCurve
if (*scaleCurve.ParameterCurve & 1)
return std::bit_cast<float>(*scaleCurve.ParameterCurve & ~1);
std::array<DBCPosition2D, 2> points;
for (std::size_t i = 0; i < scaleCurve.Points.size(); ++i)
points[i] = { .X = scaleCurve.Points[i].Pos.GetPositionX(), .Y = scaleCurve.Points[i].Pos.GetPositionY() };
CurveInterpolationMode mode = CurveInterpolationMode(*scaleCurve.ParameterCurve >> 1 & 0x7);
std::size_t pointCount = *scaleCurve.ParameterCurve >> 24 & 0xFF;
return sDB2Manager.GetCurveValueAt(mode, std::span(points.begin(), pointCount), x);
}
void AreaTrigger::SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false>&& scaleCurveMutator, Optional<AreaTriggerScaleCurveTemplate> const& curve)
{
if (!curve)
{
SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::OverrideActive), false);
return;
}
SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::OverrideActive), true);
SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::StartTimeOffset), curve->StartTimeOffset);
Position point;
// ParameterCurve packing information
// (not_using_points & 1) | ((interpolation_mode & 0x7) << 1) | ((first_point_offset & 0xFFFFF) << 4) | ((point_count & 0xFF) << 24)
// if not_using_points is set then the entire field is simply read as a float (ignoring that lowest bit)
if (float const* simpleFloat = std::get_if<float>(&curve->Curve))
{
uint32 packedCurve = std::bit_cast<uint32>(*simpleFloat);
packedCurve |= 1;
SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::ParameterCurve), packedCurve);
// clear points
for (std::size_t i = 0; i < UF::size<decltype(UF::ScaleCurve::Points)>(); ++i)
SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::Points, i), point);
}
else if (AreaTriggerScaleCurvePointsTemplate const* curvePoints = std::get_if<AreaTriggerScaleCurvePointsTemplate>(&curve->Curve))
{
CurveInterpolationMode mode = curvePoints->Mode;
if (curvePoints->Points[1].X < curvePoints->Points[0].X)
mode = CurveInterpolationMode::Constant;
switch (mode)
{
case CurveInterpolationMode::CatmullRom:
// catmullrom requires at least 4 points, impossible here
mode = CurveInterpolationMode::Cosine;
break;
case CurveInterpolationMode::Bezier3:
case CurveInterpolationMode::Bezier4:
case CurveInterpolationMode::Bezier:
// bezier requires more than 2 points, impossible here
mode = CurveInterpolationMode::Linear;
break;
default:
break;
}
uint32 pointCount = 2;
if (mode == CurveInterpolationMode::Constant)
pointCount = 1;
uint32 packedCurve = (uint32(mode) << 1) | (pointCount << 24);
SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::ParameterCurve), packedCurve);
for (std::size_t i = 0; i < curvePoints->Points.size(); ++i)
{
point.Relocate(curvePoints->Points[i].X, curvePoints->Points[i].Y);
SetUpdateFieldValue(scaleCurveMutator.ModifyValue(&UF::ScaleCurve::Points, i), point);
}
}
}
void AreaTrigger::UpdateTargetList()
{
std::vector<Unit*> targetList;

View File

@@ -134,6 +134,9 @@ class TC_GAME_API AreaTrigger : public WorldObject, public GridObject<AreaTrigge
void _UpdateDuration(int32 newDuration);
float GetProgress() const;
float GetScaleCurveValue(UF::ScaleCurve const& scaleCurve, float x) const;
void SetScaleCurve(UF::MutableFieldReference<UF::ScaleCurve, false>&& scaleCurveMutator, Optional<AreaTriggerScaleCurveTemplate> const& curve);
void UpdateTargetList();
void SearchUnits(std::vector<Unit*>& targetList, float radius, bool check3D);
void SearchUnitInSphere(std::vector<Unit*>& targetList);

View File

@@ -21,9 +21,12 @@
#include <cstring>
#include <cmath>
AreaTriggerScaleInfo::AreaTriggerScaleInfo()
AreaTriggerScaleCurvePointsTemplate::AreaTriggerScaleCurvePointsTemplate() : Mode(CurveInterpolationMode::Linear), Points()
{
}
AreaTriggerScaleCurveTemplate::AreaTriggerScaleCurveTemplate() : StartTimeOffset(0), Curve(1.0f)
{
memset(Data.Raw, 0, sizeof(Data.Raw));
}
AreaTriggerShapeInfo::AreaTriggerShapeInfo()
@@ -59,9 +62,7 @@ AreaTriggerTemplate::AreaTriggerTemplate()
Flags = 0;
}
AreaTriggerTemplate::~AreaTriggerTemplate()
{
}
AreaTriggerTemplate::~AreaTriggerTemplate() = default;
AreaTriggerCreateProperties::AreaTriggerCreateProperties()
{
@@ -80,21 +81,14 @@ AreaTriggerCreateProperties::AreaTriggerCreateProperties()
TimeToTarget = 0;
TimeToTargetScale = 0;
// legacy code from before it was known what each curve field does
// wtf? thats not how you pack curve data
float tmp = 1.0000001f;
memcpy(&ExtraScale.Data.Raw[5], &tmp, sizeof(tmp));
// also OverrideActive does nothing on ExtraScale
ExtraScale.Data.Structured.OverrideActive = 1;
ExtraScale.emplace();
Template = nullptr;
ScriptId = 0;
}
AreaTriggerCreateProperties::~AreaTriggerCreateProperties()
{
}
AreaTriggerCreateProperties::~AreaTriggerCreateProperties() = default;
bool AreaTriggerCreateProperties::HasSplines() const
{

View File

@@ -22,6 +22,7 @@
#include "ObjectGuid.h"
#include "Optional.h"
#include "SpawnData.h"
#include <variant>
#include <vector>
#define MAX_AREATRIGGER_ENTITY_DATA 8
@@ -87,34 +88,20 @@ struct AreaTriggerAction
AreaTriggerActionUserTypes TargetType;
};
// Scale array definition
// 0 - time offset from creation for starting of scaling
// 1+2,3+4 are values for curve points Vector2[2]
// 5 is packed curve information (has_no_data & 1) | ((interpolation_mode & 0x7) << 1) | ((first_point_offset & 0x7FFFFF) << 4) | ((point_count & 0x1F) << 27)
// 6 bool is_override, only valid for AREATRIGGER_OVERRIDE_SCALE_CURVE, if true then use data from AREATRIGGER_OVERRIDE_SCALE_CURVE instead of ScaleCurveId from CreateObject
struct AreaTriggerScaleInfo
struct AreaTriggerScaleCurvePointsTemplate
{
AreaTriggerScaleInfo();
AreaTriggerScaleCurvePointsTemplate();
union
{
struct
{
uint32 StartTimeOffset;
float Points[4];
struct
{
uint32 NoData : 1;
uint32 InterpolationMode : 3;
uint32 FirstPointOffset : 23;
uint32 PointCount : 5;
} CurveParameters;
uint32 OverrideActive;
} Structured;
CurveInterpolationMode Mode;
std::array<DBCPosition2D, 2> Points;
};
uint32 Raw[MAX_AREATRIGGER_SCALE];
} Data;
struct AreaTriggerScaleCurveTemplate
{
AreaTriggerScaleCurveTemplate();
uint32 StartTimeOffset;
std::variant<float, AreaTriggerScaleCurvePointsTemplate> Curve;
};
struct AreaTriggerShapeInfo
@@ -213,7 +200,7 @@ public:
AreaTriggerTemplate();
~AreaTriggerTemplate();
bool HasFlag(uint32 flag) const { return (Flags & flag) != 0; }
bool HasFlag(AreaTriggerFlags flag) const { return (Flags & flag) != 0; }
AreaTriggerId Id;
uint32 Flags;
@@ -245,8 +232,8 @@ public:
uint32 TimeToTarget;
uint32 TimeToTargetScale;
AreaTriggerScaleInfo OverrideScale;
AreaTriggerScaleInfo ExtraScale;
Optional<AreaTriggerScaleCurveTemplate> OverrideScale;
Optional<AreaTriggerScaleCurveTemplate> ExtraScale;
AreaTriggerShapeInfo Shape;
std::vector<TaggedPosition<Position::XY>> PolygonVertices;