2021-07-13 22:56:02 +00:00
|
|
|
|
void pascal near bullets_add_regular_raw(void);
|
|
|
|
|
void pascal near bullets_add_special_raw(void);
|
|
|
|
|
|
2021-06-27 18:57:36 +00:00
|
|
|
|
/// Per-spawn state
|
|
|
|
|
/// ---------------
|
|
|
|
|
/// Has no reason to be global.
|
|
|
|
|
|
|
|
|
|
extern bool group_fixedspeed;
|
2021-06-24 17:41:56 +00:00
|
|
|
|
|
|
|
|
|
// "(group_i * bullet_template.delta.spread_angle) is probably too expensive,
|
|
|
|
|
// let's rather do an addition for each additional spawned bullet :zunpet:"
|
|
|
|
|
extern unsigned char group_i_spread_angle;
|
|
|
|
|
|
|
|
|
|
extern unsigned char group_i_absolute_angle;
|
2021-06-27 18:57:36 +00:00
|
|
|
|
/// ---------------
|
|
|
|
|
|
2020-08-14 15:52:47 +00:00
|
|
|
|
#define tmpl bullet_template
|
|
|
|
|
|
|
|
|
|
void near tune_for_easy(void)
|
|
|
|
|
{
|
2021-05-25 16:22:48 +00:00
|
|
|
|
switch(tmpl.group) {
|
|
|
|
|
case BG_STACK:
|
|
|
|
|
case BG_STACK_AIMED:
|
2022-02-26 23:36:22 +00:00
|
|
|
|
tmpl.delta.stack_speed.v -= (tmpl.delta.stack_speed.v / 4);
|
2020-08-14 15:52:47 +00:00
|
|
|
|
if(tmpl.count >= 2) {
|
|
|
|
|
tmpl.count--;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_SPREAD:
|
|
|
|
|
case BG_SPREAD_AIMED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
if(tmpl.count >= 3) {
|
|
|
|
|
tmpl.count -= 2;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_RANDOM_ANGLE:
|
|
|
|
|
case BG_RING:
|
|
|
|
|
case BG_RING_AIMED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count /= 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void near tune_for_hard(void)
|
|
|
|
|
{
|
2021-05-25 16:22:48 +00:00
|
|
|
|
switch(tmpl.group) {
|
|
|
|
|
case BG_SINGLE_AIMED:
|
|
|
|
|
tmpl.group = BG_STACK_AIMED;
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count = 2;
|
2022-02-26 23:36:22 +00:00
|
|
|
|
tmpl.delta.stack_speed.set(0.375f);
|
2020-08-14 15:52:47 +00:00
|
|
|
|
break;
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_SINGLE:
|
|
|
|
|
tmpl.group = BG_STACK;
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count = 2;
|
2022-02-26 23:36:22 +00:00
|
|
|
|
tmpl.delta.stack_speed.set(0.375f);
|
2020-08-14 15:52:47 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_STACK:
|
|
|
|
|
case BG_STACK_AIMED:
|
2022-02-26 23:36:22 +00:00
|
|
|
|
tmpl.delta.stack_speed.v += (tmpl.delta.stack_speed.v / 2);
|
2020-08-14 15:52:47 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_SPREAD:
|
|
|
|
|
case BG_SPREAD_AIMED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count += 2;
|
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_RING:
|
|
|
|
|
case BG_RING_AIMED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count *= 3;
|
|
|
|
|
tmpl.count /= 2;
|
|
|
|
|
if(tmpl.count > 48) {
|
|
|
|
|
tmpl.count = 48;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_RANDOM_ANGLE:
|
|
|
|
|
case BG_RANDOM_ANGLE_AND_SPEED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count += (tmpl.count / 2);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void near tune_for_lunatic(void)
|
|
|
|
|
{
|
2021-05-25 16:22:48 +00:00
|
|
|
|
switch(tmpl.group) {
|
|
|
|
|
case BG_SINGLE_AIMED:
|
|
|
|
|
tmpl.group = BG_SPREAD_AIMED;
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count = 3;
|
2020-10-02 12:42:40 +00:00
|
|
|
|
tmpl.delta.spread_angle = +0x06;
|
2020-08-14 15:52:47 +00:00
|
|
|
|
break;
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_SINGLE:
|
|
|
|
|
tmpl.group = BG_SPREAD;
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count = 3;
|
2020-10-02 12:42:40 +00:00
|
|
|
|
tmpl.delta.spread_angle = +0x06;
|
2020-08-14 15:52:47 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_STACK:
|
|
|
|
|
case BG_STACK_AIMED:
|
2022-02-26 23:36:22 +00:00
|
|
|
|
tmpl.delta.stack_speed.v += (tmpl.delta.stack_speed.v / 2);
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count++;
|
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_SPREAD:
|
|
|
|
|
case BG_SPREAD_AIMED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count += 4;
|
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_RING:
|
|
|
|
|
case BG_RING_AIMED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count *= 2;
|
|
|
|
|
if(tmpl.count > 48) {
|
|
|
|
|
tmpl.count = 48;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_RANDOM_ANGLE:
|
|
|
|
|
case BG_RANDOM_ANGLE_AND_SPEED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
tmpl.count *= 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void near tune_for_playperf(void)
|
|
|
|
|
{
|
2021-05-25 16:22:48 +00:00
|
|
|
|
switch(tmpl.group) {
|
|
|
|
|
case BG_STACK:
|
|
|
|
|
case BG_STACK_AIMED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
if(playperf >= 24) {
|
|
|
|
|
tmpl.count++;
|
|
|
|
|
} else if((playperf <= 6) && (tmpl.count >= 2)) {
|
|
|
|
|
tmpl.count--;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_SPREAD:
|
|
|
|
|
case BG_SPREAD_AIMED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
if(playperf >= 24) {
|
|
|
|
|
tmpl.count += 2;
|
|
|
|
|
} else if((playperf <= 6) && (tmpl.count >= 3)) {
|
|
|
|
|
tmpl.count -= 2;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
case BG_RING:
|
|
|
|
|
case BG_RING_AIMED:
|
2020-08-14 15:52:47 +00:00
|
|
|
|
if(playperf >= 24) {
|
|
|
|
|
tmpl.count += 4;
|
|
|
|
|
} else if(playperf >= 20) {
|
|
|
|
|
tmpl.count += 2;
|
|
|
|
|
} else if(tmpl.count >= 5) {
|
|
|
|
|
if(playperf <= 10) {
|
|
|
|
|
tmpl.count -= 2;
|
|
|
|
|
}
|
|
|
|
|
if(playperf <= 4) {
|
|
|
|
|
tmpl.count -= 4;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef tmpl
|
|
|
|
|
|
|
|
|
|
void pascal near bullet_template_tune_easy(void)
|
|
|
|
|
{
|
|
|
|
|
tune_for_playperf();
|
|
|
|
|
tune_for_easy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pascal near bullet_template_tune_normal(void)
|
|
|
|
|
{
|
|
|
|
|
tune_for_playperf();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pascal near bullet_template_tune_hard(void)
|
|
|
|
|
{
|
|
|
|
|
tune_for_playperf();
|
|
|
|
|
tune_for_hard();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pascal near bullet_template_tune_lunatic(void)
|
|
|
|
|
{
|
|
|
|
|
tune_for_playperf();
|
|
|
|
|
tune_for_lunatic();
|
|
|
|
|
}
|
2021-06-22 19:31:26 +00:00
|
|
|
|
|
|
|
|
|
void pascal near bullets_add_regular_easy(void)
|
|
|
|
|
{
|
2022-02-26 23:36:22 +00:00
|
|
|
|
subpixel_length_8_t speed;
|
2021-06-22 19:31:26 +00:00
|
|
|
|
unsigned char count;
|
|
|
|
|
|
|
|
|
|
if(bullet_zap.active) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
count = bullet_template.count;
|
|
|
|
|
speed = bullet_template.speed.v;
|
|
|
|
|
bullets_add_regular_raw();
|
|
|
|
|
bullet_template.count = count;
|
|
|
|
|
bullet_template.speed.v = speed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void keep_speed_from_being_mutated_when_calling(nearfunc_t_near func) {
|
2022-02-26 23:36:22 +00:00
|
|
|
|
subpixel_length_8_t speed = bullet_template.speed.v;
|
2021-06-22 19:31:26 +00:00
|
|
|
|
func();
|
|
|
|
|
bullet_template.speed.v = speed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pascal near bullets_add_regular_normal(void)
|
|
|
|
|
{
|
|
|
|
|
if(bullet_zap.active) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
keep_speed_from_being_mutated_when_calling(bullets_add_regular_raw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pascal near bullets_add_regular_hard_lunatic(void)
|
|
|
|
|
{
|
|
|
|
|
if(bullet_zap.active) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
keep_speed_from_being_mutated_when_calling(bullets_add_regular_raw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pascal near bullets_add_special_easy(void)
|
|
|
|
|
{
|
|
|
|
|
if(bullet_zap.active) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
keep_speed_from_being_mutated_when_calling(bullets_add_special_raw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pascal near bullets_add_special_normal(void)
|
|
|
|
|
{
|
|
|
|
|
if(bullet_zap.active) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
keep_speed_from_being_mutated_when_calling(bullets_add_special_raw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pascal near bullets_add_special_hard_lunatic(void)
|
|
|
|
|
{
|
|
|
|
|
if(bullet_zap.active) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
keep_speed_from_being_mutated_when_calling(bullets_add_special_raw);
|
|
|
|
|
}
|
2021-06-27 18:57:36 +00:00
|
|
|
|
|
|
|
|
|
void near bullets_add_regular_fixedspeed(void)
|
|
|
|
|
{
|
|
|
|
|
group_fixedspeed = true;
|
|
|
|
|
bullets_add_regular();
|
|
|
|
|
group_fixedspeed = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void near bullets_add_special_fixedspeed(void)
|
|
|
|
|
{
|
|
|
|
|
group_fixedspeed = true;
|
|
|
|
|
bullets_add_special();
|
|
|
|
|
group_fixedspeed = false;
|
|
|
|
|
}
|
2021-06-24 17:41:56 +00:00
|
|
|
|
|
2022-03-11 23:48:15 +00:00
|
|
|
|
#define last_bullet_in_group(group_i) \
|
2021-06-24 17:41:56 +00:00
|
|
|
|
(group_i >= (bullet_template.count - 1))
|
|
|
|
|
|
|
|
|
|
// Necessary to compile the switch statement in bullet_velocity_and_angle_set()
|
|
|
|
|
// to a binary search. Strangely, it's not used for the functions above?
|
|
|
|
|
#pragma option -G
|
|
|
|
|
|
|
|
|
|
// Sets the bullet template's velocity for bullet #[group_i] in the template's
|
|
|
|
|
// current group, as well as [group_i_absolute_angle]. Returns true if this
|
|
|
|
|
// was the last bullet for this group.
|
|
|
|
|
bool16 pascal near bullet_velocity_and_angle_set(int group_i)
|
|
|
|
|
{
|
|
|
|
|
int angle = 0x00;
|
2022-02-26 23:36:22 +00:00
|
|
|
|
subpixel_length_8_t speed;
|
2021-06-24 17:41:56 +00:00
|
|
|
|
bool done;
|
|
|
|
|
|
|
|
|
|
// Due to this default, invalid group values lead to the spawn functions
|
|
|
|
|
// repeatedly calling this function, until they completely filled the
|
|
|
|
|
// pellet / 16×16 part of the array with identical bullets using the given
|
|
|
|
|
// angle and speed.
|
|
|
|
|
// (Not really a ZUN bug until we can discover a game state where this can
|
|
|
|
|
// actually happen.)
|
|
|
|
|
done = false;
|
|
|
|
|
speed = bullet_template.speed.v;
|
|
|
|
|
|
|
|
|
|
switch(bullet_template.group) {
|
|
|
|
|
case BG_SPREAD:
|
|
|
|
|
case BG_SPREAD_AIMED:
|
|
|
|
|
if(bullet_template.count & 1) {
|
|
|
|
|
// Odd-numbered spreads always contain a bullet in the center.
|
|
|
|
|
if(group_i == 0) {
|
|
|
|
|
group_i_spread_angle = 0x00;
|
|
|
|
|
angle = 0x00;
|
|
|
|
|
} else if(group_i & 1) {
|
|
|
|
|
// Symmetric version of even-numbered bullets
|
|
|
|
|
group_i_spread_angle += bullet_template.delta.spread_angle;
|
|
|
|
|
angle = (0x100 - group_i_spread_angle);
|
|
|
|
|
} else {
|
|
|
|
|
angle = group_i_spread_angle;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Even-numbered spreads are aimed around the 0° point, and
|
|
|
|
|
// therefore need to be shifted by half of the angle. Yes, this
|
|
|
|
|
// whole separate branch, with its whole pointlessly mirrored
|
|
|
|
|
// logic, wouldn't have been necessary, and ZUN could have just
|
2021-07-27 23:18:31 +00:00
|
|
|
|
// added the angle offset after the fact. Or heck, even leaving it
|
|
|
|
|
// at that one branch and using the same code for odd- and
|
|
|
|
|
// even-numbered spreads beyond the first bullet would have been
|
|
|
|
|
// better. (He did the latter in TH05.)
|
2021-06-24 17:41:56 +00:00
|
|
|
|
if(group_i == 0) {
|
|
|
|
|
group_i_spread_angle = (bullet_template.delta.spread_angle / 2);
|
|
|
|
|
angle = group_i_spread_angle;
|
|
|
|
|
} else if(group_i & 1) {
|
|
|
|
|
// Symmetric version of even-numbered bullets
|
|
|
|
|
angle = (0x100 - group_i_spread_angle);
|
|
|
|
|
} else {
|
|
|
|
|
group_i_spread_angle += bullet_template.delta.spread_angle;
|
|
|
|
|
angle = group_i_spread_angle;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(last_bullet_in_group(group_i)) {
|
|
|
|
|
done = true;
|
|
|
|
|
}
|
|
|
|
|
if(bullet_template.group == BG_SPREAD) {
|
|
|
|
|
goto no_aim;
|
|
|
|
|
}
|
|
|
|
|
goto aim;
|
|
|
|
|
|
|
|
|
|
case BG_RING:
|
|
|
|
|
angle = ((group_i * 0x100) / bullet_template.count);
|
|
|
|
|
if(last_bullet_in_group(group_i)) {
|
|
|
|
|
done = true;
|
|
|
|
|
}
|
|
|
|
|
goto no_aim;
|
|
|
|
|
case BG_RING_AIMED:
|
|
|
|
|
angle = ((group_i * 0x100) / bullet_template.count);
|
|
|
|
|
if(last_bullet_in_group(group_i)) {
|
|
|
|
|
done = true;
|
|
|
|
|
}
|
|
|
|
|
goto aim;
|
|
|
|
|
|
|
|
|
|
// All these 16-bit randring operations seem to waste 8 bits of randomness,
|
|
|
|
|
// but each next16 call only advances the pointer by one byte anyway.
|
|
|
|
|
case BG_FORCESINGLE_RANDOM_ANGLE:
|
|
|
|
|
angle = randring2_next16();
|
|
|
|
|
done = true;
|
|
|
|
|
goto no_aim;
|
|
|
|
|
|
|
|
|
|
case BG_FORCESINGLE:
|
|
|
|
|
case BG_SINGLE:
|
|
|
|
|
done = true;
|
|
|
|
|
goto no_aim;
|
|
|
|
|
|
|
|
|
|
case BG_RANDOM_ANGLE:
|
|
|
|
|
angle = randring2_next16();
|
|
|
|
|
if(last_bullet_in_group(group_i)) {
|
|
|
|
|
done = true;
|
|
|
|
|
}
|
|
|
|
|
goto no_aim;
|
|
|
|
|
case BG_RANDOM_ANGLE_AND_SPEED:
|
|
|
|
|
angle = randring2_next16();
|
2022-04-16 03:25:19 +00:00
|
|
|
|
speed += randring2_next8_and_ge_lt_sp(0.0f, 2.0f);
|
2021-06-24 17:41:56 +00:00
|
|
|
|
if(last_bullet_in_group(group_i)) {
|
|
|
|
|
done = true;
|
|
|
|
|
}
|
|
|
|
|
goto no_aim;
|
|
|
|
|
case BG_RANDOM_CONSTRAINED_ANGLE_AIMED:
|
2022-04-16 03:25:19 +00:00
|
|
|
|
angle = randring2_next16_and_ge_lt(0x00, 0x20);
|
2021-06-24 17:41:56 +00:00
|
|
|
|
angle -= 0x10;
|
|
|
|
|
if(last_bullet_in_group(group_i)) {
|
|
|
|
|
done = true;
|
|
|
|
|
}
|
|
|
|
|
goto aim;
|
|
|
|
|
|
|
|
|
|
case BG_FORCESINGLE_AIMED:
|
|
|
|
|
case BG_SINGLE_AIMED:
|
|
|
|
|
done = true;
|
|
|
|
|
goto aim;
|
|
|
|
|
|
|
|
|
|
case BG_STACK:
|
|
|
|
|
case BG_STACK_AIMED:
|
|
|
|
|
speed += (bullet_template.delta.stack_speed * group_i);
|
|
|
|
|
if(
|
|
|
|
|
last_bullet_in_group(group_i) ||
|
|
|
|
|
(bullet_template.speed >= to_sp8(10.0f))
|
|
|
|
|
) {
|
|
|
|
|
done = true;
|
|
|
|
|
}
|
|
|
|
|
if(bullet_template.group == BG_STACK) {
|
|
|
|
|
goto no_aim;
|
|
|
|
|
}
|
|
|
|
|
goto aim;
|
|
|
|
|
}
|
|
|
|
|
aim:
|
|
|
|
|
angle += iatan2(
|
|
|
|
|
(player_pos.cur.y - bullet_template.origin.y),
|
|
|
|
|
(player_pos.cur.x - bullet_template.origin.x)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
no_aim:
|
|
|
|
|
vector2_near(
|
|
|
|
|
bullet_template.velocity, (angle + bullet_template.angle), speed
|
|
|
|
|
);
|
|
|
|
|
group_i_absolute_angle = (angle + bullet_template.angle);
|
|
|
|
|
return done;
|
|
|
|
|
}
|
2021-06-23 10:43:26 +00:00
|
|
|
|
|
|
|
|
|
void near bullet_template_speedtune_for_playperf(void)
|
|
|
|
|
{
|
|
|
|
|
bullet_template.speed.v /= 2;
|
|
|
|
|
subpixel_t speed_from_playperf = bullet_template.speed.v;
|
|
|
|
|
speed_from_playperf *= playperf;
|
|
|
|
|
speed_from_playperf /= 16;
|
|
|
|
|
|
|
|
|
|
bullet_template.speed.v += speed_from_playperf;
|
|
|
|
|
if(bullet_template.speed > to_sp8(8.0f)) {
|
|
|
|
|
bullet_template.speed.set(8.0f);
|
|
|
|
|
} else if(bullet_template.speed < to_sp8(0.5f)) {
|
|
|
|
|
bullet_template.speed.set(0.5f);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-24 18:46:39 +00:00
|
|
|
|
|
|
|
|
|
unsigned char pascal near bullet_patnum_for_angle(unsigned char angle)
|
|
|
|
|
{
|
|
|
|
|
return (
|
|
|
|
|
((angle + (ANGLE_PER_SPRITE / 2) - 1) & (0x80 - 1)) / ANGLE_PER_SPRITE
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-06-26 13:30:39 +00:00
|
|
|
|
|
|
|
|
|
bool near bullet_template_clip(void)
|
|
|
|
|
{
|
|
|
|
|
if(
|
|
|
|
|
(bullet_clear_time > 0) &&
|
2021-07-22 18:48:47 +00:00
|
|
|
|
// 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
|
2021-12-17 21:19:17 +00:00
|
|
|
|
// score points either.
|
2021-07-27 18:40:21 +00:00
|
|
|
|
(bullet_clear_time <= (BMS_DECAY_FRAMES + 1)) // differs from TH05!
|
2021-06-26 13:30:39 +00:00
|
|
|
|
) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// Also applies to 8×8 pellets, because why wouldn't you combine both
|
|
|
|
|
// cases. #goodcode
|
|
|
|
|
if(!playfield_encloses_point(
|
|
|
|
|
bullet_template.origin, BULLET16_W, BULLET16_H
|
|
|
|
|
)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if(overlap_points_wh_fast(
|
|
|
|
|
bullet_template.origin,
|
|
|
|
|
player_pos.cur,
|
|
|
|
|
BULLET_KILLBOX_W,
|
|
|
|
|
BULLET_KILLBOX_H
|
|
|
|
|
)) {
|
|
|
|
|
player_is_hit = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if(!group_fixedspeed) {
|
|
|
|
|
bullet_template_speedtune_for_playperf();
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-06-27 13:28:58 +00:00
|
|
|
|
|
|
|
|
|
#define bullet_set_spawn_vars(ptr, available, spawn_state, spawn_type) \
|
|
|
|
|
spawn_state = BSS_GRAZEABLE; \
|
|
|
|
|
switch(spawn_type) { \
|
|
|
|
|
case BST_PELLET: \
|
|
|
|
|
ptr = &pellets[PELLET_COUNT - 1]; \
|
|
|
|
|
available = PELLET_COUNT; \
|
|
|
|
|
break; \
|
|
|
|
|
case BST_BULLET16_CLOUD_BACKWARDS: \
|
|
|
|
|
spawn_state = BSS_CLOUD_BACKWARDS; \
|
|
|
|
|
goto bullet16; \
|
|
|
|
|
case BST_BULLET16_CLOUD_FORWARDS: \
|
|
|
|
|
spawn_state = BSS_CLOUD_FORWARDS; \
|
|
|
|
|
goto bullet16; \
|
|
|
|
|
default: \
|
|
|
|
|
bullet16: \
|
|
|
|
|
ptr = &bullets16[BULLET16_COUNT - 1]; \
|
|
|
|
|
available = BULLET16_COUNT; \
|
|
|
|
|
break; \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define bullet_init_from_template(bullet, group_done, group_i, spawn_state) \
|
|
|
|
|
bullet->age = 0; \
|
|
|
|
|
bullet->pos.cur = bullet_template.origin; \
|
|
|
|
|
bullet->from_group = bullet_template.group; \
|
|
|
|
|
bullet->patnum = bullet_template.patnum; \
|
|
|
|
|
bullet->spawn_state = static_cast<bullet_spawn_state_t>(spawn_state); \
|
|
|
|
|
\
|
|
|
|
|
group_done = bullet_velocity_and_angle_set(group_i); \
|
|
|
|
|
\
|
|
|
|
|
if(bullet_template.patnum >= PAT_BULLET16_D) { \
|
|
|
|
|
bullet->patnum += bullet_patnum_for_angle(group_i_absolute_angle); \
|
|
|
|
|
} \
|
|
|
|
|
\
|
|
|
|
|
bullet->pos.velocity = bullet_template.velocity; \
|
|
|
|
|
bullet->angle = group_i_absolute_angle; \
|
|
|
|
|
bullet->speed_final = bullet_template.speed; \
|
|
|
|
|
bullet->speed_cur = bullet_template.speed; \
|
|
|
|
|
|
|
|
|
|
void pascal near bullets_add_regular_raw(void)
|
|
|
|
|
{
|
|
|
|
|
bullet_t near *bullet;
|
|
|
|
|
int group_i;
|
|
|
|
|
int bullets_available;
|
|
|
|
|
unsigned char move_state;
|
|
|
|
|
bool group_done;
|
|
|
|
|
unsigned char spawn_state; // MODDERS: Should be bullet_spawn_state_t
|
|
|
|
|
|
|
|
|
|
if(bullet_template.spawn_type == BST_GATHER_PELLET) {
|
|
|
|
|
gather_template.center = bullet_template.origin;
|
|
|
|
|
gather_template.velocity.set_long(0.0f, 0.0f);
|
|
|
|
|
gather_template.radius.set(GATHER_RADIUS_START);
|
|
|
|
|
gather_template.angle_delta = 0x02;
|
|
|
|
|
gather_template.col = 9;
|
|
|
|
|
gather_template.ring_points = 8;
|
|
|
|
|
bullet_template.spawn_type = BST_PELLET;
|
|
|
|
|
gather_add_bullets();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(bullet_template_clip()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bullet_set_spawn_vars(
|
|
|
|
|
bullet, bullets_available, spawn_state, bullet_template.spawn_type
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
move_state = BMS_REGULAR;
|
|
|
|
|
if(
|
|
|
|
|
(bullet_template.speed < to_sp8(BMS_SLOWDOWN_THRESHOLD)) ||
|
|
|
|
|
bullet_clear_time
|
|
|
|
|
) {
|
|
|
|
|
if(
|
|
|
|
|
(bullet_template.group != BG_STACK) &&
|
|
|
|
|
(bullet_template.group != BG_STACK_AIMED)
|
|
|
|
|
) {
|
|
|
|
|
move_state = BMS_SLOWDOWN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
group_i = 0;
|
|
|
|
|
while(bullets_available > 0) {
|
2023-03-19 14:04:48 +00:00
|
|
|
|
if(bullet->flag == F_FREE) {
|
|
|
|
|
bullet->flag = F_ALIVE;
|
2021-06-27 13:28:58 +00:00
|
|
|
|
bullet->move_state = static_cast<bullet_move_state_t>(move_state);
|
2022-07-25 18:52:48 +00:00
|
|
|
|
bullet->u1.slowdown_time = BMS_SLOWDOWN_FRAMES;
|
|
|
|
|
bullet->u2.slowdown_speed_delta.v = (
|
2021-06-27 13:28:58 +00:00
|
|
|
|
to_sp8(BMS_SLOWDOWN_BASE_SPEED) - bullet_template.speed
|
|
|
|
|
);
|
|
|
|
|
bullet_init_from_template(bullet, group_done, group_i, spawn_state);
|
|
|
|
|
if(group_done) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
group_i++;
|
|
|
|
|
}
|
|
|
|
|
bullets_available--;
|
|
|
|
|
bullet--;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-29 18:24:30 +00:00
|
|
|
|
|
|
|
|
|
void pascal near bullets_add_special_raw(void)
|
|
|
|
|
{
|
|
|
|
|
bullet_t near *bullet;
|
|
|
|
|
int group_i;
|
|
|
|
|
int bullets_available;
|
|
|
|
|
bool group_done;
|
|
|
|
|
bullet_spawn_state_t spawn_state;
|
|
|
|
|
|
|
|
|
|
if(bullet_template_clip()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bullet_set_spawn_vars(
|
|
|
|
|
bullet, bullets_available, spawn_state, bullet_template.spawn_type
|
|
|
|
|
);
|
|
|
|
|
group_i = 0;
|
|
|
|
|
while(bullets_available > 0) {
|
2023-03-19 14:04:48 +00:00
|
|
|
|
if(bullet->flag == F_FREE) {
|
|
|
|
|
bullet->flag = F_ALIVE;
|
2021-06-29 18:24:30 +00:00
|
|
|
|
bullet->move_state = BMS_SPECIAL;
|
|
|
|
|
bullet->special_motion = bullet_template.special_motion;
|
2022-07-25 18:52:48 +00:00
|
|
|
|
bullet->u1.turns_done = 0;
|
|
|
|
|
bullet->u2.angle.v = bullet_template_special_angle.v;
|
2021-06-29 18:24:30 +00:00
|
|
|
|
bullet_init_from_template(bullet, group_done, group_i, spawn_state);
|
|
|
|
|
if(group_done) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
group_i++;
|
|
|
|
|
}
|
|
|
|
|
bullets_available--;
|
|
|
|
|
bullet--;
|
|
|
|
|
}
|
|
|
|
|
}
|