namespace Theriapolis.Core.Tactical; /// /// Integer (cx, cy) key for a tactical chunk. The chunk covers world-pixel /// rectangle [cx*CHUNK_SIZE, cy*CHUNK_SIZE, (cx+1)*CHUNK_SIZE, (cy+1)*CHUNK_SIZE). /// At the current constants (CHUNK_SIZE = 64, TACTICAL_PER_WORLD_TILE = 32), /// each chunk covers 2×2 world tiles. /// public readonly struct ChunkCoord : IEquatable { public readonly int X; public readonly int Y; public ChunkCoord(int x, int y) { X = x; Y = y; } /// Chunk that contains the given tactical-tile (world-pixel) coordinate. public static ChunkCoord ForTactical(int tx, int ty) => new(FloorDiv(tx, C.TACTICAL_CHUNK_SIZE), FloorDiv(ty, C.TACTICAL_CHUNK_SIZE)); /// Chunk that contains the given world-tile coordinate. public static ChunkCoord ForWorldTile(int wx, int wy) { // 1 world tile = TACTICAL_PER_WORLD_TILE world pixels = TACTICAL_PER_WORLD_TILE // tactical tiles. One chunk covers CHUNK_SIZE / TACTICAL_PER_WORLD_TILE world tiles. int worldTilesPerChunk = C.TACTICAL_CHUNK_SIZE / C.TACTICAL_PER_WORLD_TILE; return new(FloorDiv(wx, worldTilesPerChunk), FloorDiv(wy, worldTilesPerChunk)); } private static int FloorDiv(int a, int b) { int q = a / b; if ((a ^ b) < 0 && q * b != a) q--; return q; } public bool Equals(ChunkCoord other) => X == other.X && Y == other.Y; public override bool Equals(object? obj) => obj is ChunkCoord c && Equals(c); public override int GetHashCode() => HashCode.Combine(X, Y); public static bool operator ==(ChunkCoord a, ChunkCoord b) => a.Equals(b); public static bool operator !=(ChunkCoord a, ChunkCoord b) => !a.Equals(b); public override string ToString() => $"({X},{Y})"; }