/****************************************************************************
 *  Written by John M Dow
 *  
 *  This is Shareware. This means that you don't have to pay for it, 
 *  but can't change it, or say it's yours.
 *
 *  So there!
 *****************************************************************************
 * Warning: some of this code is really hideous, and is only to be studied
 * by the most paranoid. You and I would both be happier if you didn't read
 * this!
 *****************************************************************************
 */

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<vga.h>
#include<vgagl.h>
#include<vgakeyboard.h>
#include"soundIt.h"

#define NO_OF_LEVELS        2     /* 3 levels */

#define YES                 0
#define NO                  1
#define ON                  1
#define OFF                 0

/*
 * 
 * Position of sound effect in array
 * 
 */
#define BOOM                0
#define ROAR                1
#define SPLAT               2
#define WHEEP               3
#define SCREAM              4
#define SLURP               5
#define CLICK               6
#define GETYE               7
#define MAPSOUND            8
#define EXPLODE             9
#define TOC                 10
#define END                 11
#define GRIND               12
#define OW                  13
#define WHINE               14
#define SLOOP               15
/* Extra keys */
#define SCANCODE_O          24
#define SCANCODE_P          25

/* States for gravity map */
#define FALLING             -2
#define STATIONARY          -1

/* 
 * 
 * Positions of images in array.
 * 4 frames per image for animation
 * 
 * 
 */
#define SPACE               0
#define BRICK               4
#define SAND                8
#define ROCK                12
#define DIAMOND             16
#define BEAST               24
#define OUTSIDE             28
#define CHANGER             32
#define MORPHBLOCK          36
#define VIRUS               40
#define EGG                 44
#define MAP                 48
#define PRONGSLEFT          52
#define PRONGSRIGHT         56
#define PRONGSUP            60
#define PRONGSDOWN          20
#define BOMB                68
#define CUBE                72
#define MAXBLOCK            76

/* Handy constants */
#define MAXX                32
#define MAXY                20
#define MAXSAMP             16
#define SAMPRATE            8000         /* kHz */
#define NO_OF_CHANNELS      8

typedef struct {   int x, y,no_of_diamonds,no_of_morphers;    } start_t;

/* All this stuff is global (ooohhh) so leave alone */
unsigned char graphics[MAXBLOCK][32][32];
unsigned char map_graphics[MAXBLOCK][10][10];
int levels[20][64][48];
int current_level[64][48];
int gravity[64][48];
int current = 0;
int animframe = 0;
int manimframe = 0;
int score = 0;
int diamondcount = 0;
int DIE = 0;
int prongsx, prongsy;
int LIVES = 3;
int CHANGE = OFF;
int Virusmoved  = NO;
int Monstermoved = NO;
int Cubemoved = NO;
int current_channel = 1;
int HASMAP = NO;
int PRONGS = 20;
int SOUND = ON;
int SPEED = 0;
int COMPLETED = NO;
int FALLING_DIAMONDS = OFF;
int words[20] =  {
   00000,37583,36845,80975,96467,36245,15035,33632,34636,22234,
   74575,36336,78908,89067,34576,48657,48965,45935,49123,93092
};

Sample samps[10];





void sound(int snd_no) {
   
   /* This is so that important noises do not get blanketed */
   if(SOUND == ON) {   
      if(snd_no == GETYE || snd_no == END || snd_no == EXPLODE) {
	 Snd_effect(snd_no, 0);
      }
      else {
	 /* 
	  * NO_OF_CHANNELS ensures that each sample gets as long
	  * as possible to play
	  */
	 Snd_effect(snd_no, current_channel);
	 current_channel++;
	 if(current_channel > NO_OF_CHANNELS-1) {
	    current_channel = 1;
	 }
      }
   }
}
   



/*
 * Reads file "data32" into graphics array 
 * Graphics are stored simply as array[i][j] where [i][j] is the color of
 * (i,j)
 */
void load_graphics(void) {
     
   int graphic, row, col;
   FILE *infile;
   
   infile = fopen("data32", "rb");
   for(graphic = 0; graphic < MAXBLOCK; graphic++) {
      for(col = 0; col < 32; col++) {
	 for(row = 0; row < 32; row++) {
	    fread(&(graphics[graphic][col][row]),1,1,infile);
	 }
      }
   }
   fclose(infile);
}


/* 
 * 
 * Reads "data" into map graphics array
 * 
 */
void load_map_graphics(void) {
   
   int graphic, row, col;
   FILE *infile;
   
   infile = fopen("data", "rb");
   for(graphic = 0; graphic < MAXBLOCK; graphic++) {
      for(col = 0; col < 10; col++) {
	 for(row = 0; row < 10; row++) {
	    fread(&(map_graphics[graphic][col][row]),1,1,infile);
	 }
      }
   }
   fclose(infile);
}




/*
 * Reads file "levels" into levels array 
 * 
 */
void load_levels(void) {
     
   int level, row, col;
   FILE *infile;
   infile = fopen("levelshi", "rb");
   for(level = 0; level < 20; level++) {
      for(col = 0; col < 64; col++) {
	 for(row = 0; row < 48; row++) {
	    fread(&(levels[level][col][row]),1,1,infile);
	 }
      }
   }
   fclose(infile);
}



/*
 * 
 * Loads samples into sample bank. These are 8000Hz .ub's
 *
 */
