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
Port From (https://github.com/TrinityCore/TrinityCore/commit/c676d1477239aec4d0b235a410e5627a7070a86e)
This commit is contained in:
hondacrx
2024-01-30 21:14:55 -05:00
parent 804bc30581
commit 5e46dd951b
6 changed files with 344 additions and 101 deletions
@@ -5,7 +5,7 @@ namespace Framework.Constants
{ {
public enum AreaTriggerFlags public enum AreaTriggerFlags
{ {
HasAbsoluteOrientation = 0x01, // Nyi HasAbsoluteOrientation = 0x01,
HasDynamicShape = 0x02, // Implemented For Spheres HasDynamicShape = 0x02, // Implemented For Spheres
HasAttached = 0x04, HasAttached = 0x04,
HasFaceMovementDir = 0x08, HasFaceMovementDir = 0x08,
@@ -196,6 +196,12 @@ namespace Game.DataStorage
createProperties.PolygonVertices = verticesByCreateProperties[createProperties.Id]; createProperties.PolygonVertices = verticesByCreateProperties[createProperties.Id];
createProperties.PolygonVerticesTarget = verticesTargetByCreateProperties[createProperties.Id]; createProperties.PolygonVerticesTarget = verticesTargetByCreateProperties[createProperties.Id];
if (!createProperties.PolygonVerticesTarget.Empty() && createProperties.PolygonVertices.Count != createProperties.PolygonVerticesTarget.Count)
{
Log.outError(LogFilter.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 = splinesByCreateProperties[createProperties.Id]; createProperties.SplinePoints = splinesByCreateProperties[createProperties.Id];
_areaTriggerCreateProperties[createProperties.Id] = createProperties; _areaTriggerCreateProperties[createProperties.Id] = createProperties;
+324 -82
View File
@@ -19,7 +19,7 @@ namespace Game.Entities
{ {
public AreaTrigger() : base(false) public AreaTrigger() : base(false)
{ {
_previousCheckOrientation = float.PositiveInfinity; _verticesUpdatePreviousOrientation = float.PositiveInfinity;
_reachedDestination = true; _reachedDestination = true;
ObjectTypeMask |= TypeMask.AreaTrigger; ObjectTypeMask |= TypeMask.AreaTrigger;
@@ -83,6 +83,7 @@ namespace Game.Entities
SetMap(caster.GetMap()); SetMap(caster.GetMap());
Relocate(pos); Relocate(pos);
RelocateStationaryPosition(pos);
if (!IsPositionValid()) if (!IsPositionValid())
{ {
Log.outError(LogFilter.AreaTrigger, $"AreaTrigger (areaTriggerCreatePropertiesId: {areaTriggerCreatePropertiesId}) not created. Invalid coordinates (X: {GetPositionX()} Y: {GetPositionY()})"); Log.outError(LogFilter.AreaTrigger, $"AreaTrigger (areaTriggerCreatePropertiesId: {areaTriggerCreatePropertiesId}) not created. Invalid coordinates (X: {GetPositionX()} Y: {GetPositionY()})");
@@ -110,7 +111,6 @@ namespace Game.Entities
SetObjectScale(1.0f); SetObjectScale(1.0f);
_shape = GetCreateProperties().Shape; _shape = GetCreateProperties().Shape;
_maxSearchRadius = GetCreateProperties().GetMaxSearchRadius();
var areaTriggerData = m_values.ModifyValue(m_areaTriggerData); var areaTriggerData = m_values.ModifyValue(m_areaTriggerData);
SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.Caster), caster.GetGUID()); SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.Caster), caster.GetGUID());
@@ -125,11 +125,25 @@ namespace Game.Entities
SetUpdateFieldValue(ref spellCastVisual.ScriptVisualID, spellVisual.ScriptVisualID); SetUpdateFieldValue(ref spellCastVisual.ScriptVisualID, spellVisual.ScriptVisualID);
SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.TimeToTargetScale), GetCreateProperties().TimeToTargetScale != 0 ? GetCreateProperties().TimeToTargetScale : m_areaTriggerData.Duration); SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.TimeToTargetScale), GetCreateProperties().TimeToTargetScale != 0 ? GetCreateProperties().TimeToTargetScale : m_areaTriggerData.Duration);
SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.BoundsRadius2D), GetMaxSearchRadius()); SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.BoundsRadius2D), GetCreateProperties().GetMaxSearchRadius());
SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.DecalPropertiesID), GetCreateProperties().DecalPropertiesId); SetUpdateFieldValue(areaTriggerData.ModifyValue(m_areaTriggerData.DecalPropertiesID), GetCreateProperties().DecalPropertiesId);
SetScaleCurve(areaTriggerData.ModifyValue(m_areaTriggerData.ExtraScaleCurve), GetCreateProperties().ExtraScale); SetScaleCurve(areaTriggerData.ModifyValue(m_areaTriggerData.ExtraScaleCurve), GetCreateProperties().ExtraScale);
Player modOwner = caster.GetSpellModOwner();
if (modOwner != null)
{
float multiplier = 1.0f;
int flat = 0;
modOwner.GetSpellModValues(spellInfo, SpellModOp.Radius, spell, (float)m_areaTriggerData.BoundsRadius2D, ref flat, ref multiplier);
if (multiplier != 1.0f)
{
AreaTriggerScaleCurveTemplate overrideScale = new();
overrideScale.Curve = multiplier;
SetScaleCurve(areaTriggerData.ModifyValue(m_areaTriggerData.OverrideScaleCurve), overrideScale);
}
}
VisualAnim visualAnim = areaTriggerData.ModifyValue(m_areaTriggerData.VisualAnim); VisualAnim visualAnim = areaTriggerData.ModifyValue(m_areaTriggerData.VisualAnim);
SetUpdateFieldValue(visualAnim.ModifyValue(visualAnim.AnimationDataID), GetCreateProperties().AnimId); SetUpdateFieldValue(visualAnim.ModifyValue(visualAnim.AnimationDataID), GetCreateProperties().AnimId);
SetUpdateFieldValue(visualAnim.ModifyValue(visualAnim.AnimKitID), GetCreateProperties().AnimKitId); SetUpdateFieldValue(visualAnim.ModifyValue(visualAnim.AnimKitID), GetCreateProperties().AnimKitId);
@@ -231,6 +245,7 @@ namespace Game.Entities
{ {
SetMap(map); SetMap(map);
Relocate(position.SpawnPoint); Relocate(position.SpawnPoint);
RelocateStationaryPosition(position.SpawnPoint);
if (!IsPositionValid()) if (!IsPositionValid())
{ {
Log.outError(LogFilter.AreaTrigger, $"AreaTriggerServer (id {areaTriggerTemplate.Id}) not created. Invalid coordinates (X: {GetPositionX()} Y: {GetPositionY()})"); Log.outError(LogFilter.AreaTrigger, $"AreaTriggerServer (id {areaTriggerTemplate.Id}) not created. Invalid coordinates (X: {GetPositionX()} Y: {GetPositionY()})");
@@ -248,7 +263,8 @@ namespace Game.Entities
SetObjectScale(1.0f); SetObjectScale(1.0f);
SetDuration(-1); SetDuration(-1);
SetUpdateFieldValue(m_areaTriggerData.ModifyValue(m_areaTriggerData.BoundsRadius2D), GetMaxSearchRadius()); _shape = position.Shape;
if (position.SpellForVisuals.HasValue) if (position.SpellForVisuals.HasValue)
{ {
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(position.SpellForVisuals.Value, Difficulty.None); SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(position.SpellForVisuals.Value, Difficulty.None);
@@ -259,6 +275,7 @@ namespace Game.Entities
SetUpdateFieldValue(ref spellCastVisual.ScriptVisualID, 0u); SetUpdateFieldValue(ref spellCastVisual.ScriptVisualID, 0u);
} }
SetUpdateFieldValue(m_areaTriggerData.ModifyValue(m_areaTriggerData.BoundsRadius2D), _shape.GetMaxSearchRadius());
if (IsServerSide()) if (IsServerSide())
SetUpdateFieldValue(m_areaTriggerData.ModifyValue(m_areaTriggerData.DecalPropertiesID), 24u); // blue decal, for .debug areatrigger visibility SetUpdateFieldValue(m_areaTriggerData.ModifyValue(m_areaTriggerData.DecalPropertiesID), 24u); // blue decal, for .debug areatrigger visibility
@@ -267,11 +284,8 @@ namespace Game.Entities
VisualAnim visualAnim = m_areaTriggerData.ModifyValue(m_areaTriggerData.VisualAnim); VisualAnim visualAnim = m_areaTriggerData.ModifyValue(m_areaTriggerData.VisualAnim);
SetUpdateFieldValue(visualAnim.ModifyValue(visualAnim.AnimationDataID), -1); SetUpdateFieldValue(visualAnim.ModifyValue(visualAnim.AnimationDataID), -1);
_shape = position.Shape;
_maxSearchRadius = _shape.GetMaxSearchRadius();
if (position.PhaseUseFlags != 0 || position.PhaseId != 0 || position.PhaseGroup != 0) if (position.PhaseUseFlags != 0 || position.PhaseId != 0 || position.PhaseGroup != 0)
PhasingHandler.InitDbPhaseShift(GetPhaseShift(), (PhaseUseFlagsValues)position.PhaseUseFlags, position.PhaseId, position.PhaseGroup); PhasingHandler.InitDbPhaseShift(GetPhaseShift(), position.PhaseUseFlags, position.PhaseId, position.PhaseGroup);
UpdateShape(); UpdateShape();
@@ -290,7 +304,11 @@ namespace Game.Entities
if (!IsServerSide()) if (!IsServerSide())
{ {
// "If" order matter here, Orbit > Attached > Splines // "If" order matter here, Orbit > Attached > Splines
if (HasOrbit()) if (HasOverridePosition())
{
UpdateOverridePosition();
}
else if (HasOrbit())
{ {
UpdateOrbitPosition(diff); UpdateOrbitPosition(diff);
} }
@@ -298,10 +316,34 @@ namespace Game.Entities
{ {
Unit target = GetTarget(); Unit target = GetTarget();
if (target != null) if (target != null)
GetMap().AreaTriggerRelocation(this, target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), target.GetOrientation()); {
float orientation = 0.0f;
if (GetCreateProperties().FacingCurveId != 0)
orientation = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().FacingCurveId, GetProgress());
if (GetTemplate() == null || !GetTemplate().HasFlag(AreaTriggerFlags.HasAbsoluteOrientation))
orientation += target.GetOrientation();
GetMap().AreaTriggerRelocation(this, target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), orientation);
}
}
else if (HasSplines())
{
UpdateSplinePosition(diff);
} }
else else
UpdateSplinePosition(diff); {
if (GetCreateProperties().FacingCurveId != 0)
{
float orientation = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().FacingCurveId, GetProgress());
if (GetTemplate() == null || !GetTemplate().HasFlag(AreaTriggerFlags.HasAbsoluteOrientation))
orientation += GetStationaryO();
SetOrientation(orientation);
}
UpdateShape();
}
} }
if (GetDuration() != -1) if (GetDuration() != -1)
@@ -326,6 +368,57 @@ namespace Game.Entities
AddObjectToRemoveList(); AddObjectToRemoveList();
} }
void SetOverrideScaleCurve(float overrideScale)
{
SetScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideScaleCurve), overrideScale);
}
void SetOverrideScaleCurve(Vector2[] points, uint? startTimeOffset, CurveInterpolationMode interpolation)
{
SetScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideScaleCurve), points, startTimeOffset, interpolation);
}
void ClearOverrideScaleCurve()
{
ClearScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideScaleCurve));
}
void SetExtraScaleCurve(float extraScale)
{
SetScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.ExtraScaleCurve), extraScale);
}
void SetExtraScaleCurve(Vector2[] points, uint? startTimeOffset, CurveInterpolationMode interpolation)
{
SetScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.ExtraScaleCurve), points, startTimeOffset, interpolation);
}
void ClearExtraScaleCurve()
{
ClearScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.ExtraScaleCurve));
}
void SetOverrideMoveCurve(float x, float y, float z)
{
SetScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideMoveCurveX), x);
SetScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideMoveCurveY), y);
SetScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideMoveCurveZ), z);
}
void SetOverrideMoveCurve(Vector2[] xCurvePoints, Vector2[] yCurvePoints, Vector2[] zCurvePoints, uint? startTimeOffset, CurveInterpolationMode interpolation)
{
SetScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideMoveCurveX), xCurvePoints, startTimeOffset, interpolation);
SetScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideMoveCurveY), yCurvePoints, startTimeOffset, interpolation);
SetScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideMoveCurveZ), zCurvePoints, startTimeOffset, interpolation);
}
void ClearOverrideMoveCurve()
{
ClearScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideMoveCurveX));
ClearScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideMoveCurveY));
ClearScaleCurve(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OverrideMoveCurveZ));
}
public void SetDuration(int newDuration) public void SetDuration(int newDuration)
{ {
_duration = newDuration; _duration = newDuration;
@@ -347,18 +440,46 @@ namespace Game.Entities
}); });
} }
float GetProgress() float CalcCurrentScale()
{ {
return GetTimeSinceCreated() < GetTimeToTargetScale() ? (float)GetTimeSinceCreated() / GetTimeToTargetScale() : 1.0f; float scale = 1.0f;
if (m_areaTriggerData.OverrideScaleCurve.GetValue().OverrideActive)
scale *= Math.Max(GetScaleCurveValue(m_areaTriggerData.OverrideScaleCurve, m_areaTriggerData.TimeToTargetScale), 0.000001f);
else
{
AreaTriggerCreateProperties createProperties = GetCreateProperties();
if (createProperties != null && createProperties.ScaleCurveId != 0)
scale *= Math.Max(Global.DB2Mgr.GetCurveValueAt(createProperties.ScaleCurveId, GetScaleCurveProgress(m_areaTriggerData.OverrideScaleCurve, m_areaTriggerData.TimeToTargetScale)), 0.000001f);
}
scale *= Math.Max(GetScaleCurveValue(m_areaTriggerData.ExtraScaleCurve, m_areaTriggerData.TimeToTargetExtraScale), 0.000001f);
return scale;
} }
float GetScaleCurveValue(ScaleCurve scaleCurve, float x) float GetProgress()
{
if (_totalDuration <= 0)
return 1.0f;
return Math.Clamp((float)GetTimeSinceCreated() / (float)GetTotalDuration(), 0.0f, 1.0f);
}
float GetScaleCurveProgress(ScaleCurve scaleCurve, uint timeTo)
{
if (timeTo == 0)
return 0.0f;
return Math.Clamp((float)(GetTimeSinceCreated() - scaleCurve.StartTimeOffset) / (float)timeTo, 0.0f, 1.0f);
}
float GetScaleCurveValueAtProgress(ScaleCurve scaleCurve, float x)
{ {
Cypher.Assert(scaleCurve.OverrideActive, "ScaleCurve must be active to evaluate it"); Cypher.Assert(scaleCurve.OverrideActive, "ScaleCurve must be active to evaluate it");
// unpack ParameterCurve // unpack ParameterCurve
if ((scaleCurve.ParameterCurve & 1) != 0) if ((scaleCurve.ParameterCurve & 1u) != 0)
return BitConverter.UInt32BitsToSingle((uint)(scaleCurve.ParameterCurve & ~1)); return BitConverter.UInt32BitsToSingle((uint)(scaleCurve.ParameterCurve & ~1u));
Vector2[] points = new Vector2[2]; Vector2[] points = new Vector2[2];
for (var i = 0; i < scaleCurve.Points.GetSize(); ++i) for (var i = 0; i < scaleCurve.Points.GetSize(); ++i)
@@ -370,6 +491,36 @@ namespace Game.Entities
return Global.DB2Mgr.GetCurveValueAt(mode, points.AsSpan(0, pointCount).ToArray(), x); return Global.DB2Mgr.GetCurveValueAt(mode, points.AsSpan(0, pointCount).ToArray(), x);
} }
float GetScaleCurveValue(ScaleCurve scaleCurve, uint timeTo)
{
return GetScaleCurveValueAtProgress(scaleCurve, GetScaleCurveProgress(scaleCurve, timeTo));
}
void SetScaleCurve(ScaleCurve scaleCurve, float constantValue)
{
AreaTriggerScaleCurveTemplate curveTemplate = new();
curveTemplate.Curve = constantValue;
SetScaleCurve(scaleCurve, curveTemplate);
}
void SetScaleCurve(ScaleCurve scaleCurve, Vector2[] points, uint? startTimeOffset, CurveInterpolationMode interpolation)
{
AreaTriggerScaleCurvePointsTemplate curve = new();
curve.Mode = interpolation;
curve.Points = points;
AreaTriggerScaleCurveTemplate curveTemplate = new();
curveTemplate.StartTimeOffset = startTimeOffset.GetValueOrDefault(GetTimeSinceCreated());
curveTemplate.CurveTemplate = curve;
SetScaleCurve(scaleCurve, curveTemplate);
}
void ClearScaleCurve(ScaleCurve scaleCurve)
{
SetScaleCurve(scaleCurve, null);
}
void SetScaleCurve(ScaleCurve scaleCurve, AreaTriggerScaleCurveTemplate curve) void SetScaleCurve(ScaleCurve scaleCurve, AreaTriggerScaleCurveTemplate curve)
{ {
if (curve == null) if (curve == null)
@@ -437,7 +588,7 @@ namespace Game.Entities
} }
} }
} }
void UpdateTargetList() void UpdateTargetList()
{ {
List<Unit> targetList = new(); List<Unit> targetList = new();
@@ -493,99 +644,111 @@ namespace Game.Entities
void SearchUnitInSphere(List<Unit> targetList) void SearchUnitInSphere(List<Unit> targetList)
{ {
float radius = _shape.SphereDatas.Radius; float progress = GetProgress();
if (GetTemplate() != null && GetTemplate().HasFlag(AreaTriggerFlags.HasDynamicShape)) if (GetCreateProperties().MorphCurveId != 0)
{ progress = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().MorphCurveId, progress);
if (GetCreateProperties().MorphCurveId != 0)
{ float scale = CalcCurrentScale();
radius = MathFunctions.Lerp(_shape.SphereDatas.Radius, _shape.SphereDatas.RadiusTarget, Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().MorphCurveId, GetProgress())); float radius = MathFunctions.Lerp(_shape.SphereDatas.Radius, _shape.SphereDatas.RadiusTarget, progress) * scale;
}
}
SearchUnits(targetList, radius, true); SearchUnits(targetList, radius, true);
} }
void SearchUnitInBox(List<Unit> targetList) void SearchUnitInBox(List<Unit> targetList)
{ {
SearchUnits(targetList, GetMaxSearchRadius(), false); float progress = GetProgress();
if (GetCreateProperties().MorphCurveId != 0)
Position boxCenter = GetPosition(); progress = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().MorphCurveId, progress);
float extentsX, extentsY, extentsZ;
unsafe unsafe
{ {
extentsX = _shape.BoxDatas.Extents[0]; float scale = CalcCurrentScale();
extentsY = _shape.BoxDatas.Extents[1]; float extentsX = MathFunctions.Lerp(_shape.BoxDatas.Extents[0], _shape.BoxDatas.ExtentsTarget[0], progress) * scale;
extentsZ = _shape.BoxDatas.Extents[2]; float extentsY = MathFunctions.Lerp(_shape.BoxDatas.Extents[1], _shape.BoxDatas.ExtentsTarget[1], progress) * scale;
} float extentsZ = MathFunctions.Lerp(_shape.BoxDatas.Extents[2], _shape.BoxDatas.ExtentsTarget[2], progress) * scale;
float radius = MathF.Sqrt(extentsX * extentsX + extentsY * extentsY);
targetList.RemoveAll(unit => !unit.IsWithinBox(boxCenter, extentsX, extentsY, extentsZ / 2)); SearchUnits(targetList, radius, false);
Position boxCenter = GetPosition();
targetList.RemoveAll(unit => !unit.IsWithinBox(boxCenter, extentsX, extentsY, extentsZ / 2));
}
} }
void SearchUnitInPolygon(List<Unit> targetList) void SearchUnitInPolygon(List<Unit> targetList)
{ {
SearchUnits(targetList, GetMaxSearchRadius(), false); float progress = GetProgress();
if (GetCreateProperties().MorphCurveId != 0)
progress = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().MorphCurveId, progress);
float height = _shape.PolygonDatas.Height; float height = MathFunctions.Lerp(_shape.PolygonDatas.Height, _shape.PolygonDatas.HeightTarget, progress);
float minZ = GetPositionZ() - height; float minZ = GetPositionZ() - height;
float maxZ = GetPositionZ() + height; float maxZ = GetPositionZ() + height;
targetList.RemoveAll(unit => !CheckIsInPolygon2D(unit) || unit.GetPositionZ() < minZ || unit.GetPositionZ() > maxZ); SearchUnits(targetList, GetMaxSearchRadius(), false);
targetList.RemoveAll(unit => unit.GetPositionZ() < minZ || unit.GetPositionZ() > maxZ || !CheckIsInPolygon2D(unit));
} }
void SearchUnitInCylinder(List<Unit> targetList) void SearchUnitInCylinder(List<Unit> targetList)
{ {
SearchUnits(targetList, GetMaxSearchRadius(), false); float progress = GetProgress();
if (GetCreateProperties().MorphCurveId != 0)
progress = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().MorphCurveId, progress);
float scale = CalcCurrentScale();
float radius = MathFunctions.Lerp(_shape.CylinderDatas.Radius, _shape.CylinderDatas.RadiusTarget, progress) * scale;
float height = MathFunctions.Lerp(_shape.CylinderDatas.Height, _shape.CylinderDatas.HeightTarget, progress);
if (!m_areaTriggerData.HeightIgnoresScale)
height *= scale;
float height = _shape.CylinderDatas.Height;
float minZ = GetPositionZ() - height; float minZ = GetPositionZ() - height;
float maxZ = GetPositionZ() + height; float maxZ = GetPositionZ() + height;
SearchUnits(targetList, radius, false);
targetList.RemoveAll(unit => unit.GetPositionZ() < minZ || unit.GetPositionZ() > maxZ); targetList.RemoveAll(unit => unit.GetPositionZ() < minZ || unit.GetPositionZ() > maxZ);
} }
void SearchUnitInDisk(List<Unit> targetList) void SearchUnitInDisk(List<Unit> targetList)
{ {
float innerRadius = _shape.DiskDatas.InnerRadius; float progress = GetProgress();
float outerRadius = _shape.DiskDatas.OuterRadius; if (GetCreateProperties().MorphCurveId != 0)
float height = _shape.DiskDatas.Height; progress = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().MorphCurveId, progress);
if (GetTemplate() != null && GetTemplate().HasFlag(AreaTriggerFlags.HasDynamicShape)) float scale = CalcCurrentScale();
{ float innerRadius = MathFunctions.Lerp(_shape.DiskDatas.InnerRadius, _shape.DiskDatas.InnerRadiusTarget, progress) * scale;
float progress = GetProgress(); float outerRadius = MathFunctions.Lerp(_shape.DiskDatas.OuterRadius, _shape.DiskDatas.OuterRadiusTarget, progress) * scale;
if (GetCreateProperties().MorphCurveId != 0) float height = MathFunctions.Lerp(_shape.DiskDatas.Height, _shape.DiskDatas.HeightTarget, progress);
progress = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().MorphCurveId, progress); if (!m_areaTriggerData.HeightIgnoresScale)
height *= scale;
innerRadius = MathFunctions.Lerp(_shape.DiskDatas.InnerRadius, _shape.DiskDatas.InnerRadiusTarget, progress);
outerRadius = MathFunctions.Lerp(_shape.DiskDatas.OuterRadius, _shape.DiskDatas.OuterRadiusTarget, progress);
height = MathFunctions.Lerp(_shape.DiskDatas.Height, _shape.DiskDatas.HeightTarget, progress);
}
SearchUnits(targetList, outerRadius, false);
float minZ = GetPositionZ() - height; float minZ = GetPositionZ() - height;
float maxZ = GetPositionZ() + height; float maxZ = GetPositionZ() + height;
SearchUnits(targetList, outerRadius, false);
targetList.RemoveAll(unit => unit.IsInDist2d(this, innerRadius) || unit.GetPositionZ() < minZ || unit.GetPositionZ() > maxZ); targetList.RemoveAll(unit => unit.IsInDist2d(this, innerRadius) || unit.GetPositionZ() < minZ || unit.GetPositionZ() > maxZ);
} }
void SearchUnitInBoundedPlane(List<Unit> targetList) void SearchUnitInBoundedPlane(List<Unit> targetList)
{ {
SearchUnits(targetList, GetMaxSearchRadius(), false); float progress = GetProgress();
if (GetCreateProperties().MorphCurveId != 0)
Position boxCenter = GetPosition(); progress = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().MorphCurveId, progress);
float extentsX, extentsY;
unsafe unsafe
{ {
extentsX = _shape.BoxDatas.Extents[0]; float scale = CalcCurrentScale();
extentsY = _shape.BoxDatas.Extents[1]; float extentsX = MathFunctions.Lerp(_shape.BoundedPlaneDatas.Extents[0], _shape.BoundedPlaneDatas.ExtentsTarget[0], progress) * scale;
} float extentsY = MathFunctions.Lerp(_shape.BoundedPlaneDatas.Extents[1], _shape.BoundedPlaneDatas.ExtentsTarget[1], progress) * scale;
float radius = MathF.Sqrt(extentsX * extentsX + extentsY * extentsY);
targetList.RemoveAll(unit => SearchUnits(targetList, radius, false);
{
return !unit.IsWithinBox(boxCenter, extentsX, extentsY, MapConst.MapSize); Position boxCenter = GetPosition();
}); targetList.RemoveAll(unit => !unit.IsWithinBox(boxCenter, extentsX, extentsY, MapConst.MapSize));
}
} }
void HandleUnitEnterExit(List<Unit> newTargetList) void HandleUnitEnterExit(List<Unit> newTargetList)
@@ -679,16 +842,37 @@ namespace Game.Entities
return 0; return 0;
} }
void UpdatePolygonOrientation() float GetMaxSearchRadius()
{
return m_areaTriggerData.BoundsRadius2D * CalcCurrentScale();
}
void UpdatePolygonVertices()
{ {
float newOrientation = GetOrientation(); float newOrientation = GetOrientation();
// No need to recalculate, orientation didn't change // No need to recalculate, orientation didn't change
if (MathFunctions.fuzzyEq(_previousCheckOrientation, newOrientation)) if (MathFunctions.fuzzyEq(_verticesUpdatePreviousOrientation, newOrientation) && GetCreateProperties().PolygonVerticesTarget.Empty())
return; return;
_polygonVertices = GetCreateProperties().PolygonVertices; _polygonVertices = GetCreateProperties().PolygonVertices;
if (!GetCreateProperties().PolygonVerticesTarget.Empty())
{
float progress = GetProgress();
if (GetCreateProperties().MorphCurveId != 0)
progress = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().MorphCurveId, progress);
for (var i = 0; i < _polygonVertices.Count; ++i)
{
Vector2 vertex = _polygonVertices[i];
Vector2 vertexTarget = GetCreateProperties().PolygonVerticesTarget[i];
vertex.X = MathFunctions.Lerp(vertex.X, vertexTarget.X, progress);
vertex.Y = MathFunctions.Lerp(vertex.Y, vertexTarget.Y, progress);
}
}
float angleSin = (float)Math.Sin(newOrientation); float angleSin = (float)Math.Sin(newOrientation);
float angleCos = (float)Math.Cos(newOrientation); float angleCos = (float)Math.Cos(newOrientation);
@@ -701,7 +885,7 @@ namespace Game.Entities
vertice.Y = vertice.Y * angleCos + vertice.X * angleSin; vertice.Y = vertice.Y * angleCos + vertice.X * angleSin;
} }
_previousCheckOrientation = newOrientation; _verticesUpdatePreviousOrientation = newOrientation;
} }
bool CheckIsInPolygon2D(Position pos) bool CheckIsInPolygon2D(Position pos)
@@ -773,10 +957,17 @@ namespace Game.Entities
return locatedInPolygon; return locatedInPolygon;
} }
bool HasOverridePosition()
{
return m_areaTriggerData.OverrideMoveCurveX.GetValue().OverrideActive
&& m_areaTriggerData.OverrideMoveCurveY.GetValue().OverrideActive
&& m_areaTriggerData.OverrideMoveCurveZ.GetValue().OverrideActive;
}
public void UpdateShape() public void UpdateShape()
{ {
if (_shape.IsPolygon()) if (_shape.IsPolygon())
UpdatePolygonOrientation(); UpdatePolygonVertices();
} }
bool UnitFitToActionRequirement(Unit unit, Unit caster, AreaTriggerAction action) bool UnitFitToActionRequirement(Unit unit, Unit caster, AreaTriggerAction action)
@@ -978,6 +1169,8 @@ namespace Game.Entities
// AreaTrigger make exactly "Duration / TimeToTarget" loops during his life time // AreaTrigger make exactly "Duration / TimeToTarget" loops during his life time
float pathProgress = (float)cmi.ElapsedTimeForMovement / cmi.TimeToTarget; float pathProgress = (float)cmi.ElapsedTimeForMovement / cmi.TimeToTarget;
if (GetCreateProperties().MoveCurveId != 0)
pathProgress = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().MoveCurveId, pathProgress);
// We already made one circle and can't loop // We already made one circle and can't loop
if (!cmi.CanLoop) if (!cmi.CanLoop)
@@ -1002,7 +1195,17 @@ namespace Game.Entities
float y = centerPos.GetPositionY() + (radius * (float)Math.Sin(angle)); float y = centerPos.GetPositionY() + (radius * (float)Math.Sin(angle));
float z = centerPos.GetPositionZ() + cmi.ZOffset; float z = centerPos.GetPositionZ() + cmi.ZOffset;
return new Position(x, y, z, angle); float orientation = 0.0f;
if (GetCreateProperties().FacingCurveId != 0)
orientation = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().FacingCurveId, GetProgress());
if (GetTemplate() == null || !GetTemplate().HasFlag(AreaTriggerFlags.HasAbsoluteOrientation))
{
orientation += angle;
orientation += cmi.CounterClockwise ? MathFunctions.PiOver4 : -MathFunctions.PiOver4;
}
return new Position(x, y, z, orientation);
} }
void UpdateOrbitPosition(uint diff) void UpdateOrbitPosition(uint diff)
@@ -1024,9 +1227,6 @@ namespace Game.Entities
if (_reachedDestination) if (_reachedDestination)
return; return;
if (!HasSplines())
return;
_movementTime += diff; _movementTime += diff;
if (_movementTime >= GetTimeToTarget()) if (_movementTime >= GetTimeToTarget())
@@ -1067,11 +1267,15 @@ namespace Game.Entities
Vector3 currentPosition; Vector3 currentPosition;
_spline.Evaluate_Percent(lastPositionIndex, percentFromLastPoint, out currentPosition); _spline.Evaluate_Percent(lastPositionIndex, percentFromLastPoint, out currentPosition);
float orientation = GetOrientation(); float orientation = GetStationaryO();
if (GetTemplate() != null && GetTemplate().HasFlag(AreaTriggerFlags.HasFaceMovementDir)) if (GetCreateProperties().FacingCurveId != 0)
orientation += Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().FacingCurveId, GetProgress());
if (GetTemplate() != null && !GetTemplate().HasFlag(AreaTriggerFlags.HasAbsoluteOrientation) && GetTemplate().HasFlag(AreaTriggerFlags.HasFaceMovementDir))
{ {
Vector3 nextPoint = _spline.GetPoint(lastPositionIndex + 1); _spline.Evaluate_Derivative(lastPositionIndex, percentFromLastPoint, out Vector3 derivative);
orientation = GetAbsoluteAngle(nextPoint.X, nextPoint.Y); if (derivative.X != 0.0f || derivative.Y != 0.0f)
orientation += MathF.Atan2(derivative.Y, derivative.X);
} }
GetMap().AreaTriggerRelocation(this, currentPosition.X, currentPosition.Y, currentPosition.Z, orientation); GetMap().AreaTriggerRelocation(this, currentPosition.X, currentPosition.Y, currentPosition.Z, orientation);
@@ -1085,6 +1289,26 @@ namespace Game.Entities
} }
} }
void 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 != 0)
{
orientation = Global.DB2Mgr.GetCurveValueAt(GetCreateProperties().FacingCurveId, GetProgress());
if (GetTemplate() == null || !GetTemplate().HasFlag(AreaTriggerFlags.HasAbsoluteOrientation))
orientation += GetStationaryO();
}
GetMap().AreaTriggerRelocation(this, x, y, z, orientation);
}
void AI_Initialize() void AI_Initialize()
{ {
AI_Destroy(); AI_Destroy();
@@ -1117,7 +1341,7 @@ namespace Game.Entities
return false; return false;
} }
public override void BuildValuesCreate(WorldPacket data, Player target) public override void BuildValuesCreate(WorldPacket data, Player target)
{ {
UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target); UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target);
@@ -1197,12 +1421,31 @@ namespace Game.Entities
} }
} }
public override float GetStationaryX() { return _stationaryPosition.GetPositionX(); }
public override float GetStationaryY() { return _stationaryPosition.GetPositionY(); }
public override float GetStationaryZ() { return _stationaryPosition.GetPositionZ(); }
public override float GetStationaryO() { return _stationaryPosition.GetOrientation(); }
void RelocateStationaryPosition(Position pos) { _stationaryPosition.Relocate(pos); }
public bool IsRemoved() { return _isRemoved; } public bool IsRemoved() { return _isRemoved; }
public uint GetSpellId() { return m_areaTriggerData.SpellID; } public uint GetSpellId() { return m_areaTriggerData.SpellID; }
public AuraEffect GetAuraEffect() { return _aurEff; } public AuraEffect GetAuraEffect() { return _aurEff; }
public uint GetTimeSinceCreated() { return _timeSinceCreated; } public uint GetTimeSinceCreated() { return _timeSinceCreated; }
public void SetHeightIgnoresScale(bool heightIgnoresScale) { SetUpdateFieldValue(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.HeightIgnoresScale), heightIgnoresScale); }
public uint GetTimeToTarget() { return m_areaTriggerData.TimeToTarget; } public uint GetTimeToTarget() { return m_areaTriggerData.TimeToTarget; }
public void SetTimeToTarget(uint timeToTarget) { SetUpdateFieldValue(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.TimeToTarget), timeToTarget); }
public uint GetTimeToTargetScale() { return m_areaTriggerData.TimeToTargetScale; } public uint GetTimeToTargetScale() { return m_areaTriggerData.TimeToTargetScale; }
public void SetTimeToTargetScale(uint timeToTargetScale) { SetUpdateFieldValue(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.TimeToTargetScale), timeToTargetScale); }
public uint GetTimeToTargetExtraScale() { return m_areaTriggerData.TimeToTargetExtraScale; }
public void SetTimeToTargetExtraScale(uint timeToTargetExtraScale) { SetUpdateFieldValue(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.TimeToTargetExtraScale), timeToTargetExtraScale); }
public uint GetTimeToTargetPos() { return m_areaTriggerData.TimeToTargetPos; }
public void SetTimeToTargetPos(uint timeToTargetPos) { SetUpdateFieldValue(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.TimeToTargetPos), timeToTargetPos); }
public int GetDuration() { return _duration; } public int GetDuration() { return _duration; }
public int GetTotalDuration() { return _totalDuration; } public int GetTotalDuration() { return _totalDuration; }
@@ -1216,7 +1459,6 @@ namespace Game.Entities
public ObjectGuid GetCasterGuid() { return m_areaTriggerData.Caster; } public ObjectGuid GetCasterGuid() { return m_areaTriggerData.Caster; }
public AreaTriggerShapeInfo GetShape() { return _shape; } public AreaTriggerShapeInfo GetShape() { return _shape; }
float GetMaxSearchRadius() { return _maxSearchRadius; }
public Vector3 GetRollPitchYaw() { return _rollPitchYaw; } public Vector3 GetRollPitchYaw() { return _rollPitchYaw; }
public Vector3 GetTargetRollPitchYaw() { return _targetRollPitchYaw; } public Vector3 GetTargetRollPitchYaw() { return _targetRollPitchYaw; }
@@ -1224,7 +1466,7 @@ namespace Game.Entities
public Spline<int> GetSpline() { return _spline; } public Spline<int> GetSpline() { return _spline; }
public uint GetElapsedTimeForMovement() { return GetTimeSinceCreated(); } // @todo: research the right value, in sniffs both timers are nearly identical public uint GetElapsedTimeForMovement() { return GetTimeSinceCreated(); } // @todo: research the right value, in sniffs both timers are nearly identical
public AreaTriggerOrbitInfo GetCircularMovementInfo() { return _orbitInfo; } public AreaTriggerOrbitInfo GetOrbit() { return _orbitInfo; }
AreaTriggerFieldData m_areaTriggerData; AreaTriggerFieldData m_areaTriggerData;
@@ -1234,12 +1476,12 @@ namespace Game.Entities
AuraEffect _aurEff; AuraEffect _aurEff;
Position _stationaryPosition;
AreaTriggerShapeInfo _shape; AreaTriggerShapeInfo _shape;
float _maxSearchRadius;
int _duration; int _duration;
int _totalDuration; int _totalDuration;
uint _timeSinceCreated; uint _timeSinceCreated;
float _previousCheckOrientation; float _verticesUpdatePreviousOrientation;
bool _isRemoved; bool _isRemoved;
Vector3 _rollPitchYaw; Vector3 _rollPitchYaw;
@@ -163,13 +163,15 @@ namespace Game.Entities
case AreaTriggerTypes.Sphere: case AreaTriggerTypes.Sphere:
return Math.Max(SphereDatas.Radius, SphereDatas.RadiusTarget); return Math.Max(SphereDatas.Radius, SphereDatas.RadiusTarget);
case AreaTriggerTypes.Box: case AreaTriggerTypes.Box:
return MathF.Sqrt(BoxDatas.Extents[0] * BoxDatas.Extents[0] + BoxDatas.Extents[1] * BoxDatas.Extents[1]); return MathF.Sqrt(Math.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 AreaTriggerTypes.Cylinder: case AreaTriggerTypes.Cylinder:
return Math.Max(CylinderDatas.Radius, CylinderDatas.RadiusTarget); return Math.Max(CylinderDatas.Radius, CylinderDatas.RadiusTarget);
case AreaTriggerTypes.Disk: case AreaTriggerTypes.Disk:
return Math.Max(DiskDatas.OuterRadius, DiskDatas.OuterRadiusTarget); return Math.Max(DiskDatas.OuterRadius, DiskDatas.OuterRadiusTarget);
case AreaTriggerTypes.BoundedPlane: case AreaTriggerTypes.BoundedPlane:
return MathF.Sqrt(BoundedPlaneDatas.Extents[0] * BoundedPlaneDatas.Extents[0] / 4 + BoundedPlaneDatas.Extents[1] * BoundedPlaneDatas.Extents[1] / 4); return MathF.Sqrt(Math.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));
} }
return 0.0f; return 0.0f;
@@ -246,20 +248,18 @@ namespace Game.Entities
Position center = new(0.0f, 0.0f); Position center = new(0.0f, 0.0f);
float maxSearchRadius = 0.0f; float maxSearchRadius = 0.0f;
foreach (var vertice in PolygonVertices) foreach (var vertex in PolygonVertices)
{ maxSearchRadius = Math.Max(maxSearchRadius, center.GetExactDist2d(vertex.X, vertex.Y));
float pointDist = center.GetExactDist2d(vertice.X, vertice.Y);
if (pointDist > maxSearchRadius) foreach (var vertex in PolygonVerticesTarget)
maxSearchRadius = pointDist; maxSearchRadius = Math.Max(maxSearchRadius, center.GetExactDist2d(vertex.X, vertex.Y));
}
return maxSearchRadius; return maxSearchRadius;
} }
return Shape.GetMaxSearchRadius(); return Shape.GetMaxSearchRadius();
} }
public uint Id; public uint Id;
public AreaTriggerTemplate Template; public AreaTriggerTemplate Template;
+1 -1
View File
@@ -574,7 +574,7 @@ namespace Game.Entities
// *data << *areaTrigger.GetMovementScript(); // AreaTriggerMovementScriptInfo // *data << *areaTrigger.GetMovementScript(); // AreaTriggerMovementScriptInfo
if (hasOrbit) if (hasOrbit)
areaTrigger.GetCircularMovementInfo().Write(data); areaTrigger.GetOrbit().Write(data);
} }
if (flags.GameObject) if (flags.GameObject)
+3 -8
View File
@@ -108,7 +108,8 @@ namespace Game.Entities
ASSERT(m_ownedAuras.empty()); ASSERT(m_ownedAuras.empty());
ASSERT(m_removedAuras.empty()); ASSERT(m_removedAuras.empty());
ASSERT(m_gameObj.empty()); ASSERT(m_gameObj.empty());
ASSERT(m_dynObj.empty());*/ ASSERT(m_dynObj.empty());
ASSERT(m_areaTrigger.empty());*/
base.Dispose(); base.Dispose();
} }
@@ -813,9 +814,6 @@ namespace Game.Entities
public void RemoveAreaTrigger(uint spellId) public void RemoveAreaTrigger(uint spellId)
{ {
if (m_areaTrigger.Empty())
return;
for (var i = 0; i < m_areaTrigger.Count; ++i) for (var i = 0; i < m_areaTrigger.Count; ++i)
{ {
AreaTrigger areaTrigger = m_areaTrigger[i]; AreaTrigger areaTrigger = m_areaTrigger[i];
@@ -826,9 +824,6 @@ namespace Game.Entities
public void RemoveAreaTrigger(AuraEffect aurEff) public void RemoveAreaTrigger(AuraEffect aurEff)
{ {
if (m_areaTrigger.Empty())
return;
foreach (AreaTrigger areaTrigger in m_areaTrigger) foreach (AreaTrigger areaTrigger in m_areaTrigger)
{ {
if (areaTrigger.GetAuraEffect() == aurEff) if (areaTrigger.GetAuraEffect() == aurEff)
@@ -842,7 +837,7 @@ namespace Game.Entities
public void RemoveAllAreaTriggers() public void RemoveAllAreaTriggers()
{ {
while (!m_areaTrigger.Empty()) while (!m_areaTrigger.Empty())
m_areaTrigger[0].Remove(); m_areaTrigger.Last()?.Remove();
} }
public NPCFlags GetNpcFlags() { return (NPCFlags)m_unitData.NpcFlags[0]; } public NPCFlags GetNpcFlags() { return (NPCFlags)m_unitData.NpcFlags[0]; }