aboutsummaryrefslogtreecommitdiff
path: root/gst
diff options
context:
space:
mode:
Diffstat (limited to 'gst')
-rw-r--r--gst/fxs.c98
-rw-r--r--gst/fxs.h32
-rw-r--r--gst/gst.c111
-rw-r--r--gst/gst.h2
-rw-r--r--gst/units.c40
5 files changed, 226 insertions, 57 deletions
diff --git a/gst/fxs.c b/gst/fxs.c
index 25ddf18..9e3aef4 100644
--- a/gst/fxs.c
+++ b/gst/fxs.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
+#include <math.h>
#include "../umath/vec.h"
@@ -7,31 +8,105 @@
#include "units.h"
void fx_init (fxs *fx) {
- fx->bullets = (bullet*)malloc(sizeof(bullet)*1024);
+ fx->bullets = (bullet*)malloc(sizeof(bullet)*FXS_BULLET_MAX);
fx->bulletslen = 0;
+ fx->explosions = (explosion*)malloc(sizeof(explosion)*FXS_EXPLOSION_MAX);
+ fx->explosionslen = 0;
}
void fx_add_bullet (fxs *fx, bullet *b) {
- if (fx->bulletslen >= 1024-1) return;
+ if (fx->bulletslen >= FXS_BULLET_MAX-1) return;
fx->bullets[fx->bulletslen] = *b;
fx->bulletslen++;
}
+void fx_spread_to_head (float spread, float head[]) {
+ head[0] = 1-spread; if (spread<0.5) head[0] = spread;
+ head[1] = 1-spread*2;
+ vec2_norm(head);
+}
+
+/*
+ * param: pos is the center of the explosion
+ * param: vel is the heading of the explosion
+ * param: force is added to vel and scaled by mass
+ * param: spread [0, 1] is half the angle of the explosion
+ * param: speed [0, inf] is the initial speed
+ */
+void fx_explosion_init (fxs *fx, explosion *e,
+ float pos[], float vel[], float color[], float force[],
+ float spread, float speed, int n, float time, float lifetime)
+{
+ float normvel[2] = { vel[0], vel[1] }; vec2_norm(normvel);
+ float perpvel[2] = { normvel[1], -normvel[0] };
+ e->pos[0] = pos[0]; e->pos[1] = pos[1];
+ e->partslen = n;
+ e->force[0] = force[0]; e->force[1] = force[1];
+ e->starttime = time;
+ e->friction = 0.95;
+ for (int j=0; j<n; j++) {
+ particle *p = e->parts+j;
+ float sample = rand()%1000/1000.0 * spread;
+ float head[2]; fx_spread_to_head(sample, head);
+ if (j%2 == 0) head[0] *= -1;
+ float dir[2] = {
+ -head[0]*normvel[1] - head[1]*perpvel[1],
+ head[0]*normvel[0] + head[1]*perpvel[0]
+ };
+ p->lifetime = lifetime;
+ p->mass = 1;
+ p->pos[0] = pos[0]; p->pos[1] = pos[1];
+ p->vel[0] = dir[0]; p->vel[1] = dir[1];
+ vec2_mul(p->vel, p->vel, speed+(rand()%1000)/1000.0*speed/2);
+ p->color[0] = color[0];
+ p->color[1] = color[1];
+ p->color[2] = color[2];
+ }
+}
+
+void fx_add_explosion (fxs *fx, explosion *e) {
+ if (fx->explosionslen >= FXS_EXPLOSION_MAX-1) return;
+ fx->explosions[fx->explosionslen] = *e;
+ fx->explosionslen++;
+}
+
void fx_process (fxs *fx, float time) {
for (int i=0; i<fx->bulletslen; i++) {
bullet *b = fx->bullets+i;
+ if (b->starttime > time) continue;
if (time > b->endtime) {
// remove by replacing with last, dont care for order
*b = fx->bullets[fx->bulletslen-1];
fx->bulletslen--;
}
}
+
+ for (int i=0; i<fx->explosionslen; i++) {
+ explosion *e = fx->explosions+i;
+ if (e->starttime > time) continue;
+ int sum = e->partslen;
+ for (int j=0; j<e->partslen; j++) {
+ if (e->starttime + e->parts[j].lifetime >= time) {
+ vec2_add(e->parts[j].pos, e->parts[j].pos, e->parts[j].vel);
+ float forcemass[2];
+ vec2_mul(forcemass, e->force, e->parts[j].mass);
+ vec2_add(e->parts[j].vel, e->parts[j].vel, forcemass);
+ vec2_mul(e->parts[j].vel, e->parts[j].vel, e->friction);
+ } else { sum -= 1; }
+ }
+ if (sum == 0) {
+ // remove by replacing with last, dont care for order
+ *e = fx->explosions[fx->explosionslen-1];
+ fx->explosionslen--;
+ }
+ }
}
void fx_render (SDL_Renderer *rend, fxs *fx, float cam[], float time) {
for (int i=0; i<fx->bulletslen; i++) {
bullet *b = fx->bullets+i;
+ if (b->starttime > time) continue;
float travel_time = b->endtime - b->starttime;
float interval_time = time - b->starttime;
float amt = interval_time / travel_time;
@@ -46,10 +121,7 @@ void fx_render (SDL_Renderer *rend, fxs *fx, float cam[], float time) {
if (dist < 10) { mag = dist; }
vec2_norm(head); vec2_mul(head, head, mag);
SDL_SetRenderDrawColor(rend,
- b->color[0],
- b->color[1],
- b->color[2],
- 255);
+ b->color[0], b->color[1], b->color[2], 255);
SDL_RenderDrawLine(rend,
-cam[0] + pos[0],
-cam[1] + pos[1],
@@ -57,4 +129,18 @@ void fx_render (SDL_Renderer *rend, fxs *fx, float cam[], float time) {
-cam[1] + pos[1] + head[1]
);
}
+
+ for (int i=0; i<fx->explosionslen; i++) {
+ explosion *e = fx->explosions+i;
+ if (e->starttime > time) continue;
+ for (int j=0; j<e->partslen; j++) {
+ particle *p = e->parts+j;
+ if (e->starttime + p->lifetime >= time) {
+ SDL_SetRenderDrawColor(rend,
+ p->color[0], p->color[1], p->color[2], 255);
+ SDL_RenderDrawPoint(rend,
+ -cam[0] + p->pos[0], -cam[1] + p->pos[1]);
+ }
+ }
+ }
}
diff --git a/gst/fxs.h b/gst/fxs.h
index 2be62af..5aeb138 100644
--- a/gst/fxs.h
+++ b/gst/fxs.h
@@ -3,22 +3,52 @@
#include <SDL2/SDL.h>
+#define FXS_BULLET_MAX 4096
+#define FXS_EXPLOSION_MAX 2048
+
typedef struct {
float from[2];
float to[2];
float starttime;
float endtime;
float size;
- int color[3];
+ float color[3];
} bullet;
typedef struct {
+ float pos[2];
+ float vel[2];
+ float color[3];
+ float size;
+ float mass;
+ float lifetime;
+} particle;
+
+typedef struct {
+ float pos[2];
+ float force[2];
+ float friction;
+ particle parts[32];
+ int partslen;
+ float starttime;
+} explosion;
+
+typedef struct {
bullet *bullets;
int bulletslen;
+ explosion *explosions;
+ int explosionslen;
} fxs;
void fx_init (fxs *fx);
+
void fx_add_bullet (fxs *fx, bullet *b);
+
+void fx_explosion_init (fxs *fx, explosion *e,
+ float pos[], float vel[], float color[], float force[],
+ float spread, float speed, int n, float time, float lifetime);
+void fx_add_explosion (fxs *fx, explosion *e);
+
void fx_process (fxs *fx, float time);
void fx_render (SDL_Renderer *rend, fxs *fx, float cam[], float time);
diff --git a/gst/gst.c b/gst/gst.c
index 3b2576f..9e89f46 100644
--- a/gst/gst.c
+++ b/gst/gst.c
@@ -4,6 +4,7 @@
#include <float.h>
#include "gst.h"
+#include "../umath/vec.h"
void gst_init (gamestate *gst) {
map_init(&gst->map_editor, MAXMAP, MAXMAP, 32);
@@ -33,11 +34,9 @@ void gst_get_maparmy(gamestate *gst, map **m, army **ar) {
}
}
-void gst_lastpos (gamestate *gst) {
- for (int i=0; i<gst->ar.uslen; i++) {
- gst->ar_lastpos[i][0] = gst->ar.us[i].pos[0];
- gst->ar_lastpos[i][1] = gst->ar.us[i].pos[1];
- }
+void gst_ar_past_cycle (gamestate *gst) {
+ gst->ar_past[1] = gst->ar_past[0];
+ gst->ar_past[0] = gst->ar;
}
void gst_compute_stats (gamestate *gst, infos *info) {
@@ -48,7 +47,6 @@ void gst_compute_stats (gamestate *gst, infos *info) {
void gst_tobattle (gamestate *gst, infos *info) {
if (gst->playernum == 1) {
- //info_load_army(gst->army_bp+1, "army");
gst->army_bp[1] = gst->army_bp[0];
gst->playernum = 2;
}
@@ -79,7 +77,7 @@ void gst_tobattle (gamestate *gst, infos *info) {
}
gst_compute_stats(gst, info);
- gst_lastpos(gst);
+ gst_ar_past_cycle(gst);
gst->starttime = FLT_MAX;
gst->turn = 0;
gst->coveredtime = 0;
@@ -117,21 +115,62 @@ void gst_spawn_bullets (gamestate *gst, fxs *fx, a_dmg dmgs[], int dmgslen,
unit *u = ar->us+i;
if (dmgs[j].u == u) {
unit *t = dmgs[j].t;
- b.from[0] = u->pos[0]+16;
- b.from[1] = u->pos[1]+16;
- b.to[0] = t->pos[0]+16;
- b.to[1] = t->pos[1]+16;
float n = (float)curr[i]/counts[i];
- float travel_time = 0.1;
+
+ float u_past_x = gst->ar_past[1].us[i].pos[0];
+ float u_past_y = gst->ar_past[1].us[i].pos[1];
+ float u_pres_x = gst->ar_past[0].us[i].pos[0];
+ float u_pres_y = gst->ar_past[0].us[i].pos[1];
+
+ int t_i = 0;
+ for (int k=0; k<ar->uslen; k++) {
+ if (ar->us+k == t) { t_i = k; break; }
+ }
+
+ float t_past_x = gst->ar_past[1].us[t_i].pos[0];
+ float t_past_y = gst->ar_past[1].us[t_i].pos[1];
+ float t_pres_x = gst->ar_past[0].us[t_i].pos[0];
+ float t_pres_y = gst->ar_past[0].us[t_i].pos[1];
+
+ // interpolate from the past
+ b.from[0] = u_pres_x*(n) + u_past_x*(1-n)+16 +rand()%8-4;
+ b.from[1] = u_pres_y*(n) + u_past_y*(1-n)+16 +rand()%8-4;
+ b.to[0] = t_pres_x*(n) + t_past_x*(1-n)+16 +rand()%16-8;
+ b.to[1] = t_pres_y*(n) + t_past_y*(1-n)+16 +rand()%16-8;
+
+ float travel_time = 0.3;
float shot_time = time + n*gst->turnspeed;
b.starttime = shot_time;
b.endtime = shot_time + travel_time;
- if (u->owner == 0) {
- b.color[0] = 0; b.color[1] = 255; b.color[2] = 0;
- } else {
- b.color[0] = 255; b.color[1] = 0; b.color[2] = 0;
- }
+
+ float colors[2][3] = { {0,255,0}, {255,0,0} };
+ int selcol = 0;
+
+ if (u->owner == 0) { selcol = 0; }
+ else { selcol = 1; }
+ b.color[0] = colors[selcol][0];
+ b.color[1] = colors[selcol][1];
+ b.color[2] = colors[selcol][2];
fx_add_bullet(fx, &b);
+
+
+ { /* shooting particles */
+ float vel[2]; vec2_sub(vel, b.to, b.from);
+ float force[2] = { 0, 0 };
+ explosion e;
+ fx_explosion_init(fx, &e, b.from, vel, colors[selcol],
+ force, 0.1, 2, 4, b.starttime, 0.2);
+ fx_add_explosion(fx, &e);
+ }
+
+ { /* hit particles */
+ float vel[2]; vec2_sub(vel, b.to, b.from);
+ float force[2] = { 0, 0 };
+ explosion e;
+ fx_explosion_init(fx, &e, b.to, vel, colors[1-selcol],
+ force, 0.15, 4, 8, b.endtime, 0.8);
+ fx_add_explosion(fx, &e);
+ }
curr[i] ++;
}
}
@@ -154,7 +193,6 @@ int gst_check_victory (gamestate *gst) {
}
void gst_next_turn (gamestate *gst, infos *info, fxs *fx, float t) {
- gst_lastpos(gst);
gst->coveredtime += gst->turnspeed;
gst->turn ++;
map *m; army *ar;
@@ -170,6 +208,7 @@ void gst_next_turn (gamestate *gst, infos *info, fxs *fx, float t) {
if (gst->turn_until_finish <= 0) {
gst->over = 1;
}
+ gst_ar_past_cycle(gst);
gst_spawn_bullets(gst, fx, dmgs, fire, t);
}
@@ -214,24 +253,34 @@ void gst_render (SDL_Renderer *rend, SDL_Texture *txsprites, txtd *textd,
amt = (amt / gst->turnspeed) + 1;
if (amt > 1) amt = 1; if (amt < 0) amt = 0; // clamping away fuzzyness
+ army *past = ar;
+ army *present = ar;
+ if (gst->state == 1) {
+ past = gst->ar_past +1;
+ present = gst->ar_past +0;
+ }
+
// render units
for (int i=0; i<ar->uslen; i++) {
- if (ar->us[i].hp <= 0) continue;
- float present_x = ar->us[i].pos[0];
- float present_y = ar->us[i].pos[1];
+ if (present->us[i].hp <= 0) continue;
+
+ float past_x = past->us[i].pos[0];
+ float past_y = past->us[i].pos[1];
+
+ float present_x = present->us[i].pos[0];
+ float present_y = present->us[i].pos[1];
- float x = present_x, y = present_y;
- if (gst->state == 1) {
- x = present_x*(amt) + gst->ar_lastpos[i][0]*(1-amt);
- y = present_y*(amt) + gst->ar_lastpos[i][1]*(1-amt);
- }
+ float x = present_x*(amt) + past_x*(1-amt);
+ float y = present_y*(amt) + past_y*(1-amt);
- SDL_Rect srcRect = { ar->us[i].info.chassis*ts, ts, ts, ts };
+ SDL_Rect srcRect = {
+ present->us[i].info.chassis*ts, ts, ts, ts };
SDL_Rect dstRect = { (int)x-posx, (int)y-posy, ts, ts };
SDL_RenderCopy(rend, txsprites, &srcRect, &dstRect);
- stats_unit base; stats_unit_compute(info, &ar->us[i].info, &base);
- float amt = ar->us[i].hp / base.frame.hp;
+ stats_unit base;
+ stats_unit_compute(info, &present->us[i].info, &base);
+ float amt = present->us[i].hp / base.frame.hp;
SDL_Rect hprect = {
(int)x-posx, (int)y-posy+ts-5,
ts*amt, 6 };
@@ -240,12 +289,12 @@ void gst_render (SDL_Renderer *rend, SDL_Texture *txsprites, txtd *textd,
SDL_RenderFillRect(rend, &hprect);
SDL_SetTextureColorMod(textd->tex_small, sw*100, 100*(1-sw), 0);
- char shp[32]; sprintf(shp, "%.0f", ar->us[i].hp);
+ char shp[32]; sprintf(shp, "%.0f", present->us[i].hp);
float php[2] = { (int)x-posx, (int)y-posy+ts-5 };
render_text_small(rend, shp, php, textd);
SDL_SetTextureColorMod(textd->tex_small, 255, 160, 0);
- char sch[32]; sprintf(sch, "%.0f", ar->us[i].charge);
+ char sch[32]; sprintf(sch, "%.0f", present->us[i].charge);
float pch[2] = { (int)x-posx, (int)y-posy+ts+1 };
render_text_small(rend, sch, pch, textd);
SDL_SetTextureColorMod(textd->tex_small, 0, 0, 0);
diff --git a/gst/gst.h b/gst/gst.h
index 992d31d..d063563 100644
--- a/gst/gst.h
+++ b/gst/gst.h
@@ -20,7 +20,7 @@ typedef struct {
int playernum;
map map_battle;
army ar;
- float ar_lastpos[MAXUNITS][2];
+ army ar_past[2];
stats_unit ustats[MAXUNITS];
int state;
diff --git a/gst/units.c b/gst/units.c
index aeced1b..8b84d52 100644
--- a/gst/units.c
+++ b/gst/units.c
@@ -181,6 +181,7 @@ int army_move_step (infos *info, army *ar, map *m, stats_unit *ustats) {
int army_move (infos *info, army *ar, map *m, stats_unit *ustats) {
for (int i=0; i<ar->uslen; i++) {
ar->us[i].move_points += ustats[i].frame.speed;
+ if (ar->us[i].move_points > 1) ar->us[i].move_points = 1;
}
int iter = 0, finished = army_move_step(info, ar, m, ustats);
for (; iter<5 && !finished; iter++) {
@@ -197,6 +198,7 @@ int army_fire (infos *info, army *ar, map *m, a_dmg dmgs[],
int lw = u->info.levels[LEVEL_CHASSIS];
for (int j=0; j<ustats[i].weaponlen; j++) {
u->cooldown[j] += 1;
+ if (u->cooldown[j] > 1) u->cooldown[j] = 1;
}
}
int dmgslen = 0;
@@ -209,24 +211,26 @@ int army_fire (infos *info, army *ar, map *m, a_dmg dmgs[],
for (int j=0; j<ustats[i].weaponlen; j++) {
if (u->cooldown[j] <= 0) continue;
float range = ustats[i].weapon[j].range;
- unit_search(info, ar, m, u, t, range);
- if (t[0]!=NULL) {
- dmgs[dmgslen].u = u;
- dmgs[dmgslen].t = t[0];
-
- int t_i = 0;
- for (int k=0; k<ar->uslen; k++) {
- if (ar->us+k == t[0]) { t_i = k; break; }
- }
- float dam = stats_compute_damage(
- &ustats[i].weapon[j],
- &ustats[t_i].frame, u->reduced_armor);
-
- dmgs[dmgslen].dam = dam;
- dmgslen++;
- u->cooldown[j] -= ustats[i].weapon[j].cooldown;
- u->charge -= ustats[i].weapon[j].charge_per_shot;
- if (u->charge < 0) u->charge = 0;
+ while (u->cooldown[j] > 0) {
+ unit_search(info, ar, m, u, t, range);
+ if (t[0]!=NULL) {
+ dmgs[dmgslen].u = u;
+ dmgs[dmgslen].t = t[0];
+
+ int t_i = 0;
+ for (int k=0; k<ar->uslen; k++) {
+ if (ar->us+k == t[0]) { t_i = k; break; }
+ }
+ float dam = stats_compute_damage(
+ &ustats[i].weapon[j],
+ &ustats[t_i].frame, u->reduced_armor);
+
+ dmgs[dmgslen].dam = dam;
+ dmgslen++;
+ u->cooldown[j] -= ustats[i].weapon[j].cooldown;
+ u->charge -= ustats[i].weapon[j].charge_per_shot;
+ if (u->charge < 0) u->charge = 0;
+ } else break;
}
}
}