#include "Graphics.h"

#define PLAYER_Y_START 100
#define PLAYER_X_SPEED 10
#define MAX_NPCS 5
#define MAX_STARS 10
#define MAX_PROJECTILES 10

//#defene PROFILE(X) lastprofile = clock(); X; printf("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t%s %i\n", #X, (clock() - lastprofile))
#define PROFILE(X) X

enum sprite_e{player_ship, durno_ship, ship_trgt, durno_ship2, ship2_trgt, player_shipl,player_shipr,explode_start,explode_shp2,explode_shp3,explode_end,photon1,photon2,plasma1,plasma2};
char *sprites[] = {"player_ship","durno_ship","ship_trgt","durno_ship2","ship2_trgt","player_shipl","player_shipr","explode_shp1","explode_shp2","explode_shp3","explode_shp4","photon1","photon2","plasma1","plasma2"};

char hudbuffer[63];

struct EntityLocation_s {
  short signed int X,Y;
};

enum npctype_e{bigdurno, littledurno,maxnpctype};

struct NPC_s {
  struct EntityLocation_s location;
  enum sprite_e idlesprite;
  enum sprite_e sprite;
  enum sprite_e weaponspritestart;
  enum sprite_e weaponspriteend;
  enum npctype_e npctype;
  struct EntityLocation_s velocity;
  int health;
  struct EntityLocation_s hitbox_bl;
  struct EntityLocation_s hitbox_tr;
  int collideforce;
  int collidable;
  int explodenextframe;
  int nextfire;
  int fireinterval;
  int firewidth;
};

struct Star_s {
  struct EntityLocation_s location;
  unsigned char length;
};

struct Player_s {
  struct EntityLocation_s location;
  enum sprite_e idlesprite;
  enum sprite_e sprite;
  unsigned char velocity;
  int nextidlesprite;
  int shields;
  int nextshieldheal;
  int integrity;
  int remainingdistance;
  struct EntityLocation_s hitbox_bl;
  struct EntityLocation_s hitbox_tr;
  struct EntityLocation_s phaser1;
  struct EntityLocation_s phaser2;
  int targetleft;
  int targetright;
  short int firingleft;
  short int firingright;
  int phaserdamage;
};

struct Projectile_s {
  struct EntityLocation_s location;
  enum sprite_e sprite;
  enum sprite_e spritestart;
  enum sprite_e spriteend;
  struct EntityLocation_s velocity;
  int collidable;
  int nextframe;
  short int active;
  int damage;
};

struct Star_s Stars[MAX_STARS];
struct NPC_s NPCS[MAX_NPCS];
struct Projectile_s Projectiles[MAX_PROJECTILES];
struct Player_s Player;

extern void game_respawn_npc(int id);
extern int tick;
extern int lasttick;

enum debugs_e{dbbase,dbhitbox,dbweapons,dbinput,dbperformance,dbnpcs,dbprojectiles,dbmax};
int debugs[dbmax];

enum colour_e{lcars_black,lcars_violet1,debugpink,stargrey,debuggreen,phaserorange1,phaserorange2};
int colours[] = {0x11111100,0xc4727200,0xcc00ff00,0x66666600,0x00ff0000,0x0053ff00,0x00d5ff00};

void game_spawn_projectile(int id, int Px, int Py, int Vx, int Vy, enum sprite_e spritestart, enum sprite_e spriteend, int damage)
{
  int i;
  
  if(id < 0)
  {
    for(i = 0; i < MAX_PROJECTILES; i++)
    {
        if(Projectiles[i].active == 0)
          id = i;
    }
  }

  // If no velocity X specified we're targetting the player
  if(Vx == 0)
  {
    int V;
    int Xdistance = abs((Player.location.X + (Player.hitbox_tr.X/2)) - Px);
    int Ydistance = abs((Player.location.Y + (Player.hitbox_tr.Y/2)) - Py);
    int distance = sqrt((Xdistance^2) + (Ydistance^2));
    V = Vy;
    Vx = Xdistance / (distance / Vy);
    Vy = Ydistance / (distance / Vy);

    if(Player.location.X > Px)
      Vx = 0 - Vx;
  }

  // If it's too close to horizontal you can't dodge
  if(Py < (Player.location.X + 100))
    id = -1;
  
  //If no free IDs then we go without
  if(id >= 0)
  {
    Projectiles[id].location.X = Px;
    Projectiles[id].location.Y = Py;
    Projectiles[id].velocity.X = Vx;
    Projectiles[id].velocity.Y = Vy;
    Projectiles[id].active = 1;
    Projectiles[id].sprite = spritestart;
    Projectiles[id].spritestart = spritestart;
    Projectiles[id].spriteend = spriteend;
    Projectiles[id].nextframe = tick + 10;
    Projectiles[id].damage = damage;
    Projectiles[id].collidable = 1;
  }

}

