Initial commit: Theriapolis baseline at port/godot branch point
Captures the pre-Godot-port state of the codebase. This is the rollback anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md). All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
namespace Theriapolis.Core.Util;
|
||||
|
||||
/// <summary>
|
||||
/// Direction encoding for tile-level features (rivers, rail, roads).
|
||||
/// Directions are stored as byte values 0–7, matching the 8 compass points.
|
||||
/// 255 = "no direction" / unset.
|
||||
/// </summary>
|
||||
public static class Dir
|
||||
{
|
||||
// Direction constants (0-based, CCW from North)
|
||||
public const byte None = 255;
|
||||
public const byte N = 0; // (dx= 0, dy=-1)
|
||||
public const byte NE = 1; // (dx= 1, dy=-1)
|
||||
public const byte E = 2; // (dx= 1, dy= 0)
|
||||
public const byte SE = 3; // (dx= 1, dy= 1)
|
||||
public const byte S = 4; // (dx= 0, dy= 1)
|
||||
public const byte SW = 5; // (dx=-1, dy= 1)
|
||||
public const byte W = 6; // (dx=-1, dy= 0)
|
||||
public const byte NW = 7; // (dx=-1, dy=-1)
|
||||
|
||||
private static readonly (int dx, int dy)[] _deltas =
|
||||
{
|
||||
( 0,-1), ( 1,-1), ( 1, 0), ( 1, 1),
|
||||
( 0, 1), (-1, 1), (-1, 0), (-1,-1),
|
||||
};
|
||||
|
||||
/// <summary>Convert a (dx, dy) delta to a direction byte. Both values must be in {-1,0,1}.</summary>
|
||||
public static byte FromDelta(int dx, int dy)
|
||||
{
|
||||
for (byte i = 0; i < 8; i++)
|
||||
if (_deltas[i].dx == dx && _deltas[i].dy == dy)
|
||||
return i;
|
||||
return None;
|
||||
}
|
||||
|
||||
public static (int dx, int dy) ToDelta(byte dir)
|
||||
{
|
||||
if (dir == None) return (0, 0);
|
||||
return _deltas[dir & 7];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Two directions are parallel if their angular difference is ≤ 45° (including opposite directions).
|
||||
/// </summary>
|
||||
public static bool IsParallel(byte a, byte b)
|
||||
{
|
||||
if (a == None || b == None) return false;
|
||||
int diff = Math.Abs((int)(a & 7) - (int)(b & 7));
|
||||
diff = Math.Min(diff, 8 - diff);
|
||||
// diff 0 = same; diff 1 = 45°; diff 4 = 180° (opposite still parallel)
|
||||
return diff <= 1 || diff >= 3; // ≤45° or ≥135° (anti-parallel)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Two directions are perpendicular if their angular difference is in [60°, 120°].
|
||||
/// Using discrete 45° steps: diff 2 = 90°.
|
||||
/// </summary>
|
||||
public static bool IsPerpendicular(byte a, byte b)
|
||||
{
|
||||
if (a == None || b == None) return false;
|
||||
int diff = Math.Abs((int)(a & 7) - (int)(b & 7));
|
||||
diff = Math.Min(diff, 8 - diff);
|
||||
return diff == 2;
|
||||
}
|
||||
|
||||
/// <summary>Opposite direction.</summary>
|
||||
public static byte Opposite(byte d) => d == None ? None : (byte)((d + 4) & 7);
|
||||
}
|
||||
Reference in New Issue
Block a user