/*
Angry Moth
Copyright (C) 2006 Linley Henzell

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public Licence as published by
    the Free Software Foundation; either version 2 of the Licence, 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 Licence for more details.

    You should have received a copy of the GNU General Public Licence
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    The GPL version 2 is included in this distribution in a file called
    LICENCE.TXT. Use any text editor or the TYPE command to read it.

    You should be able to reach me by sending an email to
    l_henzell@yahoo.com.au.

File: game.c
History:


This file contains:
 - main game loop and a bit of miscellany

*/

#include "config.h"

#include "allegro.h"

#include <math.h>

#include "globvars.h"

#include "stuff.h"

#include "input.h"
#include "level.h"
#include "pbullet.h"
#include "ebullet.h"
#include "enemy.h"
//#include "display.h"
#include "cloud.h"
#include "palette.h"
#include "display.h"

#include "sound.h"

// I don't know why, but Code::Blocks refuses to recognise the contents of pickup.h. Nothing I can do.
#include "pickup.h"
void run_pickups(void);
void init_pickups(void);
//void destroy_pickup(int w, int p);
int create_pickup(int w, int colour, int x, int y);
void explode_pickup(int w, int p);



extern struct optionstruct options;





void init_player_on_new_level(void);



void begin_game(void);
void init_structs_etc(void);
//void check_player_intersect(void);

void quit_query(void);

void run_player(void);

void make_platform(void);
void run_platform(void);
void fix_platform(int y1, int y2);
int check_tile_flow(int t1, int t2);
int get_tile(int x, int y);

void player_check_pickups(void);

void platform_hline(int x1, int y, int x2);
void platform_vline(int x, int y1, int y2);

extern volatile unsigned char ticked;
extern volatile int framecounter;
extern int slacktime;
int long_slacktime;
int long_slacktime_store;

unsigned char counter;

extern int platform_tile [9] [PLAT_Y]; // in display
extern int platform_position; // in display
extern int platform_step; // in display

void init_player_on_spawn(void);

void game_loop(void)
{
 int playing = 1;

 counter = 0;

 do
 {

  arena.counter ++;
  if (player.playing)
   run_player();

 run_loops();
 if (arena.level_finished == 0
     && arena.game_over == 0)
  run_mtracks();

 get_input();
 run_level();

 run_clouds();
 run_pbullets();
 run_enemies();
 run_ebullets();
 run_pickups();
 run_underlay(); // in display.c
 run_platform();



//  play_beats();

  if (arena.game_over > 0)
  {
   arena.game_over --;
   if (arena.game_over == 1)
   {
    playing = 0;
//    kill_gameover_loop();
   }
//   if (arena.game_over == 120)
//    play_gameover_loop(1000);
  } else
   {
    if (arena.new_level_sign > 0)
     arena.new_level_sign --;
   }

  if (arena.level_finished > 0)
  {
   arena.level_finished --;
   if (arena.level_finished <= 1)
   {
    if (arena.level == 2)
     playing = 0;
    arena.level = 2;
    init_player_on_new_level();
    init_level();
    init_mtracks();
    do
    {
        slacktime ++;
    } while (ticked == 0);
    ticked = 0;
    arena.level_finished = 0;
    continue;
   }
  }

  if (ticked == 0)
  {
   run_display(1);
   framecounter++;
  }
   else
    run_display(0); // just does what is needed for collision detection


  slacktime = 0;

  do
  {
   slacktime ++;
  } while(ticked == 0);
  ticked --;

  counter ++;

  if (counter % 32 == 0)
  {
   long_slacktime_store = long_slacktime;
   long_slacktime = 0;
  }

   long_slacktime += slacktime / 100;

  if (key [KEY_ESC])
  {
      player.score = 0;
      playing = 0;
  }
   //quit_query();

 } while(playing == 1);

 if (player.score > options.highscore [arena.difficulty])
 {
  options.highscore [arena.difficulty] = player.score;
  switch(arena.difficulty)
  {
   case 0: set_config_int("Misc", "Hscore0", player.score); break;
   case 1: set_config_int("Misc", "Hscore1", player.score); break;
   case 2: set_config_int("Misc", "Hscore2", player.score); break;
  }
  arena.just_got_highscore = arena.difficulty;
 }

}

