#define __RAWKS_PLAY__
#define DBG 0
#define FIXME 0

#include "defines.h"
#include <stdio.h>
#include <sys/time.h>
#include "gl.h"
#include "gldevice.h"
#include <math.h>
#include "protos.h"
#include "globals.h"
#include "frate.h"

/* Sharon fischler suggested that I should have used Performer for this
   game.  I really should have, but I had fun trying to optimize this
   for GL.  I'm not doing any screen clears, just redrawing the entire
   screen in black (which is hard to do while also maintaining a double-
   buffer.)  It works.
   - Aaron Michael Hightower */

void game_off(void)
{
  if(!Game_over) {
    int i;

    /* Update high scores if user quits game prematurely */
    Game_over = 1;

    if(Mission_list) update_misshigh(Mission_list[Selected_mission]);

    for(i=0;i<Num_players;i++) zero_level_stats(i);
  }
  Num_players = 0;
  update_overlay(OLAY_SOUND | OLAY_IMAGE | OLAY_TEXT);

  clear_normal();
  qdevice(ESCKEY);
  qdevice(PAUSEKEY);
  qdevice(F1KEY);
  qdevice(F2KEY);
  qdevice(F3KEY);
  qdevice(F4KEY);
  qdevice(F5KEY);
  qdevice(F6KEY);
  qdevice(F7KEY);
  qdevice(F8KEY);
  qdevice(F9KEY);
  qdevice(F12KEY);
  qdevice(SPACEKEY);
  qdevice(EQUALKEY);
  qdevice(MINUSKEY);
}

static void game_on(void)
{
  Num_scores = Num_players;
  Game_over = 0;
  update_overlay(OLAY_TEXT | OLAY_CLEAR);

  clear_normal();
  qdevice(ESCKEY);
  qdevice(PAUSEKEY);
  unqdevice(F1KEY);
  unqdevice(F2KEY);
  unqdevice(F3KEY);
  unqdevice(F4KEY);
  unqdevice(F5KEY);
  qdevice(F6KEY);
  qdevice(F7KEY);
  unqdevice(F8KEY);
  unqdevice(F9KEY);
  unqdevice(SPACEKEY);
  qdevice(F12KEY);
  qdevice(EQUALKEY);
  qdevice(MINUSKEY);
}

static void game_pause(void)
{
  int rval;
  short val;

  Paused = 1;
  newsize();
  kill_all_sound();
  update_overlay(OLAY_TEXT | OLAY_IMAGE);

  clear_normal();

  qdevice(LEFTMOUSE);
  qdevice(KEYBD);
  qreset();
  curson();
  do {
    rval=qread(&val); /* Wait for upstroke on one of these keys */
    if(rval == REDRAW) setwinattr();
    else if(rval == WINQUIT || rval == WINSHUT) closeall();
  } while((rval == INPUTCHANGE || rval == REDRAW) || val) ;
  unqdevice(LEFTMOUSE);
  unqdevice(KEYBD);
  cursoff();
  Paused = 0;
  pace_frame(&Cur_time); /* Ignore time difference */
}

static void test_sound(void)
{
  sfx(SFX_FIRE);
}

