Implement native opening scenes, battle foundation and overworld movement
Checks / web (push) Canceled after 0s
Checks / web (push) Canceled after 0s
This commit is contained in:
1 parent
8b80d05ca2
commit
c08d250cf6
39 files changed
+10727
-1524
No files matched your search
@@ -0,0 +1,115 @@
|
||||
import type { GameWorld } from "../src/game/world/world";
|
||||
import type { Direction } from "../src/game/world/types";
|
||||
|
||||
/** Drive a world through scenes the way a player would: acknowledge pages,
|
||||
* answer choices in order (default YES / first weekday) and wait out timed
|
||||
* effects. Returns every page that was shown. */
|
||||
export function settle(
|
||||
world: GameWorld,
|
||||
answers: (number | string)[] = [],
|
||||
): string[] {
|
||||
const shown: string[] = [];
|
||||
let lastHeld = "";
|
||||
for (let tick = 0; tick < 20_000; tick++) {
|
||||
const dialogue = world.dialogue;
|
||||
if (dialogue) {
|
||||
const page = dialogue.pages[dialogue.index];
|
||||
const last = dialogue.index === dialogue.pages.length - 1;
|
||||
if (last && dialogue.choice) {
|
||||
shown.push(page);
|
||||
// The naming screen waits for the caller unless a name is queued.
|
||||
if (dialogue.choice.kind === "name") {
|
||||
if (typeof answers[0] !== "string") return shown;
|
||||
world.choose(answers.shift()!);
|
||||
continue;
|
||||
}
|
||||
const answer = answers.shift();
|
||||
world.choose(
|
||||
typeof answer === "number"
|
||||
? answer
|
||||
: dialogue.choice.kind === "yesno"
|
||||
? 1
|
||||
: 0,
|
||||
);
|
||||
} else if (last && dialogue.holdTicks !== undefined) {
|
||||
if (page !== lastHeld) shown.push(page);
|
||||
lastHeld = page;
|
||||
world.tick();
|
||||
} else {
|
||||
shown.push(page);
|
||||
world.advanceDialogue();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
lastHeld = "";
|
||||
if (!world.busy) {
|
||||
// Scene scripts start on an idle tick.
|
||||
world.tick();
|
||||
if (!world.busy) return shown;
|
||||
continue;
|
||||
}
|
||||
world.tick();
|
||||
}
|
||||
throw new Error("The world did not settle.");
|
||||
}
|
||||
|
||||
const DIRECTIONS = [
|
||||
["up", 0, -1],
|
||||
["down", 0, 1],
|
||||
["left", -1, 0],
|
||||
["right", 1, 0],
|
||||
] as const;
|
||||
|
||||
/** Shortest walkable path on the current map, avoiding other warps. */
|
||||
export function findPath(
|
||||
world: GameWorld,
|
||||
targetX: number,
|
||||
targetY: number,
|
||||
): Direction[] {
|
||||
const queue = [{ x: world.x, y: world.y, path: [] as Direction[] }];
|
||||
const visited = new Set<string>();
|
||||
for (let i = 0; i < queue.length; i++) {
|
||||
const node = queue[i],
|
||||
key = `${node.x},${node.y}`;
|
||||
if (visited.has(key)) continue;
|
||||
visited.add(key);
|
||||
if (node.x === targetX && node.y === targetY) return node.path;
|
||||
for (const [direction, dx, dy] of DIRECTIONS) {
|
||||
const x = node.x + dx,
|
||||
y = node.y + dy;
|
||||
if (x < 0 || y < 0 || x >= world.map.width || y >= world.map.height)
|
||||
continue;
|
||||
if (
|
||||
world.assets.permission(world.assets.collision(world.map, x, y)) !== 0
|
||||
)
|
||||
continue;
|
||||
if (world.objects().some((object) => object.x === x && object.y === y))
|
||||
continue;
|
||||
if (
|
||||
world.map.warps.some((warp) => warp.x === x && warp.y === y) &&
|
||||
(x !== targetX || y !== targetY)
|
||||
)
|
||||
continue;
|
||||
queue.push({ x, y, path: [...node.path, direction] });
|
||||
}
|
||||
}
|
||||
throw new Error(`No route to ${targetX},${targetY}`);
|
||||
}
|
||||
|
||||
/** Walk to a tile, settling any scene that a step triggers. */
|
||||
export function walkTo(
|
||||
world: GameWorld,
|
||||
targetX: number,
|
||||
targetY: number,
|
||||
answers: (number | string)[] = [],
|
||||
): string[] {
|
||||
const shown: string[] = [];
|
||||
for (const direction of findPath(world, targetX, targetY)) {
|
||||
if (!world.move(direction))
|
||||
throw new Error(
|
||||
`Blocked moving ${direction} at ${world.x},${world.y}: ${world.notice}`,
|
||||
);
|
||||
shown.push(...settle(world, answers));
|
||||
}
|
||||
return shown;
|
||||
}
|
||||
Reference in new issue
Block a user