#include <math.h>
#include "main.h"
#include "tilemap.h"
#include "sprite.h"
#include "sprhelp.h"
#include "s_player.h"
#include "collide.h"
#include "player.h"
#include "zcontrol.h"
#include "ripples.h"
#include "timeloop.h"
#include "s_bomb.h"
#include "s_pwrup.h"
#include "s_blood.h"
#include "s_exps.h"
#include "s_camera.h"
#include "sound2.h"



SPRITE *add_player_sprite(TILEMAP *map, SPRITE *sprite, PLAYER *player,
                                                     int x, int y, int dir) {
 sprite = add_sprite(sprite);

 sprite->life = -1;

 sprite->type = SPRITE_TYPE_PLAYER;

 sprite->x = (float)x + 0.5;
 sprite->y = (float)y + 0.5;

 if (map)
	sprite->z = map->tile[y][x].z + 0.4;
 else
	 sprite->z = 0;

 sprite->th = (float)dir * (M_PI / 4.0);

 sprite->xv = 0;
 sprite->yv = 0;
 sprite->zv = 0;

 sprite->thv = 0;

 sprite->r = 0.4;

 sprite->data = player;
 if (player)
	player->sprite = sprite;

 return sprite;
}


/* draw_player_sprite(): this is the player's sprite_draw_proc entry (see sprite.h).
   Use sprite_direction() to get the direction the player is facing. Then use
   draw_generic_sprite() to draw the sprite. These two functions are in
   sprhelp.h.

   In order to choose a bitmap, use the following formula:

   PLAYER00 + p*(PLAYER10-PLAYER00) + d

   where p is the player number (0 to 3) and d is the direction as returned
   by sprite_direcetion(). This gives a datafile index. Use it to look up the
   appropriate bitmap.
*/
void draw_player_sprite(BITMAP *bmp, SPRITE *sprite, float cth) {

	PLAYER *player = sprite->data;
	int d = sprite_direction(sprite->th, cth);
	int n;

	if (!player)
		return;

	n = player->id;

#ifdef ZIG_GL
	draw_generic_sprite(bmp, sprite,
		(sprite->life >= 0) ? glBloodyPod[n][d] : glPod[n][d],
		POLYTYPE_ATEX_MASK);
#else
	draw_generic_sprite(bmp, sprite,
		(sprite->life >= 0) ? BloodyPod[n][d] : Pod[n][d], POLYTYPE_ATEX_MASK);

	if (player->stat & PLAYER_STAT_INVULNERABLE) {
		float r = RND(MAX(sprite->xrad, sprite->yrad)) * .2 + MAX(sprite->xrad, sprite->yrad) * .8;
		ellipse(bmp, (int)floor(sprite->xview), (int)floor(sprite->yview),
                   (int)r, (int)r, 
				   makecol(192,192,192));
	}
#endif
}


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

 PLAYER *player = sprite->data;

 if (iv >= 0.1) player_deduct_hp(player, (int)(iv * 100) - 10 + 1);

 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]);

  /* TEMPORARY HACK, SO PLAYER CAN CLIMB */
  sprite->zv += 0.005 - 0.005 * hit->s[TILE_SURFACE];
 }

 if (iv >= 0.025)
	 play_sound(Sample.WallBang, xi, yi, zi, iv * 2000, 1000, 0);
}


