Fixed door saying open bugs
This commit is contained in:
126
src/engine/__tests__/DoorWalkthrough.test.ts
Normal file
126
src/engine/__tests__/DoorWalkthrough.test.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { applyAction } from '../simulation/simulation';
|
||||
import { type World, type Actor, type EntityId } from '../../core/types';
|
||||
import { EntityAccessor } from '../EntityAccessor';
|
||||
import { ECSWorld } from '../ecs/World';
|
||||
import { TileType } from '../../core/terrain';
|
||||
|
||||
const createTestWorld = (): World => {
|
||||
return {
|
||||
width: 10,
|
||||
height: 10,
|
||||
tiles: new Array(100).fill(TileType.EMPTY),
|
||||
exit: { x: 9, y: 9 },
|
||||
trackPath: []
|
||||
};
|
||||
};
|
||||
|
||||
describe('Multi-step Door Walkthrough Bug', () => {
|
||||
let ecsWorld: ECSWorld;
|
||||
let world: World;
|
||||
|
||||
beforeEach(() => {
|
||||
ecsWorld = new ECSWorld();
|
||||
world = createTestWorld();
|
||||
});
|
||||
|
||||
it('door should close after player walks through and moves away', () => {
|
||||
const playerId = 1 as EntityId;
|
||||
const player: Actor = {
|
||||
id: playerId, category: "combatant", isPlayer: true, type: "player", pos: { x: 3, y: 3 }, speed: 100, stats: { hp: 10, maxHp: 10 } as any, energy: 0
|
||||
} as any;
|
||||
|
||||
ecsWorld.addComponent(playerId, "position", player.pos);
|
||||
ecsWorld.addComponent(playerId, "player", {});
|
||||
ecsWorld.addComponent(playerId, "stats", { hp: 10, maxHp: 10 } as any);
|
||||
ecsWorld.addComponent(playerId, "actorType", { type: "player" });
|
||||
ecsWorld.addComponent(playerId, "energy", { current: 0, speed: 100 });
|
||||
|
||||
const accessor = new EntityAccessor(world, playerId, ecsWorld);
|
||||
|
||||
// Place a closed door at (4,3)
|
||||
const doorIdx = 3 * 10 + 4;
|
||||
world.tiles[doorIdx] = TileType.DOOR_CLOSED;
|
||||
|
||||
// 1. Move onto the door
|
||||
console.log("Step 1: Moving onto door at (4,3)");
|
||||
applyAction(world, playerId, { type: "move", dx: 1, dy: 0 }, accessor);
|
||||
expect(player.pos).toEqual({ x: 4, y: 3 });
|
||||
expect(world.tiles[doorIdx]).toBe(TileType.DOOR_OPEN);
|
||||
|
||||
// 2. Move off the door to (5,3)
|
||||
console.log("Step 2: Moving off door to (5,3)");
|
||||
applyAction(world, playerId, { type: "move", dx: 1, dy: 0 }, accessor);
|
||||
expect(player.pos).toEqual({ x: 5, y: 3 });
|
||||
|
||||
// This is where it's reported to stay open sometimes
|
||||
console.log("Door tile state after Step 2:", world.tiles[doorIdx]);
|
||||
expect(world.tiles[doorIdx]).toBe(TileType.DOOR_CLOSED);
|
||||
|
||||
// 3. Move further away to (6,3)
|
||||
console.log("Step 3: Moving further away to (6,3)");
|
||||
applyAction(world, playerId, { type: "move", dx: 1, dy: 0 }, accessor);
|
||||
expect(player.pos).toEqual({ x: 6, y: 3 });
|
||||
expect(world.tiles[doorIdx]).toBe(TileType.DOOR_CLOSED);
|
||||
});
|
||||
|
||||
it('door should close after player walks through it diagonally', () => {
|
||||
const playerId = 1 as EntityId;
|
||||
const player: Actor = {
|
||||
id: playerId, category: "combatant", isPlayer: true, type: "player", pos: { x: 3, y: 3 }, speed: 100, stats: { hp: 10, maxHp: 10 } as any, energy: 0
|
||||
} as any;
|
||||
|
||||
ecsWorld.addComponent(playerId, "position", player.pos);
|
||||
ecsWorld.addComponent(playerId, "player", {});
|
||||
ecsWorld.addComponent(playerId, "stats", { hp: 10, maxHp: 10 } as any);
|
||||
ecsWorld.addComponent(playerId, "actorType", { type: "player" });
|
||||
ecsWorld.addComponent(playerId, "energy", { current: 0, speed: 100 });
|
||||
|
||||
const accessor = new EntityAccessor(world, playerId, ecsWorld);
|
||||
|
||||
// Place a closed door at (4,4)
|
||||
const doorIdx = 4 * 10 + 4;
|
||||
world.tiles[doorIdx] = TileType.DOOR_CLOSED;
|
||||
|
||||
// 1. Move onto the door diagonally
|
||||
applyAction(world, playerId, { type: "move", dx: 1, dy: 1 }, accessor);
|
||||
expect(player.pos).toEqual({ x: 4, y: 4 });
|
||||
expect(world.tiles[doorIdx]).toBe(TileType.DOOR_OPEN);
|
||||
|
||||
// 2. Move off the door diagonally to (5,5)
|
||||
applyAction(world, playerId, { type: "move", dx: 1, dy: 1 }, accessor);
|
||||
expect(player.pos).toEqual({ x: 5, y: 5 });
|
||||
|
||||
expect(world.tiles[doorIdx]).toBe(TileType.DOOR_CLOSED);
|
||||
});
|
||||
|
||||
it('door should stay open while player is standing on it (wait action)', () => {
|
||||
const playerId = 1 as EntityId;
|
||||
const player: Actor = {
|
||||
id: playerId, category: "combatant", isPlayer: true, type: "player", pos: { x: 3, y: 3 }, speed: 100, stats: { hp: 10, maxHp: 10 } as any, energy: 0
|
||||
} as any;
|
||||
|
||||
ecsWorld.addComponent(playerId, "position", player.pos);
|
||||
ecsWorld.addComponent(playerId, "player", {});
|
||||
ecsWorld.addComponent(playerId, "stats", { hp: 10, maxHp: 10 } as any);
|
||||
ecsWorld.addComponent(playerId, "actorType", { type: "player" });
|
||||
ecsWorld.addComponent(playerId, "energy", { current: 0, speed: 100 });
|
||||
|
||||
const accessor = new EntityAccessor(world, playerId, ecsWorld);
|
||||
|
||||
// Place a closed door at (4,3)
|
||||
const doorIdx = 3 * 10 + 4;
|
||||
world.tiles[doorIdx] = TileType.DOOR_CLOSED;
|
||||
|
||||
// 1. Move onto the door
|
||||
applyAction(world, playerId, { type: "move", dx: 1, dy: 0 }, accessor);
|
||||
expect(player.pos).toEqual({ x: 4, y: 3 });
|
||||
expect(world.tiles[doorIdx]).toBe(TileType.DOOR_OPEN);
|
||||
|
||||
// 2. Wait on the door
|
||||
applyAction(world, playerId, { type: "wait" }, accessor);
|
||||
expect(player.pos).toEqual({ x: 4, y: 3 });
|
||||
expect(world.tiles[doorIdx]).toBe(TileType.DOOR_OPEN);
|
||||
});
|
||||
});
|
||||
@@ -119,7 +119,10 @@ function handleMove(w: World, actor: Actor, action: { dx: number; dy: number },
|
||||
if (w.tiles[fromIdx] === TileType.DOOR_OPEN) {
|
||||
const actorsLeft = accessor.getActorsAt(from.x, from.y);
|
||||
if (actorsLeft.length === 0) {
|
||||
console.log(`[simulation] Closing door at ${from.x},${from.y} - Actor ${actor.id} left`);
|
||||
w.tiles[fromIdx] = TileType.DOOR_CLOSED;
|
||||
} else {
|
||||
console.log(`[simulation] Door at ${from.x},${from.y} stays open - ${actorsLeft.length} actors remain`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -238,9 +238,7 @@ export class DungeonRenderer {
|
||||
|
||||
// Sync visual tile with logical tile (e.g. if grass was destroyed)
|
||||
if (tile.index !== worldTile) {
|
||||
// We can safely update the index property for basic tile switching
|
||||
// If we needed to change collision properties, we'd use putTileAt
|
||||
tile.index = worldTile;
|
||||
this.layer!.putTileAt(worldTile, tile.x, tile.y);
|
||||
}
|
||||
|
||||
const isSeen = seen[i] === 1;
|
||||
|
||||
Reference in New Issue
Block a user