void load_samples(void) {
   Snd_loadRawSample("boom.ub", &(samps[BOOM]));
   Snd_loadRawSample("roar.ub", &(samps[ROAR]));
   Snd_loadRawSample("splat.ub", &(samps[SPLAT]));
   Snd_loadRawSample("wheep.ub", &(samps[WHEEP]));
   Snd_loadRawSample("scream.ub", &(samps[SCREAM]));
   Snd_loadRawSample("slurp.ub", &(samps[SLURP]));
   Snd_loadRawSample("click.ub", &(samps[CLICK]));
   Snd_loadRawSample("getye.ub", &(samps[GETYE]));
   Snd_loadRawSample("mapsound.ub", &(samps[MAPSOUND]));
   Snd_loadRawSample("explode.ub", &(samps[EXPLODE]));
   Snd_loadRawSample("toc.ub", &(samps[TOC]));
   Snd_loadRawSample("end.ub", &(samps[END]));
   Snd_loadRawSample("grind.ub", &(samps[GRIND]));
   Snd_loadRawSample("ow.ub", &(samps[OW]));
   Snd_loadRawSample("whine.ub", &(samps[WHINE]));
   Snd_loadRawSample("sloop.ub", &(samps[SLOOP]));
}



/*
 * Simply initialises gravity map
 */
void reset_gravity(void) {
   int i,j;
   for(i=0;i<64;i++) {
      for(j=0;j<48;j++) {
	 gravity[i][j] = STATIONARY;
      }
   }
}



/* Makes a duplicate of the current level to fart around with */
void copy_level(int level_no) {
   int col,row;
   for(col = 0; col < 64; col++) {
      for(row = 0; row < 48; row++) {
	 current_level[col][row] = levels[level_no][col][row];
      }
   }
}




/*
 * Sets things up 
 */
void initialise(void) {
   vga_init();
   vga_screenoff();
   vga_setmode(10);
   keyboard_init();
   
   if(SOUND == ON ) {
      load_samples();
      Snd_init(MAXSAMP, samps, SAMPRATE, NO_OF_CHANNELS, "/dev/dsp");
   }
}



/*
 * Finds start position in level and works out no of diamonds to b collected
 */
start_t find_start(int lev) {
   start_t coords;
   int col,row;
   coords.no_of_diamonds = 0;
   coords.no_of_morphers = 0;
   coords.x = 0;
   coords.y = 0;
   for(col = 0; col < 64; col++) {
      for(row = 0; row < 48; row++) {
	 if(levels[lev][col][row] == DIAMOND) {
	    coords.no_of_diamonds++;
	 }
	 if(levels[lev][col][row] == MORPHBLOCK) {
	    coords.no_of_morphers++;
	 }
	 if(levels[lev][col][row] == PRONGS) {
	    coords.x = col;
	    coords.y = row;
	 }
      }
   }
   return coords;
}



