#include "powers.h"
#include "cache.h"
#include "globals.h"
#include "camera.h"
#include "mykeyboard.h"
#include "mymath.h"
#include "particle.h"
#include "person.h"
#include "tdsound.h"
#include "map.h"


ALLEGRO_BITMAP *flash_grenade;
ALLEGRO_BITMAP *flash_frames[10];

ALLEGRO_BITMAP *smoke_grenade;
AnimatedSprite smoke_sprite;

ALLEGRO_BITMAP *gift_spawn_bit;
ALLEGRO_BITMAP *santa_target_bit;

ALLEGRO_SAMPLE *grenade_explosion;
ALLEGRO_SAMPLE *grenade_after;

ALLEGRO_SAMPLE *santa_is_coming;

float fall_flash_grenade=0;
float flash_grenade_x=0;
float flash_grenade_y=0;
float flash_grenade_angle=0;
float flash_grenade_fall_speed=0;


float fall_smoke_grenade=0;
float smoke_grenade_x=0;
float smoke_grenade_y=0;
float smoke_grenade_angle=0;
float smoke_grenade_fall_speed=0;
float smoke_grenade_fade=1.0;


float fall_gift_spawn=0;
float gift_spawn_x=0;
float gift_spawn_y=0;
float gift_spawn_angle=0;
float gift_spawn_fall_speed=0;
float gift_spawn_fade=1.0;
float gift_spawn_wait;
float gift_flash_opacity=1.0;

float santa_call_opacity=1.0;
float santa_call_angle=0;
float santa_call_x=0;
float santa_call_y=0;
float santa_flash_opacity=0.0;


float flash_frame=-1;
float flash_size=0;
float flash_opacity=0;

bool FlashGrenadeActive=0;
bool SmokeGrenadeActive=0;
bool GiftSpawnActive=0;
bool SantaCallActive=0;

const int SMOKES_SIZE=8;

const float FLASH_RANGE=500;

class Smoke {
  public:
    Vec2D position;
    float direction;
    float speed, life, rw, ang, rw_modifier;
    void Start(Vec2D pos, float d, float sp, float lf) {
      position=pos;
      direction=d;
      speed=sp;
      life=lf;
      rw = 50;
      ang = AngleToRad(randn(360));
      rw_modifier=0;
    }
    void Update() {
      if (life == 0) return;
      position.x += cos(direction) * (speed*DeltaTime);
      position.y += sin(direction) * (speed*DeltaTime);
      life -= DeltaTime;
      if (life < 0) life = 0;
      rw += (0.5-rw_modifier)*DeltaTime;

      ang += 0.005*DeltaTime;
      rw_modifier+= 0.0005*DeltaTime;
      FixRadAngle(ang);

      if (life < 200) return;

      std::deque<Person *>::iterator it;
      for (it=persons.begin(); it!=persons.end(); it+=1) {
        if (!(*it)->HasGasProtection()) {
          if ((*it)->IsInRange(position.x, position.y, rw/2)) {
            (*it)->Smoking();
          }
        }
      }
    }
    void Draw() {
      float opm;
      opm=1.0;
      if (life < 100) opm = life/100.0;
      OPACITY_BLEND(0.3*opm);
      if (life == 0) return;
      ALLEGRO_BITMAP *cb;
      cb = smoke_sprite.GetActualBitmap()->get_bit();
      DRAW_TRANSFORMED(cb, RSW(position.x-Camera_X), RSH(position.y-Camera_Y), RSW(rw), RSH(rw), ang, 0);
      NORMAL_BLEND;
    }
};


Smoke smokes[SMOKES_SIZE+1];



void LoadPowersResources() {
  flash_grenade = al_load_bitmap("Graphics/Powers/Flash/Grenade.png");
  smoke_grenade = al_load_bitmap("Graphics/Powers/Smoke/Grenade.png");
  gift_spawn_bit= al_load_bitmap("Graphics/Powers/Gift/Gift.png");

  santa_target_bit = al_load_bitmap("Graphics/Powers/Santa/Target.png");

  grenade_explosion = al_load_sample("Sounds/GrenadeExplosion.ogg");
  grenade_after = al_load_sample("Sounds/GrenadeAfter.ogg");
  santa_is_coming = al_load_sample("Sounds/SantaIsComing.ogg");

  smoke_sprite.Load("Powers/Smoke/Smoke01");

  CacheBitmap *cb;
  cb=load_cache_bitmap("Graphics/Person/ElfRobot/Portrait.png");
  cb->get_red_bit();

  for (int i=0; i!=10; i+=1) flash_frames[i] = al_load_bitmap(("Graphics/Powers/Flash/Flash" + ToString(i+1) + ".png").c_str());
}


/*  FLASH GRENADE  */

