#include <stdlib.h>
#include <sys/bios.h>
#include <sys/libwwc.h>
#include "grlib.h"

#define N_FIRE 128
struct {
  int used;
  int x;
  int y;
  int v;
  int w;
  int color;
  int generation;
  int timer;
} fire[N_FIRE];

int lookup_free_fire(int n, int result[]) {
  int i, j;
  j=0;
  for(i=0; i<N_FIRE; i++) {
    if (j>=n) return j;
    if (!fire[i].used) {
      result[j] = i;
      j++;
    }
  }
  return j;
}

#define GRAVITY 3
#define SCALE 6 /* scaled by 2^SCALE */
void new_fire() {
  static int i;
  if (!lookup_free_fire(1, &i))
    return;
  fire[i].used = 1;
  fire[i].x = (rand()%224)<<SCALE;
  fire[i].y = 0<<SCALE;
  fire[i].v = rand()%32-16;
  fire[i].w = rand()%128+128;
  fire[i].color = rand()%8+8;
  fire[i].timer = 60;
  fire[i].generation = 1;
}

void init_fire() {
  int i;
  for(i=0; i<N_FIRE; i++)
    fire[i].used = 0;
}

void explode(int i){
  int j, k, n;
  static int small_fire[32];
  n = lookup_free_fire(32, small_fire);
  for(j=0; j<n; j++) {
    k = small_fire[j];
    fire[k].used = 1;
    fire[k].x = fire[i].x;
    fire[k].y = fire[i].y;
    fire[k].v = fire[i].v+rand()%64-32;
    fire[k].w = fire[i].w+rand()%64-32;
    if (k < 24)
      fire[k].color = fire[i].color;
    else
      fire[k].color = rand()%8+8;
    fire[k].timer = 30;
    fire[k].generation = fire[i].generation - 1;
  }
  fire[i].used = 0;
}

void process_fire(int i) {
  if (!fire[i].used)
    return;
  gr_pset(fire[i].x>>SCALE, 143-(fire[i].y>>SCALE), fire[i].color);
  gr_pset((fire[i].x>>SCALE)+1, 143-(fire[i].y>>SCALE), fire[i].color);
  gr_pset(fire[i].x>>SCALE, 142-(fire[i].y>>SCALE), fire[i].color);
  gr_pset((fire[i].x>>SCALE)+1, 142-(fire[i].y>>SCALE), fire[i].color);

  if (!(--fire[i].timer)) {
    if (fire[i].generation)
      explode(i);
    else
      fire[i].used = 0;
  }
  fire[i].x += fire[i].v;
  fire[i].y += fire[i].w;
  fire[i].w -= GRAVITY;
  if (!fire[i].generation && fire[i].timer < 20)
    if ((rand()&15)==0)
      fire[i].color &= 7;
  if (!fire[i].generation && fire[i].timer < 10)
    if ((rand()&7)==0)
      fire[i].used = 0;
  if (fire[i].x < 0 || fire[i].x >= (223<<SCALE) ||
      fire[i].y < 1 || fire[i].y >= (144<<SCALE))
    fire[i].used = 0;
}

#define PERIOD 32
main() {
  int i, t;
  int key;

  gr_init();
  init_fire();
  t=0;
  while(1) {
    gr_clear();
    if (t%(PERIOD/4) == 0)
      new_fire();
    for(i=0; i<N_FIRE; i++)
      process_fire(i);

    gr_update();
    key = key_press_check();
    t = (t+1)%PERIOD;
    if (key == 2)
      break;
  }
}
