using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
namespace Mappy.Data;
/// Single point on the movement trail (Carbonite-style).
public record MovementTrailPoint(uint Territory, uint Map, float X, float Y, double TimeStamp);
/// Config and storage for the movement trail (where you've been on the map).
public class MovementTrailConfig
{
private readonly List _points = [];
private int _nextIndex;
private float _lastX = float.MinValue;
private float _lastY = float.MinValue;
private uint _lastTerritory;
public int MaxPoints { get; set; } = 100;
public float MinDistance { get; set; } = 2f;
public float FadeTimeSeconds { get; set; } = 60f;
public Vector4 TrailColor { get; set; } = new(1f, 0f, 0f, 0.9f); // Red like Carbonite
public IReadOnlyList Points => _points;
private float EffectiveMinDistance => Mappy.System.SystemConfig?.MovementTrailMinDistance ?? MinDistance;
private float EffectiveFadeTime => Mappy.System.SystemConfig?.MovementTrailFadeTimeSeconds ?? FadeTimeSeconds;
private int EffectiveMaxPoints => Mappy.System.SystemConfig?.MovementTrailMaxPoints ?? MaxPoints;
public void Clear()
{
_points.Clear();
_nextIndex = 0;
_lastX = float.MinValue;
_lastY = float.MinValue;
}
/// Record a new trail point if the player has moved enough. Call from Framework.Update.
public void TryAddPoint(uint territory, uint map, float x, float y)
{
// Reset when changing territory
if (territory != _lastTerritory)
{
Clear();
_lastTerritory = territory;
}
var dx = x - _lastX;
var dy = y - _lastY;
var moveDist = MathF.Sqrt(dx * dx + dy * dy);
if (moveDist < EffectiveMinDistance && _lastX > float.MinValue)
return;
_lastX = x;
_lastY = y;
var now = DateTime.UtcNow.Subtract(DateTime.UnixEpoch).TotalSeconds;
var max = EffectiveMaxPoints;
if (_points.Count < max)
{
_points.Add(new MovementTrailPoint(territory, map, x, y, now));
}
else
{
_points[_nextIndex] = new MovementTrailPoint(territory, map, x, y, now);
_nextIndex = (_nextIndex + 1) % max;
}
}
/// Get points for the current map that haven't faded yet.
public IEnumerable GetVisiblePoints(uint territoryId, uint mapId)
{
var now = DateTime.UtcNow.Subtract(DateTime.UnixEpoch).TotalSeconds;
var fade = EffectiveFadeTime;
return _points
.Where(p => p.Territory == territoryId && p.Map == mapId && (now - p.TimeStamp) < fade)
.ToList();
}
}