void FlashGrenade() {
  FlashGrenadeActive=1;
  fall_flash_grenade = 200;
  flash_grenade_x=SRX(mouse_x+RSW(Camera_X));
  flash_grenade_y=SRY(mouse_y+RSH(Camera_Y));
  flash_grenade_angle=0;
  flash_grenade_fall_speed = 1;
  flash_frame=-1;
}

void UpdateFlashGrenade() {
  if (fall_flash_grenade == 0) {
    fall_flash_grenade = -1;
    flash_frame=0;
    flash_size = 300;
    flash_opacity = 1.0;
    int sz;
    sz = 100 + randn(20);
    for (int i=0; i!=sz; i+=1) {
      Vec2D dr; float sp, lf;
      dr.x = randn(150)-76;
      dr.y = randn(150)-76;
      dr = dr.Normalized();
      if (i > 80) sp = 0.5;
      else if (i > 50) sp = 0.5 + randn(30)/10.0;
      else sp = 3 + randn(7);
      lf = 15 + randn(15);
      int t;
      t=PARTICLE_SPARKLE_01+randn(5)-1;
      AddParticle(t, flash_grenade_x, flash_grenade_y, sp, dr, lf);
    }
    play_3d_sample(grenade_explosion, 2.0, 1.0, ALLEGRO_PLAYMODE_ONCE, RSW(flash_grenade_x), RSH(flash_grenade_x));
    play_3d_sample(grenade_after, 1.5, 1.0, ALLEGRO_PLAYMODE_ONCE, RSW(flash_grenade_x), RSH(flash_grenade_x));
  }
  else if (fall_flash_grenade == -1) {
    flash_frame+=(0.6*DeltaTime);
    flash_size += 4.0 * DeltaTime;
    flash_opacity -= 0.01 * DeltaTime;
    if (flash_opacity <= 0) {
      flash_opacity = 0;
      std::deque<Person *>::iterator it;
      for (it=persons.begin(); it!=persons.end(); it+=1) {
        if ((!(*it)->IsMine()) && (!(*it)->IsUnconscious())) {
          if ((*it)->IsInRange(flash_grenade_x, flash_grenade_y, FLASH_RANGE)) {
            (*it)->Flash(600);
          }
        }
      }
      FlashGrenadeActive = 0;
    }

    if (flash_frame > 9) flash_frame = 9;
  }
  else {
    flash_grenade_fall_speed += 0.025*DeltaTime;
    fall_flash_grenade -= (flash_grenade_fall_speed*DeltaTime);
    flash_grenade_angle += AngleToRad(flash_grenade_fall_speed) * DeltaTime;
    if (fall_flash_grenade <= 0) fall_flash_grenade=0;
  }
}


void DrawFlashGrenade() {
  if (fall_flash_grenade > 0) DRAW_TRANSFORMED(flash_grenade, RSW(flash_grenade_x-Camera_X), RSH(flash_grenade_y-Camera_Y), RSW(fall_flash_grenade), RSH(fall_flash_grenade), flash_grenade_angle, 0);
  if (flash_frame >= 0) {
    OPACITY_BLEND(flash_opacity/4);
    DRAW_TRANSFORMED(flash_frames[(int)flash_frame], RSW(flash_grenade_x-Camera_X), RSH(flash_grenade_y-Camera_Y), RSW(flash_size), RSH(flash_size), 0, 0);
    NORMAL_BLEND;
    al_draw_filled_rectangle(0, 0, SCREEN_W, SCREEN_H, al_map_rgba_f(1.0, 1.0, 1.0, flash_opacity/2));

    NORMAL_BLEND;
  }
}



/* SMOKE GRENADE         */




void SmokeGrenade() {
  SmokeGrenadeActive=1;
  fall_smoke_grenade = 200;
  smoke_grenade_x=SRX(mouse_x+RSW(Camera_X));
  smoke_grenade_y=SRY(mouse_y+RSH(Camera_Y));
  smoke_grenade_angle=0;
  smoke_grenade_fall_speed = 1;
  smoke_grenade_fade=0;
}

void UpdateSmokeGrenade() {
  smoke_sprite.Update();

  if (fall_smoke_grenade > 15) {
    smoke_grenade_fade = 200;
    smoke_grenade_fall_speed += 0.025*DeltaTime;
    fall_smoke_grenade -= (smoke_grenade_fall_speed*DeltaTime);
    smoke_grenade_angle += AngleToRad(smoke_grenade_fall_speed) * DeltaTime;
    if (fall_smoke_grenade <= 15) {
      fall_smoke_grenade=15;
      float a, ang;
      ang = AngleToRad(360) / SMOKES_SIZE;
      a=0;
      for (int i=0; i!=SMOKES_SIZE; i+=1) {
        a += ang;
        smokes[i].Start(Vec2D(smoke_grenade_x, smoke_grenade_y), a, 0.2, 1500);
      }
      smokes[SMOKES_SIZE].Start(Vec2D(smoke_grenade_x, smoke_grenade_y), 0, 0, 1500);
    }
  }
  else {
    smoke_grenade_fade -= DeltaTime;
    if (smoke_grenade_fade < 0) smoke_grenade_fade = 0;
    for (int i=0; i!=SMOKES_SIZE+1; i+=1) smokes[i].Update();
  }
}


