[Decompilation] [th01] Elis: Pattern 12/13

The one where Elis creates a safety zone of 256 pixels around the
initial position of the player, indicated by a circle, and then fires
pellets from random positions at the top edge of the playfield for a
while.

Followed by 5 aimed pellets from her center position.

Followed by… 7 aimed pellets from the bat entity's center position?!
Except that those aren't even correctly centered relative to the bat,
and still use the center offset of the girl sprite.

Part of P0195, funded by Yanga.
This commit is contained in:
nmlgc 2022-05-17 12:57:49 +02:00
parent a25abad9c4
commit 387431ed15
2 changed files with 131 additions and 343 deletions

View File

@ -1,6 +1,7 @@
/// Makai Stage 15 Boss - Elis
/// --------------------------
#include <dos.h>
#include <stddef.h>
#include <stdlib.h>
#include "platform.h"
@ -16,6 +17,7 @@ extern "C" {
#include "th01/math/vector.hpp"
#include "th01/hardware/egc.h"
#include "th01/hardware/graph.h"
#include "th01/hardware/input.hpp"
}
#include "th01/hardware/scrollup.hpp"
extern "C" {
@ -38,6 +40,7 @@ extern "C" {
#include "th01/main/bullet/missile.hpp"
#include "th01/main/bullet/pellet.hpp"
#include "th01/main/hud/hp.hpp"
#include "th01/main/player/player.hpp"
// Coordinates
// -----------
@ -1450,3 +1453,123 @@ elis_starpattern_ret_t pattern_three_symmetric_4_stacks_then_symmetric_arc(void)
#undef fire_symmetric
}
elis_starpattern_ret_t pattern_safety_circle_and_rain_from_top(void)
{
enum {
CIRCLE_DURATION = 200,
// A bit unfair, since the kill zone already starts in the transparent
// parts of the non-moving player sprite.
SAFETY_OFFSET_LEFT = BIGCIRCLE_RADIUS,
// Slightly less unfair.
SAFETY_OFFSET_RIGHT = (
BIGCIRCLE_RADIUS - (PLAYER_W / 2) - (PLAYER_W / 4)
),
};
#define circle pattern11_circle
extern struct {
int frames;
screen_x_t target_left;
unsigned char angle;
screen_x_t center_x(void) { return (target_left + (PLAYER_W / 2)); };
screen_y_t center_y(void) { return player_center_y(); };
} circle;
if(boss_phase_frame < 10) {
circle.frames = 0;
}
ent_attack_render();
if(boss_phase_frame < 60) {
return SP_PATTERN;
}
if(boss_phase_frame == 60) {
select_for_rank(pattern_state.interval, 4, 2, 2, 2);
circle.angle = 0x00;
}
if(bigcircle_is_summon_frame(60) && (circle.frames == 0)) {
if(boss_phase_frame == 60) {
mdrv2_se_play(8);
circle.target_left = player_left;
}
bigcircle_summon_update_and_render(circle, 0x02);
if(bigcircle_summon_done(circle)) {
bigcircle_sloppy_unput(circle); // (redundant, position unchanged)
bigcircle_put(circle, V_WHITE);
circle.frames = 1;
ent_unput_and_put_both(ENT_STILL_OR_WAVE, C_STILL);
}
} else if((circle.frames != 0) && (circle.frames < CIRCLE_DURATION)) {
circle.frames++;
// We only blit the circle to VRAM page 0, so any unblitting call for
// any overlapping sprite will "cut a hole" into the circle. So, um...
// let's just re-blit it every 4 frames? :zunpet:
if((circle.frames % 4) == 0) {
bigcircle_sloppy_unput(circle); // (redundant, position unchanged)
bigcircle_put(circle, V_WHITE);
}
if(!player_invincible) {
if(
((circle.target_left + SAFETY_OFFSET_RIGHT) <= player_left) ||
((circle.target_left - SAFETY_OFFSET_LEFT) >= player_left)
) {
delay(100);
done = true;
}
}
if(done == true) {
circle.frames = CIRCLE_DURATION;
}
if((boss_phase_frame % pattern_state.interval) == 0) {
Pellets.add_group(
(PLAYFIELD_LEFT + (rand() % (PLAYFIELD_W - PELLET_W))),
(PLAYFIELD_TOP),
(rank == RANK_LUNATIC) ? PG_1_RANDOM_WIDE : PG_1,
to_sp(4.5f)
);
}
if(
(circle.frames > (CIRCLE_DURATION - 20)) &&
((circle.frames % 4) == 0)
) {
form_fire_group(F_GIRL, PG_1_AIMED, 4.5f);
}
} else if(circle.frames < CIRCLE_DURATION) {
return SP_PATTERN;
} else {
if(circle.frames == CIRCLE_DURATION) {
bigcircle_sloppy_unput(circle);
}
circle.frames++;
if((circle.frames % 8) == 0) {
// ZUN bug: Spawning pellets relative to the top-left corner of the
// bat sprite rather than the girl one. Since this pattern only
// ever runs after a bat transformation, the position isn't
// *completely* random at least, just calculated a lot lower than
// you would expect.
Pellets.add_group(
(ent_bat.cur_left + (GIRL_W / 2) - (PELLET_W / 2)),
(ent_bat.cur_top + (GIRL_H / 2) - (PELLET_H / 2)),
PG_1_AIMED,
to_sp(4.5f)
);
}
if(circle.frames > (CIRCLE_DURATION + 60)) {
boss_phase_frame = 0;
circle.frames = 0; // (redundant, gets reset at the beginning)
circle.angle = 0x00; // (redundant, gets reset at the beginning)
return SP_STAR_OF_DAVID;
}
}
return SP_PATTERN;
#undef circle
}

View File

@ -17419,349 +17419,11 @@ ELIS_BASE_TOP = (PLAYFIELD_TOP + ((PLAYFIELD_H / 21) * 5) - (ELIS_GIRL_H / 2))
extern @pattern_bat_alternating_2_and_3_$qv:proc
extern @pattern_bat_random_rain$qv:proc
extern @pattern_three_symmetric_4_stacks$qv:proc
extern @pattern_safety_circle_and_rain_f$qv:proc
main_35_TEXT ends
main_35__TEXT segment byte public 'CODE' use16
; =============== S U B R O U T I N E =======================================
; Attributes: bp-based frame
sub_271F1 proc far
push bp
mov bp, sp
cmp _boss_phase_frame, 10
jge short loc_27201
mov word_3A76B, 0
loc_27201:
mov ax, _boss_phase_frame
mov bx, 8
cwd
idiv bx
or dx, dx
jnz short loc_27257
push 1
call _graph_accesspage_func
call @girl_bg_put$qi stdcall, 2
mov elis_attack.BE_move_lock_frame, 0
mov elis_attack.BE_bos_image, 1
call @CBossEntity@move_lock_and_put_8$qiiii stdcall, offset elis_attack, ds, large 0, large 0 or (3 shl 16)
push 0
call _graph_accesspage_func
call @girl_bg_put$qi stdcall, 2
add sp, 14h
mov elis_attack.BE_move_lock_frame, 0
mov elis_attack.BE_bos_image, 1
jmp short loc_272A0
; ---------------------------------------------------------------------------
loc_27257:
mov ax, _boss_phase_frame
mov bx, 8
cwd
idiv bx
cmp dx, 4
jnz short loc_272B5
push 1
call _graph_accesspage_func
mov elis_attack.BE_move_lock_frame, 0
mov elis_attack.BE_bos_image, 2
call @CBossEntity@move_lock_and_put_8$qiiii stdcall, offset elis_attack, ds, large 0, large 0 or (3 shl 16)
push 0
call _graph_accesspage_func
add sp, 10h
mov elis_attack.BE_move_lock_frame, 0
mov elis_attack.BE_bos_image, 2
loc_272A0:
call @CBossEntity@move_lock_and_put_8$qiiii c, offset elis_attack, ds, large 0, large 0 or (3 shl 16)
loc_272B5:
cmp _boss_phase_frame, 60
jl loc_275EF
cmp _boss_phase_frame, 60
jnz short loc_272E1
call @elis_select_for_rank$qmiiiii c, offset _elis_pattern_state, ds, large 4 or (2 shl 16), large 2 or (2 shl 16)
mov angle_3A76F, 0
loc_272E1:
cmp _boss_phase_frame, 60
jl loc_27464
mov ax, _boss_phase_frame
mov bx, 2
cwd
idiv bx
or dx, dx
jnz loc_27464
cmp word_3A76B, 0
jnz loc_27464
cmp _boss_phase_frame, 60
jnz short loc_27317
push 8
call _mdrv2_se_play
pop cx
mov ax, _player_left
mov word_3A76D, ax
loc_27317:
mov al, angle_3A76F
add al, 2
push ax ; angle_end
push word ptr angle_3A76F ; angle_start
push 1 ; angle_step
push 128 or (7 shl 16) ; (radius_y) or (col shl 16)
push 384 or (128 shl 16) ; (center_y) or (radius_x shl 16)
mov ax, word_3A76D
add ax, 10h
push ax ; center_x
call @shape_ellipse_arc_put$qiiiiiucucuc
mov al, angle_3A76F
add al, 42h
push ax ; angle_end
mov al, angle_3A76F
add al, 40h
push ax ; angle_start
push 1 ; angle_step
push 128 or (7 shl 16) ; (radius_y) or (col shl 16)
push 384 or (128 shl 16) ; (center_y) or (radius_x shl 16)
mov ax, word_3A76D
add ax, 10h
push ax ; center_x
call @shape_ellipse_arc_put$qiiiiiucucuc
mov al, angle_3A76F
add al, -7Eh
push ax ; angle_end
mov al, angle_3A76F
add al, 80h
push ax ; angle_start
push 1 ; angle_step
push 128 or (7 shl 16) ; (radius_y) or (col shl 16)
push 384 or (128 shl 16) ; (center_y) or (radius_x shl 16)
mov ax, word_3A76D
add ax, 10h
push ax ; center_x
call @shape_ellipse_arc_put$qiiiiiucucuc
add sp, 30h
mov al, angle_3A76F
add al, -3Eh
push ax ; angle_end
mov al, angle_3A76F
add al, -40h
push ax ; angle_start
push 1 ; angle_step
push 128 or (7 shl 16) ; (radius_y) or (col shl 16)
push 384 or (128 shl 16) ; (center_y) or (radius_x shl 16)
mov ax, word_3A76D
add ax, 10h
push ax ; center_x
call @shape_ellipse_arc_put$qiiiiiucucuc
add sp, 10h
mov al, angle_3A76F
add al, 2
mov angle_3A76F, al
cmp angle_3A76F, 40h
jb loc_275EF
push 255 ; angle_end
push 0 ; angle_start
push 1 ; angle_step
push 128 or (128 shl 16) ; (radius_x) or (radius_y shl 16)
push 384 ; center_y
mov ax, word_3A76D
add ax, 16
push ax ; center_x
call @shape_ellipse_arc_sloppy_unput$qiiiiucucuc
push 255 ; angle_end
push 0 ; angle_start
push 1 ; angle_step
push 128 or (7 shl 16) ; (radius_y) or (col shl 16)
push 384 or (128 shl 16) ; (center_y) or (radius_x shl 16)
mov ax, word_3A76D
add ax, 10h
push ax ; center_x
call @shape_ellipse_arc_put$qiiiiiucucuc
mov word_3A76B, 1
push 1
call _graph_accesspage_func
call @girl_bg_put$qi stdcall, 1
mov elis_still_or_wave.BE_move_lock_frame, 0
mov elis_still_or_wave.BE_bos_image, 0
call @CBossEntity@move_lock_and_put_8$qiiii stdcall, offset elis_still_or_wave, ds, large 0, large 0 or (3 shl 16)
push 0
call _graph_accesspage_func
call @girl_bg_put$qi stdcall, 1
add sp, 32h
mov elis_still_or_wave.BE_move_lock_frame, 0
mov elis_still_or_wave.BE_bos_image, 0
call @CBossEntity@move_lock_and_put_8$qiiii stdcall, offset elis_still_or_wave, ds, large 0, large 0 or (3 shl 16)
loc_2745E:
add sp, 0Ch
jmp loc_275EF
; ---------------------------------------------------------------------------
loc_27464:
cmp word_3A76B, 0
jz loc_27572
cmp word_3A76B, 0C8h ; '?'
jge loc_27572
inc word_3A76B
mov ax, word_3A76B
mov bx, 4
cwd
idiv bx
or dx, dx
jnz short loc_274C6
push 255 ; angle_end
push 0 ; angle_start
push 1 ; angle_step
push 128 or (128 shl 16) ; (radius_x) or (radius_y shl 16)
push 384 ; center_y
mov ax, word_3A76D
add ax, 16
push ax ; center_x
call @shape_ellipse_arc_sloppy_unput$qiiiiucucuc
push 255 ; angle_end
push 0 ; angle_start
push 1 ; angle_step
push 128 or (7 shl 16) ; (radius_y) or (col shl 16)
push 384 or (128 shl 16) ; (center_y) or (radius_x shl 16)
mov ax, word_3A76D
add ax, 10h
push ax ; center_x
call @shape_ellipse_arc_put$qiiiiiucucuc
add sp, 1Eh
loc_274C6:
cmp _player_invincible, 0
jnz short loc_274F2
mov ax, word_3A76D
add ax, 104
cmp ax, _player_left
jle short loc_274E5
mov ax, word_3A76D
add ax, -128
cmp ax, _player_left
jl short loc_274F2
loc_274E5:
push 64h ; 'd'
call _delay
pop cx
mov _done, 1
loc_274F2:
cmp _done, 1
jnz short loc_274FF
mov word_3A76B, 0C8h ; '?'
loc_274FF:
mov ax, _boss_phase_frame
cwd
idiv _elis_pattern_state
or dx, dx
jnz short loc_27539
push (4 shl 4) + 8
mov al, _rank
cbw
cmp ax, RANK_LUNATIC
jnz short loc_2751B
mov ax, PG_1_RANDOM_WIDE
jmp short loc_2751E
; ---------------------------------------------------------------------------
loc_2751B:
mov ax, PG_1
loc_2751E:
push ax
push PLAYFIELD_TOP
call IRand
mov bx, 632
cwd
idiv bx
push dx
push ds
push offset _Pellets
call @CPellets@add_group$qii14pellet_group_ti
add sp, 0Ch
loc_27539:
cmp word_3A76B, 0B4h ; '?'
jle loc_275EF
mov ax, word_3A76B
mov bx, 4
cwd
idiv bx
or dx, dx
jnz loc_275EF
push PG_1_AIMED or (((4 shl 4) + 8) shl 16)
mov ax, elis_still_or_wave.BE_cur_top
add ax, 44
push ax
mov ax, elis_still_or_wave.BE_cur_left
add ax, 60
push ax
push ds
push offset _Pellets
call @CPellets@add_group$qii14pellet_group_ti
jmp loc_2745E
; ---------------------------------------------------------------------------
loc_27572:
cmp word_3A76B, 0C8h ; '?'
jl short loc_275EF
cmp word_3A76B, 0C8h ; '?'
jnz short loc_275A1
push 255 ; angle_end
push 0 ; angle_start
push 1 ; angle_step
push 128 or (128 shl 16) ; (radius_x) or (radius_y shl 16)
push 384 ; center_y
mov ax, word_3A76D
add ax, 16
push ax ; center_x
call @shape_ellipse_arc_sloppy_unput$qiiiiucucuc
add sp, 0Eh
loc_275A1:
inc word_3A76B
mov ax, word_3A76B
mov bx, 8
cwd
idiv bx
or dx, dx
jnz short loc_275D2
push PG_1_AIMED or (((4 shl 4) + 8) shl 16)
mov ax, elis_bat.BE_cur_top
add ax, 44
push ax
mov ax, elis_bat.BE_cur_left
add ax, 60
push ax
push ds
push offset _Pellets
call @CPellets@add_group$qii14pellet_group_ti
add sp, 0Ch
loc_275D2:
cmp word_3A76B, 104h
jle short loc_275EF
mov _boss_phase_frame, 0
mov word_3A76B, 0
mov angle_3A76F, 0
xor ax, ax
pop bp
retf
; ---------------------------------------------------------------------------
loc_275EF:
mov ax, 1
pop bp
retf
sub_271F1 endp
; =============== S U B R O U T I N E =======================================
; Attributes: bp-based frame
@ -18216,7 +17878,7 @@ loc_27B14:
; ---------------------------------------------------------------------------
loc_27B1D:
call sub_271F1
call @pattern_safety_circle_and_rain_f$qv
mov word_35D46, ax
cmp word_35D46, 0
jnz short loc_27B5B
@ -20263,9 +19925,12 @@ _bat_target_left dw ?
_bat_target_top dw ?
_bat_frames_until_target dw ?
word_3A76B dw ?
word_3A76D dw ?
angle_3A76F db ?
public _pattern11_circle
_pattern11_circle label byte
dw ? ; frames
dw ? ; target_left
db ? ; angle
angle_3A770 db ?
word_3A771 dw ?
public _elis_invincibility_frame, _elis_invincible, _elis_wave_teleport_done