Open Tin Tower and Whirl Islands: Suicune, Ho-Oh and Lugia (#32)
Tin Tower's floors and roof and the Whirl Islands are open. The Clear Bell gets the player past the sages to Suicune in Tin Tower; after the League, the Rainbow Wing leads up to Ho-Oh, and the Silver Wing to Lugia. New specials: MonCheck and BeastsCheck (CheckOwnMonAnywhere, with its five-letter OT comparison and no Day-Care search). The playthrough driver plans ledge jumps for the later stages, waterfall descents, warp panels and Surf between warps; the run gains two stages, Routes 45 and 46 back to Ecruteak and Tin Tower's Suicune. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9c3579937c
commit
3fbc6798eb
10 files changed
+369
-21
No files matched your search
+59
-9
@@ -134,9 +134,22 @@ function open(
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Where a step in `direction` from (x, y) ends: the next tile, or, on
|
||||
* ice, the last tile of the slide before something blocks it. Undefined
|
||||
* when the step is blocked. */
|
||||
/** .ledge_table: the directions each COLL_HOP_* tile jumps toward. */
|
||||
const LEDGES: readonly (readonly Direction[])[] = [
|
||||
["right"],
|
||||
["left"],
|
||||
["up"],
|
||||
["down"],
|
||||
["down", "right"],
|
||||
["down", "left"],
|
||||
["up", "right"],
|
||||
["up", "left"],
|
||||
];
|
||||
|
||||
/** Where a step in `direction` from (x, y) ends: the next tile, two tiles
|
||||
* on when standing on a ledge that jumps that way (.TryJump), or, on ice,
|
||||
* the last tile of the slide before something blocks it. Undefined when
|
||||
* the step is blocked. */
|
||||
export function landing(
|
||||
world: GameWorld,
|
||||
x: number,
|
||||
@@ -146,10 +159,47 @@ export function landing(
|
||||
water = false,
|
||||
target,
|
||||
whirlpools = false,
|
||||
}: { water?: boolean; target?: { x: number; y: number }; whirlpools?: boolean } = {},
|
||||
ledges = false,
|
||||
}: {
|
||||
water?: boolean;
|
||||
target?: { x: number; y: number };
|
||||
whirlpools?: boolean;
|
||||
ledges?: boolean;
|
||||
} = {},
|
||||
): { x: number; y: number } | undefined {
|
||||
if (!open(world, x, y, direction, water, target, whirlpools)) return undefined;
|
||||
const [, dx, dy] = DIRECTIONS.find(([d]) => d === direction)!;
|
||||
const standing = world.assets.collision(world.map, x, y);
|
||||
if (ledges && (standing & 0xf0) === 0xa0 && LEDGES[standing & 7].includes(direction)) {
|
||||
const lx = x + dx * 2,
|
||||
ly = y + dy * 2;
|
||||
const occupied = (ox: number, oy: number) =>
|
||||
world.objects().some((object) => object.x === ox && object.y === oy);
|
||||
if (
|
||||
lx >= 0 &&
|
||||
ly >= 0 &&
|
||||
lx < world.map.width &&
|
||||
ly < world.map.height &&
|
||||
world.assets.permission(world.assets.collision(world.map, lx, ly)) === 0 &&
|
||||
!occupied(x + dx, y + dy) &&
|
||||
!occupied(lx, ly) &&
|
||||
!(
|
||||
isWarpHazard(world.assets.collision(world.map, lx, ly)) &&
|
||||
world.map.warps.some((warp) => warp.x === lx && warp.y === ly) &&
|
||||
(lx !== target?.x || ly !== target?.y)
|
||||
)
|
||||
)
|
||||
return { x: lx, y: ly };
|
||||
}
|
||||
// COLL_WATERFALL: a surfer entering from above is carried down it.
|
||||
const ahead = world.assets.collision(world.map, x + dx, y + dy);
|
||||
if (water && ahead === 0x33) {
|
||||
if (direction !== "down") return undefined;
|
||||
let fy = y + 1;
|
||||
while (world.assets.collision(world.map, x, fy) === 0x33) fy++;
|
||||
if (!open(world, x, fy - 1, "down", water, target, whirlpools)) return undefined;
|
||||
return { x, y: fy };
|
||||
}
|
||||
if (!open(world, x, y, direction, water, target, whirlpools)) return undefined;
|
||||
x += dx;
|
||||
y += dy;
|
||||
while (
|
||||
@@ -164,13 +214,13 @@ export function landing(
|
||||
|
||||
/** Shortest walkable path on the current map, avoiding other warps.
|
||||
* `water` also crosses open water, for a player who can Surf, and
|
||||
* `whirlpools` the whirlpools a player with Whirlpool can clear; a step
|
||||
* onto ice slides on until blocked. */
|
||||
* `whirlpools` the whirlpools a player with Whirlpool can clear; `ledges`
|
||||
* takes ledge jumps; a step onto ice slides on until blocked. */
|
||||
export function findPath(
|
||||
world: GameWorld,
|
||||
targetX: number,
|
||||
targetY: number,
|
||||
{ water = false, whirlpools = false } = {},
|
||||
{ water = false, whirlpools = false, ledges = false } = {},
|
||||
): Direction[] {
|
||||
const target = { x: targetX, y: targetY };
|
||||
const queue = [{ x: world.x, y: world.y, path: [] as Direction[] }];
|
||||
@@ -182,7 +232,7 @@ export function findPath(
|
||||
visited.add(key);
|
||||
if (node.x === targetX && node.y === targetY) return node.path;
|
||||
for (const [direction] of DIRECTIONS) {
|
||||
const end = landing(world, node.x, node.y, direction, { water, target, whirlpools });
|
||||
const end = landing(world, node.x, node.y, direction, { water, target, whirlpools, ledges });
|
||||
if (end) queue.push({ ...end, path: [...node.path, direction] });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user