Exact source used by this build. SHA-256: 2b4e87277afb7ffa9e6f037a044a751d2a064da2e3da0261107ccacbe44715ca.

1 import type { Area, Player, Tile, TilePosition, WorldState } from "./types";
2 
3 export function tileIndex(area: Pick<Area, "width" | "height">, x: number, y: number): number | null {
4   if (!Number.isInteger(x) || !Number.isInteger(y) || x < 0 || y < 0 || x >= area.width || y >= area.height) return null;
5   return y * area.width + x;
6 }
7 export function target(state: WorldState, player: Player, position: TilePosition): { area: Area; index: number; tile: Tile } | null {
8   const area = state.areas[player.areaId];
9   if (!area) return null;
10   const index = tileIndex(area, position.x, position.y);
11   const tile = index === null ? undefined : area.tiles[index];
12   return index === null || !tile ? null : { area, index, tile };
13 }
14 export function inToolRange(player: Player, position: TilePosition): boolean {
15   return Math.hypot(player.x - position.x, player.y - position.y) <= 1.75;
16 }
17 export function withTile(state: WorldState, area: Area, index: number, tile: Tile): WorldState {
18   const tiles = area.tiles.slice(); tiles[index] = tile;
19   return { ...state, revision: state.revision + 1, areas: { ...state.areas, [area.id]: { ...area, tiles } } };
20 }
21 export function withPlayer(state: WorldState, player: Player): WorldState {
22   return { ...state, revision: state.revision + 1, players: { ...state.players, [player.id]: player } };
23 }
24 export function withInventory(player: Player, id: string, delta: number): Player {
25   const next = Math.max(0, (player.inventory[id] ?? 0) + delta);
26   const inventory = { ...player.inventory };
27   if (next === 0) delete inventory[id]; else inventory[id] = next;
28   return { ...player, inventory };
29 }
30