Projectile prototypes system (#118)
* wip projectile prototypes * Partial fix for replay desyncs * some YoumuA fixes * fix various ToE problems * fix MarisaB * fix master spark * fix iku slave particle position * this timeout was somehow halved during the changes * remove some v1.2 compat hacks
This commit is contained in:
parent
0761377f41
commit
f67396423e
26 changed files with 736 additions and 441 deletions
45
src/boss.c
45
src/boss.c
|
@ -166,7 +166,7 @@ static bool attack_is_over(Attack *a) {
|
|||
}
|
||||
|
||||
static void BossGlow(Projectile *p, int t) {
|
||||
float s = 1.0+t/p->args[0]*0.5;
|
||||
float s = 1.0+t/(double)p->timeout*0.5;
|
||||
float fade = 1 - (1.5 - s);
|
||||
float deform = 5 - 10 * fade * fade;
|
||||
|
||||
|
@ -185,7 +185,7 @@ static int boss_glow(Projectile *p, int t) {
|
|||
if(t == EVENT_DEATH) {
|
||||
free(p->sprite);
|
||||
}
|
||||
return timeout_linear(p,t);
|
||||
return linear(p, t);
|
||||
}
|
||||
|
||||
static Projectile* spawn_boss_glow(Boss *boss, Color clr, int timeout) {
|
||||
|
@ -197,7 +197,7 @@ static Projectile* spawn_boss_glow(Boss *boss, Color clr, int timeout) {
|
|||
.color = clr,
|
||||
.rule = boss_glow,
|
||||
.draw_rule = BossGlow,
|
||||
.args = { timeout },
|
||||
.timeout = timeout,
|
||||
.angle = M_PI * 2 * frand(),
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
|
@ -212,11 +212,14 @@ static void spawn_particle_effects(Boss *boss) {
|
|||
bool is_extra = cur && cur->type == AT_ExtraSpell && global.frames >= cur->starttime;
|
||||
|
||||
if(!(global.frames % 13) && !is_extra) {
|
||||
complex v = cexp(I*global.frames);
|
||||
|
||||
PARTICLE("smoke", v, shadowcolor, enemy_flare,
|
||||
.draw_rule = EnemyFlareShrink,
|
||||
.args = { 180, 0, add_ref(boss), },
|
||||
PARTICLE(
|
||||
.sprite = "smoke",
|
||||
.pos = cexp(I*global.frames),
|
||||
.color = shadowcolor,
|
||||
.rule = enemy_flare,
|
||||
.timeout = 180,
|
||||
.draw_rule = Shrink,
|
||||
.args = { 0, add_ref(boss), },
|
||||
.angle = M_PI * 2 * frand(),
|
||||
.flags = PFLAG_DRAWADD,
|
||||
);
|
||||
|
@ -412,10 +415,11 @@ void boss_rule_extra(Boss *boss, float alpha) {
|
|||
0.5 + 0.2 * psina * (1-v),
|
||||
0.5 + 0.5 * psina * v
|
||||
),
|
||||
.rule = timeout_linear,
|
||||
.rule = linear,
|
||||
.timeout = 30*lt,
|
||||
.draw_rule = GrowFade,
|
||||
.flags = PFLAG_DRAWADD,
|
||||
.args = { 30*lt, vel * (1 - 2 * !(global.frames % 10)), 2.5 },
|
||||
.args = { vel * (1 - 2 * !(global.frames % 10)), 2.5 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -698,16 +702,18 @@ void process_boss(Boss **pboss) {
|
|||
|
||||
for(int i = 0; i < 256; i++) {
|
||||
tsrand_fill(3);
|
||||
PARTICLE("flare", boss->pos, 0, timeout_linear, .draw_rule = Fade,
|
||||
.args = {
|
||||
60 + 10 * afrand(2),
|
||||
(3+afrand(0)*10)*cexp(I*tsrand_a(1))
|
||||
},
|
||||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.pos = boss->pos,
|
||||
.timeout = 60 + 10 * afrand(2),
|
||||
.rule = linear,
|
||||
.draw_rule = Fade,
|
||||
.args = { (3+afrand(0)*10)*cexp(I*tsrand_a(1)) },
|
||||
);
|
||||
}
|
||||
|
||||
PARTICLE("blast", boss->pos, 0, timeout, { 60, 3 }, .draw_rule = GrowFade);
|
||||
PARTICLE("blast", boss->pos, 0, timeout, { 70, 2.5 }, .draw_rule = GrowFade);
|
||||
PARTICLE("blast", boss->pos, 0, .timeout = 60, .args = { 0, 3.0 }, .draw_rule = GrowFade);
|
||||
PARTICLE("blast", boss->pos, 0, .timeout = 70, .args = { 0, 2.5 }, .draw_rule = GrowFade);
|
||||
}
|
||||
|
||||
play_sound_ex("bossdeath", BOSS_DEATH_DELAY * 2, false);
|
||||
|
@ -818,9 +824,10 @@ void boss_start_attack(Boss *b, Attack *a) {
|
|||
.sprite = "stain",
|
||||
.pos = VIEWPORT_W/2 + VIEWPORT_W/4*anfrand(0)+I*VIEWPORT_H/2+I*anfrand(1)*30,
|
||||
.color = rgb(0.2,0.3,0.4),
|
||||
.rule = timeout_linear,
|
||||
.rule = linear,
|
||||
.timeout = 50,
|
||||
.draw_rule = GrowFade,
|
||||
.args = { 50, sign(anfrand(2))*10*(1+afrand(3)) },
|
||||
.args = { sign(anfrand(2))*10*(1+afrand(3)) },
|
||||
.flags = PFLAG_DRAWADD,
|
||||
);
|
||||
}
|
||||
|
|
77
src/enemy.c
77
src/enemy.c
|
@ -76,14 +76,19 @@ void* _delete_enemy(List **enemies, List* enemy, void *arg) {
|
|||
for(int i = 0; i < 10; i++) {
|
||||
tsrand_fill(2);
|
||||
|
||||
PARTICLE("flare", e->pos, 0, timeout_linear, .draw_rule = Fade,
|
||||
.args = { 10, (3+afrand(0)*10)*cexp(I*afrand(1)*2*M_PI) },
|
||||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.pos = e->pos,
|
||||
.timeout = 10,
|
||||
.rule = linear,
|
||||
.draw_rule = Fade,
|
||||
.args = { (3+afrand(0)*10)*cexp(I*afrand(1)*2*M_PI) },
|
||||
);
|
||||
}
|
||||
|
||||
PARTICLE("blast", e->pos, 0, blast_timeout, { 20 }, .draw_rule = Blast, .flags = PFLAG_REQUIREDPARTICLE);
|
||||
PARTICLE("blast", e->pos, 0, blast_timeout, { 20 }, .draw_rule = Blast, .flags = PFLAG_REQUIREDPARTICLE);
|
||||
PARTICLE("blast", e->pos, 0, blast_timeout, { 15 }, .draw_rule = GrowFade, .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 = 20, .draw_rule = Blast, .flags = PFLAG_REQUIREDPARTICLE);
|
||||
PARTICLE(.proto = pp_blast, .pos = e->pos, .timeout = 15, .draw_rule = GrowFade, .flags = PFLAG_REQUIREDPARTICLE);
|
||||
}
|
||||
|
||||
e->logic_rule(e, EVENT_DEATH);
|
||||
|
@ -135,43 +140,30 @@ void killall(Enemy *enemies) {
|
|||
e->hp = 0;
|
||||
}
|
||||
|
||||
int enemy_flare(Projectile *p, int t) { // a[0] timeout, a[1] velocity, a[2] ref to enemy
|
||||
if(t >= creal(p->args[0]) || REF(p->args[2]) == NULL) {
|
||||
int enemy_flare(Projectile *p, int t) { // a[0] velocity, a[1] ref to enemy
|
||||
if(t == EVENT_DEATH) {
|
||||
free_ref(p->args[1]);
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
Enemy *owner = REF(p->args[1]);
|
||||
|
||||
/*
|
||||
if(REF(p->args[1]) == NULL) {
|
||||
return ACTION_DESTROY;
|
||||
} if(t == EVENT_DEATH) {
|
||||
free_ref(p->args[2]);
|
||||
return 1;
|
||||
} else if(t < 0) {
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
if(t < 0) {
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
p->pos += p->args[1];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EnemyFlareShrink(Projectile *p, int t) {
|
||||
Enemy *e = (Enemy *)REF(p->args[2]);
|
||||
|
||||
if(e == NULL) {
|
||||
return;
|
||||
if(owner != NULL) {
|
||||
p->args[3] = owner->pos;
|
||||
}
|
||||
|
||||
r_mat_push();
|
||||
float s = 2.0-t/p->args[0]*2;
|
||||
|
||||
r_mat_translate(creal(e->pos + p->pos), cimag(e->pos + p->pos), 0);
|
||||
|
||||
if(p->angle != M_PI*0.5) {
|
||||
r_mat_rotate_deg(p->angle*180/M_PI+90, 0, 0, 1);
|
||||
}
|
||||
|
||||
if(s != 1) {
|
||||
r_mat_scale(s, s, 1);
|
||||
}
|
||||
|
||||
ProjDrawCore(p, p->color);
|
||||
r_mat_pop();
|
||||
p->pos = p->pos0 + p->args[3] + p->args[0]*t;
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
void BigFairy(Enemy *e, int t, bool render) {
|
||||
|
@ -179,9 +171,14 @@ void BigFairy(Enemy *e, int t, bool render) {
|
|||
if(!(t % 5)) {
|
||||
complex offset = (frand()-0.5)*30 + (frand()-0.5)*20.0*I;
|
||||
|
||||
PARTICLE("smoothdot", offset, rgb(0,0.2,0.3), enemy_flare,
|
||||
.draw_rule = EnemyFlareShrink,
|
||||
.args = { 50, (-50.0*I-offset)/50.0, add_ref(e) },
|
||||
PARTICLE(
|
||||
.sprite = "smoothdot",
|
||||
.pos = offset,
|
||||
.color = rgb(0,0.2,0.3),
|
||||
.rule = enemy_flare,
|
||||
.draw_rule = Shrink,
|
||||
.timeout = 50,
|
||||
.args = { (-50.0*I-offset)/50.0, add_ref(e) },
|
||||
.flags = PFLAG_DRAWADD,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -78,6 +78,5 @@ void Swirl(Enemy*, int t, bool render);
|
|||
void BigFairy(Enemy*, int t, bool render);
|
||||
|
||||
int enemy_flare(Projectile *p, int t);
|
||||
void EnemyFlareShrink(Projectile *p, int t);
|
||||
|
||||
void enemies_preload(void);
|
||||
|
|
|
@ -71,6 +71,7 @@ enum {
|
|||
EVENT_DEATH = -8999,
|
||||
EVENT_BIRTH,
|
||||
ACTION_DESTROY,
|
||||
ACTION_NONE,
|
||||
|
||||
FPS = 60,
|
||||
|
||||
|
|
16
src/item.c
16
src/item.c
|
@ -46,11 +46,6 @@ static void ent_draw_item(EntityInterface *ent) {
|
|||
});
|
||||
}
|
||||
|
||||
static int item_prio(List *litem) {
|
||||
Item *item = (Item*)litem;
|
||||
return item->type;
|
||||
}
|
||||
|
||||
Item* create_item(complex pos, complex v, ItemType type) {
|
||||
if((creal(pos) < 0 || creal(pos) > VIEWPORT_W)) {
|
||||
// we need this because we clamp the item position to the viewport boundary during motion
|
||||
|
@ -61,10 +56,7 @@ Item* create_item(complex pos, complex v, ItemType type) {
|
|||
// type = 1 + floor(Life * frand());
|
||||
|
||||
Item *i = (Item*)objpool_acquire(stage_object_pools.items);
|
||||
|
||||
// FIXME: use simpler/faster insertions when v1.2 compat is not needed
|
||||
// list_push(&global.items, i);
|
||||
list_insert_at_priority_tail(&global.items, i, type, item_prio);
|
||||
list_append(&global.items, i);
|
||||
|
||||
i->pos = pos;
|
||||
i->pos0 = pos;
|
||||
|
@ -89,7 +81,11 @@ Item* create_bpoint(complex pos) {
|
|||
Item *i = create_item(pos, 0, BPoint);
|
||||
|
||||
if(i) {
|
||||
PARTICLE("flare", pos, 0, timeout, { 30 }, .draw_rule = Fade);
|
||||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.pos = pos, .timeout = 30,
|
||||
.draw_rule = Fade
|
||||
);
|
||||
i->auto_collect = 10;
|
||||
}
|
||||
|
||||
|
|
|
@ -265,7 +265,12 @@ void process_lasers(void) {
|
|||
}
|
||||
|
||||
if(kill_now) {
|
||||
PARTICLE("flare", p, 0, timeout, { 20 }, .draw_rule = GrowFade);
|
||||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.pos = p,
|
||||
.timeout = 20,
|
||||
.draw_rule = GrowFade
|
||||
);
|
||||
laser->deathtime = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ taisei_src = files(
|
|||
'plrmodes.c',
|
||||
'progress.c',
|
||||
'projectile.c',
|
||||
'projectile_prototypes.c',
|
||||
'random.c',
|
||||
'refs.c',
|
||||
'replay.c',
|
||||
|
|
17
src/player.c
17
src/player.c
|
@ -402,9 +402,10 @@ void player_death(Player *plr) {
|
|||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.pos = plr->pos,
|
||||
.rule = timeout_linear,
|
||||
.rule = linear,
|
||||
.timeout = 40,
|
||||
.draw_rule = Shrink,
|
||||
.args = { 40, (3+afrand(0)*7)*cexp(I*tsrand_a(1)) },
|
||||
.args = { (3+afrand(0)*7)*cexp(I*tsrand_a(1)) },
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
);
|
||||
}
|
||||
|
@ -415,10 +416,11 @@ void player_death(Player *plr) {
|
|||
.sprite = "blast",
|
||||
.pos = plr->pos,
|
||||
.color = rgba(1.0, 0.3, 0.3, 0.5),
|
||||
.rule = timeout,
|
||||
.timeout = 35,
|
||||
.draw_rule = GrowFade,
|
||||
.args = { 35, 2.4 },
|
||||
.flags = PFLAG_DRAWADD | PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
.args = { 0, 2.4 },
|
||||
.blend = BLEND_ADD,
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
);
|
||||
|
||||
plr->deathtime = global.frames + DEATHBOMB_TIME;
|
||||
|
@ -759,9 +761,10 @@ void player_graze(Player *plr, complex pos, int pts, int effect_intensity) {
|
|||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.pos = pos,
|
||||
.rule = timeout_linear,
|
||||
.rule = linear,
|
||||
.timeout = 5 + 5 * afrand(2),
|
||||
.draw_rule = Shrink,
|
||||
.args = { 5 + 5 * afrand(2), (1+afrand(0)*5)*cexp(I*M_PI*2*afrand(1)) },
|
||||
.args = { 0, (1+afrand(0)*5)*cexp(I*M_PI*2*afrand(1)) },
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -35,15 +35,17 @@ void marisa_common_shot(Player *plr, int dmg) {
|
|||
if(!(global.frames % 6)) {
|
||||
Color c = rgb(1, 1, 1);
|
||||
|
||||
PROJECTILE("marisa", plr->pos + 10 - 15.0*I, c, linear, { -20.0*I },
|
||||
.type = PlrProj+dmg,
|
||||
.shader = "sprite_default",
|
||||
);
|
||||
|
||||
PROJECTILE("marisa", plr->pos - 10 - 15.0*I, c, linear, { -20.0*I },
|
||||
.type = PlrProj+dmg,
|
||||
.shader = "sprite_default",
|
||||
);
|
||||
for(int i = -1; i < 2; i += 2) {
|
||||
PROJECTILE(
|
||||
.proto = pp_marisa,
|
||||
.pos = plr->pos + 10 * i - 15.0*I,
|
||||
.color = c,
|
||||
.rule = linear,
|
||||
.args = { -20.0*I },
|
||||
.type = PlrProj+dmg,
|
||||
.shader = "sprite_default",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,12 +91,10 @@ static void trace_laser(Enemy *e, complex vel, int damage) {
|
|||
PARTICLE(
|
||||
.sprite = "flare",
|
||||
.pos = col.location,
|
||||
.rule = timeout_linear,
|
||||
.rule = linear,
|
||||
.timeout = 3 + 5 * afrand(2),
|
||||
.draw_rule = Shrink,
|
||||
.args = {
|
||||
3 + 5 * afrand(2),
|
||||
(2+afrand(0)*6)*cexp(I*M_PI*2*afrand(1))
|
||||
},
|
||||
.args = { (2+afrand(0)*6)*cexp(I*M_PI*2*afrand(1)) },
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
);
|
||||
|
||||
|
@ -403,8 +401,11 @@ static void masterspark_visual(Enemy *e, int t2, bool render) {
|
|||
}
|
||||
|
||||
static int masterspark_star(Projectile *p, int t) {
|
||||
p->args[1] += 0.1*p->args[1]/cabs(p->args[1]);
|
||||
return timeout_linear(p,t);
|
||||
if(t >= 0) {
|
||||
p->args[0] += 0.1*p->args[0]/cabs(p->args[0]);
|
||||
}
|
||||
|
||||
return linear(p, t);
|
||||
}
|
||||
|
||||
static int masterspark(Enemy *e, int t2) {
|
||||
|
@ -424,35 +425,38 @@ static int masterspark(Enemy *e, int t2) {
|
|||
complex dir = -cexp(1.2*I*nfrand())*I;
|
||||
Color c = rgb(0.7+0.3*sin(t*30),0.7+0.3*cos(t*30),0.7+0.3*cos(t*3));
|
||||
PARTICLE(
|
||||
.sprite="maristar_orbit",
|
||||
.pos=global.plr.pos+40*dir,
|
||||
.color=c,
|
||||
.rule=masterspark_star,
|
||||
.args={50, 10*dir-10*I,3},
|
||||
.angle=nfrand(),
|
||||
.flags=PFLAG_DRAWADD,
|
||||
.draw_rule=GrowFade
|
||||
.sprite = "maristar_orbit",
|
||||
.pos = global.plr.pos+40*dir,
|
||||
.color = c,
|
||||
.rule = masterspark_star,
|
||||
.timeout = 50,
|
||||
.args= { 10 * dir - 10*I, 3 },
|
||||
.angle = nfrand(),
|
||||
.blend = BLEND_ADD,
|
||||
.draw_rule = GrowFade
|
||||
);
|
||||
dir = -conj(dir);
|
||||
PARTICLE(
|
||||
.sprite="maristar_orbit",
|
||||
.pos=global.plr.pos+40*dir,
|
||||
.color=c,
|
||||
.rule=masterspark_star,
|
||||
.args={50, 10*dir-10*I,3},
|
||||
.angle=nfrand(),
|
||||
.flags=PFLAG_DRAWADD,
|
||||
.draw_rule=GrowFade
|
||||
.sprite = "maristar_orbit",
|
||||
.pos = global.plr.pos+40*dir,
|
||||
.color = c,
|
||||
.rule = masterspark_star,
|
||||
.timeout = 50,
|
||||
.args = { 10 * dir - 10*I, 3 },
|
||||
.angle = nfrand(),
|
||||
.flags = PFLAG_DRAWADD,
|
||||
.draw_rule = GrowFade
|
||||
);
|
||||
PARTICLE(
|
||||
.sprite="smoke",
|
||||
.pos=global.plr.pos-40*I,
|
||||
.color=rgb(0.9,1,1),
|
||||
.rule=timeout_linear,
|
||||
.args={50, -5*dir,3},
|
||||
.angle=nfrand(),
|
||||
.flags=PFLAG_DRAWADD,
|
||||
.draw_rule=GrowFade
|
||||
.sprite = "smoke",
|
||||
.pos = global.plr.pos-40*I,
|
||||
.color = rgb(0.9,1,1),
|
||||
.rule = linear,
|
||||
.timeout = 50,
|
||||
.args = { -5*dir, 3 },
|
||||
.angle = nfrand(),
|
||||
.flags = PFLAG_DRAWADD,
|
||||
.draw_rule = GrowFade
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "renderer/api.h"
|
||||
|
||||
static void marisa_star_trail_draw(Projectile *p, int t) {
|
||||
float s = 1 - t / creal(p->args[0]);
|
||||
float s = 1 - t / (double)p->timeout;
|
||||
|
||||
Color clr = derive_color(p->color, CLRMASK_A, rgba(0, 0, 0, s*0.5));
|
||||
|
||||
|
@ -40,12 +40,12 @@ static int marisa_star_projectile(Projectile *p, int t) {
|
|||
.sprite_ptr = get_sprite("proj/maristar"),
|
||||
.pos = p->pos,
|
||||
.color = p->color,
|
||||
.rule = timeout,
|
||||
.args = { 8 },
|
||||
.timeout = 8,
|
||||
.draw_rule = marisa_star_trail_draw,
|
||||
.angle = p->angle,
|
||||
.flags = PFLAG_DRAWADD | PFLAG_NOREFLECT,
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
.blend = BLEND_ADD,
|
||||
);
|
||||
|
||||
if(t == EVENT_DEATH) {
|
||||
|
@ -53,12 +53,13 @@ static int marisa_star_projectile(Projectile *p, int t) {
|
|||
.sprite_ptr = get_sprite("proj/maristar"),
|
||||
.pos = p->pos,
|
||||
.color = p->color,
|
||||
.rule = timeout,
|
||||
.timeout = 40,
|
||||
.draw_rule = GrowFade,
|
||||
.args = { 40, 2 },
|
||||
.args = { 0, 2 },
|
||||
.angle = frand() * 2 * M_PI,
|
||||
.flags = PFLAG_DRAWADD | PFLAG_NOREFLECT,
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
.layer = LAYER_PARTICLE_HIGH,
|
||||
.blend = BLEND_ADD,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -80,7 +81,7 @@ static int marisa_star_slave(Enemy *e, int t) {
|
|||
a *= cexp(I*i*M_PI/20*sign(v)*focus);
|
||||
|
||||
PROJECTILE(
|
||||
.sprite_ptr = get_sprite("proj/maristar"),
|
||||
.proto = pp_maristar,
|
||||
.pos = e->pos,
|
||||
.color = rgb(1.0, 0.5, 1.0),
|
||||
.rule = marisa_star_projectile,
|
||||
|
@ -99,8 +100,11 @@ static int marisa_star_slave(Enemy *e, int t) {
|
|||
|
||||
|
||||
static int marisa_star_orbit_star(Projectile *p, int t) { // XXX: because growfade is the worst
|
||||
p->args[1] += p->args[1]/cabs(p->args[1])*0.05;
|
||||
return timeout_linear(p,t);
|
||||
if(t >= 0) {
|
||||
p->args[0] += p->args[0]/cabs(p->args[0])*0.05;
|
||||
}
|
||||
|
||||
return linear(p,t);
|
||||
}
|
||||
|
||||
static Color marisa_slaveclr(int i, float low) {
|
||||
|
@ -149,10 +153,10 @@ static int marisa_star_orbit(Enemy *e, int t) {
|
|||
.sprite_ptr = get_sprite("part/lightningball"),
|
||||
.pos = e->pos,
|
||||
.color = rgba(clr[0],clr[1],clr[2],clr[3]/2),
|
||||
.rule = timeout,
|
||||
.timeout = 10,
|
||||
.draw_rule = Fade,
|
||||
.flags = PFLAG_DRAWADD | PFLAG_NOREFLECT,
|
||||
.args = { 10, 2 },
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
.blend = BLEND_ADD,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -163,8 +167,9 @@ static int marisa_star_orbit(Enemy *e, int t) {
|
|||
.color = rgba(clr[0],clr[1],clr[2],1),
|
||||
.rule = marisa_star_orbit_star,
|
||||
.draw_rule = GrowFade,
|
||||
.timeout = 150,
|
||||
.flags = PFLAG_DRAWADD | PFLAG_NOREFLECT,
|
||||
.args = { 150, -5*dir/cabs(dir), 3 },
|
||||
.args = { -5*dir/cabs(dir), 3 },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,18 +26,6 @@ PlayerCharacter character_youmu = {
|
|||
},
|
||||
};
|
||||
|
||||
int youmu_common_particle_spin(Projectile *p, int t) {
|
||||
int i = timeout_linear(p, t);
|
||||
|
||||
if(t < 0)
|
||||
return 1;
|
||||
|
||||
p->args[3] += 0.06;
|
||||
p->angle = p->args[3];
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void youmu_common_shot(Player *plr) {
|
||||
if(!(global.frames % 4)) {
|
||||
play_sound("generic_shot");
|
||||
|
@ -46,12 +34,22 @@ void youmu_common_shot(Player *plr) {
|
|||
if(!(global.frames % 6)) {
|
||||
Color c = rgb(1, 1, 1);
|
||||
|
||||
PROJECTILE("youmu", plr->pos + 10 - I*20, c, linear, { -20.0*I },
|
||||
PROJECTILE(
|
||||
.proto = pp_youmu,
|
||||
.pos = plr->pos + 10 - I*20,
|
||||
.color = c,
|
||||
.rule = linear,
|
||||
.args = { -20.0*I },
|
||||
.type = PlrProj+120,
|
||||
.shader = "sprite_default",
|
||||
);
|
||||
|
||||
PROJECTILE("youmu", plr->pos - 10 - I*20, c, linear, { -20.0*I },
|
||||
PROJECTILE(
|
||||
.proto = pp_youmu,
|
||||
.pos = plr->pos - 10 - I*20,
|
||||
.color = c,
|
||||
.rule = linear,
|
||||
.args = { -20.0*I },
|
||||
.type = PlrProj+120,
|
||||
.shader = "sprite_default",
|
||||
);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
extern PlayerCharacter character_youmu;
|
||||
|
||||
int youmu_common_particle_spin(Projectile *p, int t);
|
||||
void youmu_common_shot(Player *plr);
|
||||
void youmu_common_draw_proj(Projectile *p, Color c, float scale);
|
||||
void youmu_common_bombbg(Player *plr);
|
||||
|
|
|
@ -20,23 +20,19 @@ static Color myon_color(float f, float a) {
|
|||
}
|
||||
|
||||
static int myon_particle_rule(Projectile *p, int t) {
|
||||
if(t >= creal(p->args[0])) {
|
||||
return ACTION_DESTROY;
|
||||
}
|
||||
|
||||
if(t < 0) {
|
||||
return 1;
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
p->pos += p->args[1];
|
||||
p->pos += p->args[0];
|
||||
p->angle += 0.03 * (1 - 2 * (p->birthtime & 1));
|
||||
p->color = derive_color(approach_color(p->color, myon_color(0.5, 0), 0.04), CLRMASK_A, p->color);
|
||||
|
||||
return 1;
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
static complex myon_tail_dir(void) {
|
||||
double angle = carg(global.plr.slaves->args[1]);
|
||||
double angle = carg(global.plr.slaves->args[0]);
|
||||
complex dir = cexp(I*(0.1 * sin(global.frames * 0.05) + angle));
|
||||
float f = abs(global.plr.focus) / 30.0;
|
||||
return f * f * dir;
|
||||
|
@ -44,23 +40,23 @@ static complex myon_tail_dir(void) {
|
|||
|
||||
static int myon_flare_particle_rule(Projectile *p, int t) {
|
||||
if(t < 0) {
|
||||
return 1;
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
// wiggle wiggle
|
||||
p->pos += 0.05 * (global.plr.slaves->pos - p->pos) * cexp(I * sin((t - global.frames * 2) * 0.1) * M_PI/8);
|
||||
p->args[1] = 3 * myon_tail_dir();
|
||||
p->color = derive_color(p->color, CLRMASK_A, rgba(1, 1, 1, pow(1 - min(1, t / p->args[0]), 2)));
|
||||
p->args[0] = 3 * myon_tail_dir();
|
||||
p->color = derive_color(p->color, CLRMASK_A, rgba(1, 1, 1, pow(1 - min(1, t / (double)p->timeout), 2)));
|
||||
|
||||
return myon_particle_rule(p, t);
|
||||
}
|
||||
|
||||
static void myon_draw_trail(Projectile *p, int t) {
|
||||
float fadein = clamp(t/10.0, p->args[3], 1);
|
||||
float s = min(1, 1 - t / p->args[0]);
|
||||
float fadein = clamp(t/10.0, p->args[2], 1);
|
||||
float s = min(1, 1 - t / (double)p->timeout);
|
||||
float a = color_component(p->color, CLR_A) * fadein;
|
||||
Color c = derive_color(p->color, CLRMASK_A, rgba(0, 0, 0, a * s * s));
|
||||
youmu_common_draw_proj(p, c, fadein * (2-s) * p->args[2]);
|
||||
youmu_common_draw_proj(p, c, fadein * (2-s) * p->args[1]);
|
||||
}
|
||||
|
||||
static void spawn_stardust(complex pos, Color clr, int timeout, complex v) {
|
||||
|
@ -70,9 +66,11 @@ static void spawn_stardust(complex pos, Color clr, int timeout, complex v) {
|
|||
.color = clr,
|
||||
.draw_rule = myon_draw_trail,
|
||||
.rule = myon_particle_rule,
|
||||
.args = { timeout, v, 0.2 + 0.1 * frand(), 1 },
|
||||
.timeout = timeout,
|
||||
.args = { v, 0.2 + 0.1 * frand(), 1 },
|
||||
.angle = M_PI*2*frand(),
|
||||
.flags = PFLAG_DRAWADD | PFLAG_NOREFLECT,
|
||||
.blend = BLEND_ADD,
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
.layer = LAYER_PARTICLE_LOW | 1,
|
||||
);
|
||||
}
|
||||
|
@ -92,8 +90,10 @@ static void myon_spawn_trail(Enemy *e, int t) {
|
|||
.color = myon_color(f, (1 + f) * 0.05),
|
||||
.draw_rule = myon_draw_trail,
|
||||
.rule = myon_particle_rule,
|
||||
.args = { 60, -I*0.0*cexp(I*M_PI/16*sin(t)), -0.2, 0 },
|
||||
.flags = PFLAG_DRAWADD | PFLAG_NOREFLECT,
|
||||
.timeout = 60,
|
||||
.args = { -I*0.0*cexp(I*M_PI/16*sin(t)), -0.2, 0 },
|
||||
.blend = BLEND_ADD,
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
.angle = M_PI*2*frand(),
|
||||
);
|
||||
|
||||
|
@ -103,8 +103,10 @@ static void myon_spawn_trail(Enemy *e, int t) {
|
|||
.color = rgba(1, 1, 1, 0.2),
|
||||
.draw_rule = Shrink,
|
||||
.rule = myon_particle_rule,
|
||||
.args = { 10, cexp(I*M_PI*2*frand())*0.5, 0.2, 0 },
|
||||
.flags = PFLAG_DRAWADD | PFLAG_NOREFLECT,
|
||||
.timeout = 10,
|
||||
.args = { cexp(I*M_PI*2*frand())*0.5, 0.2, 0 },
|
||||
.blend = BLEND_ADD,
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
.angle = M_PI*2*frand(),
|
||||
);
|
||||
}
|
||||
|
@ -114,7 +116,8 @@ static void myon_spawn_trail(Enemy *e, int t) {
|
|||
.color = myon_color(f, 0.5),
|
||||
.pos = pos,
|
||||
.rule = myon_flare_particle_rule,
|
||||
.args = { 40, f * stardust_v },
|
||||
.timeout = 40,
|
||||
.args = { f * stardust_v },
|
||||
.draw_rule = Shrink,
|
||||
.flags = PFLAG_NOREFLECT | PFLAG_REQUIREDPARTICLE,
|
||||
.angle = M_PI*2*frand(),
|
||||
|
@ -149,8 +152,9 @@ static int myon_proj(Projectile *p, int t) {
|
|||
.pos = p->pos,
|
||||
.color = derive_color(p->color, CLRMASK_A, rgba(0, 0, 0, 0.075)),
|
||||
.draw_rule = myon_draw_proj_trail,
|
||||
.rule = timeout_linear,
|
||||
.args = { 10, p->args[0]*0.8, 0.6, 0 },
|
||||
.rule = linear,
|
||||
.timeout = 10,
|
||||
.args = { p->args[0]*0.8, 0.6, 0 },
|
||||
.flags = PFLAG_DRAWADD | PFLAG_NOREFLECT,
|
||||
.angle = p->angle,
|
||||
);
|
||||
|
|
|
@ -50,12 +50,12 @@ static void youmu_homing_draw_proj(Projectile *p, int t) {
|
|||
}
|
||||
|
||||
static void youmu_homing_draw_trail(Projectile *p, int t) {
|
||||
float a = clamp(1.0f - (float)t / p->args[0], 0, 1);
|
||||
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->args[0], 0, 1);
|
||||
float a = clamp(1.0f - (float)t / p->timeout, 0, 1);
|
||||
youmu_homing_draw_common(p, a, 2 - a, 0.15f * a);
|
||||
}
|
||||
|
||||
|
@ -76,9 +76,10 @@ static Projectile* youmu_homing_trail(Projectile *p, complex v, int to) {
|
|||
.pos = p->pos,
|
||||
.color = p->color,
|
||||
.angle = p->angle,
|
||||
.rule = timeout_linear,
|
||||
.rule = linear,
|
||||
.timeout = to,
|
||||
.draw_rule = youmu_homing_draw_trail,
|
||||
.args = { to, v },
|
||||
.args = { v },
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
.shader_ptr = p->shader,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
|
@ -123,7 +124,10 @@ static Projectile* youmu_trap_trail(Projectile *p, complex v, int t) {
|
|||
|
||||
static int youmu_trap(Projectile *p, int t) {
|
||||
if(t == EVENT_DEATH) {
|
||||
PARTICLE("blast", p->pos, 0, blast_timeout, { 15 },
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = p->pos,
|
||||
.timeout = 15,
|
||||
.draw_rule = Blast,
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
|
@ -145,13 +149,19 @@ static int youmu_trap(Projectile *p, int t) {
|
|||
p->shader_custom_param = charge;
|
||||
|
||||
if(!(global.plr.inputflags & INFLAG_FOCUS)) {
|
||||
PARTICLE("blast", p->pos, 0, blast_timeout, { 20 },
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = p->pos,
|
||||
.timeout = 20,
|
||||
.draw_rule = Blast,
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
);
|
||||
|
||||
PARTICLE("blast", p->pos, 0, blast_timeout, { 23 },
|
||||
PARTICLE(
|
||||
.proto = pp_blast,
|
||||
.pos = p->pos,
|
||||
.timeout = 23,
|
||||
.draw_rule = Blast,
|
||||
.flags = PFLAG_REQUIREDPARTICLE,
|
||||
.layer = LAYER_PARTICLE_LOW,
|
||||
|
@ -191,7 +201,7 @@ static int youmu_trap(Projectile *p, int t) {
|
|||
}
|
||||
|
||||
static void youmu_particle_slice_draw(Projectile *p, int t) {
|
||||
double lifetime = creal(p->args[0]);
|
||||
double lifetime = p->timeout;
|
||||
double tt = t/lifetime;
|
||||
double f = 0;
|
||||
if(tt > 0.1) {
|
||||
|
@ -217,10 +227,10 @@ static void youmu_particle_slice_draw(Projectile *p, int t) {
|
|||
|
||||
static int youmu_particle_slice_logic(Projectile *p, int t) {
|
||||
if(t < 0) {
|
||||
return 1;
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
double lifetime = creal(p->args[0]);
|
||||
double lifetime = p->timeout;
|
||||
double tt = t/lifetime;
|
||||
double a = 0;
|
||||
if(tt > 0.) {
|
||||
|
@ -250,7 +260,7 @@ static int youmu_particle_slice_logic(Projectile *p, int t) {
|
|||
);
|
||||
}
|
||||
|
||||
return timeout(p, t);
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
static void YoumuSlash(Enemy *e, int t, bool render) {
|
||||
|
@ -275,8 +285,9 @@ static int youmu_slash(Enemy *e, int t) {
|
|||
.pos = e->pos+pos,
|
||||
.draw_rule = youmu_particle_slice_draw,
|
||||
.rule = youmu_particle_slice_logic,
|
||||
.flags = PFLAG_DRAWADD | PFLAG_NOREFLECT,
|
||||
.args = { 100 },
|
||||
.flags = PFLAG_NOREFLECT,
|
||||
.blend = BLEND_ADD,
|
||||
.timeout = 100,
|
||||
.angle = carg(pos),
|
||||
);
|
||||
}
|
||||
|
|
201
src/projectile.c
201
src/projectile.c
|
@ -38,16 +38,37 @@ static ProjArgs defaults_part = {
|
|||
};
|
||||
|
||||
static void process_projectile_args(ProjArgs *args, ProjArgs *defaults) {
|
||||
int texargs = (bool)args->sprite + (bool)args->sprite_ptr + (bool)args->size;
|
||||
// Detect the deprecated way to spawn projectiles and remap it to prototypes,
|
||||
// if possible. This is so that I can conserve the remains of my sanity by
|
||||
// not having to convert every single PROJECTILE call in the game manually
|
||||
// and in one go. So, TODO: convert every single PROJECTILE call in the game
|
||||
// and remove this mess.
|
||||
|
||||
if(texargs != 1) {
|
||||
log_fatal("Exactly one of .sprite, .sprite_ptr, or .size is required");
|
||||
if(!args->proto && args->sprite && args->size == 0) {
|
||||
static struct {
|
||||
const char *name;
|
||||
ProjPrototype *proto;
|
||||
} proto_map[] = {
|
||||
#define PP(name) { #name, &_pp_##name },
|
||||
#include "projectile_prototypes/all.inc.h"
|
||||
};
|
||||
|
||||
for(int i = 0; i < sizeof(proto_map)/sizeof(*proto_map); ++i) {
|
||||
if(!strcmp(args->sprite, proto_map[i].name)) {
|
||||
args->proto = proto_map[i].proto;
|
||||
args->sprite = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!args->rule) {
|
||||
log_fatal(".rule is required");
|
||||
if(args->proto && args->proto->process_args) {
|
||||
args->proto->process_args(args->proto, args);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: move this stuff into prototypes along with the defaults?
|
||||
|
||||
if(args->sprite) {
|
||||
args->sprite_ptr = prefix_get_sprite(args->sprite, defaults->sprite);
|
||||
}
|
||||
|
@ -93,40 +114,49 @@ static void process_projectile_args(ProjArgs *args, ProjArgs *defaults) {
|
|||
}
|
||||
}
|
||||
|
||||
static double projectile_rect_area(Projectile *p) {
|
||||
if(p->sprite) {
|
||||
return p->sprite->w * p->sprite->h;
|
||||
} else {
|
||||
return creal(p->size) * cimag(p->size);
|
||||
}
|
||||
}
|
||||
|
||||
static void projectile_size(Projectile *p, double *w, double *h) {
|
||||
if(p->sprite) {
|
||||
if(p->type == Particle && p->sprite != NULL) {
|
||||
*w = p->sprite->w;
|
||||
*h = p->sprite->h;
|
||||
} else {
|
||||
*w = creal(p->size);
|
||||
*h = cimag(p->size);
|
||||
}
|
||||
|
||||
assert(*w > 0);
|
||||
assert(*h > 0);
|
||||
}
|
||||
|
||||
static double projectile_rect_area(Projectile *p) {
|
||||
double w, h;
|
||||
projectile_size(p, &w, &h);
|
||||
return w * h;
|
||||
}
|
||||
|
||||
static void ent_draw_projectile(EntityInterface *ent);
|
||||
|
||||
static int projectile_sizeprio_func(List *vproj) {
|
||||
// FIXME: remove this when v1.2 compat is not needed
|
||||
Projectile *proj = (Projectile*)vproj;
|
||||
|
||||
if(proj->priority_override) {
|
||||
return proj->priority_override;
|
||||
static inline int proj_call_rule(Projectile *p, int t) {
|
||||
if(p->timeout > 0 && t >= p->timeout) {
|
||||
return ACTION_DESTROY;
|
||||
}
|
||||
|
||||
return -rint(projectile_rect_area(proj));
|
||||
if(p->rule) {
|
||||
return p->rule(p, t);
|
||||
}
|
||||
|
||||
return ACTION_NONE;
|
||||
}
|
||||
|
||||
List* proj_insert_sizeprio(List **dest, List *elem) {
|
||||
// FIXME: remove this when v1.2 compat is not needed
|
||||
return list_insert_at_priority_tail(dest, elem, projectile_sizeprio_func(elem), projectile_sizeprio_func);
|
||||
void projectile_set_prototype(Projectile *p, ProjPrototype *proto) {
|
||||
if(p->proto && p->proto->deinit_projectile) {
|
||||
p->proto->deinit_projectile(p->proto, p);
|
||||
}
|
||||
|
||||
if(proto && proto->init_projectile) {
|
||||
proto->init_projectile(proto, p);
|
||||
}
|
||||
|
||||
p->proto = proto;
|
||||
}
|
||||
|
||||
static Projectile* _create_projectile(ProjArgs *args) {
|
||||
|
@ -151,11 +181,20 @@ static Projectile* _create_projectile(ProjArgs *args) {
|
|||
p->max_viewport_dist = args->max_viewport_dist;
|
||||
p->size = args->size;
|
||||
p->flags = args->flags;
|
||||
p->priority_override = args->priority_override;
|
||||
p->timeout = args->timeout;
|
||||
|
||||
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);
|
||||
|
||||
if((p->type == EnemyProj || p->type >= PlrProj) && (creal(p->size) <= 0 || cimag(p->size) <= 0)) {
|
||||
// FIXME: debug info is not actually attached at this point!
|
||||
set_debug_info(&p->debug);
|
||||
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)) {
|
||||
switch(p->type) {
|
||||
|
@ -168,16 +207,16 @@ static Projectile* _create_projectile(ProjArgs *args) {
|
|||
sublayer <<= 1;
|
||||
sublayer |= 1 * (p->blend == BLEND_ADD || p->flags & PFLAG_DRAWADD);
|
||||
|
||||
// If specific blending order is required, then set up the sublayer manually.
|
||||
// If specific blending order is required, then you should set up the sublayer manually.
|
||||
p->ent.draw_layer |= sublayer;
|
||||
break;
|
||||
}
|
||||
|
||||
case Particle: {
|
||||
// 1. Additive particles go above others.
|
||||
drawlayer_low_t sublayer = (p->blend == BLEND_ADD || p->flags & PFLAG_DRAWADD) * PARTICLE_ADDITIVE_SUBLAYER;
|
||||
drawlayer_low_t sublayer = (p->blend == BLEND_ADD || p->flags & PFLAG_DRAWADD) * PARTICLE_ADDITIVE_SUBLAYER;
|
||||
|
||||
// If specific blending order is required, then set up the sublayer manually.
|
||||
// If specific blending order is required, then you should set up the sublayer manually.
|
||||
p->ent.draw_layer |= sublayer;
|
||||
break;
|
||||
}
|
||||
|
@ -187,17 +226,13 @@ static Projectile* _create_projectile(ProjArgs *args) {
|
|||
}
|
||||
}
|
||||
|
||||
p->ent.draw_func = ent_draw_projectile;
|
||||
ent_register(&p->ent, ENT_PROJECTILE);
|
||||
|
||||
// BUG: this currently breaks some projectiles
|
||||
// enable this when they're fixed
|
||||
// assert(rule != NULL);
|
||||
// rule(p, EVENT_BIRTH);
|
||||
// proj_call_rule(p, EVENT_BIRTH);
|
||||
|
||||
// FIXME: use simpler/faster insertions when v1.2 compat is not needed
|
||||
// return (Projectile*)list_push(args->dest, p);
|
||||
return (Projectile*)proj_insert_sizeprio((List**)args->dest, (List*)p);
|
||||
return list_append(args->dest, p);
|
||||
}
|
||||
|
||||
Projectile* create_projectile(ProjArgs *args) {
|
||||
|
@ -221,7 +256,7 @@ Projectile* _proj_attach_dbginfo(Projectile *p, DebugInfo *dbg, const char *call
|
|||
|
||||
static void* _delete_projectile(List **projs, List *proj, void *arg) {
|
||||
Projectile *p = (Projectile*)proj;
|
||||
p->rule(p, EVENT_DEATH);
|
||||
proj_call_rule(p, EVENT_DEATH);
|
||||
|
||||
del_ref(proj);
|
||||
ent_unregister(&p->ent);
|
||||
|
@ -413,14 +448,16 @@ Projectile* spawn_projectile_collision_effect(Projectile *proj) {
|
|||
|
||||
return PARTICLE(
|
||||
.sprite_ptr = proj->sprite,
|
||||
.size = proj->size,
|
||||
.pos = proj->pos,
|
||||
.color = proj->color,
|
||||
.flags = proj->flags | PFLAG_NOREFLECT,
|
||||
.shader_ptr = proj->shader,
|
||||
.rule = timeout_linear,
|
||||
.rule = linear,
|
||||
.draw_rule = DeathShrink,
|
||||
.angle = proj->angle,
|
||||
.args = { 10, 5*cexp(I*proj->angle)},
|
||||
.args = { 5*cexp(I*proj->angle) },
|
||||
.timeout = 10,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -431,13 +468,14 @@ Projectile* spawn_projectile_clear_effect(Projectile *proj) {
|
|||
|
||||
return PARTICLE(
|
||||
.sprite_ptr = proj->sprite,
|
||||
.size = proj->size,
|
||||
.pos = proj->pos,
|
||||
.color = proj->color,
|
||||
.flags = proj->flags | PFLAG_NOREFLECT,
|
||||
.shader_ptr = proj->shader,
|
||||
.rule = timeout,
|
||||
.draw_rule = Shrink,
|
||||
.angle = proj->angle,
|
||||
.timeout = 10,
|
||||
.args = { 10 },
|
||||
);
|
||||
}
|
||||
|
@ -469,8 +507,7 @@ void process_projectiles(Projectile **projs, bool collision) {
|
|||
|
||||
for(Projectile *proj = *projs, *next; proj; proj = next) {
|
||||
next = proj->next;
|
||||
|
||||
action = proj->rule(proj, global.frames - proj->birthtime);
|
||||
action = proj_call_rule(proj, global.frames - proj->birthtime);
|
||||
|
||||
if(proj->type == DeadProj && killed < 5) {
|
||||
killed++;
|
||||
|
@ -601,23 +638,16 @@ void ProjDraw(Projectile *proj, int t) {
|
|||
void ProjNoDraw(Projectile *proj, int t) {
|
||||
}
|
||||
|
||||
int blast_timeout(Projectile *p, int t) {
|
||||
if(t == 1) {
|
||||
p->args[1] = frand()*360 + frand()*I;
|
||||
p->args[2] = frand() + frand()*I;
|
||||
}
|
||||
|
||||
return timeout(p, t);
|
||||
}
|
||||
|
||||
void Blast(Projectile *p, int t) {
|
||||
r_mat_push();
|
||||
r_mat_translate(creal(p->pos), cimag(p->pos), 0);
|
||||
r_mat_rotate_deg(creal(p->args[1]), cimag(p->args[1]), creal(p->args[2]), cimag(p->args[2]));
|
||||
if(t != p->args[0] && p->args[0] != 0)
|
||||
r_mat_scale(t/p->args[0], t/p->args[0], 1);
|
||||
|
||||
r_color4(0.3, 0.6, 1.0, 1.0 - t/p->args[0]);
|
||||
if(t != p->timeout && p->timeout != 0) {
|
||||
r_mat_scale(t/(double)p->timeout, t/(double)p->timeout, 1);
|
||||
}
|
||||
|
||||
r_color4(0.3, 0.6, 1.0, 1.0 - t/(double)p->timeout);
|
||||
|
||||
draw_sprite_batched_p(0,0,p->sprite);
|
||||
r_mat_scale(0.5+creal(p->args[2]),0.5+creal(p->args[2]),1);
|
||||
|
@ -630,7 +660,7 @@ void Shrink(Projectile *p, int t) {
|
|||
r_mat_push();
|
||||
apply_common_transforms(p, t);
|
||||
|
||||
float s = 2.0-t/p->args[0]*2;
|
||||
float s = 2.0-t/(double)p->timeout*2;
|
||||
if(s != 1) {
|
||||
r_mat_scale(s, s, 1);
|
||||
}
|
||||
|
@ -643,7 +673,7 @@ void DeathShrink(Projectile *p, int t) {
|
|||
r_mat_push();
|
||||
apply_common_transforms(p, t);
|
||||
|
||||
float s = 2.0-t/p->args[0]*2;
|
||||
float s = 2.0-t/(double)p->timeout*2;
|
||||
if(s != 1) {
|
||||
r_mat_scale(s, 1, 1);
|
||||
}
|
||||
|
@ -656,19 +686,22 @@ void GrowFade(Projectile *p, int t) {
|
|||
r_mat_push();
|
||||
apply_common_transforms(p, t);
|
||||
|
||||
float s = t/p->args[0]*(1 + (creal(p->args[2])? p->args[2] : p->args[1]));
|
||||
set_debug_info(&p->debug);
|
||||
assert(p->timeout != 0);
|
||||
|
||||
float s = t/(double)p->timeout*(1 + (creal(p->args[2])? p->args[2] : p->args[1]));
|
||||
if(s != 1) {
|
||||
r_mat_scale(s, s, 1);
|
||||
}
|
||||
|
||||
ProjDrawCore(p, multiply_colors(p->color, rgba(1, 1, 1, 1 - t/p->args[0])));
|
||||
ProjDrawCore(p, multiply_colors(p->color, rgba(1, 1, 1, 1 - t/(double)p->timeout)));
|
||||
r_mat_pop();
|
||||
}
|
||||
|
||||
void Fade(Projectile *p, int t) {
|
||||
r_mat_push();
|
||||
apply_common_transforms(p, t);
|
||||
ProjDrawCore(p, multiply_colors(p->color, rgba(1, 1, 1, 1 - t/p->args[0])));
|
||||
ProjDrawCore(p, multiply_colors(p->color, rgba(1, 1, 1, 1 - t/(double)p->timeout)));
|
||||
r_mat_pop();
|
||||
}
|
||||
|
||||
|
@ -678,7 +711,7 @@ void ScaleFade(Projectile *p, int t) {
|
|||
|
||||
double scale_min = creal(p->args[2]);
|
||||
double scale_max = cimag(p->args[2]);
|
||||
double timefactor = t / creal(p->args[0]);
|
||||
double timefactor = t / (double)p->timeout;
|
||||
double scale = scale_min * (1 - timefactor) + scale_max * timefactor;
|
||||
double alpha = pow(1 - timefactor, 2);
|
||||
|
||||
|
@ -691,36 +724,6 @@ void ScaleFade(Projectile *p, int t) {
|
|||
r_mat_pop();
|
||||
}
|
||||
|
||||
int timeout(Projectile *p, int t) {
|
||||
if(t >= creal(p->args[0]))
|
||||
return ACTION_DESTROY;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int timeout_linear(Projectile *p, int t) {
|
||||
if(t >= creal(p->args[0]))
|
||||
return ACTION_DESTROY;
|
||||
if(t < 0)
|
||||
return 1;
|
||||
|
||||
p->angle = carg(p->args[1]);
|
||||
p->pos = p->pos0 + p->args[1]*t;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int timeout_linear_fixangle(Projectile *p, int t) {
|
||||
if(t >= creal(p->args[0]))
|
||||
return ACTION_DESTROY;
|
||||
if(t < 0)
|
||||
return 1;
|
||||
|
||||
p->pos = p->pos0 + p->args[1]*t;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Petal(Projectile *p, int t) {
|
||||
float x = creal(p->args[2]);
|
||||
float y = cimag(p->args[2]);
|
||||
|
@ -743,7 +746,11 @@ void petal_explosion(int n, complex pos) {
|
|||
float t = frand();
|
||||
Color c = rgba(sin(5*t),cos(5*t),0.5,t);
|
||||
|
||||
PARTICLE("petal", pos, c, asymptotic,
|
||||
PARTICLE(
|
||||
.sprite = "petal",
|
||||
.pos = pos,
|
||||
.color = c,
|
||||
.rule = asymptotic,
|
||||
.draw_rule = Petal,
|
||||
.args = {
|
||||
(3+5*afrand(2))*cexp(I*M_PI*2*afrand(3)),
|
||||
|
@ -781,19 +788,6 @@ void projectiles_preload(void) {
|
|||
"part/lightning1",
|
||||
"part/lightningball",
|
||||
"part/smoothdot",
|
||||
"proj/ball",
|
||||
"proj/bigball",
|
||||
"proj/bullet",
|
||||
"proj/card",
|
||||
"proj/crystal",
|
||||
"proj/flea",
|
||||
"proj/hghost",
|
||||
"proj/plainball",
|
||||
"proj/rice",
|
||||
"proj/soul",
|
||||
"proj/thickrice",
|
||||
"proj/wave",
|
||||
"proj/youhoming",
|
||||
NULL);
|
||||