void play(void)
{
  Game_over = 1;

  start_time(&Cur_time);
  set_time(&New_scene_time,&Cur_time,1,0);

  while(1)
  {
    if(!Rock_head.next) { /* If no more rocks left on screen */
      if(Game_over || elapsed_sec_tenths(&New_scene_time,&Cur_time) > 0) {
	kill_all_sound();

	/* Update the high scores between levels */

	if(!Game_over) update_misshigh(Mission_list[Selected_mission]);
#if DBG
        DEBUG("init_scene");
#endif
	init_scene();
#if DBG
        DEBUG("pace_frame");
#endif

	pace_frame(&Cur_time); /* Ignore this (previous) delay in D_time */
	if(Game_over) game_off(); /* Clean up gfx screen etc */
	else game_on();
      }
    }
    if((Game_over && qtest()) || getvaluator(ESCKEY) ) {
#if DBG
        DEBUG("qread()");
#endif
      Qread = qread(&Qval);
      if(Qread == WINSHUT || Qread == WINQUIT) return;

      switch(Qread) {
#ifndef __LINUX__
	case F6KEY:
	  if(!Qval) {
	    Opts.noborder = !(Opts.noborder);
	    if(Opts.noborder) noborder();
	    winconstraints();
	    update_overlay(OLAY_TEXT);
          }
	  break;
#endif /* !__LINUX__ */
	case EQUALKEY:
	  if(Qval) {
	    volume_change(1);
	    if(Game_over) test_sound();
          }
	  break;
	case MINUSKEY:
	  if(Qval) {
	    volume_change(-1);
	    if(Game_over) test_sound();
          }
	  break;
	case ESCKEY:
	  if(!Qval) {
	    if(Game_over?affirm(0,"Do you really want to quit? (Y/N)","\0"):
			 affirm(0,"Do you really want to abort? (Y/N)","\0"))
	    {
	      if(!Game_over) game_off();
	      else closeall();
	    }
	    else {
	      if(Game_over) game_off();
	      else game_on();
            }
	    pace_frame(&Cur_time); /* Ignore this (previous) delay in D_time */
	  }
	  break;
	case REDRAW:
        case PAUSEKEY:
	case INPUTCHANGE:
	  if((!Qval || Qread == REDRAW) && (!Game_over || Qread == PAUSEKEY))
	    game_pause();
	  if(Qread!=PAUSEKEY || !Qval) setwinattr();
	case SPACEKEY:
	  if(Game_over) {
	    reload_ifnewer();
	    pace_frame(&Cur_time); /* Ignore this (previous) delay in D_time */
          }
	  break;
	default:
/*
  Some things had to move down here because linux f-keys * are not constants
*/
	  if(Qread == F9KEY) {
	    if(Game_over && Qval) {
	      if(Next_level == Mission_list[Selected_mission]->numlevels) 
		Next_level = 0;
	      init_scene();
	    }
	    break;
	  }
	  else if(Qread == F8KEY) {
	    if(getmission()) init_scene();
	    else {
	      setwinattr();
	      update_overlay(OLAY_TEXT | OLAY_IMAGE);
	    }
	    break;
          }
	  else if(Qread == F5KEY) {
	    if( !Qval && Game_over && Restartable) {
	      Num_players = Num_scores;
	      free_all_rocks();
	      Next_level = 0;
	      Speed = INIT_SPEED;
	      init_scene();
	      game_on();
	      startgame();
	      break;
	    }
	  }
	  else if(Qread == F7KEY) {
	    if( !Qval && Has_snd_hardware) {
	      Opts.nosound = !Opts.nosound;
	      if(!Snd_inited) {
		init_sound();
		pace_frame(&Cur_time);
	      }
	      if(Game_over) {
		update_overlay(OLAY_TEXT);
		test_sound();
	      }
	    }
	    break;
          }
	  else if(Qread == F1KEY || Qread == F2KEY || Qread == F3KEY ||
	          Qread == F4KEY) {
	    if( !Qval && Game_over) {
	      Num_players = 1 + (Qread - F1KEY);
	      free_all_rocks();
	      Next_level = 0;
	      Speed = INIT_SPEED;
	      init_scene();
	      game_on();
	      initkeys();
	      if(Game_over) game_off();
	      else {
		game_on();
		startgame();
	      }
            }
	    break;
	  }
#ifndef __LINUX__
	  else if(Qread == F12KEY) {
	    if(!Qval) {
	      Opts.nodbuff = !Opts.nodbuff;
	      setwinattr();
	    }
	    break;
          }
#endif
	  else {
	    fprintf(stderr,"Unknown event %d val==%d\n",Qread,Qval);
	    break;
	  }
          break;
      } /* switch() */
    }
    else {
#if DBG
      DEBUG("Nothing on the queue");
#endif
      Qread = Qval = 0;
    }

#if 0
    if(getvaluator(RIGHTSHIFTKEY)) dump();
#endif
    D_time = Speed * pace_frame(&Cur_time);
    draw_scene();
#ifdef __LINUX__
    scan_keyboard(); /* Scan the keyboard once per frame */
    scan_keyboard(); /* Scan the keyboard once per frame */
    scan_keyboard(); /* Scan the keyboard once per frame */
    scan_keyboard(); /* Scan the keyboard once per frame */
#endif
  }
}

static void initship(player)
{
  bzero(&P[player].V[0].x,sizeof(xyz)*4);
  P[player].startfired = 0;
  P[player].starthit = 0;
  P[player].startscore = 0;
  P[player].name[0] = 0;
  P[player].dead = 0.3;
  P[player].score = 0;
  P[player].fired = 0;
  P[player].hit = 0;
  P[player].finishtime = 0.0;
}