void game_draw_player()
{
  draw_sprite(sprites[Player.sprite], Player.location.X, Player.location.Y);

  if(debugs[dbhitbox])
  {
    graphics_colour(colours[debugpink]);

    // Bounding box debug
    draw_rectangle(
      Player.location.X + Player.hitbox_bl.X,
      Player.location.Y + Player.hitbox_bl.Y,
      Player.location.X + Player.hitbox_tr.X,
      Player.location.Y + Player.hitbox_tr.Y
    );
  }

  if((Player.firingleft) && (Player.targetleft >= 0))
  {
    graphics_colour(colours[phaserorange1]);
    draw_line(
      Player.location.X + Player.phaser1.X,
      Player.location.Y + Player.phaser1.Y,
      NPCS[Player.targetleft].location.X + ((NPCS[Player.targetleft].hitbox_bl.X + NPCS[Player.targetleft].hitbox_tr.X)/2),
      NPCS[Player.targetleft].location.Y + NPCS[Player.targetleft].hitbox_bl.Y
    );
    graphics_colour(colours[phaserorange2]);
    draw_dotted_line(
      Player.location.X + Player.phaser1.X + 1,
      Player.location.Y + Player.phaser1.Y,
      NPCS[Player.targetleft].location.X + ((NPCS[Player.targetleft].hitbox_bl.X + NPCS[Player.targetleft].hitbox_tr.X)/2) + 1,
      NPCS[Player.targetleft].location.Y + NPCS[Player.targetleft].hitbox_bl.Y
    );
    draw_dotted_line(
      Player.location.X + Player.phaser1.X - 1,
      Player.location.Y + Player.phaser1.Y,
      NPCS[Player.targetleft].location.X + ((NPCS[Player.targetleft].hitbox_bl.X + NPCS[Player.targetleft].hitbox_tr.X)/2) - 1,
      NPCS[Player.targetleft].location.Y + NPCS[Player.targetleft].hitbox_bl.Y
    );
  }

  if((Player.firingright) && (Player.targetright >= 0))
  {
    graphics_colour(colours[phaserorange1]);
    draw_line(
      Player.location.X + Player.phaser2.X,
      Player.location.Y + Player.phaser2.Y,
      NPCS[Player.targetright].location.X + ((NPCS[Player.targetright].hitbox_bl.X + NPCS[Player.targetright].hitbox_tr.X)/2),
      NPCS[Player.targetright].location.Y + NPCS[Player.targetright].hitbox_bl.Y
    );
    graphics_colour(colours[phaserorange2]);
    draw_dotted_line(
      Player.location.X + Player.phaser2.X + 1,
      Player.location.Y + Player.phaser2.Y,
      NPCS[Player.targetright].location.X + ((NPCS[Player.targetright].hitbox_bl.X + NPCS[Player.targetright].hitbox_tr.X)/2) + 1,
      NPCS[Player.targetright].location.Y + NPCS[Player.targetright].hitbox_bl.Y
    );
    draw_dotted_line(
      Player.location.X + Player.phaser2.X - 1,
      Player.location.Y + Player.phaser2.Y,
      NPCS[Player.targetright].location.X + ((NPCS[Player.targetright].hitbox_bl.X + NPCS[Player.targetright].hitbox_tr.X)/2) - 1,
      NPCS[Player.targetright].location.Y + NPCS[Player.targetright].hitbox_bl.Y
    );
  }

  if(debugs[dbweapons])
  {
    graphics_colour(colours[debuggreen]);

    // Draw phaser banks
    draw_line(
      Player.location.X + Player.phaser1.X,
      Player.location.Y + Player.phaser1.Y -5,
      Player.location.X + Player.phaser1.X,
      Player.location.Y + Player.phaser1.Y + 5
    );
    draw_line(
      Player.location.X + Player.phaser1.X -5,
      Player.location.Y + Player.phaser1.Y,
      Player.location.X + Player.phaser1.X +5,
      Player.location.Y + Player.phaser1.Y 
    );
    draw_line(
      Player.location.X + Player.phaser2.X,
      Player.location.Y + Player.phaser2.Y -5,
      Player.location.X + Player.phaser2.X,
      Player.location.Y + Player.phaser2.Y + 5
    );
    draw_line(
      Player.location.X + Player.phaser2.X -5,
      Player.location.Y + Player.phaser2.Y,
      Player.location.X + Player.phaser2.X +5,
      Player.location.Y + Player.phaser2.Y 
    );
  }
}

