added Freeze Sign ~ Perfect Freeze
implementation of test spellcard almost as seen in Touhou 6.
This commit is contained in:
parent
d9fdc2aa0e
commit
eae73f77ad
12 changed files with 141 additions and 48 deletions
BIN
gfx/cirnobg.png
Normal file
BIN
gfx/cirnobg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 300 KiB |
BIN
gfx/snowlayer.png
Normal file
BIN
gfx/snowlayer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 716 KiB |
|
@ -9,7 +9,8 @@ void main(void) {
|
|||
uniform sampler2D tex;
|
||||
uniform vec2 blur_orig; // center
|
||||
uniform vec2 fix_orig;
|
||||
uniform float rad; // radius of zoom effect
|
||||
uniform float blur_rad; // radius of zoom effect
|
||||
uniform float rad;
|
||||
uniform float ratio; // texture w/h
|
||||
|
||||
void main(void) {
|
||||
|
@ -19,8 +20,8 @@ void main(void) {
|
|||
vec2 pos1 = pos;
|
||||
pos1.y *= 2.0;
|
||||
|
||||
if(length(pos1) < rad)
|
||||
pos *= length(pos1)/rad;
|
||||
if(length(pos1) < blur_rad)
|
||||
pos *= length(pos1)/blur_rad;
|
||||
|
||||
gl_FragColor = texture2D(tex, pos + blur_orig);
|
||||
|
||||
|
|
50
src/boss.c
50
src/boss.c
|
@ -43,7 +43,6 @@ void spell_opening(Boss *b, int time) {
|
|||
draw_text(b->current->name, VIEWPORT_W-strlen(b->current->name)*5, y, _fonts.biolinum);
|
||||
}
|
||||
|
||||
|
||||
void draw_boss(Boss *boss) {
|
||||
draw_animation_p(creal(boss->pos), cimag(boss->pos), boss->anirow, boss->ani);
|
||||
|
||||
|
@ -52,7 +51,7 @@ void draw_boss(Boss *boss) {
|
|||
|
||||
draw_text(boss->name, 10 + strlen(boss->name)*5, 20, _fonts.biolinum);
|
||||
|
||||
if(boss->current) {
|
||||
if(boss->current) {
|
||||
char buf[16];
|
||||
snprintf(buf, 16, "%.2f", (boss->current->timeout - global.frames + boss->current->starttime)/(float)FPS);
|
||||
draw_text(buf, VIEWPORT_W - 20, 10, _fonts.biolinum);
|
||||
|
@ -89,35 +88,31 @@ void draw_boss(Boss *boss) {
|
|||
}
|
||||
|
||||
void process_boss(Boss *boss) {
|
||||
if(boss->current) {
|
||||
if(boss->current && boss->current->waypoints) {
|
||||
int time = global.frames - boss->current->starttime;
|
||||
|
||||
if(boss->current->waypoints) {
|
||||
struct Waypoint *wps = boss->current->waypoints;
|
||||
int *i = &boss->current->wp;
|
||||
|
||||
int wtime = time % (wps[boss->current->wpcount-1].time + 1);
|
||||
struct Waypoint *wps = boss->current->waypoints;
|
||||
int *i = &boss->current->wp;
|
||||
|
||||
if(time < 0) {
|
||||
boss->pos = boss->pos0 + (wps[0].pos - boss->pos0)/ATTACK_START_DELAY * (ATTACK_START_DELAY + time);
|
||||
} else {
|
||||
int wtime = time % wps[boss->current->wpcount-1].time + 1;
|
||||
|
||||
int next = *i + 1;
|
||||
if(next >= boss->current->wpcount)
|
||||
next = 0;
|
||||
|
||||
boss->pos = boss->pos0 + (wps[*i].pos - boss->pos0)/(wps[*i].time - boss->time0) * (wtime - boss->time0);
|
||||
boss->pos = wps[*i].pos + (wps[next].pos - wps[*i].pos)/(wps[*i].time - boss->time0) * (wtime - boss->time0);
|
||||
|
||||
if(wtime >= wps[*i].time) {
|
||||
boss->pos0 = wps[*i].pos;
|
||||
boss->time0 = wps[*i].time;
|
||||
if(*i == boss->current->wpcount-1)
|
||||
boss->time0 = 0;
|
||||
boss->pos0 = wps[next].pos;
|
||||
boss->time0 = wps[*i].time % wps[boss->current->wpcount-1].time;
|
||||
*i = next;
|
||||
}
|
||||
}
|
||||
|
||||
if(time == 0)
|
||||
boss->current->rule(boss, EVENT_BIRTH);
|
||||
else
|
||||
boss->current->rule(boss, time);
|
||||
|
||||
|
||||
boss->current->rule(boss, time % wps[boss->current->wpcount-1].time);
|
||||
}
|
||||
|
||||
if(time > boss->current->timeout)
|
||||
boss->dmg = boss->current->dmglimit + 1;
|
||||
|
@ -133,6 +128,13 @@ void process_boss(Boss *boss) {
|
|||
}
|
||||
}
|
||||
|
||||
void boss_death(Boss **boss) {
|
||||
free_boss(*boss);
|
||||
*boss = NULL;
|
||||
delete_projectiles(&global.projs);
|
||||
delete_lasers(&global.lasers);
|
||||
}
|
||||
|
||||
void free_boss(Boss *boss) {
|
||||
free(boss->name);
|
||||
int i;
|
||||
|
@ -147,13 +149,14 @@ void free_attack(Attack *a) {
|
|||
free(a->waypoints);
|
||||
}
|
||||
|
||||
void start_attack(Boss *b, Attack *a) {
|
||||
a->starttime = global.frames;
|
||||
void start_attack(Boss *b, Attack *a) {
|
||||
a->starttime = global.frames + ATTACK_START_DELAY;
|
||||
a->rule(b, EVENT_BIRTH);
|
||||
if(a->type == Spellcard || a->type == SurvivalSpell)
|
||||
play_sound("charge_generic");
|
||||
}
|
||||
|
||||
Attack *boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule) {
|
||||
Attack *boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule) {
|
||||
boss->attacks = realloc(boss->attacks, sizeof(Attack)*(++boss->acount));
|
||||
Attack *a = &boss->attacks[boss->acount-1];
|
||||
|
||||
|
@ -171,6 +174,7 @@ Attack *boss_add_attack(Boss *boss, AttackType type, char *name, float timeout,
|
|||
|
||||
a->dmglimit = dmg + hp;
|
||||
a->rule = rule;
|
||||
a->draw_rule = draw_rule;
|
||||
|
||||
a->starttime = global.frames;
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ typedef struct Attack {
|
|||
int wp;
|
||||
|
||||
BossRule rule;
|
||||
BossRule draw_rule;
|
||||
} Attack;
|
||||
|
||||
typedef struct Boss {
|
||||
|
@ -68,7 +69,9 @@ void free_attack(Attack *a);
|
|||
|
||||
void start_attack(Boss *b, Attack *a);
|
||||
|
||||
Attack *boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule);
|
||||
Attack *boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule);
|
||||
void boss_add_waypoint(Attack *attack, complex pos, int time);
|
||||
|
||||
void boss_death(Boss **boss);
|
||||
|
||||
#endif
|
|
@ -29,6 +29,7 @@ enum {
|
|||
VIEWPORT_H = 560,
|
||||
|
||||
POINT_OF_COLLECT = VIEWPORT_H/4,
|
||||
ATTACK_START_DELAY = 40,
|
||||
|
||||
SNDSRC_COUNT = 30,
|
||||
|
||||
|
@ -48,6 +49,7 @@ typedef struct {
|
|||
Laser *lasers;
|
||||
|
||||
int frames;
|
||||
int lasttime;
|
||||
int timer;
|
||||
|
||||
Texture *textures;
|
||||
|
@ -72,9 +74,8 @@ typedef struct {
|
|||
int points;
|
||||
|
||||
int fpstime; // frame counter
|
||||
int fps;
|
||||
|
||||
int lasttime;
|
||||
int fps;
|
||||
int show_fps;
|
||||
} Global;
|
||||
|
||||
extern Global global;
|
||||
|
|
|
@ -42,6 +42,7 @@ Projectile *create_projectile_d(Projectile **dest, char *name, complex pos, Colo
|
|||
p->tex = get_tex(buf);
|
||||
p->type = FairyProj;
|
||||
p->clr = clr;
|
||||
p->parent = NULL;
|
||||
|
||||
va_list ap;
|
||||
int i;
|
||||
|
|
|
@ -33,6 +33,7 @@ typedef struct Projectile {
|
|||
complex pos0;
|
||||
|
||||
float angle;
|
||||
void *parent;
|
||||
|
||||
ProjRule rule;
|
||||
Texture *tex;
|
||||
|
|
22
src/stage.c
22
src/stage.c
|
@ -106,6 +106,9 @@ void draw_hud() {
|
|||
draw_text(buf, 13, 49, _fonts.biolinum);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
sprintf(buf, "%i fps", global.show_fps);
|
||||
draw_text(buf, SCREEN_W-5*strlen(buf), SCREEN_H-20, _fonts.biolinum);
|
||||
}
|
||||
|
||||
void stage_draw() {
|
||||
|
@ -115,6 +118,7 @@ void stage_draw() {
|
|||
glMatrixMode(GL_MODELVIEW);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(VIEWPORT_X,VIEWPORT_Y,0);
|
||||
apply_bg_shaders();
|
||||
|
@ -137,6 +141,15 @@ void stage_draw() {
|
|||
}
|
||||
|
||||
void apply_bg_shaders() {
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, global.rtt.fbo);
|
||||
if(global.boss && global.boss->current && global.boss->current->draw_rule) {
|
||||
glPushMatrix();
|
||||
glTranslatef(-VIEWPORT_X,0,0); // Some transformation for concenience. Don't ask why. it's because of rtt.
|
||||
glScalef((VIEWPORT_W+VIEWPORT_X)/(float)VIEWPORT_W, (VIEWPORT_H+VIEWPORT_Y)/(float)VIEWPORT_H, 1);
|
||||
global.boss->current->draw_rule(global.boss, global.frames - global.boss->current->starttime);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
if(global.boss) { // Boss background shader
|
||||
|
@ -150,6 +163,7 @@ void apply_bg_shaders() {
|
|||
(creal(pos)+VIEWPORT_X)/global.rtt.nw, (VIEWPORT_H - cimag(pos) - VIEWPORT_Y/2)/global.rtt.nh);
|
||||
glUniform2f(glGetUniformLocation(shader, "fix_orig"),
|
||||
(creal(fpos)+VIEWPORT_X)/global.rtt.nw, (VIEWPORT_H - cimag(fpos) - VIEWPORT_Y/2)/global.rtt.nh);
|
||||
glUniform1f(glGetUniformLocation(shader, "blur_rad"), 0.2+0.05*sin(global.frames/10.0));
|
||||
glUniform1f(glGetUniformLocation(shader, "rad"), 0.3);
|
||||
glUniform1f(glGetUniformLocation(shader, "ratio"), (float)global.rtt.nh/global.rtt.nw);
|
||||
}
|
||||
|
@ -181,10 +195,8 @@ void stage_logic() {
|
|||
|
||||
if(global.boss) {
|
||||
process_boss(global.boss);
|
||||
if(global.boss->dmg > global.boss->attacks[global.boss->acount-1].dmglimit) {
|
||||
free_boss(global.boss);
|
||||
global.boss = NULL;
|
||||
}
|
||||
if(global.boss->dmg > global.boss->attacks[global.boss->acount-1].dmglimit)
|
||||
boss_death(&global.boss);
|
||||
}
|
||||
|
||||
global.frames++;
|
||||
|
@ -193,7 +205,7 @@ void stage_logic() {
|
|||
global.timer++;
|
||||
|
||||
if(SDL_GetTicks() > global.fpstime+1000) {
|
||||
fprintf(stderr, "FPS: %d\n", global.fps);
|
||||
global.show_fps = global.fps;
|
||||
global.fps = 0;
|
||||
global.fpstime = SDL_GetTicks();
|
||||
} else {
|
||||
|
|
|
@ -115,12 +115,12 @@ void stage0_draw() {
|
|||
void cirno_intro(Boss *c, int time) {
|
||||
if(time == EVENT_BIRTH) {
|
||||
boss_add_waypoint(c->current, VIEWPORT_W/2-100 + 30I, 100);
|
||||
boss_add_waypoint(c->current, VIEWPORT_W/2+100 + 30I, 400);
|
||||
boss_add_waypoint(c->current, VIEWPORT_W/2+100 + 30I, 200);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(time % 50))
|
||||
create_laser(LaserLine, c->pos, 10*cexp(I*carg(global.plr.pos - c->pos)+I*0.1), 30, 200, rgb(1,0,0), NULL, 0);
|
||||
// if(!(time % 50))
|
||||
// create_laser(LaserLine, c->pos, 10*cexp(I*carg(global.plr.pos - c->pos)+I*0.1), 30, 200, rgb(1,0,0), NULL, 0);
|
||||
}
|
||||
|
||||
complex lolsin(Laser *l, float t) {
|
||||
|
@ -130,24 +130,62 @@ complex lolsin(Laser *l, float t) {
|
|||
return pos;
|
||||
}
|
||||
|
||||
void cirno_test(Boss *c, int time) {
|
||||
void cirno_pfreeze_frogs(Projectile *p, int t) {
|
||||
int boss_t = (global.frames - *((int *)p->parent)) % 320;
|
||||
|
||||
if(boss_t < 110)
|
||||
linear(p, t);
|
||||
else if(boss_t == 110) {
|
||||
free(p->clr);
|
||||
p->clr = rgb(0.7,0.7,0.7);
|
||||
}
|
||||
|
||||
if(t == 240) {
|
||||
p->pos0 = p->pos;
|
||||
p->args[0] = 2*cexp(I*rand());
|
||||
}
|
||||
|
||||
if(t > 240)
|
||||
linear(p, t-240);
|
||||
|
||||
}
|
||||
|
||||
void cirno_perfect_freeze(Boss *c, int time) {
|
||||
if(time == EVENT_BIRTH) {
|
||||
boss_add_waypoint(c->current, 220 + 100I, 50);
|
||||
boss_add_waypoint(c->current, 12 + 100I, 60);
|
||||
boss_add_waypoint(c->current, 200 + 90I, 100);
|
||||
boss_add_waypoint(c->current, VIEWPORT_W/2 + 100I, 110);
|
||||
boss_add_waypoint(c->current, VIEWPORT_W/2 + 100I, 160);
|
||||
boss_add_waypoint(c->current, VIEWPORT_W/2+90 + 130I, 190);
|
||||
boss_add_waypoint(c->current, VIEWPORT_W/2-90 + 130I, 320);
|
||||
return;
|
||||
}
|
||||
int i;
|
||||
if(!(time % 50))
|
||||
for(i = 0; i < 6; i++)
|
||||
create_laser(LaserCurve, c->pos, c->pos, 50, 200, rgba(0.5,0.5,1,0.4), lolsin, i);
|
||||
|
||||
if(time > 10 && time < 80)
|
||||
create_projectile("ball", c->pos, rgb(rand()/(float)RAND_MAX, rand()/(float)RAND_MAX, rand()/(float)RAND_MAX), cirno_pfreeze_frogs, 4*cexp(I*rand()))->parent=&c->current->starttime;
|
||||
if(time > 160 && time < 220 && !(time % 7)) {
|
||||
create_projectile("rice", c->pos + 60, rgb(0.3, 0.4, 0.9), linear, 5*cexp(I*carg(global.plr.pos - c->pos)));
|
||||
create_projectile("rice", c->pos - 60, rgb(0.3, 0.4, 0.9), linear, 5*cexp(I*carg(global.plr.pos - c->pos)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cirno_pfreeze_bg(Boss *c, int time) {
|
||||
glColor4f(1,1,1,1);
|
||||
fill_screen(time/700.0, time/700.0, 2, "cirnobg");
|
||||
glColor4f(1,1,1,0.5);
|
||||
fill_screen(time/700.0, time/700.0+0.5, 2, "cirnobg");
|
||||
fill_screen(0, -time/100.0, 0, "snowlayer");
|
||||
|
||||
// draw_texture(VIEWPORT_W/2,VIEWPORT_H/2, "snowlayer");
|
||||
glColor4f(1,1,1,1);
|
||||
}
|
||||
|
||||
|
||||
Boss *create_cirno() {
|
||||
Boss* cirno = create_boss("Cirno", "cirno", VIEWPORT_W/2 + 30I);
|
||||
boss_add_attack(cirno, Normal, "Introduction", 10, 100, cirno_intro);
|
||||
boss_add_attack(cirno, Spellcard, "Test Sign ~ Strongest Implementation", 10, 100, cirno_test);
|
||||
boss_add_attack(cirno, Normal, "Introduction", 10, 100, cirno_intro, NULL);
|
||||
boss_add_attack(cirno, Spellcard, "Freeze Sign ~ Perfect Freeze", 20, 300, cirno_perfect_freeze, cirno_pfreeze_bg);
|
||||
|
||||
start_attack(cirno, cirno->attacks);
|
||||
return cirno;
|
||||
}
|
||||
|
||||
|
|
|
@ -246,4 +246,35 @@ void draw_texture_p(int x, int y, Texture *tex) {
|
|||
|
||||
glPopMatrix();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
void fill_screen(float xoff, float yoff, float ratio, char *name) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
Texture *tex = get_tex(name);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->gltex);
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glTranslatef(xoff,yoff, 0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
float rw = ratio;
|
||||
float rh = ratio;
|
||||
|
||||
if(ratio == 0) {
|
||||
rw = ((float)tex->w)/tex->truew;
|
||||
rh = ((float)tex->h)/tex->trueh;
|
||||
}
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0,0); glVertex3f(0,0,0);
|
||||
glTexCoord2f(0,rh); glVertex3f(0,VIEWPORT_H,0);
|
||||
glTexCoord2f(rw,rh); glVertex3f(VIEWPORT_W,VIEWPORT_H,0);
|
||||
glTexCoord2f(rw,0); glVertex3f(VIEWPORT_W,0,0);
|
||||
glEnd();
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
|
@ -41,4 +41,5 @@ void free_texture(Texture *tex);
|
|||
void draw_texture(int x, int y, char *name);
|
||||
void draw_texture_p(int x, int y, Texture *tex);
|
||||
|
||||
void fill_screen(float xoff, float yoff, float ratio, char *name);
|
||||
#endif
|
Loading…
Reference in a new issue