void DrawSmokeGrenade() {
  if (fall_smoke_grenade >= 15) {
    OPACITY_BLEND(smoke_grenade_fade/200.0);
    DRAW_TRANSFORMED(smoke_grenade, RSW(smoke_grenade_x-Camera_X), RSH(smoke_grenade_y-Camera_Y), RSW(fall_smoke_grenade), RSH(fall_smoke_grenade), smoke_grenade_angle, 0);
    NORMAL_BLEND;
  }
  if (fall_smoke_grenade == 15) {
    for (int i=0; i!=SMOKES_SIZE+1; i+=1) smokes[i].Draw();
  }
}


/* GIFT SPAWN  */


void GiftSpawn() {
  GiftSpawnActive=1;
  fall_gift_spawn = 200;
  gift_spawn_x=SRX(mouse_x+RSW(Camera_X));
  gift_spawn_y=SRY(mouse_y+RSH(Camera_Y));
  gift_spawn_angle=0;
  gift_spawn_fall_speed = 1;
  gift_flash_opacity = 0;
  gift_spawn_wait = 0;
}

void UpdateGiftSpawn() {
  if (gift_flash_opacity > 0) gift_flash_opacity -= 0.005 * DeltaTime;
  if (gift_flash_opacity < 0) gift_flash_opacity = 0;
  if (fall_gift_spawn > 35) {
    gift_spawn_fall_speed += 0.025*DeltaTime;
    fall_gift_spawn -= (gift_spawn_fall_speed*DeltaTime);
    gift_spawn_angle += AngleToRad(gift_spawn_fall_speed) * DeltaTime;
    if (fall_gift_spawn <= 35) {
      fall_gift_spawn=35;
      gift_spawn_wait=0;
    }
  }
  else if (gift_spawn_wait < 300) {
    gift_spawn_wait += DeltaTime*2;

    if (gift_spawn_wait >= 300) {
      play_3d_sample(grenade_explosion, 2.0, 1.0, ALLEGRO_PLAYMODE_ONCE, RSW(gift_spawn_x), RSH(gift_spawn_y));
      int sz;
      sz = 80 + randn(20);
      for (int i=0; i!=sz; i+=1) {
        Vec2D dr; float sp, lf;
        dr.x = randn(150)-76;
        dr.y = randn(150)-76;
        dr = dr.Normalized();
        if (i > 60) sp = 0.5;
        else if (i > 30) sp = 0.5 + randn(30)/10.0;
        else sp = 6 + randn(7);
        lf = 25 + randn(15);
        int t;
        t=PARTICLE_GIFT_01+randn(6)-1;
        AddParticle(t, gift_spawn_x, gift_spawn_y, sp, dr, lf);
      }
      gift_flash_opacity=0.5;

      SpawnPoint *sp;
      sp = new SpawnPoint(gift_spawn_x, gift_spawn_y, PERSON_AUTOMATED_GUARD);
      sz = 15 + randn(15);
      for (int i=0; i!=sz; i+=1) {
        SpawnPerson(sp);
      }
      delete sp;

      GiftSpawnActive=true;
    }
  }
}


void DrawGiftSpawn() {
  if (gift_flash_opacity > 0) {
    al_draw_filled_rectangle(0, 0, SCREEN_W, SCREEN_H, al_map_rgba_f(1.0, 1.0, 1.0, gift_flash_opacity));
  }

  if (gift_spawn_wait < 300) {
    Vec2D dir;
    dir.x = randn(300)-150;
    dir.y = randn(300)-150;
    dir = dir.Normalized();
    DRAW_TRANSFORMED(gift_spawn_bit, RSW(gift_spawn_x-Camera_X)+dir.x*(gift_spawn_wait/100.0), RSH(gift_spawn_y-Camera_Y)+dir.y*(gift_spawn_wait/100.0), RSW(fall_gift_spawn), RSH(fall_gift_spawn), gift_spawn_angle, 0);
  }
}




/* SANTA CALL             */


float santa_call_wait=0;

