taisei/src/projectile.c

425 lines
9.9 KiB
C
Raw Normal View History

/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
*/
#include "projectile.h"
#include <stdlib.h>
#include <math.h>
#include "global.h"
#include "list.h"
2011-12-25 08:18:03 +01:00
#include "vbo.h"
2011-04-26 16:55:18 +02:00
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);
p->type = Particle;
return p;
}
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);
}
Projectile *create_projectile_p(Projectile **dest, Texture *tex, complex pos, Color *clr,
ProjDRule draw, ProjRule rule, complex a1, complex a2, complex a3, complex a4) {
2012-08-17 16:20:05 +02:00
Projectile *p, *e, **d;
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;
p = create_element((void **)d, sizeof(Projectile));
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 = FairyProj;
p->clr = clr;
2012-08-12 21:29:10 +02:00
p->grazed = 0;
p->args[0] = a1;
p->args[1] = a2;
p->args[2] = a3;
p->args[3] = a4;
return p;
}
void _delete_projectile(void **projs, void *proj) {
Projectile *p = proj;
p->rule(p, EVENT_DEATH);
if(p->clr)
free(p->clr);
del_ref(proj);
delete_element(projs, proj);
}
void delete_projectile(Projectile **projs, Projectile *proj) {
_delete_projectile((void **)projs, proj);
}
void delete_projectiles(Projectile **projs) {
delete_all_elements((void **)projs, _delete_projectile);
}
2012-08-14 16:14:53 +02:00
int collision_projectile(Projectile *p) {
if(p->type == FairyProj) {
double angle = carg(global.plr.pos - p->pos) + p->angle;
double projr = sqrt(pow(p->tex->w/4*cos(angle),2)*5/10.0 + pow(p->tex->h/2*sin(angle)*5/10.0,2));
2012-08-12 21:29:10 +02:00
double grazer = max(p->tex->w, p->tex->h);
double dst = cabs(global.plr.pos - p->pos);
2012-08-12 21:29:10 +02:00
grazer = (0.9 * sqrt(grazer) + 0.1 * grazer) * 5;
2012-08-12 21:29:10 +02:00
if(dst < projr + 1)
return 1;
2012-08-12 21:32:29 +02:00
2012-08-13 18:09:32 +02:00
if(!p->grazed && dst < grazer && global.frames - abs(global.plr.recovery) > 0) {
2012-08-12 22:36:51 +02:00
p->grazed = True;
2012-08-14 16:14:53 +02:00
player_graze(&global.plr, p->pos - grazer * 0.3 * cexp(I*carg(p->pos - global.plr.pos)), 10);
2012-08-12 21:29:10 +02:00
}
2011-07-06 14:33:53 +02:00
} else if(p->type >= PlrProj) {
Enemy *e = global.enemies;
while(e != NULL) {
if(e->hp != ENEMY_IMMUNE && cabs(e->pos - p->pos) < 15) {
global.points += 100;
2011-11-05 10:24:58 +01:00
e->hp -= p->type - PlrProj;
return 2;
}
e = e->next;
}
2012-08-12 18:58:58 +02:00
if(global.boss && cabs(global.boss->pos - p->pos) < 42
2011-08-29 16:12:59 +02:00
&& global.boss->current->type != AT_Move && global.boss->current->type != AT_SurvivalSpell && global.boss->current->starttime < global.frames) {
2011-11-05 10:24:58 +01:00
global.boss->dmg += p->type - PlrProj;
return 2;
}
}
return 0;
}
2012-08-14 16:14:53 +02:00
void draw_projectiles(Projectile *projs) {
Projectile *proj;
2012-08-14 16:14:53 +02:00
for(proj = projs; proj; proj = proj->next)
proj->draw(proj, global.frames - proj->birthtime);
2011-12-25 08:18:03 +01:00
}
void process_projectiles(Projectile **projs, char collision) {
Projectile *proj = *projs, *del = NULL;
char killed = 0;
char col = 0;
int action;
while(proj != NULL) {
action = proj->rule(proj, global.frames - proj->birthtime);
2012-07-20 11:45:29 +02:00
if(proj->type == DeadProj && killed < 5) {
killed++;
action = ACTION_DESTROY;
create_particle1c("flare", proj->pos, NULL, Fade, timeout, 30);
create_item(proj->pos, 0, BPoint)->auto_collect = 10;
}
2012-08-14 16:14:53 +02:00
if(collision)
col = collision_projectile(proj);
if(col && proj->type != Particle) {
Color *clr = NULL;
if(proj->clr) {
clr = malloc(sizeof(Color));
memcpy(clr, proj->clr, sizeof(Color));
}
create_projectile_p(&global.particles, proj->tex, proj->pos, clr, DeathShrink, timeout_linear, 10, 5*cexp(proj->angle*I), 0, 0);
}
if(col == 1 && global.frames - abs(global.plr.recovery) >= 0)
2012-07-20 16:11:24 +02:00
player_death(&global.plr);
2011-11-01 21:20:40 +01:00
int e = 0;
if(proj->type == Particle) {
e = 300;
}
if(action == ACTION_DESTROY || col
2011-11-01 21:20:40 +01:00
|| creal(proj->pos) + proj->tex->w/2 + e < 0 || creal(proj->pos) - proj->tex->w/2 - e > VIEWPORT_W
|| cimag(proj->pos) + proj->tex->h/2 + e < 0 || cimag(proj->pos) - proj->tex->h/2 - e > VIEWPORT_H) {
del = proj;
proj = proj->next;
delete_projectile(projs, del);
if(proj == NULL) break;
} else {
proj = proj->next;
}
}
}
int linear(Projectile *p, int t) { // sure is physics in here; a[0]: velocity
if(t < 0)
return 1;
p->angle = carg(p->args[0]);
p->pos = p->pos0 + p->args[0]*t;
return 1;
}
int accelerated(Projectile *p, int t) {
if(t < 0)
return 1;
2012-07-31 14:34:20 +02:00
p->angle = carg(p->args[0]);
p->pos += p->args[0];
p->args[0] += p->args[1];
return 1;
}
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] *= 0.8;
p->pos += p->args[0]*(p->args[1] + 1);
return 1;
}
void _ProjDraw(Projectile *proj, int t) {
if(proj->clr != NULL && !tconfig.intval[NO_SHADER]) {
2012-04-05 16:27:18 +02:00
Shader *shader = get_shader("bullet_color");
glUseProgram(shader->prog);
2012-04-05 16:27:18 +02:00
glUniform4fv(uniloc(shader, "color"), 1, (GLfloat *)proj->clr);
}
2011-12-25 08:18:03 +01:00
if(proj->clr != NULL && tconfig.intval[NO_SHADER])
glColor3f(0,0,0);
draw_texture_p(0,0, proj->tex);
if(proj->clr != NULL && tconfig.intval[NO_SHADER])
glColor3f(1,1,1);
if(!tconfig.intval[NO_SHADER])
glUseProgram(0);
}
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);
2012-04-06 15:54:30 +02:00
2012-04-06 18:01:12 +02:00
if(t < 16 && proj->type < PlrProj && proj->type != Particle) {
2012-04-06 15:54:30 +02:00
float s = 2.0-t/16.0;
if(s != 1)
glScalef(s,s,1);
}
_ProjDraw(proj, t);
2011-07-06 14:33:53 +02:00
glPopMatrix();
}
2012-07-18 23:12:31 +02:00
void ProjDrawAdd(Projectile *proj, int t) {
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
ProjDraw(proj, t);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
2012-07-25 15:32:37 +02:00
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)
glColor4fv((float *)proj->clr);
draw_texture_p(0,0, proj->tex);
glPopMatrix();
if(proj->clr)
glColor3f(1,1,1);
}
2011-11-02 20:00:14 +01:00
void Blast(Projectile *p, int t) {
if(t == 1) {
p->args[1] = frand()*360 + frand()*I;
p->args[2] = frand() + frand()*I;
}
glPushMatrix();
if(p->pos)
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])
glScalef(t/p->args[0], t/p->args[0], 1);
glColor4f(0.3,0.6,1,1 - t/p->args[0]);
draw_texture_p(0,0,p->tex);
glPopMatrix();
glColor4f(1,1,1,1);
}
void Shrink(Projectile *p, int t) {
glPushMatrix();
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);
2012-04-06 18:01:12 +02:00
if(s != 1)
glScalef(s, s, 1);
_ProjDraw(p, t);
glPopMatrix();
}
2012-08-01 17:32:11 +02:00
void ShrinkAdd(Projectile *p, int t) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
Shrink(p, t);
2012-08-01 17:32:11 +02:00
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void DeathShrink(Projectile *p, int t) {
glPushMatrix();
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)
glScalef(s, 1, 1);
_ProjDraw(p, t);
glPopMatrix();
}
2012-07-30 17:57:38 +02:00
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);
float s = t/p->args[0]*(1+p->args[1]);
if(s != 1)
glScalef(s, s, 1);
if(p->clr)
glColor4f(p->clr->r,p->clr->g,p->clr->b,1-t/p->args[0]);
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);
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);
}
2012-08-01 17:32:11 +02:00
void FadeAdd(Projectile *p, int t) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glColor4f(p->clr->r,p->clr->g,p->clr->b, 1.0 - (float)t/p->args[0]);
glPushMatrix();
glTranslatef(creal(p->pos), cimag(p->pos), 0);
glRotatef(180/M_PI*p->angle+90, 0, 0, 1);
draw_texture_p(0,0, p->tex);
glPopMatrix();
glColor4f(1,1,1,1);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
int timeout(Projectile *p, int t) {
if(t >= creal(p->args[0]))
return ACTION_DESTROY;
return 1;
}
int timeout_linear(Projectile *p, int t) {
if(t >= creal(p->args[0]))
return ACTION_DESTROY;
if(t < 0)
return 1;
p->angle = carg(p->args[1]);
p->pos = p->pos0 + p->args[1]*t;
return 1;
2011-08-28 10:57:45 +02:00
}
void Petal(Projectile *p, int t) {
float x = creal(p->args[2]);
float y = cimag(p->args[2]);
float z = creal(p->args[3]);
glDisable(GL_CULL_FACE);
glPushMatrix();
if(p->pos)
glTranslatef(creal(p->pos), cimag(p->pos),0);
2011-08-28 10:57:45 +02:00
glRotatef(t*4.0 + cimag(p->args[3]), x, y, z);
if(p->clr)
glColor4fv((float *)p->clr);
2012-04-04 17:19:53 +02:00
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
2011-08-28 10:57:45 +02:00
draw_texture_p(0,0, p->tex);
2012-04-04 17:19:53 +02:00
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2011-08-28 10:57:45 +02:00
if(p->clr)
glColor4f(1,1,1,1);
glPopMatrix();
glEnable(GL_CULL_FACE);
}
void petal_explosion(int n, complex pos) {
int i;
for(i = 0; i < n; i++) {
2012-08-04 03:25:43 +02:00
tsrand_fill(8);
create_particle4c("petal", pos, rgba(0.6,1-afrand(0)*0.4,0.5,1-0.5*afrand(1)), Petal, asymptotic, (3+5*afrand(2))*cexp(I*M_PI*2*afrand(3)), 5, afrand(4) + afrand(5)*I, afrand(6) + 360.0I*afrand(7));
2011-08-28 10:57:45 +02:00
}
2012-07-18 12:33:37 +02:00
}