/*
    Bazoo_worms the game
    Copyright (C) 2011  Pavel Prochazka

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "MG_lib.h"
#include "WRMS_include.h"

static void
draw_crater (SPRITE * landscape, SDL_Rect in_r)
{
  SDL_Rect r = in_r;
  Uint8 bpp = landscape->img->format->BytesPerPixel;
  int w, h;
  Uint8 *ptr;
  SDL_Rect explosion_rect = MG_rects_cut (r, landscape->dest);
  float radius = (float) r.w / 2.0f;
  POINT mid =
    { (r.w / 2) + r.x - landscape->dest.x,
(r.h / 2) + r.y - landscape->dest.y };
  VECTOR v;

  if (MG_null_rect_p (explosion_rect))
    {
      printf ("null rect\n");
      return;
    }

  explosion_rect.x -= landscape->dest.x;
  explosion_rect.y -= landscape->dest.y;

  SDL_LockSurface (landscape->img);

  for (h = 0; h < explosion_rect.h; h++)
    {
      ptr = (Uint8 *) (landscape->img->pixels);
      ptr += (explosion_rect.y + h) * landscape->img->pitch;
      ptr += (explosion_rect.x * bpp);

      for (w = 0; w < explosion_rect.w; w++)
	{
	  v.x = (float) ((w + explosion_rect.x) - mid.x);
	  v.y = (float) ((h + explosion_rect.y) - mid.y);

	  if (vector_length (v) <= radius)
	    {
	      memcpy (ptr, &landscape->img->format->colorkey, bpp);
	    }

	  ptr += bpp;
	}
    }

  SDL_UnlockSurface (landscape->img);
  MG_invalidate_rect (in_r);
}

void
bazoo_explosion (SPRITE * bullet, float range)
{
  SPRITE *landscape = WRMS_landscape_get ();
  POINT mid = sprite_mid (bullet);
  SDL_Rect explosion_rect = { mid.x - range,
    mid.y - range,
    (int) (2.0f * range),
    (int) (2.0f * range)
  };

  draw_crater (landscape, explosion_rect);
}

static void
bazoo_give_damages (SPRITE * bullet)
{
  int damage = 0;
  LIST *wrms = WRMS_rules_worms ();
  SPRITE *worm;

  while (wrms)
    {
      worm = (SPRITE *) wrms->value;

      damage =
	(int) bazooka_compute_damage_impl (NULL, worm, sprite_mid (bullet));
      WRMS_rules_give_damage (NULL, worm, damage);

      wrms = wrms->node;
    }
}

static void
bullet_destroy (SPRITE * bullet)
{
  WRMS_rules_swap_players ();
  bazoo_give_damages (bullet);
  WRMS_visualizer_damages ();
  MG_install_callback (bullet, "on_boom", NULL);
}

void
bullet_on_iter (SPRITE * bullet)
{
  SDL_Rect r_screen = WRMS_WORLD_SCREEN;
  SDL_Rect r_cut = MG_rects_cut (bullet->dest, r_screen);

  /* when whole bullet is out of screen */
  if (MG_null_rect_p (r_cut))
    {
      /* destroy bullet only */
      MG_send_msg (bullet, "on_boom");
      MG_remove_sprite (bullet);
      return;
    }
}

void
expl_iter (SPRITE * explosion)
{
#define ALIVE_TICKS 200
  int *alived = (int *) MG_get_key (explosion, "alive_count");
  *alived += MG_get_system_dt ();

  if (*alived >= ALIVE_TICKS)
    {
      free (alived);
      MG_remove_sprite (explosion);
    }
}

void
bullet_explosion_impl (SPRITE * bazoo_bullet, SPRITE * landscape)
{
  if (landscape->type == LANDSCAPE)
    {
      POINT pp_col = pixel_perfect_collision_p (bazoo_bullet, landscape);
      if (!(pp_col.x != -1 && pp_col.y != -1))
	return;
    }
  else if (landscape->type == WORM)
    {
      SPRITE *victim = landscape;
      SPRITE *attacker = MG_get_key (bazoo_bullet, "attacking_worm");
      WRMS_team *t_victim = WRMS_worm_team (victim);
      WRMS_team *t_attacker = WRMS_worm_team (attacker);

      if (t_victim == t_attacker)	/* direct friendly fire is not allowed */
	return;

      POINT pp_col = pixel_perfect_collision_p (bazoo_bullet, victim);
      if (!(pp_col.x != -1 && pp_col.y != -1))
	return;
    }
  else
    return;

  SPRITE *expl;
  POINT bullet_mid = sprite_mid (bazoo_bullet);
  POINT expl_mid;
  /* call explose */
  bazoo_explosion (bazoo_bullet, 54.0f);

  expl = MG_make_sprite (MG_get_img ("bazooexplosion.bmp"), NULL);
  MG_install_callback (expl, "on_iter", expl_iter);
  MG_set_key (expl, "alive_count", (void *) make_int (0));
  expl_mid = sprite_mid (expl);

  MG_move_sprite (expl, bullet_mid.x - expl_mid.x, bullet_mid.y - expl_mid.y);

  MG_send_msg (bazoo_bullet, "on_boom");
  MG_remove_sprite (bazoo_bullet);
}

SPRITE *
WRMS_bullet_bazoo_impl (SPRITE * gun)
{
  DIRECTION dir;
  char *bitmap_path = WRMS_build_name (dir =
				       WRMS_gun_get_direction (gun), -1,
				       "bazoobullet", WRMS_PIXMAP_SUFFIX);

  SPRITE *bullet = MG_make_sprite (MG_get_img (bitmap_path), NULL);
  free (bitmap_path);

  MG_install_callback (bullet, "on_collide", bullet_explosion_impl);
  MG_install_callback (bullet, "on_iter", bullet_on_iter);
  MG_install_callback (bullet, "on_boom", bullet_destroy);
  MG_set_key (bullet, "gun_origin", gun);
  MG_set_key (bullet, "attacking_worm", WRMS_rules_active_worm ());

  bullet->type = BULLET;

  MG_move_sprite (bullet,
		  gun->dest.x + (gun->dest.w / 2) - (bullet->dest.w / 2),
		  gun->dest.y);

  PHYSICS p =
    WRMS_firepower (1.0f, WRMS_gun_get_angle (gun), WRMS_gun_get_power (gun));

  MG_set_weight (bullet, p.m);
  MG_set_speed (bullet, &p.v);
  MG_set_power (bullet, &p.f);

  WRMS_visualize_bullet (bullet);

  return bullet;
}
