#include <math.h>
#include "main.h"
#include "tilemap.h"
#include "sprite.h"
#include "sprhelp.h"
#include "s_animal.h"
#include "s_blood.h"
#include "s_pwrup.h"
#include "s_bomb.h" 
#include "player.h"
#include "collide.h"
#include "options.h"
#include "log.h"

#define SQDIST3(x, y, z) ((x)*(x) + (y)*(y) + (z)*(z))
#define SQ(x) ((x)*(x))

#define MAX_ANIMALS 100
int NumAnimals = 0;

/* Assumes sprite passed is a portal. */
void spawn_animal(SPRITE *sprite) {

	SPRITE *newsprite;
	ANIMAL *animal;
	int i;

	if (NumAnimals >= MAX_ANIMALS)
		return;

	newsprite = spawn_sprite(sprite);
	NumAnimals++;

	ASSERT(sprite->type == SPRITE_TYPE_PORTAL);

	newsprite->life = 1; /* Alive */

	newsprite->type = SPRITE_TYPE_ANIMAL;
	
	newsprite->th = RND(2 * M_PI);

	newsprite->x = sprite->x - sprite->r * XVECT(newsprite->th);
	newsprite->y = sprite->y - sprite->r * YVECT(newsprite->th);
	newsprite->z = sprite->z;

	newsprite->xv = (RND(1.0) - 0.5) / 10.0;
	newsprite->yv = (RND(1.0) - 0.5) / 10.0;
	newsprite->zv = (RND(0.8) - 0.4) / 10.0;
	newsprite->thv = (RND(M_PI * 2) - M_PI) / 100.0;

	newsprite->r = 0.01;

	animal = newsprite->data = malloc(sizeof(ANIMAL));
    if (!animal) exit(37);

	animal->portal = sprite->data;

	animal->powerup = 0;
	if ((random() % 10) < 8) {

		int f = random() % 110;
		for (i = 0; i < N_POWER_UPS; i++) {
			if (f < powerup_freq[i]) {
				animal->powerup = i;
				break;
			}
			else
				f -= powerup_freq[i];
		}
	}
	else
		animal->powerup = 0;

	animal->type = random() % N_ANIMALS;
}



void draw_animal(BITMAP *bmp, SPRITE *sprite, float cth) {
/*
 ellipsefill(bmp, (int)floor(sprite->xview), (int)floor(sprite->yview),
                   (int)sprite->xrad, (int)sprite->yrad, makecol(255,128,0));
*/
	ANIMAL *animal = ((ANIMAL*)sprite->data);

	(void)cth;

	draw_generic_sprite(bmp, sprite, Animal[animal->type], POLYTYPE_ATEX_MASK);
}



/* sprite_tilemap_collision() callback; see collide.h. */
static void stc_animal(TILEMAP *map,
                       SPRITE *sprite,
                       float xi, float yi, float zi,
                       float iv,
                       int xt, int yt,
                       TILE *tile, TILE_SURFACES *hit) {
 (void)xi, (void)yi; (void)zi;
 sprite->xv *= 0.99;
 sprite->yv *= 0.99;
 sprite->zv *= 0.99;
 sprite->thv *= 0.997;

 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_animal(TILEMAP *map, SPRITE *sprite) {

	float s;

    if (sprite->r < 0.5) {
	    sprite->r += 0.01;
	    if (sprite->r > 0.5)
		    sprite->r = 0.5;
        sprite_tilemap_collision(map, sprite, NULL);
    }

	sprite->zv -= 0.001;

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

	s = SQDIST3(sprite->xv, sprite->yv, sprite->zv);

	if (s < 0.0005) {
		sprite->xv *= 2;
		sprite->yv *= 2;
		sprite->zv *= 1.5;
	}

	if (sprite->life == 0) {
		int i;
		ANIMAL *animal = sprite->data;

		/* Spawn powerup if needed */
		if (animal->powerup)
			spawn_powerup(sprite);

		/* Create a blood explosion */
		for (i = 0; i < 100; i++)
			spawn_blood(sprite, 0.1 + RND(0.1), 10*animal->col_speed + 0.01);
	}
}


void free_animal_data(void *data) {

	free(data);
	NumAnimals--;

	if (NumAnimals < 0) 
		LOG(ERROR "s_animal::free_animal: Consistency error, freed more than created!\n");
}


void si_animal(TILEMAP *map, SPRITE *spr1, SPRITE *spr2) {

	SPRITE *animal, *other;
	float d;

	(void)map;

	/* Find out who's who */
	if (spr1->type == SPRITE_TYPE_ANIMAL) {
		animal = spr1;
		other = spr2;
	}
	else {
		animal = spr2;
		other = spr1;
	}

	/* Distance check */
	d = SQDIST3(spr1->x - spr2->x, spr1->y - spr2->y, spr1->z - spr2->z);

	/* Collision? */
	if (d <= SQ(spr1->r + spr2->r)) {

		/* Animal dies */
		animal->life = 0;

		/* Store collision speed */
		((ANIMAL*)animal->data)->col_speed = SQDIST3(spr1->xv - spr2->xv, spr1->yv - spr2->yv, spr1->zv - spr2->zv);

		/* Has it collided with a player */
		if (other->type == SPRITE_TYPE_PLAYER) {
			PLAYER *p2 = other->data;
			p2->points += 8;
		}
		else if (other->type == SPRITE_TYPE_BOMB) {
			BOMB *b = other->data;
			b->player->points += 30;
		}
	}

	/* Should I add a large velocity to the other sprite? */
}
