1 /* 2 * This software is licensed under the terms of the MIT License. 3 * See COPYING for further information. 4 * --- 5 * Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>. 6 * Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>. 7 */ 8 9 #ifndef IGUARD_projectile_h 10 #define IGUARD_projectile_h 11 12 #include "taisei.h" 13 14 #include "util.h" 15 #include "resource/sprite.h" 16 #include "resource/shader_program.h" 17 #include "color.h" 18 #include "objectpool.h" 19 #include "renderer/api.h" 20 #include "entity.h" 21 22 #ifdef DEBUG 23 #define PROJ_DEBUG 24 #endif 25 26 enum { 27 RULE_ARGC = 4 28 }; 29 30 typedef struct Projectile Projectile; 31 typedef LIST_ANCHOR(Projectile) ProjectileList; 32 typedef LIST_INTERFACE(Projectile) ProjectileListInterface; 33 34 typedef int (*ProjRule)(Projectile *p, int t); 35 typedef void (*ProjDrawRule)(Projectile *p, int t); 36 typedef bool (*ProjPredicate)(Projectile *p); 37 38 typedef enum { 39 PROJ_INVALID, 40 41 PROJ_ENEMY, // hazard, collides with player 42 PROJ_DEAD, // no collision, will be cleared shortly 43 PROJ_PARTICLE, // no collision, not a hazard 44 PROJ_PLAYER, // collides with enemies and bosses 45 } ProjType; 46 47 typedef enum ProjFlags { 48 // NOTE: Many of these flags are only meaningful for a specific type(s) of projectile. 49 // The relevant ProjType enum(s) are specified in [square brackets], or [ALL] if all apply. 50 51 PFLAG_NOSPAWNFLARE = (1 << 0), // [PROJ_ENEMY] Don't spawn the standard particle effect when spawned. 52 PFLAG_NOSPAWNFADE = (1 << 1), // [PROJ_ENEMY] Don't fade in when spawned; assume 100% opacity immediately. 53 PFLAG_NOGRAZE = (1 << 3), // [PROJ_ENEMY] Can't be grazed. 54 PFLAG_NOCLEAR = (1 << 4), // [PROJ_ENEMY] Can't be cleared (unless forced). 55 PFLAG_NOCLEAREFFECT = (1 << 5), // [PROJ_ENEMY, PROJ_DEAD] Don't spawn the standard particle effect when cleared. 56 PFLAG_NOCOLLISIONEFFECT = (1 << 6), // [PROJ_ENEMY, PROJ_DEAD, PROJ_PLAYER] Don't spawn the standard particle effect on collision. 57 PFLAG_NOCLEARBONUS = (1 << 7), // [PROJ_ENEMY, PROJ_DEAD] Don't spawn any bonus items on clear. 58 // PFLAG_RESERVED = (1 << 8), 59 PFLAG_NOREFLECT = (1 << 9), // [ALL] Don't render a "reflection" of this on the Stage 1 water surface. 60 PFLAG_REQUIREDPARTICLE = (1 << 10), // [PROJ_PARTICLE] Visible at "minimal" particles setting. 61 PFLAG_PLRSPECIALPARTICLE = (1 << 11), // [PROJ_PARTICLE] Apply Power Surge effect to this particle, as if it was a PROJ_PLAYER. 62 PFLAG_NOCOLLISION = (1 << 12), // [PROJ_ENEMY, PROJ_PLAYER] Disable collision detection. 63 64 PFLAG_NOSPAWNEFFECTS = PFLAG_NOSPAWNFADE | PFLAG_NOSPAWNFLARE, 65 } ProjFlags; 66 67 // FIXME: prototype stuff awkwardly shoved in this header because of dependency cycles. 68 typedef struct ProjPrototype ProjPrototype; 69 70 struct Projectile { 71 ENTITY_INTERFACE_NAMED(Projectile, ent); 72 73 cmplx pos; 74 cmplx pos0; 75 cmplx prevpos; // used to lerp trajectory for collision detection; set this to pos if you intend to "teleport" the projectile in the rule! 76 cmplx size; // affects out-of-viewport culling and grazing 77 cmplx collision_size; // affects collision with player (TODO: make this work for player projectiles too?) 78 cmplx args[RULE_ARGC]; 79 ProjRule rule; 80 ProjDrawRule draw_rule; 81 ShaderProgram *shader; 82 Sprite *sprite; 83 ProjPrototype *proto; 84 Color color; 85 ShaderCustomParams shader_params; 86 BlendMode blend; 87 int birthtime; 88 float damage; 89 float angle; 90 ProjType type; 91 DamageType damage_type; 92 int max_viewport_dist; 93 ProjFlags flags; 94 uint clear_flags; 95 96 // XXX: this is in frames of course, but needs to be float 97 // to avoid subtle truncation and integer division gotchas. 98 float timeout; 99 100 int graze_counter_reset_timer; 101 int graze_cooldown; 102 short graze_counter; 103 104 #ifdef PROJ_DEBUG 105 DebugInfo debug; 106 #endif 107 }; 108 109 typedef struct ProjArgs { 110 ProjPrototype *proto; 111 const Color *color; 112 const char *sprite; 113 Sprite *sprite_ptr; 114 const char *shader; 115 ShaderProgram *shader_ptr; 116 const ShaderCustomParams *shader_params; 117 ProjectileList *dest; 118 ProjRule rule; 119 cmplx args[RULE_ARGC]; 120 ProjDrawRule draw_rule; 121 cmplx pos; 122 cmplx size; // affects default draw order, out-of-viewport culling, and grazing 123 cmplx collision_size; // affects collision with player (TODO: make this work for player projectiles too?) 124 ProjType type; 125 ProjFlags flags; 126 BlendMode blend; 127 float angle; 128 float damage; 129 DamageType damage_type; 130 int max_viewport_dist; 131 drawlayer_t layer; 132 133 // XXX: this is in frames of course, but needs to be float 134 // to avoid subtle truncation and integer division gotchas. 135 float timeout; 136 } attr_designated_init ProjArgs; 137 138 struct ProjPrototype { 139 void (*preload)(ProjPrototype *proto); 140 void (*process_args)(ProjPrototype *proto, ProjArgs *args); 141 void (*init_projectile)(ProjPrototype *proto, Projectile *p); 142 void (*deinit_projectile)(ProjPrototype *proto, Projectile *p); 143 void *private; 144 }; 145 146 #define PP(name) \ 147 extern ProjPrototype _pp_##name; \ 148 extern ProjPrototype *pp_##name; \ 149 150 #include "projectile_prototypes/all.inc.h" 151 152 #define PARTICLE_ADDITIVE_SUBLAYER (1 << 3) 153 154 typedef enum ProjCollisionType { 155 PCOL_NONE = 0, 156 PCOL_ENTITY = (1 << 0), 157 PCOL_PLAYER_GRAZE = (1 << 1), 158 PCOL_VOID = (1 << 2), 159 } ProjCollisionType; 160 161 typedef struct ProjCollisionResult { 162 ProjCollisionType type; 163 bool fatal; // for the projectile 164 cmplx location; 165 DamageInfo damage; 166 EntityInterface *entity; 167 } ProjCollisionResult; 168 169 Projectile* create_projectile(ProjArgs *args); 170 Projectile* create_particle(ProjArgs *args); 171 172 #ifdef PROJ_DEBUG 173 Projectile* _proj_attach_dbginfo(Projectile *p, DebugInfo *dbg, const char *callsite_str); 174 #define _PROJ_WRAP_SPAWN(p) _proj_attach_dbginfo((p), _DEBUG_INFO_PTR_, #p) 175 #else 176 #define _PROJ_WRAP_SPAWN(p) (p) 177 #endif 178 179 #define _PROJ_GENERIC_SPAWN(constructor, ...) _PROJ_WRAP_SPAWN((constructor)((&(ProjArgs) { __VA_ARGS__ }))) 180 181 #define PROJECTILE(...) _PROJ_GENERIC_SPAWN(create_projectile, __VA_ARGS__) 182 #define PARTICLE(...) _PROJ_GENERIC_SPAWN(create_particle, __VA_ARGS__) 183 184 void delete_projectile(ProjectileList *projlist, Projectile *proj); 185 void delete_projectiles(ProjectileList *projlist); 186 187 void calc_projectile_collision(Projectile *p, ProjCollisionResult *out_col); 188 void apply_projectile_collision(ProjectileList *projlist, Projectile *p, ProjCollisionResult *col); 189 int trace_projectile(Projectile *p, ProjCollisionResult *out_col, ProjCollisionType stopflags, int timeofs); 190 bool projectile_in_viewport(Projectile *proj); 191 void process_projectiles(ProjectileList *projlist, bool collision); 192 bool projectile_is_clearable(Projectile *p); 193 194 Projectile* spawn_projectile_collision_effect(Projectile *proj); 195 Projectile* spawn_projectile_clear_effect(Projectile *proj); 196 Projectile* spawn_projectile_highlight_effect(Projectile *proj); 197 198 void projectile_set_prototype(Projectile *p, ProjPrototype *proto); 199 200 bool clear_projectile(Projectile *proj, uint flags); 201 202 int linear(Projectile *p, int t); 203 int accelerated(Projectile *p, int t); 204 int asymptotic(Projectile *p, int t); 205 206 void ProjDrawCore(Projectile *proj, const Color *c); 207 void ProjDraw(Projectile *p, int t); 208 void ProjNoDraw(Projectile *proj, int t); 209 210 void Shrink(Projectile *p, int t); 211 void DeathShrink(Projectile *p, int t); 212 void Fade(Projectile *p, int t); 213 void GrowFade(Projectile *p, int t); 214 void ScaleFade(Projectile *p, int t); 215 void ScaleSquaredFade(Projectile *p, int t); 216 217 void Petal(Projectile *p, int t); 218 void petal_explosion(int n, cmplx pos); 219 220 void Blast(Projectile *p, int t); 221 222 void projectiles_preload(void); 223 void projectiles_free(void); 224 225 cmplx projectile_graze_size(Projectile *p); 226 227 #endif // IGUARD_projectile_h 228