// BAFFLED.CPP -- Written by Steve Brown on Oct 22, 1992
//
//        Locate mirrored baffles, hidden in a box, by moving and firing a
//        laser into it.  Get points by guessing the correct location and
//        angle of the baffles.  VGA graphics.
//

#include <time.h>
#include <ctype.h>
#include <process.h>
#include <graphics.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
#include <dos.h>
#include "baffled.h"

void put_square(int sx, int sy, int clr);    // Put baffle selection box
void put_gun(int pos, int stat);             // Put gun on screen


FILE *in;           // High score file stream
void far *gun[4];   // Different positions of gun
char name[10];      // Name for high score
int getcode(void);  // Get and return a scan code
int nb = 0;         // Number of baffles
int tg = 0;         // Total guesses
int cg = 0;         // Correct guesses
int st = 0;         // Shots taken
int db[20][2];      // Discovered Baffles
int score;          // Score
int key_push;       // Key pressed
int i, j;           // Loop variables
int maxx, maxy;     // Max values for x and y
int cp = 0;         // Current positon of gun
int sx = 1, sy = 1; // Coordinates for baffle selection box
int tx, ty;         // Temparary x,y variables
int dir;            // Direction of gun
int x, y;           // Coordinates for laser beam


void main(void)
{
  void setup(void);           // Initialize graphics drivers
  void hscore_screen(void);   // High score screen
  void intro_screen(void);    // Intro screen
  void new_game(void);        // Intialize variable for new game
  void play_game(void);       // Play game

  setup();
  intro_screen();
  while (TRUE) {
    hscore_screen();
    play_game();
    new_game();
    }
}


// setup() ----------------------------------------------------------
void setup(void)
{
  int gdriver = VGA, gmode = VGAMED, errorcode;     // Driver stuff
  if (registerbgidriver(EGAVGA_driver) < 0)         // All drives have been
    exit(1);                                        //   loaded into the
  if (registerbgifont(triplex_font) < 0)            //   EXE file during
    exit(1);                                        //   linking of program
  if (registerbgifont(sansserif_font)  < 0)
    exit(1);
  if (registerbgifont(small_font)  < 0)
    exit(1);

  initgraph(&gdriver, &gmode, "");
  errorcode = graphresult();

  if (errorcode != grOk) {
    printf("Graphics error: %s\n", grapherrormsg(errorcode));
    printf("Press any key to halt:");
    getch();
    exit(1);
    }
  maxx = getmaxx();
  maxy = getmaxy();

}

// help_screen() ----------------------------------------------------
void help_screen(void)
{
  setcolor(3);
  settextstyle(TRIPLEX_FONT, HORIZ_DIR, 4);
  outtextxy(260, 5, "Help!");

  settextstyle(SMALL_FONT, HORIZ_DIR, 6);
  setcolor(9);
  outtextxy(125, 60, "Shoot =");
  setcolor(11);
  outtextxy(125, 60, "        <Spacebar>");
  setcolor(9);
  outtextxy(125, 60 + 15, "Move gun =");
  setcolor(11);
  outtextxy(125, 60 + 15, "           Arrow Keys");
  setcolor(9);
  outtextxy(125, 60 + 30, "Move Baffle Selector =        +");
  setcolor(11);
  outtextxy(125, 60 + 30, "                       <Ctrl>   Arrow keys");
  setcolor(9);
  outtextxy(125, 60 + 45, "Place Baffle =  and  keys");
  setcolor(11);
  outtextxy(125, 60 + 45, "              /    \\");

  settextstyle(SMALL_FONT, HORIZ_DIR, 5);
  setcolor(12);
  outtextxy(20, 140, "Instructions:");
  outtextxy(45, 155, "Use the arrow keys to move the laser cannon around the board. Press Spacebar");
  outtextxy(45, 170, "to fire.  To make a guess about the location of a baffle, first use CTRL+Arrow");
  outtextxy(45, 185, "keys to move the baffle placement box to where you think the baffle is located.");
  outtextxy(45, 200, "Then press / or \\ depending on the angle you predict.  If a baffle exists in");
  outtextxy(45, 215, "that location, and has the same angle, the baffle will be revealed.");

  setcolor(11);
  outtextxy(20, 235, "Scoring:");
  outtextxy(45, 250, "Scores are a factor of the number of shots you take, the number of guesses");
  outtextxy(45, 265, "you make and the number of baffles chosen. The lower the score, the better.");

  setcolor(10);
  outtextxy(20, 290, "Tips:");
  outtextxy(45, 305, "- It is better to waste a shot verifying a baffle, then making a wrong guess.");
  outtextxy(45, 320, "- Add more baffles, to increase your chance of getting a better score.");
}


