From a01d4abdf78d55e7bc33efcf5410b08585be6d44 Mon Sep 17 00:00:00 2001 From: Peter Stockings Date: Mon, 5 Jan 2026 21:32:18 +1100 Subject: [PATCH] Make grass block vision --- src/core/terrain.ts | 8 +++++++- src/engine/__tests__/simulation.test.ts | 4 ++-- src/engine/simulation/simulation.ts | 8 +++++--- src/rendering/FovManager.ts | 6 ++++-- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/core/terrain.ts b/src/core/terrain.ts index d319230..dc9d408 100644 --- a/src/core/terrain.ts +++ b/src/core/terrain.ts @@ -16,13 +16,14 @@ export interface TileBehavior { isBlocking: boolean; isDestructible: boolean; isDestructibleByWalk?: boolean; + blocksVision?: boolean; destructsTo?: TileType; } export const TILE_DEFINITIONS: Record = { [TileType.EMPTY]: { id: TileType.EMPTY, isBlocking: false, isDestructible: false }, [TileType.WALL]: { id: TileType.WALL, isBlocking: true, isDestructible: false }, - [TileType.GRASS]: { id: TileType.GRASS, isBlocking: false, isDestructible: true, isDestructibleByWalk: true, destructsTo: TileType.GRASS_SAPLINGS }, + [TileType.GRASS]: { id: TileType.GRASS, isBlocking: false, isDestructible: true, isDestructibleByWalk: true, blocksVision: true, destructsTo: TileType.GRASS_SAPLINGS }, [TileType.GRASS_SAPLINGS]: { id: TileType.GRASS_SAPLINGS, isBlocking: false, isDestructible: false }, [TileType.EMPTY_DECO]: { id: TileType.EMPTY_DECO, isBlocking: false, isDestructible: false }, [TileType.WALL_DECO]: { id: TileType.WALL_DECO, isBlocking: true, isDestructible: false }, @@ -45,6 +46,11 @@ export function isDestructibleByWalk(tile: number): boolean { return def ? !!def.isDestructibleByWalk : false; } +export function blocksSight(tile: number): boolean { + const def = TILE_DEFINITIONS[tile]; + return def ? (def.isBlocking || !!def.blocksVision) : false; +} + export function getDestructionResult(tile: number): number | undefined { const def = TILE_DEFINITIONS[tile]; return def ? def.destructsTo : undefined; diff --git a/src/engine/__tests__/simulation.test.ts b/src/engine/__tests__/simulation.test.ts index 0a16cd9..76fac28 100644 --- a/src/engine/__tests__/simulation.test.ts +++ b/src/engine/__tests__/simulation.test.ts @@ -82,8 +82,8 @@ describe('Combat Simulation', () => { const player = world.actors.get(1); expect(player!.pos).toEqual({ x: 4, y: 3 }); - // Tile should effectively be destroyed (turned to empty/1) - expect(world.tiles[grassIdx]).toBe(1); // TileType.EMPTY + // Tile should effectively be destroyed (turned to saplings/2) + expect(world.tiles[grassIdx]).toBe(2); // TileType.GRASS_SAPLINGS }); }); diff --git a/src/engine/simulation/simulation.ts b/src/engine/simulation/simulation.ts index 2c5f011..61a3285 100644 --- a/src/engine/simulation/simulation.ts +++ b/src/engine/simulation/simulation.ts @@ -1,7 +1,7 @@ import type { World, EntityId, Action, SimEvent, Actor, CombatantActor, CollectibleActor, ActorType } from "../../core/types"; -import { isBlocked, inBounds, isWall, tryDestructTile } from "../world/world-logic"; -import { isDestructibleByWalk } from "../../core/terrain"; +import { isBlocked, inBounds, tryDestructTile } from "../world/world-logic"; +import { isDestructibleByWalk, blocksSight } from "../../core/terrain"; import { findPathAStar } from "../world/pathfinding"; import { GAME_CONFIG } from "../../core/config/GameConfig"; import { type EntityManager } from "../EntityManager"; @@ -240,9 +240,11 @@ function canEnemySeePlayer(w: World, enemy: CombatantActor, player: CombatantAct const viewRadius = 8; // Enemy vision range let canSee = false; + const fov = new FOV.PreciseShadowcasting((x: number, y: number) => { if (!inBounds(w, x, y)) return false; - return !isWall(w, x, y); + const idx = y * w.width + x; + return !blocksSight(w.tiles[idx]); }); fov.compute(enemy.pos.x, enemy.pos.y, viewRadius, (x: number, y: number) => { diff --git a/src/rendering/FovManager.ts b/src/rendering/FovManager.ts index 4dfb161..e4710e6 100644 --- a/src/rendering/FovManager.ts +++ b/src/rendering/FovManager.ts @@ -1,6 +1,7 @@ import { FOV } from "rot-js"; import { type World, type EntityId } from "../core/types"; -import { idx, inBounds, isWall } from "../engine/world/world-logic"; +import { idx, inBounds } from "../engine/world/world-logic"; +import { blocksSight } from "../core/terrain"; import { GAME_CONFIG } from "../core/config/GameConfig"; import Phaser from "phaser"; @@ -21,7 +22,8 @@ export class FovManager { this.fov = new FOV.PreciseShadowcasting((x: number, y: number) => { if (!inBounds(world, x, y)) return false; - return !isWall(world, x, y); + const idx = y * world.width + x; + return !blocksSight(world.tiles[idx]); }); }