void startgame(void)
{
  int i;

  if(!Restartable) return;

  for(i=1;i<=Num_players;i++) {
    initship(i);
    P[i].rotation[0]=P[i].rotation[1]=0;
    P[i].rot[0]=P[i].rot[1]=0;
    P[i].numlives = Mission_list[Selected_mission]->level[0]->numlives;

    P[i].miny = P[i].minx =  /* Compute a bounding square assuming
					  rotation about the origin - this must
					  only be done after getshipnum */
    (-(P[i].maxy = P[i].maxx = max_radius(i)));
  }
  clear_normal();
}

void initkeys(void)
{
  int i;

  Restartable = 0;

  loadgeometry(); /* Load ships if not already */

  for(i=1;i<=Num_players && i<=MAX_PLAYERS;i++) {
    initship(i);
    getkeys(i);
  }
  if(Game_over) return;
  else Restartable = 1;
}

static void buy_newship(int player,int shipid)
{
  P[player].ship = Ships[shipid];
  P[player].modg = (object_geom *)realloc(P[player].modg,sizeof(object_geom));
  bzero(P[player].modg,sizeof(object_geom));
  P[player].modg->verts = (xyz *)realloc(P[player].modg->verts,
					 P[player].ship->num_verts*sizeof(xyz));
  bzero(P[player].modg->verts,P[player].ship->num_verts*sizeof(xyz));
}

static void getshipnum(int player)
{
  int shipfont = -1;
  short val;
  int rval;
  int selected_ship;
  char playnum[80],buf[80];

  buy_newship(player,selected_ship = 0);
/*   if(Num_ships < 2) return; */

  if(shipfont < 0) shipfont = openvecfont(50,30,0.7);

  sprintf(playnum,"Player %d",player);

  drawmode(NORMALDRAW);
  my_swapbuffers(NORMALDRAW);
  qdevice(ESCKEY);
  qdevice(P[player].firekey);
  qdevice(P[player].leftkey);
  qdevice(P[player].rightkey);
  while(1) {
    if(qtest()) {
      rval = qread(&val);
      if(rval == P[player].firekey || rval == ESCKEY) { if(!val) break; }
      else if(rval == REDRAW) {
	setwinattr();
      }
      else if(rval == WINQUIT || rval == WINSHUT) closeall();
      else if(val) {
	if(rval == P[player].leftkey) selected_ship++;
	else if(rval == P[player].rightkey) selected_ship--;
      }
      if (selected_ship >= Num_ships) selected_ship = 0;
      else if(selected_ship < 0) selected_ship = Num_ships-1;

      buy_newship(player,selected_ship);
    }
    drawmode(NORMALDRAW);
    C_BLACK;
    clear();

    D_time = 10.0 * pace_frame(&Cur_time);
	  /* This is to make the ship rotate at a constant speed */
    rotate_right(player); /* This is to keep out of bounds rotations from
			     causing segmentation faults */
/*     Frm = !Frm; */
    rotate_right(player);

    ortho2(-1.0,1.0,-1.0,1.0);

    cpack(0xffffff);

    vmov2(shipfont,0.0,0.9);
#if 1
    vccprint(shipfont,NORMALDRAW,0,0x00ffff,"Select ship with rotate keys");
    vccprint(shipfont,NORMALDRAW,0,0x0055ff,"Press fire key to accept");
    vmov2(shipfont,0,0.7);
    vccprint(shipfont,NORMALDRAW,0,0xffffff,"\01            \01");vmovrel2(shipfont,0,-1);
    vccprint(shipfont,NORMALDRAW,0,P[player].color,playnum); /* Address the player */
    sprintf(buf,"ID# == %x",selected_ship);
    vccprint(shipfont,NORMALDRAW,0,0xffff00,buf);
    vccprint(shipfont,NORMALDRAW,0,0x999999,"codename");
    vccprint(shipfont,NORMALDRAW,0,0xffffff,amh_basename(P[player].ship->name));
#else
    /* Stopped working (or maybe never worked) on the reality engines(!)) */
    vcprint(shipfont,"Select ship with rotate keys");
    vcprint(shipfont,"Press fire key to accept");
    vmov2(shipfont,0,0.7);
    vcprint(shipfont,"\01            \01");vmovrel2(shipfont,0,-1);
    vcprint(shipfont,playnum); /* Address the player */
    sprintf(buf,"ID# == %x",selected_ship);
    vcprint(shipfont,buf);
    vcprint(shipfont,"codename");
    vcprint(shipfont,amh_basename(P[player].ship->name));
#endif

    ortho2(-0.1,0.1,-0.1,0.1);
    cpack(P[player].color);
    draw_ship(player);
    my_swapbuffers(NORMALDRAW);
  }
  clear_overlay();
  unqdevice(P[player].firekey);
  unqdevice(P[player].leftkey);
  unqdevice(P[player].rightkey);
}

