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
|
|
|
|
/// ----------------
|
2020-08-14 19:07:46 +00:00
|
|
|
/// Everything here needs to be kept in sync with the ASM versions in
|
|
|
|
/// bullet.hpp!
|
2020-02-12 20:22:49 +00:00
|
|
|
#define BSS_CLOUD_FRAMES (BULLET_CLOUD_CELS * 4)
|
|
|
|
#define BMS_DECAY_FRAMES (BULLET_DECAY_CELS * 4)
|
2020-02-03 19:32:56 +00:00
|
|
|
#define BMS_SLOWDOWN_BASE_SPEED 4.5f
|
|
|
|
#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),
|
|
|
|
/// ------------------------
|
|
|
|
};
|
|
|
|
|
|
|
|
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
|
|
|
|
BMS_NORMAL = 2,
|
|
|
|
/// ----------------
|
|
|
|
|
|
|
|
/// Decay, no hitbox
|
|
|
|
/// ----------------
|
|
|
|
BMS_DECAY = 4,
|
|
|
|
BMS_DECAY_END = (BMS_DECAY + BMS_DECAY_FRAMES),
|
|
|
|
/// ----------------
|
|
|
|
};
|
|
|
|
|
|
|
|
enum bullet_special_motion_t {
|
|
|
|
};
|
|
|
|
/// ----------------
|
|
|
|
|
2020-08-14 19:07:46 +00:00
|
|
|
// Needs to be kept in sync with the ASM version in bullet.inc!
|
2020-02-03 19:32:56 +00:00
|
|
|
struct bullet_t {
|
|
|
|
char flag;
|
|
|
|
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;
|
|
|
|
unsigned char speed_final;
|
|
|
|
union {
|
|
|
|
unsigned char slowdown_time; // with BMS_SLOWDOWN
|
|
|
|
unsigned char turn_count; // with BMS_SPECIAL
|
|
|
|
} ax;
|
|
|
|
union {
|
|
|
|
unsigned char slowdown_speed_delta; // with BMS_SLOWDOWN
|
|
|
|
unsigned char turn_angle; // with BMS_SPECIAL
|
|
|
|
} dx;
|
|
|
|
int patnum;
|
|
|
|
|
|
|
|
#if GAME == 5
|
|
|
|
// Coordinates for BSM_STRAIGHT
|
|
|
|
SPPoint origin;
|
|
|
|
int distance;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
#define PELLET_W 8
|
|
|
|
#define PELLET_H 8
|
|
|
|
#define BULLET16_W 16
|
|
|
|
#define BULLET16_H 16
|
|
|
|
|
|
|
|
#if GAME == 5
|
|
|
|
# define PELLET_COUNT 180
|
|
|
|
# define BULLET16_COUNT 220
|
2020-02-13 21:07:11 +00:00
|
|
|
|
|
|
|
// Returns the patnum for the directional or vector bullet sprite starting at
|
|
|
|
// [patnum_base] that shows the given [angle].
|
|
|
|
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);
|
|
|
|
|
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].
|
|
|
|
int pascal near bullet_patnum_for_angle(unsigned char angle);
|
2020-04-11 14:33:22 +00:00
|
|
|
|
[Reverse-engineering] [th04/th05] Bullets: Distinguish clear and zap mechanics
And actually document them correctly.
Clear: Custom duration, awards constant points per bullet during the
entire duration, plays a decay animation
Zap: Fixed duration, awards a semi-exponential bonus for all bullets
alive on the first frame, plays a, um, "zapping" animation… in
TH04, because it's bugged in TH05 :zunpet:
Part of P0149, funded by Blue Bolt, Ember2528, and -Tom-.
2021-07-24 19:25:25 +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
|
|
|
#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
|
|
|
|
2020-09-13 17:52:38 +00:00
|
|
|
// Number of times a bouncing bullet can change its direction before it
|
|
|
|
// automatically turns into a BMS_NORMAL bullet. Global state, not set
|
|
|
|
// per-bullet!
|
|
|
|
extern unsigned char bullet_turn_count_max;
|
|
|
|
|
[Reverse-engineering] [th04/th05] Bullets: Distinguish clear and zap mechanics
And actually document them correctly.
Clear: Custom duration, awards constant points per bullet during the
entire duration, plays a decay animation
Zap: Fixed duration, awards a semi-exponential bonus for all bullets
alive on the first frame, plays a, um, "zapping" animation… in
TH04, because it's bugged in TH05 :zunpet:
Part of P0149, funded by Blue Bolt, Ember2528, and -Tom-.
2021-07-24 19:25:25 +00:00
|
|
|
// Set to `true` to clear all on-screen bullets, giving out a semi-exponential
|
|
|
|
// bonus for all bullets that were alive on the first frame of activity.
|
|
|
|
// Lasts for BULLET_ZAP_FRAMES and resets to `false` afterwards.
|
2021-07-24 12:29:47 +00:00
|
|
|
extern union {
|
|
|
|
bool active;
|
|
|
|
unsigned char frames; // doubles as the animation timer
|
|
|
|
} bullet_zap;
|
[Reverse-engineering] [th04/th05] Bullets: Distinguish clear and zap mechanics
And actually document them correctly.
Clear: Custom duration, awards constant points per bullet during the
entire duration, plays a decay animation
Zap: Fixed duration, awards a semi-exponential bonus for all bullets
alive on the first frame, plays a, um, "zapping" animation… in
TH04, because it's bugged in TH05 :zunpet:
Part of P0149, funded by Blue Bolt, Ember2528, and -Tom-.
2021-07-24 19:25:25 +00:00
|
|
|
static const int BULLET_ZAP_FRAMES_PER_CEL = 4;
|
|
|
|
static const int BULLET_ZAP_FRAMES = (
|
|
|
|
BULLET_ZAP_CELS * BULLET_ZAP_FRAMES_PER_CEL
|
|
|
|
);
|
|
|
|
|
|
|
|
// # of frames left during which all on-screen bullets should decay.
|
|
|
|
// Gives a constant point bonus for every bullet decayed during that time.
|
|
|
|
extern unsigned char bullet_clear_time;
|
|
|
|
|
2020-03-27 21:12:18 +00:00
|
|
|
/// Rendering
|
|
|
|
/// ---------
|
|
|
|
union pellet_render_t {
|
|
|
|
struct {
|
2020-08-20 19:59:45 +00:00
|
|
|
screen_x_t left;
|
|
|
|
vram_y_t top;
|
2020-03-27 21:12:18 +00:00
|
|
|
} top;
|
|
|
|
struct {
|
2020-08-21 17:18:28 +00:00
|
|
|
vram_offset_t vram_offset;
|
2020-03-27 21:12:18 +00:00
|
|
|
uint16_t sprite_offset;
|
|
|
|
} bottom;
|
|
|
|
};
|
|
|
|
|
2020-08-26 21:36:47 +00:00
|
|
|
#if (GAME == 5)
|
|
|
|
// Separate render list for pellets during their delay cloud stage.
|
|
|
|
extern int pellet_clouds_render_count;
|
|
|
|
extern bullet_t near *pellet_clouds_render[PELLET_COUNT];
|
|
|
|
#endif
|
|
|
|
|
2020-04-17 16:14:00 +00:00
|
|
|
extern int pellets_render_count;
|
2020-03-27 21:12:18 +00:00
|
|
|
extern pellet_render_t pellets_render[PELLET_COUNT];
|
|
|
|
|
|
|
|
// Renders the top and bottom part of all pellets, as per [pellets_render] and
|
2020-06-18 18:01:29 +00:00
|
|
|
// [pellets_render_count]. Assumptions:
|
2020-03-27 21:12:18 +00:00
|
|
|
// • ES is already be set to the beginning of a VRAM segment
|
|
|
|
// • The GRCG is active, and set to the intended color
|
|
|
|
// • pellets_render_top() is called before pellets_render_bottom()
|
|
|
|
void near pellets_render_top();
|
|
|
|
void near pellets_render_bottom();
|
|
|
|
/// ---------
|
|
|
|
|
2020-08-14 15:52:47 +00:00
|
|
|
/// Template
|
|
|
|
/// --------
|
2020-08-14 19:07:46 +00:00
|
|
|
// Needs to be kept in sync with the ASM version in bullet.inc!
|
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;
|
|
|
|
#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?
|
|
|
|
extern unsigned char bullet_template_turn_angle;
|
2020-08-14 15:52:47 +00:00
|
|
|
|
|
|
|
// Modifies [bullet_template] based on [playperf] and the respective
|
|
|
|
// difficulty.
|
|
|
|
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;
|
|
|
|
/// --------
|