/* Does all the work */
void update_level(void) {
   int posx,posy;
   int col,row;
   for(col = 63; col > -1; col--) {
      for(row = 47; row > -1; row--) {

	 
	 /* If a morphblock and changer is on */
	 if(*((*(current_level+col))+row) == MORPHBLOCK) {
	    if(CHANGE == ON) {
	       *((*(current_level+col))+row) = DIAMOND;
	    }
	 }

	 /* If a virus type thingy!  */
	 else if(*((*(current_level+col))+row) == VIRUS && Virusmoved == NO ) {
	    
	    /* Check and expand in virusdir */
	    if(*((*(current_level+(col-1)))+row) == SPACE && animframe == 0) {
	       *((*(current_level+(col-1)))+row) = VIRUS;
	       sound(SLOOP);
	       Virusmoved = YES;
	    }
	    else if(*((*(current_level+(col+1)))+row) == SPACE && animframe == 1) {
	       *((*(current_level+(col+1)))+row) = VIRUS;
	       sound(SLOOP);
	       Virusmoved = YES;
	    }
	    else if(current_level[col][row-1] == SPACE && animframe == 2) {
	       current_level[col][row-1] = VIRUS;
	       sound(SLOOP);
	       Virusmoved = YES;
	    }
	    else if(*((*(current_level+col))+(row+1)) == SPACE && animframe == 3) {
	       *((*(current_level+col))+(row+1)) = VIRUS;
	       sound(SLOOP);
	       Virusmoved = YES;
	    }
            
	 }
	 
	 
	 /* If a MONSTER !!! oooohhhh */
	 else if(*((*(current_level+col))+row) == BEAST && Monstermoved == NO) { 
	       
	     	       
	    if(col < prongsx && *((*(current_level+(col+1)))+row)==SPACE ) { 
	       *((*(current_level+(col+1)))+row) = BEAST;
	       *((*(current_level+col))+row) = SPACE;
	       Monstermoved = YES;
	    }
	    else if( *((*(current_level+(col+1)))+row) == PRONGS ) {
	       *((*(current_level+col))+row) = SPACE;
	       *((*(current_level+(col+1)))+row) = BEAST;
	       sound(ROAR);
	       DIE = 1;
	    }
	       
	    
	    else if( col > prongsx && *((*(current_level+(col-1)))+row) == SPACE) { 
	       *((*(current_level+(col-1)))+row) = BEAST;
	       *((*(current_level+col))+row) = SPACE;
	       Monstermoved = YES;
	    }
	    else if( *((*(current_level+(col-1)))+row)==PRONGS ) {
	       *((*(current_level+col))+row) = SPACE;
	       *((*(current_level+(col-1)))+row) = BEAST;
	       sound(ROAR);
	       DIE = 1;
	    }     
	    
		    
	    else if( row < prongsy && *((*(current_level+col))+(row+1)) == SPACE) { 
	       *((*(current_level+col))+(row+1)) = BEAST;
	       *((*(current_level+col))+row) = SPACE;
	       Monstermoved = YES;
	    }
	    else if(*((*(current_level+col))+(row+1)) == PRONGS ) {
	       *((*(current_level+col))+row) = SPACE;
	       *((*(current_level+col))+(row+1)) = BEAST;
	       sound(ROAR);
	       DIE = 1;
	    }
	       
	    
	    
	    else if( row > prongsy && (current_level[col][row-1] == SPACE)){ 
	       current_level[col][row-1] = BEAST;
	       *((*(current_level+col))+row) = SPACE;
	       Monstermoved = YES;
	    }
	    else if(current_level[col][row-1] == PRONGS ) {
	       *((*(current_level+col))+row) = SPACE;
	       current_level[col][row-1] = BEAST;
	       sound(ROAR);
	       DIE = 1;
	    }
	 }
	 
	 
	 /* If a Cube */
	 else if(*((*(current_level+col))+row) == CUBE && Cubemoved == NO) { 
	       	     	       
	    if(col < prongsx && *((*(current_level+(col+1)))+row)==SPACE ) { 
	       *((*(current_level+(col+1)))+row) = CUBE;
	       *((*(current_level+col))+row) = SPACE;
	       sound(OW);
	       Cubemoved = YES;
	    }
	    else if( col > prongsx && *((*(current_level+(col-1)))+row) == SPACE) { 
	       *((*(current_level+(col-1)))+row) = CUBE;
	       *((*(current_level+col))+row) = SPACE;
	       sound(OW);
	       Cubemoved = YES;
	    }
	    else if( row < prongsy && *((*(current_level+col))+(row+1)) == SPACE) { 
	       *((*(current_level+col))+(row+1)) = CUBE;
	       *((*(current_level+col))+row) = SPACE;
	       sound(OW);
	       Cubemoved = YES;
	    }
	    else if( row > prongsy && (current_level[col][row-1] == SPACE)){ 
	       current_level[col][row-1] = CUBE;
	       *((*(current_level+col))+row) = SPACE;
	       sound(OW);
	       Cubemoved = YES;
	    }
	 }
	 
	 
	 /* if an egg.... */
	 else if(*((*(current_level+col))+row) == EGG) {
	    
	    if(row > 46) {
	       *((*(current_level+col))+row) = SPACE;
	       current_level[col][0] = EGG;
	    }
	    /* iF UNDERNEATH IS DIAMOND OR ROCK */
	    if(*((*(current_level+col))+(row+1)) == DIAMOND ||
	       *((*(current_level+col))+(row+1)) == ROCK) {
		  /* checks area to the right of the diamond or rock */
		  if(*((*(current_level+(col+1)))+row) == SPACE &&
		     *((*(current_level+(col+1)))+(row+1)) == SPACE) {
			*((*(current_level+col))+row) = SPACE;
			*((*(current_level+(col+1)))+row) = EGG;
			*((*(gravity+col))+row) = STATIONARY;
			gravity[col+1][row] = FALLING;
		     }
		  /* otherwise checks to left ...*/
		  else if(*((*(current_level+(col-1)))+row) == SPACE &&
			  *((*(current_level+(col-1)))+(row+1)) == SPACE) {
			     *((*(current_level+col))+row) = SPACE;
			     *((*(current_level+(col-1)))+row) = EGG;
			     *((*(gravity+col))+row) = STATIONARY;
			     gravity[col-1][row] = FALLING;
			  }
	       }
	    if(*((*(current_level+col))+(row+1)) == SPACE) {
	       *((*(current_level+col))+row) = SPACE;
	       *((*(current_level+col))+(row+1)) = EGG;
	       *((*(gravity+col))+row) = STATIONARY;
	       *((*(gravity+col))+(row+1)) = FALLING;
	    }
	    	    
	    if(*((*(current_level+col))+(row+1)) != SPACE && 
	       *((*(gravity+col))+row) == FALLING) {
		  *((*(gravity+col))+row) = STATIONARY;
		  *((*(current_level+col))+row) = BEAST;
		  sound(GETYE);
	       }
	 }
	  
	 
	 
	 /* if a bomb.... */
	 else if(*((*(current_level+col))+row) == BOMB) {
	    
	    if(row > 46) {
	       *((*(current_level+col))+row) = SPACE;
	       current_level[col][0] = BOMB;
	    }
	    /* iF UNDERNEATH IS DIAMOND OR ROCK */
	    if(*((*(current_level+col))+(row+1)) == DIAMOND ||
	       *((*(current_level+col))+(row+1)) == ROCK) {
		  /* checks area to the right of the diamond or rock */
		  if(*((*(current_level+(col+1)))+row) == SPACE &&
		     *((*(current_level+(col+1)))+(row+1)) == SPACE) {
			*((*(current_level+col))+row) = SPACE;
			*((*(current_level+(col+1)))+row) = BOMB;
			*((*(gravity+col))+row) = STATIONARY;
			gravity[col+1][row] = FALLING;
		     }
		  /* otherwise checks to left ...*/
		  else if(*((*(current_level+(col-1)))+row) == SPACE &&
			  *((*(current_level+(col-1)))+(row+1)) == SPACE) {
			     *((*(current_level+col))+row) = SPACE;
			     *((*(current_level+(col-1)))+row) = BOMB;
			     *((*(gravity+col))+row) = STATIONARY;
			     gravity[col-1][row] = FALLING;
			  }
	       }
	    if(*((*(current_level+col))+(row+1)) == SPACE) {
	       *((*(current_level+col))+row) = SPACE;
	       *((*(current_level+col))+(row+1)) = BOMB;
	       *((*(gravity+col))+row) = STATIONARY;
	       *((*(gravity+col))+(row+1)) = FALLING;
	    }
	    
	    
	    if(*((*(current_level+col))+(row+1)) != SPACE && 
	       *((*(gravity+col))+row) == FALLING) {
		  *((*(gravity+col))+row) = STATIONARY;
		  sound(EXPLODE);
		  for(posx = 1; posx > -2; posx--) {
		     for(posy = 1; posy > -2; posy--) {
			if(col+posx > 0 && col+posx < 64) {
			   if(row+posy > 0 && row+posy < 48) {
			      if(current_level[col+posx][col+posy] == DIAMOND
				 || current_level[col+posx][row+posy]==MORPHBLOCK 
				 || current_level[col+posx][row+posx]==CHANGER) {
			      }
			      if(current_level[col+posx][row+posy] == CUBE) {
				 sound(WHINE);
				 current_level[col+posx][row+posy] = DIAMOND;
				 diamondcount++;
			      }
			      else if(current_level[col+posx][row+posy] == BEAST) {
				 sound(SPLAT);
				 current_level[col+posx][row+posy] = DIAMOND;
				 diamondcount++;
			      }
			      else if(current_level[col+posx][row+posy] == PRONGS) {
				 DIE = 1;
			      }
			      else {
				 current_level[col+posx][row+posy] = DIAMOND;
				 diamondcount++;
			      }
			   }
			}
		     }
		  }
	       }
	 }
	 
	 /* if a rock.....*/
	 else if(*((*(current_level+col))+row) == ROCK) {
	    
	    if(row > 46) {
	       *((*(current_level+col))+row) = SPACE;
	       current_level[col][0] = ROCK;
	    }

	    /* if object underneath is a diamond or rock*/
	    if(*((*(current_level+col))+(row+1)) == DIAMOND ||
	       *((*(current_level+col))+(row+1)) == ROCK) {
		  /* checks area to the right of the diamond or rock */
		  if(*((*(current_level+(col+1)))+row) == SPACE &&
		     *((*(current_level+(col+1)))+(row+1)) == SPACE) {
			*((*(current_level+col))+row) = SPACE;
			*((*(current_level+(col+1)))+row) = ROCK;
			*((*(gravity+col))+row) = STATIONARY;
			gravity[col+1][row] = FALLING;
			sound(BOOM);
		     }
		  /* otherwise checks to left ...*/
		  else if(*((*(current_level+(col-1)))+row) == SPACE &&
			  *((*(current_level+(col-1)))+(row+1)) == SPACE) {
			     *((*(current_level+col))+row) = SPACE;
			     *((*(current_level+(col-1)))+row) = ROCK;
			     *((*(gravity+col))+row) = STATIONARY;
			     gravity[col-1][row] = FALLING;
			     sound(BOOM);
			  }
	       }
	    
	    /* If object underneath is a SPACE */
	    if(*((*(current_level+col))+(row+1)) == SPACE) {
	       if(current_level[col][row+2] != SPACE) {
		  sound(BOOM);
	       }
	       *((*(current_level+col))+row) = SPACE;
	       *((*(current_level+col))+(row+1)) = ROCK;
	       *((*(gravity+col))+row) = STATIONARY;
	       *((*(gravity+col))+(row+1)) = FALLING;
	    }
	    
	    /* If object underneath is beastie */
	    if(*((*(current_level+col))+(row+1)) == BEAST) {
	       *((*(current_level+col))+row) = SPACE;
	       *((*(current_level+col))+(row+1)) = ROCK;
	       sound(SPLAT);
	       score+=5;
	    }
	    
	    /* If object underneath is mannie */
	    if(*((*(current_level+col))+(row+1)) == PRONGS){
	       if(*((*(gravity+col))+row) == FALLING){
		  DIE = 1;
		  sound(EXPLODE);
		  *((*(current_level+col))+row) = SPACE;
	       }
	    }
	 }
	 
	 
	 
	 
	 /* if a diamond.....*/
	 else if(FALLING_DIAMONDS == ON) {
	    
	    if(*((*(current_level+col))+row) == DIAMOND) {
	    
	
	       if(*((*(current_level+col))+(row+1)) == DIAMOND ||
		  *((*(current_level+col))+(row+1)) == ROCK) {
		  
		     
		     
		     if(*((*(current_level+(col+1)))+row) == SPACE &&
			*((*(current_level+(col+1)))+(row+1)) == SPACE) {
			   *((*(current_level+col))+row) = SPACE;
			   *((*(current_level+(col+1)))+row) = DIAMOND;
			   *((*(gravity+col))+row) = STATIONARY;
			   gravity[col+1][row] = FALLING;
			}
		     
		     else if(*((*(current_level+(col-1)))+row) == SPACE &&
			     *((*(current_level+(col-1)))+(row+1)) == SPACE) {
				*((*(current_level+col))+row) = SPACE;
				*((*(current_level+(col-1)))+row) = DIAMOND;
				*((*(gravity+col))+row) = STATIONARY;
				gravity[col-1][row] = FALLING;
				sound(WHEEP);
			     }
		  }
	       
	       
	       
	       if(*((*(current_level+col))+(row+1)) == SPACE) {
		  if(current_level[col][row+2] != SPACE) {
		     sound(WHEEP);
		  }
		  *((*(current_level+col))+row) = SPACE;
		  *((*(current_level+col))+(row+1)) = DIAMOND;
		  *((*(gravity+col))+row) = STATIONARY;
		  *((*(gravity+col))+(row+1)) = FALLING;
	       }
	       
	       
	       if(*((*(current_level+col))+(row+1)) == PRONGS){
		  if(*((*(gravity+col))+row) == FALLING){
		     DIE = 1;
		     *((*(current_level+col))+row) = SPACE;
		  }
	       }
	    }
	 }
	 else *((*(current_level+col))+row) = *((*(current_level+col))+row);
      }
   }
}

   
   