// intro_screen() ---------------------------------------------------
void intro_screen(void)
{
  settextstyle(TRIPLEX_FONT, HORIZ_DIR, 7);
  outtextxy(210, -15, "Baffled!");
  settextstyle(SMALL_FONT, HORIZ_DIR, 5);
  setcolor(14);
  outtextxy(20, 60,  "Object of game:");
  outtextxy(45, 75,  "Use the laser cannon to find the location of double sided, mirrored baffles");
  outtextxy(45, 90,  "Baffles will reflect the laser at a 90 degree angle.  These baffles are");
  outtextxy(45, 105,  "located at random intersections on the playing board.  Use the exit location");
  outtextxy(45, 120, "of the laser beam to determine baffle locations.");

  setcolor(12);
  outtextxy(20, 140, "Instructions:");
  outtextxy(45, 155, "Use the arrow keys to move the laser cannon around the board. Press Spacebar");
  outtextxy(45, 170, "to fire.  To make a guess about the location of a baffle, first use CTRL+Arrow");
  outtextxy(45, 185, "keys to move the baffle placement box to where you think the baffle is located.");
  outtextxy(45, 200, "Then press / or \\ depending on the angle you predict.  If a baffle exists in");
  outtextxy(45, 215, "that location, and has the same angle, the baffle will be revealed.");

  setcolor(11);
  outtextxy(20, 235, "Scoring:");
  outtextxy(45, 250, "Scores are a factor of the number of shots you take, the number of guesses");
  outtextxy(45, 265, "you make and the number of baffles chosen. The lower the score, the better.");

  setcolor(10);
  outtextxy(20, 290, "Tips:");
  outtextxy(45, 305, "- It is better to waste a shot verifying a baffle, then making a wrong guess.");
  outtextxy(45, 320, "- Add more baffles, to increase your chance of getting a better score.");
  getch();
}


// hscore_screen() --------------------------------------------------
void hscore_screen(void)
{
  void get_scores(void);  // Retrieve scores from "HIGHSCORE.DAT"
  char temp[50], tmp[3];  // Temporary strings
  int keypres;            // Key pressed
  int baf_num;            // Num of baffles played
  int dn = 0;             // Cursor postion
  BOOL done = FALSE;      // Determine if done

  cleardevice();
  setcolor(10);
  settextstyle(TRIPLEX_FONT, HORIZ_DIR, 5);
  outtextxy((maxx - textwidth("High Scores"))/2, -10, "High Scores");

  settextstyle(DEFAULT_FONT, HORIZ_DIR, 2);

  get_scores();
  for (int i = 0; i < 10; i++) {
    sprintf(temp, "%2d) %-10s %5s (%2s)", i + 1, hscore[i].name, hscore[i].score, hscore[i].baffle);
    outtextxy((maxx - textwidth(temp))/2, 50 + (i * 20), temp);
    }

  settextstyle(SANS_SERIF_FONT, HORIZ_DIR, 2);
  outtextxy(130, 280, "Enter # of baffles or press ESC to quit:");
  i = 0;
  for (i = 0; i < 50; i++)
    temp[i] = '\0';

  while(!done) {             // Loop to get # of baffles
    while (!kbhit()) {
      i++;
      if (i < 500) {
        setfillstyle(SOLID_FILL, 3);
        bar(530 + (dn * 10), 303, 540 + (dn * 10), 306);
        }
      else {
        setfillstyle(SOLID_FILL, 0);
        bar(530 + (dn * 10), 303, 540 + (dn * 10), 306);
        }
      if (i > 1000)
        i = 0;
      }

    setfillstyle(SOLID_FILL, 0);
    bar(530 + (dn * 10), 303, 540 + (dn * 10), 306);
    keypres = getcode();
    if (isdigit(keypres)) {
      if (dn < 2) {
        temp[dn++] = keypres;
        sprintf(tmp, "%c", keypres);
        outtextxy(535 + ((dn - 1) * 15), 280, tmp);
        }
      else {
        setcolor(11);          // Error routine
        outtextxy(150, 300, "Error: Range is not between 1 and 20");
        outtextxy(165, 320, "   - Press Enter to continue -");
        setcolor(10);
        while (getcode() != 13)
          ;
        setfillstyle(SOLID_FILL, 0);
        bar(150, 305, 600, 400);
        dn = 0;
        temp[0] = '\0';
        temp[1] = '\0';

        setfillstyle(SOLID_FILL, 0);
        bar(530 + (dn * 15), 280, 545 + ((dn + 1) * 15), 400);
      }
    }
    if (keypres == ESCKEY) {   // Exit routine
       for (i = 0; i < 4; i++)
         farfree(gun[i]);
       closegraph();
       exit(1);
       }

    if (keypres == 8) {        // Backspace routine
      if (dn - 1 >= 0) {
        temp[--dn] = '\0';
        setfillstyle(SOLID_FILL, 0);
        bar(530 + (dn * 15), 280, 545 + ((dn+1) * 15), 400);
        outtextxy(535 + ((dn - 1) * 15), 280, temp);
        }
      }

    if (keypres == 13) {       // Enter routine
      baf_num = atoi(temp);
      if (baf_num < 1 || baf_num > 20) {
        setcolor(11);
        outtextxy(150, 300, "Error: Range is not between 1 and 20");
        outtextxy(165, 320, "   - Press Enter to continue -");
        setcolor(10);
        while (getcode() != 13)
          ;
        setfillstyle(SOLID_FILL, 0);
        bar(150, 305, 600, 400);
        dn = 0;
        temp[0] = '\0';
        temp[1] = '\0';
        setfillstyle(SOLID_FILL, 0);
        bar(530 + (dn * 15), 280, 545 + ((dn+1) * 15), 400);
        }
      else {
        done = TRUE;
        nb = baf_num;
        }
      }
  }
}