void game_draw_npcs()
{
  int i;
  for(i = 0; i < MAX_NPCS; i++)
  {
    // Don't bother if they are off the screen
    if(NPCS[i].location.Y < DISPLAY_Y)
    {
      draw_sprite(sprites[NPCS[i].sprite], NPCS[i].location.X, NPCS[i].location.Y);

      // Next sprite up in index is the appropriate target icon
      if(Player.targetleft == i)
        draw_sprite(sprites[NPCS[i].sprite + 1], NPCS[i].location.X, NPCS[i].location.Y);
      if(Player.targetright == i)
        draw_sprite(sprites[NPCS[i].sprite + 1], NPCS[i].location.X, NPCS[i].location.Y);

      if(tick > NPCS[i].explodenextframe)
      {
        if((NPCS[i].sprite >= explode_start) && (NPCS[i].sprite <= explode_end))
        {
          NPCS[i].sprite++;
          if(NPCS[i].sprite > explode_end)
            game_respawn_npc(i);
        }
        NPCS[i].explodenextframe = tick + 4;
      }
      
      if(debugs[dbhitbox])
      {
        graphics_colour(colours[debugpink]);

        // Bounding box debug
        draw_rectangle(
          NPCS[i].location.X + NPCS[i].hitbox_bl.X,
          NPCS[i].location.Y + NPCS[i].hitbox_bl.Y,
          NPCS[i].location.X + NPCS[i].hitbox_tr.X,
          NPCS[i].location.Y + NPCS[i].hitbox_tr.Y
        );
      }
    }
  }
}

void game_draw_projectiles()
{
  int i;
  for(i = 0; i < MAX_PROJECTILES; i++)
  {
    if(Projectiles[i].active == 0)
      continue;

    draw_sprite(sprites[Projectiles[i].sprite], Projectiles[i].location.X,Projectiles[i].location.Y);
    Projectiles[i].sprite++;
    if(Projectiles[i].sprite > Projectiles[i].spriteend)
      Projectiles[i].sprite = Projectiles[i].spritestart;
  }
}

void game_draw_stars()
{
  unsigned char i;
  graphics_colour(colours[stargrey]);
  for(i = 0; i < MAX_STARS; i++)
  {
    draw_line(Stars[i].location.X,Stars[i].location.Y,Stars[i].location.X,Stars[i].location.Y+Stars[i].length);
  }
}

void game_setup_player()
{
  Player.location.X = DISPLAY_X/2;
  Player.location.Y = PLAYER_Y_START;
  Player.sprite = player_ship;
  Player.idlesprite = player_ship;
  Player.velocity = 100;
  Player.shields = 100;
  Player.integrity = 100;
  Player.remainingdistance = 1500000;
  Player.hitbox_bl.X = 0;
  Player.hitbox_bl.Y = 0;
  Player.hitbox_tr.X = 60;
  Player.hitbox_tr.Y = 81;
  Player.phaser1.X = 20;
  Player.phaser1.Y = 75;
  Player.phaser2.X = 41;
  Player.phaser2.Y = 75;
  Player.targetleft = -1;
  Player.targetright = -1;
  Player.firingleft = 0;
  Player.firingright = 0;
  Player.phaserdamage = 10;
}

void game_tick_stars()
{
  int i;
  for(i = 0; i < MAX_STARS; i++)
  {
    Stars[i].location.Y -= (tick - lasttick) * 4;
    if((Stars[i].location.Y + Stars[i].length) <= 0)
    {
      Stars[i].length = 20 + (rand() % 10);
      Stars[i].location.X = rand() % DISPLAY_X;
      Stars[i].location.Y = DISPLAY_Y + Stars[i].length;
    }
  }
}

void game_setup_stars()
{
  int i;
  for(i = 0; i < MAX_STARS; i++)
  {
    Stars[i].length = 20 + (rand() % 10);
    Stars[i].location.X = rand() % DISPLAY_X;
    Stars[i].location.Y = rand() % DISPLAY_Y;
  }
}