void quit_query(void)
{
/*
 if (arena.game_over > 0)
  return;

 display_quit_query();

 do
 {

  if (key [KEY_Y])
  {
   arena.game_over = 44;
   return;
  }

  if (key [KEY_N])
  {
   return;
  }

  play_beats();

  do
  {
   slacktime ++;
   slacktime = 0;
  } while(ticked == 0);

  ticked = 0;

 }
  while(TRUE);
  */
}





void new_game(void)
{
// int i;

 arena.just_got_highscore = -1;

 counter = 0;

 init_structs_etc();
 long_slacktime = 0;

// arena.level = 1;

 init_level();
 make_platform();

 arena.players = 1;
 arena.level_finished = 0;
 arena.game_over = 0;

 player.in_play = 1;
 player.playing = 1;
 player.score = 0;
 player.respawning = 0;
 player.grace = 100;

// player.pole = POLE_WHITE;
 player.recycle = 0;
 player.recycle2 = 0;
 player.switching = 0;
 player.switch_recycle = -1;
 player.bank = 0;
 player.energy = 0;
 player.charge = 0;
 player.autofire = 0;
 player.autofire_toggle = 0;

     player.weapon [0] = WPN_RED;
     player.weapon [1] = WPN_RED;
     player.power [0] = 0;
     player.power [1] = 0;

 player.red_fire = 0;
 player.blue_fire = 0;
// player.white_target = 0;
 player.green_side = 0;

  arena.player_lives = 2;
//  arena.level = 1;
//  arena.difficulty = 0;

 init_player_on_spawn();

     player.respawning = 0;
     player.grace = 0;
     player.y = 350000;

 boss.exploding = 0;


}

void init_structs_etc(void)
{
 init_pbullets();
 init_ebullets();
 init_clouds();
 init_pickups();
 arena.underlay_position = 20;
}


void run_player(void)
{

  if (player.recycle > 0)
   player.recycle --;
  if (player.recycle2 > 0)
   player.recycle2 --;
  if (player.respawning > 0)
  {
   player.respawning --;
   player.y -= 4000;
  }
  if (player.blue_fire > 0)
   blue_beam_collision();

  if (player.blue2_fire == 5)
   blue2_beam_collision();
  if (player.blue2_fire > 0)
   player.blue2_fire --;

  if (player.grace > 0)
   player.grace --;

  if (player.autofire_toggle > 0)
   player.autofire_toggle --;

  player_check_pickups();

  if (player.switch_recycle >= 0)
  {
//      if (arena.counter % 5 == 0)
   player.switch_recycle -= 2;
   if (player.switch_recycle == 10)
   {
     player.sides = player.switching;
     create_cloud(0, CLOUD_SHOCKWAVE, 2, player.x, player.y, 0, 0, 20);
     create_cloud(0, CLOUD_EXPLODE, 0, player.x, player.y, 0, 0, 14 + grand(7));
     create_cloud(1, CLOUD_SHOCKWAVE, 2, player.x, player.y, 0, 0, 20);
     create_cloud(1, CLOUD_EXPLODE, 0, player.x, player.y, 0, 0, 14 + grand(7));
   }
   if (player.switch_recycle == -1)
   {
    player.switch_recycle = -1;
   }
  }


}

void player_check_pickups(void)
{

  int p, w, vehicle = 0;

  for (w = 0; w < 2; w ++)
  {
  for (p = 0; p < NO_PICKUPS; p ++)
  {
    if (pickup[w][p].exists == 0)
     continue;

    if (pickup[w][p].x >= player.x - 18000
     && pickup[w][p].x <= player.x + 18000
     && pickup[w][p].y >= player.y - 18000
     && pickup[w][p].y <= player.y + 18000)
     {
       if (w != player.sides)
        vehicle = 1;
       player.weapon [vehicle] = pickup[w][p].colour;
       if (player.power [vehicle] < 5)
        player.power [vehicle] ++;
       player.blue_was_firing = player.blue_fire;
       player.blue_fire = 0;
       player.blue2_fire = 0;
       if (player.sides == w)
        play_effectwfvx(w, NWAV_POWERUP, 1200 + grand(150), 200, player.x);
         else
          play_effectwfvx(w, NWAV_POWERUP, 500 + grand(150), 200, player.x);
       explode_pickup(w, p);
     }


  }
  }


}