/*
 * Passed position in array, and draws screen with this position at
 * centre. Screen is 6*6. The bitmaps are not compiled, as the prog runs way 
 * too fast as it is!
 */
draw_screen( int x, int y) {
   
   int col,row,xpos,ypos;
   xpos=5;
   ypos=5;
   
   for(col = x-8; col < x+8; col++) {
      for(row = y-7; row < y+7; row++) {
	 if(col > -1 && row > -1 && col < 64 && row < 48) {
	    if(*((*(current_level+col))+row) == PRONGS) {
	       gl_putbox(xpos, ypos,32,32, *(graphics+PRONGS+manimframe));
	    }
	    else {
	       gl_putbox(xpos, ypos,32,32,graphics[(*((*(current_level+col))+row))+animframe]);
	    }
	 }
	 else { gl_putbox(xpos, ypos, 32,32,*(graphics+OUTSIDE));}
	 ypos+=32;
      }
      xpos+=32;
      ypos=5;
   }
}

void display_map(void) {
   int col,row;
   for(col = 0; col < 64; col++) {
      for(row = 0; row < 48; row++) {
	 gl_putbox((col*10),(row*10),10,10, map_graphics[*((*(current_level+col))+row)]);
      }
   }
}



/*
 * 
 * Draw status 
 * 
 */