void game_setup_input()
{
  /*
    inreg.r[0] = 4;
  inreg.r[1] = 1;
  _kernel_swi(OS_Byte,&inreg,&outreg);
  */
}

void game_respawn_npc(int id)
{
  NPCS[id].location.X = rand() % DISPLAY_X;
  NPCS[id].location.Y = DISPLAY_Y + (rand() % (DISPLAY_Y/2));
  if((rand() % 10) > 3)
    NPCS[id].npctype = littledurno;
  else
    NPCS[id].npctype = bigdurno;
  NPCS[id].collidable = 1;
  NPCS[id].nextfire = tick + (rand() % 100);
    switch(NPCS[id].npctype)
    {
      case bigdurno:
        NPCS[id].idlesprite = durno_ship;
        NPCS[id].sprite = durno_ship;
        NPCS[id].velocity.X = 0;
        NPCS[id].velocity.Y = (rand() % 3) + 1;
        NPCS[id].health = 1000;
        NPCS[id].hitbox_bl.X = 0;
        NPCS[id].hitbox_bl.Y = 0;
        NPCS[id].hitbox_tr.X = 48;
        NPCS[id].hitbox_tr.Y = 74;
        NPCS[id].collideforce = 1000;
        NPCS[id].weaponspritestart = photon1;
        NPCS[id].weaponspriteend = photon2;
        NPCS[id].fireinterval = 200;
        NPCS[id].firewidth = 400;
        break;
      case littledurno:
        NPCS[id].idlesprite = durno_ship2;
        NPCS[id].sprite = durno_ship2;
        NPCS[id].velocity.X = (rand() % 1) - 2;
        NPCS[id].velocity.Y = (rand() % 2) + 3;
        NPCS[id].health = 300;
        NPCS[id].hitbox_bl.X = 0;
        NPCS[id].hitbox_bl.Y = 0;
        NPCS[id].hitbox_tr.X = 38;
        NPCS[id].hitbox_tr.Y = 56;
        NPCS[id].collideforce = 50;
        NPCS[id].weaponspritestart = plasma1;
        NPCS[id].weaponspriteend = plasma2;
        NPCS[id].fireinterval = 80;
        NPCS[id].firewidth = 60;
        break;
    };
}

void game_setup_npcs()
{
  int i;
  for(i = 0; i < MAX_NPCS; i++)
  {
    game_respawn_npc(i);
    NPCS[i].location.Y += 400;
  }
}

void game_tick_npcs()
{
  int i;
  for(i = 0; i < MAX_NPCS; i++)
  {
    NPCS[i].location.Y -= (tick - lasttick) * NPCS[i].velocity.Y;
    NPCS[i].location.X -= (tick - lasttick) * NPCS[i].velocity.X;

    if(NPCS[i].npctype == littledurno)
    {
      if(NPCS[i].location.Y > (Player.location.Y + 500))
      {
        if(abs(NPCS[i].location.X - Player.location.X) > 100)
        {
          if(NPCS[i].location.X < Player.location.X)
            NPCS[i].velocity.X = 0 - abs(NPCS[i].velocity.X);
          else
            NPCS[i].velocity.X = abs(NPCS[i].velocity.X);
        }
      }else{
        if(NPCS[i].velocity.X > 0)
         NPCS[i].velocity.X = 1;
        else
         NPCS[i].velocity.X = -1;
      }
    }

    if(NPCS[i].location.Y + NPCS[i].hitbox_tr.Y <= 0)
      game_respawn_npc(i);
    
    if((NPCS[i].location.X + NPCS[i].hitbox_tr.X) > DISPLAY_X)
      game_respawn_npc(i);
    
    if((NPCS[i].location.X + NPCS[i].hitbox_bl.X) < 0)
      game_respawn_npc(i);

    if(tick > NPCS[i].nextfire)
    {
      // Dont fire if off screen
      if((NPCS[i].location.Y < DISPLAY_Y))
      {
        if((NPCS[i].firewidth == -1) || (abs(Player.location.X - NPCS[i].location.X) < NPCS[i].firewidth))
        {
          if(NPCS[i].weaponspritestart == photon1)
            game_spawn_projectile(-1,NPCS[i].location.X, NPCS[i].location.Y, 0, 10, NPCS[i].weaponspritestart, NPCS[i].weaponspriteend, 60);
          else
            game_spawn_projectile(-1,NPCS[i].location.X, NPCS[i].location.Y, 0, 10, NPCS[i].weaponspritestart, NPCS[i].weaponspriteend, 20);
          NPCS[i].nextfire = tick + NPCS[i].fireinterval;
        }
      }
    }

    if(NPCS[i].health <= 0)
    {
      if(NPCS[i].sprite == NPCS[i].idlesprite)
      {
        NPCS[i].collidable = 0;
        NPCS[i].sprite = explode_start;
        NPCS[i].explodenextframe = tick + 4;
        sound_play(1,-5,0,100);
        sound_play(3,-15,0,1000);
        sound_play(2,-10,1,100);
      }
    }
  }
}