void player_hit(int side_hit)
{

 int i, angle = grand(ANGLE_1), angle2;
 int distance, speed;
 int w = 0;
 if (player.sides == 0) w = 1;
 int col1 = 0, col2 = 0;

 if (w == side_hit)
  col2 = 1;

 if (player.sides == side_hit)
  col1 = 1;



   create_cloud(w, CLOUD_SPAWNER, 0, player.x, player.y, 0, 0, 40);
   create_cloud(w, CLOUD_LARGE_SHOCKWAVE, col2, player.x, player.y, 0, 0, 50);
   create_cloud(w, CLOUD_EXPLODE, 0, player.x, player.y, 0, 0, 25 + grand(10));
   create_cloud(w, CLOUD_EXPLODE, 0, player.x + grand(10000) - grand(10000), player.y + grand(10000) - grand(10000), 0, 0, 25 + grand(10));
   create_cloud(w, CLOUD_EXPLODE, 0, player.x + grand(10000) - grand(10000), player.y + grand(10000) - grand(10000), 0, 0, 25 + grand(10));
   create_cloud(w, CLOUD_EXPLODE, 0, player.x + grand(10000) - grand(10000), player.y + grand(10000) - grand(10000), 0, 0, 25 + grand(10));
   for (i = 0; i < 3; i ++)
   {
    angle += ANGLE_4 + grand(ANGLE_4);
     speed = 2000 + grand(1000) + grand(1000);
     distance = 5000;
     angle2 = angle + grand(ANGLE_16);
//     create_cloud(CLOUD_EXPLODE, POLE_NONE, enemy[e].x + xpart(angle2, distance), enemy[e].y + ypart(angle2, distance), xpart(angle2, speed), ypart(angle2, speed), 34 + grand(7));
     create_cloud(w, CLOUD_LARGE_SPRAY, 0, player.x + xpart(angle2, distance), player.y + ypart(angle2, distance), xpart(angle2, speed), ypart(angle2, speed), 20 + grand(7));
   }
   play_effectwfvx(w, NWAV_BIGBANG, 500 + grand(350), 200, player.x);



   create_cloud(player.sides, CLOUD_SPAWNER, 0, player.x, player.y, 0, 0, 20);
   create_cloud(player.sides, CLOUD_SHOCKWAVE, col1, player.x, player.y, 0, 0, 20);
   create_cloud(player.sides, CLOUD_EXPLODE, 0, player.x, player.y, 0, 0, 20 + grand(10));
   create_cloud(player.sides, CLOUD_EXPLODE, 0, player.x + grand(6000) - grand(6000), player.y + grand(6000) - grand(6000), 0, 0, 20 + grand(10));
   create_cloud(player.sides, CLOUD_EXPLODE, 0, player.x + grand(6000) - grand(6000), player.y + grand(6000) - grand(6000), 0, 0, 20 + grand(10));
   create_cloud(player.sides, CLOUD_EXPLODE, 0, player.x + grand(6000) - grand(6000), player.y + grand(6000) - grand(6000), 0, 0, 20 + grand(10));
   play_effectwfvx(player.sides, NWAV_BLAST, 1000 + grand(350), 100, player.x);


/*   for (i = 0; i < 3; i ++)
   {
    angle += ANGLE_4 + grand(ANGLE_4);
     speed = 2000 + grand(1000) + grand(1000);
     distance = 5000;
     angle2 = angle + grand(ANGLE_16);
//     create_cloud(CLOUD_EXPLODE, POLE_NONE, enemy[e].x + xpart(angle2, distance), enemy[e].y + ypart(angle2, distance), xpart(angle2, speed), ypart(angle2, speed), 34 + grand(7));
     create_cloud(w, CLOUD_LARGE_SPRAY, 0, player.x + xpart(angle2, distance), player.y + ypart(angle2, distance), xpart(angle2, speed), ypart(angle2, speed), 20 + grand(7));
   }*/

/* create_cloud(CLOUD_SHOCKWAVE, POLE_NONE, player.x, player.y, 0, 0, 20);
 create_cloud(CLOUD_EXPLODE, POLE_NONE, player.x, player.y, 0, 0, 14 + grand(7));
 for (i = 0; i < 3; i ++)
 {
  angle += ANGLE_4 + grand(ANGLE_4);
  for (j = 0; j < 5; j ++)
  {
   speed = 2000 + grand(3500) + grand(3000);
   distance = 3000;
   angle2 = angle + grand(ANGLE_16);
   create_cloud(CLOUD_DRAG_EXPLODE, POLE_NONE, player.x + xpart(angle2, distance), player.y + ypart(angle2, distance), xpart(angle2, speed), ypart(angle2, speed), 20 + grand(10));
  }
 }*/
 //int not_p = 0;

// if (p == 0)
  //not_p = 1;

// player.in_play = 0;
 if (arena.player_lives == 0)
 {
//  trigger_game_over();
  player.in_play = 0;
  arena.game_over = 200;
  arena.level_finished = 0;
 }
  else
  {
    arena.player_lives --;
    if (arena.player_lives > -1)
    {
        init_player_on_spawn();
    }
  }
// need to add a respawning thing to the extend function

}


