[Decompilation] [th01] Sariel: Pattern 3/16

The one where red birds hatch on an ellipse arc, then fly away while
shooting a randomly selected pellet group type. Containing Sariel's
first ZUN bug, resulting in unused sprite movement.

Completes P0175, funded by Ember2528.
This commit is contained in:
nmlgc 2021-12-30 03:49:06 +01:00
parent d1627c6f56
commit 40ac9a7aa1
2 changed files with 201 additions and 391 deletions

View File

@ -3,6 +3,7 @@
extern "C" {
#include <stddef.h>
#include <stdlib.h>
#include <dos.h>
#include "platform.h"
#include "pc98.h"
@ -14,6 +15,7 @@ extern "C" {
#include "th01/math/dir.hpp"
#include "th01/math/overlap.hpp"
#include "th01/math/subpixel.hpp"
#include "th01/math/vector.hpp"
#include "th01/hardware/frmdelay.h"
#include "th01/hardware/graph.h"
#include "th01/hardware/egc.h"
@ -47,10 +49,17 @@ extern "C" {
static const screen_x_t SHIELD_LEFT = 304;
static const screen_y_t SHIELD_TOP = 144;
static const screen_x_t DRESS_LEFT = 280;
static const screen_x_t DRESS_TOP = 192;
static const screen_y_t DRESS_TOP = 192;
static const screen_x_t WAND_LEFT = 296;
static const screen_y_t WAND_TOP = 48;
static const screen_y_t SHIELD_CENTER_X = 320;
static const screen_y_t SHIELD_CENTER_Y = 164;
// That's… not quite where the sphere is?
static const screen_x_t WAND_EMIT_LEFT = 340;
static const screen_y_t WAND_EMIT_TOP = 64;
// MODDERS: That's 32 more than BOSS6_2.BOS is wide? Reducing it to 96 works
// fine as well.
static const pixel_t WAND_W = 128;
@ -71,6 +80,7 @@ enum sariel_colors_t {
extern union {
int frame;
int speed_multiplied_by_8;
int interval;
int unknown;
} pattern_state;
extern bool16 invincible;
@ -162,7 +172,8 @@ static const int BIRD_HATCH_CELS = 5;
static const int BIRD_FLY_CELS = 2;
enum bird_cel_t {
C_HATCH = 1,
C_EGG = 0,
C_HATCH,
C_HATCH_last = (C_HATCH + BIRD_HATCH_CELS - 1),
C_FLY,
C_FLY_last = (C_FLY + BIRD_FLY_CELS - 1),
@ -171,6 +182,14 @@ enum bird_cel_t {
#define bird_put_8(left, top, cel) \
grc_put_8(left, top, GRC_SLOT_BIRD, cel, COL_BIRD);
// --------------------
// Spawn cross (BOSS6GR3.GRC)
// --------------------------
static const pixel_t SPAWNCROSS_W = 32;
static const pixel_t SPAWNCROSS_H = 32;
static const int SPAWNCROSS_CELS = 2;
// --------------------------
/// -------------
// .PTN
@ -480,6 +499,14 @@ void pascal near birds_reset_fire_spawn_unput_update_render(
}
}
#define birds_spawn(left, top, velocity_x, velocity_y) \
birds_reset_fire_spawn_unput_update_render( \
left, top, velocity_x, velocity_y, 1 \
);
#define birds_fire(pellet_group) \
birds_reset_fire_spawn_unput_update_render(BF_FIRE + pellet_group);
void near shield_render_both(void)
{
enum {
@ -809,3 +836,157 @@ void near pattern_random_purple_lasers(void)
#undef spawner_y
#undef spawner_x
}
void near pattern_birds_on_ellipse_arc(void)
{
#define wand_raise_animation_done pattern2_wand_raise_animation_done
#define pellet_group pattern2_pellet_group
#define eggs_alive pattern2_eggs_alive
#define spawner_left pattern2_spawner_left
#define spawner_top pattern2_spawner_top
#define spawner_velocity_x pattern2_spawner_velocity_x
#define spawner_velocity_y pattern2_spawner_velocity_y
#define egg_left pattern2_egg_left
#define egg_top pattern2_egg_top
extern bool wand_raise_animation_done;
extern bird_pellet_group_t pellet_group;
extern int eggs_alive;
extern screen_x_t egg_left[BIRD_COUNT];
extern vram_y_t egg_top[BIRD_COUNT];
extern Subpixel spawner_left;
extern Subpixel spawner_top;
extern Subpixel spawner_velocity_y;
extern Subpixel spawner_velocity_x;
point_t velocity;
if(boss_phase_frame < 40) {
return;
}
if(wand_raise_animation_done == false) {
wand_raise_animation_done = wand_render_raise_both();
}
if(boss_phase_frame < 50) {
return;
} else if(boss_phase_frame == 50) {
eggs_alive = 0;
spawner_left.v = to_sp(WAND_EMIT_LEFT);
spawner_top.v = to_sp(WAND_EMIT_TOP);
spawner_velocity_x.v = TO_SP(4 - ((rand() % 2) * 8));
spawner_velocity_y.v = TO_SP(2 - ((rand() % 2) * 4));
select_for_rank(pattern_state.interval, 20, 15, 10, 8);
mdrv2_se_play(8);
} else if(boss_phase_frame < 200) {
if(spawner_left.v < to_sp(SHIELD_CENTER_X)) {
spawner_velocity_x.v += to_sp(0.0625f);
} else {
spawner_velocity_x.v -= to_sp(0.0625f);
}
if(spawner_top.v < to_sp(SHIELD_CENTER_Y)) {
spawner_velocity_y.v += to_sp(0.0625f);
} else {
spawner_velocity_y.v -= to_sp(0.0625f);
}
sloppy_unput_32x32(spawner_left.to_pixel(), spawner_top.to_pixel());
for(int i = (eggs_alive - 1); i >= 0; i--) {
bird_put_8(egg_left[i], egg_top[i], C_EGG);
}
spawner_left.v += spawner_velocity_x.v;
spawner_top.v += spawner_velocity_y.v;
if((boss_phase_frame % pattern_state.interval) == 0) {
if(overlap_xy_lrtb_le_ge(
spawner_left.v, spawner_top.v,
to_sp(0.0), to_sp(0.0f),
to_sp(RES_X - SPAWNCROSS_W), to_sp(RES_Y - SPAWNCROSS_H)
)) {
egg_left[eggs_alive] = spawner_left.to_pixel();
egg_top[eggs_alive] = spawner_top.to_pixel();
bird_put_8(
spawner_left.to_pixel(), spawner_top.to_pixel(), C_EGG
);
eggs_alive++;
}
}
grc_put_8(
spawner_left.to_pixel(),
spawner_top.to_pixel(),
GRC_SLOT_SPAWNCROSS,
(boss_phase_frame % SPAWNCROSS_CELS),
((boss_phase_frame % 4) + 2)
);
} else if(boss_phase_frame < 400) {
if(boss_phase_frame == 200) {
if(abs(spawner_velocity_y.v) < to_sp(0.25f)) {
spawner_velocity_y.v = (spawner_velocity_y.v < 0)
? to_sp(-0.25f)
: to_sp( 0.25f);
}
if(abs(spawner_velocity_x.v) < to_sp(0.25f)) {
spawner_velocity_x.v = (spawner_velocity_x.v < 0)
? to_sp(-0.25f)
: to_sp( 0.25f);
}
for(int i = (eggs_alive - 1); i >= 0; i--) {
vector2(velocity.x, velocity.y, 3, ((rand() & 0x7F) + 0x80));
birds_spawn(egg_left[i], egg_top[i], velocity.x, velocity.y);
}
wand_lower_both();
pellet_group = static_cast<bird_pellet_group_t>(
rand() % (BPG_6_RING + 1) // excluding random rain here
);
}
if(overlap_xy_lrtb_le_ge(
spawner_left, spawner_top,
to_sp(-SPAWNCROSS_W), to_sp(-SPAWNCROSS_H),
to_sp(RES_X), to_sp(RES_Y)
)) {
sloppy_unput_32x32(spawner_left.to_pixel(), spawner_top.to_pixel());
spawner_left.v += spawner_velocity_x.v;
spawner_top.v += spawner_velocity_y.v;
// ZUN bug: ZUN suddenly forgot that [spawner] uses subpixels, not
// pixels. Comparing its position to the pixel equivalent of
// ((RES_X - SPAWNCROSS_W), (RES_Y - SPAWNCROSS_H))
// effectively clips the top-left coordinate of the spawner to a
// screen-space rectangle from (0, 0) to (38, 23). Since that's
// quite far from its actual position, the code below never gets
// executed.
if(overlap_xy_lrtb_le_ge(
spawner_left, spawner_top,
0, 0,
(RES_X - SPAWNCROSS_W), // should be subpixels
(RES_Y - SPAWNCROSS_H) // should be subpixels
)) {
// ZUN bug: Also, here. Quite ironic given that there's a
// correct version of this blitting call above… Copy-pasta
// confirmed.
grc_put_8(
spawner_left, // should be pixels
spawner_top, // should be pixels
GRC_SLOT_SPAWNCROSS,
(boss_phase_frame % SPAWNCROSS_CELS),
((boss_phase_frame % 4) + 2)
);
}
}
if(((boss_phase_frame % 16) == 0) || ((boss_phase_frame % 16) == 2)) {
birds_fire(pellet_group);
}
} else if(boss_phase_frame == 400) {
boss_phase_frame = 0;
wand_raise_animation_done = false;
}
#undef egg_top
#undef egg_left
#undef spawner_velocity_y
#undef spawner_velocity_x
#undef spawner_top
#undef spawner_left
#undef eggs_alive
#undef pellet_group
#undef wand_raise_animation_done
}

View File

@ -22440,6 +22440,7 @@ main_36_TEXT segment byte public 'CODE' use16
@dress_render_both$qv procdesc near
@pattern_vortices$qv procdesc near
@pattern_random_purple_lasers$qv procdesc near
@pattern_birds_on_ellipse_arc$qv procdesc near
main_36_TEXT ends
main_36__TEXT segment byte public 'CODE' use16
@ -22451,387 +22452,6 @@ include th01/main/boss/anim.inc
sariel_shield equ <boss_entity_0>
; =============== S U B R O U T I N E =======================================
; Attributes: bp-based frame
sub_296F0 proc near
var_2C = qword ptr -2Ch
var_24 = qword ptr -24h
var_1C = qword ptr -1Ch
var_14 = qword ptr -14h
var_A = word ptr -0Ah
var_8 = word ptr -8
var_6 = word ptr -6
@@vector_x = word ptr -4
@@vector_y = word ptr -2
enter 0Ah, 0
push si
cmp _boss_phase_frame, 40
jl loc_29A96
cmp byte_35DE1, 0
jnz short loc_2970D
call @wand_render_raise_both$qi pascal, 0
mov byte_35DE1, al
loc_2970D:
cmp _boss_phase_frame, 50
jl loc_29A96
cmp _boss_phase_frame, 50
jnz short loc_29783
mov word_35DE3, 0
mov subpixel_point_3AC50.x, (340 shl 4)
mov subpixel_point_3AC50.y, (64 shl 4)
call IRand
mov bx, 2
cwd
idiv bx
shl dx, 3
mov ax, 4
sub ax, dx
shl ax, 4
mov word_3AC56, ax
call IRand
mov bx, 2
cwd
idiv bx
shl dx, 2
mov ax, 2
sub ax, dx
shl ax, 4
mov word_3AC54, ax
call @sariel_select_for_rank$qmiiiii c, offset _sariel_pattern_state, ds, large 20 or (15 shl 16), large 10 or (8 shl 16)
push 8
call _mdrv2_se_play
pop cx
jmp loc_29A96
; ---------------------------------------------------------------------------
loc_29783:
cmp _boss_phase_frame, 200
jge loc_298A5
cmp subpixel_point_3AC50.x, (320 shl 4)
jge short loc_2979B
inc word_3AC56
jmp short loc_2979F
; ---------------------------------------------------------------------------
loc_2979B:
dec word_3AC56
loc_2979F:
cmp subpixel_point_3AC50.y, (164 shl 4)
jge short loc_297AD
inc word_3AC54
jmp short loc_297B1
; ---------------------------------------------------------------------------
loc_297AD:
dec word_3AC54
loc_297B1:
push (32 shl 16) or 48
mov ax, subpixel_point_3AC50.y
sar ax, 4
push ax
mov ax, subpixel_point_3AC50.x
sar ax, 4
push ax
call _egc_copy_rect_1_to_0_16
add sp, 8
mov ax, word_35DE3
dec ax
mov si, ax
jmp short loc_297F6
; ---------------------------------------------------------------------------
loc_297D5:
push 0 or (15 shl 16) ; (image) or (col)
push GRC_SLOT_BOSS_2 ; slot
mov bx, si
add bx, bx
push word ptr [bx+6274h] ; top
mov bx, si
add bx, bx
push word ptr [bx+6238h] ; left
call _grc_put_8
add sp, 0Ah
dec si
loc_297F6:
or si, si
jge short loc_297D5
mov ax, word_3AC56
add subpixel_point_3AC50.x, ax
mov ax, word_3AC54
add subpixel_point_3AC50.y, ax
mov ax, _boss_phase_frame
cwd
idiv _sariel_pattern_state
or dx, dx
jnz short loc_29874
cmp subpixel_point_3AC50.x, 0
jl short loc_29874
cmp subpixel_point_3AC50.x, (608 shl 4)
jg short loc_29874
cmp subpixel_point_3AC50.y, 0
jl short loc_29874
cmp subpixel_point_3AC50.y, (368 shl 4)
jg short loc_29874
mov ax, subpixel_point_3AC50.x
sar ax, 4
mov bx, word_35DE3
add bx, bx
mov [bx+6238h], ax
mov ax, subpixel_point_3AC50.y
sar ax, 4
mov bx, word_35DE3
add bx, bx
mov [bx+6274h], ax
push 0 or (15 shl 16) ; (image) or (col)
push GRC_SLOT_BOSS_2 ; slot
mov ax, subpixel_point_3AC50.y
sar ax, 4
push ax ; top
mov ax, subpixel_point_3AC50.x
sar ax, 4
push ax ; left
call _grc_put_8
add sp, 0Ah
inc word_35DE3
loc_29874:
mov ax, _boss_phase_frame
mov bx, 4
cwd
idiv bx
add dx, 2
push dx ; col
mov ax, _boss_phase_frame
mov bx, 2
cwd
idiv bx
push dx ; image
push bx ; slot
mov ax, subpixel_point_3AC50.y
sar ax, 4
push ax ; top
mov ax, subpixel_point_3AC50.x
sar ax, 4
push ax ; left
call _grc_put_8
add sp, 0Ah
jmp loc_29A96
; ---------------------------------------------------------------------------
loc_298A5:
cmp _boss_phase_frame, 400
jge loc_29A83
cmp _boss_phase_frame, 200
jnz loc_29995
mov ax, word_3AC54
mov [bp+var_6], ax
cwd
xor ax, dx
sub ax, dx
cmp ax, 4
jge short loc_298DB
cmp word_3AC54, 0
jge short loc_298D5
mov ax, 0FFFCh
jmp short loc_298D8
; ---------------------------------------------------------------------------
loc_298D5:
mov ax, 4
loc_298D8:
mov word_3AC54, ax
loc_298DB:
mov ax, word_3AC56
mov [bp+var_8], ax
cwd
xor ax, dx
sub ax, dx
cmp ax, 4
jge short loc_298FD
cmp word_3AC56, 0
jge short loc_298F7
mov ax, 0FFFCh
jmp short loc_298FA
; ---------------------------------------------------------------------------
loc_298F7:
mov ax, 4
loc_298FA:
mov word_3AC56, ax
loc_298FD:
mov ax, word_35DE3
dec ax
mov si, ax
jmp short loc_2997F
; ---------------------------------------------------------------------------
loc_29905:
call IRand
and al, 7Fh
add al, 128
push ax
push 3
push ss
lea ax, [bp+@@vector_y]
push ax
push ss
lea ax, [bp+@@vector_x]
push ax
call _vector2
add sp, 0Ch
mov bx, si
add bx, bx
mov ax, [bx+6238h]
mov [bp+var_A], ax
fild [bp+var_A]
sub sp, 8
fstp [bp+var_14]
mov bx, si
add bx, bx
fwait
mov ax, [bx+6274h]
mov [bp+var_A], ax
fild [bp+var_A]
sub sp, 8
fstp [bp+var_1C]
fwait
mov ax, [bp+@@vector_x]
mov [bp+var_A], ax
fild [bp+var_A]
sub sp, 8
fstp [bp+var_24]
fwait
mov ax, [bp+var_2]
mov [bp+var_A], ax
fild [bp+var_A]
sub sp, 8
fstp [bp+var_2C]
push 1 ; char
fwait
call @birds_reset_fire_spawn_unput_upd$qddddc
dec si
loc_2997F:
or si, si
jge short loc_29905
call @wand_lower_both$qv
call IRand
mov bx, 2
cwd
idiv bx
mov byte_35DE2, dl
loc_29995:
cmp subpixel_point_3AC50.x, (-32 shl 4)
jl loc_29A29
cmp subpixel_point_3AC50.x, (640 shl 4)
jg loc_29A29
cmp subpixel_point_3AC50.y, (-32 shl 4)
jl short loc_29A29
cmp subpixel_point_3AC50.y, (400 shl 4)
jg short loc_29A29
push (32 shl 16) or 48
mov ax, subpixel_point_3AC50.y
sar ax, 4
push ax
mov ax, subpixel_point_3AC50.x
sar ax, 4
push ax
call _egc_copy_rect_1_to_0_16
add sp, 8
mov ax, word_3AC56
add subpixel_point_3AC50.x, ax
mov ax, word_3AC54
add subpixel_point_3AC50.y, ax
cmp subpixel_point_3AC50.x, 0
jl short loc_29A29
cmp subpixel_point_3AC50.x, (38 shl 4)
jg short loc_29A29
cmp subpixel_point_3AC50.y, 0
jl short loc_29A29
cmp subpixel_point_3AC50.y, (23 shl 4)
jg short loc_29A29
mov ax, _boss_phase_frame
mov bx, 4
cwd
idiv bx
add dx, 2
push dx ; col
mov ax, _boss_phase_frame
mov bx, 2
cwd
idiv bx
push dx ; image
push bx ; slot
push subpixel_point_3AC50.y ; top
push subpixel_point_3AC50.x ; left
call _grc_put_8
add sp, 0Ah
loc_29A29:
mov ax, _boss_phase_frame
mov bx, 16
cwd
idiv bx
or dx, dx
jz short loc_29A41
mov ax, _boss_phase_frame
cwd
idiv bx
cmp dx, 2
jnz short loc_29A96
loc_29A41:
mov al, byte_35DE2
cbw
add ax, 3E9h
mov [bp+var_A], ax
fild [bp+var_A]
sub sp, 8
fstp [bp+var_14]
fldz
fwait
sub sp, 8
fstp [bp+var_1C]
fldz
fwait
sub sp, 8
fstp [bp+var_24]
fldz
fwait
sub sp, 8
fstp [bp+var_2C]
push 0 ; char
fwait
call @birds_reset_fire_spawn_unput_upd$qddddc
jmp short loc_29A96
; ---------------------------------------------------------------------------
loc_29A83:
cmp _boss_phase_frame, 400
jnz short loc_29A96
mov _boss_phase_frame, 0
mov byte_35DE1, 0
loc_29A96:
pop si
leave
retn
sub_296F0 endp
; =============== S U B R O U T I N E =======================================
; Attributes: bp-based frame
@ -26894,7 +26514,7 @@ loc_2C40D:
loc_2C419:
cmp word_35E95, 2
jnz short loc_2C423
call sub_296F0
call @pattern_birds_on_ellipse_arc$qv
loc_2C423:
cmp _boss_phase_frame, 0
@ -28433,9 +28053,12 @@ _wand_raise_frames dw 0
public _pattern1_wand_raise_animation_do
_pattern1_wand_raise_animation_do dw 0
byte_35DE1 db 0
byte_35DE2 db 0
word_35DE3 dw 0
public _pattern2_wand_raise_animation_do, _pattern2_pellet_group
public _pattern2_eggs_alive
_pattern2_wand_raise_animation_do db 0
_pattern2_pellet_group db 0
_pattern2_eggs_alive dw 0
dd 0
dd 0
dd 0
@ -28890,10 +28513,16 @@ public _pattern0_spawner_x, _pattern0_spawner_y
_pattern0_spawner_x dw 10 dup(?)
_pattern0_spawner_y dw 10 dup(?)
db 120 dup(?)
subpixel_point_3AC50 Point <?>
word_3AC54 dw ?
word_3AC56 dw ?
public _pattern2_egg_left, _pattern2_egg_top
public _pattern2_spawner_left, _pattern2_spawner_top,
public _pattern2_spawner_velocity_x, _pattern2_spawner_velocity_y
_pattern2_egg_left dw BIRD_COUNT dup(?)
_pattern2_egg_top dw BIRD_COUNT dup(?)
_pattern2_spawner_left dw ?
_pattern2_spawner_top dw ?
_pattern2_spawner_velocity_y dw ?
_pattern2_spawner_velocity_x dw ?
word_3AC58 dw ?
word_3AC5A dw ?
word_3AC5C dw ?