void game_draw_debugmenu()
{
/*  int i;
  if(debugs[dbbase])
  {
    font_colour(colours[debuggreen],colours[lcars_black],font[sys_12_8]);
    draw_text("Debug List",DISPLAY_X-200,DISPLAY_Y-40,font[sys_12_8]);
    font_colour(colours[debugs[dbhitbox]?debugpink:stargrey],colours[lcars_black],font[sys_12_8]);
    draw_text("1: hitbox",DISPLAY_X-200,DISPLAY_Y-60,font[sys_12_8]);
    font_colour(colours[debugs[dbweapons]?debugpink:stargrey],colours[lcars_black],font[sys_12_8]);
    draw_text("2: weapons",DISPLAY_X-200,DISPLAY_Y-80,font[sys_12_8]);
    font_colour(colours[debugs[dbinput]?debugpink:stargrey],colours[lcars_black],font[sys_12_8]);
    draw_text("3: input",DISPLAY_X-200,DISPLAY_Y-100,font[sys_12_8]);
    font_colour(colours[debugs[dbperformance]?debugpink:stargrey],colours[lcars_black],font[sys_12_8]);
    draw_text("4: performance",DISPLAY_X-200,DISPLAY_Y-120,font[sys_12_8]);
    font_colour(colours[debugs[dbnpcs]?debugpink:stargrey],colours[lcars_black],font[sys_12_8]);
    draw_text("5: NPCs",DISPLAY_X-200,DISPLAY_Y-140,font[sys_12_8]);
    font_colour(colours[debugs[dbprojectiles]?debugpink:stargrey],colours[lcars_black],font[sys_12_8]);
    draw_text("6: Projectiles",DISPLAY_X-200,DISPLAY_Y-160,font[sys_12_8]);
  }

  if(debugs[dbperformance])
  {
    font_colour(colours[debuggreen],colours[lcars_black],font[sys_12_8]);
    sprintf(hudbuffer,"CPF: %i",(tick-lasttick));
    draw_text(hudbuffer,DISPLAY_X-500,DISPLAY_Y-60,font[sys_12_8]);
  }

  if(debugs[dbnpcs])
  {
    font_colour(colours[debuggreen],colours[lcars_black],font[sys_12_8]);
    for(i = 0; i < MAX_NPCS; i++)
    {
      sprintf(hudbuffer,"NPCS[%i] %i%i,%i %i,%i %i",i,NPCS[i].health,NPCS[i].velocity.X,NPCS[i].velocity.Y,NPCS[i].location.X,NPCS[i].location.Y);
      draw_text(hudbuffer,DISPLAY_X-800,DISPLAY_Y-60-(i * 20),font[sys_12_8]);
    }
  }

  if(debugs[dbprojectiles])
  {
    font_colour(colours[debuggreen],colours[lcars_black],font[sys_12_8]);
    for(i = 0; i < MAX_PROJECTILES; i++)
    {
      sprintf(hudbuffer,"Projectiles[%i] %i %i,%i %i,%i",i,Projectiles[i].active,Projectiles[i].velocity.X,Projectiles[i].velocity.Y,Projectiles[i].location.X,Projectiles[i].location.Y);
      draw_text(hudbuffer,DISPLAY_X-800,DISPLAY_Y-60-(i * 20),font[sys_12_8]);
    }
  }*/
}

