WIP proj draw rule revamp; YoumuB revamp; misc changes; giant mess
cursed commit
This commit is contained in:
parent
5c6b7671ef
commit
3d1c0eee4e
46 changed files with 1032 additions and 704 deletions
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 503 B |
BIN
atlas/coroutines_temp/part/stardust.webp
Normal file
BIN
atlas/coroutines_temp/part/stardust.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
atlas/coroutines_temp/proj/hghost.webp
Normal file
BIN
atlas/coroutines_temp/proj/hghost.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
|
@ -44,6 +44,7 @@ atlases = [
|
|||
['gray16', [preset_png]],
|
||||
['huge', []],
|
||||
['portraits', ['--width=4096', '--height=4096']],
|
||||
['coroutines_temp', []], # TODO merge this into `common` when coroutines are merged
|
||||
]
|
||||
|
||||
atlas_profiles = [
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
|
||||
w = 22
|
||||
h = 23
|
||||
w = 21
|
||||
h = 34
|
||||
|
|
2
external/koishi
vendored
2
external/koishi
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 88939b719021952864030ac9dbc1be4f9d3fa063
|
||||
Subproject commit 76c7d3d3160da7a2fc73d558b3a0d759f48e8444
|
|
@ -0,0 +1,7 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
source = res/gfx/atlas_coroutines_temp_0.webp
|
||||
|
||||
# -- Pasted from the global override file --
|
||||
|
||||
anisotropy = 1
|
BIN
resources/00-taisei.pkgdir/gfx/atlas_coroutines_temp_0.webp
Normal file
BIN
resources/00-taisei.pkgdir/gfx/atlas_coroutines_temp_0.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
|
@ -1,7 +1,7 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_common_0
|
||||
region_x = 2362
|
||||
region_y = 1724
|
||||
texture = atlas_coroutines_temp_0
|
||||
region_x = 2
|
||||
region_y = 2
|
||||
region_w = 100
|
||||
region_h = 100
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# Autogenerated by the atlas packer, do not modify
|
||||
|
||||
texture = atlas_common_0
|
||||
region_x = 1632
|
||||
region_y = 372
|
||||
region_w = 22
|
||||
region_h = 23
|
||||
texture = atlas_coroutines_temp_0
|
||||
region_x = 106
|
||||
region_y = 2
|
||||
region_w = 42
|
||||
region_h = 68
|
||||
|
||||
# -- Pasted from the override file --
|
||||
|
||||
w = 22
|
||||
h = 23
|
||||
w = 21
|
||||
h = 34
|
||||
|
|
|
@ -55,11 +55,10 @@ glsl_files = files(
|
|||
'sprite_hakkero.frag.glsl',
|
||||
'sprite_hakkero.vert.glsl',
|
||||
'sprite_negative.frag.glsl',
|
||||
'sprite_particle.frag.glsl',
|
||||
'sprite_silhouette.frag.glsl',
|
||||
'sprite_silhouette.vert.glsl',
|
||||
'sprite_yinyang.frag.glsl',
|
||||
'sprite_youmu_charged_shot.frag.glsl',
|
||||
'sprite_youmu_charged_shot.vert.glsl',
|
||||
'sprite_youmu_myon_shot.frag.glsl',
|
||||
'stage1_water.frag.glsl',
|
||||
'stage6_sky.frag.glsl',
|
||||
|
|
|
@ -9,5 +9,5 @@ void spriteMain(out vec4 fragColor) {
|
|||
discard;
|
||||
}
|
||||
|
||||
fragColor = (color * texel.g + vec4(texel.b)) * (1 - customParams.r);
|
||||
fragColor = (color * texel.g + vec4(texel.b)) * customParams.r;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
void spriteMain(out vec4 fragColor) {
|
||||
vec4 texel = texture(tex, texCoord);
|
||||
float oWhite = texel.b * (1 - clamp(2 * customParams.r, 0, 1));
|
||||
float oColor = texel.g * (1 - clamp(2 * customParams.r - 1, 0, 1));
|
||||
float oWhite = texel.b * (1 - clamp(2 * (1 - customParams.r), 0, 1));
|
||||
float oColor = texel.g * (1 - clamp(2 * (1 - customParams.r) - 1, 0, 1));
|
||||
float o = clamp(oWhite + oColor, 0, 1);
|
||||
vec4 col = (texel.g * color + vec4(texel.b)) * o;
|
||||
col.a *= o;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#version 330 core
|
||||
|
||||
#include "lib/sprite_main.frag.glslh"
|
||||
|
||||
void spriteMain(out vec4 fragColor) {
|
||||
fragColor = color * texture(tex, texCoord) * customParams.r;
|
||||
}
|
1
resources/00-taisei.pkgdir/shader/sprite_particle.prog
Normal file
1
resources/00-taisei.pkgdir/shader/sprite_particle.prog
Normal file
|
@ -0,0 +1 @@
|
|||
objects = sprite_bullet.vert sprite_particle.frag
|
|
@ -1,24 +0,0 @@
|
|||
#version 330 core
|
||||
|
||||
#include "lib/sprite_main.frag.glslh"
|
||||
|
||||
/*
|
||||
ported from:
|
||||
|
||||
.R[1] = mix_colors(c_b, c_r, sqrt(charge)),
|
||||
.G[1] = c_g,
|
||||
.B[1] = mix_colors(multiply_colors(c_r, rgba(2, 0, 0, 0)), c_b, 0.75 * charge),
|
||||
.A[1] = c_a,
|
||||
*/
|
||||
|
||||
void spriteMain(out vec4 fragColor) {
|
||||
vec4 texel = texture(tex, texCoord);
|
||||
float charge = customParams.r;
|
||||
|
||||
fragColor = vec4(0.0);
|
||||
fragColor.rgb += texel.r * mix(vec3(color.r, 0.0, 0.0), vec3(0.0, 0.0, color.b), sqrt(charge));
|
||||
fragColor.g += texel.g * color.g;
|
||||
fragColor.rgb += texel.b * mix(vec3(0.0, 0.0, color.b), vec3(2.0 * color.r, 0.0, 0.0), 0.75 * charge);
|
||||
fragColor.a = texel.a * color.a;
|
||||
fragColor *= customParams.g;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
objects = sprite_youmu_charged_shot.vert sprite_youmu_charged_shot.frag
|
|
@ -1,7 +0,0 @@
|
|||
#version 330 core
|
||||
|
||||
#define SPRITE_OUT_COLOR
|
||||
#define SPRITE_OUT_TEXCOORD
|
||||
#define SPRITE_OUT_CUSTOM
|
||||
|
||||
#include "lib/sprite_default.vert.glslh"
|
|
@ -9,5 +9,5 @@ void spriteMain(out vec4 fragColor) {
|
|||
fragColor.rgb += vec3(texel.r);
|
||||
fragColor.rgb += texel.b * vec3(color.r*color.r, color.g*color.g, color.b*color.b);
|
||||
fragColor.a = texel.a * color.a;
|
||||
fragColor *= (1 - customParams.r);
|
||||
fragColor *= customParams.r;
|
||||
}
|
||||
|
|
18
src/boss.c
18
src/boss.c
|
@ -578,7 +578,8 @@ static void draw_spell_portrait(Boss *b, int time) {
|
|||
r_state_pop();
|
||||
}
|
||||
|
||||
static void BossGlow(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void BossGlow(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
float s = 1.0+t/(double)p->timeout*0.5;
|
||||
float fade = 1 - (1.5 - s);
|
||||
float deform = 5 - 10 * fade * fade;
|
||||
|
@ -632,7 +633,7 @@ static void spawn_particle_effects(Boss *boss) {
|
|||
if(!(global.frames % 13) && !is_extra) {
|
||||
PARTICLE(
|
||||
.sprite = "smoke",
|
||||
.pos = cexp(I*global.frames),
|
||||
.pos = cdir(global.frames),
|
||||
.color = RGBA(shadowcolor->r, shadowcolor->g, shadowcolor->b, 0.0),
|
||||
.rule = enemy_flare,
|
||||
.timeout = 180,
|
||||
|
@ -1120,7 +1121,7 @@ void process_boss(Boss **pboss) {
|
|||
|
||||
if(dying) {
|
||||
float t = (global.frames - boss->current->endtime)/(float)BOSS_DEATH_DELAY + 1;
|
||||
RNG_ARRAY(rng, 6);
|
||||
RNG_ARRAY(rng, 2);
|
||||
|
||||
Color *clr = RGBA_MUL_ALPHA(0.1 + sin(10*t), 0.1 + cos(10*t), 0.5, t);
|
||||
clr->a = 0;
|
||||
|
@ -1129,13 +1130,11 @@ void process_boss(Boss **pboss) {
|
|||
.sprite = "petal",
|
||||
.pos = boss->pos,
|
||||
.rule = asymptotic,
|
||||
.draw_rule = Petal,
|
||||
.draw_rule = pdraw_petal_random(),
|
||||
.color = clr,
|
||||
.args = {
|
||||
vrng_sign(rng[5]) * (3 + t * 5 * vrng_real(rng[0])) * cdir(M_PI*8*t),
|
||||
vrng_sign(rng[0]) * (3 + t * 5 * vrng_real(rng[1])) * cdir(M_PI*8*t),
|
||||
5+I,
|
||||
vrng_real(rng[2]) + vrng_real(rng[3])*I,
|
||||
vrng_real(rng[4]) + 360.0*I*vrng_real(rng[1])
|
||||
},
|
||||
.layer = LAYER_PARTICLE_PETAL,
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
|
@ -1254,7 +1253,8 @@ void boss_reset_motion(Boss *boss) {
|
|||
boss->move.retention = 0.8;
|
||||
}
|
||||
|
||||
static void boss_death_effect_draw_overlay(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void boss_death_effect_draw_overlay(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
FBPair *framebuffers = stage_get_fbpair(FBPAIR_FG);
|
||||
r_framebuffer(framebuffers->front);
|
||||
r_uniform_sampler("noise_tex", "static");
|
||||
|
@ -1361,7 +1361,7 @@ void boss_start_attack(Boss *b, Attack *a) {
|
|||
.color = RGBA(0.2, 0.3, 0.4, 0.0),
|
||||
.rule = linear,
|
||||
.timeout = 50,
|
||||
.draw_rule = GrowFade,
|
||||
.draw_rule = pdraw_timeout_scalefade(0, 1, 1, 0),
|
||||
.args = { vrng_sign(rng[2]) * 10 * vrng_range(rng[3], 1, 4) },
|
||||
);
|
||||
}
|
||||
|
|
|
@ -34,11 +34,6 @@ enum {
|
|||
COTASK_WAIT_EVENT,
|
||||
};
|
||||
|
||||
typedef struct CoEventSnapshot {
|
||||
uint32_t unique_id;
|
||||
uint16_t num_signaled;
|
||||
} CoEventSnapshot;
|
||||
|
||||
struct CoTask {
|
||||
LIST_INTERFACE(CoTask);
|
||||
koishi_coroutine_t ko;
|
||||
|
@ -237,11 +232,18 @@ static void *cotask_wake_and_resume(CoTask *task, void *arg) {
|
|||
return cotask_force_resume(task, arg);
|
||||
}
|
||||
|
||||
static CoEventStatus coevent_poll(const CoEvent *evt, const CoEventSnapshot *snap) {
|
||||
CoEventSnapshot coevent_snapshot(const CoEvent *evt) {
|
||||
return (CoEventSnapshot) {
|
||||
.unique_id = evt->unique_id,
|
||||
.num_signaled = evt->num_signaled,
|
||||
};
|
||||
}
|
||||
|
||||
CoEventStatus coevent_poll(const CoEvent *evt, const CoEventSnapshot *snap) {
|
||||
EVT_DEBUG("[%p]", (void*)evt);
|
||||
EVT_DEBUG("evt->unique_id == %u", evt->unique_id);
|
||||
EVT_DEBUG("evt->unique_id == %u", evt->unique_id);
|
||||
EVT_DEBUG("snap->unique_id == %u", snap->unique_id);
|
||||
EVT_DEBUG("evt->num_signaled == %u", evt->num_signaled);
|
||||
EVT_DEBUG("evt->num_signaled == %u", evt->num_signaled);
|
||||
EVT_DEBUG("snap->num_signaled == %u", snap->num_signaled);
|
||||
|
||||
if(
|
||||
|
@ -351,13 +353,6 @@ int cotask_wait(int delay) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline CoEventSnapshot coevent_snapshot(CoEvent *evt) {
|
||||
return (CoEventSnapshot) {
|
||||
.unique_id = evt->unique_id,
|
||||
.num_signaled = evt->num_signaled,
|
||||
};
|
||||
}
|
||||
|
||||
static void coevent_add_subscriber(CoEvent *evt, CoTask *task) {
|
||||
evt->num_subscribers++;
|
||||
assert(evt->num_subscribers != 0);
|
||||
|
|
|
@ -53,6 +53,11 @@ typedef struct CoEvent {
|
|||
uint8_t num_subscribers_allocated;
|
||||
} CoEvent;
|
||||
|
||||
typedef struct CoEventSnapshot {
|
||||
uint32_t unique_id;
|
||||
uint16_t num_signaled;
|
||||
} CoEventSnapshot;
|
||||
|
||||
struct CoSched {
|
||||
LIST_ANCHOR(CoTask) tasks, pending_tasks;
|
||||
};
|
||||
|
@ -99,6 +104,8 @@ void coevent_init(CoEvent *evt);
|
|||
void coevent_signal(CoEvent *evt);
|
||||
void coevent_signal_once(CoEvent *evt);
|
||||
void coevent_cancel(CoEvent *evt);
|
||||
CoEventSnapshot coevent_snapshot(const CoEvent *evt);
|
||||
CoEventStatus coevent_poll(const CoEvent *evt, const CoEventSnapshot *snap);
|
||||
|
||||
void _coevent_array_action(uint num, CoEvent *events, void (*func)(CoEvent*));
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
LAYER(NODRAW)
|
||||
LAYER(BACKGROUND)
|
||||
LAYER(PLAYER_SHOT)
|
||||
LAYER(PARTICLE_LOW)
|
||||
|
|
58
src/enemy.c
58
src/enemy.c
|
@ -115,27 +115,50 @@ Enemy *create_enemy_p(EnemyList *enemies, cmplx pos, float hp, EnemyVisualRule v
|
|||
return e;
|
||||
}
|
||||
|
||||
static void enemy_death_effect(cmplx pos) {
|
||||
for(int i = 0; i < 10; i++) {
|
||||
RNG_ARRAY(rng, 2);
|
||||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.pos = pos,
|
||||
.timeout = 10,
|
||||
.rule = linear,
|
||||
.draw_rule = pdraw_timeout_fade(1, 0),
|
||||
.args = { vrng_range(rng[0], 3, 13) * vrng_dir(rng[1]) },
|
||||
);
|
||||
}
|
||||
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = pos,
|
||||
.timeout = 20,
|
||||
.draw_rule = pdraw_blast(),
|
||||
.flags = PFLAG_REQUIREDPARTICLE
|
||||
);
|
||||
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = pos,
|
||||
.timeout = 20,
|
||||
.draw_rule = pdraw_blast(),
|
||||
.flags = PFLAG_REQUIREDPARTICLE
|
||||
);
|
||||
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = pos,
|
||||
.timeout = 15,
|
||||
.draw_rule = pdraw_timeout_scalefade(0, rng_f32_range(1, 2), 1, 0),
|
||||
.flags = PFLAG_REQUIREDPARTICLE
|
||||
);
|
||||
}
|
||||
|
||||
static void* _delete_enemy(ListAnchor *enemies, List* enemy, void *arg) {
|
||||
Enemy *e = (Enemy*)enemy;
|
||||
|
||||
if(e->hp <= 0 && e->hp != ENEMY_IMMUNE && e->hp != ENEMY_BOMB) {
|
||||
play_sound("enemydeath");
|
||||
|
||||
for(int i = 0; i < 10; i++) {
|
||||
RNG_ARRAY(rng, 2);
|
||||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.pos = e->pos,
|
||||
.timeout = 10,
|
||||
.rule = linear,
|
||||
.draw_rule = Fade,
|
||||
.args = { vrng_range(rng[0], 3, 13) * vrng_dir(rng[1]) },
|
||||
);
|
||||
}
|
||||
|
||||
PARTICLE(.proto = pp_blast, .pos = e->pos, .timeout = 20, .draw_rule = Blast, .flags = PFLAG_REQUIREDPARTICLE);
|
||||
PARTICLE(.proto = pp_blast, .pos = e->pos, .timeout = 20, .draw_rule = Blast, .flags = PFLAG_REQUIREDPARTICLE);
|
||||
PARTICLE(.proto = pp_blast, .pos = e->pos, .timeout = 15, .draw_rule = GrowFade, .flags = PFLAG_REQUIREDPARTICLE);
|
||||
enemy_death_effect(e->pos);
|
||||
|
||||
for(Projectile *p = global.projs.first; p; p = p->next) {
|
||||
if(p->type == PROJ_ENEMY && !(p->flags & PFLAG_NOCOLLISION) && cabs(p->pos - e->pos) < 64) {
|
||||
|
@ -242,7 +265,8 @@ void BigFairy(Enemy *e, int t, bool render) {
|
|||
.pos = offset,
|
||||
.color = RGBA(0.0, 0.2, 0.3, 0.0),
|
||||
.rule = enemy_flare,
|
||||
.draw_rule = Shrink,
|
||||
.draw_rule = pdraw_timeout_scalefade(2+2*I, 0.5+2*I, 1, 0),
|
||||
.angle = M_PI/2,
|
||||
.timeout = 50,
|
||||
.args = { (-50.0*I-offset)/50.0, add_ref(e) },
|
||||
);
|
||||
|
|
|
@ -129,6 +129,10 @@ static int ent_cmp(const void *ptr1, const void *ptr2) {
|
|||
return r;
|
||||
}
|
||||
|
||||
static inline bool ent_is_drawable(EntityInterface *ent) {
|
||||
return (ent->draw_layer & ~LAYER_LOW_MASK) > LAYER_NODRAW && ent->draw_func;
|
||||
}
|
||||
|
||||
void ent_draw(EntityPredicate predicate) {
|
||||
call_hooks(&entities.hooks.pre_draw, NULL);
|
||||
qsort(entities.array, entities.num, sizeof(EntityInterface*), ent_cmp);
|
||||
|
@ -138,7 +142,7 @@ void ent_draw(EntityPredicate predicate) {
|
|||
ent->index = _ent - entities.array;
|
||||
assert(entities.array[ent->index] == ent);
|
||||
|
||||
if(ent->draw_func && predicate(ent)) {
|
||||
if(ent_is_drawable(ent) && predicate(ent)) {
|
||||
call_hooks(&entities.hooks.pre_draw, ent);
|
||||
r_state_push();
|
||||
ent->draw_func(ent);
|
||||
|
@ -151,7 +155,7 @@ void ent_draw(EntityPredicate predicate) {
|
|||
ent->index = _ent - entities.array;
|
||||
assert(entities.array[ent->index] == ent);
|
||||
|
||||
if(ent->draw_func) {
|
||||
if(ent_is_drawable(ent)) {
|
||||
call_hooks(&entities.hooks.pre_draw, ent);
|
||||
r_state_push();
|
||||
ent->draw_func(ent);
|
||||
|
|
11
src/entity.h
11
src/entity.h
|
@ -274,6 +274,17 @@ INLINE void _ent_array_add_Entity(struct EntityInterface *ent, BoxedEntityArray
|
|||
} \
|
||||
} while(0)
|
||||
|
||||
#define ENT_ARRAY_FOREACH_COUNTER(_array, _cntr_var, _ent_var, _block) do { \
|
||||
for(uint MACROHAX_ADDLINENUM(_ent_array_iterator) = 0; MACROHAX_ADDLINENUM(_ent_array_iterator) < (_array)->size; ++MACROHAX_ADDLINENUM(_ent_array_iterator)) { \
|
||||
void *MACROHAX_ADDLINENUM(_ent_array_temp) = ENT_ARRAY_GET((_array), MACROHAX_ADDLINENUM(_ent_array_iterator)); \
|
||||
if(MACROHAX_ADDLINENUM(_ent_array_temp) != NULL) { \
|
||||
_cntr_var = MACROHAX_ADDLINENUM(_ent_array_iterator); \
|
||||
_ent_var = MACROHAX_ADDLINENUM(_ent_array_temp); \
|
||||
_block \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define ENT_ARRAY_CLEAR(_array) ((_array)->size = 0)
|
||||
|
||||
#endif // IGUARD_entity_h
|
||||
|
|
14
src/player.c
14
src/player.c
|
@ -431,7 +431,8 @@ static void _powersurge_trail_draw(Projectile *p, float t, float cmul) {
|
|||
});
|
||||
}
|
||||
|
||||
static void powersurge_trail_draw(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void powersurge_trail_draw(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
if(t > 0) {
|
||||
_powersurge_trail_draw(p, t - 0.5, 0.25);
|
||||
_powersurge_trail_draw(p, t, 0.25);
|
||||
|
@ -709,7 +710,8 @@ static int powersurge_discharge(Projectile *p, int t) {
|
|||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
static void powersurge_distortion_draw(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void powersurge_distortion_draw(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
if(config_get_int(CONFIG_POSTPROCESS) < 1) {
|
||||
return;
|
||||
}
|
||||
|
@ -774,7 +776,7 @@ static void player_powersurge_expired(Player *plr) {
|
|||
PROJECTILE(
|
||||
.pos = plr->pos,
|
||||
.size = 1+I,
|
||||
.draw_rule = ProjNoDraw,
|
||||
.layer = LAYER_NODRAW,
|
||||
.timeout = 10,
|
||||
.type = PROJ_PLAYER,
|
||||
.rule = powersurge_discharge,
|
||||
|
@ -849,7 +851,8 @@ void player_realdeath(Player *plr) {
|
|||
plr->lives--;
|
||||
}
|
||||
|
||||
static void player_death_effect_draw_overlay(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void player_death_effect_draw_overlay(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
FBPair *framebuffers = stage_get_fbpair(FBPAIR_FG);
|
||||
r_framebuffer(framebuffers->front);
|
||||
r_uniform_sampler("noise_tex", "static");
|
||||
|
@ -868,7 +871,8 @@ static void player_death_effect_draw_overlay(Projectile *p, int t) {
|
|||
r_state_push();
|
||||
}
|
||||
|
||||
static void player_death_effect_draw_sprite(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void player_death_effect_draw_sprite(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
float s = t / p->timeout;
|
||||
|
||||
float stretch_range = 3, sx, sy;
|
||||
|
|
|
@ -315,7 +315,8 @@ static int marisa_laser_renderer(Enemy *renderer, int t) {
|
|||
#undef FOR_EACH_SLAVE
|
||||
#undef FOR_EACH_REAL_SLAVE
|
||||
|
||||
static void marisa_laser_flash_draw(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void marisa_laser_flash_draw(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
Animation *fire = get_ani("fire");
|
||||
AniSequence *seq = get_ani_sequence(fire, "main");
|
||||
Sprite *spr = animation_get_frame(fire, seq, p->birthtime);
|
||||
|
|
|
@ -77,15 +77,6 @@ static int reimu_spirit_needle(Projectile *p, int t) {
|
|||
|
||||
#define REIMU_SPIRIT_HOMING_SCALE 0.75
|
||||
|
||||
static void reimu_spirit_homing_draw(Projectile *p, int t) {
|
||||
r_mat_mv_push();
|
||||
r_mat_mv_translate(creal(p->pos), cimag(p->pos), 0);
|
||||
r_mat_mv_rotate(p->angle + M_PI/2, 0, 0, 1);
|
||||
r_mat_mv_scale(REIMU_SPIRIT_HOMING_SCALE, REIMU_SPIRIT_HOMING_SCALE, 1);
|
||||
ProjDrawCore(p, &p->color);
|
||||
r_mat_mv_pop();
|
||||
}
|
||||
|
||||
static Projectile* reimu_spirit_spawn_ofuda_particle(Projectile *p, int t, double vfactor) {
|
||||
Color *c = HSLA_MUL_ALPHA(t * 0.1, 0.6, 0.7, 0.3);
|
||||
c->a = 0;
|
||||
|
@ -173,24 +164,6 @@ static Color *reimu_spirit_orb_color(Color *c, int i) {
|
|||
return c;
|
||||
}
|
||||
|
||||
static void reimu_spirit_bomb_orb_visual(Projectile *p, int t) {
|
||||
cmplx pos = p->pos;
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
cmplx offset = (10 + pow(t, 0.5)) * cexp(I * (2 * M_PI / 3*i + sqrt(1 + t * t / 300.0)));
|
||||
|
||||
Color c;
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite_ptr = p->sprite,
|
||||
.shader_ptr = p->shader,
|
||||
.pos = { creal(pos+offset), cimag(pos+offset) },
|
||||
.color = reimu_spirit_orb_color(&c, i),
|
||||
|
||||
// .shader_params = &(ShaderCustomParams) {.vector = {0.3,0,0,0}},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static int reimu_spirit_bomb_orb_trail(Projectile *p, int t) {
|
||||
if(t < 0) {
|
||||
return ACTION_ACK;
|
||||
|
@ -204,162 +177,219 @@ static int reimu_spirit_bomb_orb_trail(Projectile *p, int t) {
|
|||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
static void reimu_spirit_bomb_orb_draw_impact(Projectile *p, int t) {
|
||||
float attack = min(1, (7 + 5 * p->args[0]) * t / p->timeout);
|
||||
float decay = t / p->timeout;
|
||||
static void reimu_spirit_bomb_impact_balls(cmplx pos, int count) {
|
||||
real offset = rng_real();
|
||||
|
||||
Color c = p->color;
|
||||
color_lerp(&c, RGBA(0.2, 0.1, 0, 1.0), decay);
|
||||
color_mul_scalar(&c, pow(1 - decay, 2) * 0.75);
|
||||
for(int i = 0; i < count; i++) {
|
||||
PARTICLE(
|
||||
.sprite_ptr = get_sprite("proj/glowball"),
|
||||
.shader = "sprite_bullet",
|
||||
.color = HSLA(3 * (float)i / count + offset, 1, 0.5, 0),
|
||||
.timeout = 60,
|
||||
.pos = pos,
|
||||
.args = { cdir(2 * M_PI / count * (i + offset)) * 15 },
|
||||
.angle = rng_angle(),
|
||||
.rule = linear,
|
||||
.draw_rule = Fade,
|
||||
.layer = LAYER_BOSS,
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite_ptr = p->sprite,
|
||||
.pos = { creal(p->pos), cimag(p->pos) },
|
||||
.color = &c,
|
||||
.shader_ptr = p->shader,
|
||||
.shader_params = &p->shader_params,
|
||||
.scale.both = (0.75 + 0.25 / (pow(decay, 3.0) + 1.0)) + sqrt(5 * (1 - attack)),
|
||||
TASK(reimu_spirit_bomb_orb_impact, { BoxedProjectile orb; }) {
|
||||
cmplx pos = ENT_UNBOX(ARGS.orb)->pos;
|
||||
|
||||
play_sound("boom");
|
||||
play_sound("spellend");
|
||||
|
||||
global.shake_view = 20;
|
||||
global.shake_view_fade = 0.6;
|
||||
|
||||
double damage = 2000;
|
||||
double range = 300;
|
||||
|
||||
ent_area_damage(pos, range, &(DamageInfo){damage, DMG_PLAYER_BOMB}, NULL, NULL);
|
||||
stage_clear_hazards_at(pos, range, CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_NOW);
|
||||
|
||||
reimu_spirit_bomb_impact_balls(pos, 21);
|
||||
|
||||
int num_impacts = 3;
|
||||
int t = global.frames;
|
||||
BoxedProjectileArray impact_effects = ENT_ARRAY(Projectile, 3);
|
||||
RNG_ARRAY(rand, num_impacts);
|
||||
Color base_colors[3];
|
||||
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
base_colors[i] = *reimu_spirit_orb_color(&(Color){0}, i);
|
||||
|
||||
PARTICLE(
|
||||
.sprite = "blast",
|
||||
.color = color_mul_scalar(COLOR_COPY(&base_colors[i]), 2),
|
||||
.pos = pos + 30 * cexp(I*2*M_PI/num_impacts*(i+t*0.1)),
|
||||
.timeout = 40,
|
||||
.draw_rule = ScaleFade,
|
||||
.layer = LAYER_BOSS + 2,
|
||||
.args = { 0, 0, 7.5*I },
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
);
|
||||
|
||||
ENT_ARRAY_ADD(&impact_effects, PARTICLE(
|
||||
.sprite = "fantasyseal_impact",
|
||||
.color = reimu_spirit_orb_color(&(Color){0}, i),
|
||||
.pos = pos + 2 * cexp(I*2*M_PI/num_impacts*(i+t*0.1)),
|
||||
.timeout = 120,
|
||||
.layer = LAYER_BOSS + 1,
|
||||
.angle = -M_PI/2,
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
));
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
int live = 0;
|
||||
|
||||
ENT_ARRAY_FOREACH_COUNTER(&impact_effects, int i, Projectile *p, {
|
||||
float t = (global.frames - p->birthtime) / p->timeout;
|
||||
float attack = min(1, vrng_range(rand[i], 7, 12) * t);
|
||||
float decay = t;
|
||||
|
||||
Color c = base_colors[i];
|
||||
color_lerp(&c, RGBA(0.2, 0.1, 0, 1.0), decay);
|
||||
color_mul_scalar(&c, powf(1.0f - decay, 2.0f) * 0.75f);
|
||||
p->color = c;
|
||||
p->scale = (0.75f + 0.25f / (powf(decay, 3.0f) + 1.0f)) + sqrtf(5.0f * (1.0f - attack));
|
||||
|
||||
++live;
|
||||
});
|
||||
|
||||
if(!live) {
|
||||
break;
|
||||
}
|
||||
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
TASK(reimu_spirit_bomb_orb_visual_kill, { BoxedProjectileArray components; }) {
|
||||
ENT_ARRAY_FOREACH(&ARGS.components, Projectile *p, {
|
||||
kill_projectile(p);
|
||||
});
|
||||
}
|
||||
|
||||
static int reimu_spirit_bomb_orb(Projectile *p, int t) {
|
||||
int index = creal(p->args[1]) + 0.5;
|
||||
TASK(reimu_spirit_bomb_orb_visual, { BoxedProjectile orb; }) {
|
||||
Projectile *orb = TASK_BIND(ARGS.orb);
|
||||
DECLARE_ENT_ARRAY(Projectile, components, 3);
|
||||
|
||||
if(t == EVENT_BIRTH) {
|
||||
if(index == 0)
|
||||
global.shake_view = 4;
|
||||
p->args[3] = global.plr.pos;
|
||||
return ACTION_ACK;
|
||||
Sprite *glowball = get_sprite("proj/glowball");
|
||||
ShaderProgram *shader = r_shader_get("sprite_bullet");
|
||||
|
||||
for(int i = 0; i < components.capacity; ++i) {
|
||||
ENT_ARRAY_ADD(&components, PARTICLE(
|
||||
.sprite_ptr = glowball,
|
||||
.shader_ptr = shader,
|
||||
.color = reimu_spirit_orb_color(&(Color){0}, i),
|
||||
.opacity = 0.7,
|
||||
.layer = LAYER_PLAYER_FOCUS - 1,
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
));
|
||||
}
|
||||
|
||||
if(t == EVENT_DEATH) {
|
||||
if(global.gameover > 0) {
|
||||
return ACTION_ACK;
|
||||
INVOKE_TASK_AFTER(&orb->events.killed, reimu_spirit_bomb_orb_visual_kill, components);
|
||||
CANCEL_TASK_AFTER(&orb->events.killed, THIS_TASK);
|
||||
|
||||
for(;;) {
|
||||
cmplx pos = orb->pos;
|
||||
|
||||
ENT_ARRAY_FOREACH_COUNTER(&components, int i, Projectile *p, {
|
||||
real t = global.frames - p->birthtime;
|
||||
cmplx32 offset = (10 + pow(t, 0.5)) * cdir(2.0 * M_PI / 3*i + sqrt(1 + t * t / 300));
|
||||
p->pos = pos + offset;
|
||||
});
|
||||
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
TASK(reimu_spirit_bomb_orb, { BoxedPlayer plr; int index; real angle; }) {
|
||||
int index = ARGS.index;
|
||||
|
||||
Player *plr = ENT_UNBOX(ARGS.plr);
|
||||
Projectile *orb = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
.pos = plr->pos,
|
||||
.timeout = 200 + 20 * index,
|
||||
.type = PROJ_PLAYER,
|
||||
.damage = 1000,
|
||||
.damage_type = DMG_PLAYER_BOMB,
|
||||
.size = 10 * (1+I),
|
||||
.layer = LAYER_NODRAW,
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_NOCOLLISION | PFLAG_NOMOVE | PFLAG_MANUALANGLE,
|
||||
));
|
||||
|
||||
BoxedProjectile b_orb = ENT_BOX(orb);
|
||||
|
||||
INVOKE_TASK(reimu_spirit_bomb_orb_visual, b_orb);
|
||||
INVOKE_TASK_WHEN(&orb->events.killed, reimu_spirit_bomb_orb_impact, b_orb);
|
||||
CANCEL_TASK_AFTER(&orb->events.killed, THIS_TASK);
|
||||
|
||||
int circletime = 100 + 20 * index;
|
||||
cmplx target_homing = plr->pos;
|
||||
cmplx dir = cdir(ARGS.angle);
|
||||
cmplx vel = 0;
|
||||
|
||||
for(int t = 0;; ++t) {
|
||||
if(!player_is_bomb_active(plr)) {
|
||||
kill_projectile(orb);
|
||||
return;
|
||||
}
|
||||
|
||||
global.shake_view = 20;
|
||||
global.shake_view_fade = 0.6;
|
||||
if(t == circletime) {
|
||||
target_homing = global.plr.pos - 256*I;
|
||||
orb->flags &= ~PFLAG_NOCOLLISION;
|
||||
play_sound("redirect");
|
||||
}
|
||||
|
||||
double damage = 2000;
|
||||
double range = 300;
|
||||
cmplx target_circle = plr->pos + 10 * sqrt(t) * dir * (1 + 0.1 * sin(0.2 * t));
|
||||
dir *= cdir(0.12);
|
||||
|
||||
ent_area_damage(p->pos, range, &(DamageInfo){damage, DMG_PLAYER_BOMB}, NULL, NULL);
|
||||
stage_clear_hazards_at(p->pos, range, CLEAR_HAZARDS_ALL | CLEAR_HAZARDS_NOW);
|
||||
double circlestrength = 1.0 / (1 + exp(t - circletime));
|
||||
|
||||
int count = 21;
|
||||
real offset = rng_real();
|
||||
target_homing = plrutil_homing_target(orb->pos, target_homing);
|
||||
cmplx homing = target_homing - orb->pos;
|
||||
cmplx v = 0.3 * (circlestrength * (target_circle - orb->pos) + 0.2 * (1 - circlestrength) * (homing + 2*homing/(cabs(homing)+0.01)));
|
||||
vel += (v - vel) * 0.1;
|
||||
orb->pos += vel;
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
cmplx trail_pos = orb->pos + 10 * cdir(2*M_PI/3*(i+t*0.1));
|
||||
cmplx trail_vel = global.plr.pos - trail_pos;
|
||||
trail_vel *= 3 * circlestrength / cabs(trail_vel);
|
||||
|
||||
for(int i = 0; i < count; i++) {
|
||||
PARTICLE(
|
||||
.sprite_ptr = get_sprite("proj/glowball"),
|
||||
.shader = "sprite_bullet",
|
||||
.color = HSLA(3 * (float)i / count + offset, 1, 0.5, 0),
|
||||
.timeout = 60,
|
||||
.pos = p->pos,
|
||||
.args = { cdir(2 * M_PI / count * (i + offset)) * 15 },
|
||||
.sprite_ptr = get_sprite("part/stain"),
|
||||
// .color = reimu_spirit_orb_color(&(Color){0}, i),
|
||||
.color = HSLA(t/orb->timeout, 0.3, 0.3, 0.0),
|
||||
.pos = trail_pos,
|
||||
.angle = rng_angle(),
|
||||
.rule = linear,
|
||||
.draw_rule = Fade,
|
||||
.layer = LAYER_BOSS,
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
PARTICLE(
|
||||
.sprite = "blast",
|
||||
.color = color_mul_scalar(reimu_spirit_orb_color(&(Color){0}, i), 2),
|
||||
.pos = p->pos + 30 * cexp(I*2*M_PI/3*(i+t*0.1)),
|
||||
.timeout = 40,
|
||||
.timeout = 30,
|
||||
.draw_rule = ScaleFade,
|
||||
.layer = LAYER_BOSS + 2,
|
||||
.args = { 0, 0, 7.5*I },
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
);
|
||||
|
||||
PARTICLE(
|
||||
.sprite = "fantasyseal_impact",
|
||||
.color = reimu_spirit_orb_color(&(Color){0}, i),
|
||||
.pos = p->pos + 2 * cexp(I*2*M_PI/3*(i+t*0.1)),
|
||||
.timeout = 120,
|
||||
.draw_rule = reimu_spirit_bomb_orb_draw_impact,
|
||||
.layer = LAYER_BOSS + 1,
|
||||
.args = { rng_real() },
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
.rule = reimu_spirit_bomb_orb_trail,
|
||||
.args = { trail_vel, 0, 0.4 },
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
);
|
||||
}
|
||||
|
||||
play_sound("boom");
|
||||
play_sound("spellend");
|
||||
|
||||
return ACTION_ACK;
|
||||
YIELD;
|
||||
}
|
||||
|
||||
if(!player_is_bomb_active(&global.plr) > 0) {
|
||||
return ACTION_DESTROY;
|
||||
}
|
||||
|
||||
double circletime = 100+20*index;
|
||||
|
||||
if(t == circletime) {
|
||||
p->args[3] = global.plr.pos - 256*I;
|
||||
p->flags &= ~PFLAG_NOCOLLISION;
|
||||
play_sound("redirect");
|
||||
}
|
||||
|
||||
cmplx target_circle = global.plr.pos + 10 * sqrt(t) * p->args[0]*(1 + 0.1 * sin(0.2*t));
|
||||
p->args[0] *= cexp(I*0.12);
|
||||
|
||||
double circlestrength = 1.0 / (1 + exp(t-circletime));
|
||||
|
||||
p->args[3] = plrutil_homing_target(p->pos, p->args[3]);
|
||||
cmplx target_homing = p->args[3];
|
||||
cmplx homing = target_homing - p->pos;
|
||||
cmplx v = 0.3 * (circlestrength * (target_circle - p->pos) + 0.2 * (1-circlestrength) * (homing + 2*homing/(cabs(homing)+0.01)));
|
||||
p->args[2] += (v - p->args[2]) * 0.1;
|
||||
p->pos += p->args[2];
|
||||
|
||||
for(int i = 0; i < 3 /*&& circlestrength < 1*/; i++) {
|
||||
cmplx trail_pos = p->pos + 10 * cexp(I*2*M_PI/3*(i+t*0.1));
|
||||
cmplx trail_vel = global.plr.pos - trail_pos;
|
||||
trail_vel *= 3 * circlestrength / cabs(trail_vel);
|
||||
|
||||
PARTICLE(
|
||||
.sprite_ptr = get_sprite("part/stain"),
|
||||
// .color = reimu_spirit_orb_color(&(Color){0}, i),
|
||||
.color = HSLA(t/p->timeout, 0.3, 0.3, 0.0),
|
||||
.pos = trail_pos,
|
||||
.angle = rng_angle(),
|
||||
.timeout = 30,
|
||||
.draw_rule = ScaleFade,
|
||||
.rule = reimu_spirit_bomb_orb_trail,
|
||||
.args = { trail_vel, 0, 0.4 },
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
);
|
||||
}
|
||||
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
static void reimu_spirit_bomb(Player *p) {
|
||||
int count = 6;
|
||||
|
||||
for(int i = 0; i < count; i++) {
|
||||
PROJECTILE(
|
||||
.sprite = "glowball",
|
||||
.pos = p->pos,
|
||||
.draw_rule = reimu_spirit_bomb_orb_visual,
|
||||
.rule = reimu_spirit_bomb_orb,
|
||||
.args = { cexp(I*2*M_PI/count*i), i, 0, 0},
|
||||
.timeout = 200 + 20 * i,
|
||||
.type = PROJ_PLAYER,
|
||||
.damage = 1000,
|
||||
.size = 10 + 10*I,
|
||||
.layer = LAYER_PLAYER_FOCUS - 1,
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_NOCOLLISION,
|
||||
);
|
||||
INVOKE_TASK_DELAYED(1, reimu_spirit_bomb_orb, ENT_BOX(p), i, 2*M_PI/count*i);
|
||||
}
|
||||
|
||||
global.shake_view = 4;
|
||||
play_sound("bomb_reimu_a");
|
||||
play_sound("bomb_marisa_b");
|
||||
}
|
||||
|
@ -446,13 +476,13 @@ static void reimu_spirit_slave_shot(Enemy *e, int t) {
|
|||
.pos = e->pos,
|
||||
.color = RGBA_MUL_ALPHA(1, 0.9, 0.95, 0.7),
|
||||
.rule = reimu_spirit_homing,
|
||||
.draw_rule = reimu_spirit_homing_draw,
|
||||
.args = { v , 60, 0, e->pos + v * VIEWPORT_H * VIEWPORT_W /*creal(e->pos)*/ },
|
||||
.type = PROJ_PLAYER,
|
||||
.damage_type = DMG_PLAYER_SHOT,
|
||||
.damage = creal(e->args[2]),
|
||||
// .timeout = 60,
|
||||
.shader = "sprite_default",
|
||||
.scale = REIMU_SPIRIT_HOMING_SCALE,
|
||||
.flags = PFLAG_NOCOLLISIONEFFECT,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -108,12 +108,12 @@ static int reimu_dream_gap_bomb_projectile(Projectile *p, int t) {
|
|||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
static void reimu_dream_gap_bomb_projectile_draw(Projectile *p, int t) {
|
||||
static void reimu_dream_gap_bomb_projectile_draw(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite_ptr = p->sprite,
|
||||
.shader_ptr = p->shader,
|
||||
.color = &p->color,
|
||||
.shader_params = &p->shader_params,
|
||||
.shader_params = &(ShaderCustomParams) {{ p->opacity }},
|
||||
.pos = { creal(p->pos), cimag(p->pos) },
|
||||
.scale.both = 0.75 * clamp(t / 5.0, 0.1, 1.0),
|
||||
});
|
||||
|
@ -341,10 +341,11 @@ static void reimu_dream_spawn_warp_effect(cmplx pos, bool exit) {
|
|||
.layer = LAYER_PLAYER_FOCUS,
|
||||
);
|
||||
|
||||
Color *clr = color_mul_scalar(RGBA(0.75, rng_range(0, 0.4), 0.4, 0), 0.8-0.4*exit);
|
||||
PARTICLE(
|
||||
.sprite = exit ? "stain" : "stardust",
|
||||
.pos = pos,
|
||||
.color = color_mul_scalar(RGBA(0.75, rng_range(0, 0.4), 0.4, 0), 0.8-0.4*exit),
|
||||
.color = clr,
|
||||
.timeout = 20,
|
||||
.angle = rng_angle(),
|
||||
.draw_rule = ScaleFade,
|
||||
|
|
|
@ -56,7 +56,8 @@ static int myon_flare_particle_rule(Projectile *p, int t) {
|
|||
return r;
|
||||
}
|
||||
|
||||
static void myon_draw_trail(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void myon_draw_trail(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
float fadein = clamp(t/10.0, p->args[2], 1);
|
||||
float s = min(1, 1 - t / (double)p->timeout);
|
||||
float a = p->color.r*fadein;
|
||||
|
@ -128,7 +129,8 @@ static void myon_spawn_trail(Enemy *e, int t) {
|
|||
spawn_stardust(pos, f, 60, stardust_v);
|
||||
}
|
||||
|
||||
static void myon_draw_proj_trail(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void myon_draw_proj_trail(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
float time_progress = t / p->timeout;
|
||||
float s = 2 * time_progress;
|
||||
float a = min(1, s) * (1 - time_progress);
|
||||
|
@ -166,12 +168,13 @@ static int myon_proj(Projectile *p, int t) {
|
|||
.angle = p->angle,
|
||||
);
|
||||
|
||||
p->shader_params.vector[0] = pow(1 - min(1, t / 10.0), 2);
|
||||
p->opacity = 1.0f - powf(1.0f - fminf(1.0f, t / 10.0f), 2.0f);
|
||||
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
static void myon_proj_draw(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void myon_proj_draw(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
youmu_common_draw_proj(p, &p->color, 1);
|
||||
}
|
||||
|
||||
|
@ -402,13 +405,11 @@ static void youmu_mirror_bomb_damage_callback(EntityInterface *victim, cmplx vic
|
|||
.sprite = "petal",
|
||||
.pos = victim_origin,
|
||||
.rule = asymptotic,
|
||||
.draw_rule = Petal,
|
||||
.draw_rule = pdraw_petal_random(),
|
||||
.color = RGBA(sin(5*t) * t, cos(5*t) * t, 0.5 * t, 0),
|
||||
.args = {
|
||||
vrng_sign(R[0]) * vrng_range(R[1], 3, 3 + 5 * t) * cdir(M_PI*8*t),
|
||||
5+I,
|
||||
vrng_real(R[2]) + vrng_real(R[3])*I,
|
||||
vrng_real(R[4]) + vrng_range(R[5], 0, 360)*I,
|
||||
},
|
||||
.layer = LAYER_PARTICLE_PETAL,
|
||||
);
|
||||
|
|
|
@ -11,224 +11,46 @@
|
|||
#include "global.h"
|
||||
#include "plrmodes.h"
|
||||
#include "youmu.h"
|
||||
#include "util/glm.h"
|
||||
|
||||
static cmplx youmu_homing_target(cmplx org, cmplx fallback) {
|
||||
return plrutil_homing_target(org, fallback);
|
||||
}
|
||||
|
||||
static void youmu_homing_draw_common(Projectile *p, float clrfactor, float scale, float alpha) {
|
||||
Color c = p->color;
|
||||
color_mul(&c, RGBA(0.7f + 0.3f * clrfactor, 0.9f + 0.1f * clrfactor, 1, 1));
|
||||
static void youmu_homing_trail(Projectile *p, cmplx v, int to) {
|
||||
uint32_t tmp = p->ent.spawn_id;
|
||||
float u = M_PI * 2.0f * (float)(splitmix32(&tmp) / (double)UINT32_MAX);
|
||||
|
||||
if(alpha <= 0) {
|
||||
return;
|
||||
}
|
||||
RNG_ARRAY(R, 5);
|
||||
|
||||
bool special_snowflake_shader_bullshit = p->shader_params.vector[1] != 0;
|
||||
|
||||
if(special_snowflake_shader_bullshit) {
|
||||
// FIXME: maybe move this to logic someh-- nah. Don't even bother with this crap.
|
||||
float old = p->shader_params.vector[1];
|
||||
p->shader_params.vector[1] = alpha;
|
||||
youmu_common_draw_proj(p, &c, scale);
|
||||
p->shader_params.vector[1] = old;
|
||||
} else {
|
||||
color_mul_scalar(&c, alpha);
|
||||
youmu_common_draw_proj(p, &c, scale);
|
||||
}
|
||||
}
|
||||
|
||||
static void youmu_homing_draw_proj(Projectile *p, int t) {
|
||||
float a = clamp(1.0f - (float)t / p->args[2], 0, 1);
|
||||
youmu_homing_draw_common(p, a, 1, 0.5f);
|
||||
}
|
||||
|
||||
static void youmu_homing_draw_trail(Projectile *p, int t) {
|
||||
float a = clamp(1.0f - (float)t / p->timeout, 0, 1);
|
||||
youmu_homing_draw_common(p, a, 5 * (1 - a), 0.15f * a);
|
||||
}
|
||||
|
||||
static void youmu_trap_draw_trail(Projectile *p, int t) {
|
||||
float a = clamp(1.0f - (float)t / p->timeout, 0, 1);
|
||||
youmu_homing_draw_common(p, a, 2 - a, 0.15f * a);
|
||||
}
|
||||
|
||||
static void youmu_trap_draw_child_proj(Projectile *p, int t) {
|
||||
float to = p->args[2];
|
||||
float a = clamp(1.0 - 3 * ((t - (to - to/3)) / to), 0, 1);
|
||||
a = 1 - pow(1 - a, 2);
|
||||
youmu_homing_draw_common(p, a, 1 + 2 * pow(1 - a, 2), a);
|
||||
}
|
||||
|
||||
static float youmu_trap_charge(int t) {
|
||||
return pow(clamp(t / 60.0, 0, 1), 1.5);
|
||||
}
|
||||
|
||||
static Projectile* youmu_homing_trail(Projectile *p, cmplx v, int to) {
|
||||
return PARTICLE(
|
||||
.sprite_ptr = p->sprite,
|
||||
.pos = p->pos,
|
||||
.color = &p->color,
|
||||
.angle = p->angle,
|
||||
.rule = linear,
|
||||
PARTICLE(
|
||||
.sprite = "stardust",
|
||||
.pos = p->pos + vrng_range(R[0], 3, 12) * vrng_dir(R[1]),
|
||||
.color = RGBA(0.0, 0.3 * vrng_real(R[2]), 0.3, 0.0),
|
||||
// .draw_rule = pdraw_timeout_fade(1, 0),
|
||||
.draw_rule = pdraw_timeout_scalefade_exp(0.001*I, vrng_range(R[3], 0.5, 1.0)*(1+I), 2, 0, 2),
|
||||
.move = move_linear(-v),
|
||||
.timeout = to,
|
||||
.scale = 0.5,
|
||||
.angle = vrng_angle(R[4]),
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_PLRSPECIALPARTICLE | PFLAG_MANUALANGLE,
|
||||
.layer = LAYER_PARTICLE_MID,
|
||||
);
|
||||
|
||||
PARTICLE(
|
||||
.sprite = "smoothdot",
|
||||
.pos = p->pos,
|
||||
.color = color_mul(RGBA(0.2, 0.24, 0.3, 0.2), &p->color),
|
||||
.move = move_asymptotic_simple(-0.5*v*cdir(0.2*sin(u+3*creal(p->pos)/VIEWPORT_W*M_TAU) + 0.2*cos(u+3*cimag(p->pos)/VIEWPORT_H*M_TAU)), 2),
|
||||
.draw_rule = pdraw_timeout_scalefade_exp(0.5+0.5*I, 3+7*I, 1, 0, 2),
|
||||
.timeout = to,
|
||||
.draw_rule = youmu_homing_draw_trail,
|
||||
.args = { v },
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
.shader_ptr = p->shader,
|
||||
.shader_params = &p->shader_params,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
}
|
||||
|
||||
static int youmu_homing(Projectile *p, int t) { // a[0]: velocity, a[1]: aim (r: base, i: gain), a[2]: (r: timeout, i: charge), a[3]: initial target
|
||||
if(t == EVENT_BIRTH) {
|
||||
return ACTION_ACK;
|
||||
}
|
||||
|
||||
if(t == EVENT_DEATH) {
|
||||
PARTICLE(
|
||||
.sprite = "blast",
|
||||
.color = color_lerp(RGBA(0.5, 0.7, 1.0, 0.5), RGBA(1.0, 0.65, 0.8, 0.5), cimag(p->args[2])),
|
||||
.pos = p->pos,
|
||||
.timeout = 20,
|
||||
.draw_rule = ScaleFade,
|
||||
.layer = LAYER_PARTICLE_HIGH,
|
||||
.args = { 0, 0, 0.5 * I },
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
.angle = rng_angle(),
|
||||
);
|
||||
return ACTION_ACK;
|
||||
}
|
||||
|
||||
if(t > creal(p->args[2])) {
|
||||
return ACTION_DESTROY;
|
||||
}
|
||||
|
||||
p->args[3] = youmu_homing_target(p->pos, p->args[3]);
|
||||
|
||||
double v = cabs(p->args[0]);
|
||||
cmplx aimdir = cexp(I*carg(p->args[3] - p->pos));
|
||||
|
||||
p->args[0] += creal(p->args[1]) * aimdir;
|
||||
// p->args[0] = v * cexp(I*carg(p->args[0])) + cimag(p->args[1]) * aimdir;
|
||||
p->args[0] *= v / cabs(p->args[0]);
|
||||
|
||||
p->args[1] = creal(p->args[1]) + cimag(p->args[1]) * (1 + I);
|
||||
|
||||
p->angle = carg(p->args[0]);
|
||||
p->pos += p->args[0];
|
||||
|
||||
Projectile *trail = youmu_homing_trail(p, 0.5 * p->args[0], 12);
|
||||
trail->args[2] = p->args[2];
|
||||
|
||||
p->shader_params.vector[0] = cimag(p->args[2]);
|
||||
trail->shader_params.vector[0] = cimag(p->args[2]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Projectile* youmu_trap_trail(Projectile *p, cmplx v, int t, bool additive) {
|
||||
Projectile *trail = youmu_homing_trail(p, v, t);
|
||||
trail->draw_rule = youmu_trap_draw_trail;
|
||||
// trail->args[3] = global.frames - p->birthtime;
|
||||
trail->shader_params.vector[0] = p->shader_params.vector[0];
|
||||
trail->flags |= PFLAG_REQUIREDPARTICLE;
|
||||
|
||||
if(additive) {
|
||||
trail->color.a = 0;
|
||||
} else {
|
||||
trail->flags |= PFLAG_PLRSPECIALPARTICLE;
|
||||
}
|
||||
|
||||
return trail;
|
||||
}
|
||||
|
||||
static int youmu_trap(Projectile *p, int t) {
|
||||
if(t == EVENT_DEATH) {
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = p->pos,
|
||||
.timeout = 15,
|
||||
.draw_rule = Blast,
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
return ACTION_ACK;
|
||||
}
|
||||
|
||||
// FIXME: replace this with timeout?
|
||||
double expiretime = creal(p->args[1]);
|
||||
|
||||
if(t > expiretime) {
|
||||
return ACTION_DESTROY;
|
||||
}
|
||||
|
||||
if(t < 0) {
|
||||
return ACTION_ACK;
|
||||
}
|
||||
|
||||
float charge = youmu_trap_charge(t);
|
||||
p->shader_params.vector[0] = charge;
|
||||
|
||||
if(!(global.plr.inputflags & INFLAG_FOCUS)) {
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = p->pos,
|
||||
.timeout = 20,
|
||||
.draw_rule = Blast,
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = p->pos,
|
||||
.timeout = 23,
|
||||
.draw_rule = Blast,
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
|
||||
int cnt = round(creal(p->args[2]));
|
||||
int dmg = cimag(p->args[2]);
|
||||
cmplx aim = p->args[3];
|
||||
|
||||
for(int i = 0; i < cnt; ++i) {
|
||||
int dur = 120; // 55 + 20 * nfrand();
|
||||
float a = (i / (float)cnt) * M_PI * 2;
|
||||
cmplx dir = cexp(I*(a));
|
||||
|
||||
PROJECTILE(
|
||||
.proto = pp_youmu,
|
||||
.pos = p->pos,
|
||||
.color = RGBA(1, 1, 1, 0.85),
|
||||
.rule = youmu_homing,
|
||||
.args = { 5 * (1 + charge) * dir, aim, dur + charge*I, creal(p->pos) - VIEWPORT_H*I },
|
||||
.type = PROJ_PLAYER,
|
||||
.damage = dmg,
|
||||
.draw_rule = youmu_trap_draw_child_proj,
|
||||
.shader = "sprite_youmu_charged_shot",
|
||||
.shader_params = &(ShaderCustomParams){{ 0, 1 }},
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: dedicated sound for this?
|
||||
play_sound("enemydeath");
|
||||
play_sound("hit");
|
||||
|
||||
return ACTION_DESTROY;
|
||||
}
|
||||
|
||||
p->angle = global.frames + t;
|
||||
p->pos += p->args[0] * (0.01 + 0.99 * max(0, (10 - t) / 10.0));
|
||||
|
||||
youmu_trap_trail(p, cexp(I*p->angle), 30 * (1 + charge), true);
|
||||
youmu_trap_trail(p, cexp(I*-p->angle), 30, false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void youmu_particle_slice_draw(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void youmu_particle_slice_draw(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
double lifetime = p->timeout;
|
||||
double tt = t/lifetime;
|
||||
double f = 0;
|
||||
|
@ -286,18 +108,15 @@ static int youmu_particle_slice_logic(Projectile *p, int t) {
|
|||
|
||||
if(t%5 == 0) {
|
||||
cmplx phase = cdir(p->angle);
|
||||
RNG_ARRAY(R, 4);
|
||||
|
||||
PARTICLE(
|
||||
.sprite = "petal",
|
||||
.pos = p->pos-400*phase,
|
||||
.rule = youmu_slice_petal,
|
||||
.draw_rule = Petal,
|
||||
.draw_rule = pdraw_petal_random(),
|
||||
.args = {
|
||||
phase,
|
||||
phase*cdir(0.1),
|
||||
vrng_real(R[0]) + vrng_real(R[1])*I,
|
||||
vrng_real(R[2]) + vrng_range(R[3], 0, 360)*I,
|
||||
},
|
||||
.layer = LAYER_PARTICLE_HIGH | 0x2,
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
|
@ -380,8 +199,7 @@ static void youmu_haunting_power_shot(Player *plr, int p) {
|
|||
.proto = pp_hghost,
|
||||
.pos = plr->pos,
|
||||
.rule = youmu_asymptotic,
|
||||
.color = RGB(0.7 + 0.3 * (1-np), 0.8 + 0.2 * sqrt(1-np), 1.0),
|
||||
.draw_rule = youmu_homing_draw_proj,
|
||||
.color = color_mul_scalar(RGB(0.7 + 0.3 * (1-np), 0.8 + 0.2 * sqrt(1-np), 1.0), 0.5),
|
||||
.args = { speed * dir * (1 - 0.25 * (1 - np)), 3 * (1 - pow(1 - np, 2)), 60, },
|
||||
.type = PROJ_PLAYER,
|
||||
.damage = 20,
|
||||
|
@ -390,6 +208,237 @@ static void youmu_haunting_power_shot(Player *plr, int p) {
|
|||
}
|
||||
}
|
||||
|
||||
TASK(youmu_homing_shot, { BoxedPlayer plr; }) {
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
.proto = pp_hghost,
|
||||
.pos = ENT_UNBOX(ARGS.plr)->pos,
|
||||
.color = RGB(0.75, 0.9, 1),
|
||||
.type = PROJ_PLAYER,
|
||||
.damage = 120,
|
||||
.shader = "sprite_default",
|
||||
));
|
||||
|
||||
real speed = 10;
|
||||
real aim_strength = 0;
|
||||
real aim_strength_accel = 0.02;
|
||||
p->move = move_linear(-I * speed);
|
||||
cmplx target = VIEWPORT_W * 0.5;
|
||||
|
||||
for(int i = 0; i < 60; ++i) {
|
||||
target = youmu_homing_target(p->pos, target);
|
||||
cmplx aimdir = cnormalize(target - p->pos - p->move.velocity*10);
|
||||
p->move.velocity += aim_strength * aimdir;
|
||||
p->move.velocity *= speed / cabs(p->move.velocity);
|
||||
aim_strength += aim_strength_accel;
|
||||
|
||||
youmu_homing_trail(p, 0.5 * p->move.velocity, 12);
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
TASK(youmu_orb_homing_spirit_expire, { BoxedProjectile p; }) {
|
||||
Projectile *p = ENT_UNBOX(ARGS.p);
|
||||
|
||||
PARTICLE(
|
||||
.sprite_ptr = p->sprite,
|
||||
.shader_ptr = p->shader,
|
||||
.color = &p->color,
|
||||
.timeout = 30,
|
||||
.draw_rule = pdraw_timeout_scalefade(1+I, 0.1+I, 1, 0),
|
||||
.pos = p->pos,
|
||||
.move = p->move,
|
||||
.angle = p->angle,
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PLAYER_SHOT,
|
||||
);
|
||||
}
|
||||
|
||||
static int youmu_orb_homing_spirit_timeout(Projectile *orb) {
|
||||
return orb->timeout - projectile_time(orb);
|
||||
}
|
||||
|
||||
TASK(youmu_orb_homing_spirit, { cmplx pos; cmplx velocity; cmplx target; real charge; real damage; real spin; BoxedProjectile orb; }) {
|
||||
int timeout = youmu_orb_homing_spirit_timeout(ENT_UNBOX(ARGS.orb));
|
||||
|
||||
if(timeout <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Projectile *p = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
.proto = pp_hghost,
|
||||
.pos = ARGS.pos,
|
||||
.color = color_mul_scalar(RGB(0.75, 0.9, 1), 0.5),
|
||||
.type = PROJ_PLAYER,
|
||||
.timeout = timeout,
|
||||
.damage = ARGS.damage,
|
||||
.shader = "sprite_particle",
|
||||
));
|
||||
|
||||
INVOKE_TASK_AFTER(&p->events.killed, youmu_orb_homing_spirit_expire, ENT_BOX(p));
|
||||
|
||||
real speed = cabs(ARGS.velocity);
|
||||
real speed_target = speed;
|
||||
real aim_strength = -0.1;
|
||||
p->move = move_accelerated(ARGS.velocity, -0.06 * ARGS.velocity);
|
||||
p->move.retention = cdir(ARGS.spin);
|
||||
cmplx target = ARGS.target;
|
||||
|
||||
bool aim_peaked = false;
|
||||
bool orb_died = false;
|
||||
Projectile *orb = NULL;
|
||||
|
||||
for(;;) {
|
||||
if(!orb_died) {
|
||||
orb = ENT_UNBOX(ARGS.orb);
|
||||
|
||||
if(orb == NULL) {
|
||||
orb_died = true;
|
||||
p->timeout = 0;
|
||||
// p->move.velocity = 0;
|
||||
p->move.retention *= 0.9;
|
||||
aim_peaked = false;
|
||||
aim_strength = -0.2;
|
||||
speed *= 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
if(orb) {
|
||||
target = orb->pos;
|
||||
} else {
|
||||
target = youmu_homing_target(p->pos, creal(global.plr.pos) - 128*I);
|
||||
}
|
||||
|
||||
cmplx aimdir = cnormalize(target - p->pos - p->move.velocity);
|
||||
capproach_asymptotic_p(&p->move.retention, 0.8, 0.1, 1e-3);
|
||||
p->move.acceleration *= 0.95;
|
||||
p->move.acceleration += aim_strength * aimdir;
|
||||
|
||||
if(aim_peaked) {
|
||||
if(!orb) {
|
||||
approach_p(&aim_strength, 0.00, 0.001);
|
||||
}
|
||||
} else {
|
||||
approach_p(&aim_strength, 0.1, 0.02);
|
||||
if(aim_strength == 0.1) {
|
||||
aim_peaked = true;
|
||||
}
|
||||
}
|
||||
|
||||
real s = max(speed, cabs(p->move.velocity));
|
||||
p->move.velocity = s * cnormalize(p->move.velocity + aim_strength * s * aimdir);
|
||||
approach_asymptotic_p(&speed, speed_target, 0.05, 1e-5);
|
||||
|
||||
youmu_homing_trail(p, 0.5 * p->move.velocity, 12);
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
TASK(youmu_orb_update, { BoxedPlayer plr; BoxedProjectile orb; }) {
|
||||
Player *plr = ENT_UNBOX(ARGS.plr);
|
||||
Projectile *orb = TASK_BIND(ARGS.orb);
|
||||
|
||||
for(;;) {
|
||||
float tf = glm_ease_bounce_out(1.0f - projectile_timeout_factor(orb));
|
||||
orb->color.g = tf * tf;
|
||||
orb->color.b = tf;
|
||||
orb->scale = 0.5 + 0.5 * tf;
|
||||
orb->angle += 0.2;
|
||||
|
||||
// TODO events for player input?
|
||||
if(!(plr->inputflags & INFLAG_FOCUS)) {
|
||||
PARTICLE(
|
||||
.sprite = "blast_huge_rays",
|
||||
.pos = orb->pos,
|
||||
.timeout = 20,
|
||||
.color = RGBA(0.1, 0.5, 0.1, 0.0),
|
||||
.draw_rule = pdraw_timeout_scalefade_exp(0.01*(1+I), 1, 1, 0, 2),
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.angle = rng_angle(),
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
|
||||
PARTICLE(
|
||||
.sprite = "blast_huge_halo",
|
||||
.pos = orb->pos,
|
||||
.timeout = 30,
|
||||
.color = RGBA(0.1, 0.1, 0.5, 0.0),
|
||||
.draw_rule = pdraw_timeout_scalefade_exp(1, 0.01*(1+I), 1, 0, 2),
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.angle = rng_angle(),
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
|
||||
PARTICLE(
|
||||
.sprite = "blast_huge_halo",
|
||||
.pos = orb->pos,
|
||||
.timeout = 40,
|
||||
.color = RGBA(0.5, 0.1, 0.1, 0.0),
|
||||
.draw_rule = pdraw_timeout_scalefade_exp(0.8, -0.3*(1+I), 1, 0, 2),
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.angle = rng_angle(),
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
|
||||
// TODO sound effect;
|
||||
kill_projectile(orb);
|
||||
break;
|
||||
}
|
||||
|
||||
YIELD;
|
||||
}
|
||||
}
|
||||
|
||||
TASK(youmu_orb_death, { BoxedProjectile orb; BoxedTask control_task; }) {
|
||||
cotask_cancel(cotask_unbox(ARGS.control_task));
|
||||
Projectile *orb = ENT_UNBOX(ARGS.orb);
|
||||
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = orb->pos,
|
||||
.timeout = 20,
|
||||
.draw_rule = pdraw_blast(),
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = orb->pos,
|
||||
.timeout = 23,
|
||||
.draw_rule = pdraw_blast(),
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
}
|
||||
|
||||
TASK(youmu_orb_shot, { BoxedPlayer plr; }) {
|
||||
Player *plr = ENT_UNBOX(ARGS.plr);
|
||||
int pwr = plr->power / 100;
|
||||
|
||||
Projectile *orb = TASK_BIND_UNBOXED(PROJECTILE(
|
||||
.proto = pp_youhoming,
|
||||
.pos = plr->pos,
|
||||
.color = RGB(1, 1, 1),
|
||||
.type = PROJ_PLAYER,
|
||||
.damage = 1000,
|
||||
.timeout = 100 + 10 * pwr,
|
||||
.move = move_asymptotic(-30.0*I, -0.7*I, 0.8),
|
||||
.flags = PFLAG_MANUALANGLE,
|
||||
));
|
||||
|
||||
INVOKE_TASK(youmu_orb_update, ARGS.plr, ENT_BOX(orb));
|
||||
INVOKE_TASK_AFTER(&orb->events.killed, youmu_orb_death, ENT_BOX(orb), THIS_TASK);
|
||||
|
||||
real pdmg = 120 - 18 * 4 * (1 - pow(1 - pwr / 4.0, 1.5));
|
||||
cmplx v = 5 * I;
|
||||
|
||||
for(;;) {
|
||||
WAIT(11);
|
||||
INVOKE_TASK(youmu_orb_homing_spirit, orb->pos, v, 0, 0, pdmg, 0.1, ENT_BOX(orb));
|
||||
INVOKE_TASK(youmu_orb_homing_spirit, orb->pos, v, 0, 0, pdmg, -0.1, ENT_BOX(orb));
|
||||
}
|
||||
}
|
||||
|
||||
static void youmu_haunting_shot(Player *plr) {
|
||||
youmu_common_shot(plr);
|
||||
|
||||
|
@ -398,34 +447,11 @@ static void youmu_haunting_shot(Player *plr) {
|
|||
int pwr = plr->power / 100;
|
||||
|
||||
if(!(global.frames % (45 - 4 * pwr))) {
|
||||
int pcnt = 11 + pwr * 4;
|
||||
int pdmg = 120 - 18 * 4 * (1 - pow(1 - pwr / 4.0, 1.5));
|
||||
cmplx aim = 0.15*I;
|
||||
|
||||
PROJECTILE(
|
||||
.proto = pp_youhoming,
|
||||
.pos = plr->pos,
|
||||
.color = RGB(1, 1, 1),
|
||||
.rule = youmu_trap,
|
||||
.args = { -30.0*I, 120, pcnt+pdmg*I, aim },
|
||||
.type = PROJ_PLAYER,
|
||||
.damage = 1000,
|
||||
.shader = "sprite_youmu_charged_shot",
|
||||
.shader_params = &(ShaderCustomParams){{ 0, 1 }},
|
||||
);
|
||||
INVOKE_TASK(youmu_orb_shot, ENT_BOX(plr));
|
||||
}
|
||||
} else {
|
||||
if(!(global.frames % 6)) {
|
||||
PROJECTILE(
|
||||
.proto = pp_hghost,
|
||||
.pos = plr->pos,
|
||||
.color = RGB(0.75, 0.9, 1),
|
||||
.rule = youmu_homing,
|
||||
.args = { -10.0*I, 0.02*I, 60, VIEWPORT_W*0.5 },
|
||||
.type = PROJ_PLAYER,
|
||||
.damage = 120,
|
||||
.shader = "sprite_default",
|
||||
);
|
||||
INVOKE_TASK(youmu_homing_shot, ENT_BOX(plr));
|
||||
}
|
||||
|
||||
for(int p = 1; p <= 2*PLR_MAX_POWER/100; ++p) {
|
||||
|
@ -448,10 +474,6 @@ static void youmu_haunting_preload(void) {
|
|||
"part/youmu_slice",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SHADER_PROGRAM, flags,
|
||||
"sprite_youmu_charged_shot",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_TEXTURE, flags,
|
||||
"youmu_bombbg1",
|
||||
NULL);
|
||||
|
|
415
src/projectile.c
415
src/projectile.c
|
@ -13,12 +13,12 @@
|
|||
#include "global.h"
|
||||
#include "list.h"
|
||||
#include "stageobjects.h"
|
||||
#include "util/glm.h"
|
||||
|
||||
static ht_ptr2int_t shader_sublayer_map;
|
||||
|
||||
static ProjArgs defaults_proj = {
|
||||
.sprite = "proj/",
|
||||
.draw_rule = ProjDraw,
|
||||
.dest = &global.projs,
|
||||
.type = PROJ_ENEMY,
|
||||
.damage_type = DMG_ENEMY_SHOT,
|
||||
|
@ -30,13 +30,12 @@ static ProjArgs defaults_proj = {
|
|||
|
||||
static ProjArgs defaults_part = {
|
||||
.sprite = "part/",
|
||||
.draw_rule = ProjDraw,
|
||||
.dest = &global.particles,
|
||||
.type = PROJ_PARTICLE,
|
||||
.damage_type = DMG_UNDEFINED,
|
||||
.color = RGB(1, 1, 1),
|
||||
.blend = BLEND_PREMUL_ALPHA,
|
||||
.shader = "sprite_default",
|
||||
.shader = "sprite_particle",
|
||||
.layer = LAYER_PARTICLE_MID,
|
||||
};
|
||||
|
||||
|
@ -60,8 +59,8 @@ static void process_projectile_args(ProjArgs *args, ProjArgs *defaults) {
|
|||
}
|
||||
}
|
||||
|
||||
if(!args->draw_rule) {
|
||||
args->draw_rule = ProjDraw;
|
||||
if(!args->draw_rule.func) {
|
||||
args->draw_rule = pdraw_basic();
|
||||
}
|
||||
|
||||
if(!args->blend) {
|
||||
|
@ -100,6 +99,16 @@ static void process_projectile_args(ProjArgs *args, ProjArgs *defaults) {
|
|||
}
|
||||
}
|
||||
|
||||
if(args->scale == 0) {
|
||||
args->scale = 1+I;
|
||||
} else if(cimagf(args->scale) == 0) {
|
||||
args->scale = CMPLXF(crealf(args->scale), crealf(args->scale));
|
||||
}
|
||||
|
||||
if(args->opacity == 0) {
|
||||
args->opacity = 1;
|
||||
}
|
||||
|
||||
assert(args->type <= PROJ_PLAYER);
|
||||
}
|
||||
|
||||
|
@ -196,12 +205,48 @@ cmplx projectile_graze_size(Projectile *p) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
float32 projectile_timeout_factor(Projectile *p) {
|
||||
return p->timeout ? (global.frames - p->birthtime) / p->timeout : 0;
|
||||
}
|
||||
|
||||
static double projectile_rect_area(Projectile *p) {
|
||||
double w, h;
|
||||
projectile_size(p, &w, &h);
|
||||
return w * h;
|
||||
}
|
||||
|
||||
void projectile_set_layer(Projectile *p, drawlayer_t layer) {
|
||||
if(!(layer & LAYER_LOW_MASK)) {
|
||||
drawlayer_low_t sublayer;
|
||||
|
||||
switch(p->type) {
|
||||
case PROJ_ENEMY:
|
||||
// 1. Large projectiles go below smaller ones.
|
||||
sublayer = LAYER_LOW_MASK - (drawlayer_low_t)projectile_rect_area(p);
|
||||
sublayer = (sublayer << 4) & LAYER_LOW_MASK;
|
||||
// 2. Group by shader (hardcoded precedence).
|
||||
sublayer |= ht_get(&shader_sublayer_map, p->shader, 0) & 0xf;
|
||||
// If specific blending order is required, then you should set up the sublayer manually.
|
||||
layer |= sublayer;
|
||||
break;
|
||||
|
||||
case PROJ_PARTICLE:
|
||||
// 1. Group by shader (hardcoded precedence).
|
||||
sublayer = ht_get(&shader_sublayer_map, p->shader, 0) & 0xf;
|
||||
sublayer <<= 4;
|
||||
sublayer |= 0x100;
|
||||
// If specific blending order is required, then you should set up the sublayer manually.
|
||||
layer |= sublayer;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
p->ent.draw_layer = layer;
|
||||
}
|
||||
|
||||
static Projectile* _create_projectile(ProjArgs *args) {
|
||||
if(IN_DRAW_CODE) {
|
||||
log_fatal("Tried to spawn a projectile while in drawing code");
|
||||
|
@ -228,14 +273,11 @@ static Projectile* _create_projectile(ProjArgs *args) {
|
|||
p->damage_type = args->damage_type;
|
||||
p->clear_flags = 0;
|
||||
p->move = args->move;
|
||||
|
||||
if(args->shader_params != NULL) {
|
||||
p->shader_params = *args->shader_params;
|
||||
}
|
||||
p->scale = args->scale;
|
||||
p->opacity = args->opacity;
|
||||
|
||||
memcpy(p->args, args->args, sizeof(p->args));
|
||||
|
||||
p->ent.draw_layer = args->layer;
|
||||
p->ent.draw_func = ent_draw_projectile;
|
||||
|
||||
projectile_set_prototype(p, args->proto);
|
||||
|
@ -247,33 +289,7 @@ static Projectile* _create_projectile(ProjArgs *args) {
|
|||
log_fatal("Tried to spawn a projectile with invalid size %f x %f", creal(p->size), cimag(p->size));
|
||||
}
|
||||
|
||||
if(!(p->ent.draw_layer & LAYER_LOW_MASK)) {
|
||||
drawlayer_low_t sublayer;
|
||||
|
||||
switch(p->type) {
|
||||
case PROJ_ENEMY:
|
||||
// 1. Large projectiles go below smaller ones.
|
||||
sublayer = LAYER_LOW_MASK - (drawlayer_low_t)projectile_rect_area(p);
|
||||
sublayer = (sublayer << 4) & LAYER_LOW_MASK;
|
||||
// 2. Group by shader (hardcoded precedence).
|
||||
sublayer |= ht_get(&shader_sublayer_map, p->shader, 0) & 0xf;
|
||||
// If specific blending order is required, then you should set up the sublayer manually.
|
||||
p->ent.draw_layer |= sublayer;
|
||||
break;
|
||||
|
||||
case PROJ_PARTICLE:
|
||||
// 1. Group by shader (hardcoded precedence).
|
||||
sublayer = ht_get(&shader_sublayer_map, p->shader, 0) & 0xf;
|
||||
sublayer <<= 4;
|
||||
sublayer |= 0x100;
|
||||
// If specific blending order is required, then you should set up the sublayer manually.
|
||||
p->ent.draw_layer |= sublayer;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
projectile_set_layer(p, args->layer);
|
||||
|
||||
coevent_init(&p->events.killed);
|
||||
ent_register(&p->ent, ENT_PROJECTILE);
|
||||
|
@ -444,14 +460,14 @@ static void ent_draw_projectile(EntityInterface *ent) {
|
|||
static Projectile prev_state;
|
||||
memcpy(&prev_state, proj, sizeof(Projectile));
|
||||
|
||||
proj->draw_rule(proj, global.frames - proj->birthtime);
|
||||
proj->draw_rule.func(proj, global.frames - proj->birthtime, proj->draw_rule.args);
|
||||
|
||||
if(memcmp(&prev_state, proj, sizeof(Projectile))) {
|
||||
set_debug_info(&proj->debug);
|
||||
log_fatal("Projectile modified its state in draw rule");
|
||||
}
|
||||
#else
|
||||
proj->draw_rule(proj, global.frames - proj->birthtime);
|
||||
proj->draw_rule.func(proj, global.frames - proj->birthtime, proj->draw_rule.args);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -481,10 +497,11 @@ Projectile* spawn_projectile_collision_effect(Projectile *proj) {
|
|||
.flags = proj->flags | PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PARTICLE_HIGH,
|
||||
.shader_ptr = proj->shader,
|
||||
.rule = linear,
|
||||
.draw_rule = DeathShrink,
|
||||
.draw_rule = pdraw_timeout_scale(2+I, 0+I),
|
||||
.angle = proj->angle,
|
||||
.args = { 5*cexp(I*proj->angle) },
|
||||
// .rule = linear,
|
||||
// .args = { 5*cexp(I*proj->angle) },
|
||||
.move = { .velocity = 5*cexp(I*proj->angle), .retention = 0.95 },
|
||||
.timeout = 10,
|
||||
);
|
||||
}
|
||||
|
@ -524,9 +541,10 @@ bool clear_projectile(Projectile *proj, uint flags) {
|
|||
}
|
||||
|
||||
void kill_projectile(Projectile* proj) {
|
||||
coevent_signal_once(&proj->events.killed);
|
||||
proj->flags |= PFLAG_INTERNAL_DEAD | PFLAG_NOCOLLISION | PFLAG_NOCLEAR;
|
||||
proj->draw_rule = ProjNoDraw;
|
||||
proj->ent.draw_layer = LAYER_NODRAW;
|
||||
// WARNING: must be done last, an event handler may cancel the task this function is running in!
|
||||
coevent_signal_once(&proj->events.killed);
|
||||
}
|
||||
|
||||
void process_projectiles(ProjectileList *projlist, bool collision) {
|
||||
|
@ -617,6 +635,10 @@ bool projectile_is_clearable(Projectile *p) {
|
|||
return false;
|
||||
}
|
||||
|
||||
int projectile_time(Projectile *p) {
|
||||
return global.frames - p->birthtime;
|
||||
}
|
||||
|
||||
int linear(Projectile *p, int t) { // sure is physics in here; a[0]: velocity
|
||||
if(t == EVENT_DEATH) {
|
||||
return ACTION_ACK;
|
||||
|
@ -702,24 +724,25 @@ static inline void apply_common_transforms(Projectile *proj, int t) {
|
|||
*/
|
||||
}
|
||||
|
||||
static void bullet_highlight_draw(Projectile *p, int t) {
|
||||
static void bullet_highlight_draw(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
float timefactor = t / p->timeout;
|
||||
float sx = creal(p->args[0]);
|
||||
float sy = cimag(p->args[0]);
|
||||
float sx = args[0].as_float[0];
|
||||
float sy = args[0].as_float[1];
|
||||
float tex_angle = args[1].as_float[0];
|
||||
|
||||
float opacity = pow(1 - timefactor, 2);
|
||||
opacity = min(1, 1.5 * opacity) * min(1, timefactor * 10);
|
||||
opacity *= 1 - p->shader_params.vector[0];
|
||||
opacity *= p->opacity;
|
||||
|
||||
r_mat_tex_push();
|
||||
r_mat_tex_translate(0.5, 0.5, 0);
|
||||
r_mat_tex_rotate(p->args[1], 0, 0, 1);
|
||||
r_mat_tex_rotate(tex_angle, 0, 0, 1);
|
||||
r_mat_tex_translate(-0.5, -0.5, 0);
|
||||
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite_ptr = p->sprite,
|
||||
.shader_ptr = p->shader,
|
||||
.shader_params = &(ShaderCustomParams) {{ 1 - opacity }},
|
||||
.shader_params = &(ShaderCustomParams) {{ opacity }},
|
||||
.color = &p->color,
|
||||
.scale = { .x = sx, .y = sy },
|
||||
.rotation.angle = p->angle + M_PI * 0.5,
|
||||
|
@ -757,8 +780,7 @@ static Projectile* spawn_projectile_highlight_effect_internal(Projectile *p, boo
|
|||
.shader = "sprite_bullet",
|
||||
.size = p->size * 4.5,
|
||||
.layer = LAYER_PARTICLE_HIGH | 0x40,
|
||||
.draw_rule = ScaleSquaredFade,
|
||||
.args = { 0, 0, (0 + 2*I) * 0.1 * fmax(sx, sy) * (1 - 0.2 * vrng_real(R[0])) },
|
||||
.draw_rule = pdraw_timeout_scalefade_exp(0, 0.2f * fmaxf(sx, sy) * vrng_f32_range(R[0], 0.8f, 1.0f), 1, 0, 2),
|
||||
.angle = vrng_angle(R[1]),
|
||||
.pos = p->pos + vrng_range(R[2], 0, 8) * vrng_dir(R[3]),
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
|
@ -778,8 +800,11 @@ static Projectile* spawn_projectile_highlight_effect_internal(Projectile *p, boo
|
|||
.size = p->size * 4.5,
|
||||
.shader = "sprite_bullet",
|
||||
.layer = LAYER_PARTICLE_HIGH | 0x80,
|
||||
.draw_rule = bullet_highlight_draw,
|
||||
.args = { 0.125 * (sx + I * sy), vrng_angle(R[0]) },
|
||||
.draw_rule = {
|
||||
bullet_highlight_draw,
|
||||
.args[0].as_cmplx = 0.125 * (sx + I * sy),
|
||||
.args[1].as_float = vrng_angle(R[0]),
|
||||
},
|
||||
.angle = p->angle,
|
||||
.pos = p->pos + vrng_range(R[1], 0, 5) * vrng_dir(R[2]),
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
|
@ -800,25 +825,24 @@ static Projectile* spawn_bullet_spawning_effect(Projectile *p) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void projectile_clear_effect_draw(Projectile *p, int t) {
|
||||
static void projectile_clear_effect_draw(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
r_mat_mv_push();
|
||||
apply_common_transforms(p, t);
|
||||
|
||||
float timefactor = t / p->timeout;
|
||||
float plrfactor = clamp(1 - (cabs(p->pos - global.plr.pos) - 64) / 128, 0, 1);
|
||||
plrfactor *= clamp(timefactor * 10, 0, 1);
|
||||
float f = 1 - (1 - timefactor) * (1 - plrfactor);
|
||||
float opacity = timefactor * plrfactor;
|
||||
|
||||
Sprite spr = *p->sprite;
|
||||
Sprite *ispr = get_sprite("item/bullet_point");
|
||||
spr.w = f * ispr->w + (1 - f) * spr.w;
|
||||
spr.h = f * ispr->h + (1 - f) * spr.h;
|
||||
spr.w = lerpf(spr.w, ispr->w, opacity);
|
||||
spr.h = lerpf(spr.h, ispr->h, opacity);
|
||||
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite_ptr = &spr,
|
||||
.color = RGBA(p->color.r, p->color.g, p->color.b, p->color.a * (1 - 0)),
|
||||
.shader_params = &(ShaderCustomParams){{ f }},
|
||||
// .scale.both = 1 + 0.5 * sqrt(tf),
|
||||
.color = &p->color,
|
||||
.shader_params = &(ShaderCustomParams){{ opacity }},
|
||||
});
|
||||
|
||||
r_mat_mv_pop();
|
||||
|
@ -847,7 +871,7 @@ static int projectile_clear_effect_logic(Projectile *p, int t) {
|
|||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
Projectile* spawn_projectile_clear_effect(Projectile *proj) {
|
||||
Projectile *spawn_projectile_clear_effect(Projectile *proj) {
|
||||
if((proj->flags & PFLAG_NOCLEAREFFECT) || proj->sprite == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -873,80 +897,128 @@ Projectile* spawn_projectile_clear_effect(Projectile *proj) {
|
|||
.rule = projectile_clear_effect_logic,
|
||||
.draw_rule = projectile_clear_effect_draw,
|
||||
.angle = proj->angle,
|
||||
.opacity = proj->opacity,
|
||||
.scale = proj->scale,
|
||||
.timeout = 24,
|
||||
.args = { -1 },
|
||||
.layer = layer,
|
||||
);
|
||||
}
|
||||
|
||||
void ProjDrawCore(Projectile *proj, const Color *c) {
|
||||
SpriteParams projectile_sprite_params(Projectile *proj, SpriteParamsBuffer *spbuf) {
|
||||
spbuf->color = proj->color;
|
||||
spbuf->shader_params = (ShaderCustomParams) {{ proj->opacity, 0, 0, 0 }};
|
||||
|
||||
SpriteParams sp = { 0 };
|
||||
sp.blend = proj->blend;
|
||||
sp.color = &spbuf->color;
|
||||
sp.pos.x = creal(proj->pos);
|
||||
sp.pos.y = cimag(proj->pos);
|
||||
sp.rotation = (SpriteRotationParams) {
|
||||
.angle = proj->angle + (float)(M_PI/2),
|
||||
.vector = { 0, 0, 1 },
|
||||
};
|
||||
sp.scale.x = crealf(proj->scale);
|
||||
sp.scale.y = cimagf(proj->scale);
|
||||
sp.shader_params = &spbuf->shader_params;
|
||||
sp.shader_ptr = proj->shader;
|
||||
sp.sprite_ptr = proj->sprite;
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
static void projectile_draw_sprite(Sprite *s, const Color *clr, float32 opacity, cmplx32 scale) {
|
||||
if(opacity <= 0 || crealf(scale) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ShaderCustomParams p = {
|
||||
opacity,
|
||||
};
|
||||
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite_ptr = proj->sprite,
|
||||
.color = c,
|
||||
.shader_params = &proj->shader_params,
|
||||
.sprite_ptr = s,
|
||||
.color = clr,
|
||||
.shader_params = &p,
|
||||
.scale = { crealf(scale), cimagf(scale) },
|
||||
});
|
||||
}
|
||||
|
||||
void ProjDraw(Projectile *proj, int t) {
|
||||
r_mat_mv_push();
|
||||
apply_common_transforms(proj, t);
|
||||
void ProjDrawCore(Projectile *proj, const Color *c) {
|
||||
projectile_draw_sprite(proj->sprite, c, proj->opacity, proj->scale);
|
||||
}
|
||||
|
||||
void ProjDraw(Projectile *proj, int t, ProjDrawRuleArgs args) {
|
||||
SpriteParamsBuffer spbuf;
|
||||
SpriteParams sp = projectile_sprite_params(proj, &spbuf);
|
||||
|
||||
float eff = proj_spawn_effect_factor(proj, t);
|
||||
|
||||
/*
|
||||
if(eff < 1 && proj->color.a > 0) {
|
||||
Color c = proj->color;
|
||||
c.a *= sqrt(eff);
|
||||
ProjDrawCore(proj, &c);
|
||||
} else {
|
||||
ProjDrawCore(proj, &proj->color);
|
||||
}
|
||||
*/
|
||||
|
||||
if(eff < 1) {
|
||||
float o = proj->shader_params.vector[0];
|
||||
float a = min(1, eff * 2);
|
||||
proj->shader_params.vector[0] = 1 - (1 - o) * a;
|
||||
Color c = proj->color;
|
||||
c.a *= eff;//sqrt(eff);
|
||||
ProjDrawCore(proj, &c);
|
||||
proj->shader_params.vector[0] = o;
|
||||
} else {
|
||||
ProjDrawCore(proj, &proj->color);
|
||||
spbuf.color.a *= eff;
|
||||
spbuf.shader_params.vector[0] *= fminf(1.0f, eff * 2.0f);
|
||||
}
|
||||
|
||||
r_mat_mv_pop();
|
||||
r_draw_sprite(&sp);
|
||||
}
|
||||
|
||||
void ProjNoDraw(Projectile *proj, int t) {
|
||||
ProjDrawRule pdraw_basic(void) {
|
||||
return (ProjDrawRule) { ProjDraw };
|
||||
}
|
||||
|
||||
void Blast(Projectile *p, int t) {
|
||||
r_mat_mv_push();
|
||||
r_mat_mv_translate(creal(p->pos), cimag(p->pos), 0);
|
||||
r_mat_mv_rotate(creal(p->args[1]) * DEG2RAD, cimag(p->args[1]), creal(p->args[2]), cimag(p->args[2]));
|
||||
|
||||
if(t != p->timeout && p->timeout != 0) {
|
||||
r_mat_mv_scale(t/(double)p->timeout, t/(double)p->timeout, 1);
|
||||
}
|
||||
|
||||
float fade = 1.0 - t / (double)p->timeout;
|
||||
r_color(RGBA_MUL_ALPHA(0.3, 0.6, 1.0, fade));
|
||||
|
||||
SpriteParams sp = {
|
||||
.sprite_ptr = p->sprite,
|
||||
.color = RGBA_MUL_ALPHA(0.3, 0.6, 1.0, fade),
|
||||
static void pdraw_blast_func(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
vec3 rot_axis = {
|
||||
args[0].as_float[0],
|
||||
args[0].as_float[1],
|
||||
args[1].as_float[0],
|
||||
};
|
||||
|
||||
float32 rot_angle = args[1].as_float[1];
|
||||
float32 secondary_scale = args[2].as_float[0];
|
||||
|
||||
float32 tf = projectile_timeout_factor(p);
|
||||
float32 opacity = (1.0f - tf) * p->opacity;
|
||||
|
||||
if(tf <= 0 || opacity <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SpriteParamsBuffer spbuf;
|
||||
SpriteParams sp = projectile_sprite_params(p, &spbuf);
|
||||
sp.rotation.angle = rot_angle;
|
||||
glm_vec3_copy(rot_axis, sp.rotation.vector);
|
||||
sp.scale.x = tf;
|
||||
sp.scale.y = tf;
|
||||
|
||||
spbuf.color = *RGBA(0.3, 0.6, 1.0, 1);
|
||||
spbuf.shader_params.vector[0] = opacity;
|
||||
|
||||
r_disable(RCAP_CULL_FACE);
|
||||
r_draw_sprite(&sp);
|
||||
r_mat_mv_scale(0.5+creal(p->args[2]), 0.5+creal(p->args[2]), 1);
|
||||
r_color4(0.3 * fade, 0.6 * fade, 1.0 * fade, 0);
|
||||
sp.color = RGBA(0.3 * fade, 0.6 * fade, 1.0 * fade, 0);
|
||||
sp.scale.as_cmplx *= secondary_scale;
|
||||
spbuf.color.a = 0;
|
||||
r_draw_sprite(&sp);
|
||||
r_mat_mv_pop();
|
||||
}
|
||||
|
||||
void Shrink(Projectile *p, int t) {
|
||||
ProjDrawRule pdraw_blast(void) {
|
||||
float32 rot_angle = rng_f32_angle();
|
||||
float32 x = rng_f32();
|
||||
float32 y = rng_f32();
|
||||
float32 z = rng_f32();
|
||||
float32 secondary_scale = rng_f32_range(0.5, 1.5);
|
||||
|
||||
vec3 rot_axis = { x, y, z };
|
||||
glm_vec3_normalize(rot_axis);
|
||||
|
||||
return (ProjDrawRule) {
|
||||
.func = pdraw_blast_func,
|
||||
.args[0].as_float = { rot_axis[0], rot_axis[1] },
|
||||
.args[1].as_float = { rot_axis[2], rot_angle },
|
||||
.args[2].as_float = { secondary_scale, },
|
||||
};
|
||||
}
|
||||
|
||||
void Shrink(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
r_mat_mv_push();
|
||||
apply_common_transforms(p, t);
|
||||
|
||||
|
@ -959,7 +1031,7 @@ void Shrink(Projectile *p, int t) {
|
|||
r_mat_mv_pop();
|
||||
}
|
||||
|
||||
void DeathShrink(Projectile *p, int t) {
|
||||
void DeathShrink(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
r_mat_mv_push();
|
||||
apply_common_transforms(p, t);
|
||||
|
||||
|
@ -972,7 +1044,7 @@ void DeathShrink(Projectile *p, int t) {
|
|||
r_mat_mv_pop();
|
||||
}
|
||||
|
||||
void GrowFade(Projectile *p, int t) {
|
||||
void GrowFade(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
r_mat_mv_push();
|
||||
apply_common_transforms(p, t);
|
||||
|
||||
|
@ -988,7 +1060,7 @@ void GrowFade(Projectile *p, int t) {
|
|||
r_mat_mv_pop();
|
||||
}
|
||||
|
||||
void Fade(Projectile *p, int t) {
|
||||
void Fade(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
r_mat_mv_push();
|
||||
apply_common_transforms(p, t);
|
||||
ProjDrawCore(p, color_mul_scalar(COLOR_COPY(&p->color), 1 - t/(double)p->timeout));
|
||||
|
@ -1010,33 +1082,111 @@ static void ScaleFadeImpl(Projectile *p, int t, int fade_exponent) {
|
|||
r_mat_mv_pop();
|
||||
}
|
||||
|
||||
void ScaleFade(Projectile *p, int t) {
|
||||
void ScaleFade(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
ScaleFadeImpl(p, t, 1);
|
||||
}
|
||||
|
||||
void ScaleSquaredFade(Projectile *p, int t) {
|
||||
void ScaleSquaredFade(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
ScaleFadeImpl(p, t, 2);
|
||||
}
|
||||
|
||||
void Petal(Projectile *p, int t) {
|
||||
float x = creal(p->args[2]);
|
||||
float y = cimag(p->args[2]);
|
||||
float z = creal(p->args[3]);
|
||||
static void pdraw_scalefade_func(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
cmplx32 scale0 = args[0].as_cmplx;
|
||||
cmplx32 scale1 = args[1].as_cmplx;
|
||||
float32 opacity0 = args[2].as_float[0];
|
||||
float32 opacity1 = args[2].as_float[1];
|
||||
float32 opacity_exp = args[3].as_float[0];
|
||||
|
||||
float r = sqrt(x*x+y*y+z*z);
|
||||
x /= r; y /= r; z /= r;
|
||||
float32 timefactor = t / p->timeout;
|
||||
|
||||
cmplx32 scale = clerpf(scale0, scale1, timefactor);
|
||||
float32 opacity = lerpf(opacity0, opacity1, timefactor);
|
||||
opacity = powf(opacity, opacity_exp);
|
||||
|
||||
SpriteParamsBuffer spbuf;
|
||||
SpriteParams sp = projectile_sprite_params(p, &spbuf);
|
||||
spbuf.shader_params.vector[0] *= opacity;
|
||||
sp.scale.as_cmplx = cwmulf(sp.scale.as_cmplx, scale);
|
||||
|
||||
r_draw_sprite(&sp);
|
||||
}
|
||||
|
||||
ProjDrawRule pdraw_timeout_scalefade_exp(cmplx32 scale0, cmplx32 scale1, float32 opacity0, float32 opacity1, float32 opacity_exp) {
|
||||
if(cimagf(scale0) == 0) {
|
||||
scale0 = CMPLXF(crealf(scale0), crealf(scale0));
|
||||
}
|
||||
|
||||
if(cimagf(scale1) == 0) {
|
||||
scale1 = CMPLXF(crealf(scale1), crealf(scale1));
|
||||
}
|
||||
|
||||
return (ProjDrawRule) {
|
||||
.func = pdraw_scalefade_func,
|
||||
.args[0].as_cmplx = scale0,
|
||||
.args[1].as_cmplx = scale1,
|
||||
.args[2].as_float = { opacity0, opacity1 },
|
||||
.args[3].as_float = { opacity_exp },
|
||||
};
|
||||
}
|
||||
|
||||
ProjDrawRule pdraw_timeout_scalefade(cmplx32 scale0, cmplx32 scale1, float32 opacity0, float32 opacity1) {
|
||||
return pdraw_timeout_scalefade_exp(scale0, scale1, opacity0, opacity1, 1.0f);
|
||||
}
|
||||
|
||||
ProjDrawRule pdraw_timeout_scale(cmplx32 scale0, cmplx32 scale1) {
|
||||
return pdraw_timeout_scalefade(scale0, scale1, 1, 1);
|
||||
}
|
||||
|
||||
ProjDrawRule pdraw_timeout_fade(float32 opacity0, float32 opacity1) {
|
||||
return pdraw_timeout_scalefade(1+I, 1+I, opacity0, opacity1);
|
||||
}
|
||||
|
||||
static void pdraw_petal_func(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
vec3 rot_axis = {
|
||||
args[0].as_float[0],
|
||||
args[0].as_float[1],
|
||||
args[1].as_float[0],
|
||||
};
|
||||
|
||||
float32 rot_angle = args[1].as_float[1];
|
||||
|
||||
SpriteParamsBuffer spbuf;
|
||||
SpriteParams sp = projectile_sprite_params(p, &spbuf);
|
||||
glm_vec3_copy(rot_axis, sp.rotation.vector);
|
||||
sp.rotation.angle = DEG2RAD*t*4.0f + rot_angle;
|
||||
|
||||
spbuf.shader_params.vector[0] *= (1.0f - projectile_timeout_factor(p));
|
||||
|
||||
r_disable(RCAP_CULL_FACE);
|
||||
r_mat_mv_push();
|
||||
r_mat_mv_translate(creal(p->pos), cimag(p->pos),0);
|
||||
r_mat_mv_rotate(DEG2RAD * (t*4.0 + cimag(p->args[3])), x, y, z);
|
||||
ProjDrawCore(p, &p->color);
|
||||
r_mat_mv_pop();
|
||||
r_draw_sprite(&sp);
|
||||
}
|
||||
|
||||
ProjDrawRule pdraw_petal(float32 rot_angle, vec3 rot_axis) {
|
||||
glm_vec3_normalize(rot_axis);
|
||||
float32 x = rot_axis[0];
|
||||
float32 y = rot_axis[1];
|
||||
float32 z = rot_axis[2];
|
||||
|
||||
return (ProjDrawRule) {
|
||||
.func = pdraw_petal_func,
|
||||
.args[0].as_float = { x, y },
|
||||
.args[1].as_float = { z, rot_angle },
|
||||
};
|
||||
}
|
||||
|
||||
ProjDrawRule pdraw_petal_random(void) {
|
||||
float32 x = rng_f32();
|
||||
float32 y = rng_f32();
|
||||
float32 z = rng_f32();
|
||||
float32 rot_angle = rng_f32_angle();
|
||||
|
||||
return pdraw_petal(rot_angle, (vec3) { x, y, z });
|
||||
}
|
||||
|
||||
void petal_explosion(int n, cmplx pos) {
|
||||
for(int i = 0; i < n; i++) {
|
||||
RNG_ARRAY(R, 6);
|
||||
cmplx v = rng_dir();
|
||||
v *= rng_range(3, 8);
|
||||
real t = rng_real();
|
||||
|
||||
PARTICLE(
|
||||
|
@ -1044,15 +1194,10 @@ void petal_explosion(int n, cmplx pos) {
|
|||
.pos = pos,
|
||||
.color = RGBA(sin(5*t) * t, cos(5*t) * t, 0.5 * t, 0),
|
||||
.rule = asymptotic,
|
||||
.draw_rule = Petal,
|
||||
.args = {
|
||||
vrng_range(R[0], 3, 8) * vrng_dir(R[1]),
|
||||
5,
|
||||
vrng_real(R[2]) + vrng_real(R[3])*I,
|
||||
vrng_real(R[4]) + vrng_range(R[5], 0, 360)*I,
|
||||
},
|
||||
.move = move_asymptotic_simple(v, 5),
|
||||
.draw_rule = pdraw_petal_random(),
|
||||
// TODO: maybe remove this noreflect, there shouldn't be a cull mode mess anymore
|
||||
.flags = PFLAG_NOREFLECT | (n % 2 ? 0 : PFLAG_REQUIREDPARTICLE),
|
||||
.flags = PFLAG_NOREFLECT | (n % 2 ? 0 : PFLAG_REQUIREDPARTICLE) | PFLAG_MANUALANGLE,
|
||||
.layer = LAYER_PARTICLE_PETAL,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -34,9 +34,19 @@ typedef LIST_ANCHOR(Projectile) ProjectileList;
|
|||
typedef LIST_INTERFACE(Projectile) ProjectileListInterface;
|
||||
|
||||
typedef int (*ProjRule)(Projectile *p, int t);
|
||||
typedef void (*ProjDrawRule)(Projectile *p, int t);
|
||||
// typedef void (*ProjDrawRule)(Projectile *p, int t);
|
||||
typedef bool (*ProjPredicate)(Projectile *p);
|
||||
|
||||
typedef union {
|
||||
float32 as_float[2];
|
||||
cmplx32 as_cmplx;
|
||||
} ProjDrawRuleArgs[RULE_ARGC];
|
||||
|
||||
typedef struct ProjDrawRule {
|
||||
void (*func)(Projectile *p, int t, ProjDrawRuleArgs args);
|
||||
ProjDrawRuleArgs args;
|
||||
} ProjDrawRule;
|
||||
|
||||
typedef enum {
|
||||
PROJ_INVALID,
|
||||
|
||||
|
@ -90,7 +100,7 @@ struct Projectile {
|
|||
CoEvent killed;
|
||||
} events;
|
||||
Color color;
|
||||
ShaderCustomParams shader_params;
|
||||
attr_deprecated("this won't work") ShaderCustomParams shader_params;
|
||||
BlendMode blend;
|
||||
int birthtime;
|
||||
float damage;
|
||||
|
@ -101,6 +111,9 @@ struct Projectile {
|
|||
ProjFlags flags;
|
||||
uint clear_flags;
|
||||
|
||||
cmplx32 scale;
|
||||
float32 opacity;
|
||||
|
||||
// XXX: this is in frames of course, but needs to be float
|
||||
// to avoid subtle truncation and integer division gotchas.
|
||||
float timeout;
|
||||
|
@ -121,7 +134,7 @@ typedef struct ProjArgs {
|
|||
Sprite *sprite_ptr;
|
||||
const char *shader;
|
||||
ShaderProgram *shader_ptr;
|
||||
const ShaderCustomParams *shader_params;
|
||||
attr_deprecated("this won't work") const ShaderCustomParams *shader_params;
|
||||
ProjectileList *dest;
|
||||
ProjRule rule;
|
||||
cmplx args[RULE_ARGC];
|
||||
|
@ -139,6 +152,9 @@ typedef struct ProjArgs {
|
|||
int max_viewport_dist;
|
||||
drawlayer_t layer;
|
||||
|
||||
cmplx32 scale;
|
||||
float32 opacity;
|
||||
|
||||
// XXX: this is in frames of course, but needs to be float
|
||||
// to avoid subtle truncation and integer division gotchas.
|
||||
float timeout;
|
||||
|
@ -204,6 +220,7 @@ Projectile* spawn_projectile_clear_effect(Projectile *proj);
|
|||
Projectile* spawn_projectile_highlight_effect(Projectile *proj);
|
||||
|
||||
void projectile_set_prototype(Projectile *p, ProjPrototype *proto);
|
||||
void projectile_set_layer(Projectile *p, drawlayer_t layer);
|
||||
|
||||
bool clear_projectile(Projectile *proj, uint flags);
|
||||
void kill_projectile(Projectile *proj);
|
||||
|
@ -212,16 +229,26 @@ int linear(Projectile *p, int t);
|
|||
int accelerated(Projectile *p, int t);
|
||||
int asymptotic(Projectile *p, int t);
|
||||
|
||||
void ProjDrawCore(Projectile *proj, const Color *c);
|
||||
void ProjDraw(Projectile *p, int t);
|
||||
void ProjNoDraw(Projectile *proj, int t);
|
||||
#define DEPRECATED_DRAW_RULE attr_deprecated("")
|
||||
|
||||
void Shrink(Projectile *p, int t);
|
||||
void DeathShrink(Projectile *p, int t);
|
||||
void Fade(Projectile *p, int t);
|
||||
void GrowFade(Projectile *p, int t);
|
||||
void ScaleFade(Projectile *p, int t);
|
||||
void ScaleSquaredFade(Projectile *p, int t);
|
||||
void ProjDrawCore(Projectile *proj, const Color *c);
|
||||
void ProjDraw(Projectile *proj, int t, ProjDrawRuleArgs args) DEPRECATED_DRAW_RULE;
|
||||
|
||||
void Shrink(Projectile *p, int t, ProjDrawRuleArgs) DEPRECATED_DRAW_RULE;
|
||||
void DeathShrink(Projectile *p, int t, ProjDrawRuleArgs) DEPRECATED_DRAW_RULE;
|
||||
void Fade(Projectile *p, int t, ProjDrawRuleArgs) DEPRECATED_DRAW_RULE;
|
||||
void GrowFade(Projectile *p, int t, ProjDrawRuleArgs) DEPRECATED_DRAW_RULE;
|
||||
void ScaleFade(Projectile *p, int t, ProjDrawRuleArgs) DEPRECATED_DRAW_RULE;
|
||||
void ScaleSquaredFade(Projectile *p, int t, ProjDrawRuleArgs) DEPRECATED_DRAW_RULE;
|
||||
|
||||
ProjDrawRule pdraw_basic(void);
|
||||
ProjDrawRule pdraw_timeout_scalefade_exp(cmplx32 scale0, cmplx32 scale1, float32 opacity0, float32 opacity1, float32 opacity_exp);
|
||||
ProjDrawRule pdraw_timeout_scalefade(cmplx32 scale0, cmplx32 scale1, float32 opacity0, float32 opacity1);
|
||||
ProjDrawRule pdraw_timeout_scale(cmplx32 scale0, cmplx32 scale1);
|
||||
ProjDrawRule pdraw_timeout_fade(float32 opacity0, float32 opacity1);
|
||||
ProjDrawRule pdraw_petal(float32 rot_angle, vec3 rot_axis);
|
||||
ProjDrawRule pdraw_petal_random(void);
|
||||
ProjDrawRule pdraw_blast(void);
|
||||
|
||||
void Petal(Projectile *p, int t);
|
||||
void petal_explosion(int n, cmplx pos);
|
||||
|
@ -232,5 +259,9 @@ void projectiles_preload(void);
|
|||
void projectiles_free(void);
|
||||
|
||||
cmplx projectile_graze_size(Projectile *p);
|
||||
float32 projectile_timeout_factor(Projectile *p);
|
||||
int projectile_time(Projectile *p);
|
||||
|
||||
SpriteParams projectile_sprite_params(Projectile *proj, SpriteParamsBuffer *spbuf);
|
||||
|
||||
#endif // IGUARD_projectile_h
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
#include "util/crap.h"
|
||||
#include "util/miscmath.h"
|
||||
|
||||
#define RNG_DEPRECATED attr_deprecated("Use the new rng_ API")
|
||||
// #define RNG_DEPRECATED attr_deprecated("Use the new rng_ API")
|
||||
#define RNG_DEPRECATED
|
||||
|
||||
typedef struct RandomState {
|
||||
uint64_t state[4];
|
||||
|
|
|
@ -361,13 +361,17 @@ typedef struct SpriteStateParams {
|
|||
ShaderProgram *shader;
|
||||
} SpriteStateParams;
|
||||
|
||||
typedef struct SpriteScaleParams {
|
||||
union {
|
||||
float x;
|
||||
float both;
|
||||
typedef union SpriteScaleParams {
|
||||
struct {
|
||||
union {
|
||||
float x;
|
||||
float both;
|
||||
};
|
||||
|
||||
float y;
|
||||
};
|
||||
|
||||
float y;
|
||||
cmplx32 as_cmplx;
|
||||
} SpriteScaleParams;
|
||||
|
||||
typedef struct SpriteRotationParams {
|
||||
|
@ -388,6 +392,8 @@ typedef struct SpriteParams {
|
|||
ShaderProgram *shader_ptr;
|
||||
|
||||
Texture *aux_textures[R_NUM_SPRITE_AUX_TEXTURES];
|
||||
|
||||
// TODO: maybe embed these by value and get rid of SpriteParamsBuffer?
|
||||
const Color *color;
|
||||
const ShaderCustomParams *shader_params;
|
||||
|
||||
|
@ -399,6 +405,11 @@ typedef struct SpriteParams {
|
|||
SpriteFlipParams flip;
|
||||
} SpriteParams;
|
||||
|
||||
typedef struct SpriteParamsBuffer {
|
||||
Color color;
|
||||
ShaderCustomParams shader_params;
|
||||
} SpriteParamsBuffer;
|
||||
|
||||
// Matches vertex buffer layout
|
||||
typedef struct SpriteInstanceAttribs {
|
||||
mat4 mv_transform;
|
||||
|
|
|
@ -1304,7 +1304,7 @@ TASK_WITH_INTERFACE(icy_storm, BossAttack) {
|
|||
// play_sound("shot_special1");
|
||||
|
||||
ENT_ARRAY_FOREACH(&snowflake_projs, Projectile *p, {
|
||||
spawn_projectile_highlight_effect(p)->shader_params.vector[0] = 0.75;
|
||||
spawn_projectile_highlight_effect(p)->opacity = 0.25;
|
||||
color_lerp(&p->color, RGB(0.5, 0.5, 0.5), 0.5);
|
||||
p->move.velocity = 2 * cdir(p->angle);
|
||||
p->move.acceleration = -cdir(p->angle) * difficulty_value(0.1, 0.15, 0.2, 0.2);
|
||||
|
|
|
@ -861,7 +861,8 @@ static int wriggle_rocket_laserbullet(Projectile *p, int time) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void wriggle_slave_part_draw(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void wriggle_slave_part_draw(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
float b = 1 - t / (double)p->timeout;
|
||||
r_mat_mv_push();
|
||||
r_mat_mv_translate(creal(p->pos), cimag(p->pos), 0);
|
||||
|
@ -1203,7 +1204,8 @@ void wriggle_light_singularity(Boss *boss, int time) {
|
|||
|
||||
}
|
||||
|
||||
static void wriggle_fstorm_proj_draw(Projectile *p, int time) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void wriggle_fstorm_proj_draw(Projectile *p, int time, ProjDrawRuleArgs args) {
|
||||
float f = 1-min(time/60.0,1);
|
||||
r_mat_mv_push();
|
||||
r_mat_mv_translate(creal(p->pos), cimag(p->pos), 0);
|
||||
|
@ -1249,7 +1251,7 @@ static int wriggle_fstorm_proj(Projectile *p, int time) {
|
|||
p->args[1] *= 2/cabs(p->args[1]);
|
||||
p->angle = carg(p->args[1]);
|
||||
p->birthtime = global.frames;
|
||||
p->draw_rule = wriggle_fstorm_proj_draw;
|
||||
p->draw_rule = (ProjDrawRule) { wriggle_fstorm_proj_draw };
|
||||
p->sprite = NULL;
|
||||
projectile_set_prototype(p, pp_rice);
|
||||
spawn_projectile_highlight_effect(p);
|
||||
|
|
|
@ -1223,7 +1223,8 @@ static int kurumi_extra_bigfairy1(Enemy *e, int time) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void kurumi_extra_drainer_draw(Projectile *p, int time) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void kurumi_extra_drainer_draw(Projectile *p, int time, ProjDrawRuleArgs args) {
|
||||
cmplx org = p->pos;
|
||||
cmplx targ = p->args[1];
|
||||
double a = 0.5 * creal(p->args[2]);
|
||||
|
|
|
@ -197,7 +197,8 @@ static int scythe_mid(Enemy *e, int t) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void ScytheTrail(Projectile *p, int t) {
|
||||
DEPRECATED_DRAW_RULE
|
||||
static void ScytheTrail(Projectile *p, int t, ProjDrawRuleArgs args) {
|
||||
r_mat_mv_push();
|
||||
r_mat_mv_translate(creal(p->pos), cimag(p->pos), 0);
|
||||
r_mat_mv_rotate(p->angle + (M_PI * 0.5), 0, 0, 1);
|
||||
|
@ -1085,14 +1086,6 @@ static int broglie_particle(Projectile *p, int t) {
|
|||
return ACTION_ACK;
|
||||
}
|
||||
|
||||
/*
|
||||
if(t == EVENT_BIRTH) {
|
||||
// hidden and no collision detection until scattertime
|
||||
p->type = FakeProj;
|
||||
p->draw = ProjNoDraw;
|
||||
}
|
||||
*/
|
||||
|
||||
if(t < 0) {
|
||||
return ACTION_ACK;
|
||||
}
|
||||
|
@ -1112,7 +1105,7 @@ static int broglie_particle(Projectile *p, int t) {
|
|||
}
|
||||
} else {
|
||||
if(t == scattertime && p->type != PROJ_DEAD) {
|
||||
p->draw_rule = ProjDraw;
|
||||
projectile_set_layer(p, LAYER_BULLET);
|
||||
p->flags &= ~(PFLAG_NOCLEARBONUS | PFLAG_NOCLEAREFFECT | PFLAG_NOCOLLISION);
|
||||
|
||||
double angle_ampl = creal(p->args[3]);
|
||||
|
@ -1215,7 +1208,7 @@ static int broglie_charge(Projectile *p, int t) {
|
|||
fast ? 2.0 : 1.5,
|
||||
(1 + 2 * ((global.diff - 1) / (double)(D_Lunatic - 1))) * M_PI/11 + s_freq*10*I
|
||||
},
|
||||
.draw_rule = ProjNoDraw,
|
||||
.layer = LAYER_NODRAW,
|
||||
.flags = PFLAG_NOCLEARBONUS | PFLAG_NOCLEAREFFECT | PFLAG_NOSPAWNEFFECTS | PFLAG_NOCOLLISION,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -184,35 +184,8 @@ typedef cmplx64 cmplx;
|
|||
typedef struct { alignas(TAISEI_BUILDCONF_MALLOC_ALIGNMENT) char a; } max_align_t;
|
||||
#endif
|
||||
|
||||
// In case the C11 CMPLX macro is not present, try our best to provide a substitute
|
||||
#if !defined CMPLX
|
||||
#undef HAS_BUILTIN_COMPLEX
|
||||
|
||||
#if defined __has_builtin
|
||||
#if __has_builtin(__builtin_complex)
|
||||
#define HAS_BUILTIN_COMPLEX
|
||||
#endif
|
||||
#else
|
||||
#if defined __GNUC__ && defined __GNUC_MINOR__
|
||||
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
|
||||
#define HAS_BUILTIN_COMPLEX
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined HAS_BUILTIN_COMPLEX
|
||||
#define CMPLX(re,im) __builtin_complex((double)(re), (double)(im))
|
||||
#elif defined __clang__
|
||||
#define CMPLX(re,im) (__extension__ (_Complex double){(double)(re), (double)(im)})
|
||||
#elif defined _Imaginary_I
|
||||
#define CMPLX(re,im) (_Complex double)((double)(re) + _Imaginary_I * (double)(im))
|
||||
#else
|
||||
#define CMPLX(re,im) (_Complex double)((double)(re) + _Complex_I * (double)(im))
|
||||
#endif
|
||||
#elif defined __EMSCRIPTEN__ && defined __clang__
|
||||
// CMPLX from emscripten headers uses the clang-specific syntax without __extension__
|
||||
#pragma clang diagnostic ignored "-Wcomplex-component-init"
|
||||
#endif
|
||||
// polyfill CMPLX macros
|
||||
#include "compat_cmplx.h"
|
||||
|
||||
/*
|
||||
* Abstract away the nasty GNU attribute syntax.
|
||||
|
|
62
src/util/compat_cmplx.h
Normal file
62
src/util/compat_cmplx.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_util_compat_cmplx_h
|
||||
#define IGUARD_util_compat_cmplx_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#undef HAS_BUILTIN_COMPLEX
|
||||
|
||||
#if defined __has_builtin
|
||||
#if __has_builtin(__builtin_complex)
|
||||
#define HAS_BUILTIN_COMPLEX
|
||||
#endif
|
||||
#else
|
||||
#if defined __GNUC__ && defined __GNUC_MINOR__
|
||||
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
|
||||
#define HAS_BUILTIN_COMPLEX
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// In case the C11 CMPLX macro is not present, try our best to provide a substitute
|
||||
|
||||
#if !defined CMPLX
|
||||
#if defined HAS_BUILTIN_COMPLEX
|
||||
#define CMPLX(re,im) __builtin_complex((double)(re), (double)(im))
|
||||
#elif defined __clang__
|
||||
#define CMPLX(re,im) (__extension__ (_Complex double){ (double)(re), (double)(im) })
|
||||
#elif defined _Imaginary_I
|
||||
#define CMPLX(re,im) (_Complex double)((double)(re) + _Imaginary_I * (double)(im))
|
||||
#else
|
||||
#define CMPLX(re,im) (_Complex double)((double)(re) + _Complex_I * (double)(im))
|
||||
#endif
|
||||
#elif defined __EMSCRIPTEN__ && defined __clang__
|
||||
// CMPLX from emscripten headers uses the clang-specific syntax without __extension__
|
||||
#pragma clang diagnostic ignored "-Wcomplex-component-init"
|
||||
#endif
|
||||
|
||||
// same for CMPLXF
|
||||
|
||||
#if !defined CMPLXF
|
||||
#if defined HAS_BUILTIN_COMPLEX
|
||||
#define CMPLXF(re,im) __builtin_complex((float)(re), (float)(im))
|
||||
#elif defined __clang__
|
||||
#define CMPLXF(re,im) (__extension__ (_Complex float){ (float)(re), (float)(im) })
|
||||
#elif defined _Imaginary_I
|
||||
#define CMPLXF(re,im) (_Complex float)((float)(re) + _Imaginary_I * (float)(im))
|
||||
#else
|
||||
#define CMPLXF(re,im) (_Complex float)((float)(re) + _Complex_I * (float)(im))
|
||||
#endif
|
||||
#elif defined __EMSCRIPTEN__ && defined __clang__
|
||||
// CMPLXF from emscripten headers uses the clang-specific syntax without __extension__
|
||||
#pragma clang diagnostic ignored "-Wcomplex-component-init"
|
||||
#endif
|
||||
|
||||
#endif // IGUARD_util_compat_cmplx_h
|
|
@ -29,4 +29,10 @@
|
|||
PRAGMA(GCC diagnostic pop)
|
||||
#endif
|
||||
|
||||
typedef float (*glm_ease_t)(float);
|
||||
|
||||
INLINE float glm_ease_apply(glm_ease_t ease, float f) {
|
||||
return ease ? ease(f) : f;
|
||||
}
|
||||
|
||||
#endif // IGUARD_util_glm_h
|
||||
|
|
|
@ -15,10 +15,18 @@ double lerp(double v0, double v1, double f) {
|
|||
return f * (v1 - v0) + v0;
|
||||
}
|
||||
|
||||
float lerpf(float v0, float v1, float f) {
|
||||
return f * (v1 - v0) + v0;
|
||||
}
|
||||
|
||||
cmplx clerp(cmplx v0, cmplx v1, double f) {
|
||||
return f * (v1 - v0) + v0;
|
||||
}
|
||||
|
||||
cmplx32 clerpf(cmplx32 v0, cmplx32 v1, float32 f) {
|
||||
return f * (v1 - v0) + v0;
|
||||
}
|
||||
|
||||
double approach(double v, double t, double d) {
|
||||
if(v < t) {
|
||||
v += d;
|
||||
|
@ -117,6 +125,14 @@ cmplx cdir(double angle) {
|
|||
#endif
|
||||
}
|
||||
|
||||
cmplx cwmul(cmplx c0, cmplx c1) {
|
||||
return CMPLX(creal(c0)*creal(c1), cimag(c0)*cimag(c1));
|
||||
}
|
||||
|
||||
cmplx32 cwmulf(cmplx32 c0, cmplx32 c1) {
|
||||
return CMPLXF(crealf(c0)*crealf(c1), cimagf(c0)*cimagf(c1));
|
||||
}
|
||||
|
||||
double psin(double x) {
|
||||
return 0.5 + 0.5 * sin(x);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
#define M_TAU (M_PI * 2)
|
||||
|
||||
double lerp(double v0, double v1, double f) attr_const;
|
||||
float lerpf(float v0, float v1, float f) attr_const;
|
||||
cmplx clerp(cmplx v0, cmplx v1, double f) attr_const;
|
||||
cmplx32 clerpf(cmplx32 v0, cmplx32 v1, float32 f) attr_const;
|
||||
intmax_t imin(intmax_t, intmax_t) attr_const;
|
||||
intmax_t imax(intmax_t, intmax_t) attr_const;
|
||||
uintmax_t umin(uintmax_t, uintmax_t) attr_const;
|
||||
|
@ -41,6 +43,8 @@ void capproach_asymptotic_p(cmplx *val, cmplx target, double rate, double epsilo
|
|||
cmplx cnormalize(cmplx c) attr_const;
|
||||
cmplx cclampabs(cmplx c, double maxabs) attr_const;
|
||||
cmplx cdir(double angle) attr_const;
|
||||
cmplx cwmul(cmplx c0, cmplx c1) attr_const;
|
||||
cmplx32 cwmulf(cmplx32 c0, cmplx32 c1) attr_const;
|
||||
double psin(double) attr_const;
|
||||
int sign(double) attr_const;
|
||||
double swing(double x, double s) attr_const;
|
||||
|
|
Loading…
Reference in a new issue