void draw_status(void) {
   
   int i,j,col,row, diamonds_printed;
   col = 0;
   diamonds_printed = 0;
   for(i=0;i<LIVES;i++) {
      gl_putbox(534+col, 32,32,32, graphics[PRONGS+manimframe]);
      col+=32;
   }
   if(HASMAP == YES) {
      gl_putboxmask(566,96,32,32,graphics[MAP+animframe]);
   }
   if(diamondcount > 200) {
      for(i = 0; i < 200; i+=10) {
	 for(j = 0; j < 100; j+=10) {
	    gl_putboxmask(530+j, 150+i,10,10, map_graphics[DIAMOND]);
 	 }
      }
   }
   if(diamondcount < 201) {
      for(i = -10; i < 200; i+=10) {
	 for(j = -10; j < 100; j+=10) {
	    if(diamonds_printed < diamondcount) {
	       gl_putboxmask(530+j, 150+i, 10,10,map_graphics[DIAMOND]);
	       diamonds_printed++;
	    }
	    else {
	       gl_putboxmask(530+j, 150+i,10,10, map_graphics[SPACE]);
	    }
	 }
      }
   }
}



/*
 * 
 * 
 *               ***************************************
 *                 MAIN LOOP
 *               ***************************************
 * 
 * 
 * 
 */