void getkeys(int p)
{
  int done = 0;
  char buffer[20];

  drawmode(NORMALDRAW);
  clear_normal();

  sprintf(buffer,"Player %d",p);

  while(!done) {
    sfx(SFX_1 + p - 1);
    Game_over = 0;

    if((P[p].leftkey=ask(p,buffer,"Press key for rotating left"))==-1) {
      Num_players = 0;
      Num_scores = 4;
      Restartable = 0; /* Very important */
      return;
    }
    if((P[p].rightkey = ask(p,buffer,"Press key for rotating right"))==-1)
      continue;

    if((P[p].thrustkey= ask(p,buffer,"Press key for thrusting forward"))==-1)
      continue;

    if((P[p].firekey  = ask(p,buffer,"Press key for firing"))==-1)
      continue;

    getshipnum(p);
    done = 1;

/*  P[p].hyperkey = ask(p,buffer,"Press key for hyperspace"); */
/*  if(affirm(buffer,"Rapid fire? (Y/N)")) P[p].rapid=1; */
/*  P[p].orig = &Ships[0]; */
/*  P[p].thrust = &Ships[1]; */
/*  P[p].t_modg = (object_geom *)calloc(sizeof(object_geom),1); */
/*  P[p].t_modg->verts = (xyz *)calloc(SHIP1_T_SIZE,sizeof(xyz)); */
  }

#if DBG
  printf("player bounding box = %f %f %f %f\n",
     P[p].miny,P[p].maxy,P[p].minx,P[p].maxx);
#endif
}

float max_radius(int player)
{
  int i;
  float val = 0.0;

  for(i=0;i<P[player].ship->num_verts;i++) {
    float x,y;

/*     x = P[player].orig->verts[i].x; */
/*     y = P[player].orig->verts[i].y; */
    x = P[player].ship->vertex[0][i]->x;
    y = P[player].ship->vertex[0][i]->y;

    if(((x * x) + (y * y)) > val) val = x*x + y*y;
  }
  val = (float) sqrt((double) val);
#if DBG
  printf("%f\n",val);
#endif

  return val;
}

int affirm(int player,char *string1,char *string2)
{
  if(ask(player,string1,string2) == YKEY) return 1;
  else return 0;
}

int ask(int player,char *string1,char *string2)
{
#define NUM_ASK_FONTS 7
  static int askfont[NUM_ASK_FONTS]={-1};
  int done=0;
  int redraw = 1;
  int i;
  int inc = 1;
  short rval,val=1;

  reshapeviewport();
  ortho2(-1.0,1.0,-1.0,1.0);

  if(askfont[0] < 0) for (i=0;i<NUM_ASK_FONTS;i++) {
    askfont[i] = openvecfont(35,15,0.7-(i*0.08));
  }
  qdevice(RAWKEYBD);

  drawmode(NORMALDRAW);
  while(!done) {
    if(redraw) for(i=NUM_ASK_FONTS-1;i>=0;i--) {
      if(qtest()) break;
      vmov2(askfont[i],0.0,0.0);
      vmovrel2(askfont[i],0.0,-0.5); /* Move up half a line */
      vccprint(askfont[i],NORMALDRAW,0,ship_color(player),string1);
      vccprint(askfont[i],NORMALDRAW,0,ship_color(player),string2);
      my_swapbuffers(NORMALDRAW);
      sginap(1);
    }
    redraw = 0;
    rval = qread(&val);
    switch(rval) {
      case REDRAW:
	setwinattr();
	redraw = 1;
	break;
      case WINQUIT:
      case WINSHUT:
	closeall();
	break;
      case ESCKEY:
	if(!val) rval = done = -1;
	break;
      default:
	if(!qtest() && !val) done = 1;
	else break;
    }
  }
  clear_normal();

  unqdevice(RAWKEYBD);

  return rval;
}
