huge projectile API changes and optimizations (#93)

This commit is contained in:
Andrei Alexeyev 2017-11-10 22:49:16 +02:00 committed by GitHub
parent fa69e96643
commit 586af9a6b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 2105 additions and 871 deletions

View file

Before

Width:  |  Height:  |  Size: 116 B

After

Width:  |  Height:  |  Size: 116 B

View file

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 B

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 726 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 B

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 389 B

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 B

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 B

After

Width:  |  Height:  |  Size: 740 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 B

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 B

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 915 B

After

Width:  |  Height:  |  Size: 1,012 B

View file

@ -5,21 +5,29 @@ varying vec4 TexCoord0;
void main(void) {
gl_Position = ftransform();
gl_FrontColor = gl_Color;
TexCoord0 = gl_TextureMatrix[0] * gl_MultiTexCoord0;
}
%% -- FRAG
#version 110
uniform sampler2D tex;
uniform vec4 color;
varying vec4 TexCoord0;
uniform sampler2D tex;
uniform vec4 R;
uniform vec4 G;
uniform vec4 B;
uniform vec4 A;
uniform vec4 O;
void main(void) {
vec4 texel = texture2D(tex, vec2(TexCoord0.xy));
vec4 mixclr = mix(color, vec4(1.0), texel.b);
mixclr.a *= texel.a*color.a;
gl_FragColor = mixclr;
gl_FragColor = (
R * texel.r +
G * texel.g +
B * texel.b +
A * texel.a
) + O;
}

View file

@ -40,6 +40,7 @@ set(SRCs
random.c
config.c
color.c
recolor.c
gamepad.c
stage.c
stagedraw.c

View file

@ -153,7 +153,7 @@ static void BossGlow(Projectile *p, int t) {
glScalef(s, s, 1);
float clr[4];
parse_color_array(p->clr, clr);
parse_color_array(p->color, clr);
clr[3] = 1.5 - s;
float fade = 1 - clr[3];
@ -165,7 +165,7 @@ static void BossGlow(Projectile *p, int t) {
glPopMatrix();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(0);
glUseProgram(recolor_get_shader()->prog);
}
static int boss_glow_rule(Projectile *p, int t) {
@ -179,6 +179,22 @@ static int boss_glow_rule(Projectile *p, int t) {
return enemy_flare(p, t);
}
static Projectile* spawn_boss_glow(Boss *boss, Color clr, int timeout) {
// copy animation state to render the same frame even after the boss has changed its own
AniPlayer *aplr = aniplayer_create_copy(&boss->ani);
return PARTICLE(
// this is in sync with the boss position oscillation
.pos = boss->pos + 6 * sin(global.frames/25.0) * I,
.color = clr,
.rule = boss_glow_rule,
.draw_rule = BossGlow,
.args = { timeout, 0, add_ref(aplr), },
.angle = M_PI * 2 * frand(),
.size = (1+I)*9000, // ensure it's drawn under everything else
);
}
void draw_boss_background(Boss *boss) {
glPushMatrix();
glTranslatef(creal(boss->pos), cimag(boss->pos), 0);
@ -192,22 +208,19 @@ void draw_boss_background(Boss *boss) {
if(!(global.frames % 13) && !is_extra) {
complex v = cexp(I*global.frames);
create_particle3c("smoke", v, shadowcolor, EnemyFlareShrink, enemy_flare, 180, 0, add_ref(boss))->angle = M_PI*2*frand();
PARTICLE("smoke", v, shadowcolor, enemy_flare,
.draw_rule = EnemyFlareShrink,
.args = { 180, 0, add_ref(boss), },
.angle = M_PI * 2 * frand(),
.flags = PFLAG_DRAWADD,
);
}
if(!(global.frames % (2 + 2 * is_extra)) && (is_spell || boss_is_dying(boss))) {
// copy animation state to render the same frame even after the boss has changed its own
AniPlayer *aplr = malloc(sizeof(AniPlayer));
aniplayer_copy(aplr, &boss->ani);
// this is in sync with the boss position oscillation
complex pos = boss->pos + 6 * sin(global.frames/25.0) * I;
float glowstr = 0.5;
float a = (1.0 - glowstr) + glowstr * pow(psin(global.frames/15.0), 1.0);
glowcolor = multiply_colors(glowcolor, rgb(a, a, a));
create_particle3c("boss_shadow", pos, glowcolor, BossGlow, boss_glow_rule, 24, 0, add_ref(aplr));
spawn_boss_glow(boss, multiply_colors(glowcolor, rgb(a, a, a)), 24);
}
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
@ -349,6 +362,10 @@ void draw_boss(Boss *boss) {
}
void boss_rule_extra(Boss *boss, float alpha) {
if(global.frames % 5) {
return;
}
int cnt = 10 * max(1, alpha);
alpha = min(2, alpha);
int lt = 1;
@ -358,24 +375,26 @@ void boss_rule_extra(Boss *boss, float alpha) {
alpha = 1 * frand();
}
int i; for(i = 0; i < cnt; ++i) {
for(int i = 0; i < cnt; ++i) {
float a = i*2*M_PI/cnt + global.frames / 100.0;
complex dir = cexp(I*(a+global.frames/50.0));
complex pos = boss->pos + dir * (100 + 50 * psin(alpha*global.frames/10.0+2*i)) * alpha;
complex vel = dir * 3;
float r, g, b;
float v = max(0, alpha - 1);
float psina = psin(a);
r = 1.0 - 0.5 * psina * v;
g = 0.5 + 0.2 * psina * (1-v);
b = 0.5 + 0.5 * psina * v;
int d = 5;
if(!(global.frames % d))
create_particle3c((frand() < v*0.3 || lt > 1)? "stain" : "arc", pos, rgb(r, g, b), GrowFadeAdd, timeout_linear, 30*lt, vel * (1 - 2 * !(global.frames % (2*d))), 2.5);
PARTICLE(
.texture = (frand() < v*0.3 || lt > 1) ? "stain" : "arc",
.pos = boss->pos + dir * (100 + 50 * psin(alpha*global.frames/10.0+2*i)) * alpha,
.color = rgb(
1.0 - 0.5 * psina * v,
0.5 + 0.2 * psina * (1-v),
0.5 + 0.5 * psina * v
),
.rule = timeout_linear,
.draw_rule = GrowFade,
.flags = PFLAG_DRAWADD,
.args = { 30*lt, vel * (1 - 2 * !(global.frames % 10)), 2.5 },
);
}
}
@ -614,10 +633,22 @@ void process_boss(Boss **pboss) {
if(boss_is_dying(boss)) {
float t = (global.frames - boss->current->endtime)/(float)BOSS_DEATH_DELAY + 1;
complex pos = boss->pos;
Color c = rgba(0.1+sin(10*t),0.1+cos(10*t),0.5,t);
tsrand_fill(6);
create_particle4c("petal", pos, c, Petal, asymptotic, sign(anfrand(5))*(3+t*5*afrand(0))*cexp(I*M_PI*8*t), 5+I, afrand(2) + afrand(3)*I, afrand(4) + 360.0*I*afrand(1));
PARTICLE(
.texture = "petal",
.pos = boss->pos,
.rule = asymptotic,
.draw_rule = Petal,
.color = rgba(0.1+sin(10*t),0.1+cos(10*t),0.5,t),
.args = {
sign(anfrand(5))*(3+t*5*afrand(0))*cexp(I*M_PI*8*t),
5+I,
afrand(2) + afrand(3)*I,
afrand(4) + 360.0*I*afrand(1)
},
.flags = PFLAG_DRAWADD,
);
if(!extra) {
if(t == 1) {
@ -629,20 +660,21 @@ void process_boss(Boss **pboss) {
if(t == 1) {
for(int i = 0; i < 10; ++i) {
create_particle3c("boss_shadow", boss->pos, boss->glowcolor,
BossGlow, boss_glow_rule, 60 + 20 * i, 0,
add_ref(aniplayer_create_copy(&boss->ani)));
spawn_boss_glow(boss, boss->glowcolor, 60 + 20 * i);
}
for(int i = 0; i < 256; i++) {
tsrand_fill(3);
create_particle2c("flare", boss->pos, 0, Fade, timeout_linear,
60 + 10 * afrand(2),
(3+afrand(0)*10)*cexp(I*tsrand_a(1)));
PARTICLE("flare", boss->pos, 0, timeout_linear, .draw_rule = Fade,
.args = {
60 + 10 * afrand(2),
(3+afrand(0)*10)*cexp(I*tsrand_a(1))
},
);
}
create_particle2c("blast", boss->pos, 0, GrowFade, timeout, 60, 3);
create_particle2c("blast", boss->pos, 0, GrowFade, timeout, 70, 2.5);
PARTICLE("blast", boss->pos, 0, timeout, { 60, 3 }, .draw_rule = GrowFade);
PARTICLE("blast", boss->pos, 0, timeout, { 70, 2.5 }, .draw_rule = GrowFade);
}
play_sound_ex("bossdeath", BOSS_DEATH_DELAY * 2, false);
@ -734,7 +766,16 @@ void boss_start_attack(Boss *b, Attack *a) {
for(int i = 0; i < 10+5*(a->type == AT_ExtraSpell); i++) {
tsrand_fill(4);
create_particle2c("stain", VIEWPORT_W/2 + VIEWPORT_W/4*anfrand(0)+I*VIEWPORT_H/2+I*anfrand(1)*30, rgb(0.2,0.3,0.4), GrowFadeAdd, timeout_linear, 50, sign(anfrand(2))*10*(1+afrand(3)));
PARTICLE(
.texture = "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,
.draw_rule = GrowFade,
.args = { 50, sign(anfrand(2))*10*(1+afrand(3)) },
.flags = PFLAG_DRAWADD,
);
}
// schedule a bomb cancellation for when the spell actually starts

View file

@ -11,16 +11,15 @@
static const float conv = 1.0f / CLR_ONEVALUE;
#ifndef COLOR_INLINE
Color rgba(float r, float g, float b, float a) {
assert(!r || isnormal(r));
assert(!g || isnormal(g));
assert(!b || isnormal(b));
assert(!a || isnormal(a));
return ((((Color)(ColorComponent)(CLR_ONEVALUE * (r)) & CLR_CMASK) << CLR_R) + \
(((Color)(ColorComponent)(CLR_ONEVALUE * (g)) & CLR_CMASK) << CLR_G) + \
(((Color)(ColorComponent)(CLR_ONEVALUE * (b)) & CLR_CMASK) << CLR_B) + \
(((Color)(ColorComponent)(CLR_ONEVALUE * (a)) & CLR_CMASK) << CLR_A));
return RGBA(r, g, b, a);
}
Color rgb(float r, float g, float b) {
@ -28,12 +27,11 @@ Color rgb(float r, float g, float b) {
assert(!g || isnormal(g));
assert(!b || isnormal(b));
return ((((Color)(ColorComponent)(CLR_ONEVALUE * (r)) & CLR_CMASK) << CLR_R) + \
(((Color)(ColorComponent)(CLR_ONEVALUE * (g)) & CLR_CMASK) << CLR_G) + \
(((Color)(ColorComponent)(CLR_ONEVALUE * (b)) & CLR_CMASK) << CLR_B) + \
(CLR_ONEVALUE << CLR_A));
return RGB(r, g, b);
}
#endif
void parse_color(Color clr, float *r, float *g, float *b, float *a) {
*r = (ColorComponent)((clr >> CLR_R) & CLR_CMASK) * conv;
*g = (ColorComponent)((clr >> CLR_G) & CLR_CMASK) * conv;
@ -161,6 +159,12 @@ Color hsl(float h, float s, float l) {
return hsla(h, s, l, 1.0);
}
char* color_str(Color c) {
float r, g, b, a;
parse_color(c, &r, &g, &b, &a);
return strfmt("rgba(%f, %f, %f, %f) 0x%016"PRIxMAX, r, g, b, a, (uintmax_t)c);
}
// #define COLOR_TEST
int color_test(void) {

View file

@ -28,8 +28,20 @@
typedef uint64_t Color;
typedef int16_t ColorComponent;
#ifndef COLOR_INLINE
#ifdef NDEBUG
#define COLOR_INLINE
#endif
#endif
#ifdef COLOR_INLINE
#define rgba(r,g,b,a) RGBA(r,g,b,a)
#define rgb(r,g,b) RGB(r,g,b)
#else
Color rgba(float r, float g, float b, float a) __attribute__((const));
Color rgb(float r, float g, float b) __attribute__((const));
#endif
Color hsla(float h, float s, float l, float a) __attribute__((const));
Color hsl(float h, float s, float l) __attribute__((const));
@ -43,5 +55,26 @@ Color subtract_colors(Color c1, Color c2) __attribute__((const));
Color mix_colors(Color c1, Color c2, double a) __attribute__((const));
Color approach_color(Color src, Color dst, double delta) __attribute__((const));
float color_component(Color clr, unsigned int ofs) __attribute__((const));
char* color_str(Color c);
#ifdef RGBA
#undef RGBA
#endif
#ifdef RGB
#undef RGB
#endif
#define RGBA(r,g,b,a) \
((((Color)(ColorComponent)(CLR_ONEVALUE * (r)) & CLR_CMASK) << CLR_R) + \
(((Color)(ColorComponent)(CLR_ONEVALUE * (g)) & CLR_CMASK) << CLR_G) + \
(((Color)(ColorComponent)(CLR_ONEVALUE * (b)) & CLR_CMASK) << CLR_B) + \
(((Color)(ColorComponent)(CLR_ONEVALUE * (a)) & CLR_CMASK) << CLR_A))
#define RGB(r,g,b) \
((((Color)(ColorComponent)(CLR_ONEVALUE * (r)) & CLR_CMASK) << CLR_R) + \
(((Color)(ColorComponent)(CLR_ONEVALUE * (g)) & CLR_CMASK) << CLR_G) + \
(((Color)(ColorComponent)(CLR_ONEVALUE * (b)) & CLR_CMASK) << CLR_B) + \
(CLR_ONEVALUE << CLR_A))
int color_test(void);

View file

@ -43,16 +43,21 @@ void _delete_enemy(void **enemies, void* enemy) {
Enemy *e = (Enemy *)enemy;
if(e->hp <= 0 && e->hp > ENEMY_IMMUNE) {
int i;
play_sound("enemydeath");
for(i = 0; i < 10; i++) {
for(int i = 0; i < 10; i++) {
tsrand_fill(2);
create_particle2c("flare", e->pos, 0, Fade, timeout_linear, 10, (3+afrand(0)*10)*cexp(I*afrand(1)*2*M_PI));
PARTICLE("flare", e->pos, 0, timeout_linear, .draw_rule = Fade,
.args = { 10, (3+afrand(0)*10)*cexp(I*afrand(1)*2*M_PI) },
);
}
create_particle1c("blast", e->pos, 0, Blast, timeout, 20);
create_particle1c("blast", e->pos, 0, Blast, timeout, 20);
create_particle2c("blast", e->pos, 0, GrowFade, timeout, 15,0);
PARTICLE("blast", e->pos, 0, timeout, { 20 }, .draw_rule = Blast);
PARTICLE("blast", e->pos, 0, timeout, { 20 }, .draw_rule = Blast);
PARTICLE("blast", e->pos, 0, timeout, { 15 }, .draw_rule = GrowFade);
}
e->logic_rule(enemy, EVENT_DEATH);
del_ref(enemy);
@ -113,38 +118,37 @@ int enemy_flare(Projectile *p, int t) { // a[0] timeout, a[1] velocity, a[2] ref
void EnemyFlareShrink(Projectile *p, int t) {
Enemy *e = (Enemy *)REF(p->args[2]);
if(e == NULL)
if(e == NULL) {
return;
}
glPushMatrix();
float s = 2.0-t/p->args[0]*2;
if(e->pos + p->pos)
glTranslatef(creal(e->pos + p->pos), cimag(e->pos + p->pos), 0);
glTranslatef(creal(e->pos + p->pos), cimag(e->pos + p->pos), 0);
if(p->angle != M_PI*0.5)
if(p->angle != M_PI*0.5) {
glRotatef(p->angle*180/M_PI+90, 0, 0, 1);
}
if(s != 1)
if(s != 1) {
glScalef(s, s, 1);
}
if(p->clr)
parse_color_call(p->clr, glColor4f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
draw_texture_p(0, 0, p->tex);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
ProjDrawCore(p, p->color);
glPopMatrix();
if(p->clr)
glColor3f(1,1,1);
}
void BigFairy(Enemy *e, int t) {
if(!(t % 5)) {
complex offset = (frand()-0.5)*30 + (frand()-0.5)*20.0*I;
create_particle3c("lasercurve", offset, rgb(0,0.2,0.3), EnemyFlareShrink, enemy_flare, 50, (-50.0*I-offset)/50.0, add_ref(e));
PARTICLE("lasercurve", offset, rgb(0,0.2,0.3), enemy_flare,
.draw_rule = EnemyFlareShrink,
.args = { 50, (-50.0*I-offset)/50.0, add_ref(e) },
.flags = PFLAG_DRAWADD,
);
}
glPushMatrix();

View file

@ -63,7 +63,7 @@ Item* create_bpoint(complex pos) {
Item *i = create_item(pos, 0, BPoint);
if(i) {
create_particle1c("flare", pos, 0, Fade, timeout, 30);
PARTICLE("flare", pos, 0, timeout, { 30 }, .draw_rule = Fade);
i->auto_collect = 10;
}

View file

@ -201,7 +201,7 @@ void process_lasers(void) {
}
if(kill_now) {
create_particle1c("flare", p, 0, GrowFade, timeout, 20);
PARTICLE("flare", p, 0, timeout, { 20 }, .draw_rule = GrowFade);
laser->deathtime = 0;
}
}

View file

@ -60,7 +60,6 @@ void* create_element_at_priority(void **list_head, size_t size, int prio, int (*
if(!*list_head) {
*list_head = elem;
log_debug("PRIO: %i", prio);
return elem;
}

View file

@ -359,7 +359,7 @@ int player_run_bomb_logic(Player *plr, void *ent, complex *argptr, int (*callbac
// call the draw functions too, because some of them modify args or spawn stuff...
// this is stupid and should not happen, but for now it does.
draw_projectiles(global.particles);
draw_projectiles(global.particles, NULL);
global.frames++;
}
@ -428,11 +428,29 @@ void player_death(Player *plr) {
for(int i = 0; i < 20; i++) {
tsrand_fill(2);
create_particle2c("flare", plr->pos, 0, Shrink, timeout_linear, 40, (3+afrand(0)*7)*cexp(I*tsrand_a(1)))->type=PlrProj;
PARTICLE(
.texture = "flare",
.pos = plr->pos,
.rule = timeout_linear,
.draw_rule = Shrink,
.args = { 40, (3+afrand(0)*7)*cexp(I*tsrand_a(1)) },
.type = PlrProj,
);
}
stage_clear_hazards(false);
create_particle2c("blast", plr->pos, rgba(1,0.3,0.3,0.5), GrowFadeAdd, timeout, 35, 2.4)->type=PlrProj;
PARTICLE(
.texture = "blast",
.pos = plr->pos,
.color = rgba(1.0, 0.3, 0.3, 0.5),
.rule = timeout,
.draw_rule = GrowFade,
.args = { 35, 2.4 },
.type = PlrProj,
.flags = PFLAG_DRAWADD,
);
plr->deathtime = global.frames + DEATHBOMB_TIME;
}
}
@ -750,7 +768,15 @@ void player_graze(Player *plr, complex pos, int pts) {
int i = 0; for(i = 0; i < 5; ++i) {
tsrand_fill(3);
create_particle2c("flare", pos, 0, Shrink, timeout_linear, 5 + 5 * afrand(2), (1+afrand(0)*5)*cexp(I*tsrand_a(1)))->type=PlrProj;
PARTICLE(
.texture = "flare",
.pos = pos,
.rule = timeout_linear,
.draw_rule = Shrink,
.args = { 5 + 5 * afrand(2), (1+afrand(0)*5)*cexp(I*tsrand_a(1)) },
.type = PlrProj,
);
}
}

View file

@ -29,8 +29,17 @@ void marisa_common_shot(Player *plr) {
}
if(!(global.frames % 6)) {
create_projectile1c("marisa", plr->pos + 10 - 15.0*I, 0, linear, -20.0*I)->type = PlrProj+175;
create_projectile1c("marisa", plr->pos - 10 - 15.0*I, 0, linear, -20.0*I)->type = PlrProj+175;
Color c = rgb(1, 1, 1);
PROJECTILE("marisa", plr->pos + 10 - 15.0*I, c, linear, { -20.0*I },
.type = PlrProj+175,
.color_transform_rule = proj_clrtransform_particle,
);
PROJECTILE("marisa", plr->pos - 10 - 15.0*I, c, linear, { -20.0*I },
.type = PlrProj+175,
.color_transform_rule = proj_clrtransform_particle,
);
}
}

View file

@ -45,22 +45,22 @@ static complex trace_laser(complex origin, complex vel, int damage) {
if(col) {
tsrand_fill(3);
create_particle2c(
"flare", target, 0, Shrink, timeout_linear,
3 + 5 * afrand(2),
(2+afrand(0)*6)*cexp(I*M_PI*2*afrand(1))
)->type=PlrProj;
PARTICLE(
.texture = "flare",
.pos = target,
.rule = timeout_linear,
.draw_rule = Shrink,
.args = {
3 + 5 * afrand(2),
(2+afrand(0)*6)*cexp(I*M_PI*2*afrand(1))
},
.type = PlrProj,
);
}
return target;
}
static void set_color(int u_clr, Color c) {
float ca[4];
parse_color_array(c, ca);
glUniform4fv(u_clr, 1, ca);
}
static float set_alpha(int u_alpha, float a) {
if(a) {
glUniform1f(u_alpha, a);
@ -83,8 +83,8 @@ static void draw_magic_star(complex pos, double a, Color c1, Color c2) {
c2 = multiply_colors(c2, mul);
Texture *tex = get_tex("part/magic_star");
Shader *shader = get_shader("bullet_color");
int u_clr = uniloc(shader, "color");
Shader *shader = recolor_get_shader();
ColorTransform ct;
glUseProgram(shader->prog);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
@ -92,12 +92,14 @@ static void draw_magic_star(complex pos, double a, Color c1, Color c2) {
glTranslatef(creal(pos), cimag(pos), -1);
glScalef(0.25, 0.25, 1);
glPushMatrix();
set_color(u_clr, c1);
static_clrtransform_bullet(c1, &ct);
recolor_apply_transform(&ct);
glRotatef(global.frames * 3, 0, 0, 1);
draw_texture_p(0, 0, tex);
glPopMatrix();
glPushMatrix();
set_color(u_clr, c2);
static_clrtransform_bullet(c2, &ct);
recolor_apply_transform(&ct);
glRotatef(global.frames * -3, 0, 0, 1);
draw_texture_p(0, 0, tex);
glPopMatrix();

View file

@ -14,30 +14,21 @@ static void marisa_star(Projectile *p, int t) {
glPushMatrix();
glTranslatef(creal(p->pos), cimag(p->pos), 0);
glRotatef(t*10, 0, 0, 1);
if(p->clr) {
parse_color_call(p->clr, glColor4f);
draw_texture_p(0, 0, p->tex);
glColor4f(1, 1, 1, 1);
} else {
draw_texture_p(0, 0, p->tex);
}
ProjDrawCore(p, p->color);
glPopMatrix();
}
static void marisa_star_trail_draw(Projectile *p, int t) {
float s = 1 - t / creal(p->args[0]);
Color clr = derive_color(p->clr, CLRMASK_A, rgba(0, 0, 0, s*0.5));
Color clr = derive_color(p->color, CLRMASK_A, rgba(0, 0, 0, s*0.5));
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glPushMatrix();
glTranslatef(creal(p->pos), cimag(p->pos), 0);
glRotatef(t*10, 0, 0, 1);
glScalef(s, s, 1);
parse_color_call(clr, glColor4f);
draw_texture_p(0, 0, p->tex);
ProjDrawCore(p, clr);
glColor4f(1,1,1,1);
glPopMatrix();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -49,15 +40,32 @@ static void marisa_star_bomb_draw(Projectile *p, int t) {
static int marisa_star_projectile(Projectile *p, int t) {
float c = 0.3 * psin(t * 0.2);
p->clr = rgb(1 - c, 0.7 + 0.3 * psin(t * 0.1), 0.9 + c/3);
p->color = rgb(1 - c, 0.7 + 0.3 * psin(t * 0.1), 0.9 + c/3);
int r = accelerated(p, t);
create_projectile_p(&global.particles, get_tex("proj/maristar"), p->pos, p->clr, marisa_star_trail_draw, timeout, 10, 0, 0, 0)->type = PlrProj;
PARTICLE(
.texture_ptr = get_tex("proj/maristar"),
.pos = p->pos,
.color = p->color,
.rule = timeout,
.args = { 10 },
.draw_rule = marisa_star_trail_draw,
.type = PlrProj,
);
if(t == EVENT_DEATH) {
Projectile *impact = create_projectile_p(&global.particles, get_tex("proj/maristar"), p->pos, p->clr, GrowFadeAdd, timeout, 40, 2, 0, 0);
impact->type = PlrProj;
impact->angle = frand() * 2 * M_PI;
PARTICLE(
.texture_ptr = get_tex("proj/maristar"),
.pos = p->pos,
.color = p->color,
.rule = timeout,
.draw_rule = GrowFade,
.args = { 40, 2 },
.type = PlrProj,
.angle = frand() * 2 * M_PI,
.flags = PFLAG_DRAWADD,
);
}
return r;
@ -73,8 +81,16 @@ static int marisa_star_slave(Enemy *e, int t) {
v = creal(v) * (1 - 5 * focus) + I * cimag(v) * (1 - 2.5 * focus);
a = creal(a) * focus * -0.0525 + I * cimag(a) * 2;
create_projectile_p(&global.projs, get_tex("proj/maristar"), e->pos, rgb(1, 0.5, 1), marisa_star, marisa_star_projectile,
v, a, 0, 0)->type = PlrProj+e->args[3]*15;
PROJECTILE(
.texture_ptr = get_tex("proj/maristar"),
.pos = e->pos,
.color = rgb(1.0, 0.5, 1.0),
.rule = marisa_star_projectile,
.draw_rule = marisa_star,
.args = { v, a },
.type = PlrProj + e->args[3] * 15,
.color_transform_rule = proj_clrtransform_particle,
);
}
e->pos = global.plr.pos + (1 - focus)*e->pos0 + focus*e->args[0];
@ -85,10 +101,17 @@ static int marisa_star_slave(Enemy *e, int t) {
static int marisa_star_orbit_logic(void *v, int t, double speed) {
Projectile *p = v;
float r = cabs(p->pos0 - p->pos);
p->args[1] = (0.5e5-t*t)*cexp(I*carg(p->pos0 - p->pos))/(r*r);
p->args[0] += p->args[1]*0.2;
p->pos += p->args[0];
create_particle1c("maristar_orbit", p->pos, 0, GrowFadeAdd, timeout, 40 / speed)->type = PlrProj;
PARTICLE("maristar_orbit", p->pos, 0, timeout, { 40 / speed },
.draw_rule = GrowFade,
.type = PlrProj,
.flags = PFLAG_DRAWADD,
);
return 1;
}
@ -113,7 +136,12 @@ static void marisa_star_bomb(Player *plr) {
for(int i = 0; i < 20; i++) {
float r = frand()*40 + 100;
float phi = frand()*2*M_PI;
create_particle1c("maristar_orbit", plr->pos + r*cexp(I*phi), 0, marisa_star_bomb_draw, marisa_star_orbit, I*r*cexp(I*(phi+frand()*0.5))/10)->type=PlrProj;
PARTICLE("maristar_orbit", plr->pos + r*cexp(I*phi), 0, marisa_star_orbit,
.draw_rule = marisa_star_bomb_draw,
.args = { I*r*cexp(I*(phi+frand()*0.5))/10 },
.type = PlrProj,
);
}
}

View file

@ -45,18 +45,15 @@ void youmu_common_particle_slice_draw(Projectile *p, int t) {
}
float f = p->args[1]/p->args[0]*20.0;
glColor4f(1,1,1,1.0 - p->args[2]/p->args[0]*20.0);
p->color = rgba(1, 1, 1, 1 - p->args[2]/p->args[0]*20.0);
glPushMatrix();
glTranslatef(creal(p->pos), cimag(p->pos),0);
glRotatef(p->angle,0,0,1);
glRotatef(p->angle/M_PI*180,0,0,1);
glScalef(f,1,1);
draw_texture(0,0,"part/youmu_slice");
ProjDrawCore(p, p->color);
glPopMatrix();
glColor4f(1,1,1,1);
}
void youmu_common_shot(Player *plr) {
@ -65,7 +62,16 @@ void youmu_common_shot(Player *plr) {
}
if(!(global.frames % 6)) {
create_projectile1c("youmu", plr->pos + 10 - I*20, 0, linear, -20.0*I)->type = PlrProj+120;
create_projectile1c("youmu", plr->pos - 10 - I*20, 0, linear, -20.0*I)->type = PlrProj+120;
Color c = rgb(1, 1, 1);
PROJECTILE("youmu", plr->pos + 10 - I*20, c, linear, { -20.0*I },
.type = PlrProj+120,
.color_transform_rule = proj_clrtransform_particle,
);
PROJECTILE("youmu", plr->pos - 10 - I*20, c, linear, { -20.0*I },
.type = PlrProj+120,
.color_transform_rule = proj_clrtransform_particle,
);
}
}

View file

@ -13,12 +13,16 @@
static int myon_particle_rule(Projectile *p, int t) {
float a = 1.0;
if(t == EVENT_BIRTH) {
t = 0;
}
if(t > 0) {
double mt = creal(p->args[0]);
a *= (mt - t) / mt;
}
p->clr = mix_colors(
p->color = mix_colors(
rgba(0.85, 0.9, 1.0, 1.0),
rgba(0.5, 0.7, 1.0, a),
1 - pow(1 - a, 1 + psin((t + global.frames) * 0.1)));
@ -26,30 +30,26 @@ static int myon_particle_rule(Projectile *p, int t) {
return timeout_linear(p, t);
}
static void myon_particle_draw(Projectile *p, int t) {
// hack to bypass the bullet color shader
Color clr = p->clr;
p->clr = 0;
parse_color_call(clr, glColor4f);
Shrink(p, t);
glColor4f(1, 1, 1, 1);
p->clr = clr;
}
static void myon_draw(Enemy *e, int t) {
static void myon_spawn_trail(Enemy *e, int t) {
float a = global.frames * 0.07;
complex pos = e->pos + 3 * (cos(a) + I * sin(a));
complex dir = cexp(I*(0.1 * sin(global.frames * 0.05) + carg(global.plr.pos - e->pos)));
double v = 4 * cabs(global.plr.pos - e->pos) / (VIEWPORT_W * 0.5);
create_particle2c("flare", pos, 0, myon_particle_draw, myon_particle_rule, 20, v*dir)->type = PlrProj;
PARTICLE("flare", pos, 0, myon_particle_rule, { 20, v*dir },
.draw_rule = Shrink,
.type = PlrProj
);
}
static void youmu_mirror_myon_proj(char *tex, complex pos, double speed, double angle, double aoffs, double upfactor, int dmg) {
complex dir = cexp(I*(M_PI/2 + aoffs)) * upfactor + cexp(I * (angle + aoffs)) * (1 - upfactor);
dir = dir / cabs(dir);
create_projectile1c(tex, pos, 0, linear, speed*dir)->type = PlrProj+dmg;
PROJECTILE(tex, pos, 0, linear, { speed*dir },
.type = PlrProj+dmg,
.color_transform_rule = proj_clrtransform_particle,
);
}
static int youmu_mirror_myon(Enemy *e, int t) {
@ -58,6 +58,8 @@ static int youmu_mirror_myon(Enemy *e, int t) {
if(t < 0)
return 1;
myon_spawn_trail(e, t);
Player *plr = &global.plr;
float rad = cabs(e->pos0);
@ -125,12 +127,29 @@ static int youmu_split_logic(void *v, int t, double speed) {
FROM_TO(30,200,1) {
tsrand_fill(2);
create_particle2c("smoke", VIEWPORT_W/2 + VIEWPORT_H/2*I, rgba(0.4,0.4,0.4,afrand(0)*0.2+0.4), PartDraw, youmu_common_particle_spin, 300 / speed, speed*6*cexp(I*afrand(1)*2*M_PI));
PARTICLE(
.texture = "smoke",
.pos = VIEWPORT_W/2 + VIEWPORT_H/2*I,
.color = rgba(0.4, 0.4, 0.4, afrand(0) * 0.2 + 0.4),
.rule = youmu_common_particle_spin,
.args = { 300 / speed, speed * 6 * cexp(I*afrand(1)*2*M_PI) },
.type = PlrProj,
);
}
FROM_TO(100,170,10) {
tsrand_fill(3);
create_particle1c("youmu_slice", VIEWPORT_W/2.0 + VIEWPORT_H/2.0*I - 200-200.0*I + 400*afrand(0)+400.0*I*afrand(1), 0, youmu_common_particle_slice_draw, timeout, (100-_i) / speed)->angle = 360.0*afrand(2);
PARTICLE(
.texture = "youmu_slice",
.pos = VIEWPORT_W/2.0 + VIEWPORT_H/2.0*I - 200-200.0*I + 400*afrand(0)+400.0*I*afrand(1),
.draw_rule = youmu_common_particle_slice_draw,
.rule = timeout,
.args = { (100 - _i) / speed },
.angle = M_PI * 2 * afrand(2),
.type = PlrProj,
);
}
FROM_TO(0, 220, 1) {
@ -161,7 +180,7 @@ static void youmu_mirror_bomb(Player *plr) {
}
static void youmu_mirror_init(Player *plr) {
create_enemy_p(&plr->slaves, 40.0*I, ENEMY_IMMUNE, myon_draw, youmu_mirror_myon, 0, 0, 0, 0);
create_enemy_p(&plr->slaves, 40.0*I, ENEMY_IMMUNE, NULL, youmu_mirror_myon, 0, 0, 0, 0);
}
static void youmu_mirror_preload(void) {

View file

@ -38,9 +38,10 @@ static complex youmu_homing_target(complex org, complex fallback) {
}
static void youmu_homing_draw_common(Projectile *p, int t, float clrfactor, float alpha) {
glColor4f(0.7f + 0.3f * clrfactor, 0.9f + 0.1f * clrfactor, 1, alpha);
Color oldcolor = p->color;
p->color = multiply_colors(oldcolor, rgba(0.7f + 0.3f * clrfactor, 0.9f + 0.1f * clrfactor, 1, alpha));
ProjDraw(p, t);
glColor4f(1, 1, 1, 1);
p->color = oldcolor;
}
static void youmu_homing_draw_proj(Projectile *p, int t) {
@ -54,9 +55,16 @@ static void youmu_homing_draw_trail(Projectile *p, int t) {
}
static void youmu_homing_trail(Projectile *p, complex v, int to) {
Projectile *trail = create_projectile_p(&global.particles, p->tex, p->pos, 0, youmu_homing_draw_trail, timeout_linear, to, v, 0, 0);
trail->type = PlrProj;
trail->angle = p->angle;
PARTICLE(
.texture_ptr = p->tex,
.pos = p->pos,
.color = p->color,
.angle = p->angle,
.rule = timeout_linear,
.draw_rule = youmu_homing_draw_trail,
.args = { to, v },
.type = PlrProj,
);
}
static int youmu_homing(Projectile *p, int t) { // a[0]: velocity, a[1]: aim (r: linear, i: accelerated), a[2]: timeout, a[3]: initial target
@ -85,7 +93,7 @@ static int youmu_homing(Projectile *p, int t) { // a[0]: velocity, a[1]: aim (r:
static int youmu_trap(Projectile *p, int t) {
if(t == EVENT_DEATH) {
create_particle1c("blast", p->pos, 0, Blast, timeout, 15);
PARTICLE("blast", p->pos, 0, timeout, { 15 }, .draw_rule = Blast);
return 1;
}
@ -96,8 +104,8 @@ static int youmu_trap(Projectile *p, int t) {
}
if(!(global.plr.inputflags & INFLAG_FOCUS)) {
create_particle1c("blast", p->pos, 0, Blast, timeout, 20);
create_particle1c("blast", p->pos, 0, Blast, timeout, 23);
PARTICLE("blast", p->pos, 0, timeout, { 20 }, .draw_rule = Blast);
PARTICLE("blast", p->pos, 0, timeout, { 23 }, .draw_rule = Blast);
int cnt = creal(p->args[2]);
int dmg = cimag(p->args[2]);
@ -107,9 +115,13 @@ static int youmu_trap(Projectile *p, int t) {
for(int i = 0; i < cnt; ++i) {
float a = (i / (float)cnt) * M_PI * 2;
complex dir = cexp(I*(a));
Projectile *proj = create_projectile4c("hghost", p->pos, 0, youmu_homing, 5 * dir, aim, dur, global.plr.pos);
proj->type = PlrProj + dmg;
proj->draw = youmu_homing_draw_proj;
PROJECTILE("hghost", p->pos, rgb(1, 1, 1), youmu_homing,
.args = { 5 * dir, aim, dur, global.plr.pos },
.type = PlrProj + dmg,
.draw_rule = youmu_homing_draw_proj,
.color_transform_rule = proj_clrtransform_particle,
);
}
return ACTION_DESTROY;
@ -139,13 +151,30 @@ static int youmu_slash_logic(void *v, int t, double speed) {
FROM_TO(30, 60, 10) {
tsrand_fill(3);
create_particle1c("youmu_slice", VIEWPORT_W/2.0 - 150 + 100*_i + VIEWPORT_H/2.0*I - 10-10.0*I + 20*afrand(0)+20.0*I*afrand(1), 0, youmu_common_particle_slice_draw, timeout, 200 / speed)->angle = -10.0+20.0*afrand(2);
PARTICLE(
.texture = "youmu_slice",
.pos = VIEWPORT_W/2.0 - 150 + 100*_i + VIEWPORT_H/2.0*I - 10-10.0*I + 20*afrand(0)+20.0*I*afrand(1),
.draw_rule = youmu_common_particle_slice_draw,
.rule = timeout,
.args = { 200 / speed },
.angle = 10 * anfrand(2),
.type = PlrProj,
);
}
FROM_TO(40,200,1)
if(frand() > 0.7) {
tsrand_fill(6);
create_particle2c("blast", VIEWPORT_W*afrand(0) + (VIEWPORT_H+50)*I, rgb(afrand(1),afrand(2),afrand(3)), Shrink, timeout_linear, 80 / speed, speed * (3*(1-2.0*afrand(4))-14.0*I+afrand(5)*2.0*I));
PARTICLE(
.texture = "blast",
.pos = VIEWPORT_W*afrand(0) + (VIEWPORT_H+50)*I,
.color = rgb(afrand(1),afrand(2),afrand(3)),
.rule = timeout_linear,
.draw_rule = Shrink,
.args = { 80 / speed, speed * (3*(1-2.0*afrand(4))-14.0*I+afrand(5)*2.0*I) },
.type = PlrProj,
);
}
int tpar = 30;
@ -154,7 +183,14 @@ static int youmu_slash_logic(void *v, int t, double speed) {
if(t < creal(e->args[0])-60 && frand() > 0.2) {
tsrand_fill(3);
create_particle2c("smoke", VIEWPORT_W*afrand(0) + (VIEWPORT_H+100)*I, rgba(0.4,0.4,0.4,afrand(1)*0.2 - 0.2 + 0.6*(tpar/30.0)), PartDraw, youmu_common_particle_spin, 300 / speed, speed * (-7.0*I+afrand(2)*1.0*I));
PARTICLE(
.texture = "smoke",
.pos = VIEWPORT_W*afrand(0) + (VIEWPORT_H+100)*I,
.color = rgba(0.4,0.4,0.4,afrand(1)*0.2 - 0.2 + 0.6*(tpar/30.0)),
.rule = youmu_common_particle_spin,
.args = { 300 / speed, speed * (-7.0*I+afrand(2)*1.0*I) },
.type = PlrProj,
);
}
return 1;
@ -183,12 +219,18 @@ static void youmu_haunting_power_shot(Player *plr, int p) {
return;
}
Projectile **dst = &global.projs;
Texture *t = get_tex("proj/hghost");
for(int sign = -1; sign < 2; sign += 2) {
create_projectile_p(dst, t, plr->pos, 0, youmu_homing_draw_proj, youmu_homing,
speed * cexp(I*carg(sign*p*spread-speed*I)), aim, 60, VIEWPORT_W*0.5)->type = PlrProj+54;
PROJECTILE(
.texture_ptr = t,
.pos = plr->pos,
.rule = youmu_homing,
.draw_rule = youmu_homing_draw_proj,
.args = { speed * cexp(I*carg(sign*p*spread-speed*I)), aim, 60, VIEWPORT_W*0.5 },
.type = PlrProj+54,
.color_transform_rule = proj_clrtransform_particle,
);
}
}
@ -204,11 +246,19 @@ static void youmu_haunting_shot(Player *plr) {
int pdmg = 120 - 18 * 4 * (1 - pow(1 - pwr / 4.0, 1.5));
complex aim = 0.75;
create_projectile4c("youhoming", plr->pos, 0, youmu_trap, -30.0*I, 120, pcnt+pdmg*I, aim)->type = PlrProj+1000;
PROJECTILE("youhoming", plr->pos, rgb(1, 1, 1), youmu_trap,
.args = { -30.0*I, 120, pcnt+pdmg*I, aim },
.type = PlrProj+1000,
.color_transform_rule = proj_clrtransform_particle,
);
}
} else {
if(!(global.frames % 6)) {
create_projectile4c("hghost", plr->pos, 0, youmu_homing, -10.0*I, 0.25 + 0.1*I, 60, VIEWPORT_W*0.5)->type = PlrProj+120;
PROJECTILE("hghost", plr->pos, rgb(0.75, 0.9, 1), youmu_homing,
.args = { -10.0*I, 0.25 + 0.1*I, 60, VIEWPORT_W*0.5 },
.type = PlrProj+120,
.color_transform_rule = proj_clrtransform_particle,
);
}
for(int p = 1; p <= PLR_MAX_POWER/100; ++p) {

View file

@ -13,53 +13,117 @@
#include "list.h"
#include "vbo.h"
Projectile *create_particle4c(char *name, complex pos, Color clr, ProjDRule draw, ProjRule rule, complex a1, complex a2, complex a3, complex a4) {
Projectile *p = create_projectile_p(&global.particles, prefix_get_tex(name, "part/"), pos, clr, draw, rule, a1, a2, a3, a4);
static ProjArgs defaults_proj = {
.texture = "proj/",
.draw_rule = ProjDraw,
.dest = &global.projs,
.type = EnemyProj,
.color = RGB(1, 1, 1),
.color_transform_rule = proj_clrtransform_bullet,
};
p->type = Particle;
return p;
}
static ProjArgs defaults_part = {
.texture = "part/",
.draw_rule = ProjDraw,
.dest = &global.particles,
.type = Particle,
.color = RGB(1, 1, 1),
.color_transform_rule = proj_clrtransform_particle,
};
Projectile *create_projectile4c(char *name, complex pos, Color clr, ProjRule rule, complex a1, complex a2, complex a3, complex a4) {
return create_projectile_p(&global.projs, prefix_get_tex(name, "proj/"), pos, clr, ProjDraw, rule, a1, a2, a3, a4);
}
static void process_projectile_args(ProjArgs *args, ProjArgs *defaults) {
int texargs = (bool)args->texture + (bool)args->texture_ptr + (bool)args->size;
Projectile *create_projectile_p(Projectile **dest, Texture *tex, complex pos, Color clr,
ProjDRule draw, ProjRule rule, complex a1, complex a2, complex a3, complex a4) {
Projectile *p, *e, **d;
if(tex == NULL) {
d = dest;
} else {
for(e = *dest; e && e->next; e = e->next)
if(e->prev && tex->w*tex->h > e->tex->w*e->tex->h)
break;
if(e == NULL)
d = dest;
else
d = &e;
if(texargs != 1) {
log_fatal("Exactly one of .texture, .texture_ptr, or .size is required");
}
p = create_element((void **)d, sizeof(Projectile));
if(!args->rule) {
log_fatal(".rule is required");
}
if(args->texture) {
args->texture_ptr = prefix_get_tex(args->texture, defaults->texture);
}
if(!args->draw_rule) {
args->draw_rule = ProjDraw;
}
if(!args->dest) {
args->dest = defaults->dest;
}
if(!args->type) {
args->type = defaults->type;
}
if(!args->color) {
args->color = defaults->color;
}
if(!args->color_transform_rule) {
args->color_transform_rule = defaults->color_transform_rule;
}
if(!args->max_viewport_dist && (args->type == Particle || args->type >= PlrProj)) {
args->max_viewport_dist = 300;
}
}
static complex projectile_size2(Texture *tex, complex size) {
if(tex) {
return tex->w + I*tex->h;
}
return size;
}
static complex projectile_size(Projectile *p) {
return projectile_size2(p->tex, p->size);
}
static void projectile_size_split(Projectile *p, double *w, double *h) {
assert(w != NULL);
assert(h != NULL);
complex c = projectile_size(p);
*w = creal(c);
*h = cimag(c);
}
int projectile_prio_rawfunc(Texture *tex, complex size) {
complex s = projectile_size2(tex, size);
return -rint(creal(s) * cimag(s));
}
int projectile_prio_func(void *vproj) {
Projectile *proj = vproj;
return projectile_prio_rawfunc(proj->tex, proj->size);
}
static Projectile* _create_projectile(ProjArgs *args) {
Projectile *p = create_element_at_priority(
(void**)args->dest, sizeof(Projectile),
projectile_prio_rawfunc(args->texture_ptr, args->size),
projectile_prio_func
);
p->birthtime = global.frames;
p->pos = pos;
p->pos0 = pos;
p->angle = M_PI/2;
p->rule = rule;
p->draw = draw;
p->tex = tex;
p->type = EnemyProj;
p->clr = clr;
p->grazed = 0;
p->maxviewportdist = 0;
p->size = 0;
p->pos = p->pos0 = args->pos;
p->angle = args->angle;
p->rule = args->rule;
p->draw_rule = args->draw_rule;
p->color_transform_rule = args->color_transform_rule;
p->tex = args->texture_ptr;
p->type = args->type;
p->color = args->color;
p->grazed = (bool)(args->flags & PFLAG_NOGRAZE);
p->max_viewport_dist = args->max_viewport_dist;
p->size = args->size;
p->flags = args->flags;
p->args[0] = a1;
p->args[1] = a2;
p->args[2] = a3;
p->args[3] = a4;
memcpy(p->args, args->args, sizeof(p->args));
// BUG: this currently breaks some projectiles
// enable this when they're fixed
@ -69,6 +133,24 @@ Projectile *create_projectile_p(Projectile **dest, Texture *tex, complex pos, Co
return p;
}
Projectile* create_projectile(ProjArgs *args) {
process_projectile_args(args, &defaults_proj);
return _create_projectile(args);
}
Projectile* create_particle(ProjArgs *args) {
process_projectile_args(args, &defaults_part);
return _create_projectile(args);
}
#ifdef PROJ_DEBUG
Projectile* _proj_attach_dbginfo(Projectile *p, ProjDebugInfo *dbg) {
memcpy(&p->debug, dbg, sizeof(ProjDebugInfo));
return p;
}
#endif
void _delete_projectile(void **projs, void *proj) {
Projectile *p = proj;
p->rule(p, EVENT_DEATH);
@ -85,23 +167,6 @@ void delete_projectiles(Projectile **projs) {
delete_all_elements((void **)projs, _delete_projectile);
}
static complex projectile_size(Projectile *p) {
if(p->tex) {
return p->tex->w + I*p->tex->h;
}
return p->size;
}
static void projectile_size_split(Projectile *p, double *w, double *h) {
assert(w != NULL);
assert(h != NULL);
complex c = projectile_size(p);
*w = creal(c);
*h = cimag(c);
}
int collision_projectile(Projectile *p) {
if(p->type == EnemyProj) {
double w, h;
@ -153,23 +218,67 @@ int collision_projectile(Projectile *p) {
return 0;
}
void draw_projectiles(Projectile *projs) {
Projectile *proj;
void static_clrtransform_bullet(Color c, ColorTransform *out) {
memcpy(out, &(ColorTransform) {
.B[0] = c & ~CLRMASK_A,
.B[1] = rgba(1, 1, 1, 0),
.A[1] = c & CLRMASK_A,
}, sizeof(ColorTransform));
}
for(proj = projs; proj; proj = proj->next)
proj->draw(proj, global.frames - proj->birthtime);
void static_clrtransform_particle(Color c, ColorTransform *out) {
memcpy(out, &(ColorTransform) {
.R[1] = c & CLRMASK_R,
.G[1] = c & CLRMASK_G,
.B[1] = c & CLRMASK_B,
.A[1] = c & CLRMASK_A,
}, sizeof(ColorTransform));
}
void proj_clrtransform_bullet(Projectile *p, int t, Color c, ColorTransform *out) {
static_clrtransform_bullet(c, out);
}
void proj_clrtransform_particle(Projectile *p, int t, Color c, ColorTransform *out) {
static_clrtransform_particle(c, out);
}
static inline void draw_projectile(Projectile *proj) {
proj->draw_rule(proj, global.frames - proj->birthtime);
#ifdef PROJ_DEBUG
int cur_shader;
glGetIntegerv(GL_CURRENT_PROGRAM, &cur_shader); // NOTE: this can be really slow!
if(cur_shader != recolor_get_shader()->prog) {
log_fatal("Bad shader after drawing projectile. Offending spawn: %s:%u:%s",
proj->debug.file, proj->debug.line, proj->debug.func
);
}
#endif
}
void draw_projectiles(Projectile *projs, ProjPredicate predicate) {
glUseProgram(recolor_get_shader()->prog);
if(predicate) {
for(Projectile *proj = projs; proj; proj = proj->next) {
if(predicate(proj)) {
draw_projectile(proj);
}
}
} else {
for(Projectile *proj = projs; proj; proj = proj->next) {
draw_projectile(proj);
}
}
glUseProgram(0);
}
bool projectile_in_viewport(Projectile *proj) {
int e = proj->maxviewportdist;
if(e < 300 && (proj->type == Particle || proj->type >= PlrProj)) {
// XXX: maybe have them set it manually?
e = 300;
}
double w, h;
int e = proj->max_viewport_dist;
projectile_size_split(proj, &w, &h);
return !(creal(proj->pos) + w/2 + e < 0 || creal(proj->pos) - w/2 - e > VIEWPORT_W
@ -195,11 +304,17 @@ void process_projectiles(Projectile **projs, bool collision) {
col = collision_projectile(proj);
if(col && proj->type != Particle) {
Projectile *p = create_projectile_p(&global.particles, proj->tex, proj->pos, proj->clr, DeathShrink, timeout_linear, 10, 5*cexp(proj->angle*I), 0, 0);
if(proj->type > PlrProj) {
p->type = PlrProj;
}
PARTICLE(
.texture_ptr = proj->tex,
.pos = proj->pos,
.color = proj->color,
.flags = proj->flags,
.color_transform_rule = proj->color_transform_rule,
.rule = timeout_linear,
.draw_rule = DeathShrink,
.args = { 10, 5*cexp(proj->angle*I) },
.type = proj->type >= PlrProj ? PlrProj : Particle,
);
}
if(col == 1 && global.frames - abs(global.plr.recovery) >= 0)
@ -220,9 +335,15 @@ complex trace_projectile(complex origin, complex size, ProjRule rule, float angl
complex target = origin;
Projectile *p = NULL;
create_projectile_p(&p, NULL, origin, 0, NULL, rule, a0, a1, a2, a3);
p->type = type;
p->size = size;
PROJECTILE(
.dest = &p,
.type = type,
.size = size,
.pos = origin,
.rule = rule,
.angle = angle,
.args = { a0, a1, a2, a3 },
);
for(int t = 0; p; ++t) {
int action = p->rule(p, t);
@ -273,83 +394,60 @@ int asymptotic(Projectile *p, int t) { // v = a[0]*(a[1] + 1); a[1] -> 0
return 1;
}
void _ProjDraw(Projectile *proj, int t) {
if(proj->clr) {
static GLfloat clr[4];
Shader *shader = get_shader("bullet_color");
glUseProgram(shader->prog);
parse_color_array(proj->clr, clr);
glUniform4fv(uniloc(shader, "color"), 1, clr);
static inline void apply_common_transforms(Projectile *proj, int t) {
glTranslatef(creal(proj->pos), cimag(proj->pos), 0);
glRotatef(proj->angle*180/M_PI+90, 0, 0, 1);
if(t >= 16) {
return;
}
draw_texture_p(0,0, proj->tex);
if(proj->flags & PFLAG_NOSPAWNZOOM) {
return;
}
if(proj->clr) {
glUseProgram(0);
if(proj->type != EnemyProj && proj->type != FakeProj) {
return;
}
float s = 2.0-t/16.0;
if(s != 1) {
glScalef(s, s, 1);
}
}
static inline void apply_color(Projectile *proj, Color c) {
static ColorTransform ct;
proj->color_transform_rule(proj, proj->birthtime - global.frames, c, &ct);
recolor_apply_transform(&ct);
}
void ProjDrawCore(Projectile *proj, Color c) {
apply_color(proj, c);
if(proj->flags & PFLAG_DRAWADD) {
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
draw_texture_p(0, 0, proj->tex);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
} else if(proj->flags & PFLAG_DRAWSUB) {
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
draw_texture_p(0, 0, proj->tex);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
} else {
draw_texture_p(0, 0, proj->tex);
}
}
void ProjDraw(Projectile *proj, int t) {
glPushMatrix();
glTranslatef(creal(proj->pos), cimag(proj->pos), 0);
glRotatef(proj->angle*180/M_PI+90, 0, 0, 1);
if(t < 16 && proj->type < PlrProj && proj->type != Particle) {
float s = 2.0-t/16.0;
if(s != 1)
glScalef(s,s,1);
}
_ProjDraw(proj, t);
apply_common_transforms(proj, t);
ProjDrawCore(proj, proj->color);
glPopMatrix();
}
void ProjDrawNoFlareAdd(Projectile *proj, int t) {
glPushMatrix();
glTranslatef(creal(proj->pos), cimag(proj->pos), 0);
glRotatef(proj->angle*180/M_PI+90, 0, 0, 1);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
_ProjDraw(proj, t);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glPopMatrix();
}
void ProjDrawAdd(Projectile *proj, int t) {
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
ProjDraw(proj, t);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
void ProjDrawSub(Projectile *proj, int t) {
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
ProjDraw(proj, t);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
}
void PartDraw(Projectile *proj, int t) {
glPushMatrix();
glTranslatef(creal(proj->pos), cimag(proj->pos), 0);
glRotatef(proj->angle*180/M_PI+90, 0, 0, 1);
if(proj->clr) {
parse_color_call(proj->clr, glColor4f);
}
draw_texture_p(0,0, proj->tex);
glPopMatrix();
if(proj->clr)
glColor3f(1,1,1);
}
void ProjNoDraw(Projectile *proj, int t) {
}
void Blast(Projectile *p, int t) {
@ -359,105 +457,77 @@ void Blast(Projectile *p, int t) {
}
glPushMatrix();
if(p->pos)
glTranslatef(creal(p->pos), cimag(p->pos), 0);
glTranslatef(creal(p->pos), cimag(p->pos), 0);
glRotatef(creal(p->args[1]), cimag(p->args[1]), creal(p->args[2]), cimag(p->args[2]));
if(t != p->args[0])
if(t != p->args[0] && p->args[0] != 0)
glScalef(t/p->args[0], t/p->args[0], 1);
glColor4f(0.3,0.6,1,1 - t/p->args[0]);
apply_color(p, rgba(0.3, 0.6, 1.0, 1.0 - t/p->args[0]));
draw_texture_p(0,0,p->tex);
glScalef(0.5+creal(p->args[2]),0.5+creal(p->args[2]),1);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
draw_texture_p(0,0,p->tex);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glPopMatrix();
glColor4f(1,1,1,1);
}
void Shrink(Projectile *p, int t) {
glPushMatrix();
apply_common_transforms(p, t);
float s = 2.0-t/p->args[0]*2;
if(p->pos)
glTranslatef(creal(p->pos), cimag(p->pos), 0);
if(p->angle != M_PI*0.5)
glRotatef(p->angle*180/M_PI+90, 0, 0, 1);
if(s != 1)
if(s != 1) {
glScalef(s, s, 1);
}
_ProjDraw(p, t);
ProjDrawCore(p, p->color);
glPopMatrix();
}
void ShrinkAdd(Projectile *p, int t) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
Shrink(p, t);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void DeathShrink(Projectile *p, int t) {
glPushMatrix();
apply_common_transforms(p, t);
float s = 2.0-t/p->args[0]*2;
glTranslatef(creal(p->pos), cimag(p->pos), 0);
glRotatef(p->angle*180/M_PI+90, 0, 0, 1);
if(s != 1)
if(s != 1) {
glScalef(s, 1, 1);
}
_ProjDraw(p, t);
ProjDrawCore(p, p->color);
glPopMatrix();
}
void GrowFadeAdd(Projectile *p, int t) {
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
GrowFade(p, t);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
void GrowFade(Projectile *p, int t) {
glPushMatrix();
glTranslatef(creal(p->pos), cimag(p->pos), 0);
glRotatef(p->angle*180/M_PI+90, 0, 0, 1);
apply_common_transforms(p, t);
float s = t/p->args[0]*(1 + (creal(p->args[2])? p->args[2] : p->args[1]));
if(s != 1)
if(s != 1) {
glScalef(s, s, 1);
}
if(p->clr)
parse_color_call(derive_color(p->clr, CLRMASK_A, rgba(0,0,0,1-t/p->args[0])), glColor4f);
else if(t/p->args[0] != 0)
glColor4f(1,1,1,1-t/p->args[0]);
draw_texture_p(0,0,p->tex);
glColor4f(1,1,1,1);
ProjDrawCore(p, multiply_colors(p->color, rgba(1, 1, 1, 1 - t/p->args[0])));
glPopMatrix();
}
void Fade(Projectile *p, int t) {
if(t/creal(p->args[0]) != 0)
glColor4f(1,1,1, 1.0 - (float)t/p->args[0]);
ProjDraw(p, t);
if(t/creal(p->args[0]) != 0)
glColor4f(1,1,1,1);
glPushMatrix();
apply_common_transforms(p, t);
ProjDrawCore(p, multiply_colors(p->color, rgba(1, 1, 1, 1 - t/p->args[0])));
glPopMatrix();
}
void FadeAdd(Projectile *p, int t) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
parse_color_call(derive_color(p->clr, CLRMASK_A, rgba(0,0,0, 1.0 - (float)t/p->args[0])), glColor4f);
void ScaleFade(Projectile *p, int t) {
glPushMatrix();
glTranslatef(creal(p->pos), cimag(p->pos), 0);
glRotatef(180/M_PI*p->angle+90, 0, 0, 1);
apply_common_transforms(p, t);
glScalef(creal(p->args[1]), creal(p->args[1]), 1);
draw_texture_p(0,0, p->tex);
float a = (1.0 - t/creal(p->args[0])) * (1.0 - cimag(p->args[1]));
Color c = rgba(1, 1, 1, a);
ProjDrawCore(p, c);
glPopMatrix();
glColor4f(1,1,1,1);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
int timeout(Projectile *p, int t) {
@ -488,24 +558,11 @@ void Petal(Projectile *p, int t) {
x /= r; y /= r; z /= r;
glDisable(GL_CULL_FACE);
glPushMatrix();
if(p->pos)
glTranslatef(creal(p->pos), cimag(p->pos),0);
glTranslatef(creal(p->pos), cimag(p->pos),0);
glRotatef(t*4.0 + cimag(p->args[3]), x, y, z);
if(p->clr) {
parse_color_call(p->clr, glColor4f);
}
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
draw_texture_p(0,0, p->tex);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if(p->clr)
glColor4f(1,1,1,1);
ProjDrawCore(p, p->color);
glPopMatrix();
glEnable(GL_CULL_FACE);
}
@ -515,7 +572,16 @@ void petal_explosion(int n, complex pos) {
tsrand_fill(6);
float t = frand();
Color c = rgba(sin(5*t),cos(5*t),0.5,t);
create_particle4c("petal", pos, c, Petal, asymptotic, (3+5*afrand(2))*cexp(I*M_PI*2*afrand(3)), 5, afrand(4) + afrand(5)*I, afrand(1) + 360.0*I*afrand(0));
PARTICLE("petal", pos, c, asymptotic,
.draw_rule = Petal,
.args = {
(3+5*afrand(2))*cexp(I*M_PI*2*afrand(3)),
5,
afrand(4) + afrand(5)*I, afrand(1) + 360.0*I*afrand(0),
},
.flags = PFLAG_DRAWADD,
);
}
}
@ -555,8 +621,4 @@ void projectiles_preload(void) {
"shot_special1",
"redirect",
NULL);
preload_resources(RES_SHADER, RESF_PERMANENT,
"bullet_color",
NULL);
}

View file

@ -6,24 +6,37 @@
* Copyright (c) 2012-2017, Andrei Alexeyev <akari@alienslab.net>.
*/
#ifndef PROJECTILE
#define PROJECTILE
#pragma once
#include "util.h"
#include "resource/texture.h"
#include "color.h"
#include "recolor.h"
#include <stdbool.h>
#ifdef DEBUG
// #define PROJ_DEBUG
#endif
enum {
RULE_ARGC = 4
};
struct Projectile;
typedef int (*ProjRule)(struct Projectile *p, int t);
typedef void (*ProjDRule)(struct Projectile *p, int t);
typedef struct Projectile Projectile;
typedef int (*ProjRule)(Projectile *p, int t);
typedef void (*ProjDrawRule)(Projectile *p, int t);
typedef void (*ProjColorTransformRule)(Projectile *p, int t, Color c, ColorTransform *out);
typedef bool (*ProjPredicate)(Projectile *p);
void static_clrtransform_bullet(Color c, ColorTransform *out);
void static_clrtransform_particle(Color c, ColorTransform *out);
void proj_clrtransform_bullet(Projectile *p, int t, Color c, ColorTransform *out);
void proj_clrtransform_particle(Projectile *p, int t, Color c, ColorTransform *out);
typedef enum {
_InvalidProj,
EnemyProj, // hazard, collides with player
DeadProj, // no collision, will be converted to a BPoint item shortly
Particle, // no collision, not a hazard
@ -31,46 +44,77 @@ typedef enum {
PlrProj, // collides with enemies and bosses
} ProjType;
typedef struct Projectile {
typedef enum ProjFlags {
PFLAG_DRAWADD = (1 << 0),
PFLAG_DRAWSUB = (1 << 1),
PFLAG_NOSPAWNZOOM = (1 << 2),
PFLAG_NOGRAZE = (1 << 3),
} ProjFlags;
#ifdef PROJ_DEBUG
typedef struct ProjDebugInfo {
const char *file;
const char *func;
unsigned int line;
} ProjDebugInfo;
#endif
struct Projectile {
struct Projectile *next;
struct Projectile *prev;
complex pos;
complex pos0;
long birthtime;
float angle;
ProjRule rule;
ProjDRule draw;
Texture *tex;
complex size; // this is currently ignored if tex is not NULL.
ProjType type;
Color clr;
complex args[RULE_ARGC];
int grazed;
ProjRule rule;
ProjDrawRule draw_rule;
ProjColorTransformRule color_transform_rule;
Texture *tex;
Color color;
int birthtime;
float angle;
ProjType type;
int max_viewport_dist;
ProjFlags flags;
bool grazed;
int maxviewportdist;
} Projectile;
#ifdef PROJ_DEBUG
ProjDebugInfo debug;
#endif
};
#define create_particle3c(n,p,c,d,r,a1,a2,a3) create_particle4c(n,p,c,d,r,a1,a2,a3,0)
#define create_particle2c(n,p,c,d,r,a1,a2) create_particle4c(n,p,c,d,r,a1,a2,0,0)
#define create_particle1c(n,p,c,d,r,a1) create_particle4c(n,p,c,d,r,a1,0,0,0)
typedef struct ProjArgs {
const char *texture;
complex pos;
Color color;
ProjRule rule;
complex args[RULE_ARGC];
float angle;
ProjFlags flags;
ProjDrawRule draw_rule;
ProjColorTransformRule color_transform_rule;
Projectile **dest;
ProjType type;
Texture *texture_ptr;
complex size;
int max_viewport_dist;
} ProjArgs;
#define create_projectile3c(n,p,c,r,a1,a2,a3) create_projectile4c(n,p,c,r,a1,a2,a3,0)
#define create_projectile2c(n,p,c,r,a1,a2) create_projectile4c(n,p,c,r,a1,a2,0,0)
#define create_projectile1c(n,p,c,r,a1) create_projectile4c(n,p,c,r,a1,0,0,0)
Projectile* create_projectile(ProjArgs *args);
Projectile* create_particle(ProjArgs *args);
#ifdef PROJ_DEBUG
Projectile* _proj_attach_dbginfo(Projectile *p, ProjDebugInfo *dbg);
#define PROJECTILE(...) _proj_attach_dbginfo(create_projectile(&(ProjArgs) { __VA_ARGS__ }), &(ProjDebugInfo) { __FILE__, __func__, __LINE__ })
#define PARTICLE(...) _proj_attach_dbginfo(create_particle(&(ProjArgs) { __VA_ARGS__ }), &(ProjDebugInfo) { __FILE__, __func__, __LINE__ })
#else
#define PROJECTILE(...) create_projectile(&(ProjArgs) { __VA_ARGS__ })
#define PARTICLE(...) create_particle(&(ProjArgs) { __VA_ARGS__ })
#endif
Projectile *create_particle4c(char *name, complex pos, Color clr, ProjDRule draw, ProjRule rule, complex a1, complex a2, complex a3, complex a4);
Projectile *create_projectile4c(char *name, complex pos, Color clr, ProjRule rule, complex a1, complex a2, complex a3, complex a4);
Projectile *create_projectile_p(Projectile **dest, Texture *tex, complex pos, Color clr, ProjDRule draw, ProjRule rule, complex a1, complex a2, complex a3, complex a4);
void delete_projectile(Projectile **dest, Projectile *proj);
void delete_projectiles(Projectile **dest);
void draw_projectiles(Projectile *projs);
void draw_projectiles(Projectile *projs, ProjPredicate predicate);
int collision_projectile(Projectile *p);
bool projectile_in_viewport(Projectile *proj);
void process_projectiles(Projectile **projs, bool collision);
@ -80,33 +124,22 @@ complex trace_projectile(complex origin, complex size, ProjRule rule, float angl
int linear(Projectile *p, int t);
int accelerated(Projectile *p, int t);
int asymptotic(Projectile *p, int t);
void ProjDraw(Projectile *p, int t);
void _ProjDraw(Projectile *p, int t);
void PartDraw(Projectile *p, int t);
void ProjDrawNoFlareAdd(Projectile *p, int t);
void ProjDrawAdd(Projectile *p, int t);
void ProjDrawSub(Projectile *p, int t);
void ProjDrawCore(Projectile *proj, Color c);
void ProjDraw(Projectile *p, int t);
void ProjNoDraw(Projectile *proj, int t);
void Blast(Projectile *p, int t);
void Shrink(Projectile *p, int t);
void ShrinkAdd(Projectile *p, int t);
void GrowFade(Projectile *p, int t);
void GrowFadeAdd(Projectile *p, int t);
int bullet_flare_move(Projectile *p, int t);
void Fade(Projectile *p, int t);
void FadeAdd(Projectile *p, int t);
int timeout(Projectile *p, int t);
void DeathShrink(Projectile *p, int t);
int timeout_linear(Projectile *p, int t);
void Fade(Projectile *p, int t);
void GrowFade(Projectile *p, int t);
void ScaleFade(Projectile *p, int t);
void Blast(Projectile *p, int t);
void Petal(Projectile *p, int t);
void petal_explosion(int n, complex pos);
void projectiles_preload(void);
int timeout(Projectile *p, int t);
int timeout_linear(Projectile *p, int t);
#endif
void projectiles_preload(void);

91
src/recolor.c Normal file
View file

@ -0,0 +1,91 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (c) 2011-2017, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2017, Andrei Alexeyev <akari@alienslab.net>.
*/
#include "recolor.h"
#include "resource/resource.h"
ColorTransform colortransform_identity = {
.R[1] = RGBA(1, 0, 0, 0),
.G[1] = RGBA(0, 1, 0, 0),
.B[1] = RGBA(0, 0, 1, 0),
.A[1] = RGBA(0, 0, 0, 1),
};
struct recolor_varcache {
Color prev;
int loc;
};
static struct recolor_vars_s {
Shader *shader;
struct recolor_varcache R;
struct recolor_varcache G;
struct recolor_varcache B;
struct recolor_varcache A;
struct recolor_varcache O;
bool loaded;
} recolor_vars;
static inline void recolor_set_uniform(struct recolor_varcache *vc, Color clr) {
static float clrarr[4];
if(vc->prev != clr) {
parse_color_array(clr, clrarr);
glUniform4fv(vc->loc, 1, clrarr);
vc->prev = clr;
}
}
void recolor_init(void) {
if(recolor_vars.loaded) {
return;
}
preload_resource(RES_SHADER, "recolor", RESF_PERMANENT);
recolor_vars.shader = get_shader("recolor");
recolor_vars.R.loc = uniloc(recolor_vars.shader, "R");
recolor_vars.G.loc = uniloc(recolor_vars.shader, "G");
recolor_vars.B.loc = uniloc(recolor_vars.shader, "B");
recolor_vars.A.loc = uniloc(recolor_vars.shader, "A");
recolor_vars.O.loc = uniloc(recolor_vars.shader, "O");
int prev_prog = 0;
glGetIntegerv(GL_CURRENT_PROGRAM, &prev_prog);
glUseProgram(recolor_vars.shader->prog);
recolor_apply_transform(&colortransform_identity);
glUseProgram(prev_prog);
}
void recolor_reinit(void) {
recolor_vars.loaded = false;
recolor_init();
}
Shader* recolor_get_shader(void) {
return recolor_vars.shader;
}
void recolor_apply_transform(ColorTransform *ct) {
recolor_set_uniform(&recolor_vars.R, subtract_colors(ct->R[1], ct->R[0]));
recolor_set_uniform(&recolor_vars.G, subtract_colors(ct->G[1], ct->G[0]));
recolor_set_uniform(&recolor_vars.B, subtract_colors(ct->B[1], ct->B[0]));
recolor_set_uniform(&recolor_vars.A, subtract_colors(ct->A[1], ct->A[0]));
float accum[4] = { 0 };
static float tmp[4] = { 0 };
for(int i = 0; i < 4; ++i) {
parse_color_array(ct->pairs[i].low, tmp);
for(int j = 0; j < 4; ++j) {
accum[j] += tmp[j];
}
}
recolor_set_uniform(&recolor_vars.O, rgba(accum[0], accum[1], accum[2], accum[3]));
}

41
src/recolor.h Normal file
View file

@ -0,0 +1,41 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (c) 2011-2017, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2017, Andrei Alexeyev <akari@alienslab.net>.
*/
#pragma once
#include "color.h"
#include "resource/shader.h"
/*
* Utilities for using the recolor shader in rendering code efficiently
*/
typedef struct ColorTransform {
union {
struct {
Color R[2];
Color G[2];
Color B[2];
Color A[2];
};
struct {
Color low;
Color high;
} pairs[4];
};
} ColorTransform;
extern ColorTransform colortransform_identity;
typedef void (*ColorTransformFunc)(Color clr, ColorTransform *out, void *arg);
void recolor_init(void);
void recolor_reinit(void);
Shader* recolor_get_shader(void);
void recolor_apply_transform(ColorTransform *ct);

View file

@ -11,6 +11,7 @@
#include "video.h"
#include "menu/mainmenu.h"
#include "events.h"
#include "recolor.h"
Resources resources;
static SDL_threadID main_thread_id;
@ -373,6 +374,8 @@ void init_resources(void) {
events_register_handler(&h);
}
recolor_init();
}
void resource_util_strip_ext(char *path) {

View file

@ -225,8 +225,8 @@ static void stage_draw_objects(void) {
player_draw(&global.plr);
draw_items();
draw_projectiles(global.projs);
draw_projectiles(global.particles);
draw_projectiles(global.projs, NULL);
draw_projectiles(global.particles, NULL);
draw_lasers(true);
draw_enemies(global.enemies);
draw_lasers(false);

View file

@ -31,23 +31,28 @@ struct stage1_spells_s stage1_spells = {
cirno_snow_halation, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0*I},
.icicle_fall = {{ 8, 9, 10, 11}, AT_Spellcard, "Doom Sign ~ Icicle Fall", 35, 40000,
cirno_icicle_fall, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0*I},
#ifdef DEBUG
.benchmark = {{-1,-1,-1,14}, AT_SurvivalSpell, "Profiling ~ ベンチマーク", 40, 40000, cirno_benchmark, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0*I}
#endif
},
.extra.crystal_blizzard = {{ 0, 1, 2, 3}, AT_ExtraSpell, "Frost Sign ~ Crystal Blizzard", 60, 40000,
cirno_crystal_blizzard, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0*I},
#ifdef SPELL_BENCHMARK
.benchmark = {{-1, -1, -1,127}, AT_SurvivalSpell, "Profiling ~ ベンチマーク", 40, 40000,
cirno_benchmark, cirno_pfreeze_bg, VIEWPORT_W/2.0+100.0*I},
#endif
};
static Stage3D bgcontext;
static bool particle_filter(Projectile *part) {
return part->type < PlrProj;
}
void stage1_bg_draw(Vector pos) {
glPushMatrix();
glTranslatef(0,bgcontext.cx[1]+500,0);
glRotatef(180,1,0,0);
//glEnable(GL_TEXTURE_2D);
//glBindTexture(GL_TEXTURE_2D, get_tex("stage1/water")->gltex);
@ -64,10 +69,7 @@ void stage1_bg_draw(Vector pos) {
glTranslatef(-VIEWPORT_W/2,0,0);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
for(Projectile *p = global.particles; p; p = p->next) {
if(p->type != PlrProj)
p->draw(p,global.frames - p->birthtime);
}
draw_projectiles(global.particles, particle_filter);
draw_enemies(global.enemies);
if(global.boss)
draw_boss(global.boss);

View file

@ -10,6 +10,10 @@
#include "stage.h"
#if defined(DEBUG) && !defined(SPELL_BENCHMARK)
#define SPELL_BENCHMARK
#endif
extern struct stage1_spells_s {
// this struct must contain only fields of type AttackInfo
// order of fields affects the visual spellstage number, but not its real internal ID
@ -22,15 +26,16 @@ extern struct stage1_spells_s {
AttackInfo crystal_rain;
AttackInfo snow_halation;
AttackInfo icicle_fall;
#ifdef DEBUG
AttackInfo benchmark;
#endif
} boss;
struct {
AttackInfo crystal_blizzard;
} extra;
#ifdef SPELL_BENCHMARK
AttackInfo benchmark;
#endif
// required for iteration
AttackInfo null;
} stage1_spells;

View file

@ -67,8 +67,13 @@ int cirno_snowflake_proj(Projectile *p, int time) {
if(time == split_time) {
play_sound_ex("redirect", 30, false);
play_sound_ex("shot_special1", 30, false);
create_particle1c("stain", p->pos, 0, GrowFadeAdd, timeout, 5)->angle = p->angle;
p->clr = mix_colors(p->clr, rgb(0.5, 0.5, 0.5), 0.5);
p->color = mix_colors(p->color, rgb(0.5, 0.5, 0.5), 0.5);
PARTICLE("stain", p->pos, 0, timeout, { 5 },
.draw_rule = GrowFade,
.angle = p->angle,
.flags = PFLAG_DRAWADD,
);
}
p->pos += cabs(p->args[0])*cexp(I*p->angle);
@ -97,8 +102,8 @@ void cirno_icy(Boss *b, int time) {
complex phase = cexp(I*ang);
complex pos = b->pos+vel*t+dr*_i*phase;
create_projectile1c("crystal", pos+6*I*phase, rgb(0.0,0.1+0.1*size/5,0.8), cirno_snowflake_proj, vel)->angle=ang+M_PI/4;
create_projectile1c("crystal", pos-6*I*phase, rgb(0.0,0.1+0.1*size/5,0.8), cirno_snowflake_proj, vel)->angle=ang-M_PI/4;
PROJECTILE("crystal", pos+6*I*phase, rgb(0.0,0.1+0.1*size/5,0.8), cirno_snowflake_proj, { vel }, .angle = ang+M_PI/4);
PROJECTILE("crystal", pos-6*I*phase, rgb(0.0,0.1+0.1*size/5,0.8), cirno_snowflake_proj, { vel }, .angle = ang-M_PI/4);
int split = 3;
if(_i > split) {
@ -106,11 +111,9 @@ void cirno_icy(Boss *b, int time) {
for(int j = -1; j <= 1; j+=2) {
complex phase2 = cexp(I*M_PI/4*j)*phase;
complex pos = pos0+(dr*(_i-split))*phase2;
create_projectile1c("crystal", pos, rgb(0.0,0.3*size/5,1), cirno_snowflake_proj, vel)->angle=ang+M_PI/4*j;
PROJECTILE("crystal", pos, rgb(0.0,0.3*size/5,1), cirno_snowflake_proj, { vel }, .angle = ang+M_PI/4*j);
}
}
}
}
}
@ -122,6 +125,17 @@ void cirno_mid_outro(Boss *c, int time) {
GO_TO(c, -300.0*I, 0.035);
}
static Projectile* spawn_stain(complex pos, float angle, int to) {
return PARTICLE(
.texture = "stain",
.pos = pos,
.rule = timeout,
.draw_rule = GrowFade,
.args = { to },
.angle = angle,
.flags = PFLAG_DRAWADD,
);
}
int cirno_pfreeze_frogs(Projectile *p, int t) {
if(t < 0)
@ -137,15 +151,22 @@ int cirno_pfreeze_frogs(Projectile *p, int t) {
if(boss_t < 110)
linear(p, t);
else if(boss_t == 110) {
p->clr = rgb(0.7,0.7,0.7);
create_particle1c("stain", p->pos, 0, GrowFadeAdd, timeout, 30)->angle = p->angle;
p->color = rgb(0.7,0.7,0.7);
PARTICLE("stain", p->pos,
.rule = timeout,
.draw_rule = GrowFade,
.args = { 30 },
.angle = p->angle,
.flags = PFLAG_DRAWADD,
);
spawn_stain(p->pos, p->angle, 30);
play_sound("shot_special1");
}
if(t == 240) {
p->pos0 = p->pos;
p->args[0] = (1.8+0.2*global.diff)*cexp(I*2*M_PI*frand());
create_particle1c("stain", p->pos, 0, GrowFadeAdd, timeout, 30)->angle = p->angle;
spawn_stain(p->pos, p->angle, 30);
play_sound_ex("shot2", 0, false);
}
@ -172,8 +193,9 @@ void cirno_perfect_freeze(Boss *c, int time) {
int i;
int n = global.diff;
for(i = 0; i < n; i++)
create_projectile1c("ball", c->pos, rgb(r, g, b), cirno_pfreeze_frogs, 4*cexp(I*tsrand()));
for(i = 0; i < n; i++) {
PROJECTILE("ball", c->pos, rgb(r, g, b), cirno_pfreeze_frogs, { 4*cexp(I*tsrand()) });
}
}
GO_AT(c, 160, 190, 2 + 1.0*I);
@ -194,8 +216,8 @@ void cirno_perfect_freeze(Boss *c, int time) {
r2 = nfrand();
}
create_projectile2c("rice", c->pos + 60, rgb(0.3, 0.4, 0.9), asymptotic, (2.+0.4*global.diff)*cexp(I*(carg(global.plr.pos - c->pos) + 0.5*r1)), 2.5);
create_projectile2c("rice", c->pos - 60, rgb(0.3, 0.4, 0.9), asymptotic, (2.+0.4*global.diff)*cexp(I*(carg(global.plr.pos - c->pos) + 0.5*r2)), 2.5);
PROJECTILE("rice", c->pos + 60, rgb(0.3, 0.4, 0.9), asymptotic, { (2.+0.4*global.diff)*cexp(I*(carg(global.plr.pos - c->pos) + 0.5*r1)), 2.5 });
PROJECTILE("rice", c->pos - 60, rgb(0.3, 0.4, 0.9), asymptotic, { (2.+0.4*global.diff)*cexp(I*(carg(global.plr.pos - c->pos) + 0.5*r2)), 2.5 });
}
GO_AT(c, 190, 220, -2);
@ -270,12 +292,12 @@ void cirno_iceplosion0(Boss *c, int time) {
int i;
int n = 8+global.diff;
for(i = 0; i < n; i++) {
create_projectile2c("plainball", c->pos, rgb(0,0,0.5), asymptotic, (3+_i/3.0)*cexp(I*(2*M_PI/n*i + carg(global.plr.pos-c->pos))), _i*0.7);
PROJECTILE("plainball", c->pos, rgb(0,0,0.5), asymptotic, { (3+_i/3.0)*cexp(I*(2*M_PI/n*i + carg(global.plr.pos-c->pos))), _i*0.7 });
}
}
FROM_TO_SND("shot1_loop",40,100,1+2*(global.diff<D_Hard)) {
create_projectile2c("crystal", c->pos, rgb(0.3,0.3,0.8), accelerated, global.diff/4.*cexp(2.0*I*M_PI*frand()) + 2.0*I, 0.002*cexp(I*(M_PI/10.0*(_i%20))));
PROJECTILE("crystal", c->pos, rgb(0.3,0.3,0.8), accelerated, { global.diff/4.*cexp(2.0*I*M_PI*frand()) + 2.0*I, 0.002*cexp(I*(M_PI/10.0*(_i%20))) });
}
FROM_TO(150, 300, 30-5*global.diff) {
@ -283,7 +305,7 @@ void cirno_iceplosion0(Boss *c, int time) {
int i;
play_sound("shot1");
for(i = 0; i < 20; i++) {
create_projectile2c("plainball", c->pos, rgb(0.04*_i,0.04*_i,0.4+0.04*_i), asymptotic, (3+_i/4.0)*cexp(I*(2*M_PI/8.0*i + dif)), 2.5);
PROJECTILE("plainball", c->pos, rgb(0.04*_i,0.04*_i,0.4+0.04*_i), asymptotic, { (3+_i/4.0)*cexp(I*(2*M_PI/8.0*i + dif)), 2.5 });
}
}
}
@ -305,7 +327,7 @@ void cirno_crystal_rain(Boss *c, int time) {
if(frand() > 0.95-0.1*global.diff) {
tsrand_fill(2);
create_projectile2c("crystal", VIEWPORT_W*afrand(0), rgb(0.2,0.2,0.4), accelerated, 1.0*I, 0.01*I + (-0.005+0.005*global.diff)*anfrand(1));
PROJECTILE("crystal", VIEWPORT_W*afrand(0), rgb(0.2,0.2,0.4), accelerated, { 1.0*I, 0.01*I + (-0.005+0.005*global.diff)*anfrand(1) });
}
AT(100)
@ -319,7 +341,7 @@ void cirno_crystal_rain(Boss *c, int time) {
play_sound("shot_special1");
for(i = -n; i <= n; i++) {
create_projectile2c(odd? "plainball" : "bigball", c->pos, rgb(0.2,0.2,0.9), asymptotic, 2*cexp(I*carg(global.plr.pos-c->pos)+0.3*I*i), 2.3);
PROJECTILE(odd? "plainball" : "bigball", c->pos, rgb(0.2,0.2,0.9), asymptotic, { 2*cexp(I*carg(global.plr.pos-c->pos)+0.3*I*i), 2.3 });
}
}
@ -349,13 +371,13 @@ void cirno_iceplosion1(Boss *c, int time) {
FROM_TO(20,30,2) {
int i;
for(i = 0; i < 15+global.diff; i++) {
create_projectile2c("plainball", c->pos, rgb(0,0,0.5), asymptotic, (3+_i/3.0)*cexp(I*((2)*M_PI/8.0*i + (0.1+0.03*global.diff)*(1 - 2*frand()))), _i*0.7);
PROJECTILE("plainball", c->pos, rgb(0,0,0.5), asymptotic, { (3+_i/3.0)*cexp(I*((2)*M_PI/8.0*i + (0.1+0.03*global.diff)*(1 - 2*frand()))), _i*0.7 });
}
}
FROM_TO_SND("shot1_loop",40,100,2+2*(global.diff<D_Hard)) {
create_projectile2c("crystal", c->pos + 100, rgb(0.3,0.3,0.8), accelerated, 1.5*cexp(2.0*I*M_PI*frand()) - 0.4 + 2.0*I*global.diff/4., 0.002*cexp(I*(M_PI/10.0*(_i%20))));
create_projectile2c("crystal", c->pos - 100, rgb(0.3,0.3,0.8), accelerated, 1.5*cexp(2.0*I*M_PI*frand()) + 0.4 + 2.0*I*global.diff/4., 0.002*cexp(I*(M_PI/10.0*(_i%20))));
PROJECTILE("crystal", c->pos + 100, rgb(0.3,0.3,0.8), accelerated, { 1.5*cexp(2.0*I*M_PI*frand()) - 0.4 + 2.0*I*global.diff/4., 0.002*cexp(I*(M_PI/10.0*(_i%20))) });
PROJECTILE("crystal", c->pos - 100, rgb(0.3,0.3,0.8), accelerated, { 1.5*cexp(2.0*I*M_PI*frand()) + 0.4 + 2.0*I*global.diff/4., 0.002*cexp(I*(M_PI/10.0*(_i%20))) });
}
FROM_TO(150, 300, 30) {
@ -364,7 +386,7 @@ void cirno_iceplosion1(Boss *c, int time) {
play_sound("shot1");
for(i = 0; i < 20; i++) {
create_projectile2c("plainball", c->pos, rgb(0.04*_i,0.04*_i,0.4+0.04*_i), asymptotic, (3+_i/3.0)*cexp(I*(2*M_PI/8.0*i + dif)), 2.5);
PROJECTILE("plainball", c->pos, rgb(0.04*_i,0.04*_i,0.4+0.04*_i), asymptotic, { (3+_i/3.0)*cexp(I*(2*M_PI/8.0*i + dif)), 2.5 });
}
}
}
@ -408,7 +430,11 @@ static int halation_orb(Projectile *p, int time) {
}
if(!(time % 4)) {
create_particle1c("stain", p->pos, 0, GrowFadeAdd, timeout, 20)->angle = global.frames * 15;
PROJECTILE("stain", p->pos, 0, timeout, { 20 },
.draw_rule = GrowFade,
.angle = global.frames * 15,
.flags = PFLAG_DRAWADD,
);
}
complex center = p->args[0];
@ -430,21 +456,21 @@ static int halation_orb(Projectile *p, int time) {
}
if(time == halate_time) {
create_laserline_ab(pos2, pos3, 15, phase_time * 0.5, phase_time * 2.0, p->clr);
create_laserline_ab(pos0, pos2, 15, phase_time, phase_time * 1.5, p->clr)->lrule = halation_laser;
create_laserline_ab(pos2, pos3, 15, phase_time * 0.5, phase_time * 2.0, p->color);
create_laserline_ab(pos0, pos2, 15, phase_time, phase_time * 1.5, p->color)->lrule = halation_laser;
} if(time == halate_time + phase_time * 0.5) {
play_sound("laser1");
} else if(time == halate_time + phase_time) {
play_sound("shot1");
create_laserline_ab(pos0, pos1, 12, phase_time, phase_time * 1.5, p->clr)->lrule = halation_laser;
create_laserline_ab(pos0, pos1, 12, phase_time, phase_time * 1.5, p->color)->lrule = halation_laser;
} else if(time == halate_time + phase_time * 2) {
play_sound("shot1");
create_laserline_ab(pos0, pos3, 15, phase_time, phase_time * 1.5, p->clr)->lrule = halation_laser;
create_laserline_ab(pos1, pos3, 15, phase_time, phase_time * 1.5, p->clr)->lrule = halation_laser;
create_laserline_ab(pos0, pos3, 15, phase_time, phase_time * 1.5, p->color)->lrule = halation_laser;
create_laserline_ab(pos1, pos3, 15, phase_time, phase_time * 1.5, p->color)->lrule = halation_laser;
} else if(time == halate_time + phase_time * 3) {
play_sound("shot1");
create_laserline_ab(pos0, pos1, 12, phase_time, phase_time * 1.5, p->clr)->lrule = halation_laser;
create_laserline_ab(pos0, pos2, 15, phase_time, phase_time * 1.5, p->clr)->lrule = halation_laser;
create_laserline_ab(pos0, pos1, 12, phase_time, phase_time * 1.5, p->color)->lrule = halation_laser;
create_laserline_ab(pos0, pos2, 15, phase_time, phase_time * 1.5, p->color)->lrule = halation_laser;
} else if(time == halate_time + phase_time * 4) {
play_sound("shot1");
play_sound("shot_special1");
@ -466,7 +492,7 @@ static int halation_orb(Projectile *p, int time) {
float rot = frand() * 2 * M_PI;
for(int i = 0; i < pcount; ++i) {
create_projectile2c("crystal", p->pos, colors[i], asymptotic, cexp(I*(rot + M_PI * 2 * (float)(i+1)/pcount)), 3);
PROJECTILE("crystal", p->pos, colors[i], asymptotic, { cexp(I*(rot + M_PI * 2 * (float)(i+1)/pcount)), 3 });
}
return ACTION_DESTROY;
@ -502,11 +528,18 @@ void cirno_snow_halation(Boss *c, int time) {
int halate_time = 35 - _i * interval;
for(int p = _i*2; p <= _i*2 + 1; ++p) {
complex pos = halation_calc_orb_pos(center, rotation, p, projs);
Projectile *orb = create_projectile4c("plainball", pos, halation_color(0), halation_orb, center, rotation, p + I * projs, halate_time);
orb->draw = ProjDrawAdd;
orb->type = FakeProj;
orb->maxviewportdist = 200;
PROJECTILE(
.texture = "plainball",
.pos = halation_calc_orb_pos(center, rotation, p, projs),
.color = halation_color(0),
.rule = halation_orb,
.args = {
center, rotation, p + I * projs, halate_time
},
.type = FakeProj,
.max_viewport_dist = 200,
.flags = PFLAG_DRAWADD,
);
}
}
@ -553,8 +586,8 @@ void cirno_icicle_fall(Boss *c, int time) {
FROM_TO(20,200,30-3*global.diff) {
play_sound("shot1");
for(float i = 2-0.2*global.diff; i < 5; i+=1./(1+global.diff)) {
create_projectile1c("crystal", c->pos, rgb(0.3,0.3,0.9), cirno_icicles, 6*i*cexp(I*(-0.1+0.1*_i)));
create_projectile1c("crystal", c->pos, rgb(0.3,0.3,0.9), cirno_icicles, 6*i*cexp(I*(M_PI+0.1-0.1*_i)));
PROJECTILE("crystal", c->pos, rgb(0.3,0.3,0.9), cirno_icicles, { 6*i*cexp(I*(-0.1+0.1*_i)) });
PROJECTILE("crystal", c->pos, rgb(0.3,0.3,0.9), cirno_icicles, { 6*i*cexp(I*(M_PI+0.1-0.1*_i)) });
}
}
@ -562,8 +595,8 @@ void cirno_icicle_fall(Boss *c, int time) {
FROM_TO_SND("shot1_loop",120,200,3) {
float f = frand()*_i;
create_projectile2c("ball", c->pos, rgb(0.,0.,0.3), accelerated, 0.2*(-2*I-1.5+f),-0.02*I);
create_projectile2c("ball", c->pos, rgb(0.,0.,0.3), accelerated, 0.2*(-2*I+1.5-f),-0.02*I);
PROJECTILE("ball", c->pos, rgb(0.,0.,0.3), accelerated, { 0.2*(-2*I-1.5+f),-0.02*I });
PROJECTILE("ball", c->pos, rgb(0.,0.,0.3), accelerated, { 0.2*(-2*I+1.5-f),-0.02*I });
}
}
if(global.diff > D_Normal) {
@ -573,8 +606,15 @@ void cirno_icicle_fall(Boss *c, int time) {
float angle1 = M_PI/10*frand();
float angle2 = M_PI/10*frand();
for(float i = 1; i < 5; i++) {
create_projectile2c("ball", x, rgb(0.,0.,0.3), accelerated, i*I*0.5*cexp(I*angle1),0.001*I-(global.diff == D_Lunatic)*0.001*frand());
create_projectile2c("ball", VIEWPORT_W-x, rgb(0.,0.,0.3), accelerated, i*I*0.5*cexp(-I*angle2),0.001*I+(global.diff == D_Lunatic)*0.001*frand());
PROJECTILE("ball", x, rgb(0.,0.,0.3), accelerated, {
i*I*0.5*cexp(I*angle1),
0.001*I-(global.diff == D_Lunatic)*0.001*frand()
});
PROJECTILE("ball", VIEWPORT_W-x, rgb(0.,0.,0.3), accelerated, {
i*I*0.5*cexp(-I*angle2),
0.001*I+(global.diff == D_Lunatic)*0.001*frand()
});
}
}
}
@ -583,11 +623,17 @@ void cirno_icicle_fall(Boss *c, int time) {
}
int cirno_crystal_blizzard_proj(Projectile *p, int time) {
if(!(time % 12))
create_particle1c("stain", p->pos, 0, GrowFadeAdd, timeout, 20)->angle = global.frames * 15;
if(!(time % 12)) {
PARTICLE("stain", p->pos, 0, timeout, { 20 },
.draw_rule = GrowFade,
.angle = global.frames * 15,
.flags = PFLAG_DRAWADD,
);
}
if(time > 100 + global.diff * 100)
if(time > 100 + global.diff * 100) {
p->args[0] *= 1.03;
}
return asymptotic(p, time);
}
@ -605,7 +651,15 @@ void cirno_crystal_blizzard(Boss *c, int time) {
play_sound("shot1");
int i, cnt = 14 + global.diff * 3;
for(i = 0; i < cnt; ++i) {
create_projectile2c("crystal", i*VIEWPORT_W/cnt, i % 2? rgb(0.2,0.2,0.4) : rgb(0.5,0.5,0.5), accelerated, 0, 0.02*I + 0.01*I * (i % 2? 1 : -1) * sin((i*3+global.frames)/30.0));
PROJECTILE(
.texture = "crystal",
.pos = i*VIEWPORT_W/cnt,
.color = i % 2? rgb(0.2,0.2,0.4) : rgb(0.5,0.5,0.5),
.rule = accelerated,
.args = {
0, 0.02*I + 0.01*I * (i % 2? 1 : -1) * sin((i*3+global.frames)/30.0)
},
);
}
}
@ -618,16 +672,32 @@ void cirno_crystal_blizzard(Boss *c, int time) {
if(!(time % (1 + D_Lunatic - global.diff))) {
tsrand_fill(2);
create_projectile2c("wave", c->pos, rgb(0.2, 0.2, 0.4), cirno_crystal_blizzard_proj,
20 * (0.1 + 0.1 * anfrand(0)) * cexp(I*(carg(global.plr.pos - c->pos) + anfrand(1) * 0.2)), 5
)->draw = ProjDrawAdd;
PROJECTILE(
.texture = "wave",
.pos = c->pos,
.color = rgb(0.2, 0.2, 0.4),
.rule = cirno_crystal_blizzard_proj,
.args = {
20 * (0.1 + 0.1 * anfrand(0)) * cexp(I*(carg(global.plr.pos - c->pos) + anfrand(1) * 0.2)),
5
},
.flags = PFLAG_DRAWADD,
);
}
if(!(time % 7)) {
play_sound("shot1");
int i, cnt = global.diff - 1;
for(i = 0; i < cnt; ++i)
create_projectile2c("ball", c->pos, rgb(0.1, 0.1, 0.5), accelerated, 0, 0.01 * cexp(I*(global.frames/20.0 + 2*i*M_PI/cnt)))->draw = ProjDrawAdd;
for(i = 0; i < cnt; ++i) {
PROJECTILE(
.texture = "ball",
.pos = c->pos,
.color = rgb(0.1, 0.1, 0.5),
.rule = accelerated,
.args = { 0, 0.01 * cexp(I*(global.frames/20.0 + 2*i*M_PI/cnt)) },
.flags = PFLAG_DRAWADD,
);
}
}
}
}
@ -646,17 +716,20 @@ void cirno_benchmark(Boss* b, int t) {
double x = frand()*VIEWPORT_W;
double plrx = creal(global.plr.pos);
x = plrx + sqrt((x-plrx)*(x-plrx)+100)*(1-2*(x<plrx));
Projectile *p = create_projectile1c("ball", x, rgb(0.1, 0.1, 0.5), linear, speed*I);
p->grazed=1;
Projectile *p = PROJECTILE("ball", x, rgb(0.1, 0.1, 0.5), linear, { speed*I },
.flags = PFLAG_NOGRAZE,
);
if(t > 350 && frand() > 0.5)
p->draw=ProjDrawAdd;
p->flags |= PFLAG_DRAWADD;
if(t > 700 && frand() > 0.5)
p->tex = get_tex("proj/plainball");
if(t > 1200 && frand() > 0.5)
p->clr = rgb(1.0,0.2,0.8);
}
if(t > 1200 && frand() > 0.5)
p->color = rgb(1.0,0.2,0.8);
}
}
void cirno_superhardspellcard(Boss *c, int t) {
@ -705,7 +778,10 @@ int stage1_burst(Enemy *e, int time) {
play_sound("shot1");
for(i = -n; i <= n; i++) {
create_projectile2c("crystal", e->pos, rgb(0.2, 0.3, 0.5), asymptotic, (2+0.1*global.diff)*cexp(I*(carg(global.plr.pos - e->pos) + 0.2*i)), 5);
PROJECTILE("crystal", e->pos, rgb(0.2, 0.3, 0.5), asymptotic, {
(2+0.1*global.diff)*cexp(I*(carg(global.plr.pos - e->pos) + 0.2*i)),
5
});
}
e->moving = true;
@ -734,14 +810,20 @@ int stage1_circletoss(Enemy *e, int time) {
int dur = 40;
FROM_TO_SND("shot1_loop",60,60+dur,inter) {
e->args[0] = 0.5*e->args[0];
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 2*cexp(I*2*M_PI*inter/dur*_i), _i/2.0);
PROJECTILE("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, {
2*cexp(I*2*M_PI*inter/dur*_i),
_i/2.0 }
);
}
if(global.diff > D_Easy) {
FROM_TO_INT_SND("shot1_loop",90,500,150,5+7*global.diff,1) {
tsrand_fill(2);
create_projectile2c("thickrice", e->pos, rgb(0.2, 0.4, 0.8), asymptotic, (1+afrand(0)*2)*cexp(I*carg(global.plr.pos - e->pos)+0.05*I*global.diff*anfrand(1)), 3);
PROJECTILE("thickrice", e->pos, rgb(0.2, 0.4, 0.8), asymptotic, {
(1+afrand(0)*2)*cexp(I*carg(global.plr.pos - e->pos)+0.05*I*global.diff*anfrand(1)),
3
});
}
}
@ -764,7 +846,9 @@ int stage1_sinepass(Enemy *e, int time) {
if(frand() > 0.997-0.005*(global.diff-1)) {
play_sound("shot1");
create_projectile1c("ball", e->pos, rgb(0.8,0.8,0.4), linear, (1+0.2*global.diff+frand())*cexp(I*carg(global.plr.pos - e->pos)));
PROJECTILE("ball", e->pos, rgb(0.8,0.8,0.4), linear, {
(1+0.2*global.diff+frand())*cexp(I*carg(global.plr.pos - e->pos))
});
}
return 1;
@ -784,7 +868,9 @@ int stage1_drop(Enemy *e, int t) {
FROM_TO(10,1000,1) {
if(frand() > 0.997-0.007*(global.diff-1)) {
play_sound("shot1");
create_projectile1c("ball", e->pos, rgb(0.8,0.8,0.4), linear, (1+0.3*global.diff+frand())*cexp(I*carg(global.plr.pos - e->pos)));
PROJECTILE("ball", e->pos, rgb(0.8,0.8,0.4), linear, {
(1+0.3*global.diff+frand())*cexp(I*carg(global.plr.pos - e->pos))
});
}
}
@ -802,7 +888,10 @@ int stage1_circle(Enemy *e, int t) {
e->pos += (e->args[0] - e->pos)*0.02;
FROM_TO_INT_SND("shot1_loop",150, 550, 40, 40, 2+2*(global.diff<D_Hard)) {
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, (1.7+0.2*global.diff)*cexp(I*M_PI/10*_ni), _ni/2.0);
PROJECTILE("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, {
(1.7+0.2*global.diff)*cexp(I*M_PI/10*_ni),
_ni/2.0
});
}
FROM_TO(560,1000,1)
@ -825,8 +914,11 @@ int stage1_multiburst(Enemy *e, int t) {
play_sound("shot1");
int i;
int n = global.diff-1;
for(i = -n; i <= n; i++)
create_projectile1c("crystal", e->pos, rgb(0.2, 0.3, 0.5), linear, 2.5*cexp(I*(carg(global.plr.pos - e->pos) + i/5.0)));
for(i = -n; i <= n; i++) {
PROJECTILE("crystal", e->pos, rgb(0.2, 0.3, 0.5), linear, {
2.5*cexp(I*(carg(global.plr.pos - e->pos) + i/5.0))
});
}
}
FROM_TO(320, 700, 1) {
@ -853,15 +945,22 @@ int stage1_instantcircle(Enemy *e, int t) {
AT(150) {
play_sound("shot_special1");
for(i = 0; i < 20+2*global.diff; i++) {
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 1.5*cexp(I*2*M_PI/(20.0+global.diff)*i), 2.0);
PROJECTILE("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, {
1.5*cexp(I*2*M_PI/(20.0+global.diff)*i),
2.0
});
}
}
AT(170) {
if(global.diff > D_Easy) {
play_sound("shot_special1");
for(i = 0; i < 20+3*global.diff; i++)
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 3*cexp(I*2*M_PI/(20.0+global.diff)*i), 3.0);
for(i = 0; i < 20+3*global.diff; i++) {
PROJECTILE("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, {
3*cexp(I*2*M_PI/(20.0+global.diff)*i),
3.0
});
}
}
}
@ -888,17 +987,29 @@ int stage1_tritoss(Enemy *e, int t) {
int i;
int n = 3+global.diff/2;
for(i = 0; i < n; i++)
create_projectile2c("thickrice", e->pos, rgb(0.2, 0.4, 0.8), asymptotic, 2*cexp(I*a+2.0*I*M_PI/n*i), 3);
for(i = 0; i < n; i++){
PROJECTILE("thickrice", e->pos, rgb(0.2, 0.4, 0.8), asymptotic, {
2*cexp(I*a+2.0*I*M_PI/n*i),
3
});
}
}
FROM_TO(480, 800, 300) {
play_sound("shot_special1");
int i, n = 15 + global.diff*3;
for(i = 0; i < n; i++) {
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 1.5*cexp(I*2*M_PI/n*i), 2.0);
if(global.diff > D_Easy)
create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 3*cexp(I*2*M_PI/n*i), 3.0);
PROJECTILE("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, {
1.5*cexp(I*2*M_PI/n*i),
2.0
});
if(global.diff > D_Easy) {
PROJECTILE("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, {
3*cexp(I*2*M_PI/n*i),
3.0
});
}
}
}
@ -915,6 +1026,26 @@ void stage1_events(void) {
stage_start_bgm("stage1");
}
#ifdef TASTE_THE_RAINBOW
FROM_TO(60, 1000000000, 30) {
int cnt = 16;
for(int i = 0; i < cnt; ++i) {
PROJECTILE(
.texture = "bigball",
.pos = VIEWPORT_W * (i+0.5) / cnt,
.rule = timeout_linear,
.args = { 500, I },
.color = hsl(i/(cnt+1.0), 1.0, 0.5),
// .draw_rule = Fade,
// .flags = PFLAG_DRAWADD,
);
}
}
return;
#endif
// opening. projectile bursts
FROM_TO(100, 160, 25) {
create_enemy1c(VIEWPORT_W/2 + 70, 700, Fairy, stage1_burst, 1 + 0.6*I);

View file

@ -68,11 +68,17 @@ int stage2_great_circle(Enemy *e, int t) {
for(n = 0; n < c; n++) {
complex dir = cexp(I*(2*M_PI/c*n+partdist*(_i%c2-c2/2)+bunchdist*(_i/c2)));
create_projectile2c("rice", e->pos+30*dir, rgb(0.6,0.0,0.3), asymptotic, 1.5*dir, _i%5);
PROJECTILE("rice", e->pos+30*dir, rgb(0.6,0.0,0.3), asymptotic, {
1.5*dir,
_i%5
});
if(global.diff > D_Easy && _i%7 == 0) {
play_sound("shot1");
create_projectile1c("bigball", e->pos+30*dir, rgb(0.3,0.0,0.6), linear, 1.7*dir*cexp(0.3*I*frand()));
PROJECTILE("bigball", e->pos+30*dir, rgb(0.3,0.0,0.6), linear, {
1.7*dir*cexp(0.3*I*frand())
});
}
}
}
@ -110,7 +116,9 @@ int stage2_small_spin_circle(Enemy *e, int t) {
play_sound("shot1");
}
create_projectile1c("ball", e->pos, rgb(0.9,0.0,0.3), linear, pow(global.diff,0.7)*(conj(e->pos-VIEWPORT_W/2)/100 + ((1-2*e->dir)+3.0*I)));
PROJECTILE("ball", e->pos, rgb(0.9,0.0,0.3), linear, {
pow(global.diff,0.7)*(conj(e->pos-VIEWPORT_W/2)/100 + ((1-2*e->dir)+3.0*I))
});
}
return 1;
@ -131,8 +139,14 @@ int stage2_aim(Enemy *e, int t) {
AT(90) {
if(global.diff > D_Normal) {
play_sound("shot1");
create_projectile2c("plainball", e->pos, rgb(0.6,0.0,0.8), asymptotic, 5*cexp(I*carg(global.plr.pos-e->pos)), -1);
create_projectile1c("plainball", e->pos, rgb(0.2,0.0,0.1), linear, 3*cexp(I*carg(global.plr.pos-e->pos)));
PROJECTILE("plainball", e->pos, rgb(0.6,0.0,0.8), asymptotic, {
5*cexp(I*carg(global.plr.pos-e->pos)),
-1
});
PROJECTILE("plainball", e->pos, rgb(0.2,0.0,0.1), linear, {
3*cexp(I*carg(global.plr.pos-e->pos))
});
}
}
@ -158,8 +172,8 @@ int stage2_sidebox_trail(Enemy *e, int t) { // creal(a[0]): velocity, cimag(a[0]
if(global.diff > D_Normal)
f = 0.03*global.diff*frand();
create_projectile1c("rice", e->pos, rgb(0.9,0.0,0.9), linear, 3*cexp(I*(cimag(e->args[0])+f+0.5*M_PI)));
create_projectile1c("rice", e->pos, rgb(0.9,0.0,0.9), linear, 3*cexp(I*(cimag(e->args[0])-f-0.5*M_PI)));
PROJECTILE("rice", e->pos, rgb(0.9,0.0,0.9), linear, { 3*cexp(I*(cimag(e->args[0])+f+0.5*M_PI)) });
PROJECTILE("rice", e->pos, rgb(0.9,0.0,0.9), linear, { 3*cexp(I*(cimag(e->args[0])-f-0.5*M_PI)) });
}
return 1;
@ -184,7 +198,10 @@ int stage2_flea(Enemy *e, int t) {
FROM_TO(10, 400, 30-global.diff*3-t/70) {
if(global.diff == D_Easy) {
play_sound("shot1");
create_projectile2c("flea", e->pos, rgb(0.3,0.2,1), asymptotic, 1.5*cexp(2.0*I*M_PI*frand()), 1.5);
PROJECTILE("flea", e->pos, rgb(0.3,0.2,1), asymptotic, {
1.5*cexp(2.0*I*M_PI*frand()),
1.5
});
}
}
@ -206,7 +223,10 @@ int stage2_accel_circle(Enemy *e, int t) {
int i;
for(i = 0; i < 6; i++) {
play_sound("redirect");
create_projectile2c("ball", e->pos, rgb(0.6,0.1,0.2), accelerated, 1.5*cexp(2.0*I*M_PI/6*i)+cexp(I*carg(global.plr.pos - e->pos)), -0.02*cexp(I*(2*M_PI/6*i+0.02*frand()*global.diff)));
PROJECTILE("ball", e->pos, rgb(0.6,0.1,0.2), accelerated, {
1.5*cexp(2.0*I*M_PI/6*i)+cexp(I*carg(global.plr.pos - e->pos)),
-0.02*cexp(I*(2*M_PI/6*i+0.02*frand()*global.diff))
});
}
}
@ -239,7 +259,7 @@ int wriggle_bug(Projectile *p, int t) {
if(global.boss && global.boss->current && !((global.frames - global.boss->current->starttime - 30) % 200)) {
play_sound("redirect");
p->args[0] *= cexp(I*(M_PI/3)*nfrand());
create_particle2c("flare", p->pos, 0, GrowFade, timeout, 15, 5);
PARTICLE("flare", p->pos, 0, timeout, { 15, 5 }, .draw_rule = GrowFade);
}
return 1;
@ -253,8 +273,8 @@ void wriggle_small_storm(Boss *w, int time) {
return;
FROM_TO_SND("shot1_loop", 0,400,5-global.diff) {
create_projectile1c("rice", w->pos, rgb(1,0.5,0.2), wriggle_bug, 2*cexp(I*_i*2*M_PI/20));
create_projectile1c("rice", w->pos, rgb(1,0.5,0.2), wriggle_bug, 2*cexp(I*_i*2*M_PI/20+I*M_PI));
PROJECTILE("rice", w->pos, rgb(1,0.5,0.2), wriggle_bug, { 2*cexp(I*_i*2*M_PI/20) });
PROJECTILE("rice", w->pos, rgb(1,0.5,0.2), wriggle_bug, { 2*cexp(I*_i*2*M_PI/20+I*M_PI) });
}
GO_AT(w, 60, 120, 1)
@ -264,8 +284,12 @@ void wriggle_small_storm(Boss *w, int time) {
int i;
aniplayer_queue(&w->ani,1,0,0)->speed=4;
play_sound("shot_special1");
for(i = 0; i < 10+global.diff; i++) {
create_projectile2c("bigball", w->pos, rgb(0.1,0.3,0.0), asymptotic, 2*cexp(I*i*2*M_PI/(10+global.diff)), 2);
PROJECTILE("bigball", w->pos, rgb(0.1,0.3,0.0), asymptotic, {
2*cexp(I*i*2*M_PI/(10+global.diff)),
2
});
}
}
}
@ -311,8 +335,8 @@ void hina_cards1(Boss *h, int time) {
h->ani.stdrow = 1;
FROM_TO(0, 500, 2-(global.diff > D_Normal)) {
play_sound_ex("shot1", 4, false);
create_projectile2c("card", h->pos+50*cexp(I*t/10), rgb(0.8,0.0,0.0), asymptotic, (1.6+0.4*global.diff)*cexp(I*t/5.0), 3);
create_projectile2c("card", h->pos-50*cexp(I*t/10), rgb(0.0,0.0,0.8), asymptotic, -(1.6+0.4*global.diff)*cexp(I*t/5.0), 3);
PROJECTILE("card", h->pos+50*cexp(I*t/10), rgb(0.8,0.0,0.0), asymptotic, { (1.6+0.4*global.diff)*cexp(I*t/5.0), 3 });
PROJECTILE("card", h->pos-50*cexp(I*t/10), rgb(0.0,0.0,0.8), asymptotic, {-(1.6+0.4*global.diff)*cexp(I*t/5.0), 3 });
}
}
@ -339,8 +363,11 @@ void hina_amulet(Boss *h, int time) {
complex p = h->pos+30*log(1+_i/2.0)*n;
create_projectile2c("ball", p, rgb(0.8,0,0), accelerated, speed * 2*n*I, accel * -0.01*n);
create_projectile2c(global.diff == D_Easy ? "ball" : "crystal", p, rgb(0.8,0,0.5), accelerated, speed * -2*n*I, accel * -0.01*n);
const char *t0 = "ball";
const char *t1 = global.diff == D_Easy ? t0 : "crystal";
PROJECTILE(t0, p, rgb(0.8, 0.0, 0.0), accelerated, { speed * 2*n*I, accel * -0.01*n });
PROJECTILE(t1, p, rgb(0.8, 0.0, 0.5), accelerated, { speed * -2*n*I, accel * -0.01*n });
}
}
@ -361,7 +388,10 @@ void hina_cards2(Boss *h, int time) {
int i;
for(i = 0; i < 30; i++) {
play_sound("shot_special1");
create_projectile2c("bigball", h->pos, rgb(0.7, 0, 0.7), asymptotic, 2*cexp(I*2*M_PI*i/20.0), 3);
PROJECTILE("bigball", h->pos, rgb(0.7, 0, 0.7), asymptotic, {
2*cexp(I*2*M_PI*i/20.0),
3
});
}
}
}
@ -399,8 +429,9 @@ void hina_bad_pick(Boss *h, int time) {
play_sound_ex("shot1", 4, false);
for(i = 1; i < SLOTS; i++) {
create_projectile1c("crystal", VIEWPORT_W/SLOTS*i, rgb(0.5,0,0.6), linear, 7.0*I);
PROJECTILE("crystal", VIEWPORT_W/SLOTS*i, rgb(0.5,0,0.6), linear, { 7.0*I });
}
if(global.diff >= D_Hard) {
double shift = 0;
if(global.diff == D_Lunatic)
@ -409,7 +440,7 @@ void hina_bad_pick(Boss *h, int time) {
double height = VIEWPORT_H/SLOTS*i+shift;
if(height > VIEWPORT_H-40)
height -= VIEWPORT_H-40;
create_projectile1c("crystal", (i&1)*VIEWPORT_W+I*height, rgb(0.5,0,0.6), linear, 5.0*(1-2*(i&1)));
PROJECTILE("crystal", (i&1)*VIEWPORT_W+I*height, rgb(0.5,0,0.6), linear, { 5.0*(1-2*(i&1)) });
}
}
}
@ -426,7 +457,15 @@ void hina_bad_pick(Boss *h, int time) {
float cnt = (1+min(D_Normal,global.diff)) * 5;
for(j = 0; j < cnt; j++) {
complex o = VIEWPORT_W/SLOTS*(i + j/(cnt-1));
create_projectile3c("ball", o, rgb(0.7,0,0.0), bad_pick_bullet, 0, 0.005*nfrand() + 0.005*I * (1 + psin(i + j + global.frames)),i)->draw = ProjDrawAdd;
PROJECTILE("ball", o, rgb(0.7,0,0.0), bad_pick_bullet,
.args = {
0,
0.005*nfrand() + 0.005*I * (1 + psin(i + j + global.frames)),
i
},
.flags = PFLAG_DRAWADD,
);
}
}
}
@ -468,7 +507,7 @@ void hina_wheel(Boss *h, int time) {
for(i = 1; i < 6+d; i++) {
float a = dir * 2*M_PI/(5+d)*(i+(1 + 0.4 * d)*time/100.0+(1 + 0.2 * d)*frand()*time/1700.0);
create_projectile1c("crystal", h->pos, rgb(log(1+time*1e-3),0,0.2), linear, speed*cexp(I*a));
PROJECTILE("crystal", h->pos, rgb(log(1+time*1e-3),0,0.2), linear, { speed*cexp(I*a) });
}
}
}
@ -489,12 +528,24 @@ int hina_monty_slave(Enemy *s, int time) {
if(time > 60 && time < 720-140 + 20*(global.diff-D_Lunatic) && !(time % (int)(max(2 + (global.diff < D_Normal), (120 - 0.5 * time))))) {
play_loop("shot1_loop");
create_projectile2c("crystal", s->pos, rgb(0.5 + 0.5 * psin(time*0.2), 0.3, 1.0 - 0.5 * psin(time*0.2)),
asymptotic, 5*I + 1 * (sin(time) + I * cos(time)), 4);
PROJECTILE("crystal", s->pos,
.color = rgb(0.5 + 0.5 * psin(time*0.2), 0.3, 1.0 - 0.5 * psin(time*0.2)),
.rule = asymptotic,
.args = {
5*I + 1 * (sin(time) + I * cos(time)),
4
}
);
if(global.diff > D_Easy) {
create_projectile2c("crystal", s->pos, rgb(0.5 + 0.5 * psin(time*0.2), 0.3, 1.0 - 0.5 * psin(time*0.2)),
timeout_deadproj_linear, 500, -0.5*I + 1 * (sin(time) + I * cos(time)));
PROJECTILE("crystal", s->pos,
.color = rgb(0.5 + 0.5 * psin(time*0.2), 0.3, 1.0 - 0.5 * psin(time*0.2)),
.rule = timeout_deadproj_linear,
.args = {
500,
-0.5*I + 1 * (sin(time) + I * cos(time))
}
);
}
}
@ -505,12 +556,14 @@ void hina_monty_slave_draw(Enemy *s, int time) {
Swirl(s, time);
Texture *soul = get_tex("proj/soul");
Shader *shader = get_shader("bullet_color");
Shader *shader = recolor_get_shader();
double scale = fabs(swing(clamp(time / 60.0, 0, 1), 3)) * 1.25;
float clr1[] = {1.0, 0.0, 0.0, 1.0};
float clr2[] = {0.0, 0.0, 1.0, 1.0};
float clr3[] = {psin(time*0.05), 0.0, 1.0 - psin(time*0.05), 1.0};
ColorTransform ct;
Color clr1 = rgba(1.0, 0.0, 0.0, 1.0);
Color clr2 = rgba(0.0, 0.0, 1.0, 1.0);
Color clr3 = rgba(psin(time*0.05), 0.0, 1.0 - psin(time*0.05), 1.0);
glUseProgram(shader->prog);
@ -519,21 +572,24 @@ void hina_monty_slave_draw(Enemy *s, int time) {
glTranslatef(creal(s->pos), cimag(s->pos), 0);
glUniform4fv(uniloc(shader, "color"), 1, clr1);
static_clrtransform_bullet(clr1, &ct);
recolor_apply_transform(&ct);
glPushMatrix();
glRotatef(time, 0, 0, 1);
glScalef(scale * (0.6 + 0.6 * psin(time*0.1)), scale * (0.7 + 0.5 * psin(time*0.1 + M_PI)), 0);
draw_texture_p(0, 0, soul);
glPopMatrix();
glUniform4fv(uniloc(shader, "color"), 1, clr2);
static_clrtransform_bullet(clr2, &ct);
recolor_apply_transform(&ct);
glPushMatrix();
glRotatef(time, 0, 0, 1);
glScalef(scale * (0.7 + 0.5 * psin(time*0.1 + M_PI)), scale * (0.6 + 0.6 * psin(time*0.1)), 0);
draw_texture_p(0, 0, soul);
glPopMatrix();
glUniform4fv(uniloc(shader, "color"), 1, clr3);
static_clrtransform_bullet(clr3, &ct);
recolor_apply_transform(&ct);
glPushMatrix();
glRotatef(-time, 0, 0, 1);
// glScalef(scale * (0.7 + 0.5 * psin(time*0.1 + M_PI)), scale * (0.6 + 0.6 * psin(time*0.1)), 0);
@ -615,9 +671,16 @@ void hina_monty(Boss *h, int time) {
for(int i = 0; i < cnt; i++) {
bool top = ((global.diff > D_Hard) && (_i % 2));
complex o = !top*VIEWPORT_H*I + cwidth*(bad_pos + i/(double)(cnt - 1));
create_projectile2c("ball", o, top ? rgb(0, 0, 0.7) : rgb(0.7, 0, 0), accelerated, 0,
(top ? -0.5 : 1) * 0.004 * (sin((M_PI * 4 * i / (cnt - 1)))*0.1*global.diff - I*(1 + psin(i + global.frames)))
)->draw = ProjDrawAdd;
PROJECTILE("ball", o,
.color = top ? rgb(0, 0, 0.7) : rgb(0.7, 0, 0),
.rule = accelerated,
.args = {
0,
(top ? -0.5 : 1) * 0.004 * (sin((M_PI * 4 * i / (cnt - 1)))*0.1*global.diff - I*(1 + psin(i + global.frames)))
},
.flags = PFLAG_DRAWADD,
);
}
}
@ -647,10 +710,12 @@ void hina_monty(Boss *h, int time) {
}
complex o = cwidth * (p + 0.5/(cnt-1) - 0.5) + h->pos;
if(global.diff > D_Normal)
create_projectile2c("card", o, rgb(c * 0.8, 0, (1 - c) * 0.8), accelerated, -2.5*I, 0.05*I);
else
create_projectile1c("card", o, rgb(c * 0.8, 0, (1 - c) * 0.8), linear, 2.5*I);
if(global.diff > D_Normal) {
PROJECTILE("card", o, rgb(c * 0.8, 0, (1 - c) * 0.8), accelerated, { -2.5*I, 0.05*I });
} else {
PROJECTILE("card", o, rgb(c * 0.8, 0, (1 - c) * 0.8), linear, { 2.5*I });
}
}
}

View file

@ -72,10 +72,10 @@ static int stage3_enterswirl(Enemy *e, int t) {
double a = (M_PI * 2.0 * i) / cnt;
complex dir = cexp(I*a);
create_projectile2c(e->args[1]? "ball" : "rice", e->pos, rgb(r, g, 1.0), asymptotic,
PROJECTILE(e->args[1]? "ball" : "rice", e->pos, rgb(r, g, 1.0), asymptotic, {
1.5 * dir,
10 - 10 * psin(2 * a + M_PI/2)
);
});
}
return 1;
@ -113,14 +113,19 @@ static int stage3_slavefairy(Enemy *e, int t) {
float a = _i * 0.5;
complex dir = cexp(I*a);
create_projectile2c("wave", e->pos + dir * 10, (_i % 2)? rgb(1.0, 0.3, 0.3) : rgb(0.3, 0.3, 1.0), accelerated,
dir * 2,
dir * -0.035
PROJECTILE("wave",
.pos = e->pos + dir * 10,
.color = (_i % 2)? rgb(1.0, 0.3, 0.3) : rgb(0.3, 0.3, 1.0),
.rule = accelerated,
.args = {
dir * 2,
dir * -0.035,
},
);
if(global.diff > D_Easy && e->args[1]) create_projectile1c("ball", e->pos + dir * 10, rgb(1.0, 0.6, 0.3), linear,
dir * (1.0 + 0.5 * sin(a))
);
if(global.diff > D_Easy && e->args[1]) {
PROJECTILE("ball", e->pos + dir * 10, rgb(1.0, 0.6, 0.3), linear, { dir * (1.0 + 0.5 * sin(a)) });
}
}
if(t >= 120) {
@ -154,9 +159,10 @@ static int stage3_slavefairy2(Enemy *e, int t) {
}
complex dir = cexp(I*a);
create_projectile1c("wave",e->pos,_i&1 ? rgb(1.0,0.3,0.3): rgb(0.3,0.3,1.0), linear, 2*dir);
PROJECTILE("wave", e->pos, _i&1 ? rgb(1.0,0.3,0.3): rgb(0.3,0.3,1.0), linear, { 2*dir });
if(global.diff > D_Normal && _i % 3 == 0) {
create_projectile1c("rice",e->pos,_i&1==0 ? rgb(1.0,0.3,0.3): rgb(0.3,0.3,1.0), linear, -2*dir);
PROJECTILE("rice", e->pos, _i&1==0 ? rgb(1.0,0.3,0.3): rgb(0.3,0.3,1.0), linear, { -2*dir });
}
}
@ -174,8 +180,16 @@ static void charge_effect(Enemy *e, int t, int chargetime) {
complex n = cexp(2.0*I*M_PI*frand());
float l = 50*frand()+25;
float s = 4+_i*0.01;
float alpha = 0.5;
create_particle2c("flare", e->pos+l*n, rgb(alpha, alpha, 0.5*alpha), FadeAdd, timeout_linear, l/s, -s*n);
PARTICLE(
.texture = "flare",
.pos = e->pos+l*n,
.color = rgb(0.5, 0.5, 0.25),
.draw_rule = Fade,
.rule = timeout_linear,
.args = { l/s, -s*n },
.flags = PFLAG_DRAWADD
);
}
}
@ -206,10 +220,10 @@ static int stage3_burstfairy(Enemy *e, int t) {
int cnt = 6 + 4 * global.diff;
for(int p = 0; p < cnt; ++p) {
complex dir = cexp(I*M_PI*2*p/cnt);
create_projectile2c("ball", e->args[0],
rgb(0.2, 0.1, 0.5), asymptotic,
dir, 10 + 4 * global.diff
);
PROJECTILE("ball", e->args[0], rgb(0.2, 0.1, 0.5), asymptotic, {
dir,
10 + 4 * global.diff
});
}
}
}
@ -229,9 +243,13 @@ static int stage3_burstfairy(Enemy *e, int t) {
int cnt = 5 + global.diff;
for(int p = 0; p < cnt; ++p) {
for(int i = -1; i < 2; i += 2) {
create_projectile2c("bullet", e->pos + dir * 10,
mix_colors(rgb(1.0, 0.0, 0.0), rgb(0.0, 0.0, 1.0), psin(M_PI * phase)), asymptotic,
1.5 * dir * (1 + p / (cnt - 1.0)) * i, 3 * global.diff
PROJECTILE("bullet", e->pos + dir * 10,
.color = mix_colors(rgb(1.0, 0.0, 0.0), rgb(0.0, 0.0, 1.0), psin(M_PI * phase)),
.rule = asymptotic,
.args = {
1.5 * dir * (1 + p / (cnt - 1.0)) * i,
3 * global.diff
},
);
}
}
@ -317,9 +335,13 @@ static int stage3_chargefairy(Enemy *e, int t) {
complex paim = e->pos + (w+1) * aim - o;
paim /= cabs(paim);
create_projectile3c("wave", o,
mix_colors(rgb(1.0, 0.0, 0.0), rgb(0.0, 0.0, 1.0), f), stage3_chargefairy_proj,
paim, 6 + global.diff - layer, chargetime + 30 - t
PROJECTILE("wave", o,
.color = mix_colors(rgb(1.0, 0.0, 0.0), rgb(0.0, 0.0, 1.0), f),
.rule = stage3_chargefairy_proj,
.args = {
paim, 6 + global.diff - layer,
chargetime + 30 - t
},
);
}
}
@ -383,10 +405,10 @@ static int stage3_bitchswirl(Enemy *e, int t) {
}
FROM_TO(0, 120, 20) {
create_projectile2c("flea", e->pos, rgb(.7, 0.0, 0.5), accelerated,
PROJECTILE("flea", e->pos, rgb(.7, 0.0, 0.5), accelerated, {
2*cexp(I*carg(global.plr.pos - e->pos)),
0.005*cexp(I*(M_PI*2 * frand())) * (global.diff > D_Easy)
);
});
play_sound("shot1");
}
@ -421,9 +443,17 @@ static int stage3_cornerfairy(Enemy *e, int t) {
float c = psin(t / 15.0);
bool wave = global.diff > D_Easy && cabs(e->args[2]);
create_projectile2c(wave ? "wave" : "thickrice", e->pos, cabs(e->args[2])? rgb(0.5 - c*0.2, 0.3 + c*0.7, 1.0) : rgb(1.0 - c*0.5, 0.6, 0.5 + c*0.5), asymptotic,
(1.8-0.4*wave*!!(e->args[2]))*cexp(I*((2*i*M_PI/cnt)+carg((VIEWPORT_W+I*VIEWPORT_H)/2 - e->pos))),
1.5
PROJECTILE(
.texture = wave ? "wave" : "thickrice",
.pos = e->pos,
.color = cabs(e->args[2])
? rgb(0.5 - c*0.2, 0.3 + c*0.7, 1.0)
: rgb(1.0 - c*0.5, 0.6, 0.5 + c*0.5),
.rule = asymptotic,
.args = {
(1.8-0.4*wave*!!(e->args[2]))*cexp(I*((2*i*M_PI/cnt)+carg((VIEWPORT_W+I*VIEWPORT_H)/2 - e->pos))),
1.5
},
);
}
}
@ -458,9 +488,15 @@ static int scuttle_poison(Projectile *p, int time) {
float a = p->args[2];
float t = p->args[3] + time;
create_projectile2c((frand() > 0.5)? "thickrice" : "rice", p->pos, rgb(0.3, 0.7 + 0.3 * psin(a/3.0 + t/20.0), 0.3), accelerated,
PROJECTILE(
.texture = (frand() > 0.5)? "thickrice" : "rice",
.pos = p->pos,
.color = rgb(0.3, 0.7 + 0.3 * psin(a/3.0 + t/20.0), 0.3),
.rule = accelerated,
.args = {
0,
0.005*cexp(I*(M_PI*2 * sin(a/5.0 + t/20.0)))
0.005*cexp(I*(M_PI*2 * sin(a/5.0 + t/20.0))),
},
);
play_sound("redirect");
@ -486,13 +522,27 @@ static int scuttle_lethbite_proj(Projectile *p, int time) {
tsrand_fill(2);
Color clr = rgba(1.0,0.8,0.8,0.8);
create_particle3c("lasercurve", 0, clr, EnemyFlareShrink, enemy_flare, 100, cexp(I*(M_PI*anfrand(0))) * (1 + afrand(1)), add_ref(p));
PARTICLE(
.texture = "lasercurve",
.color = clr,
.draw_rule = EnemyFlareShrink,
.rule = enemy_flare,
.args = {
100,
cexp(I*(M_PI*anfrand(0))) * (1 + afrand(1)),
add_ref(p)
},
.flags = PFLAG_DRAWADD,
);
float offset = global.frames/15.0;
if(global.diff > D_Hard && global.boss)
if(global.diff > D_Hard && global.boss) {
offset = M_PI+carg(global.plr.pos-global.boss->pos);
create_projectile1c("thickrice", p->pos, rgb(0.4, 0.3, 1.0), linear,-cexp(I*(i*2*M_PI/cnt + offset)) * (1.0 + (global.diff > D_Normal))
);
}
PROJECTILE("thickrice", p->pos, rgb(0.4, 0.3, 1.0), linear, {
-cexp(I*(i*2*M_PI/cnt + offset)) * (1.0 + (global.diff > D_Normal))
});
}
play_sound("redirect");
@ -515,9 +565,12 @@ static void scuttle_lethbite(Boss *boss, int time) {
for(i = 0; i < cnt; ++i) {
complex v = (2 - psin((max(3, global.diff+1)*2*M_PI*i/(float)cnt) + time)) * cexp(I*2*M_PI/cnt*i);
create_projectile2c("wave", boss->pos - v * 50, _i % 2? rgb(0.7, 0.3, 0.0) : rgb(0.3, .7, 0.0), scuttle_lethbite_proj,
v,
2.0
PROJECTILE(
.texture = "wave",
.pos = boss->pos - v * 50,
.color = _i % 2? rgb(0.7, 0.3, 0.0) : rgb(0.3, .7, 0.0),
.rule = scuttle_lethbite_proj,
.args = { v, 2.0 },
);
}
@ -548,11 +601,17 @@ void scuttle_deadly_dance(Boss *boss, int time) {
if(!(time % 70)) {
for(i = 0; i < 15; ++i) {
double a = M_PI/(5 + global.diff) * i * 2;
create_projectile4c("wave", boss->pos, rgb(0.3, 0.3 + 0.7 * psin(a*3 + time/50.0), 0.3), scuttle_poison,
0,
0.02 * cexp(I*(a+time/10.0)),
a,
time
PROJECTILE(
.texture = "wave",
.pos = boss->pos,
.color = rgb(0.3, 0.3 + 0.7 * psin(a*3 + time/50.0), 0.3),
.rule = scuttle_poison,
.args = {
0,
0.02 * cexp(I*(a+time/10.0)),
a,
time
}
);
}
@ -561,10 +620,12 @@ void scuttle_deadly_dance(Boss *boss, int time) {
if(global.diff > D_Easy && !(time % 35)) {
int cnt = global.diff * 2;
for(i = 0; i < cnt; ++i) create_projectile2c("ball", boss->pos, rgb(1.0, 1.0, 0.3), asymptotic,
(0.5 + 3 * psin(time + M_PI/3*2*i)) * cexp(I*(time / 20.0 + M_PI/cnt*i*2)),
1.5
);
for(i = 0; i < cnt; ++i) {
PROJECTILE("ball", boss->pos, rgb(1.0, 1.0, 0.3), asymptotic, {
(0.5 + 3 * psin(time + M_PI/3*2*i)) * cexp(I*(time / 20.0 + M_PI/cnt*i*2)),
1.5
});
}
play_sound("shot1");
}
@ -573,8 +634,14 @@ void scuttle_deadly_dance(Boss *boss, int time) {
if(!(time % 3)) {
for(i = -1; i < 2; i += 2) {
double c = psin(time/10.0);
create_projectile1c("crystal", boss->pos, rgba(0.3 + c * 0.7, 0.6 - c * 0.3, 0.3, 0.7), linear,
10 * cexp(I*(carg(global.plr.pos - boss->pos) + (M_PI/4.0 * i * (1-time/2500.0)) * (1 - 0.5 * psin(time/15.0))))
PROJECTILE(
.texture = "crystal",
.pos = boss->pos,
.color = rgba(0.3 + c * 0.7, 0.6 - c * 0.3, 0.3, 0.7),
.rule = linear,
.args = {
10 * cexp(I*(carg(global.plr.pos - boss->pos) + (M_PI/4.0 * i * (1-time/2500.0)) * (1 - 0.5 * psin(time/15.0))))
}
);
}
}
@ -658,7 +725,19 @@ static void wriggle_slave_draw(Enemy *e, int time) {
if(time % 5 == 0) {
tsrand_fill(2);
create_particle3c("lasercurve", 5*cexp(2*I*M_PI*afrand(0)), rgba(1,1,0.8,0.6), EnemyFlareShrink, enemy_flare, 60, 0.3*cexp(2*M_PI*I*afrand(1)),add_ref(e));
PARTICLE(
.texture = "lasercurve",
.pos = 5*cexp(2*I*M_PI*afrand(0)),
.color = rgba(1,1,0.8,0.6),
.draw_rule = EnemyFlareShrink,
.rule = enemy_flare,
.args = {
60,
0.3*cexp(2*M_PI*I*afrand(1)),
add_ref(e),
},
.flags = PFLAG_DRAWADD,
);
}
}
@ -677,7 +756,18 @@ static int wriggle_rocket_laserbullet(Projectile *p, int time) {
Laser *l = create_lasercurve2c(p->pos, deathtime, deathtime, rgb(0.4, 0.9, 1.0), las_accel, 0, accel);
l->width = 15;
create_projectile_p(&global.projs, p->tex, p->pos, p->clr, p->draw, wriggle_rocket_laserbullet, add_ref(l), deathtime - 1, 0, 0);
PROJECTILE(
.texture_ptr = p->tex,
.pos = p->pos,
.color = p->color,
.draw_rule = p->draw_rule,
.rule = wriggle_rocket_laserbullet,
.args = {
add_ref(l),
deathtime - 1
}
);
play_sound("redirect");
play_sound("shot_special1");
@ -685,9 +775,17 @@ static int wriggle_rocket_laserbullet(Projectile *p, int time) {
int cnt = floor(2 + frand() * global.diff), i;
for(i = 0; i < cnt; ++i) {
create_projectile2c("thickrice", p->pos, (i % 2) ? rgb(1.0, 0.4, 0.6) : rgb(0.6, 0.4, 1.0), asymptotic,
(0.1 + frand()) * cexp(I*(2*i*M_PI/cnt+time)), 5
)->draw = ProjDrawAdd;
PROJECTILE(
.texture = "thickrice",
.pos = p->pos,
.color = (i % 2) ? rgb(1.0, 0.4, 0.6) : rgb(0.6, 0.4, 1.0),
.rule = asymptotic,
.args = {
(0.1 + frand()) * cexp(I*(2*i*M_PI/cnt+time)),
5
},
.flags = PFLAG_DRAWADD,
);
}
// FIXME: better sound
@ -713,16 +811,13 @@ static void wriggle_slave_part_draw(Projectile *p, int t) {
Texture *tex = p->tex;
glBindTexture(GL_TEXTURE_2D, tex->gltex);
float b = 1 - t / p->args[0];
parse_color_call(multiply_colors(p->clr, rgb(b, b, b)), glColor4f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glPushMatrix();
glTranslatef(creal(p->pos), cimag(p->pos), 0);
ProjDrawCore(p, multiply_colors(p->color, rgba(b, b, b, 1)));
draw_texture_p(0,0, p->tex);
glPopMatrix();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1,1,1,1);
}
static int wriggle_spell_slave(Enemy *e, int time) {
@ -744,8 +839,16 @@ static int wriggle_spell_slave(Enemy *e, int time) {
if(!(time % 2)) {
float c = 0.5 * psin(time / 25.0);
Projectile *p = create_projectile_p(&global.projs, prefix_get_tex("lasercurve", "part/"), e->pos, rgb(1.0 - c, 0.5, 0.5 + c), wriggle_slave_part_draw, timeout, 120, 0, 0, 0);
p->type = EnemyProj;
PROJECTILE(
.texture_ptr = get_tex("part/lasercurve"),
.pos = e->pos,
.color = rgb(1.0 - c, 0.5, 0.5 + c),
.draw_rule = wriggle_slave_part_draw,
.rule = timeout,
.args = { 120 },
.color_transform_rule = proj_clrtransform_particle,
);
}
// moonlight rocket rockets
@ -754,10 +857,14 @@ static int wriggle_spell_slave(Enemy *e, int time) {
float dt = 60;
l = create_lasercurve4c(e->pos, dt, dt, rgb(1.0, 1.0, 0.5), las_sine_expanding, 2.5*dir, M_PI/20, 0.2, 0);
create_projectile3c("ball", e->pos, rgb(1.0, 0.4, 0.6), wriggle_rocket_laserbullet, add_ref(l), dt-1, 1);
PROJECTILE("ball", e->pos, rgb(1.0, 0.4, 0.6), wriggle_rocket_laserbullet, {
add_ref(l), dt-1, 1
});
l = create_lasercurve4c(e->pos, dt, dt, rgb(0.5, 1.0, 0.5), las_sine_expanding, 2.5*dir, M_PI/20, 0.2, M_PI);
create_projectile3c("ball", e->pos, rgb(1.0, 0.4, 0.6), wriggle_rocket_laserbullet, add_ref(l), dt-1, 1);
PROJECTILE("ball", e->pos, rgb(1.0, 0.4, 0.6), wriggle_rocket_laserbullet, {
add_ref(l), dt-1, 1
});
play_sound("laser1");
}
@ -767,9 +874,21 @@ static int wriggle_spell_slave(Enemy *e, int time) {
FROM_TO(300, 1000000, 180) {
int cnt = 5, i;
for(i = 0; i < cnt; ++i) {
create_projectile2c("ball", e->pos, rgb(0.5, 1.0, 0.5), accelerated, 0, 0.02 * cexp(I*i*2*M_PI/cnt))->draw = ProjDrawAdd;
if(global.diff > D_Hard)
create_projectile2c("ball", e->pos, rgb(1.0, 1.0, 0.5), accelerated, 0, 0.01 * cexp(I*i*2*M_PI/cnt))->draw = ProjDrawAdd;
PROJECTILE("ball", e->pos, rgb(0.5, 1.0, 0.5), accelerated,
.args = {
0, 0.02 * cexp(I*i*2*M_PI/cnt)
},
.flags = PFLAG_DRAWADD,
);
if(global.diff > D_Hard) {
PROJECTILE("ball", e->pos, rgb(1.0, 1.0, 0.5), accelerated,
.args = {
0, 0.01 * cexp(I*i*2*M_PI/cnt)
},
.flags = PFLAG_DRAWADD,
);
}
}
// FIXME: better sound
@ -846,7 +965,6 @@ void wriggle_night_ignite(Boss *boss, int time) {
TIMER(&time)
float dfactor = global.diff / (float)D_Lunatic;
int i, j;
if(time == EVENT_DEATH) {
killall(global.enemies);
@ -858,8 +976,9 @@ void wriggle_night_ignite(Boss *boss, int time) {
return;
}
AT(0) for(j = -1; j < 2; j += 2) for(i = 0; i < 7; ++i)
AT(0) for(int j = -1; j < 2; j += 2) for(int i = 0; i < 7; ++i) {
create_enemy4c(boss->pos, ENEMY_IMMUNE, wriggle_slave_draw, wriggle_spell_slave, add_ref(boss), i*2*M_PI/7, j, 1);
}
FROM_TO_INT(0, 1000000, 180, 120, 10) {
float dt = 200;
@ -883,9 +1002,9 @@ void wriggle_night_ignite(Boss *boss, int time) {
wriggle_ignite_warnlaser(l3);
for(int i = 0; i < 5 + 15 * dfactor; ++i) {
create_projectile2c("plainball", boss->pos, rgb(c, c, 1.0), wriggle_ignite_laserbullet, add_ref(l1), i)->draw = ProjDrawAdd;
create_projectile2c("bigball", boss->pos, rgb(1.0, c, c), wriggle_ignite_laserbullet, add_ref(l2), i)->draw = ProjDrawAdd;
create_projectile2c("plainball", boss->pos, rgb(c, c, 1.0), wriggle_ignite_laserbullet, add_ref(l3), i)->draw = ProjDrawAdd;
PROJECTILE("plainball", boss->pos, rgb(c, c, 1.0), wriggle_ignite_laserbullet, { add_ref(l1), i }, .flags = PFLAG_DRAWADD);
PROJECTILE("bigball", boss->pos, rgb(1.0, c, c), wriggle_ignite_laserbullet, { add_ref(l2), i }, .flags = PFLAG_DRAWADD);
PROJECTILE("plainball", boss->pos, rgb(c, c, 1.0), wriggle_ignite_laserbullet, { add_ref(l3), i }, .flags = PFLAG_DRAWADD);
// FIXME: better sound
play_sound("shot1");
@ -978,10 +1097,17 @@ void wriggle_light_singularity(Boss *boss, int time) {
double a = ((M_PI*2.0*i)/cnt);
complex dir = cexp(I*a);
create_projectile2c(ptype, boss->pos, hsl(a/(M_PI*2) + colorofs, 1.0, 0.5), asymptotic,
dir * (1.2 - 0.2 * global.diff),
20
)->draw = ProjDrawAdd;
PROJECTILE(
.texture = ptype,
.pos = boss->pos,
.color = hsl(a/(M_PI*2) + colorofs, 1.0, 0.5),
.rule = asymptotic,
.args = {
dir * (1.2 - 0.2 * global.diff),
20
},
.flags = PFLAG_DRAWADD,
);
}
play_sound("shot_special1");
@ -995,13 +1121,13 @@ static void wriggle_fstorm_proj_draw(Projectile *p, int time) {
glPushMatrix();
glTranslatef(creal(p->pos), cimag(p->pos), 0);
glRotatef(p->angle*180/M_PI+90, 0, 0, 1);
_ProjDraw(p,time);
ProjDrawCore(p, p->color);
if(f > 0) {
p->tex = get_tex("proj/ball");
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
glScalef(f,f,f);
_ProjDraw(p,time);
ProjDrawCore(p,time);
glScalef(1/f,1/f,1/f);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
p->tex = get_tex("proj/rice");
@ -1025,7 +1151,7 @@ static int wriggle_fstorm_proj(Projectile *p, int time) {
int t = rint(creal(p->args[2]));
if(t < turntime) {
float f = t/(float)turntime;
p->clr=rgb(0.3+0.7*(1 - pow(1 - f, 4)), 0.3+0.3*f*f, 0.7-0.7*f);
p->color = rgb(0.3+0.7*(1 - pow(1 - f, 4)), 0.3+0.3*f*f, 0.7-0.7*f);
}
if(t == turntime && global.boss) {
@ -1033,12 +1159,17 @@ 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 = wriggle_fstorm_proj_draw;
p->draw_rule = wriggle_fstorm_proj_draw;
p->tex = get_tex("proj/rice");
for(int i = 0; i < 3; ++i) {
tsrand_fill(2);
create_particle2c("flare", p->pos, 0, Shrink, timeout_linear, 60, (1+afrand(0))*cexp(I*tsrand_a(1)));
PARTICLE("flare", p->pos, 0, timeout_linear,
.args = {
60, (1+afrand(0))*cexp(I*tsrand_a(1))
},
.draw_rule = Shrink,
);
}
play_sound_ex("redirect", 3, false);
@ -1066,13 +1197,16 @@ void wriggle_firefly_storm(Boss *boss, int time) {
float r = tanh(sin(_i/200.));
float v = lun ? cos(_i/150.)/pow(cosh(atanh(r)),2) : 0.5;
complex pos = 230*cexp(I*(_i*0.301+2*M_PI/cnt*i))*r;
create_projectile2c(
(global.diff >= D_Hard) && !(i%10) ? "bigball" : "ball",
boss->pos+pos,
rgb(0.2,0.2,0.6),
wriggle_fstorm_proj,
(global.diff == D_Easy) ? 40 : 100-25*(!lun)-20*(global.diff == D_Normal),
cexp(I*(!lun)*0.6)*pos/cabs(pos)*(1+v)
PROJECTILE(
.texture = (global.diff >= D_Hard) && !(i%10) ? "bigball" : "ball",
.pos = boss->pos+pos,
.color = rgb(0.2,0.2,0.6),
.rule = wriggle_fstorm_proj,
.args = {
(global.diff == D_Easy) ? 40 : 100-25*(!lun)-20*(global.diff == D_Normal),
cexp(I*(!lun)*0.6)*pos/cabs(pos)*(1+v)
},
);
}
}
@ -1106,11 +1240,15 @@ static int wriggle_nonspell_slave(Enemy *e, int time) {
if(!(time % d)) {
play_sound("shot1");
create_projectile1c("rice", e->pos, rgb(0.7, 0.2, 0.1), linear, 3 * cexp(I*carg(boss->pos - e->pos)));
if(!(time % (d*2)) || level > 1)
create_projectile1c("thickrice", e->pos, rgb(0.7, 0.7, 0.1), linear, 2.5 * cexp(I*carg(boss->pos - e->pos)));
if(level > 2)
create_projectile1c("wave", e->pos, rgb(0.3, 0.1 + 0.6 * psin(time / 25.0), 0.7), linear, 2 * cexp(I*carg(boss->pos - e->pos)));
PROJECTILE("rice", e->pos, rgb(0.7, 0.2, 0.1), linear, { 3 * cexp(I*carg(boss->pos - e->pos)) });
if(!(time % (d*2)) || level > 1) {
PROJECTILE("thickrice", e->pos, rgb(0.7, 0.7, 0.1), linear, { 2.5 * cexp(I*carg(boss->pos - e->pos)) });
}
if(level > 2) {
PROJECTILE("wave", e->pos, rgb(0.3, 0.1 + 0.6 * psin(time / 25.0), 0.7), linear, { 2 * cexp(I*carg(boss->pos - e->pos)) });
}
}
return 1;

View file

@ -76,7 +76,16 @@ int stage4_splasher(Enemy *e, int t) {
FROM_TO_SND("shot1_loop", 66-6*global.diff, 150, 5-global.diff) {
tsrand_fill(4);
create_projectile2c(afrand(0) > 0.5 ? "rice" : "thickrice", e->pos, rgb(0.8,0.3-0.1*afrand(1),0.5), accelerated, e->args[0]/2+(1-2*afrand(2))+(1-2*afrand(3))*I, 0.02*I);
PROJECTILE(
.texture = afrand(0) > 0.5 ? "rice" : "thickrice",
.pos = e->pos,
.color = rgb(0.8,0.3-0.1*afrand(1),0.5),
.rule = accelerated,
.args = {
e->args[0]/2+(1-2*afrand(2))+(1-2*afrand(3))*I,
0.02*I
}
);
}
FROM_TO(200, 300, 1)
@ -99,7 +108,10 @@ int stage4_fodder(Enemy *e, int t) {
FROM_TO(100, 200, 22-global.diff*3) {
play_sound("shot1");
create_projectile2c("ball", e->pos, rgb(1, 0.3, 0.5), asymptotic, 2*cexp(I*M_PI*2*frand()), 3);
PROJECTILE("ball", e->pos, rgb(1, 0.3, 0.5), asymptotic, {
2*cexp(I*M_PI*2*frand()),
3
});
}
return 1;
@ -124,7 +136,7 @@ int stage4_partcircle(Enemy *e, int t) {
for(i = 0; i < global.diff; i++) {
play_sound("shot2");
complex n = cexp(I*M_PI/16.0*_i + I*carg(e->args[0])-I*M_PI/4.0 + 0.01*I*i*(1-2*(creal(e->args[0]) > 0)));
create_projectile2c("wave", e->pos + (30)*n, rgb(1-0.2*i,0.5,0.7), asymptotic, 2*n, 2+2*i);
PROJECTILE("wave", e->pos + (30)*n, rgb(1-0.2*i,0.5,0.7), asymptotic, { 2*n, 2+2*i });
}
}
@ -152,11 +164,13 @@ int stage4_cardbuster(Enemy *e, int t) {
complex n = cexp(I*carg(global.plr.pos - e->pos) + 0.3*I*_i);
FROM_TO_SND("shot1_loop", 120, 120+20*global.diff, 1)
create_projectile2c("card", e->pos + 30*n, rgb(0, 1, 0), asymptotic, (1.1+0.2*global.diff)*n, 0.4*I);
FROM_TO_SND("shot1_loop", 120, 120+20*global.diff, 1) {
PROJECTILE("card", e->pos + 30*n, rgb(0, 1, 0), asymptotic, { (1.1+0.2*global.diff)*n, 0.4*I });
}
FROM_TO_SND("shot1_loop", 300, 320+20*global.diff, 1)
create_projectile2c("card", e->pos + 30*n, rgb(0, 1, 0.2), asymptotic, (1.1+0.2*global.diff)*n, 0.4*I);
FROM_TO_SND("shot1_loop", 300, 320+20*global.diff, 1) {
PROJECTILE("card", e->pos + 30*n, rgb(0, 1, 0.2), asymptotic, { (1.1+0.2*global.diff)*n, 0.4*I });
}
return 1;
}
@ -185,7 +199,7 @@ int stage4_backfire(Enemy *e, int t) {
complex n = cexp(I*M_PI*frand()-I*copysign(M_PI/2.0, creal(e->args[0])));
int i;
for(i = 0; i < global.diff; i++)
create_projectile2c("wave", e->pos, rgb(0.2, 0.2, 1-0.2*i), asymptotic, 2*n, 2+2*i);
PROJECTILE("wave", e->pos, rgb(0.2, 0.2, 1-0.2*i), asymptotic, { 2*n, 2+2*i });
}
return 1;
@ -211,9 +225,31 @@ int stage4_bigcircle(Enemy *e, int t) {
int i;
int n = 10+3*global.diff;
for(i = 0; i < n; i++) {
create_projectile2c("bigball", e->pos, rgb(0,0.8-0.4*_i,0), asymptotic, 2*cexp(2.0*I*M_PI/n*i+I*3*_i), 3*sin(6*M_PI/n*i))->draw=ProjDrawAdd;
if(global.diff > D_Easy)
create_projectile2c("ball", e->pos, rgb(0,0.3*_i,0.4), asymptotic, (1.5+global.diff*0.2)*cexp(I*3*(i+frand())), I*5*sin(6*M_PI/n*i))->draw=ProjDrawAdd;
PROJECTILE(
.texture = "bigball",
.pos = e->pos,
.color = rgb(0,0.8-0.4*_i,0),
.rule = asymptotic,
.args = {
2*cexp(2.0*I*M_PI/n*i+I*3*_i),
3*sin(6*M_PI/n*i)
},
.flags = PFLAG_DRAWADD,
);
if(global.diff > D_Easy) {
PROJECTILE(
.texture = "ball",
.pos = e->pos,
.color = rgb(0,0.3*_i,0.4),
.rule = asymptotic,
.args = {
(1.5+global.diff*0.2)*cexp(I*3*(i+frand())),
I*5*sin(6*M_PI/n*i)
},
.flags = PFLAG_DRAWADD,
);
}
}
}
return 1;
@ -230,7 +266,16 @@ int stage4_explosive(Enemy *e, int t) {
phase /= cabs(phase);
for(i = 0; i < n; i++) {
create_projectile2c("ball", e->pos, rgb(0.1, 0.2, 1-0.6*(i&1)), asymptotic, (1.1+0.3*global.diff)*cexp(I*2*M_PI*(i+frand())/(float)n)*phase, 2);
PROJECTILE(
.texture = "ball",
.pos = e->pos,
.color = rgb(0.1, 0.2, 1-0.6*(i&1)),
.rule = asymptotic,
.args = {
(1.1+0.3*global.diff)*cexp(I*2*M_PI*(i+frand())/(float)n)*phase,
2
}
);
}
play_sound("shot1");
@ -249,7 +294,15 @@ void KurumiSlave(Enemy *e, int t) {
if(!(t%2)) {
complex offset = (frand()-0.5)*30;
offset += (frand()-0.5)*20.0*I;
create_particle3c("lasercurve", offset, rgb(0.3,0.0,0.0), EnemyFlareShrink, enemy_flare, 50, (-50.0*I-offset)/50.0, add_ref(e));
PARTICLE(
.texture = "lasercurve",
.pos = offset,
.color = rgb(0.3,0.0,0.0),
.draw_rule = EnemyFlareShrink,
.rule = enemy_flare,
.args = { 50, (-50.0*I-offset)/50.0, add_ref(e) },
.flags = PFLAG_DRAWADD,
);
}
}
@ -274,8 +327,8 @@ int kurumi_burstslave(Enemy *e, int t) {
FROM_TO(0, 600, 18-2*global.diff) {
float r = cimag(e->pos)/VIEWPORT_H;
create_projectile2c("wave", e->pos + 10.0*I*e->args[0], rgb(r,0,0), accelerated, 2.0*I*e->args[0], -0.01*e->args[1]);
create_projectile2c("wave", e->pos - 10.0*I*e->args[0], rgb(r,0,0), accelerated, -2.0*I*e->args[0], -0.01*e->args[1]);
PROJECTILE("wave", e->pos + 10.0*I*e->args[0], rgb(r,0,0), accelerated, { 2.0*I*e->args[0], -0.01*e->args[1] });
PROJECTILE("wave", e->pos - 10.0*I*e->args[0], rgb(r,0,0), accelerated, {-2.0*I*e->args[0], -0.01*e->args[1] });
play_sound("shot1");
}
@ -325,8 +378,8 @@ int kurumi_spikeslave(Enemy *e, int t) {
FROM_TO(0, 600, 18-2*global.diff) {
float r = cimag(e->pos)/VIEWPORT_H;
create_projectile2c("wave", e->pos + 10.0*I*e->args[0], rgb(r,0,0), linear, 1.5*I*e->args[1], -0.01*e->args[0]);
create_projectile2c("wave", e->pos - 10.0*I*e->args[0], rgb(r,0,0), linear, -1.5*I*e->args[1], -0.01*e->args[0]);
PROJECTILE("wave", e->pos + 10.0*I*e->args[0], rgb(r,0,0), linear, { 1.5*I*e->args[1], -0.01*e->args[0] });
PROJECTILE("wave", e->pos - 10.0*I*e->args[0], rgb(r,0,0), linear, {-1.5*I*e->args[1], -0.01*e->args[0] });
play_sound("shot1");
}
@ -353,7 +406,17 @@ void kurumi_redspike(Boss *b, int time) {
int i;
int n = global.diff*8;
for(i = 0; i < n; i++)
create_projectile2c("bigball", b->pos, rgb(1,0,0), asymptotic, (1+0.1*(global.diff == D_Normal))*3*cexp(2.0*I*M_PI/n*i+I*carg(global.plr.pos-b->pos)), 3)->draw=ProjDrawAdd;
PROJECTILE(
.texture = "bigball",
.pos = b->pos,
.color = rgb(1.0, 0.0, 0.0),
.rule = asymptotic,
.args = {
(1+0.1*(global.diff == D_Normal))*3*cexp(2.0*I*M_PI/n*i+I*carg(global.plr.pos-b->pos)),
3
},
.flags = PFLAG_DRAWADD,
);
}
} else {
AT(80) {
@ -366,7 +429,10 @@ void kurumi_redspike(Boss *b, int time) {
tsrand_fill(2);
complex offset = 100*afrand(0)*cexp(2.0*I*M_PI*afrand(1));
complex n = cexp(I*carg(global.plr.pos-b->pos-offset));
create_projectile2c("rice", b->pos+offset, rgb(1,0,0), accelerated, -1*n, 0.05*n)->draw=ProjDrawAdd;
PROJECTILE("rice", b->pos+offset, rgb(1,0,0), accelerated,
.args = { -1*n, 0.05*n },
.flags = PFLAG_DRAWADD,
);
play_sound("shot2");
}
}
@ -427,7 +493,7 @@ Boss* create_kurumi_mid(void) {
int splitcard(Projectile *p, int t) {
if(t == creal(p->args[2])) {
p->args[0] += p->args[3];
p->clr = derive_color(p->clr, CLRMASK_B, rgb(0, 0, -color_component(p->clr, CLR_B)));
p->color = derive_color(p->color, CLRMASK_B, rgb(0, 0, -color_component(p->color, CLR_B)));
play_sound_ex("redirect", 10, false);
}
@ -462,7 +528,9 @@ int stage4_supercard(Enemy *e, int t) {
int i;
complex n = cexp(I*carg(global.plr.pos - e->pos) + 0.3*I*_i);
for(i = -1; i <= 1 && t; i++)
create_projectile4c("card", e->pos + 30*n, rgb(1-_i/20.0, 0, 0.4), splitcard, 1*n, 0.4*I, 100-time+70, 1.4*I*i*n);
PROJECTILE("card", e->pos + 30*n, rgb(1-_i/20.0, 0, 0.4), splitcard, {
1*n, 0.4*I, 100-time+70, 1.4*I*i*n
});
}
return 1;
@ -495,8 +563,12 @@ void kurumi_breaker(Boss *b, int time) {
for(i = 0; i < c; i++) {
complex n = cexp(2.0*I*M_PI/c*i);
create_projectile4c("rice", p, rgb(1,0,0.5), splitcard, 3*n, 0,
kt, 1.5*cexp(I*carg(global.plr.pos - p - 2*kt*n))-2.6*n);
PROJECTILE("rice", p, rgb(1,0,0.5), splitcard, {
3*n,
0,
kt,
1.5*cexp(I*carg(global.plr.pos - p - 2*kt*n))-2.6*n
});
}
}
@ -504,8 +576,12 @@ void kurumi_breaker(Boss *b, int time) {
FROM_TO(60, 400, 100) {
play_sound("shot_special1");
aniplayer_queue(&b->ani,1,0,0);
for(i = 0; i < 20; i++)
create_projectile2c("bigball", b->pos, rgb(0.5,0,0.5), asymptotic, cexp(2.0*I*M_PI/20.0*i), 3)->draw=ProjDrawAdd;
for(i = 0; i < 20; i++) {
PROJECTILE("bigball", b->pos, rgb(0.5,0,0.5), asymptotic,
.args = { cexp(2.0*I*M_PI/20.0*i), 3 },
.flags = PFLAG_DRAWADD,
);
}
}
}
@ -524,10 +600,7 @@ int aniwall_bullet(Projectile *p, int t) {
p->pos += p->args[0];
}
float r, g, b, a;
parse_color(p->clr,&r,&g,&b,&a);
p->clr = rgb(cimag(p->pos)/VIEWPORT_H, g, b);
p->color = derive_color(p->color, CLRMASK_R, rgb(cimag(p->pos)/VIEWPORT_H, 0, 0));
return 1;
}
@ -573,7 +646,7 @@ int aniwall_slave(Enemy *e, int t) {
complex v = e->args[2]/cabs(e->args[2])*I*sign(creal(e->args[0]));
if(cimag(v) > -0.1 || global.diff >= D_Normal) {
play_sound("shot1");
create_projectile2c("ball", e->pos+I*v*20*nfrand(), rgb(1,0,0), aniwall_bullet, 1*v, 40);
PROJECTILE("ball", e->pos+I*v*20*nfrand(), rgb(1,0,0), aniwall_bullet, { 1*v, 40 });
}
}
}
@ -582,8 +655,12 @@ int aniwall_slave(Enemy *e, int t) {
}
void KurumiAniWallSlave(Enemy *e, int t) {
if(e->args[1])
create_particle1c("lasercurve", e->pos, rgb(1,1,1), FadeAdd, timeout, 30);
if(e->args[1]) {
PARTICLE("lasercurve", e->pos, rgb(1,1,1), timeout, { 30 },
.draw_rule = Fade,
.flags = PFLAG_DRAWADD,
);
}
}
void kurumi_aniwall(Boss *b, int time) {
@ -624,16 +701,24 @@ void kurumi_sbreaker(Boss *b, int time) {
complex p = b->pos + 150*sin(_i/8.0)+100.0*I*cos(_i/15.0);
complex n = cexp(2.0*I*M_PI/c*_i);
create_projectile4c("rice", p, rgb(1,0,0.5), splitcard, 2*n, 0,
kt, 1.5*cexp(I*carg(global.plr.pos - p - 2*kt*n))-1.7*n);
PROJECTILE("rice", p, rgb(1.0, 0.0, 0.5), splitcard, {
2*n,
0,
kt,
1.5*cexp(I*carg(global.plr.pos - p - 2*kt*n))-1.7*n
});
}
FROM_TO(60, dur, 100) {
play_sound("shot_special1");
aniplayer_queue(&b->ani,1,0,0);
for(i = 0; i < 20; i++)
create_projectile2c("bigball", b->pos, rgb(0.5,0,0.5), asymptotic, cexp(2.0*I*M_PI/20.0*i), 3)->draw=ProjDrawAdd;
for(i = 0; i < 20; i++) {
PROJECTILE("bigball", b->pos, rgb(0.5, 0.0, 0.5), asymptotic,
.args = { cexp(2.0*I*M_PI/20.0*i), 3 },
.flags = PFLAG_DRAWADD,
);
}
}
}
@ -674,7 +759,10 @@ int blowwall_slave(Enemy *e, int t) {
else
type = "plainball";
create_projectile2c(type, e->pos, rgb(1, 0.1, 0.1), asymptotic, (1+3*f)*cexp(2.0*I*M_PI*frand()), 4)->draw=ProjDrawAdd;
PROJECTILE(type, e->pos, rgb(1.0, 0.1, 0.1), asymptotic,
.args = { (1+3*f)*cexp(2.0*I*M_PI*frand()), 4 },
.flags = PFLAG_DRAWADD
);
}
play_sound("shot_special1");
@ -754,8 +842,12 @@ int kdanmaku_slave(Enemy *e, int t) {
if(!(t % 1)) {
for(i = 0; i < n; i++) {
complex p = VIEWPORT_W/(float)n*(i+frand()) + I*cimag(e->pos);
if(cabs(p-global.plr.pos) > 60)
create_projectile1c("thickrice", p, rgb(1, 0.5, 0.5), linear, 0.5*cexp(2.0*I*M_PI*frand()))->draw = ProjDrawAdd;
if(cabs(p-global.plr.pos) > 60) {
PROJECTILE("thickrice", p, rgb(1, 0.5, 0.5), linear,
.args = { 0.5*cexp(2.0*I*M_PI*frand()) },
.flags = PFLAG_DRAWADD,
);
}
}
}
@ -804,7 +896,7 @@ int kurumi_extra_dead_shield_proj(Projectile *p, int time) {
return 1;
}
p->clr = mix_colors(
p->color = mix_colors(
rgb(0.2, 0.1, 0.5),
rgb(2.0, 0.0, 0.0),
min(time / 60.0f, 1.0f));
@ -821,7 +913,7 @@ int kurumi_extra_dead_shield(Enemy *e, int time) {
// complex dir = cexp(I*(M_PI * 0.5 * nfrand() + carg(global.plr.pos - e->pos)));
// complex dir = cexp(I*(carg(global.plr.pos - e->pos)));
complex dir = cexp(I*creal(e->args[0]));
create_projectile2c("rice", e->pos, 0, kurumi_extra_dead_shield_proj, 2*dir, 10);
PROJECTILE("rice", e->pos, 0, kurumi_extra_dead_shield_proj, { 2*dir, 10 });
play_sound("shot1");
}
@ -834,7 +926,10 @@ int kurumi_extra_dead_shield(Enemy *e, int time) {
for(int i = 0; i < cnt; ++i) {
complex dir = cexp(I*M_PI*2*i/(double)cnt);
tsrand_fill(2);
create_projectile2c("ball", e->pos, 0, kurumi_extra_dead_shield_proj, 1.5 * (1 + afrand(0)) * dir, 4 + anfrand(1))->draw = ProjDrawAdd;
PROJECTILE("ball", e->pos, 0, kurumi_extra_dead_shield_proj,
.args = { 1.5 * (1 + afrand(0)) * dir, 4 + anfrand(1) },
.flags = PFLAG_DRAWADD,
);
}
// FIXME: needs a more powerful 'explosion' sound
@ -885,8 +980,8 @@ int kurumi_extra_bigfairy1(Enemy *e, int time) {
complex arg = cexp(I*2*M_PI*i/count);
if(global.diff == D_Lunatic)
arg *= phase;
create_lasercurve2c(e->pos,20,200,rgb(1,0.3,0.7),las_accel,arg,0.1*arg);
create_projectile2c("bullet",e->pos,rgb(1,0.3,0.7),accelerated,arg,0.1*arg);
create_lasercurve2c(e->pos, 20, 200, rgb(1,0.3,0.7), las_accel, arg, 0.1*arg);
PROJECTILE("bullet", e->pos, rgb(1.0, 0.3, 0.7), accelerated, { arg, 0.1*arg });
}
play_sound("laser1");
@ -900,14 +995,22 @@ void kurumi_extra_drainer_draw(Projectile *p, int time) {
complex targ = p->args[1];
double a = 0.5 * creal(p->args[2]);
ColorTransform ct;
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glColor4f(1.0, 0.5, 0.5, a);
static_clrtransform_particle(rgba(1.0, 0.5, 0.5, a), &ct);
recolor_apply_transform(&ct);
loop_tex_line_p(org, targ, 16, time * 0.01, p->tex);
glColor4f(0.4, 0.2, 0.2, a);
static_clrtransform_particle(rgba(0.4, 0.2, 0.2, a), &ct);
recolor_apply_transform(&ct);
loop_tex_line_p(org, targ, 18, time * 0.0043, p->tex);
glColor4f(0.5, 0.2, 0.5, a);
static_clrtransform_particle(rgba(0.5, 0.2, 0.5, a), &ct);
recolor_apply_transform(&ct);
loop_tex_line_p(org, targ, 24, time * 0.003, p->tex);
glColor4f(1,1,1,1);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
@ -946,8 +1049,15 @@ int kurumi_extra_drainer(Projectile *p, int time) {
}
void kurumi_extra_create_drainer(Enemy *e) {
Projectile *p = create_projectile_p(&global.projs, get_tex("part/sinewave"), e->pos, 0, kurumi_extra_drainer_draw, kurumi_extra_drainer, add_ref(e), 0, 0, 0);
p->type = FakeProj;
PROJECTILE(
.texture_ptr = get_tex("part/sinewave"),
.pos = e->pos,
.rule = kurumi_extra_drainer,
.draw_rule = kurumi_extra_drainer_draw,
.args = { add_ref(e) },
.type = FakeProj,
.color_transform_rule = proj_clrtransform_particle,
);
}
void kurumi_swirl_draw(Enemy *e, int time) {
@ -993,7 +1103,7 @@ int kurumi_extra_fairy(Enemy *e, int t) {
}
/*FROM_TO(100, 200, 22-global.diff*3) {
create_projectile2c("ball", e->pos, rgb(1, 0.3, 0.5), asymptotic, 2*cexp(I*M_PI*2*frand()), 3);
PROJECTILE("ball", e->pos, rgb(1, 0.3, 0.5), asymptotic, 2*cexp(I*M_PI*2*frand()), 3);
}*/
int attacktime = creal(e->args[1]);
@ -1008,7 +1118,7 @@ int kurumi_extra_fairy(Enemy *e, int t) {
for(int j = 0; j < count; j++) {
complex pos = len/2/tan(2*M_PI/corners)*I+(j/(double)count-0.5)*len;
pos *= cexp(I*2*M_PI/corners*i);
create_projectile1c("flea", e->pos+pos, rgb(1, 0.3, 0.5), linear, vel+0.1*I*pos/cabs(pos));
PROJECTILE("flea", e->pos+pos, rgb(1, 0.3, 0.5), linear, { vel+0.1*I*pos/cabs(pos) });
}
}
} else {
@ -1018,7 +1128,7 @@ int kurumi_extra_fairy(Enemy *e, int t) {
double x = (j/(double)count-0.5)*2*M_PI;
complex pos = 0.5*cos(x)+sin(2*x) + (0.5*sin(x)+cos(2*x))*I;
pos*=vel/cabs(vel);
create_projectile1c("flea", e->pos+rad*pos, rgb(0.5, 0.3, 1), linear, vel+0.1*pos);
PROJECTILE("flea", e->pos+rad*pos, rgb(0.5, 0.3, 1), linear, { vel+0.1*pos });
}
}
}
@ -1033,7 +1143,7 @@ int kurumi_extra_fairy(Enemy *e, int t) {
FROM_TO(attacktime,attacktime+flytime,20-global.diff*3) {
if(global.diff>D_Easy) {
create_projectile1c("ball", e->pos, rgba(0.1+0.07*_i, 0.3, 1-0.05*_i,0.8), timeout, 50)->draw=ProjDrawAdd;
PROJECTILE("ball", e->pos, rgba(0.1+0.07*_i, 0.3, 1-0.05*_i,0.8), timeout, { 50 }, .flags = PFLAG_DRAWADD);
}
}
if(t > attacktime + flytime + 20 && global.boss) {
@ -1202,7 +1312,10 @@ static int scythe_post_mid(Enemy *e, int t) {
Color c = rgb(cos(ca), sin(ca), cos(ca+2.1));
play_sound_ex(pe->snd, 3, true);
create_projectile2c(pe->proj, shotorg, c, asymptotic, (1.2-0.1*global.diff)*shotdir, 5 * sin(t/150.0));
PROJECTILE(pe->proj, shotorg, c, asymptotic, {
(1.2-0.1*global.diff)*shotdir,
5 * sin(t/150.0)
});
}

View file

@ -46,6 +46,7 @@ Dialog *stage5_boss_dialog(void) {
dadd_msg(d,Right, "If your confidence will not allow you to back down, then so be it. I will test you using all of Heavens might, and if you are unfit, you shall be cast down from this Tower of Babel!");
dadd_msg(d,Left, "I shall pass whatever test necessary if it will allow me to fulfill the wishes of Lady Yuyuko!");
}
dadd_msg(d, BGM, "stage5boss");
return d;
}
@ -82,7 +83,10 @@ int stage5_greeter(Enemy *e, int t) {
int i;
for(i = -(int)global.diff; i <= (int)global.diff; i++) {
create_projectile2c("bullet", e->pos, rgb(0.0,0.0,1.0), asymptotic, (3.5+(global.diff == D_Lunatic))*cexp(I*carg(global.plr.pos-e->pos) + 0.06*I*i), 5);
PROJECTILE("bullet", e->pos, rgb(0.0,0.0,1.0), asymptotic, {
(3.5+(global.diff == D_Lunatic))*cexp(I*carg(global.plr.pos-e->pos) + 0.06*I*i),
5
});
}
}
@ -104,7 +108,7 @@ int stage5_lightburst(Enemy *e, int t) {
int c = 5+global.diff;
for(i = 0; i < c; i++) {
complex n = cexp(I*carg(global.plr.pos) + 2.0*I*M_PI/c*i);
create_projectile2c("ball", e->pos + 50*n*cexp(-0.4*I*_i*global.diff), rgb(0.3, 0, 0.7), asymptotic, 3*n, 3);
PROJECTILE("ball", e->pos + 50*n*cexp(-0.4*I*_i*global.diff), rgb(0.3, 0, 0.7), asymptotic, { 3*n, 3 });
}
}
@ -125,8 +129,8 @@ int stage5_swirl(Enemy *e, int t) {
e->pos += e->args[0];
FROM_TO(0, 400, 26-global.diff*4) {
create_projectile2c("bullet", e->pos, rgb(0.3, 0.4, 0.5), asymptotic, 2*e->args[0]*I/cabs(e->args[0]), 3);
create_projectile2c("bullet", e->pos, rgb(0.3, 0.4, 0.5), asymptotic, -2*e->args[0]*I/cabs(e->args[0]), 3);
PROJECTILE("bullet", e->pos, rgb(0.3, 0.4, 0.5), asymptotic, { 2*e->args[0]*I/cabs(e->args[0]), 3 });
PROJECTILE("bullet", e->pos, rgb(0.3, 0.4, 0.5), asymptotic, {-2*e->args[0]*I/cabs(e->args[0]), 3 });
}
return 1;
@ -142,11 +146,10 @@ int stage5_limiter(Enemy *e, int t) {
e->pos += e->args[0];
FROM_TO(0, 1200, 3) {
create_projectile2c("rice", e->pos, rgb(0.5,0.1,0.2), asymptotic, 10*cexp(I*carg(global.plr.pos-e->pos)+0.2*I-0.1*I*(global.diff/4)+3.0*I/(_i+1)), 2);
create_projectile2c("rice", e->pos, rgb(0.5,0.1,0.2), asymptotic, 10*cexp(I*carg(global.plr.pos-e->pos)-0.2*I+0.1*I*(global.diff/4)-3.0*I/(_i+1)), 2);
PROJECTILE("rice", e->pos, rgb(0.5,0.1,0.2), asymptotic, { 10*cexp(I*carg(global.plr.pos-e->pos)+0.2*I-0.1*I*(global.diff/4)+3.0*I/(_i+1)), 2 });
PROJECTILE("rice", e->pos, rgb(0.5,0.1,0.2), asymptotic, { 10*cexp(I*carg(global.plr.pos-e->pos)-0.2*I+0.1*I*(global.diff/4)-3.0*I/(_i+1)), 2 });
}
return 1;
}
@ -167,7 +170,7 @@ int stage5_laserfairy(Enemy *e, int t) {
complex n = cexp(I*carg(global.plr.pos-e->pos)+(0.2-0.02*global.diff)*I*_i);
float fac = (0.5+0.2*global.diff);
create_lasercurve2c(e->pos, 100, 300, rgb(0.7, 0.3, 1), las_accel, fac*4*n, fac*0.05*n);
create_projectile2c("plainball", e->pos, rgb(0.7, 0.3, 1), accelerated, fac*4*n, fac*0.05*n)->draw = ProjDrawAdd;
PROJECTILE("plainball", e->pos, rgb(0.7, 0.3, 1), accelerated, { fac*4*n, fac*0.05*n }, .flags = PFLAG_DRAWADD);
}
return 1;
}
@ -183,7 +186,7 @@ int stage5_miner(Enemy *e, int t) {
FROM_TO(0, 600, 5-global.diff/2) {
tsrand_fill(2);
create_projectile1c("rice", e->pos + 20*cexp(2.0*I*M_PI*afrand(0)), rgb(0,0,cabs(e->args[0])), linear, cexp(2.0*I*M_PI*afrand(1)));
PROJECTILE("rice", e->pos + 20*cexp(2.0*I*M_PI*afrand(0)), rgb(0,0,cabs(e->args[0])), linear, { cexp(2.0*I*M_PI*afrand(1)) });
}
return 1;
@ -196,15 +199,17 @@ int stage5_explosion(Enemy *e, int t) {
return 1;
}
FROM_TO(0, 80, 1)
FROM_TO(0, 80, 1) {
e->pos += e->args[0];
}
FROM_TO(90, 300, 7-global.diff)
create_projectile2c("soul", e->pos, rgb(0,0,1), asymptotic, 4*cexp(0.5*I*_i), 3)->draw = ProjDrawAdd;
FROM_TO(90, 300, 7-global.diff) {
PROJECTILE("soul", e->pos, rgb(0,0,1), asymptotic, { 4*cexp(0.5*I*_i), 3 }, .flags = PFLAG_DRAWADD);
}
FROM_TO(200, 720, 6-global.diff) {
create_projectile2c("rice", e->pos, rgb(1,0,0), asymptotic, 2*cexp(-0.3*I*_i+frand()*I), 3);
create_projectile2c("rice", e->pos, rgb(1,0,0), asymptotic, -2*cexp(-0.3*I*_i+frand()*I), 3);
PROJECTILE("rice", e->pos, rgb(1,0,0), asymptotic, { 2*cexp(-0.3*I*_i+frand()*I), 3 });
PROJECTILE("rice", e->pos, rgb(1,0,0), asymptotic, {-2*cexp(-0.3*I*_i+frand()*I), 3 });
}
FROM_TO(500, 800, 100-10*global.diff)
@ -217,15 +222,30 @@ void iku_slave_draw(Enemy *e, int t) {
complex offset = (frand()-0.5)*10 + (frand()-0.5)*10.0*I;
if(e->args[2] && !(t % 5)) {
char *part = frand() > 0.5 ? "lightning0" : "lightning1";
Projectile *p = create_particle1c(part, e->pos+3*offset, rgb(1.0, 1.0, 1.0), FadeAdd, timeout, 20);
p->angle = frand()*2*M_PI;
PARTICLE(part, e->pos+3*offset, rgb(1.0, 1.0, 1.0), timeout,
.args = { 20 },
.draw_rule = Fade,
.flags = PFLAG_DRAWADD,
.angle = frand()*2*M_PI,
);
}
if(!(t % 3)) {
float alpha = 1;
if(!e->args[2])
if(!e->args[2]) {
alpha *= 0.03;
create_particle3c("lightningball", e->pos, rgba(.1*alpha, .1*alpha, .6*alpha, 0.1*alpha), FadeAdd, enemy_flare, 50,offset*0.1,add_ref(e));
}
PARTICLE(
.texture = "lightningball",
.pos = e->pos,
.color = rgba(0.1*alpha, 0.1*alpha, 0.6*alpha, 0.5*alpha),
.draw_rule = Fade,
.rule = enemy_flare,
.args = { 50, offset*0.1, add_ref(e) },
.flags = PFLAG_DRAWADD,
);
}
}
@ -272,7 +292,16 @@ int stage5_lightburst2(Enemy *e, int t) {
for(i = 0; i < c; i++) {
tsrand_fill(2);
complex n = cexp(I*carg(global.plr.pos-e->pos) + 2.0*I*M_PI/c*i);
create_projectile2c("bigball", e->pos + 50*n*cexp(-1.0*I*_i*global.diff), rgb(0.3, 0, 0.7+0.3*(_i&1)), asymptotic, 2.5*n+0.25*global.diff*afrand(0)*cexp(2.0*I*M_PI*afrand(1)), 3);
PROJECTILE(
.texture = "bigball",
.pos = e->pos + 50*n*cexp(-1.0*I*_i*global.diff),
.color = rgb(0.3, 0, 0.7+0.3*(_i&1)),
.rule = asymptotic,
.args = {
2.5*n+0.25*global.diff*afrand(0)*cexp(2.0*I*M_PI*afrand(1)),
3
}
);
}
}
@ -291,8 +320,7 @@ int stage5_superbullet(Enemy *e, int t) {
FROM_TO(60, 200, 1) {
complex n = cexp(I*M_PI*sin(_i/(8.0+global.diff)+frand()*0.1)+I*carg(global.plr.pos-e->pos));
create_projectile2c("bullet", e->pos + 50*n, rgb(0.6, 0, 0), asymptotic, 2*n, 10);
PROJECTILE("bullet", e->pos + 50*n, rgb(0.6, 0, 0), asymptotic, { 2*n, 10 });
}
FROM_TO(260, 400, 1)
@ -310,7 +338,18 @@ void iku_intro(Boss *b, int t) {
static void cloud_common(void) {
tsrand_fill(4);
float v = (afrand(2)+afrand(3))*0.5+1.0;
create_projectile_p(&global.projs,get_tex("part/lightningball"), VIEWPORT_W*afrand(0)-15.0*I, rgba(0.2,0.0,0.4,0.6), PartDraw, accelerated, 1-2*afrand(1)+v*I, -0.01*I,0,0);
PROJECTILE(
.texture_ptr = get_tex("part/lightningball"),
.pos = VIEWPORT_W*afrand(0)-15.0*I,
.color = rgba(0.2, 0.0, 0.4, 0.6),
.rule = accelerated,
.args = {
1-2*afrand(1)+v*I,
-0.01*I
},
.color_transform_rule = proj_clrtransform_particle,
);
}
void iku_bolts(Boss *b, int time) {
@ -326,7 +365,13 @@ void iku_bolts(Boss *b, int time) {
b->ani.mirrored = !b->ani.mirrored;
aniplayer_queue(&b->ani,1,0,5);
for(i = 0; i < c; i++) {
create_projectile2c("ball", b->pos, rgb(0.4, 1, 1), asymptotic, (i+2)*0.4*cexp(I*carg(global.plr.pos-b->pos))+0.2*(global.diff-1)*frand(), 3)->draw = ProjDrawAdd;
PROJECTILE("ball", b->pos, rgb(0.4, 1, 1), asymptotic,
.args = {
(i+2)*0.4*cexp(I*carg(global.plr.pos-b->pos))+0.2*(global.diff-1)*frand(),
3
},
.flags = PFLAG_DRAWADD,
);
}
}
@ -364,15 +409,24 @@ void iku_atmospheric(Boss *b, int time) {
int c = 6+global.diff;
for(i = -c*0.5; i <= c*0.5; i++) {
create_projectile2c("ball", p1+(p2-p1)/c*i, rgb(1-1/(1+fabs(0.1*i)), 0.5-0.1*abs(i), 1), accelerated, 0, (0.004+0.001*global.diff)*cexp(I*carg(p2-p1)+I*M_PI/2+0.2*I*i))->draw = ProjDrawAdd;
PROJECTILE(
.texture = "ball",
.pos = p1+(p2-p1)/c*i,
.color = rgb(1-1/(1+fabs(0.1*i)), 0.5-0.1*abs(i), 1),
.rule = accelerated,
.args = {
0, (0.004+0.001*global.diff)*cexp(I*carg(p2-p1)+I*M_PI/2+0.2*I*i)
},
.flags = PFLAG_DRAWADD,
);
}
}
FROM_TO(0, 500, 7-global.diff) {
if(global.diff >= D_Hard)
create_projectile2c("thickrice", VIEWPORT_W*frand(), rgb(0,0.3,0.7), accelerated, 0, 0.01*I);
PROJECTILE("thickrice", VIEWPORT_W*frand(), rgb(0,0.3,0.7), accelerated, { 0, 0.01*I });
else
create_projectile1c("rice", VIEWPORT_W*frand(), rgb(0,0.3,0.7), linear, 2*I);
PROJECTILE("rice", VIEWPORT_W*frand(), rgb(0,0.3,0.7), linear, { 2*I });
}
}
@ -399,7 +453,7 @@ void iku_bolts2(Boss *b, int time) {
FROM_TO(0, 400, 5-global.diff)
if(frand() < 0.9)
create_projectile1c("plainball", b->pos, rgb(0.2,0,0.8), linear, cexp(0.1*I*_i));
PROJECTILE("plainball", b->pos, rgb(0.2,0,0.8), linear, { cexp(0.1*I*_i) });
FROM_TO(0, 70, 1)
GO_TO(b, 100+200.0*I, 0.02);
@ -426,7 +480,13 @@ int lightning_slave(Enemy *e, int t) {
if(cabs(e->pos-global.plr.pos) > 60) {
tsrand_fill(2);
Color clr = rgb(1-1/(1+0.01*_i), 0.5-0.01*_i, 1);
create_projectile2c("wave", e->pos, clr, accelerated, (0.5+0.3*(_i&1)*(global.diff==D_Lunatic))*e->args[0]/cabs(e->args[0])*I, 0.001*global.diff*(1-2*afrand(0)+I*afrand(1)))->draw = ProjDrawAdd;
PROJECTILE("wave", e->pos, clr, accelerated,
.args = {
(0.5+0.3*(_i&1)*(global.diff==D_Lunatic))*e->args[0]/cabs(e->args[0])*I,
0.001*global.diff*(1-2*afrand(0)+I*afrand(1))
},
.flags = PFLAG_DRAWADD,
);
}
return 1;
@ -436,8 +496,12 @@ static int zigzag_bullet(Projectile *p, int t) {
int l = 50;
p->pos = p->pos0+(abs(((2*t)%l)-l/2)*I+t)*2*p->args[0];
if(t%2 == 0)
create_particle1c("lightningball", p->pos, rgb(0.1,0.1,0.6), FadeAdd, timeout, 15);
if(t%2 == 0) {
PARTICLE("lightningball", p->pos, rgb(0.1,0.1,0.6), timeout, { 15 },
.draw_rule = Fade,
.flags = PFLAG_DRAWADD,
);
}
return 1;
}
@ -464,14 +528,25 @@ void iku_lightning(Boss *b, int time) {
float l = 150*frand()+50;
float s = 4+_i*0.01;
float alpha = 0.5;
create_particle2c("lightningball", b->pos+l*n, rgb(0.1*alpha,0.1*alpha,0.6*alpha), FadeAdd, timeout_linear, l/s, -s*n);
PARTICLE(
.texture = "lightningball",
.pos = b->pos+l*n,
.color = rgb(0.1*alpha, 0.1*alpha, 0.6*alpha),
.draw_rule = Fade,
.flags = PFLAG_DRAWADD,
.rule = timeout_linear,
.args = { l/s, -s*n },
);
}
if(global.diff == D_Lunatic && time > 0 && !(time%100)) {
int c = 7;
for(int i = 0; i<c; i++)
create_projectile1c("bigball", b->pos, rgb(0.5,0.1,1), zigzag_bullet, cexp(2*M_PI*I/c*i+I*carg(global.plr.pos-b->pos)))->draw = ProjDrawAdd;
PROJECTILE("bigball", b->pos, rgb(0.5,0.1,1), zigzag_bullet,
.args = { cexp(2*M_PI*I/c*i+I*carg(global.plr.pos-b->pos)) },
.flags = PFLAG_DRAWADD,
);
}
AT(100) {
@ -480,13 +555,23 @@ void iku_lightning(Boss *b, int time) {
int c = 40;
int l = 200;
int s = 10;
float alpha = 1;
for(int i=0; i < c; i++) {
complex n = cexp(2.0*I*M_PI*frand());
create_particle2c("smoke", b->pos, rgb(0.4*alpha,0.4*alpha,1*alpha), FadeAdd, timeout_linear, l/s, s*n);
PARTICLE(
.texture = "smoke",
.pos = b->pos,
.color = rgb(0.4, 0.4, 1.0),
.draw_rule = Fade,
.rule = timeout_linear,
.args = { l/s, s*n },
.flags = PFLAG_DRAWADD,
);
}
for(int i = 0; i < global.diff+1; i++)
for(int i = 0; i < global.diff+1; i++){
create_enemy1c(b->pos, ENEMY_IMMUNE, NULL, lightning_slave, 10*cexp(I*carg(global.plr.pos - b->pos)+2.0*I*M_PI/(global.diff+1)*i));
}
}
}
@ -504,13 +589,19 @@ void iku_bolts3(Boss *b, int time) {
int i, c = 10+global.diff;
complex n = cexp(I*carg(global.plr.pos-b->pos)+0.1*I-0.2*I*frand());
for(i = 0; i < c; i++) {
create_projectile2c("ball", b->pos, rgb(0.4, 1, 1), asymptotic, (i+2)*0.4*n+0.2*(global.diff-1)*frand(), 3)->draw = ProjDrawAdd;
PROJECTILE("ball", b->pos, rgb(0.4, 1, 1), asymptotic,
.args = {
(i+2)*0.4*n+0.2*(global.diff-1)*frand(),
3
},
.flags = PFLAG_DRAWADD,
);
}
}
FROM_TO(0, 400, 5-global.diff)
if(frand() < 0.9)
create_projectile1c("plainball", b->pos, rgb(0.2,0,0.8), linear, cexp(0.1*I*_i));
PROJECTILE("plainball", b->pos, rgb(0.2,0,0.8), linear, { cexp(0.1*I*_i) });
FROM_TO(0, 70, 1)
GO_TO(b, 100+200.0*I, 0.02);
@ -560,7 +651,14 @@ void iku_cathode(Boss *b, int t) {
int c = 5+global.diff;
for(i = 0; i < c; i++) {
create_projectile3c("bigball", b->pos, rgb(0.2, 0.4, 1), induction_bullet, 2*cexp(2.0*I*M_PI*frand()), 0.01*I*(1-2*(_i&1)),1)->draw = ProjDrawAdd;
PROJECTILE("bigball", b->pos, rgb(0.2, 0.4, 1), induction_bullet,
.args = {
2*cexp(2.0*I*M_PI*frand()),
0.01*I*(1-2*(_i&1)),
1
},
.flags = PFLAG_DRAWADD,
);
create_lasercurve2c(b->pos, 60, 200, rgb(0.4, 1, 1), cathode_laser, 2*cexp(2.0*I*M_PI*M_PI*frand()), 0.015*I*(1-2*(_i&1)));
}
}
@ -587,7 +685,13 @@ void iku_induction(Boss *b, int t) {
float a = -0.0002*(global.diff-D_Easy);
if(global.diff == D_Hard)
a += 0.0005;
create_projectile2c("ball", b->pos, clr, induction_bullet, 2*cexp(2.0*I*M_PI/c*i+I*M_PI/2+I*shift), (0.01+0.001*global.diff)*I*(1-2*j)+a)->draw = ProjDrawAdd;
PROJECTILE("ball", b->pos, clr, induction_bullet,
.args = {
2*cexp(2.0*I*M_PI/c*i+I*M_PI/2+I*shift),
(0.01+0.001*global.diff)*I*(1-2*j)+a
},
.flags = PFLAG_DRAWADD,
);
}
}
@ -618,13 +722,24 @@ Enemy* iku_extra_find_next_slave(complex from, double playerbias) {
return nearest;
}
void iku_extra_slave_draw(Enemy *e, int t) {
iku_slave_draw(e, t);
if(e->args[2] && !(t % 5)) {
complex offset = (frand()-0.5)*30 + (frand()-0.5)*20.0*I;
create_particle3c("lasercurve", offset, e->args[1] ? rgb(1.0, 0.5, 0.0) : rgb(0.0, 0.5, 0.5), EnemyFlareShrink, enemy_flare, 50, (-50.0*I-offset)/50.0, add_ref(e));
PARTICLE(
.texture = "lasercurve",
.pos = offset,
.color = e->args[1] ? rgb(1.0, 0.5, 0.0) : rgb(0.0, 0.5, 0.5),
.draw_rule = EnemyFlareShrink,
.rule = enemy_flare,
.args = {
50,
(-50.0*I-offset)/50.0,
add_ref(e)
},
.flags = PFLAG_DRAWADD,
);
}
}
@ -656,8 +771,8 @@ int iku_extra_trigger_bullet(Projectile *p, int t) {
int cnt = 6 + 2 * global.diff;
for(int i = 0; i < cnt; ++i) {
complex dir = cexp(I*(t + i*2*M_PI/cnt));
create_projectile2c("bigball", p->pos, rgb(1, 0.5, 0), asymptotic, 1.1*dir, 5)->draw = ProjDrawAdd;
create_projectile2c("bigball", p->pos, rgb(0, 0.5, 1), asymptotic, dir, 10)->draw = ProjDrawAdd;
PROJECTILE("bigball", p->pos, rgb(1, 0.5, 0), asymptotic, { 1.1*dir, 5 }, .flags = PFLAG_DRAWADD);
PROJECTILE("bigball", p->pos, rgb(0, 0.5, 1), asymptotic, { dir, 10 }, .flags = PFLAG_DRAWADD);
}
global.shake_view += 5;
global.shake_view_fade = 0.2;
@ -666,11 +781,18 @@ int iku_extra_trigger_bullet(Projectile *p, int t) {
p->angle = global.frames + t;
char *part = frand() > 0.5 ? "lightning0" : "lightning1";
complex ofs = nfrand();
ofs += I * nfrand();
Projectile *prt = create_particle2c(part, p->pos + 3 * ofs, rgb(1.0, 0.7 + 0.2 * nfrand(), 0.4), GrowFadeAdd, timeout, 20, 2.4);
prt->angle = frand() * 2 * M_PI;
tsrand_fill(5);
PARTICLE(
.texture = afrand(0) > 0.5 ? "lightning0" : "lightning1",
.pos = p->pos + 3 * (anfrand(1)+I*anfrand(2)),
.angle = afrand(3) * 2 * M_PI,
.color = rgb(1.0, 0.7 + 0.2 * anfrand(4), 0.4),
.rule = timeout,
.draw_rule = GrowFade,
.args = { 20, 2.4 },
.flags = PFLAG_DRAWADD,
);
return 1;
}
@ -686,8 +808,11 @@ void iku_extra_fire_trigger_bullet(void) {
Boss *b = global.boss;
create_projectile3c("soul", b->pos, rgb(0.2, 0.2, 1.0), iku_extra_trigger_bullet,
3*cexp(I*carg(e->pos - b->pos)), add_ref(e), -1);
PROJECTILE("soul", b->pos, rgb(0.2, 0.2, 1.0), iku_extra_trigger_bullet, {
3*cexp(I*carg(e->pos - b->pos)),
add_ref(e),
-1
});
}
int iku_extra_slave(Enemy *e, int t) {
@ -718,7 +843,10 @@ int iku_extra_slave(Enemy *e, int t) {
double r = frand() * 2 * M_PI;
for(i = 0; i < cnt; ++i) {
create_projectile2c("rice", e->pos, rgb(1, 1, 0), asymptotic, 2*cexp(I*(r+i*2*M_PI/cnt)), 2)->draw = ProjDrawAdd;
PROJECTILE("rice", e->pos, rgb(1, 1, 0), asymptotic,
.args = { 2*cexp(I*(r+i*2*M_PI/cnt)), 2 },
.flags = PFLAG_DRAWADD,
);
}
}
} else {
@ -736,7 +864,10 @@ int iku_extra_slave(Enemy *e, int t) {
continue;
for(i = 0; i < cnt; ++i) {
create_projectile2c("ball", o->pos, rgb(0, 1, 1), asymptotic, 1.5*cexp(I*(t + i*2*M_PI/cnt)), 5)->draw = ProjDrawAdd;
PROJECTILE("ball", o->pos, rgb(0, 1, 1), asymptotic,
.args = { 1.5*cexp(I*(t + i*2*M_PI/cnt)), 5},
.flags = PFLAG_DRAWADD,
);
}
o->args[1] = 0;

View file

@ -69,7 +69,9 @@ int stage6_hacker(Enemy *e, int t) {
int i;
for(i = 0; i < 6; i++) {
complex n = sin(_i*0.2)*cexp(I*0.3*(i/2-1))*(1-2*(i&1));
create_projectile1c("wave", e->pos + 120*n, rgb(1.0, 0.2-0.01*_i, 0.0), linear, (0.25-0.5*psin(global.frames+_i*46752+16463*i+467*sin(global.frames*_i*i)))*global.diff+creal(n)+2.0*I);
PROJECTILE("wave", e->pos + 120*n, rgb(1.0, 0.2-0.01*_i, 0.0), linear, {
(0.25-0.5*psin(global.frames+_i*46752+16463*i+467*sin(global.frames*_i*i)))*global.diff+creal(n)+2.0*I
});
}
}
@ -92,7 +94,16 @@ int stage6_side(Enemy *e, int t) {
int i;
int c = 15+10*global.diff;
for(i = 0; i < c; i++) {
create_projectile2c((i%2 == 0) ? "rice" : "flea", e->pos+5*(i/2)*e->args[1], rgb(0.1*cabs(e->args[2]), 0.5, 1), accelerated, (1.0*I-2.0*I*(i&1))*(0.7+0.2*global.diff), 0.001*(i/2)*e->args[1]);
PROJECTILE(
.texture = (i%2 == 0) ? "rice" : "flea",
.pos = e->pos+5*(i/2)*e->args[1],
.color = rgb(0.1*cabs(e->args[2]), 0.5, 1),
.rule = accelerated,
.args = {
(1.0*I-2.0*I*(i&1))*(0.7+0.2*global.diff),
0.001*(i/2)*e->args[1]
}
);
}
e->hp /= 4;
}
@ -122,30 +133,22 @@ int stage6_flowermine(Enemy *e, int t) {
e->args[0] += 0.07*cexp(I*carg(e->args[1]-e->pos));
FROM_TO(0, 1000, 7-global.diff) {
create_projectile2c("rice", e->pos + 40*cexp(I*0.6*_i+I*carg(e->args[0])), rgb(1-psin(_i), 0.3, psin(_i)), wait_proj, I*cexp(I*0.6*_i)*(0.7+0.3*global.diff), 200)->angle = 0.6*_i;
PROJECTILE(
.texture = "rice",
.pos = e->pos + 40*cexp(I*0.6*_i+I*carg(e->args[0])),
.color = rgb(1-psin(_i), 0.3, psin(_i)),
.rule = wait_proj,
.args = {
I*cexp(I*0.6*_i)*(0.7+0.3*global.diff),
200
},
.angle = 0.6*_i,
);
}
return 1;
}
void ScaleFade(Projectile *p, int t) {
glPushMatrix();
glTranslatef(creal(p->pos), cimag(p->pos), 0);
glScalef(creal(p->args[1]), creal(p->args[1]), 1);
glRotatef(180/M_PI*p->angle, 0, 0, 1);
float a = (1.0 - t/creal(p->args[0])) * (1.0 - cimag(p->args[1]));
if(a != 1)
glColor4f(1,1,1,a);
draw_texture_p(0, 0, p->tex);
if(a != 1)
glColor4f(1,1,1,1);
glPopMatrix();
}
void scythe_common(Enemy *e, int t) {
e->args[1] += cimag(e->args[1]);
}
@ -165,21 +168,51 @@ int scythe_mid(Enemy *e, int t) {
e->pos += (6-global.diff-0.005*I*t)*e->args[0];
n = cexp(cimag(e->args[1])*I*t);
create_projectile2c("bigball", e->pos + 80*n, rgb(0.2, 0.5-0.5*cimag(n), 0.5+0.5*creal(n)), wait_proj, global.diff*cexp(0.6*I)*n, 100)->draw=ProjDrawAdd;
PROJECTILE(
.texture = "bigball",
.pos = e->pos + 80*n,
.color = rgb(0.2, 0.5-0.5*cimag(n), 0.5+0.5*creal(n)),
.rule = wait_proj,
.args = {
global.diff*cexp(0.6*I)*n,
100
},
.flags = PFLAG_DRAWADD,
);
if(global.diff > D_Normal && t&1)
create_projectile2c("ball", e->pos + 80*n, rgb(0, 0.2, 0.5), accelerated, n, 0.01*global.diff*cexp(I*carg(global.plr.pos - e->pos - 80*n)))->draw=ProjDrawAdd;
if(global.diff > D_Normal && t&1) {
PROJECTILE("ball", e->pos + 80*n, rgb(0, 0.2, 0.5), accelerated,
.args = {
n,
0.01*global.diff*cexp(I*carg(global.plr.pos - e->pos - 80*n))
},
.flags = PFLAG_DRAWADD,
);
}
scythe_common(e, t);
return 1;
}
void Scythe(Enemy *e, int t) {
Projectile *p = create_projectile_p(&global.particles, get_tex("stage6/scythe"), e->pos+I*6*sin(global.frames/25.0), 0, ScaleFade, timeout, 8, e->args[2], 0, 0);
p->type = Particle;
p->angle = creal(e->args[1]);
PARTICLE(
.texture_ptr = get_tex("stage6/scythe"),
.pos = e->pos+I*6*sin(global.frames/25.0),
.draw_rule = ScaleFade,
.rule = timeout,
.args = { 8, e->args[2] },
.angle = creal(e->args[1]) - M_PI/2,
);
create_particle2c("lasercurve", e->pos+100*creal(e->args[2])*frand()*cexp(2.0*I*M_PI*frand()), rgb(1,0.1,1), GrowFadeAdd, timeout_linear, 60, -I+1);
PARTICLE(
.texture = "lasercurve",
.pos = e->pos+100*creal(e->args[2])*frand()*cexp(2.0*I*M_PI*frand()),
.color = rgb(1.0, 0.1, 1.0),
.draw_rule = GrowFade,
.rule = timeout_linear,
.args = { 60, -I+1 },
.flags = PFLAG_DRAWADD,
);
}
int scythe_intro(Enemy *e, int t) {
@ -242,7 +275,16 @@ int scythe_infinity(Enemy *e, int t) {
float w = min(0.15, 0.0001*(t-40));
e->pos = VIEWPORT_W/2 + 200.0*I + 200*cos(w*(t-40)+M_PI/2.0) + I*80*sin(creal(e->args[0])*w*(t-40));
create_projectile2c("ball", e->pos+80*cexp(I*creal(e->args[1])), rgb(cos(creal(e->args[1])), sin(creal(e->args[1])), cos(creal(e->args[1])+2.1)), asymptotic, (1+0.4*global.diff)*cexp(I*creal(e->args[1])), 3 + 0.2 * global.diff);
PROJECTILE(
.texture = "ball",
.pos = e->pos+80*cexp(I*creal(e->args[1])),
.color = rgb(cos(creal(e->args[1])), sin(creal(e->args[1])), cos(creal(e->args[1])+2.1)),
.rule = asymptotic,
.args = {
(1+0.4*global.diff)*cexp(I*creal(e->args[1])),
3 + 0.2 * global.diff
}
);
}
scythe_common(e, t);
@ -319,12 +361,12 @@ int scythe_newton(Enemy *e, int t) {
//p->args[0] /= 2;
if(global.diff > D_Normal && (int)(creal(e->args[3])+0.5) % (15-5*(global.diff == D_Lunatic)) == 0) {
p->args[0] = cexp(I*f);
p->clr = rgb(1,0,0.5);
p->color = rgb(1,0,0.5);
p->tex = get_tex("proj/bullet");
p->args[1] = 0.005*I;
} else {
p->args[0] = 2*cexp(I*2*M_PI*frand());
p->clr = rgba(frand(), 0, 1, 0.8);
p->color = rgba(frand(), 0, 1, 0.8);
}
p->args[2] = 1;
}
@ -333,7 +375,7 @@ int scythe_newton(Enemy *e, int t) {
FROM_TO(100, 10000, 5-global.diff/2) {
if(cabs(global.plr.pos-e->pos) > 50)
create_projectile3c("rice", e->pos, rgb(0.3, 1, 0.8), linear, I,0,1);
PROJECTILE("rice", e->pos, rgb(0.3, 1, 0.8), linear, { I });
}
scythe_common(e, t);
@ -361,7 +403,7 @@ void elly_newton(Boss *b, int t) {
for(x = -w; x <= w; x++) {
for(y = -w; y <= w; y++) {
create_projectile2c("ball", b->pos+(x+I*y)*(18)*cexp(I*a), rgb(0, 0.5, 1), accelerated, 2*cexp(I*a), 0);
PROJECTILE("ball", b->pos+(x+I*y)*(18)*cexp(I*a), rgb(0, 0.5, 1), linear, { 2*cexp(I*a) });
}
}
}
@ -383,7 +425,6 @@ int scythe_kepler(Enemy *e, int t) {
GO_TO(e, global.boss->pos + 100*cexp(I*_i*0.01),0.03);
}
scythe_common(e, t);
return 1;
}
@ -437,7 +478,17 @@ int kepler_bullet(Projectile *p, int t) {
n=7;
if(tier <= 1+(global.diff>D_Hard) && cimag(p->args[1])*(tier+1) < n) {
create_projectile3c("flea",p->pos,rgb(0.3+0.3*tier,0.6-0.3*tier,1),kepler_bullet,cabs(p->args[0])*phase,tier+1,add_ref(p));
PROJECTILE(
.texture = "flea",
.pos = p->pos,
.color = rgb(0.3 + 0.3 * tier, 0.6 - 0.3 * tier, 1.0),
.rule = kepler_bullet,
.args = {
cabs(p->args[0])*phase,
tier+1,
add_ref(p)
}
);
}
}
return 1;
@ -450,7 +501,8 @@ void elly_kepler(Boss *b, int t) {
AT(0) {
global.enemies->birthtime = global.frames;
global.enemies->logic_rule = scythe_kepler;
create_projectile3c("soul",b->pos,rgb(0.3,0.8,1),kepler_bullet,50+10*global.diff,0,0);
PROJECTILE("soul", b->pos, rgb(0.3,0.8,1), kepler_bullet, { 50+10*global.diff });
elly_clap(b,20);
}
@ -463,9 +515,12 @@ void elly_kepler(Boss *b, int t) {
int c = 2;
for(int i = 0; i < c; i++) {
complex n = cexp(I*2*M_PI/c*i+I*0.6*_i);
create_projectile3c("soul",b->pos,rgb(0.3,0.8,1),kepler_bullet,50*n,0,(1.4+0.1*global.diff)*n);
PROJECTILE("soul", b->pos, rgb(0.3,0.8,1), kepler_bullet, {
50*n,
0,
(1.4+0.1*global.diff)*n
});
}
}
}
@ -485,7 +540,7 @@ void elly_frequency2(Boss *b, int t) {
FROM_TO(0, 2000, 3-global.diff/2) {
complex n = sin(t*0.12*global.diff)*cexp(t*0.02*I*global.diff);
create_projectile2c("plainball", b->pos+80*n, rgb(0,0,0.7), asymptotic, 2*n/cabs(n), 3);
PROJECTILE("plainball", b->pos+80*n, rgb(0,0,0.7), asymptotic, { 2*n/cabs(n), 3 });
}
}
@ -549,10 +604,19 @@ void Baryon(Enemy *e, int t) {
glPopMatrix();
glDisable(GL_TEXTURE_2D);
// create_particle2c("flare", e->pos+40*frand()*cexp(2.0*I*M_PI*frand()), rgb(0, 1, 1), GrowFadeAdd, timeout_linear, 50, 1-I);
// PARTICLE("flare", e->pos+40*frand()*cexp(2.0*I*M_PI*frand()), rgb(0, 1, 1), GrowFadeAdd, timeout_linear, 50, 1-I);
if(!(t % 10) && global.boss && cabs(e->pos - global.boss->pos) > 2) {
create_particle1c("stain", e->pos+10*frand()*cexp(2.0*I*M_PI*frand()), rgb(0, 1*alpha, 0.7*alpha), FadeAdd, timeout, 50)->angle = 2*M_PI*frand();
PARTICLE(
.texture = "stain",
.pos = e->pos+10*frand()*cexp(2.0*I*M_PI*frand()),
.color = rgb(0, 1*alpha, 0.7*alpha),
.draw_rule = Fade,
.rule = timeout,
.args = { 50 },
.angle = 2*M_PI*frand(),
.flags = PFLAG_DRAWADD,
);
}
}
@ -589,8 +653,23 @@ void BaryonCenter(Enemy *e, int t) {
}
glDisable(GL_TEXTURE_2D);
create_particle2c("flare", e->pos+40*frand()*cexp(2.0*I*M_PI*frand()), rgb(0, 1, 1), GrowFadeAdd, timeout_linear, 50, 1-I);
create_particle1c("stain", e->pos+40*frand()*cexp(2.0*I*M_PI*frand()), rgb(0, 1, 0.2), FadeAdd, timeout, 50)->angle = 2*M_PI*frand();
complex p = e->pos+40*frand()*cexp(2.0*I*M_PI*frand());
PARTICLE("flare", p, rgb(0.0, 1.0, 1.0),
.draw_rule = GrowFade,
.rule = timeout_linear,
.args = { 50, 1-I },
.flags = PFLAG_DRAWADD,
);
PARTICLE("stain", p, rgb(0.0, 1.0, 0.2),
.draw_rule = Fade,
.rule = timeout,
.args = { 50 },
.angle = 2*M_PI*frand(),
.flags = PFLAG_DRAWADD,
);
}
int baryon_unfold(Enemy *e, int t) {
@ -714,9 +793,20 @@ int baryon_eigenstate(Enemy *e, int t) {
for(i = 0; i < c; i++) {
complex n = cexp(2.0*I*_i+I*M_PI/2+I*creal(e->args[2]));
for(j = 0; j < 3; j++)
create_projectile4c("plainball", e->pos + 60*cexp(2.0*I*M_PI/c*i), rgb(j == 0, j == 1, j == 2), eigenstate_proj, 1*n, 1, 60, 0.6*I*n*(j-1)*cexp(0.4*I-0.1*I*global.diff))->draw = ProjDrawAdd;
for(j = 0; j < 3; j++) {
PROJECTILE(.texture = "plainball",
.pos = e->pos + 60*cexp(2.0*I*M_PI/c*i),
.color = rgb(j == 0, j == 1, j == 2),
.rule = eigenstate_proj,
.args = {
1*n,
1,
60,
0.6*I*n*(j-1)*cexp(0.4*I-0.1*I*global.diff)
},
.flags = PFLAG_DRAWADD,
);
}
}
}
@ -772,7 +862,7 @@ int broglie_particle(Projectile *p, int t) {
} else {
if(t == scattertime && p->type != DeadProj) {
p->type = EnemyProj;
p->draw = ProjDrawAdd;
p->draw_rule = ProjDraw;
double angle_ampl = creal(p->args[3]);
double angle_freq = cimag(p->args[3]);
@ -836,19 +926,23 @@ int broglie_charge(Projectile *p, int t) {
double inc = pow(1.10 - 0.10 * (global.diff - D_Easy), 2);
for(double ofs = 0; ofs < l->deathtime; ofs += inc, ++pnum) {
complex pos = l->prule(l, ofs);
bool fast = global.diff == D_Easy || pnum & 1;
char *txt = fast ? "thickrice" : "rice";
double spd = fast ? 2.0 : 1.5;
Projectile *part = create_projectile4c(txt, pos,
hsl(hue + lnum * (M_PI/12)/(M_PI/2), 1.0, 0.5), broglie_particle,
add_ref(l), I*ofs + l->timespan + ofs - 10, spd,
(1 + 2 * ((global.diff - 1) / (double)(D_Lunatic - 1))) * M_PI/11 + s_freq*10*I);
part->draw = ProjNoDraw;
part->type = FakeProj;
PROJECTILE(
.texture = fast ? "thickrice" : "rice",
.pos = l->prule(l, ofs),
.color = hsl(hue + lnum * (M_PI/12)/(M_PI/2), 1.0, 0.5),
.rule = broglie_particle,
.args = {
add_ref(l),
I*ofs + l->timespan + ofs - 10,
fast ? 2.0 : 1.5,
(1 + 2 * ((global.diff - 1) / (double)(D_Lunatic - 1))) * M_PI/11 + s_freq*10*I
},
.draw_rule = ProjNoDraw,
.flags = PFLAG_DRAWADD,
.type = FakeProj,
);
}
}
@ -880,9 +974,9 @@ int baryon_broglie(Enemy *e, int t) {
TIMER(&t);
Enemy *master = NULL;
for(Enemy *e = global.enemies; e; e = e->next) {
if(e->draw_rule == Baryon) {
master = e;
for(Enemy *en = global.enemies; en; en = en->next) {
if(en->draw_rule == Baryon) {
master = en;
break;
}
}
@ -914,16 +1008,22 @@ int baryon_broglie(Enemy *e, int t) {
FROM_TO(delay, delay + step * cnt - 1, step) {
double a = 2*M_PI * (0.25 + 1.0/cnt*_i);
complex n = cexp(I*a);
double hue = (attack_num * M_PI + a + M_PI/6) / (M_PI*2);
Projectile *p = create_projectile4c("ball", e->pos + 15*n,
hsl(hue, 1.0, 0.55),
broglie_charge, n, (fire_delay - step * _i), attack_num, hue
PROJECTILE(
.texture = "ball",
.pos = e->pos + 15*n,
.color = hsl(hue, 1.0, 0.55),
.rule = broglie_charge,
.args = {
n,
(fire_delay - step * _i),
attack_num,
hue
},
.flags = PFLAG_DRAWADD,
.angle = (2*M_PI*_i)/cnt + aim_angle,
);
p->draw = ProjDrawAdd;
p->angle = (2*M_PI*_i)/cnt + aim_angle;
}
if(t < delay /*|| t > delay + fire_delay*/) {
@ -977,7 +1077,16 @@ int baryon_nattack(Enemy *e, int t) {
FROM_TO(30, 10000, (7 - global.diff)) {
float a = 0.2*_i + creal(e->args[2]) + 0.006*t;
float ca = a + t/60.0f;
create_projectile2c("ball", e->pos+40*cexp(I*a), rgb(cos(ca), sin(ca), cos(ca+2.1)), asymptotic, (1+0.2*global.diff)*cexp(I*a), 3);
PROJECTILE(
.texture = "ball",
.pos = e->pos+40*cexp(I*a),
.color = rgb(cos(ca), sin(ca), cos(ca+2.1)),
.rule = asymptotic,
.args = {
(1+0.2*global.diff)*cexp(I*a),
3
}
);
}
return 1;
@ -1090,7 +1199,17 @@ int baryon_ricci(Enemy *e, int t) {
FROM_TO(150,100000,10) {
int c = 3;
complex n = cexp(2*M_PI*I * (0.25 + 1.0/c*_i));
create_projectile2c("ball", 15*n, rgb(0,0.5,0.1),ricci_proj2,-n,add_ref(e))->draw = ProjDrawAdd;
PROJECTILE(
.texture = "ball",
.pos = 15*n,
.color = rgb(0.0, 0.5, 0.1),
.rule = ricci_proj2,
.args = {
-n,
add_ref(e),
},
.flags = PFLAG_DRAWADD,
);
}
}
}
@ -1135,14 +1254,14 @@ static int ricci_proj(Projectile *p, int t) {
}
p->pos = p->pos0 + p->args[0]*t+shift;
p->angle = carg(p->args[0]);
float r,g,b,a;
parse_color(p->clr,&r,&g,&b, &a);
a = 0.5 + 0.5 * max(0,tanh((time-80)/100.))*clamp(influence,0.2,1);
float a = 0.5 + 0.5 * max(0,tanh((time-80)/100.))*clamp(influence,0.2,1);
a *= min(1, t / 20.0f);
p->clr = rgba(r,g,cabs(shift)/20., a);
p->color = derive_color(p->color, CLRMASK_B|CLRMASK_A,
rgba(0, 0, cabs(shift)/20.0, a)
);
return 1;
}
@ -1166,9 +1285,10 @@ void elly_ricci(Boss *b, int t) {
int w = VIEWPORT_W;
complex pos = 0.5 * w/(float)c + fmod(w/(float)c*(i+0.5*_i),w) + (VIEWPORT_H+10)*I;
Projectile *p = create_projectile1c("ball", pos, rgba(0.5, 0.0, 0,0), ricci_proj, -v*I);
p->draw = ProjDrawNoFlareAdd;
p->maxviewportdist = SAFE_RADIUS_MAX;
PROJECTILE("ball", pos, rgba(0.5, 0.0, 0,0), ricci_proj, { -v*I },
.flags = PFLAG_DRAWADD | PFLAG_NOSPAWNZOOM | PFLAG_NOGRAZE,
.max_viewport_dist = SAFE_RADIUS_MAX,
);
}
}
}
@ -1212,7 +1332,7 @@ void elly_baryonattack2(Boss *b, int t) {
complex n = cexp(I*(a+carg(global.plr.pos-b->pos)));
for(int j = 0; j < 3; ++j) {
create_projectile2c("bigball", b->pos, rgb(0,0.2,0.9), asymptotic, n, 2 * j);
PROJECTILE("bigball", b->pos, rgb(0,0.2,0.9), asymptotic, { n, 2 * j });
}
}
} else {
@ -1222,7 +1342,7 @@ void elly_baryonattack2(Boss *b, int t) {
for(x = -w; x <= w; x++)
for(y = -w; y <= w; y++)
create_projectile2c("bigball", b->pos+25*(x+I*y)*n, rgb(0,0.2,0.9), asymptotic, n, 3);
PROJECTILE("bigball", b->pos+25*(x+I*y)*n, rgb(0,0.2,0.9), asymptotic, { n, 3 });
}
}
}
@ -1287,13 +1407,23 @@ void elly_lhc(Boss *b, int t) {
complex v = 3*cexp(2.0*I*M_PI*frand());
tsrand_fill(4);
create_lasercurve2c(pos, 70+20*global.diff, 300, rgb(1, 1, 1), las_accel, v, 0.02*frand()*copysign(1,creal(v)))->width=15;
create_projectile1c("soul", pos, rgb(0.4, 0, 1.0), linear, (1+2.5*afrand(0))*cexp(2.0*I*M_PI*afrand(1)))->draw = ProjDrawAdd;
create_projectile1c("bigball", pos, rgb(1, 0, 0.4), linear, (1+2.5*afrand(2))*cexp(2.0*I*M_PI*afrand(3)))->draw = ProjDrawAdd;
PROJECTILE("soul", pos, rgb(0.4, 0.0, 1.0), linear,
.args = { (1+2.5*afrand(0))*cexp(2.0*I*M_PI*afrand(1)) },
.flags = PFLAG_DRAWADD
);
PROJECTILE("bigball", pos, rgb(1.0, 0.0, 0.4), linear,
.args = { (1+2.5*afrand(2))*cexp(2.0*I*M_PI*afrand(3)) },
.flags = PFLAG_DRAWADD
);
}
}
FROM_TO(0, 100000,7-global.diff)
create_projectile2c("ball", b->pos, rgb(0, 0.4,1), asymptotic, cexp(2.0*I*_i), 3)->draw = ProjDrawAdd;
PROJECTILE("ball", b->pos, rgb(0, 0.4,1), asymptotic,
.args = { cexp(2.0*I*_i), 3 },
.flags = PFLAG_DRAWADD,
);
FROM_TO(300, 10000, 400) {
global.shake_view = 0;
@ -1371,23 +1501,53 @@ int curvature_slave(Enemy *e, int t) {
if(cabs(pos - global.plr.pos) > 50) {
tsrand_fill(2);
float speed = 0.5/(1+(global.diff < D_Hard));
create_projectile2c("flea",pos,rgb(0.1*afrand(0), 0.6,1), curvature_bullet, speed*cexp(2*M_PI*I*afrand(1)), add_ref(e));
PROJECTILE(
.texture = "flea",
.pos = pos,
.color = rgb(0.1*afrand(0), 0.6,1),
.rule = curvature_bullet,
.args = {
speed*cexp(2*M_PI*I*afrand(1)),
add_ref(e)
}
);
}
}
if(global.diff > D_Easy && t % (60-8*global.diff) == 0) {
tsrand_fill(2);
complex pos = VIEWPORT_W*afrand(0)+I*VIEWPORT_H*afrand(1);
if(cabs(pos - global.plr.pos) > 100)
create_projectile1c("ball",pos,rgb(1, 0.4,1), linear, cexp(I*carg(global.plr.pos-pos)))->draw = ProjDrawAdd;
if(cabs(pos - global.plr.pos) > 100) {
PROJECTILE("ball", pos, rgb(1, 0.4,1), linear,
.args = { cexp(I*carg(global.plr.pos-pos)) },
.flags = PFLAG_DRAWADD,
);
}
}
if(global.diff >= D_Hard && !(t%20)) {
Projectile *p = create_projectile1c("bigball",global.boss->pos,rgb(0.5, 0.4,1), linear, 4*I*cexp(I*M_PI*2/5*saw(t/100.)));
p->draw = ProjDrawAdd;
Projectile *p =PROJECTILE(
.texture = "bigball",
.pos = global.boss->pos,
.color = rgb(0.5, 0.4,1),
.rule = linear,
.args = { 4*I*cexp(I*M_PI*2/5*saw(t/100.)) },
.flags = PFLAG_DRAWADD,
);
if(global.diff == D_Lunatic) {
create_projectile2c("plainball",global.boss->pos,rgb(0.2, 0.4,1), curvature_orbiter, 40*cexp(I*t/400),add_ref(p))->draw = ProjDrawAdd;
PROJECTILE(
.texture = "plainball",
.pos = global.boss->pos,
.color = rgb(0.2, 0.4,1),
.rule = curvature_orbiter,
.args = {
40*cexp(I*t/400),
add_ref(p)
},
.flags = PFLAG_DRAWADD,
);
}
}
@ -1434,14 +1594,6 @@ void elly_baryon_explode(Boss *b, int t) {
}
}
void ScaleFadeSub(Projectile *proj, int t) {
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
ScaleFade(proj, t);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glBlendEquation(GL_FUNC_ADD);
}
int theory_proj(Projectile *p, int t) {
if(t < 0)
@ -1478,7 +1630,7 @@ int theory_proj(Projectile *p, int t) {
break;
}
p->clr = rgb(cos(p->angle), sin(p->angle), cos(p->angle+2.1));
p->color = rgb(cos(p->angle), sin(p->angle), cos(p->angle+2.1));
p->args[1] += I;
}
@ -1503,8 +1655,18 @@ int scythe_theory(Enemy *e, int t) {
n = cexp(cimag(e->args[1])*I*t);
TIMER(&t);
FROM_TO(0, 300, 4)
create_projectile2c("ball", e->pos + 80*n, rgb(carg(n), 1-carg(n), 1/carg(n)), wait_proj, (0.6+0.3*global.diff)*cexp(0.6*I)*n, 100)->draw=ProjDrawAdd;
FROM_TO(0, 300, 4) {
PROJECTILE(
.texture = "ball",
.pos = e->pos + 80*n,
.color = rgb(carg(n), 1-carg(n), 1/carg(n)),
.rule = wait_proj,
.args = {
(0.6+0.3*global.diff)*cexp(0.6*I)*n, 100
},
.flags = PFLAG_DRAWADD,
);
}
scythe_common(e, t);
return 1;
@ -1529,14 +1691,33 @@ void elly_theory(Boss *b, int time) {
FROM_TO(0, 500, 10)
for(i = 0; i < 3; i++) {
tsrand_fill(5);
create_particle2c("stain", b->pos+80*afrand(0)*cexp(2.0*I*M_PI*afrand(1)), rgba(1-afrand(2),0.8,0.5,1), FadeAdd, timeout, 60, 1+3*afrand(3))->angle = 2*M_PI*afrand(4);
PARTICLE(
.texture = "stain",
.pos = b->pos+80*afrand(0)*cexp(2.0*I*M_PI*afrand(1)),
.color = rgb(1 - afrand(2), 0.8, 0.5),
.draw_rule = Fade,
.rule = timeout,
.args = {60, 1+3*afrand(3) },
.angle = 2*M_PI*afrand(4),
.flags = PFLAG_DRAWADD,
);
}
FROM_TO(20, 70, 30-global.diff) {
int c = 20+2*global.diff;
for(i = 0; i < c; i++) {
complex n = cexp(2.0*I*M_PI/c*i);
create_projectile2c("soul", b->pos, rgb(0.2, 0, 0.9), accelerated, n, (0.01+0.002*global.diff)*n+0.01*I*n*(1-2*(_i&1)))->draw = ProjDrawAdd;
PROJECTILE(
.texture = "soul",
.pos = b->pos,
.color = rgb(0.2, 0, 0.9),
.rule = accelerated,
.args = {
n,
(0.01+0.002*global.diff)*n+0.01*I*n*(1-2*(_i&1))
},
.flags = PFLAG_DRAWADD,
);
}
}
@ -1544,9 +1725,17 @@ void elly_theory(Boss *b, int time) {
int x, y;
int w = 2;
complex n = cexp(0.7*I*_i+0.2*I*frand());
for(x = -w; x <= w; x++)
for(y = -w; y <= w; y++)
create_projectile2c("ball", b->pos + (15+5*global.diff)*(x+I*y)*n, rgb(0, 0.5, 1), accelerated, 2*n, 0.026*n);
for(x = -w; x <= w; x++) {
for(y = -w; y <= w; y++) {
PROJECTILE(
.texture = "ball",
.pos = b->pos + (15+5*global.diff)*(x+I*y)*n,
.color = rgb(0, 0.5, 1),
.rule = accelerated,
.args = { 2*n, 0.026*n }
);
}
}
}
FROM_TO(250, 299, 10) {

View file

@ -177,6 +177,7 @@ typedef void (APIENTRY *tsglGenBuffers_ptr)(GLsizei n, GLuint *buffers);
typedef void (APIENTRY *tsglGenFramebuffers_ptr)(GLsizei n, GLuint *framebuffers);
typedef void (GLAPIENTRY *tsglGenTextures_ptr)(GLsizei n, GLuint *textures);
typedef void (APIENTRY *tsglGetActiveUniform_ptr)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
typedef void (GLAPIENTRY *tsglGetIntegerv_ptr)(GLenum pname, GLint *params);
typedef void (APIENTRY *tsglGetProgramInfoLog_ptr)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (APIENTRY *tsglGetProgramiv_ptr)(GLuint program, GLenum pname, GLint *params);
typedef void (APIENTRY *tsglGetShaderInfoLog_ptr)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
@ -195,7 +196,6 @@ typedef void (GLAPIENTRY *tsglReadBuffer_ptr)(GLenum mode);
typedef void (GLAPIENTRY *tsglReadPixels_ptr)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
typedef void (GLAPIENTRY *tsglRotatef_ptr)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
typedef void (GLAPIENTRY *tsglScalef_ptr)(GLfloat x, GLfloat y, GLfloat z);
typedef void (GLAPIENTRY *tsglScissor_ptr)(GLint x, GLint y, GLsizei width, GLsizei height);
typedef void (APIENTRY *tsglShaderSource_ptr)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
typedef void (GLAPIENTRY *tsglTexCoordPointer_ptr)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr);
typedef void (GLAPIENTRY *tsglTexImage2D_ptr)(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
@ -270,6 +270,7 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#undef glGenFramebuffers
#undef glGenTextures
#undef glGetActiveUniform
#undef glGetIntegerv
#undef glGetProgramInfoLog
#undef glGetProgramiv
#undef glGetShaderInfoLog
@ -288,7 +289,6 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#undef glReadPixels
#undef glRotatef
#undef glScalef
#undef glScissor
#undef glShaderSource
#undef glTexCoordPointer
#undef glTexImage2D
@ -364,6 +364,7 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#define glGenFramebuffers tsglGenFramebuffers
#define glGenTextures tsglGenTextures
#define glGetActiveUniform tsglGetActiveUniform
#define glGetIntegerv tsglGetIntegerv
#define glGetProgramInfoLog tsglGetProgramInfoLog
#define glGetProgramiv tsglGetProgramiv
#define glGetShaderInfoLog tsglGetShaderInfoLog
@ -382,7 +383,6 @@ typedef void (GLAPIENTRY *tsglViewport_ptr)(GLint x, GLint y, GLsizei width, GLs
#define glReadPixels tsglReadPixels
#define glRotatef tsglRotatef
#define glScalef tsglScalef
#define glScissor tsglScissor
#define glShaderSource tsglShaderSource
#define glTexCoordPointer tsglTexCoordPointer
#define glTexImage2D tsglTexImage2D
@ -460,6 +460,7 @@ GLDEF(glGenBuffers, tsglGenBuffers, tsglGenBuffers_ptr) \
GLDEF(glGenFramebuffers, tsglGenFramebuffers, tsglGenFramebuffers_ptr) \
GLDEF(glGenTextures, tsglGenTextures, tsglGenTextures_ptr) \
GLDEF(glGetActiveUniform, tsglGetActiveUniform, tsglGetActiveUniform_ptr) \
GLDEF(glGetIntegerv, tsglGetIntegerv, tsglGetIntegerv_ptr) \
GLDEF(glGetProgramInfoLog, tsglGetProgramInfoLog, tsglGetProgramInfoLog_ptr) \
GLDEF(glGetProgramiv, tsglGetProgramiv, tsglGetProgramiv_ptr) \
GLDEF(glGetShaderInfoLog, tsglGetShaderInfoLog, tsglGetShaderInfoLog_ptr) \
@ -478,7 +479,6 @@ GLDEF(glReadBuffer, tsglReadBuffer, tsglReadBuffer_ptr) \
GLDEF(glReadPixels, tsglReadPixels, tsglReadPixels_ptr) \
GLDEF(glRotatef, tsglRotatef, tsglRotatef_ptr) \
GLDEF(glScalef, tsglScalef, tsglScalef_ptr) \
GLDEF(glScissor, tsglScissor, tsglScissor_ptr) \
GLDEF(glShaderSource, tsglShaderSource, tsglShaderSource_ptr) \
GLDEF(glTexCoordPointer, tsglTexCoordPointer, tsglTexCoordPointer_ptr) \
GLDEF(glTexImage2D, tsglTexImage2D, tsglTexImage2D_ptr) \
@ -560,6 +560,7 @@ GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers);
GLAPI void GLAPIENTRY glGenTextures( GLsizei n, GLuint *textures );
GLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
GLAPI void GLAPIENTRY glGetIntegerv( GLenum pname, GLint *params );
GLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
GLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);
GLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
@ -578,7 +579,6 @@ GLAPI void GLAPIENTRY glReadBuffer( GLenum mode );
GLAPI void GLAPIENTRY glReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels );
GLAPI void GLAPIENTRY glRotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );
GLAPI void GLAPIENTRY glScalef( GLfloat x, GLfloat y, GLfloat z );
GLAPI void GLAPIENTRY glScissor( GLint x, GLint y, GLsizei width, GLsizei height);
GLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
GLAPI void GLAPIENTRY glTexCoordPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );
GLAPI void GLAPIENTRY glTexImage2D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
@ -653,6 +653,7 @@ GLAPI void GLAPIENTRY glViewport( GLint x, GLint y, GLsizei width, GLsizei heigh
#define tsglGenFramebuffers glGenFramebuffers
#define tsglGenTextures glGenTextures
#define tsglGetActiveUniform glGetActiveUniform
#define tsglGetIntegerv glGetIntegerv
#define tsglGetProgramInfoLog glGetProgramInfoLog
#define tsglGetProgramiv glGetProgramiv
#define tsglGetShaderInfoLog glGetShaderInfoLog
@ -671,7 +672,6 @@ GLAPI void GLAPIENTRY glViewport( GLint x, GLint y, GLsizei width, GLsizei heigh
#define tsglReadPixels glReadPixels
#define tsglRotatef glRotatef
#define tsglScalef glScalef
#define tsglScissor glScissor
#define tsglShaderSource glShaderSource
#define tsglTexCoordPointer glTexCoordPointer
#define tsglTexImage2D glTexImage2D