fix: sleep emoji, invention history race condition, and gathering stuck state
- Add persistent 💤 emoji over sleeping NPCs (tracks sprite position) - Buffer history events (inventions, narration, stockpile) in SocketClient to fix race condition where data arrived before GameScene handlers registered - Fix NPCs getting stuck on 'gather' goal: tree trunks are both obstacles and resource tiles, so pathfinding always failed. Now findNearestResource returns adjacent walkable tiles for non-walkable resources, and gatheringSystem checks adjacent tiles. Added wander fallback when pathfinding to any gather target fails. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -57,10 +57,13 @@ export function gatheringSystem(world: World, map: GameMap): void {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not yet gathering — check if at resource tile and idle
|
||||
// Not yet gathering — check if at or adjacent to resource tile and idle
|
||||
if (movement.state !== 'idle') continue;
|
||||
|
||||
const resourceTile = map.resourceTiles.find(r => r.x === pos.x && r.y === pos.y);
|
||||
const resourceTile = map.resourceTiles.find(r => r.x === pos.x && r.y === pos.y)
|
||||
?? map.resourceTiles.find(r =>
|
||||
Math.abs(r.x - pos.x) + Math.abs(r.y - pos.y) === 1 && !map.isWalkable(r.x, r.y)
|
||||
);
|
||||
if (!resourceTile) continue;
|
||||
|
||||
// Start gathering
|
||||
|
||||
@@ -16,13 +16,22 @@ import type { PickupState } from './pickupSystem.js';
|
||||
function findNearestResource(map: GameMap, from: Position): Position | null {
|
||||
const tiles = map.resourceTiles;
|
||||
if (tiles.length === 0) return null;
|
||||
let best = tiles[0];
|
||||
let bestDist = Math.abs(from.x - best.x) + Math.abs(from.y - best.y);
|
||||
for (let i = 1; i < tiles.length; i++) {
|
||||
const d = Math.abs(from.x - tiles[i].x) + Math.abs(from.y - tiles[i].y);
|
||||
if (d < bestDist) { best = tiles[i]; bestDist = d; }
|
||||
|
||||
// Sort by distance so we try closest first
|
||||
const sorted = [...tiles].sort((a, b) =>
|
||||
(Math.abs(from.x - a.x) + Math.abs(from.y - a.y)) -
|
||||
(Math.abs(from.x - b.x) + Math.abs(from.y - b.y))
|
||||
);
|
||||
|
||||
for (const tile of sorted) {
|
||||
if (map.isWalkable(tile.x, tile.y)) {
|
||||
return { x: tile.x, y: tile.y };
|
||||
}
|
||||
// Resource is on a non-walkable tile (e.g. tree trunk) — find adjacent walkable tile
|
||||
const adjacent = map.findNearestWalkable(tile.x, tile.y, 1);
|
||||
if (adjacent) return adjacent;
|
||||
}
|
||||
return { x: best.x, y: best.y };
|
||||
return null;
|
||||
}
|
||||
|
||||
function isNighttime(gameTime: number): boolean {
|
||||
@@ -196,6 +205,17 @@ export function npcBrainSystem(world: World, map: GameMap, gameTime: number, eve
|
||||
movement.target = target;
|
||||
movement.path = path;
|
||||
movement.direction = directionTo(pos, path[0]);
|
||||
} else if (goal === 'gather') {
|
||||
// Can't reach any resource — fall back to wander
|
||||
brain.currentGoal = 'wander';
|
||||
const wanderTarget = map.getRandomWalkable();
|
||||
const wanderPath = findPath(map, pos, wanderTarget);
|
||||
if (wanderPath && wanderPath.length > 0) {
|
||||
movement.state = 'walking';
|
||||
movement.target = wanderTarget;
|
||||
movement.path = wanderPath;
|
||||
movement.direction = directionTo(pos, wanderPath[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user