int main_loop() {

   /*
    * 
    *   ******************************************
    *    PRE LOOP STUFF
    *   ******************************************
    * 
    * 
    */
   
   int i;
   start_t coords;
   GraphicsContext realscreen;
   GraphicsContext virtualscreen;
   PRONGS = PRONGSDOWN;
   copy_level(current);
   reset_gravity();
   coords = find_start(current);
   diamondcount = coords.no_of_diamonds + coords.no_of_morphers;
   prongsx = coords.x;
   prongsy = coords.y;
   LIVES = 3;
   CHANGE = OFF;
   HASMAP = NO;
   printf("current = %d\nProngsx = %d\nprongsy = %d\n", current,prongsx, prongsy);
   gl_setcontextvga(10);
   gl_getcontext( &realscreen );
   gl_setcontextvgavirtual(10);
   gl_getcontext( &virtualscreen);
   gl_clearscreen(4);
   draw_status();
   draw_screen(prongsx, prongsy);
   gl_copyscreen(&realscreen);
   sound(END);

   /*
    * 
    *     ******************************************
    *            LOOP
    *     ******************************************
    * 
    * 
    */
   while(1) {
      keyboard_update();
      update_level();
      /*
       * 
       *        *************************************
       *           LEFT KEY PRESSED
       *        *************************************
       * 
       */
      
      if(keyboard_keypressed(SCANCODE_O)) {
	 PRONGS = PRONGSLEFT;
	 manimframe++;
	 if(manimframe > 3) {
	    manimframe = 0;
	 }
	 if(*((*(current_level+(prongsx-1)))+prongsy)==BRICK) {
	    }
	 else if(*((*(current_level+(prongsx-1)))+prongsy)==VIRUS) {
	 }
	 else if(*((*(current_level+(prongsx-1)))+prongsy)==CUBE) {
	 }
	 else if(*((*(current_level+(prongsx-1)))+prongsy)==MORPHBLOCK) {
	 }
	 else if(*((*(current_level+(prongsx-1)))+prongsy)==MAP) {
	    sound(MAPSOUND);
	    HASMAP = YES;
	    *((*(current_level+(prongsx-1)))+prongsy)=SPACE;
	 }
	 else if(*((*(current_level+(prongsx-1)))+prongsy)==ROCK) {
	    if(*((*(current_level+(prongsx-2)))+prongsy)==SPACE) {
	       *((*(current_level+(prongsx-2)))+prongsy)=ROCK;
	       *((*(current_level+(prongsx-1)))+prongsy)=SPACE;
	       *((*(current_level+prongsx))+prongsy) = SPACE;
	       prongsx--;
	       sound(GRIND);
	       if(prongsx<0) {
		  prongsx=0;
	       }
	    }
	    if(*((*(current_level+(prongsx-2)))+prongsy)==BEAST) {
	       *((*(current_level+(prongsx-2)))+prongsy)=ROCK;
	       *((*(current_level+(prongsx-1)))+prongsy)=SPACE;
	       *((*(current_level+prongsx))+prongsy) = SPACE;
	       prongsx--;
	       if(prongsx<0) {
		  prongsx=0;
	       }
	       sound(SPLAT);
	       score+=5;
	    }
	 }

	 else if(*((*(current_level+(prongsx-1)))+prongsy)==EGG) {
	    if(*((*(current_level+(prongsx-2)))+prongsy)==SPACE) {
	       *((*(current_level+(prongsx-2)))+prongsy)=EGG;
	       *((*(current_level+(prongsx-1)))+prongsy)=SPACE;
	       *((*(current_level+prongsx))+prongsy) = SPACE;
	       prongsx--;
	       sound(GRIND);
	       if(prongsx<0) {
		  prongsx=0;
	       }
	    }
	 }
	 
	 else if(*((*(current_level+(prongsx-1)))+prongsy)==BOMB) {
	    if(*((*(current_level+(prongsx-2)))+prongsy)==SPACE) {
	       *((*(current_level+(prongsx-2)))+prongsy)=BOMB;
	       *((*(current_level+(prongsx-1)))+prongsy)=SPACE;
	       *((*(current_level+prongsx))+prongsy) = SPACE;
	       prongsx--;
	       sound(GRIND);
	       if(prongsx<0) {
		  prongsx=0;
	       }
	    }
	 }
	 else if(*((*(current_level+(prongsx-1)))+prongsy) == CHANGER) {
	    *((*(current_level+(prongsx-1)))+prongsy) = SPACE;
	    sound(CLICK);
	    CHANGE = ON;
	 }
	 else if(*((*(current_level+(prongsx-1)))+prongsy) == SAND) {
	    score++;
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    sound(SLURP);
	    prongsx--;
	    if(prongsx<0) {
	       prongsx=0;
	    }
	    gravity[prongsx][prongsy-1] = STATIONARY;
	 }
	 else if(*((*(current_level+(prongsx-1)))+prongsy) == DIAMOND) {
	    score += 10;
	    diamondcount--;
	    sound(WHEEP);
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsx--;
	    if(prongsx<0) {
	       prongsx=0;
	    }
	    gravity[prongsx][prongsy-1] = STATIONARY;
	 }
	 else {
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsx--;
	    if(prongsx<0) {
	       prongsx=0;
	    }
	 }
	 *((*(current_level+prongsx))+prongsy) = PRONGS;
      }
      
      /*
       * 
       * 
       * 
       *              ********************************
       *                RIGHT KEY PRESSED
       *              ********************************
       * 
       * 
       * 
       */
      if(keyboard_keypressed(SCANCODE_P)) {
	 PRONGS = PRONGSRIGHT;
	 manimframe++;
	 if(manimframe > 3) {
	    manimframe = 0;
	 }
	 if(current_level[prongsx+1][prongsy]==BRICK) {
	 }
	 else if(current_level[prongsx+1][prongsy]==VIRUS) {
	 }
	 else if(current_level[prongsx+1][prongsy]==MORPHBLOCK) {
	 }
	 else if(current_level[prongsx+1][prongsy]==CUBE) {
	 }
	 else if(current_level[prongsx+1][prongsy]==BEAST) {
	    sound(ROAR);
	    DIE = 1;
	 }
	 else if(current_level[prongsx+1][prongsy]==MAP) {
	    sound(MAPSOUND);
	    HASMAP = YES;
	    current_level[prongsx+1][prongsy]=SPACE;
	 }
	 else if(current_level[prongsx+1][prongsy]==ROCK) {
	    if(current_level[prongsx+2][prongsy]==SPACE) {
	       current_level[prongsx+2][prongsy]=ROCK;
	       current_level[prongsx+1][prongsy]=SPACE;
	       *((*(current_level+prongsx))+prongsy) = SPACE;
	       sound(GRIND);
	       prongsx++;
	       if(prongsx>64) {
		  prongsx=64;
	       }
	    }
	    if(current_level[prongsx+2][prongsy]==BEAST) {
	       current_level[prongsx+2][prongsy]=ROCK;
	       current_level[prongsx+1][prongsy]=SPACE;
	       *((*(current_level+prongsx))+prongsy) = SPACE;
	       sound(SPLAT);
	       score+=5;
	       prongsx++;
	       if(prongsx>64) {
		  prongsx=64;
	       }
	    }
	 }
	 else if(current_level[prongsx+1][prongsy] == CHANGER) {
	    current_level[prongsx+1][prongsy] = SPACE;
	    sound(CLICK);
	    CHANGE = ON;
	 }
	 else if(current_level[prongsx+1][prongsy]==EGG) {
	    if(current_level[prongsx+2][prongsy]==SPACE) {
	       current_level[prongsx+2][prongsy]=EGG;
	       current_level[prongsx+1][prongsy]=SPACE;
	       *((*(current_level+prongsx))+prongsy) = SPACE;
	       prongsx++;
	       sound(GRIND);
	       if(prongsx>64) {
		  prongsx=64;
	       }
	    }
	 }
	 else if(current_level[prongsx+1][prongsy]==BOMB) {
	    if(current_level[prongsx+2][prongsy]==SPACE) {
	       current_level[prongsx+2][prongsy]=BOMB;
	       current_level[prongsx+1][prongsy]=SPACE;
	       *((*(current_level+prongsx))+prongsy) = SPACE;
	       prongsx++;
	       sound(GRIND);
	       if(prongsx>64) {
		  prongsx=64;
	       }
	    }
	 }
	 else if(current_level[prongsx+1][prongsy] == SAND) {
	    score++;
	    sound(SLURP);
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsx++;
	    if(prongsx>64) {
	       prongsx=64;
	    }
	    gravity[prongsx][prongsy-1] = STATIONARY;
	 }
	 else if(current_level[prongsx+1][prongsy] == DIAMOND) {
	    score += 10;
	    diamondcount--;
	    sound(WHEEP);
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsx++;
	    if(prongsx>64) {
	       prongsx=64;
	    }
	    gravity[prongsx][prongsy-1] = STATIONARY;
	 }
	 else {
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsx++;
	    if(prongsx>64) {
	       prongsx=64;
	    }
	 }	 
	 *((*(current_level+prongsx))+prongsy) = PRONGS;
      }
      
      /*
       * 
       * 
       * 
       *           *****************************
       *                UP KEY PRESSED
       *           *****************************
       * 
       * 
       * 
       */
      if(keyboard_keypressed(SCANCODE_Q)) {
	 PRONGS = PRONGSUP;
	 manimframe++;
	 if(manimframe > 3) {
	    manimframe = 0;
	 }
	 if(current_level[prongsx][prongsy-1]==BRICK ||
	    current_level[prongsx][prongsy-1]==ROCK) {
	    }
	 else if(current_level[prongsx][prongsy-1]==VIRUS) {
	 }
	 else if(current_level[prongsx][prongsy-1]==EGG) {
	 }
	 else if(current_level[prongsx][prongsy-1]==BOMB) {
	 }
	 else if(current_level[prongsx][prongsy-1]==CUBE) {
	 }

	 else if(current_level[prongsx][prongsy-1]==MORPHBLOCK) {
	 }
	 else if(current_level[prongsx][prongsy-1]==BEAST) {
	    sound(ROAR);
	    DIE = 1;
	 }
	 else if(current_level[prongsx][prongsy-1]==MAP) {
	    sound(MAPSOUND);
	    HASMAP = YES;
	    current_level[prongsx][prongsy-1]=SPACE;
	 }
	 else if(current_level[prongsx][prongsy-1] == CHANGER) {
	    current_level[prongsx][prongsy-1] = SPACE;
	    sound(CLICK);
	    CHANGE = ON;
	 }
	 else if(current_level[prongsx][prongsy-1] == SAND) {
	    score++;
	    sound(SLURP);
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsy--;
	    if(prongsy<1) {
	       prongsy=1;
	    }
	    gravity[prongsx][prongsy-1] = STATIONARY;
	 }
	 else if(current_level[prongsx][prongsy-1] == DIAMOND) {
	    score += 10;
	    diamondcount--;
	    sound(WHEEP);
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsy--;
	    if(prongsy<1) {
	       prongsy=1;
	    }
	    gravity[prongsx][prongsy-1] = STATIONARY;
	 }
	 else {
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsy--;
	    if(prongsy<1) {
	       prongsy=1;
	    }
	 }
	 *((*(current_level+prongsx))+prongsy) = PRONGS;
      }
      
      
      /*
       * 
       * 
       *               ***************************
       *                 DOWN KEY PRESSED
       *               ***************************
       * 
       * 
       * 
       */
      if(keyboard_keypressed(SCANCODE_A)) {
	 PRONGS = PRONGSDOWN;
	 manimframe++;
	 if(manimframe > 3) {
	    manimframe = 0;
	 }
	 if(current_level[prongsx][prongsy+1]==BRICK ||
	    current_level[prongsx][prongsy+1]==ROCK) {
	    }
	 else if(current_level[prongsx][prongsy+1]==VIRUS) {
	 }
	 else if(current_level[prongsx][prongsy+1]==MORPHBLOCK) {
	 }
	 else if(current_level[prongsx][prongsy+1]==CUBE) {
	 }
	 else if(current_level[prongsx][prongsy+1]==EGG) {
	 }
	 else if(current_level[prongsx][prongsy+1]==BOMB) {
	 }
	 else if(current_level[prongsx][prongsy+1]==BEAST) {
	    sound(ROAR);
	    DIE = 1;
	 }
	 else if(current_level[prongsx][prongsy+1]==MAP) {
	    sound(MAPSOUND);
	    HASMAP = YES;
	    current_level[prongsx][prongsy+1]=SPACE;
	 }
	 else if(current_level[prongsx][prongsy+1] == CHANGER) {
	    current_level[prongsx][prongsy+1] = SPACE;
	    sound(CLICK);
	    CHANGE = ON;
	 }
	 else if(current_level[prongsx][prongsy+1] == SAND) {
	    score++;
	    sound(SLURP);
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsy++;
	    if(prongsy>48) {
	       prongsy=48;
	    }
	    gravity[prongsx][prongsy-1] = STATIONARY;
	 }
	 else if(current_level[prongsx][prongsy+1] == DIAMOND) {
	    score += 10;
	    diamondcount--;
	    sound(WHEEP);
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsy++;
	    if(prongsy>48) {
	       prongsy=48;
	    }
	    gravity[prongsx][prongsy-1] = STATIONARY;
	 }
	 else {   /* Rubout prongs */
	    *((*(current_level+prongsx))+prongsy) = SPACE;
	    prongsy++;
	    if(prongsy>48) {
	       prongsy=48;
	    }
	 }
	 *((*(current_level+prongsx))+prongsy) = PRONGS;
      }

      /*
       * 
       * 
       *         ****************************
       *           MAP BUTTON
       *         ****************************
       * 
       * 
       */
      if(keyboard_keypressed(SCANCODE_SPACE) && HASMAP == YES) {
	 
	 sound(MAPSOUND);
	 display_map();
	 gl_copyscreen(&realscreen);
	 sleep(2);
	 sound(MAPSOUND);
	 gl_clearscreen(4);
	 gl_copyscreen(&realscreen);
      }
      /* Suicide button */
      if(keyboard_keypressed(SCANCODE_ESCAPE)) {
	 keyboard_clearstate();
	 DIE = 1;
      }
      
      
      
      /*
       * 
       * 
       * 
       *    ***********************************
       *     POST LOOP STUFF
       *    ***********************************
       * 
       * 
       * 
       */
      
      draw_status();
      draw_screen(prongsx,prongsy);
      gl_copyscreen( &realscreen );
      
      if(DIE == 1) {
	 DIE = 0;
	 sound(SCREAM);
	 
	 /* Screen pulse thingy */
	 gl_setcontext(&realscreen);
	 for(i=17;i<30;i++) {
	    gl_clearscreen(i);
	 }
	 for(i=30;i>16;i--) {
	    gl_clearscreen(i);
	 }
	 gl_setcontext(&virtualscreen);
	 LIVES--;
	 if(LIVES == 0) {
	    if(SOUND == ON) {
	       sound(TOC);
	       sleep(5);
	    }
	    return EXIT_FAILURE;
	 }
	 
	 copy_level(current);
	 reset_gravity();
	 CHANGE = OFF;
	 HASMAP = NO;
	 diamondcount = coords.no_of_diamonds + coords.no_of_morphers;
	 prongsx = coords.x;
	 prongsy = coords.y;
	 gl_clearscreen(4);
	 gl_copyscreen(&realscreen);
      }
      if(diamondcount == 0) {
	 return EXIT_SUCCESS;
      }
      animframe++; 
      if(animframe > 3) {
	 animframe = 0;
      }
      Monstermoved = NO;
      Cubemoved = NO;
      Virusmoved = NO;
   }
}