void game_tick_collider()
{
  int i;
  for(i = 0; i < MAX_NPCS; i++)
  {
    if(!NPCS[i].collidable)
      continue;
    // Excuse this formatting
    if(
      game_hitbox_collide(
        (Player.location.X + Player.hitbox_bl.X),(Player.location.Y + Player.hitbox_bl.Y),
        (Player.hitbox_tr.X - Player.hitbox_bl.X),(Player.hitbox_tr.Y - Player.hitbox_bl.Y),
        (NPCS[i].location.X + NPCS[i].hitbox_bl.X),(NPCS[i].location.Y + NPCS[i].hitbox_bl.Y),
        (NPCS[i].hitbox_tr.X - NPCS[i].hitbox_bl.X),(NPCS[i].hitbox_tr.Y - NPCS[i].hitbox_bl.Y)
      )
    )
    {

      /*if(debugs[dbhitbox])
      {
        font_colour(colours[debuggreen],colours[lcars_black],font[sys_12_8]);
        sprintf(hudbuffer,"NPCS[%i] hits player",i,NPCS[i].location.X,NPCS[i].location.Y);
        draw_text(hudbuffer,DISPLAY_X-900,DISPLAY_Y-260-(i * 20),font[sys_12_8]);
      }*/

      NPCS[i].health -= 300;
      NPCS[i].collidable = 0;
      NPCS[i].velocity.Y = NPCS[i].velocity.Y / 2;
      NPCS[i].velocity.X = NPCS[i].velocity.X * 4;

      Player.shields -= NPCS[i].collideforce;
      if(Player.shields < 0)
      {
        Player.integrity += Player.shields;
        Player.shields = 0;
      }
    }
  }

  for(i = 0; i < MAX_PROJECTILES; i++)
  {
    if(!Projectiles[i].active)
      continue;
    if(!Projectiles[i].collidable)
      continue;
    // Excuse this formatting
    if(
      game_hitbox_collide(
        (Player.location.X + Player.hitbox_bl.X),(Player.location.Y + Player.hitbox_bl.Y),
        (Player.hitbox_tr.X - Player.hitbox_bl.X),(Player.hitbox_tr.Y - Player.hitbox_bl.Y),
        Projectiles[i].location.X,Projectiles[i].location.Y,
        10,10
      )
    )
    {
      sound_play(2,-5, 20,1);
      Projectiles[i].active = 0;
      Player.shields -= Projectiles[i].damage;
      if(Player.shields < 0)
      {
        Player.integrity += Player.shields;
        Player.shields = 0;
      }
    }
  }
}

void game_tick_player_targets()
{
  int i;
  int NoseX = Player.location.X + Player.hitbox_bl.X + (Player.hitbox_tr.X/2);
  int NoseXLeft = Player.location.X + Player.hitbox_bl.X;
  int NoseXRight = Player.location.X + Player.hitbox_bl.X  + Player.hitbox_tr.X;
  int NoseY = Player.location.Y + + Player.hitbox_bl.Y  + Player.hitbox_tr.Y;
  int LeftDistance = 1000;
  int RightDistance = 1000;
  int LeftCornerX, LeftCornerY, RightCornerX,DistanceX,DistanceY;
  Player.targetleft = -1;
  Player.targetright = -1;

  for(i = 0; i < MAX_NPCS; i++)
  {
    if(!NPCS[i].collidable)
      continue;
    if(NPCS[i].location.Y > (DISPLAY_Y-50))
      continue;
    LeftCornerX = NPCS[i].location.X + NPCS[i].hitbox_bl.X;
    LeftCornerY = NPCS[i].location.Y + NPCS[i].hitbox_bl.Y;
    RightCornerX = NPCS[i].location.X + NPCS[i].hitbox_tr.X;

    if(LeftCornerY > NoseY)
    {
      DistanceY = LeftCornerY - NoseY;
      DistanceX = abs(NoseX - ((LeftCornerX + RightCornerX) / 2));

      if((DistanceY/5) > DistanceX)
      {
        if((NoseXRight - ((LeftCornerX + RightCornerX) / 2)) > 0)
        {
          if(DistanceY < LeftDistance)
          {
            LeftDistance = DistanceY;
            Player.targetleft = i;
          }
        }
        if((NoseXLeft - ((LeftCornerX + RightCornerX) / 2)) < 0)
        {
          if(DistanceY < RightDistance)
          {
            RightDistance = DistanceY;
            Player.targetright = i;
          }
        }
      }
    }
  }

}

void game_tick_projectiles()
{
  int i;
  for(i = 0; i < MAX_PROJECTILES; i++)
  {
    if(!Projectiles[i].active)
      continue;

    if(tick > Projectiles[i].nextframe)
    {
      if((Projectiles[i].sprite >= photon1) && (Projectiles[i].sprite <= photon2))
      {
        Projectiles[i].sprite++;
        if(Projectiles[i].sprite > photon2)
          Projectiles[i].sprite = photon1;
      }
      Projectiles[i].nextframe = tick + 10;
    }


    Projectiles[i].location.Y -= (tick - lasttick) * Projectiles[i].velocity.Y;
    Projectiles[i].location.X -= (tick - lasttick) * Projectiles[i].velocity.X;

    if((Projectiles[i].location.Y) <= 0)
    {
      Projectiles[i].active = 0;
    }
  }
}



void game_tick_input()
{
  if(debugs[dbbase])
  {
    // 1
    if(input_readkey(17))
      debugs[dbinput] = 1;
    // 2
    if(input_readkey(48))
      debugs[dbhitbox] = 1;
    // 3
    if(input_readkey(49))
      debugs[dbweapons] = 1;
    // 4
    if(input_readkey(18))
      debugs[dbperformance] = 1;
    // 5
    if(input_readkey(19))
      debugs[dbnpcs] = 1;
    // 6
    if(input_readkey(24))
      debugs[dbprojectiles] = 1;
  }
  
  /*if(debugs[dbinput])
  {
    font_colour(colours[debuggreen],colours[lcars_black],font[sys_12_8]);
    sprintf(hudbuffer,"Keycode: %i",input_readanykey());
    draw_text(hudbuffer,DISPLAY_X-500,DISPLAY_Y-40,font[sys_12_8]);
  }*/

  // Q
  if(input_readkey(16))
    Player.integrity = 1000;
//    debugs[dbbase] = 1;

  if(tick > Player.nextidlesprite)
    Player.sprite = Player.idlesprite;

  // Right arrow
  if(input_readkey(121))
  {
    Player.location.X += PLAYER_X_SPEED * (tick - lasttick);
    Player.sprite = player_shipr;
    Player.nextidlesprite = tick + 15;
    if((Player.location.X + Player.hitbox_tr.X) > DISPLAY_X)
    {
      Player.location.X = DISPLAY_X - Player.hitbox_tr.X;
    }
  }

  // Left arrow
  if(input_readkey(25))
  {
    Player.location.X -= PLAYER_X_SPEED * (tick - lasttick);
    Player.sprite = player_shipl;
    Player.nextidlesprite = tick + 15;
    if((Player.location.X + Player.hitbox_bl.X) < 0)
    {
      Player.location.X = 0 - Player.hitbox_bl.X;
    }
  }

  // Space
  if(input_readkey(98))
  {
    Player.firingleft = 1;
    Player.firingright = 1;
    Player.nextshieldheal = tick + 100;
  }else{
    Player.firingleft = 0;
    Player.firingright = 0;
  }
}

void game_setup_audio()
{
  sound_voices(4);

  sound_set_voice(1,"WaveSynth-Beep");
  sound_set_voice(2,"Percussion-Noise");
  sound_set_voice(3,"Percussion-Soft");
  sound_set_voice(4,"Percussion-Noise");
}

void game_draw_hud()
{
  draw_sprite("lcars",4,DISPLAY_Y-164);
  draw_sprite("pointer",141+(Player.shields*2),DISPLAY_Y - 164 + 84);
  draw_sprite("pointer",141+(Player.integrity*2),DISPLAY_Y - 164 + 44);
  draw_sprite("pointer",141+(Player.remainingdistance/7500),DISPLAY_Y - 164 + 4);
}

void game1_setup()
{
  game_setup_input();
  game_setup_audio();
  game_setup_stars();
  game_setup_player();
  game_setup_npcs();
  tick = clock();
}

void game_tick_player()
{
  Player.remainingdistance -= Player.velocity * (tick - lasttick);

  if(Player.shields < 100)
  {
    if(tick > Player.nextshieldheal)
    {
      Player.shields += 1;
      Player.nextshieldheal = tick + 10;
    }
  }

  if((Player.firingleft) && (Player.targetleft >= 0))
  {
    NPCS[Player.targetleft].health -= (tick - lasttick) * Player.phaserdamage;
  }

  if((Player.firingright) && (Player.targetright >= 0))
  {
    NPCS[Player.targetright].health -= (tick - lasttick) * Player.phaserdamage;
  }
}

