using System.Numerics;
using Content.Shared.GameTicking;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
namespace Content.Server.Tabletop
{
public sealed partial class TabletopSystem
{
///
/// Separation between tabletops in the tabletop map.
///
private const int TabletopSeparation = 100;
///
/// Map where all tabletops reside.
///
public MapId TabletopMap { get; private set; } = MapId.Nullspace;
///
/// The number of tabletops created in the map.
/// Used for calculating the position of the next one.
///
private int _tabletops = 0;
///
/// Despite the name, this method is only used to subscribe to events.
///
private void InitializeMap()
{
SubscribeLocalEvent(OnRoundRestart);
}
///
/// Gets the next available position for a tabletop, and increments the tabletop count.
///
///
private Vector2 GetNextTabletopPosition()
{
return UlamSpiral(++_tabletops) * TabletopSeparation;
}
///
/// Ensures that the tabletop map exists. Creates it if it doesn't.
///
private void EnsureTabletopMap()
{
if (TabletopMap != MapId.Nullspace && _map.MapExists(TabletopMap))
return;
var mapUid = _map.CreateMap(out var mapId);
TabletopMap = mapId;
_tabletops = 0;
var mapComp = Comp(mapUid);
// Lighting is always disabled in tabletop world.
mapComp.LightingEnabled = false;
Dirty(mapUid, mapComp);
}
///
/// Algorithm for mapping scalars to 2D positions in the same pattern as an Ulam Spiral.
///
/// Scalar to map to a 2D position. Must be greater than or equal to 1.
/// The mapped 2D position for the scalar.
private Vector2i UlamSpiral(int n)
{
var k = (int)MathF.Ceiling((MathF.Sqrt(n) - 1) / 2);
var t = 2 * k + 1;
var m = (int)MathF.Pow(t, 2);
t--;
if (n >= m - t)
return new Vector2i(k - (m - n), -k);
m -= t;
if (n >= m - t)
return new Vector2i(-k, -k + (m - n));
m -= t;
if (n >= m - t)
return new Vector2i(-k + (m - n), k);
return new Vector2i(k, k - (m - n - t));
}
private void OnRoundRestart(RoundRestartCleanupEvent _)
{
if (TabletopMap == MapId.Nullspace || !_map.MapExists(TabletopMap))
return;
// This will usually *not* be the case, but better make sure.
_map.DeleteMap(TabletopMap);
// Reset tabletop count.
_tabletops = 0;
}
}
}