// get_scores() -----------------------------------------------------
void get_scores(void)
{
  int get_value(char *);       // Get entry from file
  int recno = 0;               // Current record number

  if ((in = fopen("HIGHSCOR.DAT", "r")) != NULL) {
    while (get_value(hscore[recno].name) != EOF && recno < 10) {
      if (get_value(hscore[recno].score) == EOF)
        break;
      if (get_value(hscore[recno].baffle) == EOF)
        break;
      recno++;
      }
    fclose(in);
    }
}



// get_value() ------------------------------------------------------
int get_value(char *s)
{
  int ch;                      // Character

  while ((ch = getc(in)) != EOF && ch != '\n')
    *s++ = ch;
  *s = '\0';
  return ch;
}


// play_game() ------------------------------------------------------
void play_game(void)
{
  void setup_graph(void);      // Setup playing board
  void put_instruc(void);      // Put instructions on screen
  void put_info(BOOL);         // Put information on screen
  void help_screen(void);      // Construct help screen
  void move_gun(int cm);       // Move gun
  void put_baffle(void);       // Put baffle if found
  void correct_tone(void);     // Tone for correct guess
  void wrong_tone(void);       // Tone for incorrect guess
  void calc_score(void);       // Calculate score
  void get_dir(int cp);        // Get direction of gun
  void shoot_beam(void);       // Shoot beam
  void get_result(void);       // Get result of shot

  BOOL exist;                  // True if baffle exists
  BOOL done = FALSE;           // Flag for done
  BOOL win = TRUE;             // Flag for win
  int slot;                    // Slot to shoot down

  setup_graph();
  put_instruc();

  while (!done) {
    key_push = getcode();
    put_info(TRUE);
    switch (key_push) {
      case LEFTKEY:           // Left arrow key pressed
        if (cp >= 0 && cp < 10)
          move_gun(-1);
        if (cp >= 20 && cp < 30)
          move_gun(1);
        break;
      case RIGHTKEY:          // Right arrow key pressed
        if (cp >= 0 && cp < 10)
          move_gun(1);
        if (cp >= 20 && cp < 30)
          move_gun(-1);
	break;
      case UPKEY:             // Up arrow key pressed
        if (cp >= 10 && cp < 20)
          move_gun(-1);
        if (cp >= 30 && cp < 40)
          move_gun(1);
	break;
      case DOWNKEY:           // Down arrow key pressed
        if (cp >= 10 && cp < 20)
          move_gun(1);
        if (cp >= 30 && cp < 40)
          move_gun(-1);
	break;
      case CTRL_R:            // Ctrl - Right arrow key pressed
	put_square(sx, sy, 5);
	sx++;
	if (sx > 9)
	  sx = 9;
	put_square(sx, sy, SCLR);
	break;
      case CTRL_L:            // Ctrl - Left arrow key pressed
	put_square(sx, sy, 5);
	sx--;
	if (sx < 0)
	  sx = 0;
	put_square(sx, sy, SCLR);
	break;
      case CTRL_U:            // Ctrl - Up arrow key pressed
	put_square(sx, sy, 5);
	sy--;
	if (sy < 0)
	  sy = 0;
	put_square(sx, sy, SCLR);
	break;
      case CTRL_D:            // Ctrl - Down arrow key pressed
	put_square(sx, sy, 5);
	sy++;
	if (sy > 9)
	  sy = 9;
	put_square(sx, sy, SCLR);
	break;
      case FORWARD:           // Forward slash pressed
        exist = FALSE;
	put_info(FALSE);
        for (i = 0; i <= cg; i++) {
          if (db[i][1] == sx && db[i][2] == sy)
            exist = TRUE;
          }

	if (IntSec[sx][sy].Angle == 1 && exist == FALSE) {
	  cg++;
          db[cg][1] = sx;
          db[cg][2] = sy;
          put_baffle();
          correct_tone();
	  }
        else
          wrong_tone();
	tg++;
	put_info(TRUE);
        if (cg == nb)
          done = TRUE;
	break;
      case BACK:              // Back slash pressed
        exist = FALSE;
	put_info(FALSE);
        for (i = 0; i <= cg; i++) {
          if (db[i][1] == sx && db[i][2] == sy)
            exist = TRUE;
          }

	if (IntSec[sx][sy].Angle == 0 && exist == FALSE) {
	  cg++;
          db[cg][1] = sx;
          db[cg][2] = sy;
          put_baffle();
          correct_tone();
	  }
        else
          wrong_tone();
	tg++;
	put_info(TRUE);
        if (cg == nb)
          done = TRUE;

	break;
      case SHOT:              // Shoot key pressed
        put_info(FALSE);
        st++;
        put_info(TRUE);
	get_dir(cp);
	shoot_beam();
	get_result();
	break;
      case ESCKEY:            // Escape key pressed
        win = FALSE;
        done = TRUE;
        break;
      case 59:                // F1 pressed
        setactivepage(1);
        cleardevice();
        help_screen();
        setvisualpage(1);
        setactivepage(0);
        getch();
        setvisualpage(0);
        break;
      }
    }
    if (win) {                // Game over!
      setcolor(0);
      settextstyle(3, HORIZ_DIR, 1);
      outtextxy(5, 80, "Correct!");
      setcolor(15);
      outtextxy(5, 80, "You Win!");
      settextstyle(SMALL_FONT, HORIZ_DIR, 4);
      outtextxy(0, 110, "Press enter to continue");
      getch();
      calc_score();
      }
}


