#include <math.h>
#include "main.h"
#include "tilemap.h"
#include "sprite.h"
#include "sprhelp.h"
#include "s_bomb.h"
#include "player.h"
#include "collide.h"
#include "s_exps.h"
#include "log.h"


/* Assumes sprite passed is a player. 

  Bomb types:
   -1 - Intro bomb
    0 - normal bomb
	1 - Magnetic bomb
	2 - Missile bomb
	3 - Seeking bomb
	4 - Mine Bomb
*/

void spawn_bomb(SPRITE *sprite, int type) {

 SPRITE *newsprite = spawn_sprite(sprite);
 BOMB *bomb;

 float rz = SIN45 * sprite->r;
 float rx = rz * XVECT(sprite->th);
 float ry = rz * YVECT(sprite->th);
 float s = SQDIST3(sprite->xv, sprite->yv, sprite->zv);

 ASSERT(sprite->type == SPRITE_TYPE_PLAYER);

 newsprite->type = SPRITE_TYPE_BOMB;

 LOG("Launching bomb type %i\n", type);


 if (type == 0 || type == 1 || type == -1) {
	if (s < 0.003) {
		rx = -rx;  ry = -ry;
	}

	newsprite->x = sprite->x - rx;
	newsprite->y = sprite->y - ry;
	newsprite->z = sprite->z - rz;
	
	 newsprite->th = sprite->th;

	newsprite->xv = sprite->xv + ry * sprite->thv / 5;
	newsprite->yv = sprite->yv - rx * sprite->thv / 5;
	newsprite->zv = sprite->zv;
	newsprite->thv = sprite->thv;

	newsprite->life = (type == 1) ? 300 : 500; /* Bombs explode after 5 seconds !!! (3 seconds for Magnetic bombs) */
 }
 else if (type == 2) {
	newsprite->x = sprite->x + rx;
	newsprite->y = sprite->y + ry;
	newsprite->z = sprite->z + rz;

	 newsprite->th = sprite->th;

	newsprite->xv = sprite->xv + XVECT(sprite->th) / 4;
	newsprite->yv = sprite->yv + YVECT(sprite->th) / 4;
	newsprite->zv = 0;
	newsprite->thv = sprite->thv;

	newsprite->life = 10000; /* Bomb explodes on contact! */
 }
 else if (type == 3) {
	newsprite->x = sprite->x + rx;
	newsprite->y = sprite->y + ry;
	newsprite->z = sprite->z + rz;

	 newsprite->th = sprite->th;

	newsprite->xv = sprite->xv + XVECT(sprite->th) / 4;
	newsprite->yv = sprite->yv + YVECT(sprite->th) / 4;
	newsprite->zv = 0;
	newsprite->thv = sprite->thv;

	newsprite->life = 400; /* 4 seconds for seek */
 }
 else if (type == 4) {
	newsprite->x = sprite->x + rx;
	newsprite->y = sprite->y + ry;
	newsprite->z = sprite->z + rz;

	 newsprite->th = sprite->th;

	newsprite->xv = 0;
	newsprite->yv = 0;
	newsprite->zv = 0;
	newsprite->thv = 0;

	newsprite->life = -1; /* 4 seconds for seek */
 }

 if (type == 1) {
 	newsprite->anim = &MagBomb;
	newsprite->anim_speed = 0;
	newsprite->cur_frame = 0;
	newsprite->num_frames = 1;
 }
 else {
 	newsprite->anim = Bomb;
	newsprite->anim_speed = 8192;
	newsprite->cur_frame = 0;
	newsprite->num_frames = 8;
 }
 if (type == -1)
	 newsprite->anim_speed = 6144;
 
 newsprite->r = 0.01;

 bomb = newsprite->data = malloc(sizeof(BOMB));

 if (!bomb) exit(37);

 bomb->player = sprite->data;
 bomb->type = type;
 bomb->count = 0;
 bomb->mini_exp = FALSE;
 bomb->target = NULL;

 /* If seeking, then find nearest target */
 if (type == 3) {
	 PLAYER *player = sprite->data, *min_player = NULL;
	 float min_dist = 99999999999;

	 if (!player)
		 return;

	 /* Go to start of list */
	 while (player->prev)
		 player = player->prev;	

	 /* Find nearest */
	 while (player) {
		 float d;

		 if (player->sprite == sprite || !player->sprite) {
			 player = player->next;
			 continue;
		 }

		 d = SQDIST2(player->sprite->x - sprite->x, player->sprite->y - sprite->y);
		 if (d < min_dist) {
			 min_dist = d;
			 min_player = player;
		 }

		 player = player->next;
	 }

	 bomb->target = min_player;
 }

 return;
}



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

