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,
|
||||
);
|
||||