// setup_graph() ----------------------------------------------------
void setup_graph(void)
{
  void get_gun(void);          // Get image for gun
  void calc_grid(void);        // Calculate points for grid
  void draw_grid(void);        // Draw the grid

  int row, col;                // Baffle coordinates
  int angle;                   // Angle of baffle

  randomize();

  for (i = 0; i < 10; i++) {   // Loop to initialize struct
    for (j = 0; j < 10; j++) {
      IntSec[i][j].Baffle = FALSE;
      IntSec[i][j].Angle = -1;
      }
    }

  for (i = 1; i <= nb; i++) {  // Randomly generate baffles
    row = random(10);
    col = random(10);
    angle = random(2);
    if (IntSec[row][col].Baffle == TRUE)
      i--;
    else {
      IntSec[row][col].Baffle = TRUE;
      IntSec[row][col].Angle = angle;
      }
    }

  for (i = 0; i < nb; i++) {   // Intialize array of known baffles
    db[i][1] = -1;
    db[i][2] = -1;
    }

  cleardevice();
  get_gun();
  calc_grid();
  draw_grid();
  put_gun(cp, COPY_PUT);
  put_square(sx, sy, SCLR);
}

// put_instruc() ----------------------------------------------------
void put_instruc(void)
{
  setcolor(14);
  settextstyle(3, HORIZ_DIR, 1);
  outtextxy(563, 0, "Baffled!");
  settextstyle(SMALL_FONT, HORIZ_DIR, 4);
  outtextxy(545, 18, "By Stephen Brown");
  outtextxy(545, 27, " Oct. 22, 1992");
}

