taisei/src/projectile.h

273 lines
9.5 KiB
C
Raw Normal View History

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
2024-05-16 23:30:41 +02:00
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
*/
#pragma once
#include "taisei.h"
2017-02-26 21:59:51 +01:00
#include "color.h"
#include "coroutine/coevent.h"
#include "entity.h"
#include "move.h"
#include "renderer/api.h"
#include "resource/resource.h"
#include "resource/shader_program.h"
#include "resource/sprite.h"
#include "util.h"
#if defined(DEBUG) && !defined(RNG_API_CHECK)
#define PROJ_DEBUG
#endif
2017-02-07 19:34:55 +01:00
#ifdef PROJ_DEBUG
#define IF_PROJ_DEBUG(...) __VA_ARGS__
#else
#define IF_PROJ_DEBUG(...)
#endif
enum {
PROJ_DRAWRULE_NUMARGS = 4
};
typedef LIST_ANCHOR(Projectile) ProjectileList;
typedef LIST_INTERFACE(Projectile) ProjectileListInterface;
typedef int (*ProjRule)(Projectile *p, int t);
typedef bool (*ProjPredicate)(Projectile *p);
typedef union {
float as_float[2];
cmplxf as_cmplx;
2019-12-27 16:59:15 +01:00
void *as_ptr;
} ProjDrawRuleArgs[PROJ_DRAWRULE_NUMARGS];
typedef struct ProjDrawRule {
void (*func)(Projectile *p, int t, ProjDrawRuleArgs args);
ProjDrawRuleArgs args;
} ProjDrawRule;
2011-07-06 14:33:53 +02:00
typedef enum {
PROJ_INVALID,
PROJ_ENEMY, // hazard, collides with player
PROJ_DEAD, // no collision, will be cleared shortly
PROJ_PARTICLE, // no collision, not a hazard
PROJ_PLAYER, // collides with enemies and bosses
2011-07-06 14:33:53 +02:00
} ProjType;
typedef enum ProjFlags {
2019-03-28 18:05:35 +01:00
// NOTE: Many of these flags are only meaningful for a specific type(s) of projectile.
// The relevant ProjType enum(s) are specified in [square brackets], or [ALL] if all apply.
PFLAG_NOSPAWNFLARE = (1 << 0), // [PROJ_ENEMY] Don't spawn the standard particle effect when spawned.
PFLAG_NOSPAWNFADE = (1 << 1), // [PROJ_ENEMY] Don't fade in when spawned; assume 100% opacity immediately.
PFLAG_NOGRAZE = (1 << 3), // [PROJ_ENEMY] Can't be grazed.
PFLAG_NOCLEAR = (1 << 4), // [PROJ_ENEMY] Can't be cleared (unless forced).
PFLAG_NOCLEAREFFECT = (1 << 5), // [PROJ_ENEMY, PROJ_DEAD] Don't spawn the standard particle effect when cleared.
PFLAG_NOCOLLISIONEFFECT = (1 << 6), // [PROJ_ENEMY, PROJ_DEAD, PROJ_PLAYER] Don't spawn the standard particle effect on collision.
PFLAG_NOCLEARBONUS = (1 << 7), // [PROJ_ENEMY, PROJ_DEAD] Don't spawn any bonus items on clear.
2019-09-01 22:27:11 +02:00
PFLAG_NOMOVE = (1 << 8), // [ALL] Don't call move_update for this projectile.
2019-03-28 18:05:35 +01:00
PFLAG_NOREFLECT = (1 << 9), // [ALL] Don't render a "reflection" of this on the Stage 1 water surface.
PFLAG_REQUIREDPARTICLE = (1 << 10), // [PROJ_PARTICLE] Visible at "minimal" particles setting.
PFLAG_PLRSPECIALPARTICLE = (1 << 11), // [PROJ_PARTICLE] Apply Power Surge effect to this particle, as if it was a PROJ_PLAYER.
PFLAG_NOCOLLISION = (1 << 12), // [PROJ_ENEMY, PROJ_PLAYER] Disable collision detection.
PFLAG_INTERNAL_DEAD = (1 << 13), // [ALL] Delete as soon as processed. (internal flag, do not use)
2019-09-01 22:27:11 +02:00
PFLAG_MANUALANGLE = (1 << 14), // [ALL] Don't automatically update the angle.
PFLAG_NOAUTOREMOVE = (1 << 15), // [ALL] Don't automatically remove when outside viewport.
PFLAG_INDESTRUCTIBLE = (1 << 16), // [PROJ_ENEMY, PROJ_PLAYER] Projectile doesn't get destroyed on collision.
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
PFLAG_NOSPAWNEFFECTS = PFLAG_NOSPAWNFADE | PFLAG_NOSPAWNFLARE,
} ProjFlags;
typedef enum ProjCollisionType {
PCOL_NONE = 0,
PCOL_ENTITY = (1 << 0),
PCOL_PLAYER_GRAZE = (1 << 1),
PCOL_VOID = (1 << 2),
} ProjCollisionType;
typedef struct ProjCollisionResult {
ProjCollisionType type;
bool fatal; // for the projectile
cmplx location;
DamageInfo damage;
EntityInterface *entity;
} ProjCollisionResult;
// FIXME: prototype stuff awkwardly shoved in this header because of dependency cycles.
typedef struct ProjPrototype ProjPrototype;
DEFINE_ENTITY_TYPE(Projectile, {
cmplx pos;
cmplx pos0;
cmplx prevpos; // used to lerp trajectory for collision detection; set this to pos if you intend to "teleport" the projectile in the rule!
cmplx size; // affects out-of-viewport culling and grazing
cmplx collision_size; // affects collision with player (TODO: make this work for player projectiles too?)
ShaderProgram *shader;
Sprite *sprite;
ProjPrototype *proto;
2023-02-24 01:44:54 +01:00
ProjDrawRule draw_rule;
/*
* This field is usually NULL except during handling of "collision" and "killed" events.
*
* "Collision" events are run before the collision result is applied, so they may modify this
* struct to affect the outcome.
*
* "Killed" events are run after the collision has happened, and thus shouldn't write to this
* field.
*
* Note that this may be NULL during "killed" events or cancelled "collision" events.
* In the former case this usually means the projectile was killed manually.
*
* Out of bounds auto-removals are considered collisions with "void" (PCOL_VOID).
*
* The pointer becomes invalid as soon as the event handler yields.
*/
ProjCollisionResult *collision;
MoveParams move;
2020-02-23 08:29:42 +01:00
COEVENTS_ARRAY(
collision,
2020-02-23 08:29:42 +01:00
cleared,
killed
) events;
Color color;
BlendMode blend;
int birthtime;
2018-07-30 09:04:09 +02:00
float damage;
float angle;
float angle_delta;
cmplx _cached_delta_pos;
real _cached_angle;
2011-07-06 14:33:53 +02:00
ProjType type;
2018-07-30 09:04:09 +02:00
DamageType damage_type;
int max_viewport_dist;
ProjFlags flags;
uint clear_flags;
cmplxf scale;
float opacity;
// XXX: this is in frames of course, but needs to be float
// to avoid subtle truncation and integer division gotchas.
float timeout;
2018-07-30 09:04:09 +02:00
int graze_counter_reset_timer;
int graze_cooldown;
2018-07-30 09:04:09 +02:00
short graze_counter;
IF_PROJ_DEBUG(
DebugInfo debug;
)
});
typedef struct ProjArgs {
ProjPrototype *proto;
Premultiplied alpha (#133) * WIP premultiplied alpha * WIP color API rework (doesn't build yet; lots of things left to convert) * convert everything remaining to new Color api except stage*_event.c files * convert the stages to new Color api. builds & runs now; still many rendering errors * fix the bullet shader for premultiplied alpha * fix masterspark, graphs and stage 1 fog clouds * fix marisa_b and most of spellcards * Add deprecation warnings for BLEND_ADD and PFLAG_DRAWADD * fix a segfault in stage 6 undo accidental earlier change * fix text_hud.frag.glsl * fix scuttle bg and remaining stage3 BLEND_ADDs * fix marisa laser opacity * hacky fix for myon The old implementation relied on alpha being stored inside p->color. In premul alpha this doesn’t work and functions like color_set_opacity can’t solve this i think. So I tried messing around with it until it looked somewhat similar. * fix marisa_b stars * remove color_set_opacity i overlooked * more plrmode blending changes * fixup additive blending in stage 1 * various premultiplied alpha fixups for bosses and enemies * stage 2 premul alpha fixups * stage 4 premul alpha fixups * stage 5 premul alpha fixups * stage 6 premul alpha fixups * make lasers also use the PMA blend mode * remove PFLAG_DRAWADD and PFLAG_DRAWSUB * fix remaining PMA issues in menus * lame extraspell bg workaround * fix item alpha * make marisaA lasers look somewhat like in master * fix marisaA bomb background fadeout * fixup various r_color4 calls * fix myon * remove dead code * fix use of BLEND_ADD in player death effect * fix myon shot trails (broken on master as well) * fix myon shot fade-in * extend the sprite shaders custom parameter to a vec4 * fix youmuB stuff and make it look somewhat better. the code looks even worse though.
2018-07-23 19:07:59 +02:00
const Color *color;
const char *sprite;
Sprite *sprite_ptr;
const char *shader;
ShaderProgram *shader_ptr;
ProjectileList *dest;
ProjDrawRule draw_rule;
cmplx pos;
cmplx size; // affects default draw order, out-of-viewport culling, and grazing
cmplx collision_size; // affects collision with player (TODO: make this work for player projectiles too?)
MoveParams move;
ProjType type;
ProjFlags flags;
BlendMode blend;
float angle;
float angle_delta;
2018-07-30 09:04:09 +02:00
float damage;
DamageType damage_type;
int max_viewport_dist;
drawlayer_t layer;
cmplxf scale;
float opacity;
// XXX: this is in frames of course, but needs to be float
// to avoid subtle truncation and integer division gotchas.
float timeout;
} attr_designated_init ProjArgs;
struct ProjPrototype {
void (*preload)(ProjPrototype *proto, ResourceGroup *rg);
void (*process_args)(ProjPrototype *proto, ProjArgs *args);
void (*reset)(ProjPrototype *proto);
void (*init_projectile)(ProjPrototype *proto, Projectile *p);
void (*deinit_projectile)(ProjPrototype *proto, Projectile *p);
void *private;
};
#define PP(name) \
extern ProjPrototype _pp_##name; \
extern ProjPrototype *pp_##name; \
#include "projectile_prototypes/all.inc.h"
2021-06-18 16:07:51 +02:00
Projectile *create_projectile(ProjArgs *args)
attr_nonnull_all attr_returns_nonnull attr_returns_max_aligned;
Projectile *create_particle(ProjArgs *args)
attr_nonnull_all attr_returns_nonnull attr_returns_max_aligned;
#ifdef PROJ_DEBUG
Projectile *_proj_attach_dbginfo(Projectile *p, DebugInfo *dbg, const char *callsite_str)
attr_nonnull_all;
#define _PROJ_WRAP_SPAWN(p) _proj_attach_dbginfo((p), _DEBUG_INFO_PTR_, #p)
#else
#define _PROJ_WRAP_SPAWN(p) (p)
#endif
#define _PROJ_GENERIC_SPAWN(constructor, ...) _PROJ_WRAP_SPAWN((constructor)((&(ProjArgs) { __VA_ARGS__ })))
#define PROJECTILE(...) _PROJ_GENERIC_SPAWN(create_projectile, __VA_ARGS__)
#define PARTICLE(...) _PROJ_GENERIC_SPAWN(create_particle, __VA_ARGS__)
void delete_projectiles(ProjectileList *projlist) attr_nonnull_all;
void calc_projectile_collision(Projectile *p, ProjCollisionResult *out_col) attr_nonnull_all;
void apply_projectile_collision(ProjectileList *projlist, Projectile *p, ProjCollisionResult *col) attr_nonnull_all;
int trace_projectile(Projectile *p, ProjCollisionResult *out_col, ProjCollisionType stopflags, int timeofs) attr_nonnull_all;
bool projectile_in_viewport(Projectile *proj) attr_nonnull_all;
void process_projectiles(ProjectileList *projlist, bool collision) attr_hot attr_nonnull_all;
bool projectile_is_clearable(Projectile *p) attr_nonnull_all;
Projectile *spawn_projectile_collision_effect(Projectile *proj) attr_nonnull_all;
Projectile *spawn_projectile_clear_effect(Projectile *proj) attr_nonnull_all;
Projectile *spawn_projectile_highlight_effect(Projectile *proj) attr_nonnull_all;
void projectile_set_prototype(Projectile *p, ProjPrototype *proto) attr_nonnull(1);
void projectile_set_layer(Projectile *p, drawlayer_t layer) attr_nonnull_all;
bool clear_projectile(Projectile *proj, uint flags) attr_nonnull_all;
void kill_projectile(Projectile *proj) attr_nonnull_all;
ProjDrawRule pdraw_basic(void);
ProjDrawRule pdraw_timeout_scalefade_exp(cmplxf scale0, cmplxf scale1, float opacity0, float opacity1, float opacity_exp);
ProjDrawRule pdraw_timeout_scalefade(cmplxf scale0, cmplxf scale1, float opacity0, float opacity1);
ProjDrawRule pdraw_timeout_scale(cmplxf scale0, cmplxf scale1);
ProjDrawRule pdraw_timeout_fade(float opacity0, float opacity1);
ProjDrawRule pdraw_petal(float rot_angle, vec3 rot_axis);
ProjDrawRule pdraw_petal_random(void);
ProjDrawRule pdraw_blast(void);
void petal_explosion(int n, cmplx pos);
2011-08-28 10:57:45 +02:00
void projectiles_preload(ResourceGroup *rg);
Lots of disorganized (mostly) visual overhaul (#156) * WIP some projectile effects * fix segfault * Laser smoothing and glow via post-processing blur magic TODO: make it optional * fix memory corruption * fix memory corruption for realsies now * fix color_get_hsl for out-of-range colors * some more bullet flare tweaks * some lame clear effect workarounds * spawn bullet flares after frame 0; looks better and fixes some problems * New baryon explosion; fix petal_explosion; leanify everything * Add missing bullet flare sprite, rebuild main atlas * improve batching efficiency with bullet spawn flares * forgot git add * Group projectiles/particles by shader where possible * Another take on baryon explosion; make fg framebuffers 16bit * WIP some settings for toasters * remove stupid debug log * microoptimization that probably does nothing anyway * somewhat more intuitive quality settings * Whitelist more particles (MarisaB is on hold) * Whitelist (and fix) some more stage6 particles (mostly ToE) * Add a spell name background * Experimental radial healthbar for bosses * healthbar tweaks * thiccer healthbars in response to feedback * remove healthbar survival timer; just fade out on survivals * Add linear healthbars option; WIP other boss HUD tweaks * Use the proper spell card name format * New font and some random garbage to go along with it * Generate static font outlines for use in text shaders * Use outlines in overlay text shader * Complete boss HUD/healthbar fading logic * fix boss timer limit * stage5 bombs explosion effect * split PFLAG_NOSPAWNZOOM into PFLAG_NOSPAWNFLARE and PFLAG_NOSPAWNFADE; introduce PFLAG_NOSPAWNEFFECTS which disables both (it's just the two values OR'd together) simplify vampiric vapor bullet spawning effect * Remove spawn fade-in from super-fast stage5 fairy projectiles (limiters) * lower particle density in v.vapor in minimal mode * graze effect tweaks * fix text shortening, tweak replay menu layout * stupid debug spam * revisit grazing effects again * dumb debug spam again * improve boss attack timer * overlay effect for boss deaths (similar to the player one) * spice up spellcard declaration (HUD) * don't spawn boss death overlay if fleed * modify Exo2 font to use tabular figures * adjust replay menu for the font change * draw timer & power with standard font (phasing out the numbers font) * WIP new HUD; random fixes/tweaks * hud: move difficulty indicator * hud: move debug stuff around * preloads, mostly * fix youmuA batching conflict * shitty workaround for the shitty screenshake shit * remove extraspell lag by stopping to draw stagebg sooner which is possible because extra spells have a different spellcard_intro timing. Fun fact of the day: the duration of spellcard_intro is always ATTACK_START_DELAY_EXTRA even for normal spells! * new stain particle * i disabled background rendering… * "batch" marisa_b masterspark draws * remove these once a new atlas is generated * make toe quick again * hopefully fix all occurences of changed stain and ScaleFade behavior * tweaking reimu_a and toe boson launch effects * make lhc fast again * softer involnerability effect * fix stage 1 snow on the water bug (and improve performance) translated the time to the future a bit because it only seemed to be an issue for small time values * remove unnecessary spawnflare from toe * tone down extra spell start effect * experimental ReimuB gap shader optimization * fix python3 shebangs * generate simple blur shaders w/ hardcoded kernels * New loading screen * lasers: fix incorrect draw hook registration * add webp support for atlas generator * Use ImageMagick for atlas composition (adds 16-bit support) * Atlas maintenance * make the vampiric vapor bullets less prone to invisibility * Revert a few particles to the quadratic fade curve * experimental baryon effect * improve baryon sprites * disable the baryon effect on minimal postprocessing setting
2019-01-04 23:59:39 +01:00
void projectiles_free(void);
cmplx projectile_graze_size(Projectile *p);
float projectile_timeout_factor(Projectile *p);
int projectile_time(Projectile *p);
SpriteParams projectile_sprite_params(Projectile *proj, SpriteParamsBuffer *spbuf);