[Decompilation] [th04/th05] Bullets: Update function

… (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-.
This commit is contained in:
nmlgc 2021-07-22 20:48:47 +02:00
parent 0d7fc5af77
commit 4d24ca53bd
21 changed files with 429 additions and 817 deletions

View File

@ -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 @&&|
$**
|

View File

@ -345,6 +345,22 @@ void foo(int i) {
## Flags
### `-G` (Generate for speed)
* Replaces
```asm
ENTER <stack size>, 0
```
with
```asm
PUSH BP
MOV BP, SP
SUB SP, <stack size>
```
### `-Z` (Suppress register reloads)
* The tracked contents of `ES` are reset after a conditional statement. If the

View File

@ -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)) \

View File

@ -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<subpixel_t>(center_y) >= to_sp(0 - (h / 2))) && \
(static_cast<subpixel_t>(center_y) < to_sp(PLAYFIELD_H + (h / 2))) && \
(static_cast<subpixel_t>(center_x) >= to_sp(0 - (w / 2))) && \
(static_cast<subpixel_t>(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<subpixel_t>(center_x) > to_sp(0 - (w / 2))) && \
(static_cast<subpixel_t>(center_x) < to_sp(PLAYFIELD_W + (w / 2))) && \
(static_cast<subpixel_t>(center_y) > to_sp(0 - (h / 2))) && \
(static_cast<subpixel_t>(center_y) < to_sp(PLAYFIELD_H + (h / 2))) \
)
#define playfield_encloses_point(center, w, h) \

2
th04/bullet_u.cpp Normal file
View File

@ -0,0 +1,2 @@
#pragma option -zCmain_032_TEXT -zPmain_03
#include "th04/main/bullet/update.cpp"

View File

@ -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;

View File

@ -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
);

View File

@ -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<unsigned char &>(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<unsigned char &>(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--;
}
}
}

View File

@ -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();
// ----------

View File

@ -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

View File

@ -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
);

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -101,4 +101,6 @@ typedef enum {
PAT_YUUKA6_VANISH_3 = 180,
// --------
/// =======
_main_patnum_t_FORCE_INT16 = 0x7FFF,
} main_patnum_t;

View File

@ -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

View File

@ -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 ?

2
th05/bullet_u.cpp Normal file
View File

@ -0,0 +1,2 @@
#pragma option -zCmain_033_TEXT -zPmain_03
#include "th04/main/bullet/update.cpp"

View File

@ -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;

View File

@ -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

View File

@ -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