void SantaCall() {
  SantaCallActive=1;
  santa_call_x=SRX(mouse_x+RSW(Camera_X));
  santa_call_y=SRY(mouse_y+RSH(Camera_Y));
  santa_call_wait=400;
  play_3d_sample(santa_is_coming, 1.5, 1.0, ALLEGRO_PLAYMODE_ONCE, RSW(santa_call_x), RSH(santa_call_y));
}

void UpdateSantaCall() {
  if (SantaCallActive) {
    santa_call_wait -= DeltaTime;
    if (santa_call_wait < 0) {
      int sz;
      sz = 100 + randn(20);
      for (int i=0; i!=sz; i+=1) {
        Vec2D dr; float sp, lf;
        dr.x = randn(150)-76;
        dr.y = randn(150)-76;
        dr = dr.Normalized();
        if (i > 80) sp = 0.5;
        else if (i > 50) sp = 0.5 + randn(30)/10.0;
        else sp = 3 + randn(7);
        lf = 15 + randn(15);
        int t;
        t=PARTICLE_SPARKLE_01+randn(5)-1;
        AddParticle(t, santa_call_x, santa_call_y, sp, dr, lf);
      }
      play_3d_sample(grenade_explosion, 2.0, 1.0, ALLEGRO_PLAYMODE_ONCE, RSW(santa_call_x), RSH(santa_call_y));
      play_3d_sample(grenade_after, 1.5, 1.0, ALLEGRO_PLAYMODE_ONCE, RSW(santa_call_x), RSH(santa_call_y));

      SpawnPoint *sp;
      sp = new SpawnPoint(santa_call_x, santa_call_y, PERSON_SANTA);
      SpawnPerson(sp);
      delete sp;
      SantaCallActive=false;
    }
  }
  santa_call_angle += 0.005*DeltaTime;
  FixRadAngle(santa_call_angle);
}


void DrawSantaCall() {
  if (!SantaCallActive) {
    DRAW_TRANSFORMED(santa_target_bit, mouse_x, mouse_y, RSW(100), RSH(100), santa_call_angle, 0);
  }
  else {
    DRAW_TRANSFORMED(santa_target_bit, RSW(santa_call_x-Camera_X), RSH(santa_call_y-Camera_Y), RSW(100), RSH(100), santa_call_angle, 0);
  }
}






/* GENERAL UPDATE & DRAW */


void ResetPowers() {
  ActualPowersCooldown[0]=0;
  ActualPowersCooldown[1]=0;
  ActualPowersCooldown[2]=0;
  ActualPowersCooldown[3]=0;
  FlashGrenadeActive=false;
  SmokeGrenadeActive=false;
  GiftSpawnActive=false;
  SantaCallActive=false;
}


void UpdatePowers() {
  if (ActualPower != -1) {
    if (ActualPowersCooldown[ActualPower] <= 0) {
      if ((Keyboard_Recently_Released[ALLEGRO_KEY_MOUSE_LCLICK]) & (mouse_x < SCREEN_W-RSW(180))) {
          if (actual_map->IsFree(SRW(mouse_x+RSW(Camera_X)), SRH(mouse_y+RSH(Camera_Y)))) {
          if (ActualPower == 0) FlashGrenade();
          if (ActualPower == 1) SmokeGrenade();
          if (ActualPower == 2) GiftSpawn();
          if (ActualPower == 3) SantaCall();

          if (ActualPower == 0) ActualPowersCooldown[ActualPower] = 600;
          if (ActualPower == 1) ActualPowersCooldown[ActualPower] = 2200;
          if (ActualPower == 2) ActualPowersCooldown[ActualPower] = 600;
          if (ActualPower == 3) ActualPowersCooldown[ActualPower] = 600;

          ActualPowers[ActualPower] -= 1;
          ActualPower = -1;
        }
      }
      if (Keyboard_Recently_Input[ALLEGRO_KEY_MOUSE_RCLICK]) {
        ActualPower = -1;
      }
    }
    else {
      ActualPower = -1;
    }
  }
  for (int i=0; i!=4; i+=1) {
    if (ActualPowersCooldown[i] > 0) ActualPowersCooldown[i] -= DeltaTime;
    else ActualPowersCooldown[i] = 0;
  }

  if (FlashGrenadeActive) UpdateFlashGrenade();
  if (SmokeGrenadeActive) UpdateSmokeGrenade();
  if (GiftSpawnActive)    UpdateGiftSpawn();
  if (SantaCallActive)    UpdateSantaCall();
  if (ActualPower == 3)   UpdateSantaCall();
}



void DrawPowers() {
  if (FlashGrenadeActive) DrawFlashGrenade();
  if (SmokeGrenadeActive) DrawSmokeGrenade();
  if (GiftSpawnActive)    DrawGiftSpawn();
  if (SantaCallActive)    DrawSantaCall();
  if (ActualPower == 3)   DrawSantaCall();
}
