mirror of https://github.com/nmlgc/ReC98.git
[Research] [th01] Find out why defeating bosses with lasers can crash the game
Brought to you by diagonal movement and the combined effect of 4 ZUN bugs. Most commonly reported for Elis and Mima. Part of P0197, funded by Yanga and Ember2528.
This commit is contained in:
parent
b165871ece
commit
9cd1b04894
|
@ -557,6 +557,14 @@ void graph_r_line(
|
|||
grcg_put(vram_offset, pixels, 16); \
|
||||
pixels = 0; \
|
||||
} else { \
|
||||
/* ZUN bug: Getting here with a [vram_offset] of 0x0000 will
|
||||
* cause a 4-byte write starting at 0xFFFF. On the 80286 and
|
||||
* later CPUs, offset overflows within an instruction are
|
||||
* illegal even in Real Mode, and will raise a General
|
||||
* Protection Fault.
|
||||
* As of May 2022, Anex86 is the only PC-98 emulator to
|
||||
* correctly replicate this behavior of real hardware,
|
||||
* though. */ \
|
||||
vram_offset--; \
|
||||
unput32_at(vram_offset); \
|
||||
} \
|
||||
|
@ -630,6 +638,16 @@ void graph_r_line(
|
|||
plot_loop(y_cur, h, y_direction, x_cur, w, 1);
|
||||
}
|
||||
restore_last:
|
||||
// ZUN bug: Off-by-one error, as [x_cur] and [y_cur] are one past the
|
||||
// intended right / bottom coordinates after the plot_loop. Should have
|
||||
// calculated [vram_offset] from [x_vram] and [y_vram] just like the
|
||||
// plot_loop, since those values are directly updated for the next VRAM
|
||||
// byte after a blit, and would thus be correct here as well.
|
||||
//
|
||||
// This way, the offset could potentially end up at [right = 640] or
|
||||
// [bottom = -1]. Both together are not only the same as (0, 0) and thus
|
||||
// wrap from the right edge of VRAM back to the left one, but also trigger
|
||||
// the same General Protection Fault seen in the plot_loop itself.
|
||||
vram_offset = vram_offset_shift(x_cur, y_cur) - 1;
|
||||
unput32_at(vram_offset);
|
||||
end:
|
||||
|
|
|
@ -74,7 +74,13 @@ void graph_r_line_patterned(
|
|||
dots16_t pattern
|
||||
);
|
||||
|
||||
// Recovers the pixels on the given arbitrary-angle line from page 1.
|
||||
// Recovers horizontal 32-pixel chunks along on the given arbitrary-angled line
|
||||
// from page 1. The [right] and [bottom] points are included in the line.
|
||||
//
|
||||
// ZUN bug: Will raise a General Protection Fault if it ever writes to the
|
||||
// topmost byte of VRAM, corresponding to the pixel coordinates from (0, 0) to
|
||||
// (0, 7) inclusive. Thanks to an off-by-one error, this also happens for any
|
||||
// lines ending at ((RES_X - 1), 0).
|
||||
void graph_r_line_unput(
|
||||
screen_x_t left, vram_y_t top, screen_x_t right, vram_y_t bottom
|
||||
);
|
||||
|
|
|
@ -2146,7 +2146,7 @@ void elis_main(void)
|
|||
Pellets.unput_and_reset();
|
||||
girl_bg_put(1);
|
||||
Missiles.reset();
|
||||
shootout_lasers_unput_and_reset_broken(i);
|
||||
shootout_lasers_unput_and_reset_broken(i); // MODDERS: Remove
|
||||
boss_defeat_animate();
|
||||
scene_init_and_load(5);
|
||||
}
|
||||
|
|
|
@ -89,7 +89,8 @@ public:
|
|||
// Directly sets [done] if the laser collides with the player.
|
||||
void update_hittest_and_render(void);
|
||||
|
||||
// Tries to unblit the entire laser, but fails hilariously.
|
||||
// Tries to unblit the entire laser, but fails hilariously and potentially
|
||||
// even crashes the game.
|
||||
void unput_and_reset(void) {
|
||||
if(alive) {
|
||||
// Two ZUN bugs here:
|
||||
|
@ -101,13 +102,20 @@ public:
|
|||
// who knows how accurate that actually is?
|
||||
//
|
||||
// 2) graph_r_line_unput() takes screen_x_t and vram_y_t, not
|
||||
// LaserPixels truncated to 16-bits :zunpet: As a result, this
|
||||
// call effectively unblit random 32-bit pixel chunks.
|
||||
// LaserPixels truncated to 16-bits. :zunpet: The function then
|
||||
// interpolates and clips these values in a rather clumsy
|
||||
// attempt to find a line segment between those garbage
|
||||
// coordinates that actually falls within the boundaries of
|
||||
// VRAM. At best, this search fails, and the function simply
|
||||
// does nothing. At worst, the resulting line triggers the ZUN
|
||||
// bugs in graph_r_line_unput(), raising a General Protection
|
||||
// Fault.
|
||||
// The latter is exactly the cause behind potential crashes when
|
||||
// defeating bosses while there are diagonally moving lasers on
|
||||
// screen, which are most commonly reported for Elis and Mima.
|
||||
//
|
||||
// Not that it matters a lot. This function is only called at the
|
||||
// end of a boss battle, immediately before transitioning to the
|
||||
// tally screen. Still, not doing anything would have been the
|
||||
// better choice.
|
||||
// So yeah, not doing anything would have been the much better
|
||||
// choice.
|
||||
graph_r_line_unput(
|
||||
ray_start_left.v, ray_start_y.v, origin_left.v, origin_y.v
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue