64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
import type { World } from "../../core/types";
|
|
import { isBlocking, isDestructible, getDestructionResult } from "../../core/terrain";
|
|
import { type EntityAccessor } from "../EntityAccessor";
|
|
|
|
|
|
export function inBounds(w: World, x: number, y: number): boolean {
|
|
return x >= 0 && y >= 0 && x < w.width && y < w.height;
|
|
}
|
|
|
|
export function idx(w: World, x: number, y: number): number {
|
|
return y * w.width + x;
|
|
}
|
|
|
|
export function isWall(w: World, x: number, y: number): boolean {
|
|
// Alias for isBlocking for backward compatibility
|
|
return isBlockingTile(w, x, y);
|
|
}
|
|
|
|
export function isBlockingTile(w: World, x: number, y: number): boolean {
|
|
const tile = w.tiles[idx(w, x, y)];
|
|
return isBlocking(tile);
|
|
}
|
|
|
|
export function tryDestructTile(w: World, x: number, y: number): boolean {
|
|
if (!inBounds(w, x, y)) return false;
|
|
|
|
const i = idx(w, x, y);
|
|
const tile = w.tiles[i];
|
|
|
|
if (isDestructible(tile)) {
|
|
const nextTile = getDestructionResult(tile);
|
|
if (nextTile !== undefined) {
|
|
w.tiles[i] = nextTile;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export function isBlocked(w: World, x: number, y: number, accessor: EntityAccessor | undefined): boolean {
|
|
if (!inBounds(w, x, y)) return true;
|
|
if (isBlockingTile(w, x, y)) return true;
|
|
|
|
if (!accessor) return false;
|
|
const actors = accessor.getActorsAt(x, y);
|
|
if (actors.some(a => a.category === "combatant")) return true;
|
|
|
|
// Check for interactable entities (switches, etc.) that should block movement
|
|
if (accessor.context) {
|
|
const ecs = accessor.context;
|
|
const isInteractable = ecs.getEntitiesWith("position", "trigger").some(id => {
|
|
const p = ecs.getComponent(id, "position");
|
|
const t = ecs.getComponent(id, "trigger");
|
|
return p?.x === x && p?.y === y && t?.onInteract;
|
|
});
|
|
if (isInteractable) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|