void init_player_on_spawn(void)
{

     player.respawning = 75;
     player.grace = 220;
     player.y = 700000;
     player.x = 160000;
     player.charge = 0;
     player.weapon [0] = WPN_RED;
     player.weapon [1] = WPN_RED;
     player.power [0] = 0;
     player.power [1] = 0;
     player.red_fire = 0;
     player.blue_was_firing = player.blue_fire;
     player.blue_fire = 0;
     player.blue2_fire = 0;
     player.green_side = 0;
     player.white_recycle1 = 1;
     player.white_recycle2 = 1;
     player.recycle = 2;
     player.bank = 0;
// MAY NEED TO ADD BELOW!!!
}

void init_player_on_new_level(void)
{

     player.respawning = 0;
     player.grace = 0;
     player.y = 350000;
     player.x = 160000;
     player.charge = 0;
     player.red_fire = 0;
     player.blue_was_firing = player.blue_fire;
     player.blue_fire = 0;
     player.blue2_fire = 0;
     player.green_side = 0;
     player.white_recycle1 = 1;
     player.white_recycle2 = 1;
     player.recycle = 2;
     player.bank = 0;
// MAY NEED TO ADD ABOVE!!!

}



void make_platform(void)
{

 int i, j;
 platform_position = 0;
 platform_step = 0;

 int vert1 = grand(6) + 2;
 int vert2 = 0;

 int v21 = -1;
 int v22 = -1;


 for (j = 0; j < PLAT_Y; j ++)
 {
  for (i = 0; i < 9; i ++)
  {
   platform_tile [i] [j] = PLATFORM_EMPTY; // empty
  }
 }



 for (j = 0; j < PLAT_Y; j ++)
 {

   if (grand(7) == 0)
   {
       vert2 = vert1;
       vert1 = grand(6) + 2;
       //platform_hline(vert1, j, vert2);
       platform_hline(vert1, j, vert2);
   }

   if (grand(5) == 0)
   {
    if (grand(3) == 0)
     v21 = -1;
      else
      {
          v22 = v21;
          v21 = grand(7) + 2;
          platform_hline(v21, j, v22);
      }
   }

   if (grand(21) == 0)
    platform_hline(0, j, 8);

   if (grand(21) == 0)
    platform_hline(grand(6), j, 8);

   if (grand(21) == 0)
    platform_hline(0, j, grand(4) + 5);

  for (i = 0; i < 9; i ++)
  {
//   platform_tile [i] [j] = PLATFORM_EMPTY; // empty

   if (i == v21)
     platform_tile [i] [j] = 1;

   if (i == vert1)
     platform_tile [i] [j] = 1;

   if (grand(7) == 0)
    platform_tile [i] [j] = 1;
  }
 }

 fix_platform(0, PLAT_Y);

}

