From 4d24ca53bdebe46d8043477f2c452cb65d06223c Mon Sep 17 00:00:00 2001 From: nmlgc Date: Thu, 22 Jul 2021 20:48:47 +0200 Subject: [PATCH] [Decompilation] [th04/th05] Bullets: Update function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … (24 + (difficulty * 8) + rank) in TH04, and (42 + (difficulty * 8)) in TH05. Also, TH05 only doesn't have TH04's bullet zap animation because ZUN didn't consistently use constants… Completes P0151, funded by Blue Bolt and -Tom-. --- Makefile.mak | 4 +- Research/Borland C++ decompilation.md | 16 + th01/math/overlap.hpp | 18 ++ th02/main/playfld.hpp | 19 +- th04/bullet_u.cpp | 2 + th04/main/bullet/add.cpp | 3 + th04/main/bullet/bullet.hpp | 19 +- th04/main/bullet/update.cpp | 335 +++++++++++++++++++++ th04/main/hud/hud.h | 3 + th04/main/player/player.inc | 2 - th04/main/pointnum/pointnum.hpp | 4 +- th04/main/score.hpp | 2 + th04/main032.cpp | 9 + th04/sprites/cels.inc | 1 - th04/sprites/main_pat.h | 2 + th04/sprites/main_pat.inc | 3 - th04_main.asm | 389 +----------------------- th05/bullet_u.cpp | 2 + th05/sprites/main_pat.h | 2 + th05/sprites/main_pat.inc | 3 - th05_main.asm | 408 +------------------------- 21 files changed, 429 insertions(+), 817 deletions(-) create mode 100644 th04/bullet_u.cpp create mode 100644 th05/bullet_u.cpp diff --git a/Makefile.mak b/Makefile.mak index c00339d6..2a80682f 100644 --- a/Makefile.mak +++ b/Makefile.mak @@ -138,7 +138,7 @@ bin\th04\op.exe: bin\th04\op.obj th04\m_char.cpp bin\th01\vplanset.obj bin\frmde $** | -bin\th04\main.exe: bin\th04\main.obj bin\th04\slowdown.obj bin\th04\player_p.obj bin\th04\scoreupd.obj th04\main011.cpp bin\th04\cfg_lres.obj bin\th01\vplanset.obj bin\th03\vector2.obj bin\frmdely1.obj bin\hfliplut.obj th04\mpn_free.cpp bin\th04\input_w.obj th04\mpn_l_i.cpp bin\th04\vector.obj bin\th04\snd_pmdr.obj bin\th04\snd_mmdr.obj bin\th04\snd_kaja.obj bin\th04\snd_mode.obj bin\th04\snd_load.obj bin\th04\cdg_put.obj bin\th04\exit.obj bin\th04\initmain.obj bin\th04\cdg_p_na.obj bin\th04\cdg_p_pr.obj bin\th04\input_s.obj bin\th04\snd_se_r.obj bin\th04\snd_se.obj bin\th04\cdg_load.obj th04\gather.cpp bin\th04\scrolly3.obj bin\th04\motion_3.obj th04\main032.cpp +bin\th04\main.exe: bin\th04\main.obj bin\th04\slowdown.obj bin\th04\player_p.obj bin\th04\scoreupd.obj th04\main011.cpp bin\th04\cfg_lres.obj bin\th01\vplanset.obj bin\th03\vector2.obj bin\frmdely1.obj bin\hfliplut.obj th04\mpn_free.cpp bin\th04\input_w.obj th04\mpn_l_i.cpp bin\th04\vector.obj bin\th04\snd_pmdr.obj bin\th04\snd_mmdr.obj bin\th04\snd_kaja.obj bin\th04\snd_mode.obj bin\th04\snd_load.obj bin\th04\cdg_put.obj bin\th04\exit.obj bin\th04\initmain.obj bin\th04\cdg_p_na.obj bin\th04\cdg_p_pr.obj bin\th04\input_s.obj bin\th04\snd_se_r.obj bin\th04\snd_se.obj bin\th04\cdg_load.obj th04\gather.cpp bin\th04\scrolly3.obj bin\th04\motion_3.obj th04\bullet_u.cpp th04\main032.cpp $(CC) $(CFLAGS) $(LARGE_LFLAGS) -DGAME=4 -DBINARY='M' -3 -Z -nbin\th04\ -eMAIN.EXE @&&| $** | @@ -161,7 +161,7 @@ bin\th05\op.exe: th05\op010.cpp bin\th05\op.obj th05\op011.cpp th05\m_char.cpp b $** | -bin\th05\main.exe: bin\th05\main.obj bin\th04\slowdown.obj bin\th05\cfg_lres.obj th05\main010.cpp th05\main011.cpp th05\p_common.cpp th05\p_reimu.cpp th05\p_marisa.cpp th05\p_mima.cpp th05\p_yuuka.cpp bin\th05\player.obj bin\th05\hud_bar.obj bin\th05\scoreupd.obj th05\main012.cpp bin\th04\player_p.obj th05\main013.cpp bin\th03\vector2.obj bin\hfliplut.obj bin\th04\snd_pmdr.obj bin\th04\snd_mmdr.obj bin\th04\snd_mode.obj bin\th05\bullet.obj bin\th04\cdg_p_na.obj bin\th04\snd_se_r.obj bin\th04\snd_se.obj bin\th05\cdg_put.obj bin\th04\exit.obj bin\th05\vector.obj bin\th05\snd_load.obj bin\th05\snd_kaja.obj bin\th05\initmain.obj bin\th05\input_s.obj bin\th05\inp_h_w.obj bin\th05\frmdelay.obj bin\th04\cdg_load.obj bin\th04\scrolly3.obj bin\th04\motion_3.obj th05\main031.cpp th05\gather.cpp th05\main032.cpp th05\main034.cpp th05\main035.cpp +bin\th05\main.exe: bin\th05\main.obj bin\th04\slowdown.obj bin\th05\cfg_lres.obj th05\main010.cpp th05\main011.cpp th05\p_common.cpp th05\p_reimu.cpp th05\p_marisa.cpp th05\p_mima.cpp th05\p_yuuka.cpp bin\th05\player.obj bin\th05\hud_bar.obj bin\th05\scoreupd.obj th05\main012.cpp bin\th04\player_p.obj th05\main013.cpp bin\th03\vector2.obj bin\hfliplut.obj bin\th04\snd_pmdr.obj bin\th04\snd_mmdr.obj bin\th04\snd_mode.obj bin\th05\bullet.obj bin\th04\cdg_p_na.obj bin\th04\snd_se_r.obj bin\th04\snd_se.obj bin\th05\cdg_put.obj bin\th04\exit.obj bin\th05\vector.obj bin\th05\snd_load.obj bin\th05\snd_kaja.obj bin\th05\initmain.obj bin\th05\input_s.obj bin\th05\inp_h_w.obj bin\th05\frmdelay.obj bin\th04\cdg_load.obj bin\th04\scrolly3.obj bin\th04\motion_3.obj th05\main031.cpp th05\gather.cpp th05\main032.cpp th05\bullet_u.cpp th05\main034.cpp th05\main035.cpp $(CC) $(CFLAGS) $(LARGE_LFLAGS) -3 -Z -DGAME=5 -DBINARY='M' -nbin\th05\ -eMAIN.EXE @&&| $** | diff --git a/Research/Borland C++ decompilation.md b/Research/Borland C++ decompilation.md index 2ae7f62d..b577cde0 100644 --- a/Research/Borland C++ decompilation.md +++ b/Research/Borland C++ decompilation.md @@ -345,6 +345,22 @@ void foo(int i) { ## Flags +### `-G` (Generate for speed) + +* Replaces + +```asm +ENTER , 0 +``` + +with + +```asm +PUSH BP +MOV BP, SP +SUB SP, +``` + ### `-Z` (Suppress register reloads) * The tracked contents of `ES` are reset after a conditional statement. If the diff --git a/th01/math/overlap.hpp b/th01/math/overlap.hpp index ac09f9b6..442c405e 100644 --- a/th01/math/overlap.hpp +++ b/th01/math/overlap.hpp @@ -23,6 +23,24 @@ #define overlap_xy_xywh_le_ge(x1, y1, x2, y2, w2, h2) \ overlap_xy_ltrb_le_ge(x1, y1, x2, y2, (x2 + w2), (y2 + h2)) +// Ugly, and should not exist, but generates one fewer instruction when used +// with _AX and _DX register pseudovariables... +#define overlap_offcenter_1d_inplace_fast(delta, dist_edge1, dist_edge2) ( \ + (unsigned int)((delta) += dist_edge1, delta) <= (dist_edge1 + dist_edge2) \ +) + +#define overlap_offcenter_inplace_fast( \ + delta_x, delta_y, dist_to_left, dist_to_top, dist_to_right, dist_to_bottom \ +) ( \ + overlap_offcenter_1d_inplace_fast(delta_x, dist_to_left, dist_to_right) && \ + overlap_offcenter_1d_inplace_fast(delta_y, dist_to_top, dist_to_bottom) \ +) + +#define overlap_wh_inplace_fast(delta_x, delta_y, w, h) \ + overlap_offcenter_inplace_fast( \ + delta_x, delta_y, (w / 2), (w / 2), (h / 2), (h / 2) \ + ) + #define overlap_points_wh_fast(p1, p2, p1_w, p1_h) ( \ ((unsigned int)((p1.x - p2.x) + (p1_w / 2)) <= (p1_w)) && \ ((unsigned int)((p1.y - p2.y) + (p1_h / 2)) <= (p1_h)) \ diff --git a/th02/main/playfld.hpp b/th02/main/playfld.hpp index 05dbc1bc..64643da5 100644 --- a/th02/main/playfld.hpp +++ b/th02/main/playfld.hpp @@ -24,11 +24,22 @@ void far playfield_tram_wipe(void); #endif +#define playfield_encloses_yx_lt_ge(center_x, center_y, w, h) ( \ + /* Casting the center coordinate allows macro to easily be used with */ \ + /* the _AX and _DX pseudoregisters after motion_update(). */ \ + (static_cast(center_y) >= to_sp(0 - (h / 2))) && \ + (static_cast(center_y) < to_sp(PLAYFIELD_H + (h / 2))) && \ + (static_cast(center_x) >= to_sp(0 - (w / 2))) && \ + (static_cast(center_x) < to_sp(PLAYFIELD_W + (w / 2))) \ +) + #define playfield_encloses(center_x, center_y, w, h) ( \ - (center_x > to_sp(0 - (w / 2))) && \ - (center_x < to_sp(PLAYFIELD_W + (w / 2))) && \ - (center_y > to_sp(0 - (h / 2))) && \ - (center_y < to_sp(PLAYFIELD_H + (h / 2))) \ + /* Casting the center coordinate allows macro to easily be used with */ \ + /* the _AX and _DX pseudoregisters after motion_update(). */ \ + (static_cast(center_x) > to_sp(0 - (w / 2))) && \ + (static_cast(center_x) < to_sp(PLAYFIELD_W + (w / 2))) && \ + (static_cast(center_y) > to_sp(0 - (h / 2))) && \ + (static_cast(center_y) < to_sp(PLAYFIELD_H + (h / 2))) \ ) #define playfield_encloses_point(center, w, h) \ diff --git a/th04/bullet_u.cpp b/th04/bullet_u.cpp new file mode 100644 index 00000000..af404554 --- /dev/null +++ b/th04/bullet_u.cpp @@ -0,0 +1,2 @@ +#pragma option -zCmain_032_TEXT -zPmain_03 +#include "th04/main/bullet/update.cpp" diff --git a/th04/main/bullet/add.cpp b/th04/main/bullet/add.cpp index ba46d366..c88d2d9b 100644 --- a/th04/main/bullet/add.cpp +++ b/th04/main/bullet/add.cpp @@ -433,6 +433,9 @@ bool near bullet_template_clip(void) { if( (bullet_clear_time > 0) && + // If a newly spawned bullet wouldn't fully decay during the remaining + // time, let's simply not spawn it at all? This way, they don't award + // points either. (bullet_clear_time <= (BMS_DECAY_FRAMES + 1)) ) { return true; diff --git a/th04/main/bullet/bullet.hpp b/th04/main/bullet/bullet.hpp index bfbda2e8..a456a52e 100644 --- a/th04/main/bullet/bullet.hpp +++ b/th04/main/bullet/bullet.hpp @@ -13,8 +13,9 @@ /// ---------------- /// Everything here needs to be kept in sync with the ASM versions in /// bullet.hpp! +static const int BMS_DECAY_FRAMES_PER_CEL = 4; #define BSS_CLOUD_FRAMES (BULLET_CLOUD_CELS * 4) -#define BMS_DECAY_FRAMES (BULLET_DECAY_CELS * 4) +#define BMS_DECAY_FRAMES (BULLET_DECAY_CELS * BMS_DECAY_FRAMES_PER_CEL) // Regular bullets with a given speed below BMS_SLOWDOWN_THRESHOLD are set to // BMS_SLOWDOWN. This fires them at BMS_SLOWDOWN_BASE_SPEED instead, and then @@ -39,6 +40,8 @@ enum bullet_spawn_state_t { BSS_CLOUD_FORWARDS = 4, BSS_CLOUD_END = (BSS_CLOUD_FORWARDS + BSS_CLOUD_FRAMES), /// ------------------------ + + _bullet_spawn_state_t_FORCE_UINT8 = 0xFF }; enum bullet_move_state_t { @@ -57,6 +60,8 @@ enum bullet_move_state_t { BMS_DECAY = 4, BMS_DECAY_END = (BMS_DECAY + BMS_DECAY_FRAMES), /// ---------------- + + _bullet_move_state_t_FORCE_UINT8 = 0xFF }; enum bullet_special_motion_t { @@ -65,7 +70,7 @@ enum bullet_special_motion_t { // Needs to be kept in sync with the ASM version in bullet.inc! struct bullet_t { - char flag; + unsigned char flag; char age; PlayfieldMotion pos; unsigned char from_group; // unused @@ -75,12 +80,14 @@ struct bullet_t { bullet_spawn_state_t spawn_state; bullet_move_state_t move_state; bullet_special_motion_t special_motion; - unsigned char speed_final; + SubpixelLength8 speed_final; union { unsigned char slowdown_time; // with BMS_SLOWDOWN unsigned char turn_count; // with BMS_SPECIAL } ax; union { + // Difference between [speed_final] and the BMS_SLOWDOWN_BASE_SPEED. + // Always positive for BMS_SLOWDOWN bullets. unsigned char slowdown_speed_delta; // with BMS_SLOWDOWN unsigned char turn_angle; // with BMS_SPECIAL } dx; @@ -113,6 +120,8 @@ int pascal near bullet_patnum_for_angle(int patnum_base, unsigned char angle); // Updates [bullet]'s patnum based on its current angle. void pascal near bullet_update_patnum(bullet_t near *bullet); +// Turns every 4th bullet into a point item when zapping bullets. +extern bool bullet_zap_drop_point_items; #else # define PELLET_COUNT 240 # define BULLET16_COUNT 200 @@ -120,9 +129,6 @@ void pascal near bullet_update_patnum(bullet_t near *bullet); // Returns the offset for a directional bullet sprite that shows the given // [angle]. unsigned char pascal near bullet_patnum_for_angle(unsigned char angle); - -// 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) @@ -144,6 +150,7 @@ extern union { unsigned char frames; // doubles as the animation timer } bullet_zap; static const int BULLET_ZAP_FRAMES_PER_CEL = 4; +// ZUN bug: Effectively 1 in TH05, see bullets_update() for the cause. static const int BULLET_ZAP_FRAMES = ( BULLET_ZAP_CELS * BULLET_ZAP_FRAMES_PER_CEL ); diff --git a/th04/main/bullet/update.cpp b/th04/main/bullet/update.cpp index b1104929..344660b1 100644 --- a/th04/main/bullet/update.cpp +++ b/th04/main/bullet/update.cpp @@ -1,6 +1,341 @@ +#pragma option -G + +extern "C" { +#include "platform.h" +#include "pc98.h" +#include "planar.h" +#include "th01/math/overlap.hpp" +#include "th01/math/subpixel.hpp" +#include "th04/math/motion.hpp" +#include "th04/math/vector.hpp" +#include "th04/main/frames.h" +#include "th04/main/scroll.hpp" +#include "th04/main/playfld.hpp" +#include "th04/main/playperf.hpp" +#include "th04/main/rank.hpp" +#include "th04/main/score.hpp" +#include "th04/main/slowdown.hpp" +#include "th04/main/spark.hpp" #include "th04/main/bullet/bullet.hpp" +#include "th04/main/hud/hud.h" +#include "th04/main/hud/popup.hpp" +#include "th04/main/player/player.hpp" +#include "th04/main/pointnum/pointnum.hpp" +#include "th04/main/gather.hpp" + +#if (GAME == 5) + #include "th04/main/item/items.hpp" + #include "th05/sprites/main_pat.h" + + static const int SLOWDOWN_BULLET_THRESHOLD_UNUSED = 32; +#else + #include "th04/sprites/main_pat.h" + + static const int SLOWDOWN_BULLET_THRESHOLD_UNUSED = 24; +#endif + +#pragma option -a2 void pascal near bullet_turn_x(bullet_t near &bullet) ; void pascal near bullet_turn_y(bullet_t near &bullet) ; + +void pascal near bullet_update_special(bullet_t near &bullet); + +#pragma option -G + +void bullets_update(void) +{ + int i; + int bullets_seen = 0; + #if (GAME == 5) + pellet_clouds_render_count = 0; + #endif + pellets_render_count = 0; + bullet_t near *bullet = &bullets[BULLET_COUNT - 1]; + + // Since we iterate over the bullet array backwards, we encounter the 16×16 + // bullets first. + #define is_bullet16(i) \ + (i < BULLET16_COUNT) + + #define is_pellet(i) \ + !is_bullet16(i) + + if(bullet_zap.active == false) { + for(i = 0; i < BULLET_COUNT; i++, bullet--) { + if(bullet->flag == 0) { + continue; + } + if(bullet->flag == 2) { + bullet->flag = 0; + continue; + } + bullets_seen++; + if(bullet_clear_time) { + if(bullet->move_state < BMS_DECAY) { + bullet->move_state = BMS_DECAY; + bullet->patnum = is_bullet16(i) + ? PAT_DECAY_BULLET16 + : PAT_DECAY_PELLET; + + if(bullet->age != 0) { + score_delta += 100; + } else { + score_delta += 10; + } + } else { + reinterpret_cast(bullet->move_state)++; + if(bullet->move_state >= BMS_DECAY_END) { + bullet->pos.update_seg3(); + bullet->flag = 2; + continue; + } + if((bullet->move_state % BMS_DECAY_FRAMES_PER_CEL) == 0) { + bullet->patnum++; + } + } + } + bullet->age++; + if(bullet->spawn_state >= BSS_ACTIVE) { + if(bullet->spawn_state == BSS_ACTIVE) { + bullet->spawn_state = BSS_GRAZEABLE; + } else { + // In delay cloud state + if(bullet->spawn_state == BSS_CLOUD_BACKWARDS) { + bullet->pos.prev = bullet->pos.cur; + bullet->pos.cur.x.v -= (bullet->pos.velocity.x.v << 3); + bullet->pos.cur.y.v -= (bullet->pos.velocity.y.v << 3); + bullet->spawn_state = BSS_CLOUD_FORWARDS; + } else if(bullet->spawn_state == BSS_CLOUD_FORWARDS) { + bullet->pos.update_seg3(); + } else { + bullet->pos.prev = bullet->pos.cur; + bullet->pos.cur.x.v += (bullet->pos.velocity.x.v / 3); + bullet->pos.cur.y.v += (bullet->pos.velocity.y.v / 3); + } + reinterpret_cast(bullet->spawn_state)++; + if(bullet->spawn_state >= BSS_CLOUD_END) { + #if (GAME == 5) + if(!playfield_encloses_yx_lt_ge( + bullet->pos.cur.x, + bullet->pos.cur.y, + BULLET16_W, + BULLET16_H + )) { + bullet->flag = 2; + continue; + } + #endif + bullet->spawn_state = BSS_ACTIVE; + } + #if (GAME == 5) + else if(is_pellet(i)) { + pellet_clouds_render[pellet_clouds_render_count++] = + bullet; + } + #endif + continue; + } + } + if(bullet->move_state == BMS_SPECIAL) { + bullet_update_special(*bullet); + } else if(bullet->move_state == BMS_SLOWDOWN) { + bullet->ax.slowdown_time--; + bullet->speed_cur.v = (bullet->speed_final.v + (( + bullet->ax.slowdown_time * bullet->dx.slowdown_speed_delta + ) / BMS_SLOWDOWN_FRAMES)); + if(bullet->ax.slowdown_time == 0) { + bullet->speed_cur = bullet->speed_final; + bullet->move_state = BMS_REGULAR; + } + vector2_near( + bullet->pos.velocity, bullet->angle, bullet->speed_cur + ); + } + + /* DX:AX = */ bullet->pos.update_seg3(); + if(!playfield_encloses(_AX, _DX, BULLET16_W, BULLET16_H)) { + bullet->flag = 2; + continue; + } + + if(bullet_clear_time != 0) { + continue; + } + _AX -= player_pos.cur.x.v; + _DX -= player_pos.cur.y.v; + if(player_invincibility_time == 0) { + // Yup, a bullet must have been grazed in a previous frame + // before it can be collided with. + if(bullet->spawn_state != BSS_GRAZEABLE) { + if(overlap_wh_inplace_fast( + _AX, _DX, BULLET_KILLBOX_W, BULLET_KILLBOX_H + )) { + bullet->flag = 2; + player_is_hit = true; + continue; + } + } else { + // Yes, the graze box is biased to the right, and taller + // than wide. + if(overlap_offcenter_inplace_fast( + _AX, _DX, + to_sp(16.0f), to_sp(22.0f), to_sp(20.0f), to_sp(22.0f) + )) { + /* TODO: Replace with the decompiled call + * sparks_add_random(bullet->pos.cur.x, bullet->pos.cur.y, to_sp(2.0f), 2); + * once that function is part of this translation unit */ + __asm { + db 0xFF, 0x74, 0x02; + db 0xFF, 0x74, 0x04; + db 0x66, 0x68, 2, 0x00, (2 * 16), 0x00; + nop; + push cs; + call near ptr sparks_add_random; + } + bullet->spawn_state = BSS_GRAZED; + if(stage_graze < STAGE_GRAZE_CAP) { + stage_graze++; + hud_graze_put(); + score_delta += graze_score; + } + } + } + } + + if(is_pellet(i)) { + pellets_render[pellets_render_count].top.left = ( + bullet->pos.cur.to_screen_left(PELLET_W) + ); + pellets_render[pellets_render_count].top.top = ( + bullet->pos.cur.to_vram_top_scrolled_seg3(PELLET_H) + ); + pellets_render_count++; + } + } + if(turbo_mode == false) { + #if (GAME == 5) + slowdown_caused_by_bullets = false; + i = 42; + #else + i = 24; + i += playperf; + #endif + i += (rank * 8); + if(bullets_seen >= i) { + if(!stage_frame_mod2) { + slowdown_factor = 2; + #if (GAME == 5) + slowdown_caused_by_bullets = true; + #endif + } + } else if(bullets_seen >= (i + SLOWDOWN_BULLET_THRESHOLD_UNUSED)) { + // Yes, never executed, as the first condition would then have + // been true as well + slowdown_factor = 2; + #if (GAME == 5) + slowdown_caused_by_bullets = true; + #endif + } + } + } else { + // A bit wasteful to run all of this every frame, since no new bullets + // are spawned while [bullet_zap] is active; the bullet spawn wrapper + // functions prevent that. Then again, this means that the code here + // does kind of rely on bullets not being spawned through other methods. + + unsigned int score_per_bullet; + unsigned int score_step; + + // Without this cap, the [popup_bonus] formula would be + // 0.5n³ - n² + 1.5n + // with n = [bullets_seen]. + unsigned int score_per_bullet_cap; + unsigned char patnum; + + patnum = + (PAT_BULLET_ZAP + (bullet_zap.frames / BULLET_ZAP_FRAMES_PER_CEL) + ); + score_per_bullet = 1; + score_step = 1; + #if (GAME == 5) + // ZUN bug: All code below uses TH04's patnum for that sprite. This + // causes the decay animation to never actually play in TH05. + #define PAT_BULLET_ZAP 72 + + score_per_bullet_cap = (rank == RANK_EXTRA) + ? 1600 + : select_for_rank(960, 1280, 1280, 1280); + #else + switch(rank) { + case RANK_EASY: + score_per_bullet_cap = 1000; + break; + case RANK_NORMAL: + case RANK_HARD: + case RANK_LUNATIC: + score_per_bullet_cap = 1600; + break; + case RANK_EXTRA: + score_per_bullet_cap = 2000; + break; + } + #endif + + popup_bonus = 0; + for(i = 0; i < BULLET_COUNT; i++, bullet--) { + if(bullet->flag != 1) { + continue; + } + bullet->pos.velocity.set(0.0f, 0.0f); + bullet->pos.update_seg3(); + + // ZUN bug: Always false in TH05, see above + if(patnum < (PAT_BULLET_ZAP + BULLET_DECAY_CELS)) { + bullet->patnum = patnum; + #if (GAME == 5) + bullets_seen++; + #endif + continue; + } + popup_bonus += score_per_bullet; + score_delta += score_per_bullet; + pointnums_add_white( + bullet->pos.cur.x, bullet->pos.cur.y, score_per_bullet + ); + + score_per_bullet += score_step; + score_step += 3; + if(score_per_bullet > score_per_bullet_cap) { + score_per_bullet = score_per_bullet_cap; + } + + bullet->flag = 2; + #if (GAME == 5) + if(bullet_zap_drop_point_items && ((bullets_seen % 4) == 0)) { + items_add(bullet->pos.cur.x, bullet->pos.cur.y, IT_POINT); + } + bullets_seen++; + #endif + } + // Note that this would show only one popup even *if* bullets could + // spawn during the zap frames: Popups can be changed at least every + // 64 frames, and BULLET_ZAP_FRAMES is smaller. + if(popup_bonus) { + popup_show(POPUP_ID_BONUS); + } + bullet_zap.frames++; + + // ZUN bug: Always true in TH05, see above + if(patnum >= (PAT_BULLET_ZAP + BULLET_ZAP_CELS)) { + bullet_zap.active = false; + } + } + if(bullet_clear_time) { + bullet_clear_time--; + } +} + +} diff --git a/th04/main/hud/hud.h b/th04/main/hud/hud.h index 35a55f03..7cbac246 100644 --- a/th04/main/hud/hud.h +++ b/th04/main/hud/hud.h @@ -23,4 +23,7 @@ void pascal hud_hp_put(int bar_value); // Renders the HP bar at the fraction of ([hp_cur] / [hp_max]), or instead // takes asingle fill step if the previous bar value was lower. void pascal hud_hp_update_and_render(int hp_cur, int hp_max); + +// Displays [stage_graze] in the graze row. +void pascal hud_graze_put(); // ---------- diff --git a/th04/main/player/player.inc b/th04/main/player/player.inc index 59ee1e0a..fc99781b 100644 --- a/th04/main/player/player.inc +++ b/th04/main/player/player.inc @@ -3,8 +3,6 @@ PLAYER_OPTION_W = 16 PLAYER_OPTION_H = 16 PLAYER_OPTION_DISTANCE = (PLAYER_W / 2) + (PLAYER_OPTION_W / 2) -GRAZE_MAX = 999 - ; Shots ; ----- SHOT_W = 16 diff --git a/th04/main/pointnum/pointnum.hpp b/th04/main/pointnum/pointnum.hpp index 8a831886..19b64799 100644 --- a/th04/main/pointnum/pointnum.hpp +++ b/th04/main/pointnum/pointnum.hpp @@ -54,10 +54,10 @@ extern unsigned char pointnum_white_p; ); #endif -int pascal pointnum_add_white( +void pascal near pointnums_add_white( Subpixel center_x, Subpixel center_y, uint16_t points ); -int pascal pointnum_add_yellow( +void pascal near pointnums_add_yellow( Subpixel center_x, Subpixel center_y, uint16_t points ); diff --git a/th04/main/score.hpp b/th04/main/score.hpp index 16ab4a3f..fdc3cce8 100644 --- a/th04/main/score.hpp +++ b/th04/main/score.hpp @@ -1,5 +1,7 @@ #include "th04/score.h" +static const unsigned int STAGE_GRAZE_CAP = 999; + extern unsigned int graze_score; // Set per difficulty. extern unsigned int stage_graze; // Reset to 0 when moving to a new stage. diff --git a/th04/main032.cpp b/th04/main032.cpp index a494d5c3..4e6215bc 100644 --- a/th04/main032.cpp +++ b/th04/main032.cpp @@ -16,10 +16,19 @@ extern "C" { #include "th04/math/randring.h" #include "th04/math/vector.hpp" #include "th04/sprites/main_pat.h" +#include "th04/main/frames.h" #include "th04/main/playfld.hpp" #include "th04/main/playperf.hpp" #include "th04/main/player/player.hpp" #include "th04/main/bullet/bullet.hpp" +#include "th04/main/hud/hud.h" +#include "th04/main/hud/popup.hpp" +#include "th04/main/pointnum/pointnum.hpp" +#include "th04/main/rank.hpp" +#include "th04/main/spark.hpp" +#include "th04/main/score.hpp" +#include "th04/main/scroll.hpp" +#include "th04/main/slowdown.hpp" #include "th04/main/gather.hpp" #pragma option -a2 diff --git a/th04/sprites/cels.inc b/th04/sprites/cels.inc index b368f4e9..99d4818a 100644 --- a/th04/sprites/cels.inc +++ b/th04/sprites/cels.inc @@ -3,6 +3,5 @@ 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 diff --git a/th04/sprites/main_pat.h b/th04/sprites/main_pat.h index 04905846..ae146911 100644 --- a/th04/sprites/main_pat.h +++ b/th04/sprites/main_pat.h @@ -101,4 +101,6 @@ typedef enum { PAT_YUUKA6_VANISH_3 = 180, // -------- /// ======= + + _main_patnum_t_FORCE_INT16 = 0x7FFF, } main_patnum_t; diff --git a/th04/sprites/main_pat.inc b/th04/sprites/main_pat.inc index ec066835..62b4e3b0 100644 --- a/th04/sprites/main_pat.inc +++ b/th04/sprites/main_pat.inc @@ -19,12 +19,9 @@ 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_ZAP = 72 PAT_BULLET16_D = 76 PAT_BULLET16_D_BLUE = PAT_BULLET16_D PAT_BULLET16_D_YELLOW = 92 -PAT_DECAY_PELLET = 108 -PAT_DECAY_BULLET16 = 112 PAT_YUUKA6_PARASOL_BACK_OPEN = 128 PAT_YUUKA6_PARASOL_BACK_HALFOPEN = 130 diff --git a/th04_main.asm b/th04_main.asm index 4936f444..2ed6c4e5 100644 --- a/th04_main.asm +++ b/th04_main.asm @@ -27808,396 +27808,10 @@ off_1C8B6 dw offset loc_1C755 dw offset loc_1C885 dw offset loc_1C8A2 bullet_update_special endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame -public _bullets_update -_bullets_update proc far - -@@patnum = byte ptr -9 -var_8 = word ptr -8 -var_6 = word ptr -6 -@@points = word ptr -4 -var_2 = word ptr -2 - - push bp - mov bp, sp - sub sp, 0Ah - push si - push di - mov [bp+var_2], 0 - mov _pellets_render_count, 0 - mov si, offset _bullets[(BULLET_COUNT - 1) * size bullet_t] - cmp _bullet_zap_active, 0 - jnz loc_1CB44 - xor di, di - jmp loc_1CAFC -; --------------------------------------------------------------------------- - -loc_1C8EC: - cmp [si+bullet_t.flag], 0 - jz loc_1CAF8 - cmp [si+bullet_t.flag], 2 - jnz short loc_1C8FE - mov [si+bullet_t.flag], 0 - jmp loc_1CAF8 -; --------------------------------------------------------------------------- - -loc_1C8FE: - inc [bp+var_2] - cmp _bullet_clear_time, 0 - jz short loc_1C961 - cmp [si+bullet_t.move_state], BMS_DECAY - jnb short loc_1C939 - mov [si+bullet_t.move_state], BMS_DECAY - cmp di, BULLET16_COUNT - jge short loc_1C91D - mov ax, PAT_DECAY_BULLET16 - jmp short loc_1C920 -; --------------------------------------------------------------------------- - -loc_1C91D: - mov ax, PAT_DECAY_PELLET - -loc_1C920: - mov [si+bullet_t.BULLET_patnum], ax - cmp [si+bullet_t.age], 0 - jz short loc_1C931 - add _score_delta, 100 - jmp short loc_1C961 -; --------------------------------------------------------------------------- - -loc_1C931: - add _score_delta, 10 - jmp short loc_1C961 -; --------------------------------------------------------------------------- - -loc_1C939: - inc [si+bullet_t.move_state] - cmp [si+bullet_t.move_state], BMS_DECAY_END - jb short loc_1C94F - lea ax, [si+bullet_t.pos] - call @PlayfieldMotion@update_seg3$qv pascal, ax - mov [si+bullet_t.flag], 2 - jmp loc_1CAF8 -; --------------------------------------------------------------------------- - -loc_1C94F: - mov al, [si+bullet_t.move_state] - mov ah, 0 - mov bx, (BMS_DECAY_FRAMES / BULLET_DECAY_CELS) - cwd - idiv bx - or dx, dx - jnz short loc_1C961 - inc [si+bullet_t.BULLET_patnum] - -loc_1C961: - inc [si+bullet_t.age] - cmp [si+bullet_t.spawn_state], BSS_ACTIVE - jb short loc_1C9DA - cmp [si+bullet_t.spawn_state], BSS_ACTIVE - jnz short loc_1C976 - mov [si+bullet_t.spawn_state], BSS_GRAZEABLE - jmp short loc_1C9DA -; --------------------------------------------------------------------------- - -loc_1C976: - cmp [si+bullet_t.spawn_state], BSS_CLOUD_BACKWARDS - jnz short loc_1C99C - mov eax, dword ptr [si+bullet_t.pos.cur] - mov dword ptr [si+bullet_t.pos.prev], eax - mov ax, [si+bullet_t.pos.velocity.x] - shl ax, 3 - sub [si+bullet_t.pos.cur.x], ax - mov ax, [si+bullet_t.pos.velocity.y] - shl ax, 3 - sub [si+bullet_t.pos.cur.y], ax - mov [si+bullet_t.spawn_state], BSS_CLOUD_FORWARDS - jmp short loc_1C9C8 -; --------------------------------------------------------------------------- - -loc_1C99C: - cmp [si+bullet_t.spawn_state], BSS_CLOUD_FORWARDS - jnz short loc_1C9AB - lea ax, [si+bullet_t.pos] - call @PlayfieldMotion@update_seg3$qv pascal, ax - jmp short loc_1C9C8 -; --------------------------------------------------------------------------- - -loc_1C9AB: - mov eax, dword ptr [si+bullet_t.pos.cur] - mov dword ptr [si+bullet_t.pos.prev], eax - mov ax, [si+bullet_t.pos.velocity.x] - mov bx, 3 - cwd - idiv bx - add [si+bullet_t.pos.cur.x], ax - mov ax, [si+bullet_t.pos.velocity.y] - cwd - idiv bx - add [si+bullet_t.pos.cur.y], ax - -loc_1C9C8: - inc [si+bullet_t.spawn_state] - cmp [si+bullet_t.spawn_state], BSS_CLOUD_END - jb loc_1CAF8 - mov [si+bullet_t.spawn_state], BSS_ACTIVE - jmp loc_1CAF8 -; --------------------------------------------------------------------------- - -loc_1C9DA: - cmp [si+bullet_t.move_state], BMS_SPECIAL - jnz short loc_1C9E6 - call bullet_update_special pascal, si - jmp short loc_1CA27 -; --------------------------------------------------------------------------- - -loc_1C9E6: - cmp [si+bullet_t.move_state], BMS_SLOWDOWN - jnz short loc_1CA27 - dec [si+bullet_t.slowdown_time] - mov al, [si+bullet_t.slowdown_time] - mov ah, 0 - mov dl, [si+bullet_t.slowdown_speed_delta] - mov dh, 0 - imul dx - mov bx, BMS_SLOWDOWN_FRAMES - cwd - idiv bx - add al, [si+bullet_t.speed_final] - mov [si+bullet_t.speed_cur], al - cmp [si+bullet_t.slowdown_time], 0 - jnz short loc_1CA17 - mov al, [si+bullet_t.speed_final] - mov [si+bullet_t.speed_cur], al - mov [si+bullet_t.move_state], BMS_REGULAR - -loc_1CA17: - lea ax, [si+bullet_t.pos.velocity] - push ax - push word ptr [si+bullet_t.BULLET_angle] - mov al, [si+bullet_t.speed_cur] - mov ah, 0 - push ax - call vector2_near - -loc_1CA27: - lea ax, [si+bullet_t.pos] - call @PlayfieldMotion@update_seg3$qv pascal, ax - cmp ax, (-8 shl 4) - jle short loc_1CA43 - cmp ax, ((PLAYFIELD_W + 8) shl 4) - jge short loc_1CA43 - cmp dx, (-8 shl 4) - jle short loc_1CA43 - cmp dx, ((PLAYFIELD_H + 8) shl 4) - jl short loc_1CA49 - -loc_1CA43: - mov [si+bullet_t.flag], 2 - jmp loc_1CAF8 -; --------------------------------------------------------------------------- - -loc_1CA49: - cmp _bullet_clear_time, 0 - jnz loc_1CAF8 - sub ax, _player_pos.cur.x - sub dx, _player_pos.cur.y - cmp _player_invincibility_time, 0 - jnz short loc_1CAC5 - cmp [si+bullet_t.spawn_state], BSS_GRAZEABLE - jz short loc_1CA82 - add ax, (4 shl 4) - cmp ax, (8 shl 4) - ja short loc_1CAC5 - add dx, (4 shl 4) - cmp dx, (8 shl 4) - ja short loc_1CAC5 - mov [si+bullet_t.flag], 2 - mov _player_is_hit, 1 - jmp short loc_1CAF8 -; --------------------------------------------------------------------------- - -loc_1CA82: - add ax, (16 shl 4) - cmp ax, (36 shl 4) - ja short loc_1CAC5 - add dx, (22 shl 4) - cmp dx, (44 shl 4) - ja short loc_1CAC5 - push [si+bullet_t.pos.cur.x] - push [si+bullet_t.pos.cur.y] - push large (((2 shl 4) shl 16) or 2) - nopcall sparks_add_random - mov [si+bullet_t.spawn_state], BSS_GRAZED - cmp _stage_graze, GRAZE_MAX - jnb short loc_1CAC5 - inc _stage_graze - call hud_graze_put - movzx eax, _graze_score - add _score_delta, eax - -loc_1CAC5: - cmp di, BULLET16_COUNT - jl short loc_1CAF8 - mov ax, [si+bullet_t.pos.cur.x] - sar ax, 4 - add ax, (PLAYFIELD_LEFT - (PELLET_W / 2)) - mov bx, _pellets_render_count - shl bx, 2 - mov _pellets_render[bx].PRT_left, ax - mov ax, [si+bullet_t.pos.cur.y] - add ax, ((PLAYFIELD_TOP - (PELLET_H / 2)) shl 4) - call scroll_subpixel_y_to_vram_seg3 pascal, ax - mov bx, _pellets_render_count - shl bx, 2 - mov _pellets_render[bx].PRT_top, ax - inc _pellets_render_count - -loc_1CAF8: - inc di - sub si, size bullet_t - -loc_1CAFC: - cmp di, BULLET_COUNT - jl loc_1C8EC - cmp _turbo_mode, 0 - jnz loc_1CC19 - mov di, 24 - mov al, _playperf - mov ah, 0 - add di, ax - mov al, _rank - mov ah, 0 - shl ax, 3 - add di, ax - cmp [bp+var_2], di - jl short loc_1CB31 - cmp _stage_frame_mod2, 0 - jnz loc_1CC19 - jmp short loc_1CB3B -; --------------------------------------------------------------------------- - -loc_1CB31: - lea ax, [di+18h] - cmp ax, [bp+var_2] - jg loc_1CC19 - -loc_1CB3B: - mov _slowdown_factor, 2 - jmp loc_1CC19 -; --------------------------------------------------------------------------- - -loc_1CB44: - mov al, _bullet_zap_active - mov ah, 0 - mov bx, BULLET_ZAP_CELS - cwd - idiv bx - add al, PAT_BULLET_ZAP - mov [bp+@@patnum], al - mov [bp+@@points], 1 - mov [bp+var_6], 1 - mov al, _rank - mov ah, 0 - mov bx, ax - cmp bx, RANK_EXTRA - ja short loc_1CB84 - add bx, bx - jmp cs:off_1CC29[bx] - -loc_1CB71: - mov [bp+var_8], 1000 - jmp short loc_1CB84 -; --------------------------------------------------------------------------- - -loc_1CB78: - mov [bp+var_8], 1600 - jmp short loc_1CB84 -; --------------------------------------------------------------------------- - -loc_1CB7F: - mov [bp+var_8], 2000 - -loc_1CB84: - mov _popup_bonus, 0 - xor di, di - jmp short loc_1CBF1 -; --------------------------------------------------------------------------- - -loc_1CB91: - cmp [si+bullet_t.flag], 1 - jnz short loc_1CBED - mov [si+bullet_t.pos.velocity.x], 0 - mov [si+bullet_t.pos.velocity.y], 0 - lea ax, [si+bullet_t.pos] - call @PlayfieldMotion@update_seg3$qv pascal, ax - cmp [bp+@@patnum], PAT_BULLET16_D - jnb short loc_1CBB7 - mov al, [bp+@@patnum] - mov ah, 0 - mov [si+bullet_t.BULLET_patnum], ax - jmp short loc_1CBED -; --------------------------------------------------------------------------- - -loc_1CBB7: - movzx eax, [bp+@@points] - add _popup_bonus, eax - add _score_delta, eax - call pointnums_add_white pascal, [si+bullet_t.pos.cur.x], [si+bullet_t.pos.cur.y], [bp+@@points] - mov ax, [bp+var_6] - add [bp+@@points], ax - add [bp+var_6], 3 - mov ax, [bp+@@points] - cmp ax, [bp+var_8] - jbe short loc_1CBEA - mov ax, [bp+var_8] - mov [bp+@@points], ax - -loc_1CBEA: - mov [si+bullet_t.flag], 2 - -loc_1CBED: - inc di - sub si, size bullet_t - -loc_1CBF1: - cmp di, BULLET_COUNT - jl short loc_1CB91 - cmp _popup_bonus, 0 - jz short loc_1CC0A - mov _popup_id_new, POPUP_ID_BONUS - mov _popup, offset popup_update_and_render - -loc_1CC0A: - inc _bullet_zap_active - cmp [bp+@@patnum], PAT_BULLET16_D - jb short loc_1CC19 - mov _bullet_zap_active, 0 - -loc_1CC19: - cmp _bullet_clear_time, 0 - jz short loc_1CC24 - dec _bullet_clear_time - -loc_1CC24: - pop di - pop si - leave - retf -; --------------------------------------------------------------------------- - db 0 -off_1CC29 dw offset loc_1CB71 - dw offset loc_1CB78 - dw offset loc_1CB78 - dw offset loc_1CB78 - dw offset loc_1CB7F -_bullets_update endp main_032_TEXT ends main_033_TEXT segment byte public 'CODE' use16 + extern _bullets_update:proc BULLET_TEMPLATE_TUNE_EASY procdesc near BULLET_TEMPLATE_TUNE_NORMAL procdesc near BULLET_TEMPLATE_TUNE_HARD procdesc near @@ -34220,6 +33834,7 @@ word_25678 dw ? db 6 dup(?) word_25680 dw ? db 6 dup(?) +public _rank _rank db ? include th04/main/score[bss].asm byte_256A2 db ? diff --git a/th05/bullet_u.cpp b/th05/bullet_u.cpp new file mode 100644 index 00000000..0c37ebc7 --- /dev/null +++ b/th05/bullet_u.cpp @@ -0,0 +1,2 @@ +#pragma option -zCmain_033_TEXT -zPmain_03 +#include "th04/main/bullet/update.cpp" diff --git a/th05/sprites/main_pat.h b/th05/sprites/main_pat.h index 55a55065..fa91bfe4 100644 --- a/th05/sprites/main_pat.h +++ b/th05/sprites/main_pat.h @@ -134,4 +134,6 @@ typedef enum { PAT_DECAY_B6BALL_last = (PAT_DECAY_B6BALL + BULLET_DECAY_CELS - 1), /// ------- /// ======= + + _main_patnum_t_FORCE_INT16 = 0x7FFF, } main_patnum_t; diff --git a/th05/sprites/main_pat.inc b/th05/sprites/main_pat.inc index a74db56e..49be4c73 100644 --- a/th05/sprites/main_pat.inc +++ b/th05/sprites/main_pat.inc @@ -30,9 +30,6 @@ PAT_BULLET16_V = 84 PAT_BULLET16_V_RED = PAT_BULLET16_V PAT_BULLET16_V_BLUE = 116 PAT_CLOUD_PELLET = 148 -PAT_BULLET_ZAP = 152 -PAT_DECAY_PELLET = 156 -PAT_DECAY_BULLET16 = 160 PAT_EXPLOSION_SMALL = 164 PAT_FIREWAVE_LEFT = 168 PAT_FIREWAVE_RIGHT = 169 diff --git a/th05_main.asm b/th05_main.asm index a511fed8..701157b9 100644 --- a/th05_main.asm +++ b/th05_main.asm @@ -12836,413 +12836,7 @@ off_17BF0 dw offset loc_17A4E dw offset loc_17BBA bullet_update_special endp -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -_bullets_update proc far - -@@patnum = byte ptr -9 -var_8 = word ptr -8 -var_6 = word ptr -6 -@@points = word ptr -4 -var_2 = word ptr -2 - - push bp - mov bp, sp - sub sp, 0Ah - push si - push di - mov [bp+var_2], 0 - mov _pellet_clouds_render_count, 0 - mov _pellets_render_count, 0 - mov si, offset _bullets[(BULLET_COUNT - 1) * size bullet_t] - cmp _bullet_zap_active, 0 - jnz loc_17EC3 - xor di, di - jmp loc_17E78 -; --------------------------------------------------------------------------- - -loc_17C2E: - cmp [si+bullet_t.flag], 0 - jz loc_17E74 - cmp [si+bullet_t.flag], 2 - jnz short loc_17C40 - mov [si+bullet_t.flag], 0 - jmp loc_17E74 -; --------------------------------------------------------------------------- - -loc_17C40: - inc [bp+var_2] - cmp _bullet_clear_time, 0 - jz short loc_17CA3 - cmp [si+bullet_t.move_state], BMS_DECAY - jnb short loc_17C7B - mov [si+bullet_t.move_state], BMS_DECAY - cmp di, BULLET16_COUNT - jge short loc_17C5F - mov ax, PAT_DECAY_BULLET16 - jmp short loc_17C62 -; --------------------------------------------------------------------------- - -loc_17C5F: - mov ax, PAT_DECAY_PELLET - -loc_17C62: - mov [si+bullet_t.BULLET_patnum], ax - cmp [si+bullet_t.age], 0 - jz short loc_17C73 - add _score_delta, 100 - jmp short loc_17CA3 -; --------------------------------------------------------------------------- - -loc_17C73: - add _score_delta, 10 - jmp short loc_17CA3 -; --------------------------------------------------------------------------- - -loc_17C7B: - inc [si+bullet_t.move_state] - cmp [si+bullet_t.move_state], BMS_DECAY_END - jb short loc_17C91 - lea ax, [si+bullet_t.pos] - call @PlayfieldMotion@update_seg3$qv pascal, ax - mov [si+bullet_t.flag], 2 - jmp loc_17E74 -; --------------------------------------------------------------------------- - -loc_17C91: - mov al, [si+bullet_t.move_state] - mov ah, 0 - mov bx, (BMS_DECAY_FRAMES / BULLET_DECAY_CELS) - cwd - idiv bx - or dx, dx - jnz short loc_17CA3 - inc [si+bullet_t.BULLET_patnum] - -loc_17CA3: - inc [si+bullet_t.age] - cmp [si+bullet_t.spawn_state], BSS_ACTIVE - jb loc_17D56 - cmp [si+bullet_t.spawn_state], BSS_ACTIVE - jnz short loc_17CBB - mov [si+bullet_t.spawn_state], BSS_GRAZEABLE - jmp loc_17D56 -; --------------------------------------------------------------------------- - -loc_17CBB: - cmp [si+bullet_t.spawn_state], BSS_CLOUD_BACKWARDS - jnz short loc_17CE1 - mov eax, dword ptr [si+bullet_t.pos.cur] - mov dword ptr [si+bullet_t.pos.prev], eax - mov ax, [si+bullet_t.pos.velocity.x] - shl ax, 3 - sub [si+bullet_t.pos.cur.x], ax - mov ax, [si+bullet_t.pos.velocity.y] - shl ax, 3 - sub [si+bullet_t.pos.cur.y], ax - mov [si+bullet_t.spawn_state], BSS_CLOUD_FORWARDS - jmp short loc_17D0D -; --------------------------------------------------------------------------- - -loc_17CE1: - cmp [si+bullet_t.spawn_state], BSS_CLOUD_FORWARDS - jnz short loc_17CF0 - lea ax, [si+bullet_t.pos] - call @PlayfieldMotion@update_seg3$qv pascal, ax - jmp short loc_17D0D -; --------------------------------------------------------------------------- - -loc_17CF0: - mov eax, dword ptr [si+bullet_t.pos.cur] - mov dword ptr [si+bullet_t.pos.prev], eax - mov ax, [si+bullet_t.pos.velocity.x] - mov bx, 3 - cwd - idiv bx - add [si+bullet_t.pos.cur.x], ax - mov ax, [si+bullet_t.pos.velocity.y] - cwd - idiv bx - add [si+bullet_t.pos.cur.y], ax - -loc_17D0D: - inc [si+bullet_t.spawn_state] - cmp [si+bullet_t.spawn_state], BSS_CLOUD_END - jb short loc_17D3D - cmp [si+bullet_t.pos.cur.y], (-8 shl 4) - jl short loc_17D30 - cmp [si+bullet_t.pos.cur.y], ((PLAYFIELD_H + 8) shl 4) - jge short loc_17D30 - cmp [si+bullet_t.pos.cur.x], (-8 shl 4) - jl short loc_17D30 - cmp [si+bullet_t.pos.cur.x], ((PLAYFIELD_W + 8) shl 4) - jl short loc_17D36 - -loc_17D30: - mov [si+bullet_t.flag], 2 - jmp loc_17E74 -; --------------------------------------------------------------------------- - -loc_17D36: - mov [si+bullet_t.spawn_state], BSS_ACTIVE - jmp loc_17E74 -; --------------------------------------------------------------------------- - -loc_17D3D: - cmp di, BULLET16_COUNT - jl loc_17E74 - mov bx, _pellet_clouds_render_count - add bx, bx - mov _pellet_clouds_render[bx], si - inc _pellet_clouds_render_count - jmp loc_17E74 -; --------------------------------------------------------------------------- - -loc_17D56: - cmp [si+bullet_t.move_state], BMS_SPECIAL - jnz short loc_17D62 - call bullet_update_special pascal, si - jmp short loc_17DA3 -; --------------------------------------------------------------------------- - -loc_17D62: - cmp [si+bullet_t.move_state], BMS_SLOWDOWN - jnz short loc_17DA3 - dec [si+bullet_t.slowdown_time] - mov al, [si+bullet_t.slowdown_time] - mov ah, 0 - mov dl, [si+bullet_t.slowdown_speed_delta] - mov dh, 0 - imul dx - mov bx, BMS_SLOWDOWN_FRAMES - cwd - idiv bx - add al, [si+bullet_t.speed_final] - mov [si+bullet_t.speed_cur], al - cmp [si+bullet_t.slowdown_time], 0 - jnz short loc_17D93 - mov al, [si+bullet_t.speed_final] - mov [si+bullet_t.speed_cur], al - mov [si+bullet_t.move_state], BMS_REGULAR - -loc_17D93: - lea ax, [si+bullet_t.pos.velocity] - push ax - push word ptr [si+bullet_t.BULLET_angle] - mov al, [si+bullet_t.speed_cur] - mov ah, 0 - push ax - call vector2_near - -loc_17DA3: - lea ax, [si+bullet_t.pos] - call @PlayfieldMotion@update_seg3$qv pascal, ax - cmp ax, (-8 shl 4) - jle short loc_17DBF - cmp ax, ((PLAYFIELD_W + 8) shl 4) - jge short loc_17DBF - cmp dx, (-8 shl 4) - jle short loc_17DBF - cmp dx, ((PLAYFIELD_H + 8) shl 4) - jl short loc_17DC5 - -loc_17DBF: - mov [si+bullet_t.flag], 2 - jmp loc_17E74 -; --------------------------------------------------------------------------- - -loc_17DC5: - cmp _bullet_clear_time, 0 - jnz loc_17E74 - sub ax, _player_pos.cur.x - sub dx, _player_pos.cur.y - cmp _player_invincibility_time, 0 - jnz short loc_17E41 - cmp [si+bullet_t.spawn_state], BSS_GRAZEABLE - jz short loc_17DFE - add ax, (4 shl 4) - cmp ax, (8 shl 4) - ja short loc_17E41 - add dx, (4 shl 4) - cmp dx, (8 shl 4) - ja short loc_17E41 - mov [si+bullet_t.flag], 2 - mov _player_is_hit, 1 - jmp short loc_17E74 -; --------------------------------------------------------------------------- - -loc_17DFE: - add ax, (16 shl 4) - cmp ax, (36 shl 4) - ja short loc_17E41 - add dx, (22 shl 4) - cmp dx, (44 shl 4) - ja short loc_17E41 - push [si+bullet_t.pos.cur.x] - push [si+bullet_t.pos.cur.y] - push large (((2 shl 4) shl 16) or 2) - nopcall sparks_add_random - mov [si+bullet_t.spawn_state], BSS_GRAZED - cmp _stage_graze, GRAZE_MAX - jnb short loc_17E41 - inc _stage_graze - call hud_graze_put - movzx eax, _graze_score - add _score_delta, eax - -loc_17E41: - cmp di, BULLET16_COUNT - jl short loc_17E74 - mov ax, [si+bullet_t.pos.cur.x] - sar ax, 4 - add ax, (PLAYFIELD_LEFT - (PELLET_W / 2)) - mov bx, _pellets_render_count - shl bx, 2 - mov _pellets_render[bx].PRT_left, ax - mov ax, [si+bullet_t.pos.cur.y] - add ax, ((PLAYFIELD_TOP - (PELLET_H / 2)) shl 4) - call scroll_subpixel_y_to_vram_seg3 pascal, ax - mov bx, _pellets_render_count - shl bx, 2 - mov _pellets_render[bx].PRT_top, ax - inc _pellets_render_count - -loc_17E74: - inc di - sub si, size bullet_t - -loc_17E78: - cmp di, BULLET_COUNT - jl loc_17C2E - cmp _turbo_mode, 0 - jnz loc_17FB7 - mov _slowdown_caused_by_bullets, 0 - mov di, 2Ah ; '*' - mov al, _rank - mov ah, 0 - shl ax, 3 - add di, ax - cmp [bp+var_2], di - jl short loc_17EAB - cmp _stage_frame_mod2, 0 - jnz loc_17FB7 - jmp short loc_17EB5 -; --------------------------------------------------------------------------- - -loc_17EAB: - lea ax, [di+20h] - cmp ax, [bp+var_2] - jg loc_17FB7 - -loc_17EB5: - mov _slowdown_factor, 2 - mov _slowdown_caused_by_bullets, 1 - jmp loc_17FB7 -; --------------------------------------------------------------------------- - -loc_17EC3: - mov al, _bullet_zap_active - mov ah, 0 - mov bx, BULLET_ZAP_CELS - cwd - idiv bx - add al, PAT_BULLET_ZAP - mov [bp+@@patnum], al - mov [bp+@@points], 1 - mov [bp+var_6], 1 - cmp _rank, RANK_EXTRA - jnz short loc_17EE9 - mov ax, 1600 - jmp short loc_17EFA -; --------------------------------------------------------------------------- - -loc_17EE9: - push ( 960 shl 16) or 1280 - push (1280 shl 16) or 1280 - call select_for_rank - -loc_17EFA: - mov [bp+var_8], ax - mov _popup_bonus, 0 - xor di, di - jmp loc_17F8D -; --------------------------------------------------------------------------- - -loc_17F0B: - cmp [si+bullet_t.flag], 1 - jnz short loc_17F89 - mov [si+bullet_t.pos.velocity.x], 0 - mov [si+bullet_t.pos.velocity.y], 0 - lea ax, [si+bullet_t.pos] - call @PlayfieldMotion@update_seg3$qv pascal, ax - cmp [bp+@@patnum], 76 ; TH04 leftover; PAT_BULLET16_D in that game, unused here - jnb short loc_17F31 - mov al, [bp+@@patnum] - mov ah, 0 - mov [si+bullet_t.BULLET_patnum], ax - jmp short loc_17F86 -; --------------------------------------------------------------------------- - -loc_17F31: - movzx eax, [bp+@@points] - add _popup_bonus, eax - add _score_delta, eax - call pointnums_add_white pascal, [si+bullet_t.pos.cur.x], [si+bullet_t.pos.cur.y], [bp+@@points] - mov ax, [bp+var_6] - add [bp+@@points], ax - add [bp+var_6], 3 - mov ax, [bp+@@points] - cmp ax, [bp+var_8] - jbe short loc_17F64 - mov ax, [bp+var_8] - mov [bp+@@points], ax - -loc_17F64: - mov [si+bullet_t.flag], 2 - cmp _bullet_zap_drop_point_items, 0 - jz short loc_17F86 - mov ax, [bp+var_2] - mov bx, 4 - cwd - idiv bx - or dx, dx - jnz short loc_17F86 - call items_add pascal, [si+bullet_t.pos.cur.x], [si+bullet_t.pos.cur.y], IT_POINT - -loc_17F86: - inc [bp+var_2] - -loc_17F89: - inc di - sub si, size bullet_t - -loc_17F8D: - cmp di, BULLET_COUNT - jl loc_17F0B - cmp _popup_bonus, 0 - jz short loc_17FA8 - mov _popup_id_new, POPUP_ID_BONUS - mov _popup, offset popup_update_and_render - -loc_17FA8: - inc _bullet_zap_active - cmp [bp+@@patnum], 76 ; TH04 leftover; PAT_BULLET16_D in that game, unused here - jb short loc_17FB7 - mov _bullet_zap_active, 0 - -loc_17FB7: - cmp _bullet_clear_time, 0 - jz short loc_17FC2 - dec _bullet_clear_time - -loc_17FC2: - pop di - pop si - leave - retf -_bullets_update endp + extern _bullets_update:proc main_033_TEXT ends main_034_TEXT segment byte public 'CODE' use16