/* 
 * 
 * 
 * 
 *           ************************************************
 *            PLAY THE GAME LOOP
 *           ************************************************
 * 
 * 
 * 
 */
void play_the_game(void) {
   int i;
   int ALIVE = YES;
   initialise();
   
   while(ALIVE == YES) {
      if(main_loop() == EXIT_FAILURE) {
	 ALIVE = NO;
      }
      else {
	 current++;
	 if(current > NO_OF_LEVELS) {
	    COMPLETED = YES;
	    ALIVE = NO;
	 }
      }
   } 
   keyboard_close();
   Snd_restore();
}



int main(void)  {
   
   int i, cheese;
   char sound,dia, ch;
   load_graphics();
   load_map_graphics();
   load_levels();
      
   system("clear");
   printf("\n\n\t\tL i n u x   L i z a r d s !\n\nHi Resolution version\n\nWritten by John M Dow\nVersion 1.3\n\n");
   printf("Control keys are:\n");
   printf("\t\tQ - Up \t\t\tA - Down\n");
   printf("\t\tO - Left\t\tP - Right\n");
   printf("\n\t\tEscape - Commit suicide!, SPACE - Map\n");
   
      
   printf("\n\nLevel Password? (00000 for level 1):");
   scanf("%d", &cheese);
   current = 0;
   for( i = 0; i < 20; i++ ) {
      if( cheese == words[i] ) {
	 current = i;
      }
   }
   printf("\nDo you wish to have strange noises? (y for yay, anything else for nay):");
   scanf("%s",&sound);
   if(sound == 'y') {
      SOUND = ON;
   }
   else{
      SOUND = OFF;
   }
   printf("\nDo you want falling diamonds? (y for yay, anything else for nay):");
   scanf("%s",&dia);
   if(dia == 'y') {
      FALLING_DIAMONDS = ON;
   }
 

   
   system("clear");
   play_the_game();
   system("clear");
   if(COMPLETED == NO) {
      printf("You scored a triumphant %d and reached level %d.\n",score, current+1);
      printf("\n\nThe password for level %d is %d.\n\n",current+1,words[current]);
      printf("\n\n\n\n");
   }
   if(COMPLETED == YES) {
      printf("Err...... I'm not sure how you managed to do that. I'm going to \n");
      printf("have to design more levels.\n");
   }  
   return EXIT_SUCCESS;
}
