Entry 355
"Event 22's cures and finale: piros_colour's line waits for its window, and a room change disables the event task at once"
Documented in The event interpreter.
Filescrates/piney-event/src/vm/exec.rscrates/piney-event/src/host.rscrates/piney-event/tests/vm_fixture.txttools/test_event_vm.pycrates/piney-game/src/piros.rscrates/piney-game/src/area_host.rscrates/piney-game/src/field_host.rscrates/piney-game/src/session/tests/event22.rsdocs/engine/event-vm.md
Two reports on INF event 22 (PIRO02, the Cursed Piros quest), both fixed.
Issue #30: the cure's line went by unseen
When Kite takes a cure (items 15/54-57), blocks 21-24 delete it, add one
to eventStatus[1] and set eventStatus[24] (the save's +0x6510) to the
message of the line: 16, 20, 24 or 35. Blocks 25-27 then run
piros_colour 0. On statuses 3, 5, 7 (and 9 with operand 0) the case
plays sound 74 and shows that message's first line through
ccEvent::DispInfo (INF SLUS_202.67:0x001b27b0). In the field,
DispInfo blocks:
- it waits for
ccMenuCtrl::CheckMenuTypeto be -1; - it calls
ChangeInfo, thenccBreathThread(5); - it polls
Check(0)a frame at a time until the window is answered; - it calls
Close, thenccBreathThread(10).
The case's flash and tint come after. 99 ported the case from an eemu
run that stubbed DispInfo as a plain call, so the port opened the window
and went on. Five frames later message 17 replaced it.
Now Host::piros_colour(code) sets the case up and answers whether it
tells the line (piros::Sequence::tells). If so, the interpreter plays
sound 74 and runs DispInfo's wait itself. It reuses the announcements'
code (announce_from, which now takes the window's opener), and
Host::info_lines opens the window. Then comes the host's
Wait::PirosColour. Sequence no longer carries the sound or the line.
Its first tick is the instruction's own frame. The fixture test
(piros_colour_is_the_games, 66 records) adds the sound and the line back
when the case tells one, and still matches.
event_22_tells_piros_used_the_cure (area 31's dungeon, the first cure
given) checks the order:
- the line (message 16) opens at frame 134, after sound 74;
- it is answered at 171;
- message 17 opens at 186: 10 frames of
DispInfo's tail, then the case's breath of 5.
Issue #31: the finale played on the loading screen, and gave no diary
The fourth cure takes the status to 9. Block 28 then sets
eventStatus[0] to 2 and runs room_point 5. Block 29 (eventStatus[0]
2, in point 5, phase 4 or more) is the finale. It ends with item_add_menu 0 12 24 (Piros' Diary) and scene to Mac Anu.
room_point calls WORLD_MAN::RoomSelect (main 0x0019dca0). It always
ends in ccGame::ChangeScene, whose ChangeRequest(6, 7) calls
ccDisableThEvent at once (phase -1). So in the game, the rest of that
pass cannot start block 29. Block 29 waits for the new room's set-up and
runs once play begins, in view.
The port's host made the scene change, but the task was disabled only
when the area took the request, after the interpreter's frame. In between,
block 29 started in the old room, where the scene had already moved to
point 5's room. The new room's set-up then held its loading frame
(Phase::Hold) through the whole cutscene. Its windows showed over the
black screen with the logo, as in the report.
The diary was lost the same way. item_add_menu asks for menu 29, but the
held set-up never runs the menus, so field_menu read -1 the next frame.
The interpreter took that as the menu closed, and nothing gave the item.
The interpreter now disables itself after room and room_point, as it
does at scene. Both run only while playing (level 2 or more; the
cases check $s5 < 2), and room_point with no such point does nothing,
as the game's loop does. prev_room (127, WORLD_MAN::GoPrevRoom
0x001a40b0) also ends in ChangeScene and is treated the same, though no
script on any of the four discs uses it.
tools/test_event_vm.py had stubbed RoomSelect and GoPrevRoom whole,
so its run of the game never reached their ChangeScene, and the fixture
kept the phase at 4 after a room change. Both are now hooked to disable
the task, as its ChangeScene hook already does. The fixture was written
again: 5 of its 252 play records changed, all to the port's new counts.
- Event 22 block 29 takes 365 frames (was 299) once block 28's
room_pointhas disabled the task: its windows take the set-up screen's shape. - Event 58 blocks 6-8 and event 162 block 8 change the same way, after an
earlier block's
room.every_block_played_matches_the_gamepasses on it.
event_22_finale_plays_in_the_room_and_gives_the_diary gives the fourth
cure at status 8 and checks four things:
- block 29's first line opens in the new room's area, in play;
- menu 29 opens;
- Piros' Diary (12/24) is in Kite's items back in Mac Anu;
eventStatus[1]ends at 10.
Without the fix, the line opens in the old room and menu 29 never opens.
The test helper board_done must stop rewriting eventStatus[0] once
the cure is given, or it undoes block 28's 2 in the new room's set-up.
Shots of the fixed finale: the room lit with Kite and Piros under message 32, then "You now have Piros' Diary!" over the same scene.