// move_gun() -------------------------------------------------------
void move_gun(int cm)
{
   put_gun(cp, XOR_PUT);
   cp += cm;
   switch (cp) {
     case 40:
       cp = 0;
       break;
     case -1:
       cp = 39;
       break;
     }

   put_gun(cp, COPY_PUT);
}

// put_info() -------------------------------------------------------
void put_info(BOOL clr)
{
  char temp[80];               // Temporary storage
  setcolor(14);
  settextstyle(SMALL_FONT, HORIZ_DIR, 5);
  outtextxy(1, 1, "Num of Baffles:");
  outtextxy(1, 12, "Total Guesses:");
  outtextxy(1, 24, "Baffles Found:");
  outtextxy(1, 36, "Shots Taken: ");
  settextstyle(SMALL_FONT, HORIZ_DIR, 6);
  outtextxy(525, 320, "Score:");

  if (clr)
    setcolor(14);
  else
    setcolor(0);

  settextstyle(SMALL_FONT, HORIZ_DIR, 5);
  sprintf(temp, "               %d", nb);
  outtextxy(1, 1, temp);
  sprintf(temp, "               %d", tg);
  outtextxy(1, 12, temp);
  sprintf(temp, "               %d", cg);
  outtextxy(1, 24, temp);
  sprintf(temp, "            %d", st);
  outtextxy(1, 36, temp);

  settextstyle(SMALL_FONT, HORIZ_DIR, 6);
  score = (100 * (20 - nb)) + st + ((tg - cg) * (30 - nb));
  sprintf(temp, "       %d", score);
  outtextxy(525, 320, temp);
  setcolor(17);

  settextstyle(SMALL_FONT, HORIZ_DIR, 5);
  setcolor(9);
  outtextxy(10, 320, "Press      for help");
  setcolor(11);
  outtextxy(10, 320, "      <F1>");
}

// put_baffle() -----------------------------------------------------
void put_baffle(void)
{
  for(i = 0; i <= cg; i++) {
    tx = 165 + ((db[i][1]) * 35);
    ty = 60 + ((db[i][2]) * 25);
    setcolor(SCLR);
    if (IntSec[db[i][1]][db[i][2]].Angle == 0)
      line(tx - 5, ty - 5, tx + 5, ty + 5);

    if (IntSec[db[i][1]][db[i][2]].Angle == 1)
      line(tx - 5, ty + 5, tx + 5, ty - 5);
    }
}


// correct_tone() ---------------------------------------------------
void correct_tone(void)
{
  setcolor(0);
  settextstyle(3, HORIZ_DIR, 1);
  outtextxy(5, 80, "Wrong!");
  setcolor(15);
  outtextxy(5, 80, "Correct!");
  sound(400);
  delay(100);
  nosound();
  delay(100);
  sound(400);
  delay(80);
  nosound();
  delay(100);
  sound(600);
  delay(250);
  nosound();
}

// wrong_tone() -----------------------------------------------------
void wrong_tone(void)
{
  setcolor(0);
  settextstyle(3, HORIZ_DIR, 1);
  outtextxy(5, 80, "Correct!");
  setcolor(15);
  outtextxy(5, 80, "Wrong!");
  sound(300);
  delay(200);
  nosound();
  delay(150);
  sound(250);
  delay(250);
  nosound();
}


// get_dir() --------------------------------------------------------
void get_dir(int cp)
{
  if (cp >= 0 && cp < 10) {    // Gun faces down
      dir = DOWN;
      x = cp;
      y = -1;
      }

  if (cp >= 10 && cp < 20) {   // Gun faces left
      dir = LEFT;
      x = 10;
      y = cp - 10;
      }

  if (cp >= 20 && cp < 30) {   // Gun faces up
      dir = UP;
      x = 29 - cp;
      y = 10;
      }

  if (cp >= 30 && cp < 40) {   // Gun faces right
      dir = RIGHT;
      x = -1;
      y = 39 - cp;
      }
}