void game1_death()
{
  int currentstart = 0;
  int introframe = 0;
  sound_voices(4);

  sound_set_voice(1,"WaveSynth-Beep");
  sound_set_voice(2,"WaveSynth-Beep");
  sound_set_voice(3,"WaveSynth-Beep");
  sound_set_voice(4,"WaveSynth-Beep");
  sound_composition_init();
  
  currentstart += 100;
  sound_composition_element_add(currentstart,1,sound_note("D2"),150);
  currentstart += 100;
  sound_composition_element_add(currentstart,2,sound_note("G2"),200);
  currentstart += 200;
  sound_composition_element_add(currentstart,3,sound_note("B3"),75);
  currentstart += 40;
  sound_composition_element_add(currentstart,4,sound_note("G2"),75);
  currentstart += 50;
  sound_composition_element_add(currentstart,2,sound_note("B3"),200);
  currentstart += 200;
  sound_composition_element_add(currentstart,1,sound_note("A3"),100);
  currentstart += 100;
  sound_composition_element_add(currentstart,3,sound_note("G2"),150);
  currentstart += 150;
  sound_composition_element_add(currentstart,2,sound_note("E2"),100);
  currentstart += 100;
  sound_composition_element_add(currentstart,1,sound_note("D2"),150);
  currentstart += 150;
  sound_composition_element_add(currentstart,3,sound_note("D2"),150);
  currentstart += 100;
  sound_composition_element_add(currentstart,4,sound_note("G2"),150);
  currentstart += 150;
  sound_composition_element_add(currentstart,1,sound_note("B3"),75);
  currentstart += 40;
  sound_composition_element_add(currentstart,2,sound_note("G2"),75);
  currentstart += 40;
  sound_composition_element_add(currentstart,3,sound_note("B3"),150);
  currentstart += 150;
  sound_composition_element_add(currentstart,4,sound_note("A3"),130);
  currentstart += 100;
  sound_composition_element_add(currentstart,1,sound_note("G2"),200);
  currentstart += 300;
  tick = clock();

  sound_composition_start(clock());

  draw_sprite("spacebar",(DISPLAY_X/2)-106,50);
  draw_sprite("kia",(DISPLAY_X/2)-300,500);

  screen_flipbuffer();

  while(sound_composition_incomplete())
  {
    sound_composition_tick(clock());

      if(clock() > (tick + 100))
      {
        if(input_readkey(98))
          sound_composition_stop();
      }
  }
}

void game1_briefing()
{
  screen_clear();

  draw_spritetext(
"~~~~~~~~{chief engineers log - uss archimedes - stardate 1234567890 ~~==========~~===============}\n\n\nthe federation has begun diplomatic relations with the planet korell. their unusual position within an asteroid belt \nmeans their planet has to be protected by a deflector shield. the federation has offered to help enhance this shield. \nonce this upgrade was completed we were preparing to leave when we recieved a priority one transmission from the \narchimedes saying a fleet of fighters from the neighbouring planet of durnovaria was en route to torell. it transpires \nthat the deflector shield may also have some military value that was concealed from the federation. the durnovarians \nhave said our shuttle is now considered a military target and will be treated as such. must to get back to the archimedes \nbefore we get dragged further into the conflict between the two planets.\n\n\n\n\n\n\n\n\n\n\n\n\n\n~~~~~~~~{==========================================~~~~~~~~=======}"
, 50, 950);

  draw_sprite("spacebar",(DISPLAY_X/2)-106,50);

  screen_flipbuffer();

  tick = clock();
  while(1)
  {
    if(clock() > (tick + 100))
    {
      if(input_readkey(98))
        return;
    }
  }
}

int game1_tick()
{
  lasttick = tick;
  tick = clock();

  screen_flipbuffer();
  screen_clear();

  if(Player.integrity > 200)
  {
    return 2;
  }
  else if(Player.integrity > 0)
  {
    PROFILE(game_tick_stars());
    PROFILE(game_tick_input());
    PROFILE(game_tick_player());
    PROFILE(game_tick_npcs());
    PROFILE(game_tick_collider());
    PROFILE(game_tick_player_targets());
    PROFILE(game_tick_npcs());
    PROFILE(game_tick_projectiles());
    PROFILE(game_draw_stars());
    PROFILE(game_draw_player());
    PROFILE(game_draw_npcs());
    PROFILE(game_draw_projectiles());

    PROFILE(game_draw_hud());
    PROFILE(game_draw_debugmenu());
    return 0;
  }else{
    screen_flipbuffer();
    screen_clear();
    game1_death();
    return 1;
  }
  

}
