2021-10-04 18:53:23 +00:00
|
|
|
|
/// Everything here needs to be kept in sync with the ASM versions in
|
|
|
|
|
/// bullet.inc!
|
|
|
|
|
|
2020-03-31 16:25:15 +00:00
|
|
|
|
#include "th04/sprites/cels.h"
|
|
|
|
|
|
2021-05-25 16:22:48 +00:00
|
|
|
|
/// Game-specific group and spawn types
|
|
|
|
|
/// -----------------------------------
|
[Reverse-engineering] [th04/th05] Bullet pattern types
uth05win TL note: "n-way all-around" means "ring"… yep, let's better
improve on the naming here, once again using established terminology
from Sparen's Danmaku Design Guide at
https://sparen.github.io/ph3tutorials/ddsga3.html
Since TH04 only supports rings *or* spreads *or* stacks, overloading
[delta] to store both spread angle and stack speed, that enum does
serve kind of a purpose in TH04. Unlike TH05, where it could be vastly
simplified to a bitfield with 4 flags: aim to player, randomize angle,
randomize speed, force single. Which could then actually create *more*
types of patterns than these uselessly defined 14 distinct types, all
of which can already be derived from the other values of the upcoming
template structure:
• Set [stack] to 1 if you don't want a stack
• Set [spread] to 1 if you don't want a spread
• Set [spread_delta_angle] to 0 to turn a N-way spread into a ring
Easy.
Part of P0075, funded by Myles and -Tom-.
2020-02-14 16:34:06 +00:00
|
|
|
|
#if GAME == 5
|
2021-05-25 16:22:48 +00:00
|
|
|
|
# include "th05/main/bullet/types.h"
|
[Reverse-engineering] [th04/th05] Bullet pattern types
uth05win TL note: "n-way all-around" means "ring"… yep, let's better
improve on the naming here, once again using established terminology
from Sparen's Danmaku Design Guide at
https://sparen.github.io/ph3tutorials/ddsga3.html
Since TH04 only supports rings *or* spreads *or* stacks, overloading
[delta] to store both spread angle and stack speed, that enum does
serve kind of a purpose in TH04. Unlike TH05, where it could be vastly
simplified to a bitfield with 4 flags: aim to player, randomize angle,
randomize speed, force single. Which could then actually create *more*
types of patterns than these uselessly defined 14 distinct types, all
of which can already be derived from the other values of the upcoming
template structure:
• Set [stack] to 1 if you don't want a stack
• Set [spread] to 1 if you don't want a spread
• Set [spread_delta_angle] to 0 to turn a N-way spread into a ring
Easy.
Part of P0075, funded by Myles and -Tom-.
2020-02-14 16:34:06 +00:00
|
|
|
|
#else
|
2021-05-25 16:22:48 +00:00
|
|
|
|
# include "th04/main/bullet/types.h"
|
[Reverse-engineering] [th04/th05] Bullet pattern types
uth05win TL note: "n-way all-around" means "ring"… yep, let's better
improve on the naming here, once again using established terminology
from Sparen's Danmaku Design Guide at
https://sparen.github.io/ph3tutorials/ddsga3.html
Since TH04 only supports rings *or* spreads *or* stacks, overloading
[delta] to store both spread angle and stack speed, that enum does
serve kind of a purpose in TH04. Unlike TH05, where it could be vastly
simplified to a bitfield with 4 flags: aim to player, randomize angle,
randomize speed, force single. Which could then actually create *more*
types of patterns than these uselessly defined 14 distinct types, all
of which can already be derived from the other values of the upcoming
template structure:
• Set [stack] to 1 if you don't want a stack
• Set [spread] to 1 if you don't want a spread
• Set [spread_delta_angle] to 0 to turn a N-way spread into a ring
Easy.
Part of P0075, funded by Myles and -Tom-.
2020-02-14 16:34:06 +00:00
|
|
|
|
#endif
|
2021-05-25 16:22:48 +00:00
|
|
|
|
/// -----------------------------------
|
[Reverse-engineering] [th04/th05] Bullet pattern types
uth05win TL note: "n-way all-around" means "ring"… yep, let's better
improve on the naming here, once again using established terminology
from Sparen's Danmaku Design Guide at
https://sparen.github.io/ph3tutorials/ddsga3.html
Since TH04 only supports rings *or* spreads *or* stacks, overloading
[delta] to store both spread angle and stack speed, that enum does
serve kind of a purpose in TH04. Unlike TH05, where it could be vastly
simplified to a bitfield with 4 flags: aim to player, randomize angle,
randomize speed, force single. Which could then actually create *more*
types of patterns than these uselessly defined 14 distinct types, all
of which can already be derived from the other values of the upcoming
template structure:
• Set [stack] to 1 if you don't want a stack
• Set [spread] to 1 if you don't want a spread
• Set [spread_delta_angle] to 0 to turn a N-way spread into a ring
Easy.
Part of P0075, funded by Myles and -Tom-.
2020-02-14 16:34:06 +00:00
|
|
|
|
|
2020-02-03 19:32:56 +00:00
|
|
|
|
/// States and modes
|
|
|
|
|
/// ----------------
|
2021-07-22 18:48:47 +00:00
|
|
|
|
static const int BMS_DECAY_FRAMES_PER_CEL = 4;
|
2020-02-12 20:22:49 +00:00
|
|
|
|
#define BSS_CLOUD_FRAMES (BULLET_CLOUD_CELS * 4)
|
2021-07-22 18:48:47 +00:00
|
|
|
|
#define BMS_DECAY_FRAMES (BULLET_DECAY_CELS * BMS_DECAY_FRAMES_PER_CEL)
|
2021-06-27 13:28:58 +00:00
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
// gradually slows them down to their given speed over the next
|
|
|
|
|
// BMS_SLOWDOWN_FRAMES.
|
|
|
|
|
// • In TH04, this is not done for stacks.
|
2021-07-25 16:36:18 +00:00
|
|
|
|
// • In TH05, this is not done for any group with BST_NO_SLOWDOWN set.
|
2020-02-03 19:32:56 +00:00
|
|
|
|
#define BMS_SLOWDOWN_BASE_SPEED 4.5f
|
2021-06-27 13:28:58 +00:00
|
|
|
|
#define BMS_SLOWDOWN_THRESHOLD (BMS_SLOWDOWN_BASE_SPEED - 0.5f)
|
2020-02-03 19:32:56 +00:00
|
|
|
|
#define BMS_SLOWDOWN_FRAMES 32
|
|
|
|
|
|
|
|
|
|
enum bullet_spawn_state_t {
|
|
|
|
|
/// Hitbox is active
|
|
|
|
|
/// ----------------
|
|
|
|
|
BSS_GRAZEABLE = 0,
|
|
|
|
|
BSS_GRAZED = 1,
|
|
|
|
|
BSS_ACTIVE = 2,
|
|
|
|
|
/// ----------------
|
|
|
|
|
|
|
|
|
|
/// Delay "cloud", no hitbox
|
|
|
|
|
/// ------------------------
|
|
|
|
|
BSS_CLOUD_BACKWARDS = 3,
|
|
|
|
|
BSS_CLOUD_FORWARDS = 4,
|
|
|
|
|
BSS_CLOUD_END = (BSS_CLOUD_FORWARDS + BSS_CLOUD_FRAMES),
|
|
|
|
|
/// ------------------------
|
2021-07-22 18:48:47 +00:00
|
|
|
|
|
|
|
|
|
_bullet_spawn_state_t_FORCE_UINT8 = 0xFF
|
2020-02-03 19:32:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum bullet_move_state_t {
|
|
|
|
|
/// Hitbox is active
|
|
|
|
|
/// ----------------
|
|
|
|
|
// Slows down from BMS_SLOWDOWN_BASE_SPEED to [final_speed]
|
|
|
|
|
BMS_SLOWDOWN = 0,
|
|
|
|
|
// Special processing according to [special_motion]
|
|
|
|
|
BMS_SPECIAL = 1,
|
|
|
|
|
// No special processing
|
2021-07-25 17:03:45 +00:00
|
|
|
|
BMS_REGULAR = 2,
|
2020-02-03 19:32:56 +00:00
|
|
|
|
/// ----------------
|
|
|
|
|
|
|
|
|
|
/// Decay, no hitbox
|
|
|
|
|
/// ----------------
|
|
|
|
|
BMS_DECAY = 4,
|
|
|
|
|
BMS_DECAY_END = (BMS_DECAY + BMS_DECAY_FRAMES),
|
|
|
|
|
/// ----------------
|
2021-07-22 18:48:47 +00:00
|
|
|
|
|
|
|
|
|
_bullet_move_state_t_FORCE_UINT8 = 0xFF
|
2020-02-03 19:32:56 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum bullet_special_motion_t {
|
2022-02-19 10:32:42 +00:00
|
|
|
|
// This is so dumb.
|
|
|
|
|
_bullet_special_motion_t_offset = static_cast<int8_t>((GAME - 5) * 0x81),
|
|
|
|
|
|
|
|
|
|
// Slows down the bullet from its initial speed to 0, then aims to the
|
|
|
|
|
// player and resets to its initial speed.
|
|
|
|
|
// Affected by [bullet_special_motion.turns_max].
|
|
|
|
|
BSM_SLOWDOWN_THEN_TURN_AIMED,
|
|
|
|
|
|
|
|
|
|
// Slows down the bullet from its initial speed to 0, then increases its
|
|
|
|
|
// angle by [angle.turn_by] and resets to its initial speed.
|
|
|
|
|
// Affected by [bullet_special_motion.turns_max].
|
|
|
|
|
BSM_SLOWDOWN_THEN_TURN,
|
|
|
|
|
|
|
|
|
|
// Accelerates the speed of the bullet by
|
|
|
|
|
// [bullet_special_motion.speed_delta] every frame.
|
|
|
|
|
BSM_SPEEDUP,
|
|
|
|
|
|
|
|
|
|
// Slows down the bullet from its initial speed to 0 while turning it
|
|
|
|
|
// towards [angle.target]. Upon reaching a speed of 0, the bullet
|
|
|
|
|
// continues flying at that exact angle and resets to its initial speed.
|
|
|
|
|
BSM_SLOWDOWN_TO_ANGLE,
|
|
|
|
|
|
|
|
|
|
// Bounces the bullet into the opposite direction if it reaches the
|
|
|
|
|
// respective edge of the playfield.
|
|
|
|
|
// Affected by [bullet_special_motion.turns_max].
|
|
|
|
|
BSM_BOUNCE_LEFT_RIGHT,
|
|
|
|
|
BSM_BOUNCE_TOP_BOTTOM,
|
|
|
|
|
BSM_BOUNCE_LEFT_RIGHT_TOP_BOTTOM,
|
|
|
|
|
BSM_BOUNCE_LEFT_RIGHT_TOP,
|
|
|
|
|
|
|
|
|
|
// Accelerates the Y velocity of the bullet by
|
|
|
|
|
// [bullet_special_motion.speed_delta] every two frames.
|
|
|
|
|
BSM_GRAVITY,
|
|
|
|
|
|
|
|
|
|
#if (GAME == 5)
|
|
|
|
|
// Exact linear movement along a line; recalculates the bullet position
|
|
|
|
|
// based on the origin, angle, and distance every frame. Useful if
|
|
|
|
|
// regular incremental subpixel movement would introduce too much
|
|
|
|
|
// quantization noise.
|
|
|
|
|
BSM_EXACT_LINEAR,
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
BSM_NONE = 0xFF,
|
2020-02-03 19:32:56 +00:00
|
|
|
|
};
|
2022-02-19 10:30:10 +00:00
|
|
|
|
|
|
|
|
|
union bullet_special_angle_t {
|
|
|
|
|
unsigned char turn_by;
|
|
|
|
|
char target;
|
|
|
|
|
int8_t v;
|
|
|
|
|
};
|
2020-02-03 19:32:56 +00:00
|
|
|
|
/// ----------------
|
|
|
|
|
|
|
|
|
|
struct bullet_t {
|
2021-07-22 18:48:47 +00:00
|
|
|
|
unsigned char flag;
|
2020-02-03 19:32:56 +00:00
|
|
|
|
char age;
|
2021-06-30 14:30:06 +00:00
|
|
|
|
PlayfieldMotion pos;
|
2021-05-25 16:22:48 +00:00
|
|
|
|
unsigned char from_group; // unused
|
2020-02-03 19:32:56 +00:00
|
|
|
|
int8_t unused;
|
|
|
|
|
SubpixelLength8 speed_cur;
|
|
|
|
|
unsigned char angle;
|
|
|
|
|
bullet_spawn_state_t spawn_state;
|
|
|
|
|
bullet_move_state_t move_state;
|
|
|
|
|
bullet_special_motion_t special_motion;
|
2021-07-22 18:48:47 +00:00
|
|
|
|
SubpixelLength8 speed_final;
|
2020-02-03 19:32:56 +00:00
|
|
|
|
union {
|
|
|
|
|
unsigned char slowdown_time; // with BMS_SLOWDOWN
|
2022-02-19 10:30:10 +00:00
|
|
|
|
unsigned char turns_done; // with BMS_SPECIAL
|
2020-02-03 19:32:56 +00:00
|
|
|
|
} ax;
|
|
|
|
|
union {
|
2021-07-22 18:48:47 +00:00
|
|
|
|
// Difference between [speed_final] and the BMS_SLOWDOWN_BASE_SPEED.
|
|
|
|
|
// Always positive for BMS_SLOWDOWN bullets.
|
2022-02-26 23:36:22 +00:00
|
|
|
|
SubpixelLength8 slowdown_speed_delta; // with BMS_SLOWDOWN
|
|
|
|
|
bullet_special_angle_t angle; // with BMS_SPECIAL
|
2020-02-03 19:32:56 +00:00
|
|
|
|
} dx;
|
|
|
|
|
int patnum;
|
|
|
|
|
|
|
|
|
|
#if GAME == 5
|
2022-02-19 10:32:42 +00:00
|
|
|
|
// Coordinates for BSM_EXACT_LINEAR
|
2020-02-03 19:32:56 +00:00
|
|
|
|
SPPoint origin;
|
2022-02-19 10:32:42 +00:00
|
|
|
|
Subpixel distance;
|
2020-02-03 19:32:56 +00:00
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define PELLET_W 8
|
|
|
|
|
#define PELLET_H 8
|
|
|
|
|
#define BULLET16_W 16
|
|
|
|
|
#define BULLET16_H 16
|
|
|
|
|
|
2021-06-26 13:30:39 +00:00
|
|
|
|
// Symmetrical around the center point of each bullet, and treated in relation
|
|
|
|
|
// to a 1×1 "hitbox" around the player's center point.
|
|
|
|
|
static const subpixel_t BULLET_KILLBOX_W = TO_SP(8);
|
|
|
|
|
static const subpixel_t BULLET_KILLBOX_H = TO_SP(8);
|
|
|
|
|
|
2020-02-03 19:32:56 +00:00
|
|
|
|
#if GAME == 5
|
|
|
|
|
# define PELLET_COUNT 180
|
|
|
|
|
# define BULLET16_COUNT 220
|
2020-02-13 21:07:11 +00:00
|
|
|
|
|
2022-02-20 10:20:21 +00:00
|
|
|
|
// Returns the sprite ID of a directional or vector bullet sprite that
|
|
|
|
|
// represents the given [angle], relative to [patnum_base]. While the function
|
|
|
|
|
// is technically not restricted to `main_patnum_t` in TH05 and can also be
|
|
|
|
|
// used for a general (angle / BULLET_D_CELS) division, it still assumes
|
|
|
|
|
// [patnum_base] to be that type in order to distinguish vector bullets.
|
|
|
|
|
unsigned char pascal near bullet_patnum_for_angle(
|
|
|
|
|
int patnum_base, unsigned char angle
|
|
|
|
|
);
|
2020-02-13 21:07:11 +00:00
|
|
|
|
|
2021-07-22 18:48:47 +00:00
|
|
|
|
// Turns every 4th bullet into a point item when zapping bullets.
|
|
|
|
|
extern bool bullet_zap_drop_point_items;
|
2020-02-03 19:32:56 +00:00
|
|
|
|
#else
|
|
|
|
|
# define PELLET_COUNT 240
|
|
|
|
|
# define BULLET16_COUNT 200
|
2020-02-13 21:07:11 +00:00
|
|
|
|
|
|
|
|
|
// Returns the offset for a directional bullet sprite that shows the given
|
|
|
|
|
// [angle].
|
2021-06-24 18:46:39 +00:00
|
|
|
|
unsigned char pascal near bullet_patnum_for_angle(unsigned char angle);
|
2020-02-03 19:32:56 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define BULLET_COUNT (PELLET_COUNT + BULLET16_COUNT)
|
|
|
|
|
|
|
|
|
|
extern bullet_t bullets[BULLET_COUNT];
|
|
|
|
|
#define pellets (&bullets[0])
|
|
|
|
|
#define bullets16 (&bullets[PELLET_COUNT])
|
2020-02-15 20:13:31 +00:00
|
|
|
|
|
2022-02-19 10:30:10 +00:00
|
|
|
|
// Global parameters for special motion types.
|
|
|
|
|
extern union {
|
|
|
|
|
// Number of times a bullet can change its direction during various special
|
|
|
|
|
// motion types, before it changes back into a BMS_REGULAR bullet. A value
|
|
|
|
|
// of 0 will still allow a single direction change.
|
|
|
|
|
unsigned char turns_max;
|
|
|
|
|
|
|
|
|
|
SubpixelLength8 speed_delta;
|
|
|
|
|
} bullet_special_motion;
|
2020-09-13 17:52:38 +00:00
|
|
|
|
|
2020-08-14 15:52:47 +00:00
|
|
|
|
/// Template
|
|
|
|
|
/// --------
|
2020-02-15 20:13:31 +00:00
|
|
|
|
struct bullet_template_t {
|
|
|
|
|
uint8_t spawn_type;
|
|
|
|
|
unsigned char patnum; // TH05: 0 = pellet
|
2021-07-01 15:44:18 +00:00
|
|
|
|
PlayfieldPoint origin;
|
2020-02-15 20:13:31 +00:00
|
|
|
|
#if GAME == 5
|
2021-05-25 16:22:48 +00:00
|
|
|
|
bullet_group_t group;
|
2020-02-15 20:13:31 +00:00
|
|
|
|
bullet_special_motion_t special_motion;
|
|
|
|
|
unsigned char spread;
|
|
|
|
|
unsigned char spread_angle_delta;
|
|
|
|
|
unsigned char stack;
|
|
|
|
|
SubpixelLength8 stack_speed_delta;
|
|
|
|
|
unsigned char angle;
|
|
|
|
|
SubpixelLength8 speed;
|
2022-03-31 01:45:05 +00:00
|
|
|
|
|
|
|
|
|
void set_spread(unsigned char count, unsigned char angle_delta) {
|
|
|
|
|
// MODDERS: Just assign the values regularly, and don't rely on the
|
|
|
|
|
// physical layout of the structure.
|
|
|
|
|
reinterpret_cast<uint16_t &>(spread) = ((angle_delta << 8) | count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef RANK_H
|
|
|
|
|
void set_stack_for_rank(
|
|
|
|
|
unsigned char count_for_easy,
|
|
|
|
|
unsigned char count_for_normal,
|
|
|
|
|
unsigned char count_for_hard,
|
|
|
|
|
unsigned char count_for_lunatic,
|
|
|
|
|
subpixel_length_8_t speed_delta_for_easy,
|
|
|
|
|
subpixel_length_8_t speed_delta_for_normal,
|
|
|
|
|
subpixel_length_8_t speed_delta_for_hard,
|
|
|
|
|
subpixel_length_8_t speed_delta_for_lunatic
|
|
|
|
|
) {
|
|
|
|
|
// MODDERS: Just assign the values regularly, and don't rely on the
|
|
|
|
|
// physical layout of the structure.
|
|
|
|
|
reinterpret_cast<uint16_t &>(stack) = select_for_rank(
|
|
|
|
|
((count_for_easy << 8) | speed_delta_for_easy),
|
|
|
|
|
((count_for_normal << 8) | speed_delta_for_normal),
|
|
|
|
|
((count_for_hard << 8) | speed_delta_for_hard),
|
|
|
|
|
((count_for_lunatic << 8) | speed_delta_for_lunatic)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2020-02-15 20:13:31 +00:00
|
|
|
|
#else
|
2021-07-01 15:44:18 +00:00
|
|
|
|
PlayfieldPoint velocity;
|
2021-05-25 16:22:48 +00:00
|
|
|
|
bullet_group_t group;
|
2020-02-15 20:13:31 +00:00
|
|
|
|
unsigned char angle;
|
|
|
|
|
SubpixelLength8 speed;
|
|
|
|
|
unsigned char count;
|
|
|
|
|
bullet_template_delta_t delta;
|
|
|
|
|
uint8_t unused_1;
|
|
|
|
|
bullet_special_motion_t special_motion;
|
|
|
|
|
uint8_t unused_2;
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
extern bullet_template_t bullet_template;
|
2020-09-13 17:52:38 +00:00
|
|
|
|
// Separate from the template, for some reason?
|
2022-02-19 10:30:10 +00:00
|
|
|
|
extern bullet_special_angle_t bullet_template_special_angle;
|
2020-08-14 15:52:47 +00:00
|
|
|
|
|
|
|
|
|
// Modifies [bullet_template] based on [playperf] and the respective
|
2021-06-27 18:57:36 +00:00
|
|
|
|
// difficulty. These don't modify the base [speed]; that is done by the spawn
|
|
|
|
|
// functions themselves, unless overridden via the _fixedspeed() variants.
|
2020-08-14 15:52:47 +00:00
|
|
|
|
void pascal near bullet_template_tune_easy(void);
|
|
|
|
|
void pascal near bullet_template_tune_normal(void);
|
|
|
|
|
void pascal near bullet_template_tune_hard(void);
|
|
|
|
|
void pascal near bullet_template_tune_lunatic(void);
|
|
|
|
|
|
|
|
|
|
extern nearfunc_t_near bullet_template_tune;
|
2021-07-25 17:03:45 +00:00
|
|
|
|
|
|
|
|
|
// The actual functions for spawning bullets based on the [bullet_template].
|
|
|
|
|
// Both TH04 and TH05 pointlessly use separate functions for spawning "regular"
|
|
|
|
|
// bullets (which receive a move state of BMS_SLOWDOWN or BMS_REGULAR) or
|
|
|
|
|
// "special" ones (which are BMS_SPECIAL).
|
|
|
|
|
#if (GAME == 5)
|
|
|
|
|
void near bullets_add_regular(void);
|
|
|
|
|
void near bullets_add_special(void);
|
2021-07-25 17:58:36 +00:00
|
|
|
|
|
|
|
|
|
// Only used for the revenge bullets fired from Stage 3 Alice's barrier.
|
|
|
|
|
void far bullets_add_regular_far(void);
|
2021-07-25 17:03:45 +00:00
|
|
|
|
#else
|
2021-06-22 19:31:26 +00:00
|
|
|
|
// TH04 additionally uses pointless per-difficulty wrappers around these
|
|
|
|
|
// spawn functions that don't actually do anything difficulty-specific.
|
|
|
|
|
void pascal near bullets_add_regular_easy(void);
|
|
|
|
|
void pascal near bullets_add_regular_normal(void);
|
|
|
|
|
void pascal near bullets_add_regular_hard_lunatic(void);
|
|
|
|
|
void pascal near bullets_add_special_easy(void);
|
|
|
|
|
void pascal near bullets_add_special_normal(void);
|
|
|
|
|
void pascal near bullets_add_special_hard_lunatic(void);
|
|
|
|
|
|
2021-07-25 17:03:45 +00:00
|
|
|
|
// Set to the version of the wrapper functions above that match the
|
|
|
|
|
// current difficulty.
|
|
|
|
|
extern nearfunc_t_near bullets_add_regular;
|
|
|
|
|
extern nearfunc_t_near bullets_add_special;
|
|
|
|
|
#endif
|
2021-06-27 18:57:36 +00:00
|
|
|
|
|
|
|
|
|
// Further wrappers around the spawn functions that bypass base [speed] tuning
|
|
|
|
|
// of the resulting bullets based on [playperf], and fire them at a constant
|
|
|
|
|
// speed instead.
|
|
|
|
|
void near bullets_add_regular_fixedspeed(void);
|
|
|
|
|
void near bullets_add_special_fixedspeed(void);
|
2020-08-14 15:52:47 +00:00
|
|
|
|
/// --------
|