void platform_hline(int x1, int y, int x2)
{
 int i;

 if (x1 < 0) x1 = 0;
 if (x1 > 8) x1 = 8;
 if (x2 < 0) x2 = 0;
 if (x2 > 8) x2 = 8;

 if (x2 > x1)
 {
  for (i = x1; i < x2; i ++)
  {
     platform_tile [i] [y] = 1;
  }
 }
   else
    for (i = x2; i < x1; i ++)
    {
       platform_tile [i] [y] = 1;
    }


}
/*
void platform_vline(int x, int y1, int y2)
{
 int i;


 if (y2 > y1)
 {
  for (i = y1; i < y2; i ++)
  {
     platform_tile [x] [i] = 1;
  }
 }
   else
    for (i = y2; i < y1; i ++)
    {
     platform_tile [x] [i] = 1;
    }
}*/

void run_platform(void)
{

 platform_position += 4;
 if (platform_position >= 55)
 {
  platform_position -= 55;
  platform_step ++;
 }
 if (platform_step > PLAT_Y)
  platform_step -= PLAT_Y;

}

void fix_platform(int y1, int y2)
{
 int i, j, tile;

 for (i = 0; i < 9; i ++)
 {
  for (j = y1; j < y2; j ++)
  {
      if (platform_tile [i] [j] == PLATFORM_EMPTY)
       continue;
      tile = PLATFORM_NODE; // need to fix this
      if (get_tile(i - 1, j) != PLATFORM_EMPTY)
       tile = PLATFORM_L;
      if (get_tile(i + 1, j) != PLATFORM_EMPTY)
       tile = PLATFORM_R;
      if (get_tile(i, j + 1) != PLATFORM_EMPTY)
       tile = PLATFORM_U;
      if (get_tile(i, j - 1) != PLATFORM_EMPTY)
       tile = PLATFORM_D;

      if (get_tile(i - 1, j) != PLATFORM_EMPTY && get_tile(i + 1, j) != PLATFORM_EMPTY)
       tile = PLATFORM_LR_TLR;
      if (get_tile(i, j - 1) != PLATFORM_EMPTY && get_tile(i, j + 1) != PLATFORM_EMPTY)
       tile = PLATFORM_UD_TUD;

      if (get_tile(i + 1, j) != PLATFORM_EMPTY && get_tile(i, j + 1) != PLATFORM_EMPTY)
       tile = PLATFORM_UR;
      if (get_tile(i - 1, j) != PLATFORM_EMPTY && get_tile(i, j - 1) != PLATFORM_EMPTY)
       tile = PLATFORM_DL;
      if (get_tile(i + 1, j) != PLATFORM_EMPTY && get_tile(i, j - 1) != PLATFORM_EMPTY)
       tile = PLATFORM_DR;
      if (get_tile(i - 1, j) != PLATFORM_EMPTY && get_tile(i, j + 1) != PLATFORM_EMPTY)
       tile = PLATFORM_UL;

      if (get_tile(i + 1, j) != PLATFORM_EMPTY
          && get_tile(i, j + 1) != PLATFORM_EMPTY
          && get_tile(i, j - 1) != PLATFORM_EMPTY)
       tile = PLATFORM_UDL;

      if (get_tile(i - 1, j) != PLATFORM_EMPTY
          && get_tile(i, j + 1) != PLATFORM_EMPTY
          && get_tile(i, j - 1) != PLATFORM_EMPTY)
       tile = PLATFORM_UDR;

      if (get_tile(i - 1, j) != PLATFORM_EMPTY
          && get_tile(i + 1, j) != PLATFORM_EMPTY
          && get_tile(i, j - 1) != PLATFORM_EMPTY)
       tile = PLATFORM_DLR;

      if (get_tile(i - 1, j) != PLATFORM_EMPTY
          && get_tile(i + 1, j) != PLATFORM_EMPTY
          && get_tile(i, j + 1) != PLATFORM_EMPTY)
       tile = PLATFORM_ULR;

      if (get_tile(i - 1, j) == PLATFORM_EMPTY
          && get_tile(i + 1, j) == PLATFORM_EMPTY
          && get_tile(i, j - 1) == PLATFORM_EMPTY
          && get_tile(i, j + 1) == PLATFORM_EMPTY)
       tile = PLATFORM_EMPTY;

      if (get_tile(i - 1, j) != PLATFORM_EMPTY
          && get_tile(i + 1, j) != PLATFORM_EMPTY
          && get_tile(i, j - 1) != PLATFORM_EMPTY
          && get_tile(i, j + 1) != PLATFORM_EMPTY)
       tile = PLATFORM_NODE;

       platform_tile [i] [j] = tile;

  }
 }

 int t = 0;

 for (i = 0; i < 9; i ++)
 {
  for (j = y1; j < y2; j ++)
  {
      t = get_tile(i, j);
      if (t == PLATFORM_LR_TLR)
      {
       if (check_tile_flow(t, get_tile(i + 1, j)))
        t = PLATFORM_LR_TL;
       if (check_tile_flow(t, get_tile(i - 1, j)))
        t = PLATFORM_LR_TR;
       if (check_tile_flow(t, get_tile(i - 1, j)) && check_tile_flow(t, get_tile(i + 1, j)))
        t = PLATFORM_LR;
      }
      if (t == PLATFORM_UD_TUD)
      {
       if (check_tile_flow(t, get_tile(i, j + 1)))
        t = PLATFORM_UD_TU;
       if (check_tile_flow(t, get_tile(i, j - 1)))
        t = PLATFORM_UD_TD;
       if (check_tile_flow(t, get_tile(i, j - 1)) && check_tile_flow(t, get_tile(i, j + 1)))
        t = PLATFORM_UD;
      }
    platform_tile [i] [j] = t;
  }
 }

 for (i = 0; i < 9; i ++)
 {
  for (j = y1; j < y2; j ++)
  {
    if (get_tile(i, j) == PLATFORM_D
        && get_tile(i, j + 1) == PLATFORM_U)
        {
         platform_tile [i] [j] = PLATFORM_EMPTY;
         platform_tile [i] [j + 1] = PLATFORM_EMPTY;
        }
  }
 }

}

