// MUTANT XPIDERS
    // Version 1.4
    //
    //	History
    //	Date			Comments
    //	01/06/1999	Built skeleton. Got keys to work (zx/)
    // 02/06/99  Designed ship and implemented BOB for it
    // 03/06/99  Got firing working, just right
    // 04/06/99  Refined firing code further
    // 05/06/99  Ship destroys. Started on spider-web code + finished.
    // 06/06/99  Procedurised code and finished game logic (needs tweaking)
    // 07/06/99  Added firing/launching sounds. Added backdrop.
    // 08/06/99  Added 'wave' logic.
    // 09/06/99  Re-coded between-screen logic
    // 10/06/99  Reduced number of objects to speed up cycles. Created variables-per-wave.
    // 12/06/99	 Found bug in Spider-moving/firing routine. Pesky joystick bug also produces random up/left moves!!
    // 13/06/99  Finished off level-logic and sounds. Title screen and re-start.
    //	15/06/99	 Corrected minor sound bug and added version number to front screen.
    // 16/06/99  Made 'start' level easier.
    // 19/06/99  Added 'Continue' option. Added 'wait until all fire out' code.
    // 20/06/99  Tidied up end wave/game logic. Added end-of-wave message. Various screen dissolves implemented. (V1.3)
    // 11/07/99  Started making cSpider class (v1.4)
    // 12/07/99	 Continued "". Created generic cBOB class.
    // 13/07/99	 Finished making cSpider class. Started on cSpiderFire class
    // 14/07/99	 Created classes for all multiple sounds
    // 21/07/99	 Created simple base class for Sounds
    // 22/07/99	 Did cBaseFire class
    // 23/07/99  Changing globals into class statics for neatness
    // Released as verion 1.4
    // 16/07/00  Version 1.5 - Added sounds/logic for extra life feature. Added PAUSE facility.
    // 17/07/00  Started adding DEMO mode.
    // 18/07/00  Ship movement for demo mode
    // 21/07/00  Implement realtime before demo starts
    // 22/07/00  Timer countdown display
    
    // INCLUDES ///////////////////////////////////////////////
    
    //#define ship_nohit	//When defined, this stop our Base Ship from dying - for debugging purposes
    
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>   // include important windows stuff
    #include <windowsx.h>
    #include <mmsystem.h>
    #include <iostream.h> // include important C/C++ stuff
    #include <conio.h>
    #include <stdlib.h>
    #include <malloc.h>
    #include <memory.h>
    #include <string.h>
    #include <stdarg.h>
    #include <stdio.h>
    #include <math.h>
    #include <io.h>
    #include <fcntl.h>
    #include <time.h>
    
    #include <ddraw.h>  // directX includes
    #include <dsound.h>
    #include <dinput.h>
    #include "gpdumb1.h" // game library includes
    #include "gpdumb2.h"
    
    int Game_Main(void *parms);
    
    // DEFINES ////////////////////////////////////////////////
    
    // defines for windows
    #define WINDOW_CLASS_NAME "WINXCLASS"  // class name
    
    #define WINDOW_WIDTH    640   // size of window
    #define WINDOW_HEIGHT   480
    
    #define BASE_FIRE_COUNT           26    // Number of individual ship firing at any one time.
    #define BASE_FIRE_SOUND_COUNT     10    // Number of simultaneous base fire sounds
    
    #define SPIDER_COUNT              20    // Number of Mutant Spiders catered for
    
    #define SPIDER_FIRE_COUNT         10	 // Count of Spider Fire on the go at any one time
    #define SPIDER_FIRE_SOUND_COUNT   10    // Number of simultaneous spider fire sounds
    
    #define SPIDER_START_SOUND_COUNT   5    // Number of simultaneous spider start sounds
    #define SPIDER_LAUNCH_SOUND_COUNT  5    // Number of simultaneous spider move sounds
    #define SPIDER_HIT_SOUND_COUNT     5    // Number of simultaneous spider hits
    
    
    // CLASSES   //////////////////////////////////////////////
    
    // BOB classes
    
    class cBOB
    {
    	public:
    		cBOB()
    		{}
    
    		~cBOB()
    		{
    			Destroy_BOB2(&the_BOB);
    		}
    
    		BOB* get_pBOB()
    		{
    			return &the_BOB;
    		}
    
    		int isAlive() const
    		{
    			if (the_BOB.state == BOB_STATE_ALIVE)
    				return TRUE;
    			else
    				return FALSE;
    		}
    
    		void setAlive()
    		{
    			the_BOB.state = BOB_STATE_ALIVE;
    		}
    
    		int isDying() const
    		{
    			if (the_BOB.state == BOB_STATE_DYING)
    				return TRUE;
    			else
    				return FALSE;
    		}
    
    		void setDying()
    		{
    			the_BOB.state = BOB_STATE_DYING;
    		}
    
    		int isDead() const
    		{
    			if (the_BOB.state == BOB_STATE_DEAD)
    				return TRUE;
    			else
    				return FALSE;
    		}
    
    		void setDead()
    		{
    			the_BOB.state = BOB_STATE_DEAD;
    		}
    
    		int getX() const
    		{
    				return the_BOB.x;
    		}
    
    		void setX(int x_coord)
    		{
    				the_BOB.x = x_coord;
    		}
    
    		int getY() const
    		{
    				return the_BOB.y;
    		}
    
    		void setY(int y_coord)
    		{
    				the_BOB.y = y_coord;
    		}
    
    		int getXV() const
    		{
    				return the_BOB.xv;
    		}
    
    		int getYV() const
    		{
    				return the_BOB.yv;
    		}
    
    	protected:
    		BOB the_BOB;		// Multi-purpose BOB with generic methods - basis for specific BOBs
    };
    
    
    class cBase : public cBOB
    {
    	public:
    
    		cBase() : demo_vel_x(0), demo_vel_y(0)
    		{}	// Does nothing - all initialisation are done in loadBOB as they cannot be performed at object instantiation time
    
    		~cBase()
    		{}	// Does nothing - all clearing up are done in cBOB
    
    		void loadBOB()
    		{
    			Load_Bitmap_File(&bitmap8bit, "base_ship.bmp");
    			// now create the Base FIRE
    			Create_BOB(&the_BOB,0,0,
    				32,32, 						// Size of each frame
    				12,							// Number of frames
    				BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM,
    				DDSCAPS_SYSTEMMEMORY);
    			setAlive();
    			Set_Vel_BOB(&the_BOB,6,6); 	// Set vertical/horizontal speed - doesn't change;
    			// load base_ship frames
    			for (int index=0; index<6; index++)
    			{
    				Load_Frame_BOB(&the_BOB,&bitmap8bit,index,index,0,BITMAP_EXTRACT_MODE_CELL);
    				Load_Frame_BOB(&the_BOB,&bitmap8bit,index+6,index,1,BITMAP_EXTRACT_MODE_CELL);
    			}
    			Set_Anim_Speed_BOB(&the_BOB,1);	// set animation speed
    			int base_ship_OK[6] = {0,1,2,3,4,5};
    			Load_Animation_BOB(&the_BOB,0,6,base_ship_OK);
    			int base_ship_explode[6] = {6,7,8,9,10,11};
    			Load_Animation_BOB(&the_BOB,1,6,base_ship_explode);
    			Unload_Bitmap_File(&bitmap8bit);	// unload data infile
    			Set_Animation_BOB(&the_BOB,0);	// Set Base Ship animation to normal
    		}
    
    		void reset()
    		{
    			setAlive();
    			Set_Animation_BOB(&the_BOB,0); 										// reset Base Ship animation
    			the_BOB.curr_frame = 0;													// ... and manually set first frame
    			Set_Pos_BOB(&the_BOB,SCREEN_WIDTH/2, SCREEN_HEIGHT-31-20);	// set position (X_position of base at bottom)
    			base_firing = 0;
    			base_fire2  = 99;
    			dead_cycle_count = 0;
    			ship_fire_move = 0;
    		}
    
    		void move(enum {DEMO_OFF, DEMO_ON} demo)
    		// Move ship according to input
    		{
    			if (demo == DEMO_OFF)
    			{
    				// Process MOUSE movements separately
    				// LEFT/RIGHT
    				the_BOB.x += mouse_state.lX;		// Left/Right
    				the_BOB.y += mouse_state.lY;		// Up/Down
    
    				if (mouse_state.lX < 0)
    					ship_fire_move = -2;	 			// Momentum of fire if initiated whilst Base Ship is moving left
    				if (mouse_state.lX > 0)
    					ship_fire_move = 2;	 			// Momentum of fire if initiated whilst Base Ship is moving right
    
    				// LEFT
    				if ( (keyboard_state[DIK_Z])		// Z = move base_ship LEFT
    					|| (joy_state.lX < -230) ) 	// Joystick left
    				{
    					the_BOB.x -= the_BOB.xv;
    					ship_fire_move = -2;	 			// Momentum of fire if initiated whilst Base Ship is moving left
    				}
    
    				// RIGHT
    				if ( (keyboard_state[DIK_X])		// X = move base_ship RIGHT
    					|| (joy_state.lX > 230) )  	// Joystick right
    				{
    					the_BOB.x += the_BOB.xv;
    					ship_fire_move = +2;				// Momentum of fire if initiated whilst Base Ship is moving right
    					if (keyboard_state[DIK_Z])
    						ship_fire_move = 0;			// If both left/right are pressed then nullify sideways movement.
    				}
    
    				// UP
    				if (( keyboard_state[DIK_K])		// K = move base_ship UP
    					|| (joy_state.lY < -230) ) 	// Joystick up
    					the_BOB.y -= the_BOB.yv;
    
    				// DOWN
    				if ( (keyboard_state[DIK_M])		// M = move base_ship DOWN
    					|| (joy_state.lY > 230) )  	// Joystick down
    					the_BOB.y += the_BOB.yv;
    			}
    			else
    			{
    				// Demo ship movement
    				the_BOB.x += demo_vel_x;
    				the_BOB.y += demo_vel_y;
    				if (rand()%20 == 0) demo_vel_x = (6 - rand()%13); // Random speed/dir -6 to 6
    				if (rand()%20 == 0) demo_vel_y = (3 - rand()%7); // Random speed/dir -3 to 3
    				// 'Bounce' if hugging side of screen
    				if (the_BOB.x <= 0)							// Too near the left?
    					demo_vel_x = (rand()%6)+1;
    				if (the_BOB.x >= SCREEN_WIDTH - 31)		// Too near the right?
    					 demo_vel_x = -((rand()%6)+1);
    				if (the_BOB.y <= SCREEN_HEIGHT - 120)	// Too near the top?
    					demo_vel_y = (rand()%3)+1;
    				if (the_BOB.y >= SCREEN_HEIGHT - 51)	// Too near the bottom
    					demo_vel_y = -((rand()%3)+1);
    			}
    
    			// Don't move Base Ship off screen
    			if (the_BOB.x < 3)
    				the_BOB.x = 3;
    			if (the_BOB.x > SCREEN_WIDTH - 35)
    				the_BOB.x = SCREEN_WIDTH - 35;
    			if (the_BOB.y < SCREEN_HEIGHT - 120)
    				the_BOB.y = SCREEN_HEIGHT - 120;
    			if (the_BOB.y > SCREEN_HEIGHT - 51)
    				the_BOB.y = SCREEN_HEIGHT - 51;
    
    		}
    
    		int isFiring() const
    		// Is the base currently firing?
    		{
    			if (base_firing == 0)
    				return FALSE;
    			else
    				return TRUE;
    		}
    
    		void startFiring()
    		{
    			base_firing = 1;
    		}
    
    		void setBaseFire2(int value)
    		{
    			base_fire2 = value;
    		}
    
    		int animate_and_check_second_fire()
    		// Animate base_ship if currently in firing cycle - check whether to release 2nd base_ship_fire yet (on cycle 3)
    		{
    			int release_second_fire = 0;
    			if (base_firing > 0)
    			{
    				if (base_firing < 7)
    					Animate_BOB(&the_BOB);
    				base_firing++;
    				if (base_firing == 10)									// Have we finished Base Ship firing cycle?
    					base_firing = 0;										// Yes - ready to start another one!
    				if ( (base_firing == 4) && (base_fire2 != 99) )	// Ready to set 2nd fire loose
    				{
    					release_second_fire = base_fire2;				// Signal to caller to start 2nd fire
    					base_fire2 = 99;
    				}
    			}
    			return release_second_fire;
    		}
    
    void draw()
    		// Draw base as normal, splat with random pixels if current dying.
    		{
    			if (!isDead())
    			{
    				Draw_BOB(&the_BOB,lpddsback);
    				if (isDying())
    				{
    					DD_Lock_Back_Surface();		// For pixel-drawing
    					for (int i=0; i < dead_cycle_count*10; i++)
    					{
    						Draw_Pixel(the_BOB.x+4+(rand()%24),the_BOB.y+4+(rand()%24),rand()%256,back_buffer, back_lpitch);
    					}
    					DD_Unlock_Back_Surface();
    				}
    			}
    		}
    
    	private:
    		int	base_firing;			// Base Ship firing cycle?
    		int  	base_fire2;				// Index of 2nd fire (99 = none)
    		int   demo_vel_x;				// Demo speed/direction
    		int   demo_vel_y;				// Demo speed/direction
    
    	public:
    		int 	ship_fire_move;		// Momentum of sideways movement of ship passed on to current ship fire
    		int  	dead_cycle_count;		// Cycle size of ship when dying
    };
    
    
    class cBaseFire : public cBOB
    {
    	public:
    
    		cBaseFire()
    		{}	// Does nothing - all initialisation are done in loadBOB as they cannot be performed at object instantiation time
    
    		~cBaseFire()
    		{
    			count--;
    			if (count == 0)
    				Destroy_BOB2(&master_base_fire);
    		}
    
    		void loadBOB()
    		{
    			count++;
    			if (count == 0)
    			{
    				// First call - create master base fire, from which standard base fires are made
    				Load_Bitmap_File(&bitmap8bit, "base_fire.bmp");
    				// now create the Base FIRE
    				Create_BOB(&master_base_fire,0,0,
    					8,16, 						// Size of each frame
    					16,							// Number of frames
    					BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM,
    					DDSCAPS_SYSTEMMEMORY);
    				master_base_fire.state = BOB_STATE_DEAD;
    				master_base_fire.yv = 15;		// Vertical speed for intial momentum of Base Ship Fire(y=y-this)
    				// load base_fire frames
    				for (int index=0; index<8; index++)
    				{
    					Load_Frame_BOB(&master_base_fire,&bitmap8bit,index,index,0,BITMAP_EXTRACT_MODE_CELL);
    					Load_Frame_BOB(&master_base_fire,&bitmap8bit,index+8,index,1,BITMAP_EXTRACT_MODE_CELL);
    				}
    				Set_Anim_Speed_BOB(&master_base_fire,1);	// set animation speed
    				int base_fire_up[8] = {0,1,2,3,4,5,6,7};
    				Load_Animation_BOB(&master_base_fire,0,8,base_fire_up);
    				int base_fire_down[8] = {8,9,10,11,12,13,14,15};
    				Load_Animation_BOB(&master_base_fire,1,8,base_fire_down);
    				Unload_Bitmap_File(&bitmap8bit);	// unload data infile
    			}
    
    			Create_BOB(&the_BOB,0,0,
    				8,16, 						// Size of each frame
    				16,							// Number of frames
    				BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,
    				DDSCAPS_SYSTEMMEMORY);
    			Clone_BOB(&master_base_fire, &the_BOB);
    		}
    
    		void reset()
    		{
    			Set_Animation_BOB(&the_BOB,0);
    			the_BOB.curr_frame = 0;
    			the_BOB.state = BOB_STATE_DEAD;						// De-activate all base ship Fires
    		}
    
    		void start_new_base_fire(const int new_x, const int base_ship_y, const int ship_fire_move)
    		// Set a new base fire going on its merry way up
    		{
    			setAlive();
    			Set_Pos_BOB(&the_BOB,new_x,			 				// Horiz position based on ship when fired
    										base_ship_y - 4);				// Vert pos matched to base ship height
    			Set_Vel_BOB(&the_BOB, ship_fire_move,				// Move sideways with the movement of the sideways ship at this time.
    										 master_base_fire.yv);		// Vertical motion matched to master BOB
    			Set_Animation_BOB(&the_BOB,0);						// Going UP animation-frames
    		}
    
    		void move_draw()
    		{
    			if (the_BOB.yv == -1)									// Hit the top!
    				Set_Animation_BOB(&the_BOB,1);					// Going DOWN
    			Animate_BOB(&the_BOB);
    			Draw_BOB(&the_BOB,lpddsback);
    			if (the_BOB.curr_frame%9 == 0)						//	Reduce/increase velocity once per cycle
    			{
    				if ((the_BOB.yv < 3) && (the_BOB.yv > -3))
    					the_BOB.yv -= 1;									// Almost at top - slow down velocity changes
    				else if ((the_BOB.yv < 5) && (the_BOB.yv > -5))
    					the_BOB.yv -= 2;									// Approaching top - slow down velocity changes
    				else
    					the_BOB.yv -= 3;									// Normal velocity changes
    			}
    			the_BOB.x += the_BOB.xv;
    			the_BOB.y -= the_BOB.yv;
    			// If base fire is returning to, and reached, ground then mark it dead
    			if (
    				 (the_BOB.x < 2) ||
    				 (the_BOB.x > (SCREEN_WIDTH-10) ) ||
    				 (the_BOB.y > (SCREEN_HEIGHT - 32 - the_BOB.yv) )
    				)
    				setDead();
    		}
    
    	private:
    		static int count;								// Count of cBaseFires in existence
    		static BOB master_base_fire;				// Master BOB from which others are created
    	public:
    		static int base_fire_currently_alive;	// Can't end wave until all base fire out.
    
    };
    // Actual versions of cBaseFire class 'statics'
    int cBaseFire::count = -1;
    BOB cBaseFire::master_base_fire;
    int cBaseFire::base_fire_currently_alive;
    
    class cSpider : public cBOB
    {
    	public:
    
    		cSpider()
    		{}	// Does nothing - all initialisation are done in loadBOB as they cannot be performed at object instantiation time
    
    		~cSpider()
    		{
    			count--;
    			if (count == 0)
    				Destroy_BOB2(&master_spider);
    		}
    
    		void loadBOB()
    		{
    			count++;
    			if (count == 0)
    			{
    				// First call - create master spider, from which standard spiders are made
    				Load_Bitmap_File(&bitmap8bit, "spider.bmp");
    				// now create the SPIDER
    				Create_BOB(&master_spider,0,0,
    					32,32, 							// Size of each frame
    					14,								// Number of frames
    					BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM,
    					DDSCAPS_SYSTEMMEMORY);
    				master_spider.state = SPIDER_INACTIVE;
    				// load Spider frames
    				int index;
    				for (index=0; index<4; index++)	// Spider descending
    				{
    					Load_Frame_BOB(&master_spider,&bitmap8bit,index,index,0,BITMAP_EXTRACT_MODE_CELL);
    				}
    				for (index=0; index<3; index++)	// Spider flying
    				{
    					Load_Frame_BOB(&master_spider,&bitmap8bit,index+4,index,1,BITMAP_EXTRACT_MODE_CELL);
    				}
    				for (index=0; index<7; index++)	// Spider dying
    				{
    					Load_Frame_BOB(&master_spider,&bitmap8bit,index+7,index,2,BITMAP_EXTRACT_MODE_CELL);
    				}
    
    				int spider_descending_web[12] = {0,1,0,1,2,1,2,3,2,3,0,3};
    				Load_Animation_BOB(&master_spider,0,12,spider_descending_web);
    				int spider_flying[4] 			= {4,6,5,6};
    				Load_Animation_BOB(&master_spider,1,4,spider_flying);
    				int spider_dying[7] 				= {7,8,9,10,11,12,13};
    				Load_Animation_BOB(&master_spider,2,7,spider_dying);
    				Unload_Bitmap_File(&bitmap8bit);	// unload data infile
    			}
    
    			Create_BOB(&the_BOB,0,0,
    				32,32, 							// Size of each frame
    				14,								// Number of frames
    				BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM,
    				DDSCAPS_SYSTEMMEMORY);
    			Clone_BOB(&master_spider, &the_BOB);
    		}
    
    		void reset()
    		{
    			Set_Animation_BOB(&the_BOB,0);
    			the_BOB.curr_frame = 0;
    			the_BOB.state = SPIDER_INACTIVE;			// De-activate spiders
    		}
    
    		void draw()
    		// Draw Spider if actually there!
    		{
    			if (isActive())
    			{
    				Animate_BOB(&the_BOB);
    				Draw_BOB(&the_BOB,lpddsback);
    				// If spider has gone through 1 dying graphic cycle then RIP
    				if ( (the_BOB.state == SPIDER_DYING) && (the_BOB.curr_frame == 13) )
    					the_BOB.state = SPIDER_INACTIVE;
    			}
    		}
    
    		void growWeb()
    		{
    			the_BOB.y += descend_speed;
    		}
    
    		int isWebFinished() const
    		{
    			if (the_BOB.y < max_web_length)
    				return FALSE;
    			else
    				return TRUE;
    		}
    
    		int isActive() const
    		{
    			if (the_BOB.state == SPIDER_INACTIVE)
    				return FALSE;
    			else
    				return TRUE;
    		}
    
    		int isInactive() const
    		{
    			if (the_BOB.state == SPIDER_INACTIVE)
    				return TRUE;
    			else
    				return FALSE;
    		}
    
    		void setInactive()
    		{
    			the_BOB.state = SPIDER_INACTIVE;
    		}
    
    		int isDescending() const
    		{
    			if (the_BOB.state == SPIDER_DESCENDING)
    				return TRUE;
    			else
    				return FALSE;
    		}
    		void setDescending()
    		{
    			the_BOB.state = SPIDER_DESCENDING;
    			Set_Animation_BOB(&the_BOB,0);
    			Animate_BOB(&the_BOB);													// Get first frame right.
    			Set_Anim_Speed_BOB(&the_BOB,5);										// set animation speed
    			Set_Pos_BOB(&the_BOB, (rand()%(SCREEN_WIDTH-66))+33, 1);		// Web is 16 length at start
    			max_web_length = (rand()%300+20);									// How long will the final web be?
    		}
    
    		int isFlying() const
    		{
    			if (the_BOB.state == SPIDER_FLYING)
    				return TRUE;
    			else
    				return FALSE;
    		}
    		void setFlying()
    		{
    			the_BOB.state = SPIDER_FLYING;
    			Set_Animation_BOB(&the_BOB,1);		 											// Spider 'flying' graphic
    			Set_Anim_Speed_BOB(&the_BOB,2);	 												// set animation speed (wings flapping)
    			setTimeBeforeChangeDir(); 															// Time before change of direction.
    			if (rand()%5 > 2)		// 2/5ths of the time spider stays still
    				Set_Vel_BOB(&the_BOB,0,0);
    			else
    				Set_Vel_BOB(&the_BOB,(rand()%(max_speed*2+1))-max_speed, 			// Set initial flying velocities
    								         (rand()%(max_speed*2+1))-max_speed);
    			setTimeBeforeFiring();																// Time to first fire after launch
    		}
    
    		int isDying() const
    		{
    			if (the_BOB.state == SPIDER_DYING)
    				return TRUE;
    			else
    				return FALSE;
    		}
    
    		void setDying()
    		{
    			the_BOB.state = SPIDER_DYING;
    			Set_Animation_BOB(&the_BOB,2);				// Reset Spider graphic to 'dying'
    			Set_Anim_Speed_BOB(&the_BOB,2);				// set animation speed
    		}
    
    		void setTimeBeforeChangeDir()
    		{
    			 time_before_change_dir = (rand()%max_time_before_move)+1;
    		}
    
    		int checkChangeDir()
    		{
    			time_before_change_dir--;
    			if (time_before_change_dir == 0)
    			{
    				setTimeBeforeChangeDir(); 													// Time before change of direction.
    				if (rand()%5 > 2)																// 2/5ths of the time spider stays still
    					Set_Vel_BOB(&the_BOB,0, 0);
    				else
    					Set_Vel_BOB(&the_BOB, (rand()%(max_speed*2+1))-max_speed, 	// Set initial flying velocities
    												 (rand()%(max_speed*2+1))-max_speed );
    			}
    			// Move spider around screen
    			the_BOB.x += the_BOB.xv;														// Horizontal movement
    			if (the_BOB.x < 0)
    			{
    				the_BOB.x = 0;
    				the_BOB.xv = -the_BOB.xv;
    			}
    			if (the_BOB.x > SCREEN_WIDTH-33)
    			{
    				the_BOB.x = SCREEN_WIDTH-33;
    				the_BOB.xv = -the_BOB.xv;
    			}
    
    			the_BOB.y += the_BOB.yv;														// Vertical movement
    			if (the_BOB.y < 0)
    			{
    				the_BOB.y = 0;
    				the_BOB.yv = -the_BOB.yv;
    			}
    			if (the_BOB.y > SCREEN_HEIGHT-70)
    			{
    				the_BOB.y = SCREEN_HEIGHT-70;
    				the_BOB.yv = -the_BOB.yv;
    			}
    		}
    
    		void setTimeBeforeFiring()
    		{
    			 time_before_firing = (rand()%max_time_before_fire)+1;
    		}
    
    		int fireNow()
    		{
    			time_before_firing--;
    			if (time_before_firing == 0)
    				return TRUE;
    			else
    				return FALSE;
    		}
    
    		static void setWaveVariables(const int wave)
    		{
    			allowed_onscreen = wave;						// How many spiders at onec
    			descend_speed = (wave+1)/3;					// Speed at which spiders descend web;
    			if (descend_speed > 3)
    				descend_speed = 3;
    			this_wave = wave * 8;							// Spiders left to die until the end of this wave
    			max_speed = wave/2;						   	// The maximum speed which the spiders can move
    			if (max_speed > 8)
    				max_speed = 8;
    			max_time_before_move = 400-(wave<<4);		// The maximum amount of time before the spider will change direction
    			if (max_time_before_move < 40)
    				max_time_before_move = 40;
    			max_time_before_fire = 400-(wave<<5);	 	// The maximum amount of time before the spider will fire
    			if (max_time_before_fire < 40)
    				max_time_before_fire = 40;
    		}
    
    	private:
    		int	max_web_length;								// Max length of web line before spider detaches
    		int	time_before_change_dir;						// Counter before we change the direction.
    		int   time_before_firing;							// Counter before next firing.
    
    		static const int SPIDER_INACTIVE;
    		static const int SPIDER_DESCENDING;
    		static const int SPIDER_FLYING;
    		static const int SPIDER_DYING;
    		static int count;							// Count of cSpiders in existence
    		static BOB master_spider;				// Master BOB from which others are created
    
    		static int max_time_before_move; 	// The maximum amount of time before the spider will change direction
    		static int max_time_before_fire; 	// The maximum amount of time before the spider will fire
    		static int max_speed;					// The maximum speed which the spiders can move
    		static int descend_speed;				// Speed at which spiders descend web;
    
    
    	public:
    		static int currently_alive;			// Spiders currently alive
    		// Wave variables
    		static int allowed_onscreen;			// Max num of spiders allowed on-screen in this wave at any one time
    		static int this_wave;					// Spiders left to die until the end of this wave
    
    
    };
    // Actual versions of cSpider class 'statics'
    const int cSpider::SPIDER_INACTIVE   = 0;
    const int cSpider::SPIDER_DESCENDING = 1;
    const int cSpider::SPIDER_FLYING     = 2;
    const int cSpider::SPIDER_DYING      = 3;
    int cSpider::count = -1;
    BOB cSpider::master_spider;
    int cSpider::max_time_before_move;
    int cSpider::max_time_before_fire;
    int cSpider::max_speed;
    int cSpider::descend_speed;
    int cSpider::currently_alive;
    int cSpider::allowed_onscreen;
    int cSpider::this_wave;
    
    
    class cSpiderFire : public cBOB
    {
    	public:
    
    		cSpiderFire()
    		{}	// Does nothing - all initialisation are done in loadBOB as they cannot be performed at object instantiation time
    
    		~cSpiderFire()
    		{
    			count--;
    			if (count == 0)
    				Destroy_BOB2(&master_spider_fire);
    		}
    
    		void loadBOB()
    		{
    			count++;
    			if (count == 0)
    			{
    				// First call - create master spider fire, from which standard spider fires are made
    				Load_Bitmap_File(&bitmap8bit, "spider_fire.bmp");
    				// now create the Spider FIRE
    				Create_BOB(&master_spider_fire,0,0,
    					16,16, 						// Size of each frame
    					4,								// Number of frames
    					BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,
    					DDSCAPS_SYSTEMMEMORY);
    				master_spider_fire.state = BOB_STATE_DEAD;
    				// load spider_fire frames
    				for (int index=0; index<4; index++)
    				{
    					Load_Frame_BOB(&master_spider_fire,&bitmap8bit,index,index,0,BITMAP_EXTRACT_MODE_CELL);
    				}
    				Set_Anim_Speed_BOB(&master_spider_fire,1);	// set animation speed
    				int spider_fire_frames[4] = {0,1,2,3};
    				Load_Animation_BOB(&master_spider_fire,0,4,spider_fire_frames);
    				Unload_Bitmap_File(&bitmap8bit);	// unload data infile
    			}
    
    			Create_BOB(&the_BOB,0,0,
    				16,16, 						// Size of each frame
    				4,								// Number of frames
    				BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_FRAME,
    				DDSCAPS_SYSTEMMEMORY);
    			Clone_BOB(&master_spider_fire, &the_BOB);
    		}
    
    		void reset()
    		{
    			Set_Animation_BOB(&the_BOB,0);
    			the_BOB.curr_frame = 0;
    			setDead();	// Remove all spider Fires
    		}
    
    		void startFire(const int X_coord, const int Y_coord, const int XV, const int YV, const int spider_owner_sub)
    		{
    			setAlive();
    			// Set fire to start at position of Spider, velocity half of sideways and faster downwards
    			Set_Pos_BOB(&the_BOB, X_coord+8, Y_coord+16);
    			Set_Vel_BOB(&the_BOB, XV/2, YV+additional_spider_fire_vertical_velocity);
    			if (the_BOB.yv < 0)
    				the_BOB.yv = additional_spider_fire_vertical_velocity;  // No fire upwards!
    			spider_fire_owner = spider_owner_sub;  	// Assign 'owner' of this fire so it can't be detroyed by it.
    		}
    
    		int getOwner() const
    		{
    			return spider_fire_owner;
    		}
    
    		void move_draw()
    		{
    			if (the_BOB.curr_frame == 0)
    				the_BOB.yv+=1;					// Speed up downward journey of spider fire once per cycle
    			Move_BOB(&the_BOB);
    			// Check whether spider fire reached bottom of screen or gone off sides
    			if ( (the_BOB.x < 0) ||
    				  (the_BOB.x > (SCREEN_WIDTH - 17 - abs(the_BOB.xv)) )  ||
    				  (the_BOB.y > (SCREEN_HEIGHT - 9 - (the_BOB.yv))) )
    				  setDead();
    			else
    			{
    				Animate_BOB(&the_BOB);
    				Draw_BOB(&the_BOB,lpddsback);
    			}
    		}
    
    		static void setWaveVariables(const int wave)
    		{
    			additional_spider_fire_vertical_velocity = wave/4;	// Amount added to spider vertical velocity when firing
    
    		}
    
    	private:
    		int	spider_fire_owner;						// Owner of this fire (so it can't be killed by it)
    		static int count;									// Count of cSpiderFires in existence
    		static BOB master_spider_fire;				// Master BOB from which others are created
    		static int additional_spider_fire_vertical_velocity;
    	public:
    		static int spider_fire_currently_alive;	// Can't end wave until all spider fire out.
    
    };
    // Actual versions of cSpiderFire class 'statics'
    int cSpiderFire::count = -1;
    BOB cSpiderFire::master_spider_fire;
    int cSpiderFire::additional_spider_fire_vertical_velocity;
    int cSpiderFire::spider_fire_currently_alive;
    
    // SOUND classes
    
    class cSound
    {
    	public:
    		int getSoundId() const
    		{
    			return sound;
    		}
    		void init_pan()
    		{
    			Set_Sound_Pan(sound,((rand()%201)-100)*10);	// Give random panning to sound interesting
    		}
    	protected:
    		int sound;	// Sound id
    };
    
    class cBaseFireSound : public cSound
    {
    	public:
    		void loadSound()
    		{
    			count++;
    			if (count == 0)	// First call - create master spider, from which standard spiders are made
    				master_sound = Load_VOC("base_fire.voc");
    			sound = Replicate_Sound(master_sound);
    		}
    		int static next_free_sound(int max)
    		{
    			if (current_sound < max-1)			// Ready for next 'free' slot (which should have finished playing by now)
    				current_sound++;
    			else
    				current_sound = 0;
    			return current_sound;
    		}
    	private:
    		static int master_sound;			  	// Used to create 'clone' sounds
    		static int count;							// Count of number of cSpiderFireSounds in existence
    		static int current_sound;				// Current sound to play - loop around
    };
    // Actual versions of cBaseFireSound class 'statics'
    int cBaseFireSound::master_sound;
    int cBaseFireSound::count = -1;
    int cBaseFireSound::current_sound = 0;
    
    
    class cSpiderStartSound : public cSound
    {
    	public:
    		void loadSound()
    		{
    			count++;
    			if (count == 0)						// First call - create master spider, from which standard spiders are made
    				master_sound = Load_VOC("spider_start.voc");
    			sound = Replicate_Sound(master_sound);
    		}
    		int static next_free_sound(int max)
    		{
    			if (current_sound < max-1)			// Ready for next 'free' slot (which should have finished playing by now)
    				current_sound++;
    			else
    				current_sound = 0;
    			return current_sound;
    		}
    	private:
    		static int master_sound;			  	// Used to create 'clone' sounds
    		static int count;							// Count of number of cSpiderFireSounds in existence
    		static int current_sound;				// Current sound to play - loop around
    };
    // Actual versions of cSpiderFireSound class 'statics'
    int cSpiderStartSound::master_sound;
    int cSpiderStartSound::count = -1;
    int cSpiderStartSound::current_sound = 0;
    
    
    class cSpiderLaunchSound : public cSound
    {
    	public:
    		void loadSound()
    		{
    			count++;
    			if (count == 0)						// First call - create master spider, from which standard spiders are made
    				master_sound = Load_VOC("spider_launch.voc");
    			sound = Replicate_Sound(master_sound);
    		}
    		int static next_free_sound(int max)
    		{
    			if (current_sound < max-1)			// Ready for next 'free' slot (which should have finished playing by now)
    				current_sound++;
    			else
    				current_sound = 0;
    			return current_sound;
    		}
    	private:
    		static int master_sound;			  	// Used to create 'clone' sounds
    		static int count;							// Count of number of cSpiderFireSounds in existence
    		static int current_sound;				// Current sound to play - loop around
    };
    // Actual versions of cSpiderFireSound class 'statics'
    int cSpiderLaunchSound::master_sound;
    int cSpiderLaunchSound::count = -1;
    int cSpiderLaunchSound::current_sound = 0;
    
    
    class cSpiderFireSound : public cSound
    {
    	public:
    		void loadSound()
    		{
    			count++;
    			if (count == 0)						// First call - create master spider, from which standard spiders are made
    				master_sound = Load_VOC("spider_fire.voc");
    			sound = Replicate_Sound(master_sound);
    		}
    		int static next_free_sound(int max)
    		{
    			if (current_sound < max-1)			// Ready for next 'free' slot (which should have finished playing by now)
    				current_sound++;
    			else
    				current_sound = 0;
    			return current_sound;
    		}
    	private:
    		static int master_sound;			  	// Used to create 'clone' sounds
    		static int count;							// Count of number of cSpiderFireSounds in existence
    		static int current_sound;				// Current sound to play - loop around
    };
    // Actual versions of cSpiderFireSound class 'statics'
    int cSpiderFireSound::master_sound;
    int cSpiderFireSound::count = -1;
    int cSpiderFireSound::current_sound = 0;
    
    
    class cSpiderHitSound : public cSound
    {
    	public:
    		void loadSound()
    		{
    			count++;
    			if (count == 0)						// First call - create master spider, from which standard spiders are made
    				master_sound = Load_VOC("spider_hit.voc");
    			sound = Replicate_Sound(master_sound);
    		}
    		int static next_free_sound(int max)
    		{
    			if (current_sound < max-1)			// Ready for next 'free' slot (which should have finished playing by now)
    				current_sound++;
    			else
    				current_sound = 0;
    			return current_sound;
    		}
    	private:
    		static int master_sound;			  	// Used to create 'clone' sounds
    		static int count;							// Count of number of cSpiderFireSounds in existence
    		static int current_sound;				// Current sound to play - loop around
    };
    // Actual versions of cSpiderFireSound class 'statics'
    int cSpiderHitSound::master_sound;
    int cSpiderHitSound::count = -1;
    int cSpiderHitSound::current_sound = 0;
    
    
    class cBaseHitSound : public cSound
    {
    	public:
    		void loadSound()
    		{
    			sound = Load_VOC("base_hit.voc");
    		}
    		void playSound()
    		{
    			Play_Sound(sound,0);
    		}
    };
    
    class cExtraLife : public cSound
    {
    	public:
    		void loadSound()
    		{
    			sound = Load_VOC("extra_life.voc");
    		}
    		void playSound()
    		{
    			Play_Sound(sound,0);
    		}
    };
    
    
    // PROTOTYPES /////////////////////////////////////////////
    
    // game console
    int Game_Init(void *parms=NULL);
    int Game_Shutdown(void *parms=NULL);
    int Game_Main(void *parms=NULL);
    
    // GLOBALS ////////////////////////////////////////////////
    
    HWND main_window_handle  = NULL; // save the window handle
    HINSTANCE main_instance  = NULL; // save the instance
    char buffer[80];                 // used to print text
    
    BITMAP_IMAGE backdrop;      		// the background image
    
    // Instantiate sounds
    cBase					 base_ship;
    cBaseHitSound  	 base_hit_sound;
    cExtraLife		  	 extra_life_sound;
    
    cBaseFire			 base_fire[BASE_FIRE_COUNT];
    cBaseFireSound 	 base_fire_sound[BASE_FIRE_SOUND_COUNT];
    
    cSpider 				 spider[SPIDER_COUNT];
    cSpiderFire 		 spider_fire[SPIDER_FIRE_COUNT];
    cSpiderStartSound  spider_start_sound[SPIDER_START_SOUND_COUNT];
    cSpiderLaunchSound spider_launch_sound[SPIDER_LAUNCH_SOUND_COUNT];
    cSpiderFireSound   spider_fire_sound[SPIDER_FIRE_SOUND_COUNT];
    cSpiderHitSound 	 spider_hit_sound[SPIDER_HIT_SOUND_COUNT];
    
    // Game globals
    enum {start_title,		  								// Display he title screen
    		start_new_wave,									// Reset variables, display wave message, and begin
    		in_progress,										// Game running normally
    		game_over											// Player out of lives
    		} game_status;										// The status of the game
    
    int				escape_pressed	= FALSE;				// Pressing ESCape at any time will terminate game/
    int 				wave;										// Subsequent waves get harder
    int				wave_end_message;						// Random message at end of screen
    int				initial_wave_selected;				// The wave the user chose to start with, for repeat play.
    int 				player_lives;							// Number of lives
    int				player_lives_disp;					// Display the correct number (as actual gets decremented at exact moment);
    unsigned long 	score;									// The score!
    unsigned long	score_at_last_end_wave;				// Keep score at last wave completed for Continue
    unsigned int	extra_life_val;						// Extra life awared every 'this' number of points
    unsigned long	next_extra_life_awarded;			// Next extra life awarded at 'this' score
    int				end_of_wave_nigh;						// End of wave in sight?
    char				starting_level_description[10];	// For use in Game Over message
    enum				{PAUSE_OFF, PAUSE_ON} pause; 	   // Game Pause facility
    enum				{PAUSE_PRESSED_NO, PAUSE_PRESSED_YES} pause_press;
    time_t 			demo_start_wait;						// Demo will start x seconds from here
    int 				demo_start_wait_elapsed;			// Seconds since above
    enum				{DEMO_OFF, DEMO_ON} demo; 	      // Game Demo facility
    
    // FUNCTIONS //////////////////////////////////////////////
    
    LRESULT CALLBACK WindowProc(HWND hwnd,
    									 UINT msg,
    									 WPARAM wparam,
    									 LPARAM lparam)
    {
    // this is the main message handler of the system
    PAINTSTRUCT	ps;		   // used in WM_PAINT
    HDC			hdc;	   // handle to a device context
    
    // what is the message
    switch(msg)
    	{
    	case WM_CREATE:
    		  {
    			// do initialization stuff here
    			return(0);
    		  } break;
    
    	 case WM_PAINT:
    			{
    			// start painting
    			hdc = BeginPaint(hwnd,&ps);
    			// end painting
    			EndPaint(hwnd,&ps);
    			return(0);
    		  } break;
    
    	case WM_DESTROY:
    		{
    		// kill the application
    		PostQuitMessage(0);
    		return(0);
    		} break;
    
    	default:break;
    
    	 } // end switch
    
    // process any messages that we didn't take care of
    return (DefWindowProc(hwnd, msg, wparam, lparam));
    
    } // end WinProc
    
    // WINMAIN ////////////////////////////////////////////////
    
    int WINAPI WinMain(	HINSTANCE hinstance,
    					HINSTANCE hprevinstance,
    					LPSTR lpcmdline,
    					int ncmdshow)
    {
    // this is the winmain function
    
    WNDCLASS winclass;	// this will hold the class we create
    HWND	 	hwnd;			// generic window handle
    MSG		msg;			// generic message
    HDC      hdc;     	// generic dc
    PAINTSTRUCT ps;   	// generic paintstruct
    
    // first fill in the window class stucture
    winclass.style				= CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    winclass.lpfnWndProc		= WindowProc;
    winclass.cbClsExtra		= 0;
    winclass.cbWndExtra		= 0;
    winclass.hInstance		= hinstance;
    winclass.hIcon				= LoadIcon(NULL, IDI_APPLICATION);
    winclass.hCursor			= LoadCursor(NULL, IDC_ARROW);
    winclass.hbrBackground	= GetStockObject(BLACK_BRUSH);
    winclass.lpszMenuName	= NULL;
    winclass.lpszClassName	= WINDOW_CLASS_NAME;
    
    // register the window class
    if (!RegisterClass(&winclass))
    	return(0);
    
    // create the window, note the use of WS_POPUP
    if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
    						  "WinX Game Console",	 // title
    						  WS_POPUP | WS_VISIBLE,
    						  0,0,	   		// x,y
    						  WINDOW_WIDTH,  	// width
    						  WINDOW_HEIGHT, 	// height
    						  NULL,	   		// handle to parent
    						  NULL,	   		// handle to menu
    						  hinstance,		// instance
    						  NULL)))			// creation parms
    return(0);
    
    // save the window handle and instance in a global
    main_window_handle = hwnd;
    main_instance      = hinstance;
    
    // perform all game console specific initialization
    Game_Init();
    
    // enter main event loop
    while(1)
    	{
    	if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
    		{
    		// test if this is a quit
    		  if (msg.message == WM_QUIT)
    			  break;
    
    		// translate any accelerator keys
    		TranslateMessage(&msg);
    
    		// send the message to the window proc
    		DispatchMessage(&msg);
    		} // end if
    
    	 // main game processing goes here
    		Game_Main();
    		if (escape_pressed)
    			break;
    
    	} // end while
    
    // shutdown game and release all resources
    Game_Shutdown();
    
    // return to Windows like this
    return(msg.wParam);
    
    } // end WinMain
    
    // WINX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
    
    int Game_Init(void *parms)
    {
    // this function is where you do all the initialization
    // for your game
    game_status = start_title;
    
    // seed random number generate
    srand(Start_Clock());
    
    // hide the mouse
    ShowCursor(FALSE);
    
    
    int index;
    
    // start up DirectDraw (replace the parms as you desire)
    DD_Init(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP);
    
    // initilize DirectSound
    DSound_Init();
    
    // initialize DirectInput
    DInput_Init();
    
    // initialize keyboard
    DI_Init_Keyboard();
    
    // initialize mouse
    DI_Init_Mouse();
    
    // initialize joystick
    DI_Init_Joystick();
    
    // Process the backdrop
    Load_Bitmap_File(&bitmap8bit, "backdrop.bmp");
    Set_Palette(bitmap8bit.palette);
    Create_Bitmap(&backdrop, 0,0, SCREEN_WIDTH, SCREEN_HEIGHT);
    Load_Image_Bitmap(&backdrop,&bitmap8bit,0,0,BITMAP_EXTRACT_MODE_ABS);
    Unload_Bitmap_File(&bitmap8bit);
    
    // load the player's BASE SHIP and Hit sound
    base_ship.loadBOB();
    base_hit_sound.loadSound();
    
    // load the extra life sound
    extra_life_sound.loadSound();
    
    
    // Load BASE FIRE object BOBs
    for (int base_fire_sub=0; base_fire_sub < BASE_FIRE_COUNT; base_fire_sub++)
    	base_fire[base_fire_sub].loadBOB();
    
    for (int base_fire_sound_sub=0; base_fire_sound_sub < BASE_FIRE_SOUND_COUNT; base_fire_sound_sub++)
    	base_fire_sound[base_fire_sound_sub].loadSound();
    
    // Load SPIDER object BOBs
    for (int spider_sub=0; spider_sub < SPIDER_COUNT; spider_sub++)
    	spider[spider_sub].loadBOB();
    
    // Load SPIDER FIRE object BOBs
    for (int spider_fire_sub=0; spider_fire_sub < SPIDER_FIRE_COUNT; spider_fire_sub++)
    	spider_fire[spider_fire_sub].loadBOB();
    
    // Load SOUNDS
    for (int spider_start_sound_sub=0; spider_start_sound_sub < SPIDER_START_SOUND_COUNT; spider_start_sound_sub++)
    	spider_start_sound[spider_start_sound_sub].loadSound();
    
    for (int spider_launch_sound_sub=0; spider_launch_sound_sub < SPIDER_LAUNCH_SOUND_COUNT; spider_launch_sound_sub++)
    	spider_launch_sound[spider_launch_sound_sub].loadSound();
    
    for (int spider_fire_sound_sub=0; spider_fire_sound_sub < SPIDER_FIRE_SOUND_COUNT; spider_fire_sound_sub++)
    	spider_fire_sound[spider_fire_sound_sub].loadSound();
    
    for (int spider_hit_sound_sub=0; spider_hit_sound_sub < SPIDER_HIT_SOUND_COUNT; spider_hit_sound_sub++)
    	spider_hit_sound[spider_hit_sound_sub].loadSound();
    
    
    // return success
    return(1);
    
    } // end Game_Init
    
    ///////////////////////////////////////////////////////////
    
    int Game_Shutdown(void *parms)
    {
    // this function is where you shutdown your game and
    // release all resources that you allocated (automatically done in cBOB class)
    
    // shut everything down
    Destroy_Bitmap(&backdrop);
    
    Delete_All_Sounds();
    
    // shutdown directdraw last
    DD_Shutdown();
    
    // now directsound
    DSound_Shutdown();
    
    // finally directinput
    DI_Release_Keyboard();
    DI_Release_Mouse();
    DI_Release_Joystick();
    
    DInput_Shutdown();
    
    // return success
    return(1);
    } // end Game_Shutdown
    
    
    // Prorotypes for Game_Main;
    void display_backdrop();
    void check_user_input();
    void reset_all_objects();
    void print_left(char* text, int y_coord, int colour);
    void print_centre(char* text, int y_coord, int colour);
    void screen_fadeout(int effect);
    void screen_scrunch();
    void show_title_screen();
    void new_wave();
    void animate_base_ship();
    void check_ship_hit_and_process_dying();
    void draw_base_fires_and_check_if_hit_ship();
    void create_new_spider();
    void check_wave_end();
    void check_descending_spiders_and_draw_webs();
    void move_draw_check_spiders();
    void play_spider_move_sound();
    void check_for_spider_hit();
    void draw_spider_fire_and_check_ship_hit();
    void play_spider_hit_sound();
    void print_status_line(char surface);
    void game_over_screen();
    ///////////////////////////////////////////////////////////###########################################################
    
    int Game_Main(void *parms)
    {
    	if (game_status == start_title)
    		show_title_screen();
    
    	else if (game_status == start_new_wave)
    		new_wave();
    
    	else if (game_status == in_progress)
    	{
    		Start_Clock();  // start the timing clock
    
    		check_user_input(); // process input...test keyboard_state, joy_state
    
    		if (pause == PAUSE_OFF)
    		{
    			display_backdrop();
    
    			animate_base_ship();
    			check_ship_hit_and_process_dying();
    			draw_base_fires_and_check_if_hit_ship();
    
    			create_new_spider();
    			check_descending_spiders_and_draw_webs();
    
    			check_for_spider_hit();
    			move_draw_check_spiders();
    			draw_spider_fire_and_check_ship_hit();
    
    			if (game_status == in_progress)
    				base_ship.draw();
    
    			print_status_line('B');
    
    			DD_Flip(); // flip the surfaces
    		}
    		else
    			print_status_line('B');
    
    		Wait_Clock(20); // Time sync
    	}
    
    	else if (game_status == game_over)
    	{
    		game_over_screen();
    	}
    
    	// return success
    	return(0);
    
    } // end Game_Main
    
    ///////////////////////////////////////////////////////////###########################################################
    ///////////////////////////////////////////////////////////###########################################################
    
    ///////////////////////////////////////////////////////////
    
    void init_game()
    // Initialise all active game switches.
    {
    	DD_Fill_Surface(lpddsback, 0);
    	DD_Fill_Surface(lpddsprimary, 0);
    	wave		 	    = 0;					// Initial wave-1
    	player_lives    = 3;					// Number of lives player starts game with
    	score			    = 0;					// Initial score
    	pause 			 = PAUSE_OFF;
    	pause_press 	 = PAUSE_PRESSED_NO;
    	demo 			 	 = DEMO_OFF;
    
    	game_status     = start_new_wave;
    	reset_all_objects();
    }
    
    
    ///////////////////////////////////////////////////////////
    
    void reset_all_objects()
    // Initialise all object to their centre/off position.
    {
    	// set position (X_position of base at bottom), Y_position of base at bottom - height of ship - area for displays
    	base_ship.reset();
    
    	for (int base_fire_sub=0; (base_fire_sub < BASE_FIRE_COUNT); base_fire_sub++)
    		base_fire[base_fire_sub].reset();
    
    	for (int spider_sub=0; spider_sub < SPIDER_COUNT; spider_sub++)
    		spider[spider_sub].reset();
    
    	for (int spider_fire_sub=0; (spider_fire_sub < SPIDER_FIRE_COUNT); spider_fire_sub++)
    		spider_fire[spider_fire_sub].reset();
    
    	int temp_message;
    	do
       {
    	  temp_message = rand()%10;
    	} while (temp_message == wave_end_message);
    	wave_end_message = temp_message;		// Random message from 0 to 9 (doesn't repeat)
    }
    
    ///////////////////////////////////////////////////////////
    
    void print_left(char* text, int y_coord, int colour)
    // Print TEXT to primary buffer
    {
    		Draw_Text_GDI(text, 20, y_coord, colour, lpddsprimary);
    }
    
    ///////////////////////////////////////////////////////////
    
    void print_centre(char* text, int y_coord, int colour)
    // Print TEXT to primary buffer
    {
    		Draw_Text_GDI(text, (SCREEN_WIDTH/2)-(7*strlen(text)/2), y_coord, colour, lpddsprimary);
    }
    
    ///////////////////////////////////////////////////////////
    
    void screen_fadeout(int effect = SCREEN_DARKNESS)
    {
    	PALETTEENTRY the_palette[256];
    	Save_Palette(the_palette);
    	DD_Lock_Primary_Surface();
    	Screen_Transitions(effect,primary_buffer,primary_lpitch);
    	DD_Unlock_Primary_Surface();
    	DD_Fill_Surface(lpddsprimary,0);
    	DD_Fill_Surface(lpddsback, 0);
    	Set_Palette(the_palette);
    }
    
    ///////////////////////////////////////////////////////////
    
    void show_title_screen()
    {
    	init_game();
    	DD_Fill_Surface(lpddsprimary, 1);
    	Draw_Text_GDI("v 1.5",600,0,144,lpddsprimary);	// Version number top-right
    	print_centre("=============  ",8,198);
    	print_centre("Mutant Xpiders",20,204);
    	print_centre("=============  ",34,198);
    	print_centre("(A PC DirectX sequel to my 1983 BBC Microcomputer game, by Trevor LAWFORD)",56,59);
    	print_left("A simple left/right/up/down/fire game, written as an exercise in DirectX5 programming.",105,63);
    	print_left("Play using keyboard (Z=left, X=right, K=up, M=down, SPACE=fire), or a digital joystick.",130,156);
    	print_left("For *best* play mode use the MOUSE.  P=toggle Pause.  SPACE=end Demo.  ESC=Quit.",145,156);
    	print_left("Game Basics:",185,125);
    	print_left("1) You can use the sustained-fire capability of your Base Cannon as much as you want,",200,125);
    	print_left("    but *do* bear in mind that what goes up must come down, with attitude!",215,125);
    	print_left("    Use the sideways movement of your Cannon to affect angle of fire.",230,125);
    	print_left("2) All on-screen shots are lethal to yourself, the Xpiders, and any opposing shots.",245,125);
    	print_left("3) SCORE: Descending Xpiders=50, Flying Xpiders=200, Completed wave=500.",260,125);
    	print_centre("Comments are welcome to me at <trevor.lawford@btinternet.com>    ",305,215);
    	print_centre("My Web page is at <http://www.btinternet.com/~~trevor.lawford/>",325,215);
    	print_left("                "\
    				  "-------------------------------------------------------------------------------------------------------------------",360,100);
    	print_centre("Enter starting difficulty - press...",380,210);
    	print_centre("(1) Trainee (start wave 1, extra life every 10000)",405,180);
    	print_centre("(2) Regular (start wave 3, extra life every 15000)",420,174);
    	print_centre("                     (3) Pro        (start wave 7, extra life every 20000)",435,30);
    
    	demo_start_wait = time(NULL);	// Time now
    	for (int dx=0; dx<19; dx++)
    	{
    		Draw_Text_GDI(".",580+(dx*3),460,144,lpddsprimary);	// Print initial countdown 'dots'
    	}
    	int selected = FALSE;
    	do
    	{
    		demo_start_wait_elapsed = time(NULL) - demo_start_wait;	// Time since demo wait started in seconds
    		DI_Read_Keyboard(); // get input
    		if (keyboard_state[DIK_ESCAPE])
    		{
    			escape_pressed = TRUE;	// Finished!
    			return; // Fast track attahere
    		}
    		else if (keyboard_state[DIK_1])
    		{
    			selected = TRUE;
    			strcpy(starting_level_description,"trainee");
    			wave=0;
    			extra_life_val = 10000;
    		}
    		else if (keyboard_state[DIK_2])
    		{
    			selected = TRUE;
    			strcpy(starting_level_description,"regular");
    			wave=2;
    			extra_life_val = 15000;
    		}
    		else if (keyboard_state[DIK_3])
    		{
    			selected = TRUE;
    			strcpy(starting_level_description,"pro");
    			wave=6;
    			extra_life_val = 20000;
    		}
    		else if (demo_start_wait_elapsed >= 19)		// Wait 20 seconds before starting demo
    		{
    			demo = DEMO_ON;
    			selected = TRUE;
    			strcpy(starting_level_description,"DEMO");
    			wave=(rand()%5)+8;
    			extra_life_val = 60000;		// No extra life in demo.
    		}
    		else
    			Draw_Text_GDI(".",577+(demo_start_wait_elapsed*3),460,1,lpddsprimary);	// Erase timed-out 'dots' with background-colour print
    	} while (!selected);
    	next_extra_life_awarded = extra_life_val;
    
    	initial_wave_selected = wave;
    	screen_fadeout(SCREEN_SCRUNCH);
    	game_status = start_new_wave;
    
    }
    
    ///////////////////////////////////////////////////////////
    
    void new_wave()
    // Message at New Wave
    {
    		wave++;	// Move up to first/next wave
    		DD_Fill_Surface(lpddsprimary, 1);
    		if (demo == DEMO_OFF)
    			sprintf(buffer,"Wave #%d",wave);
    		else
    			sprintf(buffer,"DEMO Wave #%d",wave);
    		print_centre(buffer,200,210);
    		player_lives_disp = player_lives;
    		print_status_line('P');
    		Sleep(600);
    		reset_all_objects();
    
    		// Wave-specific variables
    		end_of_wave_nigh = 0;
    		cSpider::setWaveVariables(wave);
    		cSpiderFire::setWaveVariables(wave);
    
    		for (int spider_start_sound_sub=0; spider_start_sound_sub < SPIDER_START_SOUND_COUNT; spider_start_sound_sub++)
    			spider_start_sound[spider_start_sound_sub].init_pan();
    
    		for (int spider_launch_sound_sub=0; spider_launch_sound_sub < SPIDER_LAUNCH_SOUND_COUNT; spider_launch_sound_sub++)
    			spider_launch_sound[spider_launch_sound_sub].init_pan();
    
    		for (int spider_fire_sound_sub=0; spider_fire_sound_sub < SPIDER_FIRE_SOUND_COUNT; spider_fire_sound_sub++)
    			spider_fire_sound[spider_fire_sound_sub].init_pan();
    
    		for (int spider_hit_sound_sub=0; spider_hit_sound_sub < SPIDER_HIT_SOUND_COUNT; spider_hit_sound_sub++)
    			spider_hit_sound[spider_hit_sound_sub].init_pan();
    
    		screen_fadeout();
    		cSpider::currently_alive = 0;
    
    		game_status = in_progress;
    }
    
    ///////////////////////////////////////////////////////////
    
    void display_backdrop()
    // Display the backdrop (screen-sized BMP)
    {
    	// lock the back buffer
    	DD_Lock_Back_Surface();
    	// draw the background reactor image
    	Draw_Bitmap(&backdrop, back_buffer, back_lpitch, 0);
    	// unlock the back buffer
    	DD_Unlock_Back_Surface();
    }
    
    ///////////////////////////////////////////////////////////
    
    void check_user_input()
    {
    	DI_Read_Keyboard(); // get input
    	DI_Read_Joystick();
    	DI_Read_Mouse();
    
    	// Exit if (a) player presses ESCape, or (b) is player is out of lives
    	if (keyboard_state[DIK_ESCAPE])
    	{
    		PostMessage(main_window_handle, WM_DESTROY,0,0);
    		escape_pressed = TRUE;	// Finished!
    	}
    
    	// Pause gameplay if player presses 'P'
    	// Player must have released P before toggle works again
    	if (keyboard_state[DIK_P])
    	{
    		if (pause_press == PAUSE_PRESSED_NO)
    		{
    			pause_press = PAUSE_PRESSED_YES;
    			if (pause == PAUSE_OFF)
    				pause = PAUSE_ON;
    			else
    				pause = PAUSE_OFF;
    		}
    	}
    	else
    		pause_press = PAUSE_PRESSED_NO;
    	if (pause == PAUSE_ON)
    		return;
    
    	// Stop demo if player presses SPACE
    	if (keyboard_state[DIK_SPACE])
    	{
    		if (demo == DEMO_ON)
    		{
    			demo = DEMO_OFF;
    			init_game();
    			game_status = start_title;
    			return;
    		}
    	}
    
    	base_ship.ship_fire_move = 0;			 										// Reset Momentum of sideways movement of ship passed on to current ship fire
    
    	if (base_ship.isAlive())														// Only move/fire if Base Ship OK
    	{
    		base_ship.move(demo);														// Process ship movement according to user input
    
    		// FIRE!
    		if ( (demo == DEMO_OFF) &&
    			 ((keyboard_state[DIK_SPACE])	   									// Space = base_ship Fire!
    		  || (joy_state.rgbButtons[0]) 											// Joystick FIRE button
    		  || (mouse_state.rgbButtons[0]))
    		  || ((demo == DEMO_ON) &&
    				(rand()%10==0)) )
    
    		{
    			if ( (!base_ship.isFiring()) && (end_of_wave_nigh == 0) )	// Can only fire when outside firing cycle
    			{
    				if (demo == DEMO_OFF)
    					Play_Sound(base_fire_sound[cBaseFireSound::next_free_sound(BASE_FIRE_SOUND_COUNT)].getSoundId(),0);	// Play firing sound
    				base_ship.startFiring();											// Start cycle
    				int start_base_ship_fire_count = 0;								// Count is for 1 of 2 subsequent firings to be initiated here
    				// Find the next 2 free slots in firing list
    				for (int base_fire_sub=0; (base_fire_sub < BASE_FIRE_COUNT) && (start_base_ship_fire_count < 2); base_fire_sub++)
    				{
    					if (base_fire[base_fire_sub].isDead())
    					{
    						// Start off a new base fire
    						if (start_base_ship_fire_count == 0)					// Set 1st fire loose NOW
    						{
    							base_fire[base_fire_sub].start_new_base_fire(base_ship.getX()-1, base_ship.getY(), base_ship.ship_fire_move);
    						}
    						else
    							base_ship.setBaseFire2(base_fire_sub);				// Record 2nd fire for NEXT TIME (in animate_base_ship)
    						start_base_ship_fire_count++;
    					}
    				}
    			}
    		}
    	}
    }
    
    ///////////////////////////////////////////////////////////
    
    void animate_base_ship()
    // Animate base_ship if currently in firing cycle - release 2nd of 2 fire if ready
    {
    	int fire_second = base_ship.animate_and_check_second_fire();
    	if (fire_second)
    		base_fire[fire_second].start_new_base_fire(base_ship.getX()+25, base_ship.getY(), base_ship.ship_fire_move);
    }
    
    ///////////////////////////////////////////////////////////
    
    void check_ship_hit_and_process_dying()
    // Ship has been hit!
    {
    	if ( (player_lives == 0) && (!base_ship.isDying()) )
    			game_status = game_over;
    
    	if (base_ship.isDying())
    	{
    		if (base_ship.dead_cycle_count > 0)
    			Animate_BOB(base_ship.get_pBOB());
    		base_ship.dead_cycle_count++;
    
    		if (base_ship.dead_cycle_count > 28)						// Leave ship image upside down
    		{
    			base_ship.setDead();	  // Ship now gone
    			// Reset everything for next life
    			if (end_of_wave_nigh == 0)
    				reset_all_objects();										//else this will happen when new wave starts anyway
    			cSpider::this_wave += cSpider::currently_alive; 	// Keep number of spiders in current wave to start again
    			// Fade to Black before we start the next life.
    			if (end_of_wave_nigh == 0)
    				screen_fadeout(SCREEN_DISOLVE);
    			player_lives_disp = player_lives;
    		}
    	}
    }
    
    ///////////////////////////////////////////////////////////
    
    void draw_base_fires_and_check_if_hit_ship()
    // Move and display all current base fires
    {
    	cBaseFire::base_fire_currently_alive = 0;
    	for (int base_fire_sub=0; (base_fire_sub < BASE_FIRE_COUNT); base_fire_sub++)
    	{
    		if (base_fire[base_fire_sub].isAlive())
    		{
    			cBaseFire::base_fire_currently_alive++;
    			//Draw_Text_GDI("X",base_fire_sub*10,03,RGB(255,150,0),lpddsback); // LIVE fires
    			if ( (base_ship.isAlive()) &&
    				  (base_fire[base_fire_sub].getYV() < 0) &&													// Fire coming back down
    				  (Collision_BOBS(base_ship.get_pBOB(),base_fire[base_fire_sub].get_pBOB())) )	// and ship in same place
    			{
    				base_fire[base_fire_sub].setDead();																// Fire destroyed as well
    #ifndef ship_nohit
    				if (demo == DEMO_OFF)
    				{
    					Stop_All_Sounds();
    					base_hit_sound.playSound();																	// Play 'hit' sound
    					base_ship.setDying();																			// Ship hit by own fire - DYING
    					player_lives--;
    					Set_Animation_BOB(base_ship.get_pBOB(),1);												// Explode!!
    				}
    #endif
    			}
    
    			//sprintf(buffer,"%d",base_fire_clone[0].yv);
    			//Draw_Text_GDI(buffer,0,0,RGB(255,150,0),lpddsback);
    			base_fire[base_fire_sub].move_draw();
    		}
    		//else
    			//Draw_Text_GDI("x",base_fire_sub*10,0,RGB(0,150,255),lpddsback); // DEAD fires
    	}
    }
    
    ///////////////////////////////////////////////////////////
    
    void create_new_spider()
    // Starting up new spiders as DESCENDERS on webs
    {
    
    	cSpider::currently_alive = 0;
    	for (int spider_sub=0; spider_sub < SPIDER_COUNT; spider_sub++)
    	{
    		if (spider[spider_sub].isActive())
    			cSpider::currently_alive++;
    	}
    
    	//sprintf(buffer,"%d",cSpider::spiders_currently_alive);						// Write number of live spiders
    	//Draw_Text_GDI(buffer,0,0,RGB(255,150,0),lpddsback);
    
    	if (cSpider::currently_alive > cSpider::allowed_onscreen)					// In earlier waves we don't have all of them at once;
    		return;
    
    	check_wave_end();		// Finished wave yet?
    
    	for (spider_sub=0; spider_sub < SPIDER_COUNT; spider_sub++)
    	{
    		//The higher the wave, the more frequent they are!!
    		if ( (spider[spider_sub].isInactive()) && (rand()%3000 < (wave<<1)) && (cSpider::this_wave > 0))
    		{
    			if (demo == DEMO_OFF)
    				Play_Sound(spider_start_sound[cSpiderStartSound::next_free_sound(SPIDER_START_SOUND_COUNT)].getSoundId(),0);
    			cSpider::this_wave--;															// Count down for Spiders this wave
    			spider[spider_sub].setDescending();											// set Spider starting down the web
    		}
    	}
    }
    
    ///////////////////////////////////////////////////////////
    
    void check_wave_end()
    // Check whether we start a new wave yet
    {
    	// If no more spiders to launch this wave, wait until all the current ones are gone.
    	if ( (cSpider::this_wave == 0) && (cSpider::currently_alive == 0) )
    	{
    		if (end_of_wave_nigh == 0)
    			end_of_wave_nigh = 1;
    		if ( (cSpiderFire::spider_fire_currently_alive == 0) && (cBaseFire::base_fire_currently_alive == 0) )
    		{
    			end_of_wave_nigh++;
    			if ( (end_of_wave_nigh > 3) && (!base_ship.isDying()) )		// Allow for game logic to undraw last fire on screen
    			{
    				screen_fadeout();
    				if (demo == DEMO_ON)													// If DEMO mode then go back to title screen
    				{
    					demo = DEMO_OFF;
    					init_game();
    					game_status = start_title;
    					return;
    				}
    				score += 500;     													// Score 500 for finishing a wave
    				score_at_last_end_wave = score;									// Keep score at last wave completed for Continue
    				if (player_lives != 0)												// Did we lose final life at end of wave?
    					game_status = start_new_wave;
    				return;
    			}
    		}
    	}
    }
    
    ///////////////////////////////////////////////////////////
    
    void check_descending_spiders_and_draw_webs()
    //Draw all the current webs for descending spiders - check when they are turning into Flying Spiders!
    // Must be done on LOCKed surface
    {
    	DD_Lock_Back_Surface();
    	for (int spider_sub=0; spider_sub < SPIDER_COUNT; spider_sub++)
    	{
    		if (spider[spider_sub].isDescending())
    		{
    			VLine(0,spider[spider_sub].getY(),spider[spider_sub].getX()+15,180,back_buffer, back_lpitch);
    			// Grow until max_web_length - then becomes FLYING SPIDER
    			if (!spider[spider_sub].isWebFinished())
    				spider[spider_sub].growWeb();
    			else
    			{
    				// Spider now reached end of web and turned in FLYING SPIDER - armed and dangerous!!!
    				spider[spider_sub].setFlying();
    				if (demo == DEMO_OFF)
    					Play_Sound(spider_launch_sound[cSpiderLaunchSound::next_free_sound(SPIDER_LAUNCH_SOUND_COUNT)].getSoundId(),0);
    			}
    		}
    
    	}
    	DD_Unlock_Back_Surface();
    }
    ///////////////////////////////////////////////////////////
    
    void move_draw_check_spiders()
    // Has flying spider hit ship?
    // Ready to change direction?
    // Ready to fire?
    // Draw Spider.
    {
    	for (int spider_sub=0; spider_sub < SPIDER_COUNT; spider_sub++)
    	{
    		if (spider[spider_sub].isFlying())
    		{
    			if ( (base_ship.isAlive()) &&
    				  (Collision_BOBS(base_ship.get_pBOB(),spider[spider_sub].get_pBOB())) )	// Ship hit by flying Spider?
    			{
    				spider[spider_sub].setInactive();														// Spider is hit as well!
    				play_spider_hit_sound();
    #ifndef ship_nohit
    				if (demo == DEMO_OFF)
    				{
    					Stop_All_Sounds();
    					base_hit_sound.playSound();															// Play 'hit' sound
    					base_ship.setDying();																	// Ship hit by flying Spider - DYING
    					player_lives--;
    					Set_Animation_BOB(base_ship.get_pBOB(),1);										// Explode!!
    				}
    #endif
    			}
    
    			spider[spider_sub].checkChangeDir();
    
    			// Check for Spider firing
    			if (spider[spider_sub].fireNow())
    			{
    				// Time for Spider to fire
    				int spider_fire_found = FALSE;
    				for (int spider_fire_sub=0; (spider_fire_sub < SPIDER_FIRE_COUNT) && (!spider_fire_found); spider_fire_sub++)
    				{
    					if (spider_fire[spider_fire_sub].isDead())	// Find first available spider fire
    					{
    						spider_fire[spider_fire_sub].startFire(spider[spider_sub].getX(), spider[spider_sub].getY(),
    																			spider[spider_sub].getXV(), spider[spider_sub].getYV(),
    																			spider_sub);
    						spider_fire_found = TRUE;
    						if (demo == DEMO_OFF)
    							Play_Sound(spider_fire_sound[cSpiderFireSound::next_free_sound(SPIDER_FIRE_SOUND_COUNT)].getSoundId(),0);	// Play firing sound
    					}
    				}
    				spider[spider_sub].setTimeBeforeFiring();			// Set counter for next spider firing
    			}
    		}
    
    		spider[spider_sub].draw();
    	}
    }
    
    ///////////////////////////////////////////////////////////
    
    void check_for_spider_hit()
    // Check whether a live Spider has been hit by Base Ship fire.
    {
    	for (int spider_sub=0; spider_sub < SPIDER_COUNT; spider_sub++)
    	{
    		if ( spider[spider_sub].isDescending() || spider[spider_sub].isFlying() )
    		{
    			// First check... have we hit one with 'live' fire
    			for (int base_fire_sub=0; (base_fire_sub < BASE_FIRE_COUNT); base_fire_sub++)
    			{
    				if (base_fire[base_fire_sub].isAlive())
    				{
    					if (Collision_BOBS(spider[spider_sub].get_pBOB(),base_fire[base_fire_sub].get_pBOB()))
    					{
    						// We've hit a spider!
    						if (spider[spider_sub].isFlying())
    							score += 200;							// Score 200 for FLYING spiders
    						else
    							score += 50; 							// Score 50 for DESCENDING spiders
    						spider[spider_sub].setDying();
                      play_spider_hit_sound();
    						base_fire[base_fire_sub].setDead();	// And fire is out, too.
    					}
    				}
    			}
    
    			// Now check... get this... that a Spider Fire hasn't hit another Spider... YES!!!!
    			for (int spider_fire_sub=0; (spider_fire_sub < SPIDER_FIRE_COUNT); spider_fire_sub++)
    			{
    				  if (spider_fire[spider_fire_sub].isAlive())
    				  {
    						if ( (Collision_BOBS(spider[spider_sub].get_pBOB(),spider_fire[spider_fire_sub].get_pBOB()))
    						  && (spider_fire[spider_fire_sub].getOwner() != spider_sub) )
    						{
    							// A SPIDER hit another spider (not self!)
    							spider[spider_sub].setDying();
                         play_spider_hit_sound();
    							spider_fire[spider_fire_sub].setDead();	// And Spider fire is out, too.
    						}
    				  }
    			}
    
    		}
    	}
    }
    ///////////////////////////////////////////////////////////
    
    void draw_spider_fire_and_check_ship_hit()
    // Draw and advance all Spider Fires
    {
    	cSpiderFire::spider_fire_currently_alive = 0;
    	for (int spider_fire_sub=0; spider_fire_sub < SPIDER_FIRE_COUNT; spider_fire_sub++)
    	{
    		if (spider_fire[spider_fire_sub].isAlive())
    		{
    			cSpiderFire::spider_fire_currently_alive++;
    			// Draw_Text_GDI("X",spider_fire_sub*10,03,RGB(255,150,0),lpddsback); // LIVE fires DEBUG
    			// Has Spider fire hit Base Ship?
    			if (base_ship.isAlive())
    			{
    				if (Collision_BOBS(base_ship.get_pBOB(),spider_fire[spider_fire_sub].get_pBOB()))	// Ship hit by Spider Fire?
    				{
    					spider_fire[spider_fire_sub].setDead();			// Stop displaying fire.
    #ifndef ship_nohit
    					if (demo == DEMO_OFF)
    					{
    					   Stop_All_Sounds();
    						base_hit_sound.playSound();						// Play 'hit' sound
    						base_ship.setDying();								// Ship hit by flying Spider fire - DYING
    						player_lives--;
    						Set_Animation_BOB(base_ship.get_pBOB(),1);	// Explode!!
    					}
    #endif
    				}
    			}
    
    			// Ship Fire hit Spider fire - null both
    			for (int base_fire_sub=0; (base_fire_sub < BASE_FIRE_COUNT); base_fire_sub++)
    			{
    				if (base_fire[base_fire_sub].isAlive())
    				{
    					if (Collision_BOBS(spider_fire[spider_fire_sub].get_pBOB(),base_fire[base_fire_sub].get_pBOB()))
    					{
    						spider_fire[spider_fire_sub].setDead();		// Stop displaying fire.
    						base_fire[base_fire_sub].setDead();		  		// And fire is out, too.
    					}
    				}
    			}
    			spider_fire[spider_fire_sub].move_draw();
    		}
    		// else
    			// Draw_Text_GDI("x",spider_fire_sub*10,0,RGB(0,150,255),lpddsback); // DEAD fires - DEBUG
    	}
    }
    
    ///////////////////////////////////////////////////////////
    
    void play_spider_hit_sound()
    // Spider has been hit - make the sound.
    {
    	if (demo == DEMO_OFF)
    		Play_Sound(spider_hit_sound[cSpiderHitSound::next_free_sound(SPIDER_HIT_SOUND_COUNT)].getSoundId(),0);
    }
    
    ///////////////////////////////////////////////////////////
    
    void print_status_line(char surface)
    // Print the player's life and the score
    {
    	// First check whether player should get another life
    	if (score >= next_extra_life_awarded)
    	{
    		next_extra_life_awarded += extra_life_val;
    		if (demo == DEMO_OFF)
    			extra_life_sound.playSound();						 // Play 'extra life' sound
    		player_lives++;
    		player_lives_disp = player_lives;
    	}
    
    	sprintf(buffer,"%d : %.8d",player_lives_disp,score);
    	if (surface == 'P')
    		Draw_Text_GDI(buffer,8,SCREEN_HEIGHT-20,67,lpddsprimary);
    	else
    		Draw_Text_GDI(buffer,8,SCREEN_HEIGHT-20,67,lpddsback);
    
    	if ( (end_of_wave_nigh > 0) && (demo == DEMO_OFF) )
    	{
    		switch (wave_end_message)
    		{
    			case 0:
    				Draw_Text_GDI("< <   FINISHED 'EM OFF   > >", 220, 100, (rand()%214)+1, lpddsback);
    				break;
    			case 1:
    				Draw_Text_GDI("< <   GOOD SHOOTIN' THERE   > >", 210, 100, (rand()%214)+1, lpddsback);
    				break;
    			case 2:
    				Draw_Text_GDI("< <   SENT 'EM TO HELL!   > >", 220, 100, (rand()%214)+1, lpddsback);
    				break;
    			case 3:
    				Draw_Text_GDI("< <   SHOOT THEM SUCKERS DOWN   > >", 200, 100, (rand()%214)+1, lpddsback);
    				break;
    			case 4:
    				Draw_Text_GDI("< <   SPLATTED 'EM GOOD!!   > >", 210, 100, (rand()%214)+1, lpddsback);
    				break;
    			case 5:
    				Draw_Text_GDI("< <   MAKE 'EM SCREAM   > >", 220, 100, (rand()%214)+1, lpddsback);
    				break;
    			case 6:
    				Draw_Text_GDI("< <   ATTACK OVER   > >", 230, 100, (rand()%214)+1, lpddsback);
    				break;
    			case 7:
    				Draw_Text_GDI("< <   WAVE COMPLETED   > >", 220, 100, (rand()%214)+1, lpddsback);
    				break;
    			case 8:
    				Draw_Text_GDI("< <   MAKE MY DAY   > >", 230, 100, (rand()%214)+1, lpddsback);
    				break;
    			default:
    				Draw_Text_GDI("< <   WELL DONE PLAYER   > >", 220, 100, (rand()%214)+1, lpddsback);
    				break;
    		}
    	}
    	if (pause == PAUSE_ON)
    	{
    		Draw_Text_GDI("<<  DEMO MODE (SPACE to end)  >>", 204, 200, 0, lpddsprimary); // Wipeout pre-existing text
    		Draw_Text_GDI("< <   G A M E   P A U S E D   > >", 220, 200, (rand()%214)+1, lpddsprimary);
    	}
    	if (demo == DEMO_ON)
    	{
    		Draw_Text_GDI("<<  DEMO MODE (SPACE to end)  >>", 204, 200, (rand()%214)+1, lpddsback);
    	}
    }
    ///////////////////////////////////////////////////////////
    
    void game_over_screen()
    {
    		Stop_All_Sounds();
    		int wave_reached = wave-1;		// Current wave, for 'Continue' option.
    		DD_Fill_Surface(lpddsprimary, 0);
    		print_centre("G A M E    O V E R",100,30);
    		sprintf(buffer,"You reached wave %d, and scored %d points at '%s' level",wave,score,starting_level_description);
    		print_centre(buffer,180,155);
    		print_centre("Another Game? (SPACE = yes,   C = Continue,   ESC = Main Menu)",240,210);
    		print_centre("                        ('Continue' starts at last completed wave with score at that time)",260,210);
    		print_status_line('P');
    		int chosen = FALSE;
    		while (!chosen)
    		{
    			DI_Read_Keyboard(); // get input
    			if (keyboard_state[DIK_SPACE])
    			{
    				chosen=TRUE;
    				init_game();
    				wave = initial_wave_selected;		// Start with what user requested originally
    				print_centre("< <   GET READY   > >",210,69);
    			}
    			if (keyboard_state[DIK_C])
    			{
    				chosen=TRUE;
    				init_game();
    				wave = wave_reached;					// Continue with current wave
                score = score_at_last_end_wave;	// Refresh score from last successful wave end
    				print_centre("< <   GET READY   > >",210,69);
    			}
    			if (keyboard_state[DIK_ESCAPE])
    			{
    				chosen = TRUE;
    				init_game();
    				game_status = start_title;
    				print_centre("Returning to Main Menu",210,69);
    			}
    		}
    		screen_fadeout();
    }
    
    ///////////////////////////////////////////////////////////###########################################################