#include <math.h>
#include "main.h"
#include "tilemap.h"
#include "sprite.h"
#include "s_expp.h"
#include "sprhelp.h"
#include "collide.h"
#include "texture.h"



#define N_EXP_BMP 16



typedef struct EXPPARTICLE {

 int exp_bmp;

} EXPPARTICLE;



/* explosion_colours[brightness][sprite][background] */
unsigned char explosion_colours[16][16][256];



void generate_explosion_colours() {
 int x, y, z;
 int c;

 for (z = 0; z < 16; z++) {
  for (y = 0; y < 16; y++) {

   c = (y + z - 15) >> 1;

   if (c >= 0) {
    for (x = 0; x < 240; x++) {
     explosion_colours[z][y][x] = 240 + c;
    }
    for (; x < 256; x++) {
     explosion_colours[z][y][x] = MIN(x + c, 255);
    }
   } else {
    for (x = 0; x < 256; x++) {
     explosion_colours[z][y][x] = x;
    }
   }

  }
 }
}



void spawn_expp(SPRITE *sprite, float size) {

 static int exp_bmp = 0;

 SPRITE *newsprite = spawn_sprite(sprite);
 EXPPARTICLE *expp;
 float r, a;

 newsprite->life = (int)ceil(size);

 newsprite->type = SPRITE_TYPE_EXPP;

 newsprite->x = sprite->x;
 newsprite->y = sprite->y;
 newsprite->z = sprite->z;

 newsprite->zv = RND(1.9999) - 0.99995;

 r = sqrt(1.0 - newsprite->zv * newsprite->zv);
 a = RND(2 * M_PI);

 newsprite->xv = r * cos(a);
 newsprite->yv = r * sin(a);

 r = 0.02 * pow(RND(size), 1.0 / 3.0);

 newsprite->xv *= r;
 newsprite->yv *= r;
 newsprite->zv *= r;

 newsprite->xv += sprite->xv;
 newsprite->yv += sprite->yv;
 newsprite->zv += sprite->zv;

 newsprite->r = sprite->r; /* inherit the radius of the source */

 expp = newsprite->data = malloc(sizeof(EXPPARTICLE));

 if (!expp) exit(37);

 expp->exp_bmp = exp_bmp;
 exp_bmp = (exp_bmp + 1) % N_EXP_BMP;
}



void draw_expp(BITMAP *bmp, SPRITE *sprite, float cth) {

 EXPPARTICLE *expp = sprite->data;

 int br = sprite->life >> 2;

 (void)cth;

 color_map = (COLOR_MAP *)&explosion_colours[MIN(br, 15)];

 draw_generic_sprite(bmp, sprite, dat[EXP00_BMP + expp->exp_bmp].dat,
                                                   POLYTYPE_ATEX_MASK_TRANS);
}



/* sprite_tilemap_collision() callback; see collide.h. */
static void stc_expp(TILEMAP *map,
                     SPRITE *sprite,
                     float xi, float yi, float zi,
                     float iv,
                     int xt, int yt,
                     TILE *tile, TILE_SURFACES *hit) {

	int i;

	(void)xi; (void)yi; (void)zi;

	for (i = 0; i < N_TILE_SURFACES; i++)
		tile->damage.s[i] += iv * hit->s[i];

 if (xt >= 0) {
  if (tile->lift == 0 && tile->texture < TEXTURE_NUM_SUBSIDABLE) tile->z -= iv * tile->u.subsidence;

  /* This is not perfect at all */
  create_disturbance(map->ripple_info,
                     tile->ripples,
                     sprite->x - xt, sprite->y - yt, sprite->r, -1000000*iv*hit->s[TILE_SURFACE]);
 }
}



void update_expp(TILEMAP *map, SPRITE *sprite) {

 sprite->xv *= 0.954;
 sprite->yv *= 0.954;
 sprite->zv *= 0.954;

 extrapolate_sprite_no_th(sprite);

 sprite_tilemap_collision(map, sprite, &stc_expp);

 sprite->life--;
}



/* Expp-expp interaction. Repel, and reinforce particles near to each other.
*/
void si_expp_expp(TILEMAP *map, SPRITE *spr1, SPRITE *spr2);