// shoot_beam() -----------------------------------------------------
void shoot_beam(void)
{
  int done = FALSE;
  while(done == FALSE) {
    switch(dir) {
      case DOWN:               // Beam shot down
	while(++y < 10) {
	  if (IntSec[x][y].Baffle) {
	    if (IntSec[x][y].Angle == 0)
	      dir = RIGHT;
	    else
	      dir = LEFT;
	    break;
	    }
	  }
	if (y == 10)
	  done = TRUE;
	break;

      case UP:                 // Beam shot up
	while(--y > -1) {
	  if (IntSec[x][y].Baffle) {
	    if (IntSec[x][y].Angle == 0)
	      dir = LEFT;
	    else
	      dir = RIGHT;
	    break;
	    }
	  }
	if (y == -1)
	  done = TRUE;
	break;

      case LEFT:               // Beam shot left
	while(--x > -1) {
	  if (IntSec[x][y].Baffle) {
	    if (IntSec[x][y].Angle == 0)
	      dir = UP;
	    else
	      dir = DOWN;
	    break;
	    }
	  }
	if (x == -1)
	  done = TRUE;
	break;

      case RIGHT:              // Beam shot right
	while(++x < 10) {
	  if (IntSec[x][y].Baffle) {
	    if (IntSec[x][y].Angle == 0)
	      dir = DOWN;
	    else
	      dir = UP;
	    break;
	    }
	  }
	if (x == 10)
	  done = TRUE;
	break;
    }
  }
}


// get_result() -----------------------------------------------------
void get_result(void)
{
  void enter_beam(int cp);     // Show beam entering
  void exit_beam(int dir);     // Show beam exiting

  switch(dir) {
    case DOWN:
      enter_beam(cp);
      exit_beam(DOWN);
      break;
    case LEFT:
      enter_beam(cp);
      exit_beam(LEFT);
      break;
    case UP:
      enter_beam(cp);
      exit_beam(UP);
      break;
    case RIGHT:
      enter_beam(cp);
      exit_beam(RIGHT);
      break;
    }
}

// calc_score() -----------------------------------------------------
void calc_score(void)
{
  void put_scores();           // Put scores in "HIGHSCORE.DAT"
  char temp[30];               // Temporary storage
  char ch[2] = {'\0'};         // Temporary storage
  BOOL hs = FALSE;             // High score flag
  int cl = 0;                  // Current letter

  for(i = 0; i < 10; i++) {
    if (atoi(hscore[i].score) > score || atoi(hscore[i].score) == 0)
      hs = TRUE;
    }
  if (hs) {
    cleardevice();
    setcolor(14);
    settextstyle(DEFAULT_FONT, HORIZ_DIR, 4);
    outtextxy(70, 5, "New High Score!!");
    settextstyle(DEFAULT_FONT, HORIZ_DIR, 2);
    sprintf(temp, "Score: %d", score);
    outtextxy(250, 50, temp);
    outtextxy(120, 150, "Enter your name:");
    while ((ch[0] = getch()) != 13 && cl < 10) {
      if (isascii(ch[0]) && ch[0] != '\0' && ch[0] != 8 && cl < 10) {
        ch[1] = '\0';
        outtextxy(390 + (cl * 15), 150, ch);
        name[cl++] = ch[0];
        }
      if (ch[0] == 8  && cl > -1) {
        cl--;
        setfillstyle(SOLID_FILL, 0);
        bar(390 + (cl * 15), 150, 405 + (cl * 15), 170);
        name[cl] = '\0';
        }
      }
    name[9] = '\0';
    put_scores();
    }
}


// get_gun() --------------------------------------------------------
void get_gun(void)
{
  unsigned size;               // Memory needed to store gun images
  setfillstyle(SOLID_FILL, 2);
  size = imagesize(0, 0, 30, 30);  /* get byte size of image */
  for (i = 0; i < 4; i++) {
    cleardevice();
    if ((gun[i] = farmalloc(size)) == NULL) {  // Allocate memory for gun
      closegraph();
      printf("Error: not enough heap space to run mirror.\n");
      exit(1);
      }
    switch (i) {               // Store gun facing up
      case UP:
	bar(5, 5, 15, 20);
	bar(8, 0, 12, 10);
	getimage(0, 0, 30, 30, gun[i]);
	break;
      case DOWN:               // Store gun facing down
	bar(5, 5, 15, 20);
	bar(8, 15, 12, 25);
	getimage(0, 5, 30, 30, gun[i]);
	break;
      case LEFT:               // Store gun facing left
	bar(5, 5, 25, 12);
	bar(0, 7, 15, 10);
	getimage(0, 0, 30, 30, gun[i]);
	break;
      case RIGHT:              // Store gun facing right
	bar(5, 5, 25, 12);
	bar(15, 7, 30, 10);
	getimage(0, 0, 30, 30, gun[i]);
	break;
      }
    }
    cleardevice();
}