#define BOMB_XRAD 32.0
#define BOMB_YRAD 32.0

    static char spark_behind[] = {1, 0, 0, 0, 0, 1, 1, 1};
    static float spx[] = {59.0 / BOMB_XRAD - 1.0,
                          52.0 / BOMB_XRAD - 1.0,
                          31.0 / BOMB_XRAD - 1.0,
                          11.0 / BOMB_XRAD - 1.0,
                           4.0 / BOMB_XRAD - 1.0,
                          10.0 / BOMB_XRAD - 1.0,
                          32.0 / BOMB_XRAD - 1.0,
                          51.0 / BOMB_XRAD - 1.0};

#define SPX(n) (spx[n])
#define SPY(n) (8 / BOMB_YRAD - 1.0)

#define SPARK_XRAD 16
#define SPARK_YRAD 16

    int fr = sprite->cur_frame >> 16;
    int sp = ((sprite->cur_frame & 65535) * 3) >> 16;

    float xview, yview, xrad, yrad;

	(void)cth;

    if (spark_behind[fr] == 0)
	    draw_generic_sprite(bmp, sprite, sprite->anim[fr], POLYTYPE_ATEX_MASK);

    xview = sprite->xview;
    yview = sprite->yview;
    xrad = sprite->xrad;
    yrad = sprite->yrad;
    sprite->xview += sprite->xrad * SPX(fr);
    sprite->yview += sprite->yrad * SPY(fr);
    sprite->xrad *= SPARK_XRAD / BOMB_XRAD;
    sprite->yrad *= SPARK_YRAD / BOMB_YRAD;

    color_map = &add_map;

	draw_generic_sprite(bmp, sprite, dat[SPARK1_BMP + sp].dat, POLYTYPE_ATEX_MASK_TRANS);

    sprite->xview = xview;
    sprite->yview = yview;
    sprite->xrad = xrad;
    sprite->yrad = yrad;

    if (spark_behind[fr])
	    draw_generic_sprite(bmp, sprite, sprite->anim[fr], POLYTYPE_ATEX_MASK);
}



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

 BOMB *bomb = sprite->data;

 (void)xi; (void)yi; (void)zi;
 sprite->xv *= 0.99;
 sprite->yv *= 0.99;
 sprite->zv *= 0.99;
 sprite->thv *= 0.997;

 if (iv)
	 bomb->count++;

 if (xt >= 0)
  /* 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_bomb(TILEMAP *map, SPRITE *sprite) {

 BOMB *bomb = sprite->data;

 sprite->cur_frame += sprite->anim_speed;
 if (sprite->cur_frame >= itofix(sprite->num_frames))
	sprite->cur_frame = 0;

 if (sprite->r < 0.4) {
     if (bomb->type == 2)
	     sprite->r += 0.1;
     else
         sprite->r += 0.01;
     if (sprite->r > 0.4) sprite->r = 0.4;
     sprite_tilemap_collision(map, sprite, NULL);
 }

 if (bomb->type != 2 && map)
	sprite->zv -= 0.001;

 if (bomb->target && bomb->target->sprite) {
	 SPRITE *spr2 = bomb->target->sprite;
	 if (spr2->x < sprite->x)
		 sprite->xv -= 0.005;
	 else
		 sprite->xv += 0.005;

	 if (spr2->y < sprite->y)
		 sprite->yv -= 0.005;
	 else
		 sprite->yv += 0.005;
 }

 extrapolate_sprite(sprite);
 sprite_tilemap_collision(map, sprite, stc_bomb);

 if ((bomb->count && bomb->type == 2) || (bomb->count > 3 && bomb->type == 3)) {
	 sprite->xv = 0; sprite->yv = 0; sprite->zv = 0;
	 sprite->life = 0;
 }

 if (bomb->type == 4) {
	 sprite->xv = 0; sprite->yv = 0;
 }

 if (sprite->life > 0) sprite->life--;

 if (sprite->life == 0) {
  /* create an explosion!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
	 if (bomb->type == -1)
		create_explosion(sprite, 200.0);
	 else
		create_explosion(sprite, bomb->mini_exp ? 35.0 : 50.0);
 }
}
