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
@@ -1069,6 +1069,8 @@ export const JOHTO = {
|
||||
FindPartyMonThatSpecies: 0xc276,
|
||||
PlayCurMonCry: 0xc472,
|
||||
GiveDratini: 0x8b170,
|
||||
BeastsCheck: 0x4a6e8,
|
||||
MonCheck: 0x4a711,
|
||||
"GiveDratini.Movesets": 0x8b1c4,
|
||||
MoveDeletion: 0x2c547,
|
||||
"MoveDeletion.DeleterIntroText": 0x2c5ef,
|
||||
@@ -1328,6 +1330,24 @@ export const NATIVE_MAPS: Record<string, string> = {
|
||||
"3:58": "Mt. Mortar",
|
||||
"3:59": "Mt. Mortar 2F",
|
||||
"3:60": "Mt. Mortar B1F",
|
||||
"3:4": "Tin Tower 1F",
|
||||
"3:5": "Tin Tower 2F",
|
||||
"3:6": "Tin Tower 3F",
|
||||
"3:7": "Tin Tower 4F",
|
||||
"3:8": "Tin Tower 5F",
|
||||
"3:9": "Tin Tower 6F",
|
||||
"3:10": "Tin Tower 7F",
|
||||
"3:11": "Tin Tower 8F",
|
||||
"3:12": "Tin Tower 9F",
|
||||
"15:12": "Tin Tower roof",
|
||||
"3:66": "Whirl Islands",
|
||||
"3:67": "Whirl Islands",
|
||||
"3:68": "Whirl Islands",
|
||||
"3:69": "Whirl Islands",
|
||||
"3:70": "Whirl Islands",
|
||||
"3:71": "Whirl Islands B1F",
|
||||
"3:72": "Whirl Islands B2F",
|
||||
"3:73": "Lugia’s chamber",
|
||||
"3:61": "Ice Path 1F",
|
||||
"3:62": "Ice Path B1F",
|
||||
"3:63": "Ice Path B2F",
|
||||
|
||||
@@ -73,6 +73,7 @@ import { displayUnownWords, hoOhChamber, omanyteChamber } from "./ruins";
|
||||
import { slotMachine } from "./slot-machine";
|
||||
import { cardFlip } from "./card-flip";
|
||||
import { giveDratini, moveDeletion } from "./blackthorn";
|
||||
import { beastsCheck, monCheck } from "./tin-tower";
|
||||
import {
|
||||
checkMagikarpLength,
|
||||
findPartyMonThatSpecies,
|
||||
@@ -3426,6 +3427,10 @@ export class ScriptRun {
|
||||
this.specialContext(pages, take),
|
||||
this.state.magikarpRecord,
|
||||
);
|
||||
case JOHTO.MonCheck:
|
||||
return monCheck(this.specialContext(pages, take), value);
|
||||
case JOHTO.BeastsCheck:
|
||||
return beastsCheck(this.specialContext(pages, take));
|
||||
case JOHTO.GiveDratini:
|
||||
giveDratini(this.specialContext(pages, take), value);
|
||||
return value;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import type { SpecialContext } from "./special-context";
|
||||
|
||||
const RAIKOU = 243,
|
||||
ENTEI = 244,
|
||||
SUICUNE = 245;
|
||||
|
||||
/** CheckOwnMon's OT comparison: the first five characters, stopping at a
|
||||
* terminator both names share (NAME_LENGTH_JAPANESE - 2 compares, then
|
||||
* one more). */
|
||||
const sameOT = (ot: string, player: string) => {
|
||||
const a = `${ot}@`,
|
||||
b = `${player}@`;
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (a[i] !== b[i]) return false;
|
||||
if (a[i] === "@") return true;
|
||||
}
|
||||
return a[4] === b[4];
|
||||
};
|
||||
|
||||
/** CheckOwnMonAnywhere (engine/pokemon/search_owned.asm): a Pokémon of
|
||||
* `species` with the player's ID and OT in the party or a box. An empty
|
||||
* party finds nothing; the Day-Care is not searched. The party struct's
|
||||
* species is read, so an Egg counts as its species. */
|
||||
export function ownsMon(c: SpecialContext, species: number) {
|
||||
const { party, storage } = c.state;
|
||||
if (!party.length) return false;
|
||||
const player = c.player();
|
||||
const owns = (mon: { species: number; otId: number; ot: string }) =>
|
||||
mon.species === species && mon.otId === player.id && sameOT(mon.ot, player.name);
|
||||
return party.some(owns) || storage.boxes.some((box) => box.some(owns));
|
||||
}
|
||||
|
||||
/** MonCheck: 1 when the player owns a Pokémon of the species. */
|
||||
export const monCheck = (c: SpecialContext, species: number) =>
|
||||
ownsMon(c, species) ? 1 : 0;
|
||||
|
||||
/** BeastsCheck: 1 when the player owns Raikou, Entei and Suicune. */
|
||||
export const beastsCheck = (c: SpecialContext) =>
|
||||
[RAIKOU, ENTEI, SUICUNE].every((species) => ownsMon(c, species)) ? 1 : 0;
|
||||
Reference in new issue
Block a user