// calc_grid() ------------------------------------------------------
void calc_grid(void)
{
   for (i = 0; i < 10; i++) {  // Calculate coordinates for grid
     Points[i].y = 45;
     Points[i].x = 165 + (i * 35);

     Points[i + 10].x = 500;
     Points[i + 10].y = 60 + (i * 25);

     Points[i + 20].y = 300;
     Points[i + 20].x = 165 + ((9 - i) * 35);


     Points[i + 30].x = 145;
     Points[i + 30].y = 60 + ((9 - i) * 25);
     }
}



// draw_grid() ------------------------------------------------------
void draw_grid(void)
{
   rectangle(145, 45, 500, 300);
   setcolor(5);
   for (i = 0; i < 10; i++) {
     for (j = 0; j <= 255; j++)
       line(Points[i].x - 5, Points[i].y + j, Points[i].x + 5, Points[i].y + j);

     for (j = 355; j >= 0; j--)
       line(Points[i + 30].x + j, Points[i + 30].y - 4, Points[i + 30].x + j, Points[i + 30].y + 3);
     }
}


// enter_beam() -----------------------------------------------------
void enter_beam(int cp)
{
  int mx, my, cx, cy;          // Coordinates for beam
  int len;                     // Length of beam

  // x = 165 + (cp * 35)
  // y = 60  + (cp * 25)

  if (cp >= 0 && cp < 10) {       // Direction of beam travel is DOWN
      cx = 165 + (cp * 35);
      cy = 58  + (-1.5 * 25);
      mx = 0;
      my = 1;
      len = 24;
      }

  if (cp >= 10 && cp < 20) {      // Direction of beam travel is  LEFT
      cx = 173 + (10.5 * 35);
      cy = 60  + ((9 - (19 - cp)) * 25);
      mx = -1;
      my = 0;
      len = 39;
      }

  if (cp >= 20 && cp < 30) {      //  Direction of beam travel is  UP
      cx = 165 + ((29 - cp) * 35);
      cy = 63  + (10.5 * 25);
      mx = 0;
      my = -1;
      len = 24;
      }

  if (cp >= 30 && cp < 40) {      //  Direction of beam travel is  RIGHT
      cx = 158 + (-1.5 * 35);
      cy = 59  + ((39 - cp) * 25);
      mx = 1;
      my = 0;
      len = 39;
      }

  for (i = 0; i < len; i++) {
    delay(5);
    putpixel(cx + mx * (i + 1), cy + my * (i + 1), 11);
    }

  for (i = 0; i < len; i++) {
    delay(5);
    putpixel((cx += mx), (cy += my), 0);
    }
}


// exit_beam() ------------------------------------------------------
void exit_beam(int dr)
{
int bx, by, mx = 0, my = 0;    // Coordinates for beam

switch (dr) {
  case UP:
   bx = 165 + (x * 35);
   by = 70 + (y * 25);
   my = -1;
  break;

  case DOWN:
   bx = 165 + (x * 35);
   by = 50 + (y * 25);
   my = 1;
  break;

  case LEFT:
   bx = 180 + (x * 35);
   by = 60 + (y * 25);
   mx = -1;
  break;

  case RIGHT:
   bx = 150 + (x * 35);
   by = 60 + (y * 25);
   mx = 1;
  break;
  }

  for (i = 0; i < 30; i++) {    // Draw beam
    delay(5);
    putpixel((bx += mx), (by += my), 11);
    }
  for (i = 0; i < 10; i += 2) { // Draw explosion
    putpixel(bx + i, by, 15);
    putpixel(bx - i, by, 15);
    putpixel(bx, by + i, 15);
    putpixel(bx, by - i, 15);
    putpixel(bx + i, by + i, 15);
    putpixel(bx - i, by - i, 15);
    putpixel(bx - i, by + i, 15);
    putpixel(bx + i, by - i, 15);
    }
  setcolor(0);
  bx -= (mx * 30);
  by -= (my * 30);
  for (i = 0; i < 30; i++) {    // Erase beam
    delay(5);
    putpixel((bx += mx), (by += my), 0);
    }
  for (i = 0; i < 10; i += 2) { // Erase explosion
    putpixel(bx + i, by, 0);
    putpixel(bx - i, by, 0);
    putpixel(bx, by + i, 0);
    putpixel(bx, by - i, 0);
    putpixel(bx + i, by + i, 0);
    putpixel(bx - i, by - i, 0);
    putpixel(bx - i, by + i, 0);
    putpixel(bx + i, by - i, 0);
    delay(15);
    }
  delay(100);
  for (i = 0; i < 10; i += 2) { // Draw explosion
    putpixel(bx + i, by, 14);
    putpixel(bx - i, by, 14);
    putpixel(bx, by + i, 14);
    putpixel(bx, by - i, 14);
    putpixel(bx + i, by + i, 14);
    putpixel(bx - i, by - i, 14);
    putpixel(bx - i, by + i, 14);
    putpixel(bx + i, by - i, 14);
    }
  for (i = 0; i < 10; i += 2) { // Erase explosion
    putpixel(bx + i, by, 0);
    putpixel(bx - i, by, 0);
    putpixel(bx, by + i, 0);
    putpixel(bx, by - i, 0);
    putpixel(bx + i, by + i, 0);
    putpixel(bx - i, by - i, 0);
    putpixel(bx - i, by + i, 0);
    putpixel(bx + i, by - i, 0);
    delay(15);
    }
}