/* update_player_sprite(): this is the player's sprite_update_proc entry (see
   sprite.h).

   ELABORATE WHEN THE EXTERNAL DATA ARE READY (player.h).
*/
void update_player_sprite(TILEMAP *map, SPRITE *sprite) {

 PLAYER *player = sprite->data;

 int l = 0, r = 0, f = 0, b = 0;
 int i;

 if (!player)
	 return;

 if (player->hp <= 0) {
  if (sprite->life < 0) {
   int i;
   sprite->life = 100 + (random() & 127);
   for (i = 0; i < 100; i++) {
    SPRITE *blood = spawn_blood(sprite, 0.1 + RND(0.1), 0.05);
    if (blood->zv < 0) blood->zv = -blood->zv;
   }
  } else {
   sprite->life--;
   if (sprite->life == 0) {
    create_explosion(sprite, 50);
    player->sprite = 0;
	player->time_of_death = game_time;
   }
  }
 } else if (game_has_started) {
  do {

		l |= control_key(player->control, CONTROL_KEY_LEFT);
		r |= control_key(player->control, CONTROL_KEY_RIGHT);
		f |= control_key(player->control, CONTROL_KEY_FORWARD);
		b |= control_key(player->control, CONTROL_KEY_BACKWARD);

		if (control_key(player->control, CONTROL_KEY_FIRE) && player->fire_delay == 0) {

			if (player->num_missiles <= 0 && player->num_bombs > 0) {
				spawn_bomb(sprite, 0);
				player->num_bombs--;
			}
			else if (player->num_missiles > 0) {
				spawn_bomb(sprite, 2);
				player->num_missiles--;
			}
			player->fire_delay = 30;
		}
		if (control_key(player->control, CONTROL_KEY_POWERUP) && player->held_powerup && !player->fire_delay && (game_time - player->powerup_time) >= 150) {

			player->fire_delay = 30;

			if (player->held_powerup == POWERUP_MYSTERY)
				player->held_powerup = (random() % (N_POWER_UPS - 2)) + 2;

			if (player->held_powerup == POWERUP_HEALTH) {
				player->hp += 12000;
				player->hp = MIN(player->hp, player->maxhp);
			}
			else if (player->held_powerup == POWERUP_INVULNERABILITY) {
				player->stat |= PLAYER_STAT_INVULNERABLE;
				player->stat_timer[0] = 1000;
			}
			else if (player->held_powerup == POWERUP_BOMB) {
				player->num_bombs += 5;
				player->num_bombs = MID(0, player->num_bombs, 99);
			}
			else if (player->held_powerup == POWERUP_SPEED_BOOST) {
				player->stat |= PLAYER_STAT_SPEED_BOOST;
				player->stat_timer[1] = 1000;
			}
			else if (player->held_powerup == POWERUP_JUMP) 
				player->sprite->zv += 0.5;
			else if (player->held_powerup == POWERUP_MAGBOMBS) {
				spawn_bomb(sprite, 1);
			}
			else if (player->held_powerup == POWERUP_BOMB_LAUNCHER) {
				player->num_missiles += 5;
				player->num_missiles = MID(0, player->num_missiles, 99);
			}
			else if (player->held_powerup == POWERUP_SEEKING_BOMB) {
				spawn_bomb(sprite, 3);
			}
			else if (player->held_powerup == POWERUP_MINE_BOMB) {
				spawn_bomb(sprite, 4);
			}

			player->held_powerup = 0;
		}

  } while (control_ack(player->control));

  if (l && !r) sprite->thv -= 0.0004;
  if (r && !l) sprite->thv += 0.0004;

  if (f && !b) {
	  sprite->xv += 0.002 * XVECT(sprite->th) * ((player->stat & (PLAYER_STAT_INVULNERABLE | PLAYER_STAT_SPEED_BOOST)) ? 2 : 1);
      sprite->yv += 0.002 * YVECT(sprite->th) * ((player->stat & (PLAYER_STAT_INVULNERABLE | PLAYER_STAT_SPEED_BOOST)) ? 2 : 1);
  }
  if (b && !f) {
   sprite->xv -= 0.002 * XVECT(sprite->th) * ((player->stat & (PLAYER_STAT_INVULNERABLE | PLAYER_STAT_SPEED_BOOST)) ? 2 : 1);
   sprite->yv -= 0.002 * YVECT(sprite->th) * ((player->stat & (PLAYER_STAT_INVULNERABLE | PLAYER_STAT_SPEED_BOOST)) ? 2 : 1);
  }

  if (player->fire_delay) player->fire_delay--;

  for (i = 0; i < 32; i++) {
	  if (player->stat & (1 << i)) {
		  player->stat_timer[i]--;

		  if (player->stat_timer[i] <= 0) {
			  player->stat_timer[i] = 0;
			  player->stat &= ~(1 << i);
		  }
	  }
	}
 }
 else {
	while (control_ack(player->control));
 }

 sprite->zv -= 0.001 * ((player->stat & (PLAYER_STAT_INVULNERABLE | PLAYER_STAT_SPEED_BOOST)) ? 0.5 : 1);

 sprite->xv *= 0.98;
 sprite->yv *= 0.98;
 sprite->zv *= 0.98;
 sprite->thv *= 0.98;

 extrapolate_sprite(sprite);
 sprite_tilemap_collision(map, sprite, &stc_player);

 if (player->camspr)
	camera_set_target(map, player->camspr->data, sprite);
}
