diff --git a/gfx/boss_indicator.png b/gfx/boss_indicator.png
new file mode 100644
index 00000000..202cddfa
Binary files /dev/null and b/gfx/boss_indicator.png differ
diff --git a/gfx/boss_indicator.svg b/gfx/boss_indicator.svg
new file mode 100644
index 00000000..b7e734ac
--- /dev/null
+++ b/gfx/boss_indicator.svg
@@ -0,0 +1,118 @@
+
+
+
+
diff --git a/gfx/proj/ball.svg b/gfx/proj/ball.svg
index c3c951cd..11158b1c 100644
--- a/gfx/proj/ball.svg
+++ b/gfx/proj/ball.svg
@@ -10,12 +10,12 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="26"
- height="26"
+ width="28.202377"
+ height="28.202377"
id="svg2"
version="1.1"
- inkscape:version="0.48.1 r9760"
- sodipodi:docname="ball_auto.svg"
+ inkscape:version="0.48.2 r9819"
+ sodipodi:docname="ball.svg"
inkscape:export-filename="/home/laochailan/src/taisei/gfx/proj/ball.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
@@ -80,16 +80,16 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.627417"
- inkscape:cx="8.6638704"
- inkscape:cy="10.219011"
+ inkscape:cx="14.309939"
+ inkscape:cy="11.320207"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
- inkscape:window-width="958"
- inkscape:window-height="1037"
- inkscape:window-x="960"
- inkscape:window-y="17"
- inkscape:window-maximized="0"
+ inkscape:window-width="1920"
+ inkscape:window-height="1038"
+ inkscape:window-x="0"
+ inkscape:window-y="-1"
+ inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
@@ -110,7 +110,7 @@
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
- transform="translate(0.25949629,-1026.6081)">
+ transform="translate(1.360685,-1025.5069)">
+ d="m 18.782524,10.034214 a 8.4631844,8.4631844 0 1 1 -16.9263686,0 8.4631844,8.4631844 0 1 1 16.9263686,0 z"
+ transform="matrix(1.5023271,0,0,1.5023271,-2.76252,1024.5334)" />
diff --git a/gfx/proj/plainball.png b/gfx/proj/plainball.png
new file mode 100644
index 00000000..6f98c4e4
Binary files /dev/null and b/gfx/proj/plainball.png differ
diff --git a/gfx/proj/plainball.svg b/gfx/proj/plainball.svg
new file mode 100644
index 00000000..8bac8f07
--- /dev/null
+++ b/gfx/proj/plainball.svg
@@ -0,0 +1,125 @@
+
+
+
+
diff --git a/src/boss.c b/src/boss.c
index 182f6231..06e5a7a4 100644
--- a/src/boss.c
+++ b/src/boss.c
@@ -50,7 +50,8 @@ void draw_boss(Boss *boss) {
draw_text(AL_Center, VIEWPORT_W - 20, 10, buf, _fonts.standard);
glPushMatrix();
- glTranslatef(boss->attacks[boss->acount-1].dmglimit+10, 4,0);
+ glTranslatef(VIEWPORT_W-10, 4, 0);
+ glScalef((VIEWPORT_W-20)/(float)boss->attacks[boss->acount-1].dmglimit,1,1);
int i;
for(i = boss->acount-1; i >= 0; i--) {
@@ -62,7 +63,7 @@ void draw_boss(Boss *boss) {
glColor3f(1,1,1);
break;
case AT_Spellcard:
- glColor3f(1,0.8,0.8);
+ glColor3f(1,0.65,0.65);
break;
case AT_SurvivalSpell:
glColor3f(1,0.5,0.5);
@@ -133,6 +134,11 @@ void start_attack(Boss *b, Attack *a) {
a->rule(b, EVENT_BIRTH);
if(a->type == AT_Spellcard || a->type == AT_SurvivalSpell)
play_sound("charge_generic");
+
+ Projectile *p;
+ for(p = global.projs; p; p = p->next)
+ if(p->type == FairyProj)
+ p->type = DeadProj;
}
Attack *boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule) {
diff --git a/src/dialog.c b/src/dialog.c
index 3cd99962..393edd49 100644
--- a/src/dialog.c
+++ b/src/dialog.c
@@ -14,8 +14,10 @@ Dialog *create_dialog(char *left, char *right) {
Dialog *d = malloc(sizeof(Dialog));
memset(d, 0, sizeof(Dialog));
- d->images[Left] = get_tex(left);
- d->images[Right] = get_tex(right);
+ if(left)
+ d->images[Left] = get_tex(left);
+ if(right)
+ d->images[Right] = get_tex(right);
d->page_time = global.frames;
d->birthtime = global.frames;
diff --git a/src/item.c b/src/item.c
index af766c49..22e7ba20 100644
--- a/src/item.c
+++ b/src/item.c
@@ -32,7 +32,7 @@ void draw_items() {
for(p = global.items; p; p = p->next) {
switch(p->type){
case Power:
- if(global.plr.power <= PLR_MAXPOWER) {
+ if(global.plr.power < PLR_MAXPOWER) {
tex = get_tex("items/power");
break;
}
@@ -90,7 +90,7 @@ void process_items() {
if(v == 1) {
switch(item->type) {
case Power:
- plr_set_power(&global.plr, global.plr.power + 0.05);
+ plr_set_power(&global.plr, global.plr.power + 0.01);
break;
case Point:
global.points += 100;
diff --git a/src/projectile.c b/src/projectile.c
index 6181fc36..d13381fd 100644
--- a/src/projectile.c
+++ b/src/projectile.c
@@ -172,8 +172,8 @@ int linear(Projectile *p, int t) { // sure is physics in here; a[0]: velocity
int accelerated(Projectile *p, int t) {
if(t < 0)
return 1;
- p->angle = carg(p->args[0]);
- p->pos = p->pos0 + p->args[0]*t + p->args[1]*t*t;
+ p->angle = carg(p->args[0] + p->args[1]*t);
+ p->pos = p->pos0 + p->args[0]*t + p->args[1]*t*t/2.0;
return 1;
}
@@ -181,7 +181,7 @@ int accelerated(Projectile *p, int t) {
int asymptotic(Projectile *p, int t) { // v = a[0]*(a[1] + 1); a[1] -> 0
if(t < 0)
return 1;
- p->angle = carg(p->args[0] + p->args[1]);
+ p->angle = carg(p->args[0]);
p->args[1] *= 0.8;
p->pos += p->args[0]*(p->args[1] + 1);
diff --git a/src/stage.c b/src/stage.c
index 09bbcefa..27b04f08 100644
--- a/src/stage.c
+++ b/src/stage.c
@@ -117,6 +117,9 @@ void draw_hud() {
sprintf(buf, "%i fps", global.fps.show_fps);
draw_text(AL_Right, SCREEN_W, SCREEN_H-20, buf, _fonts.standard);
+
+ if(global.boss)
+ draw_texture(VIEWPORT_X+creal(global.boss->pos), 590, "boss_indicator");
}
void stage_draw() {
diff --git a/src/stages/stage0.c b/src/stages/stage0.c
index 538dc0ec..8765ae26 100644
--- a/src/stages/stage0.c
+++ b/src/stages/stage0.c
@@ -10,13 +10,15 @@
#include "stage.h"
#include "global.h"
-Dialog *test_dialog() {
- Dialog *d = create_dialog("dialog/marisa", "dialog/youmu");
+Dialog *stage0_dialog() {
+ Dialog *d = create_dialog(global.plr.cha == Marisa ? "dialog/marisa" : "dialog/youmu", "masterspark");
- dadd_msg(d, Left, "Hello");
- dadd_msg(d, Right, "Hello you");
- dadd_msg(d, Right, "Uhm ... who are you?\nNew line.\nAnother longer line.");
- dadd_msg(d, Left, "idk");
+ dadd_msg(d, Right, "Hey! Who is there?");
+ dadd_msg(d, Left, "Just someone?");
+ dadd_msg(d, Right, "How dare you pass the lake of the fairies!\nIt's a dangerous area for weak humans.");
+ dadd_msg(d, Left, "I'm just walking by. Any problem with that?");
+ dadd_msg(d, Right, "Of course! It's not right!");
+ dadd_msg(d, Right, "I'll just freeze you!");
return d;
}
@@ -78,14 +80,20 @@ void stage0_draw() {
void cirno_intro(Boss *c, int time) {
- TIMER(&time);
-
- GO_TO(c, VIEWPORT_W/2.0 + 100I, 0.03);
- AT(220)
- global.dialog = test_dialog();
+ GO_TO(c, VIEWPORT_W/2.0 + 100I, 0.035);
}
+void cirno_icy(Boss *c, int time) {
+ int t = time % 280;
+ TIMER(&t);
+
+ FROM_TO(0, 200, 3) {
+ create_projectile2c("crystal", VIEWPORT_W/2.0 + 10*_i*(0.5-frand()) + cimag(c->pos)*I, rgb(0.2,0.5,0.4+0.5*frand()), accelerated, 1.7*cexp(I*_i/10.0)*(1-2*(_i&1)), 0.0001I*_i + (0.0025 - 0.005*frand()));
+ }
+}
+
+
int cirno_pfreeze_frogs(Projectile *p, int t) {
if(t == EVENT_DEATH)
free_ref(p->args[1]);
@@ -132,14 +140,14 @@ void cirno_perfect_freeze(Boss *c, int time) {
create_projectile2c("ball", c->pos, rgb(r, g, b), cirno_pfreeze_frogs, 4*cexp(I*rand()), add_ref(global.boss));
}
- GO_AT(c, 110, 150, 2 + 1I);
+ GO_AT(c, 160, 190, 2 + 1I);
FROM_TO(160, 220, 6) {
- create_projectile2c("rice", c->pos + 60, rgb(0.3, 0.4, 0.9), asymptotic, 4*cexp(I*(carg(global.plr.pos - c->pos) + frand() - 0.5)), 2.5);
- create_projectile2c("rice", c->pos - 60, rgb(0.3, 0.4, 0.9), asymptotic, 4*cexp(I*(carg(global.plr.pos - c->pos) + frand() - 0.5)), 2.5);
+ create_projectile2c("rice", c->pos + 60, rgb(0.3, 0.4, 0.9), asymptotic, 3*cexp(I*(carg(global.plr.pos - c->pos) + frand() - 0.5)), 2.5);
+ create_projectile2c("rice", c->pos - 60, rgb(0.3, 0.4, 0.9), asymptotic, 3*cexp(I*(carg(global.plr.pos - c->pos) + frand() - 0.5)), 2.5);
}
- GO_AT(c, 160, 220, -3)
+ GO_AT(c, 190, 220, -2)
FROM_TO(280, 320, 1)
GO_TO(c, VIEWPORT_W/2.0 + 100I, 0.04);
@@ -155,10 +163,133 @@ void cirno_pfreeze_bg(Boss *c, int time) {
glColor4f(1,1,1,1);
}
-Boss *create_cirno() {
+Boss *create_cirno_mid() {
Boss* cirno = create_boss("Cirno", "cirno", VIEWPORT_W + 150 + 30I);
- boss_add_attack(cirno, AT_Move, "Introduction", 4, 0, cirno_intro, NULL);
- boss_add_attack(cirno, AT_Spellcard, "Freeze Sign ~ Perfect Freeze", 22, 100, cirno_perfect_freeze, cirno_pfreeze_bg);
+ boss_add_attack(cirno, AT_Move, "Introduction", 2, 0, cirno_intro, NULL);
+ boss_add_attack(cirno, AT_Normal, "Icy Storm", 20, 240, cirno_icy, NULL);
+ boss_add_attack(cirno, AT_Spellcard, "Freeze Sign ~ Perfect Freeze", 32, 350, cirno_perfect_freeze, cirno_pfreeze_bg);
+
+ start_attack(cirno, cirno->attacks);
+ return cirno;
+}
+
+void cirno_intro_boss(Boss *c, int time) {
+ TIMER(&time);
+ GO_TO(c, VIEWPORT_W/2.0 + 100I, 0.035);
+
+ AT(100)
+ global.dialog = stage0_dialog();
+}
+
+void cirno_iceplosion0(Boss *c, int time) {
+ int t = time % 350;
+ TIMER(&t);
+
+ FROM_TO(20,30,2) {
+ int i;
+ for(i = 0; i < 8; 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.3)), _i*0.7);
+ }
+ }
+
+ FROM_TO(40,100,1) {
+ create_projectile2c("crystal", c->pos, rgb(0.3,0.3,0.8), accelerated, 2*cexp(2I*M_PI*frand()) + 2I, 0.002*cexp(I*(M_PI/10.0*(_i%20))));
+ }
+
+ FROM_TO(150, 300, 30) {
+ float dif = M_PI*2*frand();
+ int i;
+ 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);
+ }
+ }
+}
+
+void cirno_crystal_rain(Boss *c, int time) {
+ int t = time % 500;
+ TIMER(&t);
+
+ if(frand() > 0.8)
+ create_projectile2c("crystal", VIEWPORT_W*frand(), rgb(0.2,0.2,0.4), accelerated, 1I, 0.01I + 0.005 - 0.01*frand());
+
+ FROM_TO(100, 400, 100)
+ create_projectile2c("bigball", c->pos, rgb(0.2,0.2,0.9), asymptotic, 2*cexp(I*carg(global.plr.pos-c->pos)), 2.3);
+
+ GO_AT(c, 20, 70, 1+0.6I);
+ GO_AT(c, 120, 170, -1+0.2I);
+ GO_AT(c, 230, 300, -1+0.6I);
+
+ FROM_TO(400, 500, 1)
+ GO_TO(c, VIEWPORT_W/2.0 + 100I, 0.01);
+}
+
+void cirno_iceplosion1(Boss *c, int time) {
+ int t = time % 360;
+ TIMER(&t);
+
+ if(time < 0)
+ GO_TO(c, VIEWPORT_W/2.0 + 100I, 0.02);
+
+ FROM_TO(20,30,2) {
+ int i;
+ for(i = 0; i < 16; 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*(1 - 2*frand()))), _i*0.7);
+ }
+ }
+
+ FROM_TO(40,100,2) {
+ create_projectile2c("crystal", c->pos + 100, rgb(0.3,0.3,0.8), accelerated, 1.5*cexp(2I*M_PI*frand()) - 0.4 + 2I, 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(2I*M_PI*frand()) + 0.4 + 2I, 0.002*cexp(I*(M_PI/10.0*(_i%20))));
+ }
+
+ FROM_TO(150, 300, 30) {
+ float dif = M_PI*2*frand();
+ int i;
+ 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);
+ }
+ }
+}
+
+int cirno_icicles(Projectile *p, int t) {
+ if(t < 0)
+ return 1;
+
+ int turn = 60;
+
+ if(t < turn) {
+ p->pos += p->args[0]*pow(0.9,t);
+ } else if(t == turn) {
+ p->args[0] = 2.5*cexp(I*(carg(p->args[0])-M_PI/2.0+M_PI*(creal(p->args[0]) > 0)));
+ } else if(t > turn) {
+ p->pos += p->args[0];
+ }
+
+ p->angle = carg(p->args[0]);
+
+ return 1;
+}
+
+void cirno_icicle_fall(Boss *c, int time) {
+ int t = time % 400;
+ TIMER(&t);
+
+ FROM_TO(20,200,30) {
+ int i;
+ for(i = 2; i < 5; i++) {
+ 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)));
+ }
+ }
+}
+
+Boss *create_cirno() {
+ Boss* cirno = create_boss("Cirno", "cirno", -150 + 100I);
+ boss_add_attack(cirno, AT_Move, "Introduction", 2, 0, cirno_intro_boss, NULL);
+ boss_add_attack(cirno, AT_Normal, "Iceplosion 0", 20, 240, cirno_iceplosion0, NULL);
+ boss_add_attack(cirno, AT_Spellcard, "Freeze Sign ~ Crystal Rain", 28, 350, cirno_crystal_rain, cirno_pfreeze_bg);
+ boss_add_attack(cirno, AT_Normal, "Iceplosion 1", 20, 240, cirno_iceplosion1, NULL);
+ boss_add_attack(cirno, AT_Spellcard, "Doom Sign ~ Icicle Fall", 35, 350, cirno_icicle_fall, cirno_pfreeze_bg);
start_attack(cirno, cirno->attacks);
return cirno;
@@ -288,12 +419,74 @@ int stage0_multiburst(Enemy *e, int t) {
return 1;
}
+int stage0_instantcircle(Enemy *e, int t) {
+ TIMER(&t);
+ AT(EVENT_DEATH) {
+ spawn_items(e->pos, 2,4,0,0);
+ return 1;
+ }
+
+ FROM_TO(0, 110, 1) {
+ e->pos += e->args[0];
+ }
+
+ int i;
+
+ AT(150) {
+ for(i = 0; i < 20; i++)
+ create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 1.5*cexp(I*M_PI/10.0*i), 2.0);
+ }
+
+ AT(170) {
+ for(i = 0; i < 20; i++)
+ create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 3*cexp(I*M_PI/10.0*i), 3.0);
+ }
+
+ if(t > 200)
+ e->pos += e->args[1];
+
+ return 1;
+}
+
+int stage0_tritoss(Enemy *e, int t) {
+ TIMER(&t);
+ AT(EVENT_DEATH) {
+ spawn_items(e->pos, 5,5,0,0);
+ return 1;
+ }
+
+ FROM_TO(0, 100, 1) {
+ e->pos += e->args[0];
+ }
+
+ FROM_TO(120, 800,5) {
+ float a = M_PI/30.0*((_i/7)%30)+0.1*(1-2*frand());
+
+ create_projectile2c("thickrice", e->pos, rgb(0.2, 0.4, 0.8), asymptotic, 2*cexp(I*a), 3);
+ create_projectile2c("thickrice", e->pos, rgb(0.2, 0.4, 0.8), asymptotic, 2*cexp(I*(a+2*M_PI/3.0)), 3);
+ create_projectile2c("thickrice", e->pos, rgb(0.2, 0.4, 0.8), asymptotic, 2*cexp(I*(a+4*M_PI/3.0)), 3);
+ }
+
+ FROM_TO(480, 800, 300) {
+ int i;
+ for(i = 0; i < 20; i++) {
+ create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 1.5*cexp(I*M_PI/10.0*i), 2.0);
+ create_projectile2c("rice", e->pos, rgb(0.6, 0.2, 0.7), asymptotic, 3*cexp(I*M_PI/10.0*i), 3.0);
+ }
+ }
+
+ if(t > 820)
+ e->pos += e->args[1];
+
+ return 1;
+}
+
void stage0_events() {
if(global.dialog)
return;
TIMER(&global.timer);
- /*
+
// opening. projectile bursts
FROM_TO(100, 160, 25) {
create_enemy1c(VIEWPORT_W/2 + 70, 5, Fairy, stage0_burst, 1 + 0.6I);
@@ -305,8 +498,7 @@ void stage0_events() {
create_enemy1c(70 + _i*40, 6, Fairy, stage0_burst, -1 + 0.6I);
create_enemy1c(VIEWPORT_W - (70 + _i*40), 6, Fairy, stage0_burst, 1 + 0.6I);
}
-
-
+
// big fairies, circle + projectile toss
FROM_TO(400, 460, 50)
create_enemy2c(VIEWPORT_W*_i + VIEWPORT_H/3*I, 20, Fairy, stage0_circletoss, 2-4*_i-0.3I, 1-2*_i);
@@ -336,11 +528,36 @@ void stage0_events() {
for(i = 0; i < 5; i++)
create_enemy1c(VIEWPORT_W/4 + VIEWPORT_H/10*i, 5, Fairy, stage0_multiburst, i - 2.5);
}
- */
- AT(200) {
+
+ AT(2700)
+ global.boss = create_cirno_mid();
+
+ // some chaotic swirls + instant circle combo
+ FROM_TO(2760, 3800, 20)
+ create_enemy2c(VIEWPORT_W/2 - 200*(1-2*frand()), 3, Swirl, stage0_drop, 1I, 0.001I + 0.02+0.06*(1-2*frand()));
+
+ FROM_TO(2900, 3750, 190)
+ create_enemy2c(VIEWPORT_W*frand(), 25, Fairy, stage0_instantcircle, 2I, 3.0 - 6*frand() - 1I);
+
+
+ // multiburst + normal circletoss, later tri-toss
+ FROM_TO(3900, 4800, 200)
+ create_enemy1c(VIEWPORT_W*frand(), 5, Fairy, stage0_multiburst, 2.5*frand());
+
+ FROM_TO(4000, 4100, 20)
+ create_enemy2c(VIEWPORT_W*_i + VIEWPORT_H/3*I, 20, Fairy, stage0_circletoss, 2-4*_i-0.3I, 1-2*_i);
+
+ AT(4200)
+ create_enemy2c(VIEWPORT_W/2.0, 30, Fairy, stage0_tritoss, 2I, -2.6I);
+
+ AT(5000)
global.boss = create_cirno();
-// global.dialog = test_dialog();
+
+ AT(5200) {
+ global.game_over = 1;
+ printf("You won! for now.\n");
}
+
}
void stage0_start() {