// put_scores() -----------------------------------------------------
void put_scores(void)
{
  FILE *out;                   // Stream to "HIGHSCORE.DAT"
  struct highscore temp;       // Struct of high score entries
  out = fopen("HIGHSCOR.DAT", "w");

  strcpy(hscore[9].name, name);
  sprintf(hscore[9].score, "%d", score);
  sprintf(hscore[9].baffle, "%d", nb);

  for (i = 0; i < 10; i++) {
    if (hscore[i].score[0] == '\0')
      strcpy(hscore[i].score, "32000");
    }

  for (i = 0; i < 9; i++) {
    for (j = i + 1; j < 10; j++) {
      if (hscore[i].score != 0 && hscore[j].score != 0) {
        if (atoi(hscore[i].score) > atoi(hscore[j].score)) {
          temp = hscore[i];
          hscore[i] = hscore[j];
          hscore[j] = temp;
          }
        }
      }
    }


  for (i = 0; i < 10; i++) {   // Send output to file
    if (strcmp(hscore[i].score, "32000") == 0)
      hscore[i].score[0] = '\0';
    fputs(hscore[i].name, out);
    fputc('\n', out);
    fputs(hscore[i].score, out);
    fputc('\n', out);
    fputs(hscore[i].baffle, out);
    fputc('\n', out);
    }
  fclose(out);
}


// new_game() ------------------------------------------------------
void new_game(void)
{
  nb = 0;
  tg = 0;
  cg = 0;
  st = 0;
  score = 0;
  cp = 0;
  sx = 1;
  sy = 1;
  for (i = 0; i < 20; i++) {
    db[i][1] = '\0';
    db[i][2] = '\0';
    }
  for (i = 1; i < 10; i++)
    name[i] = '\0';
}

// put_gun() --------------------------------------------------------
void put_gun(int pos, int stat)
{
  if (pos >= 0 && pos < 10)    // Put gun down
    putimage(Points[pos].x - 10, Points[pos].y - 45, gun[DOWN], stat);

  if (pos >= 10 && pos < 20)   // Put gun left
    putimage(Points[pos].x + 40, Points[pos].y - 9, gun[LEFT], stat);

  if (pos >= 20 && pos < 30)   // Put gun up
    putimage(Points[pos].x - 10, Points[pos].y + 25, gun[UP], stat);

  if (pos >= 30 && pos < 40)   // Put gun right
    putimage(Points[pos].x - 70, Points[pos].y - 9, gun[RIGHT], stat);

}


// put_square() -----------------------------------------------------
void put_square(int sx, int sy, int clr)
{
setcolor(clr);
tx = 165 + ((sx) * 35);
ty = 60 + ((sy) * 25);
rectangle(tx - 5, ty - 5, tx + 5, ty + 5);
}


// getcode() --------------------------------------------------------
int getcode()
{
  int ch = 0;                  // Input character
  if (kbhit()) {
    if ((ch = getch()) == 0)
      ch = getch();
    }
  return ch;
}
