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 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + Enemy + Enemy + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + 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() {