int check_tile_flow(int t1, int t2)
{
 if (t1 == PLATFORM_LR_TLR
     || t1 == PLATFORM_LR_TL
     || t1 == PLATFORM_LR_TR
     || t1 == PLATFORM_LR)
 {
  if (t2 == PLATFORM_LR_TLR
      || t2 == PLATFORM_LR_TR
      || t2 == PLATFORM_LR_TL
      || t2 == PLATFORM_LR)
       return 1;
  return 0;
 }
 if (t1 == PLATFORM_UD_TUD
     || t1 == PLATFORM_UD_TU
     || t1 == PLATFORM_UD_TD
     || t1 == PLATFORM_UD)
 {
  if (t2 == PLATFORM_UD_TUD
      || t2 == PLATFORM_UD_TU
      || t2 == PLATFORM_UD_TD
      || t2 == PLATFORM_UD)
       return 1;
  return 0;
 }
 return 0;
}

int get_tile(int x, int y)
{
/* if (x == -1 && y == -1)
  return -1;//platform_tile [8] [PLAT_Y - 1];
 if (x == -1 && y == PLAT_Y)
  return -1;//platform_tile [8] [0];
 if (x == 9 && y == -1)
  return -1;//platform_tile [0] [PLAT_Y - 1];
 if (x == 9 && y == PLAT_Y)
  return -1;//platform_tile [0] [0];
 if (x == -1)
  return -1;//platform_tile [8] [y];
 if (x == 9)
  return -1;//platform_tile [0] [y];
 if (y == -1)
  return -1;//platform_tile [x] [PLAT_Y - 1];
 if (y == PLAT_Y)
  return -1;*///platform_tile [x] [0];
   if (x == -1 && y == -1)
  return platform_tile [8] [PLAT_Y - 1];
 if (x == -1 && y == PLAT_Y)
  return platform_tile [8] [0];
 if (x == 9 && y == -1)
  return platform_tile [0] [PLAT_Y - 1];
 if (x == 9 && y == PLAT_Y)
  return platform_tile [0] [0];
 if (x == -1)
  return platform_tile [8] [y];
 if (x == 9)
  return platform_tile [0] [y];
 if (y == -1)
  return platform_tile [x] [PLAT_Y - 1];
 if (y == PLAT_Y)
  return platform_tile [x] [0];

 return platform_tile [x] [y];


}
