[Reverse-engineering] [th04/th05] Bullets: Distinguish clear and zap mechanics

And actually document them correctly.

Clear: Custom duration, awards constant points per bullet during the
       entire duration, plays a decay animation
  Zap: Fixed duration, awards a semi-exponential bonus for all bullets
       alive on the first frame, plays a, um, "zapping" animation… in
       TH04, because it's bugged in TH05 :zunpet:

Part of P0149, funded by Blue Bolt, Ember2528, and -Tom-.
This commit is contained in:
nmlgc 2021-07-24 21:25:25 +02:00
parent e1a26bb9b1
commit 75c4f2d3cc
14 changed files with 79 additions and 68 deletions

View File

@ -109,8 +109,8 @@ void pascal near bullet_update_patnum(bullet_t near *bullet);
// [angle].
int pascal near bullet_patnum_for_angle(unsigned char angle);
// Turns every 4th bullet into a point item when clearing bullets.
extern bool bullet_clear_drop_point_items;
// Turns every 4th bullet into a point item when zapping bullets.
extern bool bullet_zap_drop_point_items;
#endif
#define BULLET_COUNT (PELLET_COUNT + BULLET16_COUNT)
@ -124,6 +124,19 @@ extern bullet_t bullets[BULLET_COUNT];
// per-bullet!
extern unsigned char bullet_turn_count_max;
// Set to `true` to clear all on-screen bullets, giving out a semi-exponential
// bonus for all bullets that were alive on the first frame of activity.
// Lasts for BULLET_ZAP_FRAMES and resets to `false` afterwards.
extern bool bullet_zap_active;
static const int BULLET_ZAP_FRAMES_PER_CEL = 4;
static const int BULLET_ZAP_FRAMES = (
BULLET_ZAP_CELS * BULLET_ZAP_FRAMES_PER_CEL
);
// # of frames left during which all on-screen bullets should decay.
// Gives a constant point bonus for every bullet decayed during that time.
extern unsigned char bullet_clear_time;
/// Rendering
/// ---------
union pellet_render_t {

View File

@ -2,10 +2,6 @@ public _bullet_turn_count_max, _bullet_template_turn_angle
_bullet_turn_count_max db ?
_bullet_template_turn_angle db ?
public _bullet_clear_trigger, _bullet_clear_time
; Set to non-zero to clear all on-screen bullets, giving out bonus points for
; each one.
_bullet_clear_trigger db ?
; # of frames left during which all on-screen bullets should decay.
; Does not give a point bonus when used on its own. (unsigned)
public _bullet_zap_active, _bullet_clear_time
_bullet_zap_active db ?
_bullet_clear_time db ?

View File

@ -9,7 +9,7 @@ bullets_gather_invalidate proc near
else
mov di, BULLET_COUNT
endif
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short @@pellets_decaying
cmp _bullet_clear_time, 0
jnz short @@pellets_decaying

View File

@ -5,6 +5,7 @@
#define HITSHOT_CELS 4
#define BULLET_CLOUD_CELS 4
#define BULLET_DECAY_CELS 4
#define BULLET_ZAP_CELS 4
// Directional bullets with one axis of symmetry; sprites cover 180 degrees
#define BULLET_D_CELS 16

View File

@ -3,5 +3,6 @@ include th02/sprites/cels.inc
HITSHOT_CELS = 4
BULLET_CLOUD_CELS = 4
BULLET_DECAY_CELS = 4
BULLET_ZAP_CELS = 4
BULLET_D_CELS = 16
BULLET_V_CELS = 32

View File

@ -36,8 +36,8 @@ typedef enum {
PAT_EXPLOSION_SMALL = 68,
PAT_BULLET_KILL = 72,
PAT_BULLET_KILL_last = (PAT_BULLET_KILL + BULLET_DECAY_CELS - 1),
PAT_BULLET_ZAP = 72,
PAT_BULLET_ZAP_last = (PAT_BULLET_ZAP + BULLET_ZAP_CELS - 1),
PAT_BULLET16_D,
PAT_BULLET16_D_BLUE = PAT_BULLET16_D,
PAT_BULLET16_D_BLUE_last = (PAT_BULLET16_D_BLUE + BULLET_D_CELS - 1),

View File

@ -19,7 +19,7 @@ PAT_BULLET16_N_SMALL_BALL_RED = 60
PAT_BULLET16_N_BALL_RED = 61
PAT_BULLET16_N_HEART_BALL_RED = 62
PAT_EXPLOSION_SMALL = 68
PAT_BULLET_KILL = 72
PAT_BULLET_ZAP = 72
PAT_BULLET16_D = 76
PAT_BULLET16_D_BLUE = PAT_BULLET16_D
PAT_BULLET16_D_YELLOW = 92

View File

@ -10743,7 +10743,7 @@ sub_11ECB proc near
mov word_266D0, 1
mov byte_266D2, 0
mov _palette_changed, 0
mov _bullet_clear_trigger, 0
mov _bullet_zap_active, 0
mov _stage_graze, 0
mov _circles_color, GC_R
call grc_setclip pascal, large (PLAYFIELD_LEFT shl 16) or PLAYFIELD_TOP, large ((PLAYFIELD_RIGHT - 1) shl 16) or (PLAYFIELD_BOTTOM - 1)
@ -12435,7 +12435,7 @@ loc_12D6D:
@@bullets16_more?:
cmp di, BULLET16_COUNT
jl @@sprite_bullet_loop
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short loc_12DBE
cmp _bullet_clear_time, 0
jnz short loc_12DBE
@ -13241,7 +13241,7 @@ loc_1422D:
; ---------------------------------------------------------------------------
loc_142A2:
mov _bullet_clear_trigger, 1
mov _bullet_zap_active, 1
push 5
call sub_19F6E
@ -13605,7 +13605,7 @@ loc_14629:
add ax, (-16 shl 4)
call scroll_subpixel_y_to_vram_always pascal, ax
mov si, ax
mov _bullet_clear_trigger, 1
mov _bullet_zap_active, 1
mov al, byte_2559A
mov ah, 0
mov dx, 14h
@ -14502,7 +14502,7 @@ loc_14E8E: ; default
loc_14EB5:
mov _midboss_damage_this_frame, 1
mov _bullet_clear_trigger, 1
mov _bullet_zap_active, 1
mov al, byte_255B4
mov ah, 0
mov dx, 12h
@ -15086,7 +15086,7 @@ loc_15414:
add ax, (-16 shl 4)
call scroll_subpixel_y_to_vram_always pascal, ax
mov si, ax
mov _bullet_clear_trigger, 1
mov _bullet_zap_active, 1
mov al, byte_255C7
mov ah, 0
mov dx, 1Eh
@ -17400,7 +17400,7 @@ loc_16963:
call boss_explode_big pascal, 2
mov _boss_phase, PHASE_EXPLODE_BIG
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
cmp _boss_mode_change, 0
jz short loc_16986
push 3Ch ; '<'
@ -19600,7 +19600,7 @@ loc_17C54:
call boss_explode_big pascal, 2
mov _boss_phase, PHASE_EXPLODE_BIG
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
cmp _boss_mode_change, 0
jz short loc_17C77
push 28h ; '('
@ -21151,7 +21151,7 @@ loc_1895A:
call boss_explode_big pascal, 2
mov _boss_phase, PHASE_EXPLODE_BIG
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
cmp _boss_mode_change, 0
jz short loc_1897E
push 0C8h
@ -22503,7 +22503,7 @@ loc_1955E:
call boss_explode_big pascal, 0
mov _boss_phase, PHASE_EXPLODE_BIG
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
cmp _boss_mode_change, 0
jz short loc_19581
push 14h
@ -23439,7 +23439,7 @@ loc_19E3D:
call boss_explode_big pascal, 0
mov _boss_phase, PHASE_EXPLODE_BIG
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
cmp _boss_mode_change, 0
jz short loc_19E60
push 0Ah
@ -26020,7 +26020,7 @@ loc_1B8A4:
call boss_explode_big pascal, 2
mov _boss_phase, PHASE_EXPLODE_BIG
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
cmp _boss_mode_change, 0
jz short loc_1B8C7
push 46h ; 'F'
@ -27539,7 +27539,7 @@ loc_1C62F:
call boss_explode_big pascal, 3
mov _boss_phase, PHASE_EXPLODE_BIG
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
cmp _boss_mode_change, 0
jz short loc_1C652
push 28h ; '('
@ -27844,7 +27844,7 @@ var_2 = word ptr -2
mov [bp+var_2], 0
mov _pellets_render_count, 0
mov si, offset _bullets[(BULLET_COUNT - 1) * size bullet_t]
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz loc_1CB44
xor di, di
jmp loc_1CAFC
@ -28106,12 +28106,12 @@ loc_1CB3B:
; ---------------------------------------------------------------------------
loc_1CB44:
mov al, _bullet_clear_trigger
mov al, _bullet_zap_active
mov ah, 0
mov bx, BULLET_DECAY_CELS
mov bx, BULLET_ZAP_CELS
cwd
idiv bx
add al, PAT_BULLET_KILL
add al, PAT_BULLET_ZAP
mov [bp+@@patnum], al
mov [bp+@@points], 1
mov [bp+var_6], 1
@ -28187,10 +28187,10 @@ loc_1CBF1:
mov _popup, offset popup_update_and_render
loc_1CC0A:
inc _bullet_clear_trigger
inc _bullet_zap_active
cmp [bp+@@patnum], PAT_BULLET16_D
jb short loc_1CC19
mov _bullet_clear_trigger, 0
mov _bullet_zap_active, 0
loc_1CC19:
cmp _bullet_clear_time, 0
@ -28228,7 +28228,7 @@ var_2 = byte ptr -2
var_1 = byte ptr -1
enter 2, 0
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short locret_1CF14
mov al, _bullet_template.count
mov [bp+var_2], al
@ -28255,7 +28255,7 @@ sub_1CF16 proc near
var_1 = byte ptr -1
enter 2, 0
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short locret_1CF30
mov al, _bullet_template.speed
mov [bp+var_1], al
@ -28278,7 +28278,7 @@ sub_1CF32 proc near
var_1 = byte ptr -1
enter 2, 0
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short locret_1CF4C
mov al, _bullet_template.speed
mov [bp+var_1], al
@ -28301,7 +28301,7 @@ sub_1CF4E proc near
var_1 = byte ptr -1
enter 2, 0
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short locret_1CF68
mov al, _bullet_template.speed
mov [bp+var_1], al
@ -28324,7 +28324,7 @@ sub_1CF6A proc near
var_1 = byte ptr -1
enter 2, 0
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short locret_1CF84
mov al, _bullet_template.speed
mov [bp+var_1], al
@ -28347,7 +28347,7 @@ sub_1CF86 proc near
var_1 = byte ptr -1
enter 2, 0
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short locret_1CFA0
mov al, _bullet_template.speed
mov [bp+var_1], al
@ -32520,7 +32520,7 @@ loc_1F855:
call boss_explode_big pascal, 2
mov _boss_phase, PHASE_EXPLODE_BIG
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
cmp _boss_mode_change, 0
jz short loc_1F878
push 28h ; '('
@ -34159,7 +34159,7 @@ loc_2066F:
call boss_explode_big pascal, 3
mov _boss_phase, PHASE_EXPLODE_BIG
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
cmp _boss_mode_change, 0
jz short loc_20693
push 0C8h

View File

@ -13,8 +13,8 @@ exalice_phase_end proc near
call boss_explode_small pascal, si
cmp _boss_phase_timed_out, 0
jnz short @@set
mov _bullet_clear_drop_point_items, 1
mov _bullet_clear_trigger, 1
mov _bullet_zap_drop_point_items, 1
mov _bullet_zap_active, 1
call _boss_items_drop
@@set:

View File

@ -69,7 +69,7 @@ b6balls_update proc near
@@no_cloud:
cmp _bullet_clear_time, 0
jnz short @@decay
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jz short @@motion_update
@@decay:

View File

@ -14,7 +14,7 @@ lasers_update proc near
jz @@next
cmp _bullet_clear_time, 0
jnz short @@shootout
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jz short @@switch
@@shootout:

View File

@ -58,8 +58,8 @@ typedef enum {
PAT_CLOUD_PELLET,
PAT_CLOUD_PELLET_last = (PAT_CLOUD_PELLET + BULLET_CLOUD_CELS - 1),
PAT_BULLET_KILL,
PAT_BULLET_KILL_last = (PAT_BULLET_KILL + BULLET_DECAY_CELS - 1),
PAT_BULLET_ZAP,
PAT_BULLET_ZAP_last = (PAT_BULLET_ZAP + BULLET_ZAP_CELS - 1),
PAT_DECAY_PELLET,
PAT_DECAY_PELLET_last = (PAT_DECAY_PELLET + BULLET_DECAY_CELS - 1),
PAT_DECAY_BULLET16,

View File

@ -30,7 +30,7 @@ PAT_BULLET16_V = 84
PAT_BULLET16_V_RED = PAT_BULLET16_V
PAT_BULLET16_V_BLUE = 116
PAT_CLOUD_PELLET = 148
PAT_BULLET_KILL = 152
PAT_BULLET_ZAP = 152
PAT_DECAY_PELLET = 156
PAT_DECAY_BULLET16 = 160
PAT_EXPLOSION_SMALL = 164

View File

@ -3959,7 +3959,7 @@ sub_EACE proc near
mov byte_25FF8, 0
mov byte_25FE8, 0
mov _palette_changed, 0
mov _bullet_clear_trigger, 0
mov _bullet_zap_active, 0
mov _stage_graze, 0
mov _circles_color, GC_R
call grc_setclip pascal, large (PLAYFIELD_LEFT shl 16) or PLAYFIELD_TOP, large ((PLAYFIELD_RIGHT - 1) shl 16) or (PLAYFIELD_BOTTOM - 1)
@ -5558,7 +5558,7 @@ loc_1016B:
loc_10171:
cmp [bp+@@i], BULLET16_COUNT
jl loc_100DE
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short loc_101DC
cmp _bullet_clear_time, 0
jnz short loc_101DC
@ -10106,7 +10106,7 @@ include th05/main/playperf_adjust_speed.asm
sub_15A5C proc near
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short locret_15A6E
push word ptr _bullet_template.BT_angle
call loc_15C94
@ -10123,7 +10123,7 @@ sub_15A5C endp
sub_15A70 proc near
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz short locret_15A8C
mov byte_221C0, 1
push word ptr _bullet_template.BT_angle
@ -12872,7 +12872,7 @@ var_2 = word ptr -2
mov _pellet_clouds_render_count, 0
mov _pellets_render_count, 0
mov si, offset _bullets[(BULLET_COUNT - 1) * size bullet_t]
cmp _bullet_clear_trigger, 0
cmp _bullet_zap_active, 0
jnz loc_17EC3
xor di, di
jmp loc_17E78
@ -13158,12 +13158,12 @@ loc_17EB5:
; ---------------------------------------------------------------------------
loc_17EC3:
mov al, _bullet_clear_trigger
mov al, _bullet_zap_active
mov ah, 0
mov bx, BULLET_DECAY_CELS
mov bx, BULLET_ZAP_CELS
cwd
idiv bx
add al, PAT_BULLET_KILL
add al, PAT_BULLET_ZAP
mov [bp+@@patnum], al
mov [bp+@@points], 1
mov [bp+var_6], 1
@ -13216,7 +13216,7 @@ loc_17F31:
loc_17F64:
mov [si+bullet_t.flag], 2
cmp _bullet_clear_drop_point_items, 0
cmp _bullet_zap_drop_point_items, 0
jz short loc_17F86
mov ax, [bp+var_2]
mov bx, 4
@ -13242,10 +13242,10 @@ loc_17F8D:
mov _popup, offset popup_update_and_render
loc_17FA8:
inc _bullet_clear_trigger
inc _bullet_zap_active
cmp [bp+@@patnum], 76 ; TH04 leftover; PAT_BULLET16_D in that game, unused here
jb short loc_17FB7
mov _bullet_clear_trigger, 0
mov _bullet_zap_active, 0
loc_17FB7:
cmp _bullet_clear_time, 0
@ -13420,7 +13420,7 @@ loc_1812B:
jge short loc_1818B
cmp _midboss_hp, 0
jg short loc_181C4
mov _bullet_clear_trigger, 1
mov _bullet_zap_active, 1
push 5
call sub_173AC
call items_add pascal, _midboss_pos.cur.x, _midboss_pos.cur.y, IT_BIGPOWER
@ -14446,7 +14446,7 @@ loc_18B24:
jge short loc_18B67
cmp _midboss_hp, 0
jg short loc_18BA0
mov _bullet_clear_trigger, 1
mov _bullet_zap_active, 1
push 0Fh
call sub_173AC
call items_add pascal, _midboss_pos.cur.x, _midboss_pos.cur.y, IT_BOMB
@ -15656,7 +15656,7 @@ loc_195A1:
loc_195BC:
cmp _midboss_hp, 0
jg short loc_19613
mov _bullet_clear_trigger, 1
mov _bullet_zap_active, 1
push 0Fh
call sub_173AC
call items_add pascal, _midboss_pos.cur.x, _midboss_pos.cur.y, IT_1UP
@ -18272,7 +18272,7 @@ loc_1AE8B:
loc_1AE98:
inc _boss_phase
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
mov _boss_phase_frame, 0
call snd_se_play pascal, 12
mov _player_invincibility_time, BOSS_DEFEAT_INVINCIBILITY_FRAMES
@ -18780,7 +18780,7 @@ loc_1B32F:
loc_1B34A:
cmp _midboss_hp, 0
jg short loc_1B3A1
mov _bullet_clear_trigger, 1
mov _bullet_zap_active, 1
push 0Fh
call sub_173AC
call items_add pascal, _midboss_pos.cur.x, _midboss_pos.cur.y, IT_BOMB
@ -23863,7 +23863,7 @@ loc_1E7F2:
jnb short loc_1E82B
cmp _midboss_hp, 0
jg short loc_1E864
mov _bullet_clear_trigger, 1
mov _bullet_zap_active, 1
push 1Eh
call sub_173AC
call items_add pascal, _midboss_pos.cur.x, _midboss_pos.cur.y, IT_1UP
@ -25310,7 +25310,7 @@ loc_1F643:
mov _boss_phase_frame, 0
mov _boss_phase, PHASE_BOSS_EXPLODE_SMALL
mov _boss_custombullets_render, offset nullfunc_near
mov _bullet_clear_drop_point_items, 0
mov _bullet_zap_drop_point_items, 0
jmp short loc_1F666
; ---------------------------------------------------------------------------
@ -25659,7 +25659,7 @@ loc_1F936:
sub _midboss_hp, ax
cmp _midboss_hp, 0
jg short loc_1F9A1
mov _bullet_clear_trigger, 1
mov _bullet_zap_active, 1
push 1Eh
call sub_173AC
call items_add pascal, _midboss_pos.cur.x, _midboss_pos.cur.y, IT_1UP
@ -25838,7 +25838,7 @@ loc_1FBED:
call boss_explode_big
inc _boss_phase
mov al, _boss_mode_change
mov _bullet_clear_trigger, al
mov _bullet_zap_active, al
cmp _boss_mode_change, 0;m_bSuccessDefeat
jz short loc_1FC10
call sub_17416 pascal, [bp+n1000]
@ -26239,8 +26239,8 @@ asc_226B6 db ' ',0
; char aMaine_1[]
aMaine_1 db 'maine',0
db 0
public _bullet_clear_drop_point_items
_bullet_clear_drop_point_items db 0
public _bullet_zap_drop_point_items
_bullet_zap_drop_point_items db 0
db 0
byte_226C2 db 0
db 0