tests: from the badge, the road to Mt. Moon is not a ring at the Pewter end, and Route 4's doors and sides are the cartridge's
This commit is contained in:
parent
5147ab1a87
commit
d181f952a7
1 changed files with 134 additions and 0 deletions
|
|
@ -3452,3 +3452,137 @@ fn tail_whip_at_its_limit_is_not_dealt_and_a_route_one_battle_is_won() {
|
||||||
);
|
);
|
||||||
assert!(won > 0, "no wild battle was won in {budget} frames: {battles:?}");
|
assert!(won > 0, "no wild battle was won in {budget} frames: {battles:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ROUTE_4: u32 = 0x0f;
|
||||||
|
const MT_MOON_1F: u32 = 0x3b;
|
||||||
|
|
||||||
|
/// A rung-11 checkpoint just after the Boulder Badge, or `None` to skip.
|
||||||
|
///
|
||||||
|
/// Row 59's is the route survey's own: `examples/scene_probe.rs` driven from the row-58 checkpoint
|
||||||
|
/// with `FLY_PROBE_CATCH=route FLY_PROBE_PREFER="GO OBJECTIVE,TALK"` until rung 11, written by
|
||||||
|
/// `FLY_PROBE_SAVE_RANK=11` on the first safe overworld frame -- in the gym, beside BROCK.
|
||||||
|
fn badge_checkpoint() -> Option<flysim::store::Checkpoint> {
|
||||||
|
std::env::var_os("FLY_BADGE_CHECKPOINT").map(|path| {
|
||||||
|
flysim::store::load(std::path::Path::new(&path))
|
||||||
|
.expect("the checkpoint should be a FLYSIM01 envelope")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// From the badge: the fly takes the road to Mt. Moon instead of walking the Pewter end of Route 3.
|
||||||
|
///
|
||||||
|
/// **What the row-58 review measured** (the route survey carried past the badge, 2026-09-23):
|
||||||
|
/// from about frame 68,000, Pewter City (39, 17) and Route 3 (0, 9) in a ring, `GO OBJECTIVE`
|
||||||
|
/// done on Route 3 538 times and `GO ROUTE` done on Pewter 537. The live fly was due to reach
|
||||||
|
/// the same state as soon as it earned the badge.
|
||||||
|
///
|
||||||
|
/// **What was wrong** (`infra/docs/macros-traps.md` row 59), two things stacked:
|
||||||
|
///
|
||||||
|
/// - the map graph had Route 4 east of Route 3 and a Mt. Moon door on Route 3. The headers put
|
||||||
|
/// Route 4 north of Route 3 and both of Mt. Moon's doors on Route 4, so Route 3's north edge,
|
||||||
|
/// the one road to the mountain, named no map and was nobody's first hop; and Route 4's two
|
||||||
|
/// sides, which the mountain cuts apart, were one node;
|
||||||
|
/// - Route 3's first trainer closed his challenge onto five frames of plain overworld before the
|
||||||
|
/// battle was decided, and the walk he interrupted was written as a refusal on the first of
|
||||||
|
/// them: (11, 6), the one gap between the road's west end and the rest of it, walled for the
|
||||||
|
/// session.
|
||||||
|
///
|
||||||
|
/// The claims, none of them about which button the fly presses:
|
||||||
|
///
|
||||||
|
/// - the fly is on **Route 4** and at **Mt. Moon's door** (map `0x3b`) inside the budget;
|
||||||
|
/// - Pewter City and Route 3 are **not a ring**: under forty crossings between them, against
|
||||||
|
/// over a thousand on the base.
|
||||||
|
///
|
||||||
|
/// ```sh
|
||||||
|
/// FLY_ROM=/path/to/pokemon-red.gb \
|
||||||
|
/// FLY_BADGE_CHECKPOINT=.local/checkpoints/survey-rank11-row59.checkpoint \
|
||||||
|
/// cargo test --release -p flysim --test rom_macros_mode -- --nocapture the_road_to_mt_moon
|
||||||
|
/// ```
|
||||||
|
#[test]
|
||||||
|
fn the_road_to_mt_moon_is_not_a_ring_at_the_pewter_end_from_the_badge_checkpoint() {
|
||||||
|
let rom = skip_without_rom!();
|
||||||
|
let Some(checkpoint) = badge_checkpoint() else {
|
||||||
|
eprintln!("skipped: no FLY_BADGE_CHECKPOINT");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let mut run = Run::resume(&rom, MacroMode::Macros, &checkpoint);
|
||||||
|
assert!(run.adapter.progress().rank >= 11, "the checkpoint is past the badge");
|
||||||
|
|
||||||
|
let mut crossings = 0u32;
|
||||||
|
let mut on_route_4: Option<u32> = None;
|
||||||
|
let mut at_mt_moon: Option<u32> = None;
|
||||||
|
let mut previous = run.map();
|
||||||
|
for frame in 0..288_000u32 {
|
||||||
|
run.frame();
|
||||||
|
let map = run.map();
|
||||||
|
if map != previous {
|
||||||
|
if (previous == PEWTER_CITY && map == ROUTE_3) || (previous == ROUTE_3 && map == PEWTER_CITY) {
|
||||||
|
crossings += 1;
|
||||||
|
}
|
||||||
|
previous = map;
|
||||||
|
}
|
||||||
|
if on_route_4.is_none() && map == ROUTE_4 {
|
||||||
|
on_route_4 = Some(frame);
|
||||||
|
}
|
||||||
|
if at_mt_moon.is_none() && map == MT_MOON_1F {
|
||||||
|
at_mt_moon = Some(frame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let progress = run.adapter.progress();
|
||||||
|
eprintln!(
|
||||||
|
"{:.1} brain minutes: Route 4 at {on_route_4:?}, Mt. Moon at {at_mt_moon:?}, Pewter / Route 3 \
|
||||||
|
crossings {crossings}, rank {} ({}), route {:?}, macros {:?}",
|
||||||
|
run.ms / 60_000.0,
|
||||||
|
progress.rank,
|
||||||
|
progress.rank_label,
|
||||||
|
run.route,
|
||||||
|
run.started
|
||||||
|
);
|
||||||
|
assert!(crossings < 40, "{crossings} crossings between Pewter City and Route 3: {:?}", run.started);
|
||||||
|
assert!(on_route_4.is_some(), "the fly never reached Route 4: {:?}", run.route);
|
||||||
|
assert!(at_mt_moon.is_some(), "the fly never reached Mt. Moon's door: {:?}", run.route);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Route 4's two sides, read off the cartridge: the warp table the geography's pieces are keyed
|
||||||
|
/// by, and the piece the fly is standing in on arrival from Route 3.
|
||||||
|
///
|
||||||
|
/// The table's door indices and tiles are the disassembly's (`data/maps/objects/Route4.asm`); this
|
||||||
|
/// is the same three warps read from `wWarpEntries` on the loaded map, and the piece named by the
|
||||||
|
/// decoded grid ([`geography::region_on`]) rather than by the doors.
|
||||||
|
#[test]
|
||||||
|
fn route_4s_doors_and_sides_are_the_cartridges_from_the_badge_checkpoint() {
|
||||||
|
use flybrain_gb::pokemon_red::macros::geography::{self, Region};
|
||||||
|
let rom = skip_without_rom!();
|
||||||
|
let Some(checkpoint) = badge_checkpoint() else {
|
||||||
|
eprintln!("skipped: no FLY_BADGE_CHECKPOINT");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let mut run = Run::resume(&rom, MacroMode::Macros, &checkpoint);
|
||||||
|
let mut read = None;
|
||||||
|
for _ in 0..216_000u32 {
|
||||||
|
run.frame();
|
||||||
|
if run.map() != ROUTE_4 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(player) = flybrain_gb::pokemon_red::state::player(&mut run.gb) else { continue };
|
||||||
|
let Ok(grid) = flybrain_gb::pokemon_red::state::map_grid(&mut run.gb) else { continue };
|
||||||
|
if u32::from(player.map) != ROUTE_4 || grid.map() != player.map {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let warps = flybrain_gb::pokemon_red::state::warps(&mut run.gb);
|
||||||
|
read = Some((player, warps, geography::region_on(player.map, player.x, player.y, Some(&grid))));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let Some((player, warps, region)) = read else {
|
||||||
|
panic!("the fly never stood on Route 4 with its grid decoded: {:?}", run.route);
|
||||||
|
};
|
||||||
|
eprintln!("on Route 4 at ({}, {}), piece {region:?}, warps {warps:?}", player.x, player.y);
|
||||||
|
let doors: Vec<(u8, u8, u8)> =
|
||||||
|
warps.iter().map(|warp| (warp.x, warp.y, warp.destination_map)).collect();
|
||||||
|
assert_eq!(
|
||||||
|
doors,
|
||||||
|
vec![(11, 5, 0x44), (18, 5, 0x3b), (24, 5, 0x3c)],
|
||||||
|
"the Pokécenter, the cave mouth and B1F's exit, in the table's order"
|
||||||
|
);
|
||||||
|
assert_eq!(region, Region::piece(0x0f, 0), "arrived from Route 3, on the cave mouth's side");
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue