raiders3d_2.cpp
上传用户:husern
上传日期:2018-01-20
资源大小:42486k
文件大小:69k
源码类别:

游戏

开发平台:

Visual C++

  1. // RAIDERS3D_2.CPP - 3D star raiders game version 2.0, 16-bit 
  2. // READ THIS!
  3. // To compile make sure to include DDRAW.LIB, DSOUND.LIB,
  4. // DINPUT.LIB, DINPUT8.LIB, WINMM.LIB in the project link list, and of course 
  5. // the C++ source modules T3DLIB1-7.CPP and the headers T3DLIB1-7.H
  6. // be in the working directory of the compiler
  7. // PRESS <N> to change the nebula
  8. // INCLUDES ///////////////////////////////////////////////
  9. #define DEBUG_OFF 
  10. #define INITGUID       // make sure al the COM interfaces are available
  11.                        // instead of this you can include the .LIB file
  12.                        // DXGUID.LIB
  13. #define WIN32_LEAN_AND_MEAN  
  14. #include <windows.h>   // include important windows stuff
  15. #include <windowsx.h> 
  16. #include <mmsystem.h>
  17. #include <iostream.h> // include important C/C++ stuff
  18. #include <conio.h>
  19. #include <stdlib.h> 
  20. #include <malloc.h>  
  21. #include <memory.h>
  22. #include <string.h> 
  23. #include <stdarg.h>
  24. #include <stdio.h> 
  25. #include <math.h>
  26. #include <io.h> 
  27. #include <fcntl.h>
  28. #include <ddraw.h>  // directX includes
  29. #include <dsound.h>
  30. #include <dmksctrl.h>
  31. #include <dmusici.h>
  32. #include <dmusicc.h>
  33. #include <dmusicf.h>
  34. #include <dinput.h>
  35. #include "T3DLIB1.h" // game library includes
  36. #include "T3DLIB2.h"
  37. #include "T3DLIB3.h"
  38. #include "T3DLIB4.h"
  39. #include "T3DLIB5.h"
  40. #include "T3DLIB6.h"
  41. #include "T3DLIB7.h"
  42. // DEFINES ////////////////////////////////////////////////
  43. // defines for windows interface
  44. #define WINDOW_CLASS_NAME "WIN3DCLASS"  // class name
  45. #define WINDOW_TITLE      "T3D Graphics Console Ver 2.0"
  46. #define WINDOW_WIDTH      800  // size of window
  47. #define WINDOW_HEIGHT     600
  48. #define WINDOW_BPP        16    // bitdepth of window (8,16,24 etc.)
  49.                                 // note: if windowed and not
  50.                                 // fullscreen then bitdepth must
  51.                                 // be same as system bitdepth
  52.                                 // also if 8-bit the a pallete
  53.                                 // is created and attached
  54.    
  55. #define WINDOWED_APP      0     // 0 not windowed, 1 windowed
  56. // 3D engine constants for overlay star field
  57. #define NEAR_Z            10    // the near clipping plane
  58. #define FAR_Z             2000  // the far clipping plane    
  59. #define VIEW_DISTANCE      400  // viewing distance from viewpoint 
  60.                                 // this gives a field of view of 90 degrees
  61.                                 // when projected on a window of 800 wide
  62. // create some constants for ease of access
  63. #define AMBIENT_LIGHT_INDEX   0 // ambient light index
  64. #define INFINITE_LIGHT_INDEX  1 // infinite light index
  65. #define POINT_LIGHT_INDEX     2 // point light index
  66. #define POINT_LIGHT2_INDEX    3 // point light index
  67. #define SPOT_LIGHT2_INDEX     4 // spot light index
  68. // alien defines
  69. #define NUM_ALIENS            16 // total number of ALIEN fighters 
  70. // states for aliens
  71. #define ALIEN_STATE_DEAD      0  // alien is dead
  72. #define ALIEN_STATE_ALIVE     1  // alien is alive
  73. #define ALIEN_STATE_DYING     2  // alien is in process of dying
  74. // star defines
  75. #define NUM_STARS           256  // number of stars in sim
  76. // game state defines
  77. #define GAME_STATE_INIT       0  // game initializing for first time
  78. #define GAME_STATE_RESTART    1  // game restarting after game over
  79. #define GAME_STATE_RUN        2  // game running normally
  80. #define GAME_STATE_DEMO       3  // game in demo mode
  81. #define GAME_STATE_OVER       4  // game over
  82. #define GAME_STATE_EXIT       5  // game state exit
  83. #define MAX_MISSES_GAME_OVER  25 // miss this many and it's game over man
  84. // interface text positions
  85. #define TPOS_SCORE_X          346  // players score
  86. #define TPOS_SCORE_Y          4
  87. #define TPOS_HITS_X           250  // total kills
  88. #define TPOS_HITS_Y           36
  89. #define TPOS_ESCAPED_X        224  // aliens that have escaped
  90. #define TPOS_ESCAPED_Y        58
  91.  
  92. #define TPOS_GLEVEL_X         430 // diff level of game
  93. #define TPOS_GLEVEL_Y         58
  94. #define TPOS_SPEED_X          404 // diff level of game
  95. #define TPOS_SPEED_Y          36
  96. #define TPOS_GINFO_X          400  // general information
  97. #define TPOS_GINFO_Y          240
  98. #define TPOS_ENERGY_X         158 // weapon energy level
  99. #define TPOS_ENERGY_Y         6
  100. // player defines
  101. #define CROSS_START_X         0
  102. #define CROSS_START_Y         0
  103. #define CROSS_WIDTH           56
  104. #define CROSS_HEIGHT          56
  105. // font display stuff
  106. #define FONT_HPITCH           12  // space between chars
  107. #define FONT_VPITCH           14  // space between lines
  108. // difficulty stuff
  109. #define DIFF_RATE             (float)(.001f)  // rate to advance  difficulty per frame
  110. #define DIFF_PMAX             75
  111. // explosion stuff
  112. #define NUM_EXPLOSIONS        16
  113. // PROTOTYPES /////////////////////////////////////////////
  114. // game console funtions
  115. int Game_Init(void *parms=NULL);
  116. int Game_Shutdown(void *parms=NULL);
  117. int Game_Main(void *parms=NULL);
  118. // starfield functions
  119. void Draw_Starfield(UCHAR *video_buffer, int lpitch);
  120. void Move_Starfield(void);
  121. void Init_Starfield(void);
  122. // alien functions
  123. void Process_Aliens(void);
  124. void Draw_Aliens(void);
  125. void Init_Aliens(void);
  126. int  Start_Alien(void);
  127. // explosions
  128. int Start_Mesh_Explosion(OBJECT4DV2_PTR obj, // object to destroy
  129.                          MATRIX4X4_PTR mrot, // initial orientation
  130.                          int detail,         // the detail level,1 highest detail
  131.                          float rate,         // velocity of explosion shrapnel
  132.                          int lifetime);      // total lifetime of explosion
  133. void Draw_Mesh_Explosions(void);
  134. // font functions
  135. int Draw_Bitmap_Font_String(BOB_PTR font, 
  136.                             int x, int y, 
  137.                             char *string, 
  138.                             int hpitch, int vpitch, 
  139.                             LPDIRECTDRAWSURFACE7 dest); 
  140. int Load_Bitmap_Font(char *fontfile, BOB_PTR font);
  141. // TYPES ///////////////////////////////////////////////////
  142. // this a 3D star
  143. typedef struct STAR3D_TYP
  144.         {
  145.         USHORT color;     // color of point 16-bit
  146.         float x,y,z;      // coordinates of point in 3D
  147.         } STAR3D, *STAR3D_PTR;
  148. // ALIEN fighter object
  149. typedef struct ALIEN_TYP
  150.         {
  151.         int      state;  // state of this ALIEN fighter
  152.         int      count;  // generic counter
  153.         int      aux;    // generic auxialiary var
  154.         POINT3D  pos;    // position of ALIEN fighter
  155.         VECTOR3D vel;    // velocity of ALIEN fighter
  156.         VECTOR3D rot;    // rotational velocities
  157.         VECTOR3D ang;    // current orientation
  158.         } ALIEN, *ALIEN_PTR;
  159. // GLOBALS /////////////////////////////////////////////////
  160. HWND main_window_handle           = NULL; // save the window handle
  161. HINSTANCE main_instance           = NULL; // save the instance
  162. char buffer[2048];                        // used to print text
  163. // initialize camera position and direction
  164. POINT4D  cam_pos    = {0,0,0,1};
  165. POINT4D  cam_target = {0,0,0,1};
  166. VECTOR4D cam_dir    = {0,0,0,1};
  167. // all your initialization code goes here...
  168. VECTOR4D vscale={1.0,1.0,1.0,1}, 
  169.          vpos = {0,0,0,1}, 
  170.          vrot = {0,0,0,1};
  171. CAM4DV1        cam;       // the single camera
  172. RENDERLIST4DV2 rend_list; // the render list
  173. // color constants for line drawing
  174. USHORT rgb_green,  
  175.        rgb_white,
  176.        rgb_red,
  177.        rgb_blue;
  178. // colors for lights
  179. RGBAV1 white, light_gray, gray, black, red, green, blue;
  180. // music and sound stuff
  181. int main_track_id      = -1, // main music track id
  182.     laser_id           = -1, // sound of laser pulse
  183.     explosion_id       = -1, // sound of explosion
  184.     flyby_id           = -1, // sound of ALIEN fighter flying by
  185.     game_over_id       = -1, // game over
  186.     ambient_systems_id = -1; // ambient sounds
  187. // star globals
  188. STAR3D stars[NUM_STARS]; // the starfield
  189. // player and game globals
  190. int player_z_vel = 4; // virtual speed of viewpoint/ship
  191. float cross_x = 0, // cross hairs
  192.       cross_y = 0; 
  193. int cross_x_screen  = WINDOW_WIDTH/2,   // used for cross hair
  194.     cross_y_screen  = WINDOW_HEIGHT/2, 
  195.     target_x_screen = WINDOW_WIDTH/2,   // used for targeter
  196.     target_y_screen = WINDOW_HEIGHT/2;
  197. int escaped        = 0;   // tracks number of missed ships
  198. int hits           = 0;   // tracks number of hits
  199. int score          = 0;   // take a guess :)
  200. int weapon_energy  = 100; // weapon energy
  201. int weapon_active  = 0;   // tracks if weapons are energized
  202. int game_state           = GAME_STATE_INIT; // state of game
  203. int game_state_count1    = 0;               // general counters
  204. int game_state_count2    = 0;
  205. int restart_state        = 0;               // state when game is restarting
  206. int restart_state_count1 = 0;               // general counter
  207. // diffiuculty
  208. float  diff_level    = 1;                   // difficulty level used in velocity and probability calcs
  209. // alien globals
  210. ALIEN      aliens[NUM_ALIENS];   // the ALIEN fighters
  211. OBJECT4DV2 obj_alien;            // the master object
  212. // explosions
  213. OBJECT4DV2 explobj[NUM_EXPLOSIONS]; // the explosions
  214. // game imagery assets
  215. BOB cockpit;               // the cockpit image
  216. BOB starscape;             // the background starscape
  217. BOB tech_font;             // the bitmap font for the engine
  218. BOB crosshair;             // the player's cross hair
  219. // these are the positions of the energy binding on the main lower control panel
  220. POINT2D energy_bindings[6] = { {342, 527}, {459, 527}, 
  221.                                {343, 534}, {458, 534}, 
  222.                                {343, 540}, {458, 540} };
  223. // these hold the positions of the weapon burst which use lighting too
  224. // the starting points are known, but the end points are computed on the fly
  225. // based on the cross hair
  226. POINT2D weapon_bursts[4] = { {78, 500}, {0,0},     // left energy weapon
  227.                              {720, 500}, {0,0} };  // right energy weapon
  228. int px = 0, py = 0, pz = 500 ; // debug stuff for object tracking
  229. // FUNCTIONS //////////////////////////////////////////////
  230. LRESULT CALLBACK WindowProc(HWND hwnd, 
  231.     UINT msg, 
  232.                             WPARAM wparam, 
  233.                             LPARAM lparam)
  234. {
  235. // this is the main message handler of the system
  236. PAINTSTRUCT ps;    // used in WM_PAINT
  237. HDC hdc;    // handle to a device context
  238. // what is the message 
  239. switch(msg)
  240. {
  241. case WM_CREATE: 
  242.         {
  243. // do initialization stuff here
  244. return(0);
  245. } break;
  246.     case WM_PAINT:
  247.          {
  248.          // start painting
  249.          hdc = BeginPaint(hwnd,&ps);
  250.          // end painting
  251.          EndPaint(hwnd,&ps);
  252.          return(0);
  253.         } break;
  254. case WM_DESTROY: 
  255. {
  256. // kill the application
  257. PostQuitMessage(0);
  258. return(0);
  259. } break;
  260. default:break;
  261.     } // end switch
  262. // process any messages that we didn't take care of 
  263. return (DefWindowProc(hwnd, msg, wparam, lparam));
  264. } // end WinProc
  265. // WINMAIN ////////////////////////////////////////////////
  266. int WINAPI WinMain( HINSTANCE hinstance,
  267. HINSTANCE hprevinstance,
  268. LPSTR lpcmdline,
  269. int ncmdshow)
  270. {
  271. // this is the winmain function
  272. WNDCLASS winclass; // this will hold the class we create
  273. HWND  hwnd; // generic window handle
  274. MSG  msg; // generic message
  275. HDC      hdc;       // generic dc
  276. PAINTSTRUCT ps;     // generic paintstruct
  277. // first fill in the window class stucture
  278. winclass.style = CS_DBLCLKS | CS_OWNDC | 
  279.                           CS_HREDRAW | CS_VREDRAW;
  280. winclass.lpfnWndProc = WindowProc;
  281. winclass.cbClsExtra = 0;
  282. winclass.cbWndExtra = 0;
  283. winclass.hInstance = hinstance;
  284. winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  285. winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  286. winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  287. winclass.lpszMenuName = NULL; 
  288. winclass.lpszClassName = WINDOW_CLASS_NAME;
  289. // register the window class
  290. if (!RegisterClass(&winclass))
  291. return(0);
  292. // create the window, note the test to see if WINDOWED_APP is
  293. // true to select the appropriate window flags
  294. if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
  295.   WINDOW_TITLE,  // title
  296.   (WINDOWED_APP ? (WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION) : (WS_POPUP | WS_VISIBLE)),
  297.     0,0,    // x,y
  298.   WINDOW_WIDTH,  // width
  299.                           WINDOW_HEIGHT, // height
  300.   NULL,    // handle to parent 
  301.   NULL,    // handle to menu
  302.   hinstance,// instance
  303.   NULL))) // creation parms
  304. return(0);
  305. // save the window handle and instance in a global
  306. main_window_handle = hwnd;
  307. main_instance      = hinstance;
  308. // resize the window so that client is really width x height
  309. if (WINDOWED_APP)
  310. {
  311. // now resize the window, so the client area is the actual size requested
  312. // since there may be borders and controls if this is going to be a windowed app
  313. // if the app is not windowed then it won't matter
  314. RECT window_rect = {0,0,WINDOW_WIDTH-1,WINDOW_HEIGHT-1};
  315. // make the call to adjust window_rect
  316. AdjustWindowRectEx(&window_rect,
  317.      GetWindowStyle(main_window_handle),
  318.      GetMenu(main_window_handle) != NULL,  
  319.      GetWindowExStyle(main_window_handle));
  320. // save the global client offsets, they are needed in DDraw_Flip()
  321. window_client_x0 = -window_rect.left;
  322. window_client_y0 = -window_rect.top;
  323. // now resize the window with a call to MoveWindow()
  324. MoveWindow(main_window_handle,
  325.            0, // x position
  326.            0, // y position
  327.            window_rect.right - window_rect.left, // width
  328.            window_rect.bottom - window_rect.top, // height
  329.            FALSE);
  330. // show the window, so there's no garbage on first render
  331. ShowWindow(main_window_handle, SW_SHOW);
  332. } // end if windowed
  333. // perform all game console specific initialization
  334. Game_Init();
  335. // disable CTRL-ALT_DEL, ALT_TAB, comment this line out 
  336. // if it causes your system to crash
  337. SystemParametersInfo(SPI_SCREENSAVERRUNNING, TRUE, NULL, 0);
  338. // enter main event loop
  339. while(1)
  340. {
  341. if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  342. // test if this is a quit
  343.         if (msg.message == WM_QUIT)
  344.            break;
  345. // translate any accelerator keys
  346. TranslateMessage(&msg);
  347. // send the message to the window proc
  348. DispatchMessage(&msg);
  349. } // end if
  350.     
  351.     // main game processing goes here
  352.     Game_Main();
  353. } // end while
  354. // shutdown game and release all resources
  355. Game_Shutdown();
  356. // enable CTRL-ALT_DEL, ALT_TAB, comment this line out 
  357. // if it causes your system to crash
  358. SystemParametersInfo(SPI_SCREENSAVERRUNNING, FALSE, NULL, 0);
  359. // return to Windows like this
  360. return(msg.wParam);
  361. } // end WinMain
  362. ////////////////////////////////////////////////////////////////////
  363. void Render_Energy_Bindings(POINT2D_PTR bindings, // array containing binding positions in the form
  364.                                                   // start point, end point, start point, end point...
  365.                             int num_bindings,     // number of energy bindings to render 1-3
  366.                             int num_segments,     // number of segments to randomize bindings into
  367.                             int amplitude,        // amplitude of energy binding
  368.                             int color,            // color of bindings
  369.                             UCHAR *video_buffer,  // video buffer to render
  370.                             int lpitch)           // memory pitch of buffer
  371. {
  372. // this functions renders the energy bindings across the main exterior energy
  373. // transmission emitters :) Basically, the function takes two points in 2d then
  374. // it anchors a line at the two ends and randomly walks from end point to the
  375. // other by breaking the line into segments and then randomly modulating the y position
  376. // and amount amplitude +-, maximum number of segments 16
  377. POINT2D segments[17]; // to hold constructed segments after construction
  378. // render each binding
  379. for (int index = 0; index < num_bindings; index++)
  380.     {
  381.     // store starting and ending positions
  382.     
  383.     // starting position
  384.     segments[0] = bindings[index*2];
  385.     
  386.     // ending position
  387.     segments[num_segments] = bindings[index*2+1];
  388.     // compute vertical gradient, so if y positions of endpoints are
  389.     // greatly different bindings will be modulated using the straight line
  390.     // as a basis
  391.     float dyds = (segments[num_segments].y - segments[0].y) / (float)num_segments;
  392.     float dxds = (segments[num_segments].x - segments[0].x) / (float)num_segments;
  393.     // now build up segments
  394.     for (int sindex = 1; sindex < num_segments; sindex++)
  395.         {
  396.         segments[sindex].x = segments[sindex-1].x + dxds;
  397.         segments[sindex].y = segments[0].y + sindex*dyds + RAND_RANGE(-amplitude, amplitude);
  398.         } // end for segment            
  399.     // draw binding
  400.     for (sindex = 0; sindex < num_segments; sindex++)
  401.         Draw_Line16(segments[sindex].x, segments[sindex].y, 
  402.                     segments[sindex+1].x, segments[sindex+1].y,
  403.                     color, video_buffer, lpitch); 
  404.     } // end for index
  405. } // end Render_Energy_Binding
  406. ////////////////////////////////////////////////////////////////////
  407. void Render_Weapon_Bursts(POINT2D_PTR burstpoints, // array containing energy burst positions in the form
  408.                                                    // start point, end point, start point, end point...
  409.                             int num_bursts,
  410.                             int num_segments,     // number of segments to randomize bindings into
  411.                             int amplitude,        // amplitude of energy binding
  412.                             int color,            // color of bindings
  413.                             UCHAR *video_buffer,  // video buffer to render
  414.                             int lpitch)           // memory pitch of buffer
  415. {
  416. // this functions renders the weapon energy bursts from the weapon emitter or wherever
  417. // function derived from Render_Energy_Binding, but generalized 
  418. // Basically, the function takes two points in 2d then
  419. // it anchors a line at the two ends and randomly walks from end point to the
  420. // other by breaking the line into segments and then randomly modulating the x,y position
  421. // and amount amplitude +-, maximum number of segments 16
  422. POINT2D segments[17]; // to hold constructed segments after construction
  423. // render each energy burst
  424. for (int index = 0; index < num_bursts; index++)
  425.     {
  426.     // store starting and ending positions
  427.     
  428.     // starting position
  429.     segments[0] = burstpoints[index*2];
  430.     
  431.     // ending position
  432.     segments[num_segments] = burstpoints[index*2+1];
  433.     // compute horizontal/vertical gradients, so we can modulate the lines 
  434.     // on the proper trajectory
  435.     float dyds = (segments[num_segments].y - segments[0].y) / (float)num_segments;
  436.     float dxds = (segments[num_segments].x - segments[0].x) / (float)num_segments;
  437.     // now build up segments
  438.     for (int sindex = 1; sindex < num_segments; sindex++)
  439.         {
  440.         segments[sindex].x = segments[0].x + sindex*dxds + RAND_RANGE(-amplitude, amplitude);
  441.         segments[sindex].y = segments[0].y + sindex*dyds + RAND_RANGE(-amplitude, amplitude);
  442.         } // end for segment            
  443.     // draw binding
  444.     for (sindex = 0; sindex < num_segments; sindex++)
  445.         Draw_Line16(segments[sindex].x, segments[sindex].y, 
  446.                     segments[sindex+1].x, segments[sindex+1].y,
  447.                     color, video_buffer, lpitch); 
  448.     } // end for index
  449. } // end Render_Weapons_Bursts
  450. ///////////////////////////////////////////////////////////////
  451. int Load_Bitmap_Font(char *fontfile, BOB_PTR font)
  452. {
  453. // this is a semi generic font loader...
  454. // expects the file name of a font in a template that is 
  455. // 4 rows of 16 cells, each character is 16x14, and cell 0 is the space character
  456. // characters from 32 to 95, " " to "-", suffice for 90% of text work
  457. // load the font bitmap template
  458. if (!Load_Bitmap_File(&bitmap16bit, fontfile))
  459.    return(0);
  460. // create the bob that will hold the font, use a bob for speed, we can use the 
  461. // hardware blitter
  462. Create_BOB(font, 0,0,16,14,64, BOB_ATTR_VISIBLE | BOB_ATTR_SINGLE_FRAME, DDSCAPS_SYSTEMMEMORY, 0, 16); 
  463. // load all the frames
  464. for (int index=0; index < 64; index++)
  465.      Load_Frame_BOB16(font, &bitmap16bit,index,index%16,index/16,BITMAP_EXTRACT_MODE_CELL);
  466. // unload the bitmap file
  467. Unload_Bitmap_File(&bitmap16bit);
  468. // return success
  469. return(1);
  470. } // end Load_Bitmap_Font
  471. ///////////////////////////////////////////////////////////////
  472. int Draw_Bitmap_Font_String(BOB_PTR font,  // pointer to bob containing font
  473.                             int x, int y,  // screen position to render
  474.                             char *string,  // string to render
  475.                             int hpitch, int vpitch, // horizontal and vertical pitch
  476.                             LPDIRECTDRAWSURFACE7 dest) // destination surface
  477. {
  478. // this function draws a string based on a 64 character font sent in as a bob
  479. // the string will be drawn at the given x,y position with intercharacter spacing
  480. // if hpitch and a interline spacing of vpitch
  481. // are things semi valid?
  482. if (!string || !dest)
  483.    return(0);
  484. // loop and render
  485. for (int index = 0; index < strlen(string); index++)
  486.     {
  487.     // set the position and character
  488.     font->x = x;
  489.     font->y = y;
  490.     font->curr_frame = string[index] - 32;
  491.     // test for overflow set to space
  492.     if (font->curr_frame > 63 || font->curr_frame < 0) font->curr_frame = 0;
  493.     // render character (i hate making a function call!)
  494.     Draw_BOB16(font, dest);
  495.     // move position
  496.     x+=hpitch;
  497.     } // end for index
  498. // return success
  499. return(1);
  500. } // end Draw_Bitmap_Font_String
  501. /////////////////////////////////////////////////////////
  502. int Start_Alien(void)
  503. {
  504. // this function hunts in the alien list, finds an available alien and 
  505. // starts it up
  506. for (int index = 0; index < NUM_ALIENS; index++)
  507.     {
  508.     // is this alien available?
  509.     if (aliens[index].state == ALIEN_STATE_DEAD)
  510.        {
  511.        // clear any residual data
  512.        memset((void *)&aliens[index], 0, sizeof (ALIEN) );
  513.        // start alien up
  514.        aliens[index].state = ALIEN_STATE_ALIVE;
  515.        
  516.        // select random position in bounding volume
  517.        aliens[index].pos.x = RAND_RANGE(-1000,1000);
  518.        aliens[index].pos.y = RAND_RANGE(-1000,1000);
  519.        aliens[index].pos.z = 20000;
  520.        
  521.        // select velocity based on difficulty level
  522.        aliens[index].vel.x = RAND_RANGE(-10,10);
  523.        aliens[index].vel.y = RAND_RANGE(-10,10);
  524.        aliens[index].vel.z = -(10*diff_level+rand()%200);
  525.        // set rotation rate for z axis only
  526.        aliens[index].rot.z = RAND_RANGE(-5,5);
  527.  
  528.        // return the index
  529.        return(index);
  530.        } // end if   
  531.     } // end for index
  532. // failure
  533. return(-1);
  534. } // end Start_Alien
  535. /////////////////////////////////////////////////////////
  536. void Init_Aliens(void)
  537. {
  538. // initializes all the ALIEN fighters to a known state
  539. for (int index = 0; index < NUM_ALIENS; index++)
  540.     {
  541.     // zero ALIEN fighter out
  542.     memset((void *)&aliens[index], 0, sizeof (ALIEN) );
  543.     // set any other specific info now...
  544.     aliens[index].state = ALIEN_STATE_DEAD;
  545.     } // end for
  546. } // end Init_Aliens
  547. /////////////////////////////////////////////////////////
  548. void Draw_Aliens(void)
  549. {
  550. // this function draws all the active ALIEN fighters
  551. MATRIX4X4 mrot; // used to transform objects
  552. for (int index = 0; index < NUM_ALIENS; index++)
  553.     {
  554.     // which state is alien in
  555.     switch(aliens[index].state)
  556.           {
  557.           // is the alien dead? if so move on
  558.           case ALIEN_STATE_DEAD: break;
  559.           // is the alien alive?
  560.           case ALIEN_STATE_ALIVE:
  561.           case ALIEN_STATE_DYING:
  562.           {
  563.           // reset the object (this only matters for backface and object removal)
  564.           Reset_OBJECT4DV2(&obj_alien);
  565.           // generate rotation matrix around y axis
  566.           Build_XYZ_Rotation_MATRIX4X4(aliens[index].ang.x, aliens[index].ang.y, aliens[index].ang.z ,&mrot);
  567.          
  568.           // rotate the local coords of the object
  569.           Transform_OBJECT4DV2(&obj_alien, &mrot, TRANSFORM_LOCAL_TO_TRANS,1);
  570.           // set position of constant shaded cube
  571.           obj_alien.world_pos.x = aliens[index].pos.x;
  572.           obj_alien.world_pos.y = aliens[index].pos.y;
  573.           obj_alien.world_pos.z = aliens[index].pos.z;
  574.           // attempt to cull object
  575.           if (!Cull_OBJECT4DV2(&obj_alien, &cam, CULL_OBJECT_XYZ_PLANES))
  576.              {
  577.              // perform world transform
  578.              Model_To_World_OBJECT4DV2(&obj_alien, TRANSFORM_TRANS_ONLY);
  579.              // insert the object into render list
  580.              Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_alien,0);
  581.              } // end if 
  582.           // ok, now test for collision with energy bursts, strategy is as follows
  583.           // we will project the bounding box of the object into screen space to coincide with
  584.           // the energy burst on the screen, if there is an overlap then the target is hit
  585.           // simply need to do a few transforms, this kinda sucks that we are going to do this work
  586.           // 2x, but the problem is that the graphics pipeline knows nothing about collision etc.,
  587.           // so we can't "get to" the information me want since we are ripping the objects apart
  588.           // and passing them down the pipeline for a later world to camera transform, thus you
  589.           // may want to think about this problem when making your own game, how tight to couple
  590.           // collision and the engine, HOWEVER, the only reason we are having a problem at all is that
  591.           // we want to use the screen coords of the energy burst this is fine, but a more effective method
  592.           // would be to compute the 3D world coords of where the energy burst is firing and then project
  593.           // that parallelpiped in 3D space to see where the player is trying to fire, this is a classic
  594.           // problem with screen picking, hence, in the engine, when an object is rendered sometimes its 
  595.           // a good idea to track somekind of collision boundary in screen coords that can be used later
  596.           // for "object picking" and collision, anyway, let's do it the easy way, but the long way....
  597.           // first is the player firing weapon?
  598.           if (weapon_active)
  599.              {
  600.              // we need 4 transforms total, first we need all our points in world coords,
  601.              // then we need camera coords, then perspective coords, then screen coords
  602.              // we need to transform 2 points: the center and a point lying on the surface of the  
  603.              // bounding sphere, as long as the 
  604.              POINT4D pbox[4], // bounding box coordinates, center points, surrounding object
  605.                               // denoted by X's, we need to project these to screen coords
  606.                               // ....X.... 
  607.                               // . |   | .
  608.                               // X |-O-| X
  609.                               // . |   | . 
  610.                               // ....X....
  611.                               // we will use the average radius as the distance to each X from the center
  612.                      presult; // used to hold temp results
  613.              // world to camera transform
  614.              // transform center point only
  615.              Mat_Mul_VECTOR4D_4X4(&obj_alien.world_pos, &cam.mcam, &presult);
  616.              // result holds center of object in camera coords now
  617.              // now we are in camera coords, aligned to z-axis, compute radial point axis aligned
  618.              // bounding box points
  619.              // x+r, y, z
  620.              pbox[0].x = presult.x + obj_alien.avg_radius[obj_alien.curr_frame];
  621.              pbox[0].y = presult.y;
  622.              pbox[0].z = presult.z;
  623.              pbox[0].w = 1;        
  624.              // x-r, y, z
  625.              pbox[1].x = presult.x - obj_alien.avg_radius[obj_alien.curr_frame];
  626.              pbox[1].y = presult.y;
  627.              pbox[1].z = presult.z;
  628.              pbox[1].w = 1;     
  629.              // x, y+r, z
  630.              pbox[2].x = presult.x;
  631.              pbox[2].y = presult.y + obj_alien.avg_radius[obj_alien.curr_frame];
  632.              pbox[2].z = presult.z;
  633.              pbox[2].w = 1;     
  634.              // x, y-r, z
  635.              pbox[3].x = presult.x;
  636.              pbox[3].y = presult.y - obj_alien.avg_radius[obj_alien.curr_frame];
  637.              pbox[3].z = presult.z;
  638.              pbox[3].w = 1;     
  639.              // now we are ready to project the points to screen space
  640.              float alpha = (0.5*cam.viewport_width-0.5);
  641.              float beta  = (0.5*cam.viewport_height-0.5);
  642.              // loop and process each point
  643.              for (int bindex=0; bindex < 4; bindex++)
  644.                  {
  645.                  float z = pbox[bindex].z;
  646.                  // perspective transform first
  647.                  pbox[bindex].x = cam.view_dist*pbox[bindex].x/z;
  648.                  pbox[bindex].y = cam.view_dist*pbox[bindex].y*cam.aspect_ratio/z;
  649.                  // z = z, so no change
  650.                  // screen projection
  651.                  pbox[bindex].x =  alpha*pbox[bindex].x + alpha; 
  652.                  pbox[bindex].y = -beta*pbox[bindex].y + beta;
  653.                  } // end for bindex
  654. #ifdef DEBUG_ON
  655.              // now we have the 4 points is screen coords and we can test them!!! ya!!!!
  656.              Draw_Clip_Line16(pbox[0].x, pbox[2].y, pbox[1].x, pbox[2].y, rgb_red, back_buffer, back_lpitch);
  657.              Draw_Clip_Line16(pbox[0].x, pbox[3].y, pbox[1].x, pbox[3].y, rgb_red, back_buffer, back_lpitch);
  658.              Draw_Clip_Line16(pbox[0].x, pbox[2].y, pbox[0].x, pbox[3].y, rgb_red, back_buffer, back_lpitch);
  659.              Draw_Clip_Line16(pbox[1].x, pbox[2].y, pbox[1].x, pbox[3].y, rgb_red, back_buffer, back_lpitch);
  660. #endif
  661.              // test for collision
  662.              if ((cross_x_screen > pbox[1].x) && (cross_x_screen < pbox[0].x) &&
  663.                  (cross_y_screen > pbox[2].y) && (cross_y_screen < pbox[3].y) )
  664.                 {
  665.                 Start_Mesh_Explosion(&obj_alien, // object to blow
  666.                                      &mrot,      // initial orientation
  667.                                      3,          // the detail level,1 highest detail
  668.                                      .5,         // velocity of explosion shrapnel
  669.                                      100);       // total lifetime of explosion         
  670.                 // remove from simulation
  671.                 aliens[index].state = ALIEN_STATE_DEAD;
  672.                 // make some sound
  673.                 DSound_Play(explosion_id);
  674.                 // increment hits
  675.                 hits++;
  676.               
  677.                 // take into consideration the z, the speed, the level, blah blah
  678.                 score += (int)((diff_level*10 + obj_alien.world_pos.z/10));
  679.                 } // end if
  680.         
  681.              } // end if weapon active
  682.           } break;
  683.          
  684.           default: break;
  685.           } // end switch
  686.     } // end for index
  687. // debug code
  688. #ifdef DEBUG_ON
  689. // reset the object (this only matters for backface and object removal)
  690. Reset_OBJECT4DV2(&obj_alien);
  691. static int ang_y = 0;
  692. // generate rotation matrix around y axis
  693. Build_XYZ_Rotation_MATRIX4X4(0, ang_y++, 0 ,&mrot);
  694.          
  695. // rotate the local coords of the object
  696. Transform_OBJECT4DV2(&obj_alien, &mrot, TRANSFORM_LOCAL_TO_TRANS,1);
  697. // set position of constant shaded cube
  698. obj_alien.world_pos.x = px;
  699. obj_alien.world_pos.y = py;
  700. obj_alien.world_pos.z = pz;
  701. // perform world transform
  702. Model_To_World_OBJECT4DV2(&obj_alien, TRANSFORM_TRANS_ONLY);
  703. // insert the object into render list
  704. Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &obj_alien,0);
  705. #endif
  706. } // end Draw_Aliens
  707. //////////////////////////////////////////////////////////
  708. void Draw_Mesh_Explosions(void)
  709. {
  710. // this function draws the mesh explosions
  711. MATRIX4X4 mrot; // used to transform objects
  712. // draw the explosions, note we do NOT cull them
  713. for (int eindex = 0; eindex < NUM_EXPLOSIONS; eindex++)
  714.     {
  715.     // is the mesh explosions active
  716.     if ((explobj[eindex].state & OBJECT4DV2_STATE_ACTIVE))
  717.        {
  718.        // reset the object
  719.        Reset_OBJECT4DV2(&explobj[eindex]);
  720.        // generate rotation matrix 
  721.        Build_XYZ_Rotation_MATRIX4X4(0, 0, 0 ,&mrot);
  722.          
  723.        // rotate the local coords of the object
  724.        Transform_OBJECT4DV2(&explobj[eindex], &mrot, TRANSFORM_LOCAL_TO_TRANS,1);
  725.        // perform world transform
  726.        Model_To_World_OBJECT4DV2(&explobj[eindex], TRANSFORM_TRANS_ONLY);
  727.        // insert the object into render list
  728.        Insert_OBJECT4DV2_RENDERLIST4DV2(&rend_list, &explobj[eindex],0);
  729.    
  730.        // now animate the mesh
  731.        VECTOR4D_PTR trajectory = (VECTOR4D_PTR)explobj[eindex].ivar1;
  732.        
  733.        for (int pindex = 0; pindex < explobj[eindex].num_polys; pindex++)
  734.            {
  735.            // vertex 0
  736.            VECTOR4D_Add(&explobj[eindex].vlist_local[pindex*3 + 0].v,
  737.                         &trajectory[pindex*2+0], 
  738.                         &explobj[eindex].vlist_local[pindex*3 + 0].v);
  739.            // vertex 1
  740.            VECTOR4D_Add(&explobj[eindex].vlist_local[pindex*3 + 1].v,
  741.                         &trajectory[pindex*2 + 0], 
  742.                         &explobj[eindex].vlist_local[pindex*3 + 1].v);
  743.            // vertex 2
  744.            VECTOR4D_Add(&explobj[eindex].vlist_local[pindex*3 + 2].v,
  745.                         &trajectory[pindex*2 + 0], 
  746.                         &explobj[eindex].vlist_local[pindex*3 + 2].v);
  747.            // modulate color
  748.            //explobj[eindex].plist[pindex].color = RGB16Bit(rand()%255,0,0);
  749.            } // end for pindex
  750.       // update counter, test for terminate
  751.       if (--explobj[eindex].ivar2 < 0)
  752.          {
  753.          // reset this object
  754.          explobj[eindex].state  = OBJECT4DV2_STATE_NULL;           
  755.          // release memory of object, but only data that isn't linked to master object
  756.          // local vertex list
  757.          if (explobj[eindex].head_vlist_local)
  758.             free(explobj[eindex].head_vlist_local);
  759.          // transformed vertex list
  760.          if (explobj[eindex].head_vlist_trans)
  761.             free(explobj[eindex].head_vlist_trans);
  762.          // polygon list
  763.          if (explobj[eindex].plist)
  764.             free(explobj[eindex].plist);
  765.          // trajectory list
  766.          if ((VECTOR4D_PTR)(explobj[eindex].ivar1))
  767.             free((VECTOR4D_PTR)explobj[eindex].ivar1);
  768.          // now clear out object completely
  769.          memset((void *)&explobj[eindex], 0, sizeof(OBJECT4DV2));
  770.          } // end if 
  771.        } // end if  
  772.     } // end for eindex
  773.  
  774. } // end Draw_Mesh_Explosions
  775. //////////////////////////////////////////////////////////
  776. int Start_Mesh_Explosion(OBJECT4DV2_PTR obj,  // object to destroy
  777.                          MATRIX4X4_PTR mrot, // initial orientation of object
  778.                          int detail,          // the detail level,1 highest detail
  779.                          float rate,          // velocity of explosion shrapnel
  780.                          int lifetime)        // total lifetime of explosion
  781. {
  782. // this function "blows up" an object, it takes a pointer to the object to
  783. // be destroyed, the detail level of the polyogonal explosion, 1 is high detail, 
  784. // numbers greater than 1 are lower detail, the detail selects the polygon extraction
  785. // stepping, hence a detail of 5 would mean every 5th polygon in the original mesh
  786. // should be part of the explosion, on average no more than 10-50% of the polygons in 
  787. // the original mesh should be used for the explosion; some would be vaporized and
  788. // in a more practical sense, when an object is far, there's no need to have detail
  789. // the next parameter is the rate which is used as a general scale for the explosion
  790. // velocity, and finally lifetime which is the number of cycles to display the explosion
  791. // the function works by taking the original object then copying the core information
  792. // except for the polygon and vertex lists, the function operates by selecting polygon 
  793. // by polygon to be destroyed and then makes a copy of the polygon AND all of it's vertices,
  794. // thus the vertex coherence is completely lost, this is a necessity since each polygon must
  795. // be animated separately by the engine, thus they can't share vertices, additionally at the
  796. // end if the vertex list will be the velocity and rotation information for each polygon
  797. // this is hidden to the rest of the engine, now for the explosion, the center of the object
  798. // is used as the point of origin then a ray is drawn thru each polygon, then each polygon
  799. // is thrown at some velocity with a small rotation rate
  800. // finally the system can only have so many explosions at one time
  801. // step: 1 find an available explosion
  802. for (int eindex = 0; eindex < NUM_EXPLOSIONS; eindex++)
  803.     {
  804.     // is this explosion available?
  805.     if (explobj[eindex].state == OBJECT4DV2_STATE_NULL)
  806.        {
  807.        // copy the object, including the pointers which we will unlink shortly...
  808.        explobj[eindex]                =  *obj;
  809.        explobj[eindex].state = OBJECT4DV2_STATE_ACTIVE | OBJECT4DV2_STATE_VISIBLE;
  810.        // recompute a few things
  811.        explobj[eindex].num_polys      = obj->num_polys/detail;
  812.        explobj[eindex].num_vertices   = 3*obj->num_polys;
  813.        explobj[eindex].total_vertices = 3*obj->num_polys; // one frame only
  814.       
  815.        // unlink/re-allocate all the pointers except the texture coordinates, we can use those, they don't
  816.        // depend on vertex coherence
  817.        // allocate memory for vertex lists
  818.        if (!(explobj[eindex].vlist_local = (VERTEX4DTV1_PTR)malloc(sizeof(VERTEX4DTV1)*explobj[eindex].num_vertices)))
  819.           return(0);
  820.        // clear data
  821.        memset((void *)explobj[eindex].vlist_local,0,sizeof(VERTEX4DTV1)*explobj[eindex].num_vertices);
  822.        if (!(explobj[eindex].vlist_trans = (VERTEX4DTV1_PTR)malloc(sizeof(VERTEX4DTV1)*explobj[eindex].num_vertices)))
  823.            return(0);
  824.        // clear data
  825.        memset((void *)explobj[eindex].vlist_trans,0,sizeof(VERTEX4DTV1)*explobj[eindex].num_vertices);
  826.        // allocate memory for polygon list
  827.        if (!(explobj[eindex].plist = (POLY4DV2_PTR)malloc(sizeof(POLY4DV2)*explobj[eindex].num_polys)))
  828.           return(0);
  829.        // clear data
  830.        memset((void *)explobj[eindex].plist,0,sizeof(POLY4DV2)*explobj[eindex].num_polys);
  831.        // now, we need somewhere to store the vector trajectories of the polygons and their rotational rates
  832.        // so let's allocate an array of VECTOR4D elements to hold this information and then store it
  833.        // in ivar1, therby using ivar as a pointer, this is perfectly fine :)
  834.        // each record will consist of a velocity and a rotational rate in x,y,z, so V0,R0, V1,R1,...Vn-1, Rn-1
  835.        // allocate memory for polygon list
  836.        if (!(explobj[eindex].ivar1 = (int)malloc(sizeof(VECTOR4D)*2*explobj[eindex].num_polys)))
  837.           return(0);
  838.        // clear data
  839.        memset((void *)explobj[eindex].ivar1,0,sizeof(VECTOR4D)*2*explobj[eindex].num_polys);
  840.        // alias working pointer
  841.        VECTOR4D_PTR trajectory = (VECTOR4D_PTR)explobj[eindex].ivar1;
  842.        // these are needed to track the "head" of the vertex list for multi-frame objects
  843.        explobj[eindex].head_vlist_local = explobj[eindex].vlist_local;
  844.        explobj[eindex].head_vlist_trans = explobj[eindex].vlist_trans;
  845.        // set the lifetime in ivar2
  846.        explobj[eindex].ivar2 = lifetime;
  847.        // now comes the tricky part, loop and copy each polygon, but as we copy the polygons, we have to copy
  848.        // the vertices, and insert them, and fix up the vertice indices etc.
  849.        for (int pindex = 0; pindex < explobj[eindex].num_polys; pindex++)
  850.            {
  851.            // alright, we want to copy the (pindex*detail)th poly from the master to the (pindex)th
  852.            // polygon in explosion
  853.            explobj[eindex].plist[pindex] = obj->plist[pindex*detail];
  854.            // we need to modify, the vertex list pointer and the vertex indices themselves
  855.            explobj[eindex].plist[pindex].vlist = explobj[eindex].vlist_local;
  856.            // now comes the hard part, we need to first copy the vertices from the original mesh
  857.            // into the new vertex storage, but at the same time keep the same vertex ordering
  858.           
  859.            // vertex 0
  860.            explobj[eindex].plist[pindex].vert[0] = pindex*3 + 0;
  861.            explobj[eindex].vlist_local[pindex*3 + 0] = obj->vlist_local[ obj->plist[pindex*detail].vert[0] ];
  862.            // vertex 1
  863.            explobj[eindex].plist[pindex].vert[1] = pindex*3 + 1;
  864.            explobj[eindex].vlist_local[pindex*3 + 1] = obj->vlist_local[ obj->plist[pindex*detail].vert[1] ];
  865.            // vertex 2
  866.            explobj[eindex].plist[pindex].vert[2] = pindex*3 + 2;
  867.            explobj[eindex].vlist_local[pindex*3 + 2] = obj->vlist_local[ obj->plist[pindex*detail].vert[2] ];
  868.            // reset shading flag to constant for some of the shrapnel since they are giving off light 
  869.            if ((rand()%5) == 1)
  870.               {
  871.               SET_BIT(explobj[eindex].plist[pindex].attr, POLY4DV2_ATTR_SHADE_MODE_PURE);
  872.               RESET_BIT(explobj[eindex].plist[pindex].attr, POLY4DV2_ATTR_SHADE_MODE_GOURAUD);
  873.               RESET_BIT(explobj[eindex].plist[pindex].attr, POLY4DV2_ATTR_SHADE_MODE_FLAT);
  874.               // set color
  875.               explobj[eindex].plist[pindex].color = RGB16Bit(128+rand()%128,0,0);
  876.               } // end if
  877.            // add some random noise to trajectory
  878.            static VECTOR4D mv;
  879.        
  880.            // first compute trajectory as vector from center to vertex piercing polygon
  881.            VECTOR4D_INIT(&trajectory[pindex*2+0], &obj->vlist_local[ obj->plist[pindex*detail].vert[0] ].v);
  882.            VECTOR4D_Scale(rate, &trajectory[pindex*2+0], &trajectory[pindex*2+0]);          
  883.          
  884.            mv.x = RAND_RANGE(-10,10);
  885.            mv.y = RAND_RANGE(-10,10);
  886.            mv.z = RAND_RANGE(-10,10);
  887.            mv.w = 1;
  888.            VECTOR4D_Add(&mv, &trajectory[pindex*2+0], &trajectory[pindex*2+0]);
  889.            // now rotation rate, this is difficult to do since we don't have the center of the polygon
  890.            // maybe later...
  891.            // trajectory[pindex*2+1] = 
  892.            } // end for pindex
  893.        // now transform final mesh into position destructively
  894.        Transform_OBJECT4DV2(&explobj[eindex], mrot, TRANSFORM_LOCAL_ONLY,1);
  895.        return(1);
  896.        
  897.        } // end if found a free explosion
  898.     } // end for eindex
  899. // return failure
  900. return(0);
  901. } // end Start_Mesh_Explosion
  902. ///////////////////////////////////////////////////////////
  903. void Process_Aliens(void)
  904. {
  905. // this function moves the aliens and performs AI
  906. for (int index = 0; index < NUM_ALIENS; index++)
  907.     {
  908.     // which state is alien in
  909.     switch(aliens[index].state)
  910.           {
  911.           // is the alien dead? if so move on
  912.           case ALIEN_STATE_DEAD: break;
  913.           // is the alien alive?
  914.           case ALIEN_STATE_ALIVE:
  915.           case ALIEN_STATE_DYING:
  916.           {
  917.           // move the alien
  918.           aliens[index].pos.x+=aliens[index].vel.y;
  919.           aliens[index].pos.y+=aliens[index].vel.y;
  920.           aliens[index].pos.z+=aliens[index].vel.z;
  921.         
  922.           // rotate the alien
  923.           if ((aliens[index].ang.x+=aliens[index].rot.x) > 360)
  924.               aliens[index].ang.x = 0;
  925.           if ((aliens[index].ang.y+=aliens[index].rot.y) > 360)
  926.               aliens[index].ang.y = 0;
  927.             
  928.           if ((aliens[index].ang.z+=aliens[index].rot.z) > 360)
  929.               aliens[index].ang.z = 0;
  930.           // test if alien has past players near clipping plane
  931.           // if so remove from simulation
  932.           if (aliens[index].pos.z < cam.near_clip_z)
  933.              {
  934.              // remove from simulation
  935.              aliens[index].state = ALIEN_STATE_DEAD;
  936.              // another one gets away!
  937.              escaped++;
  938.              } // end if 
  939.           } break;
  940.    
  941.       
  942.           default: break;
  943.           } // end switch
  944.     } // end for index
  945. } // end Process_Aliens
  946. //////////////////////////////////////////////////////////
  947. void Init_Starfield(void)
  948. {
  949. // create the starfield
  950. for (int index=0; index < NUM_STARS; index++)
  951.     {
  952.     // randomly position stars in an elongated cylinder stretching from
  953.     // the viewpoint 0,0,-d to the yon clipping plane 0,0,far_z
  954.     stars[index].x = -WINDOW_WIDTH/2  + rand()%WINDOW_WIDTH;
  955.     stars[index].y = -WINDOW_HEIGHT/2 + rand()%WINDOW_HEIGHT;
  956.     stars[index].z = NEAR_Z + rand()%(FAR_Z - NEAR_Z);
  957.     // set color of stars
  958.     stars[index].color = rgb_white;
  959.     } // end for index
  960. } // end Init_Starfield
  961. //////////////////////////////////////////////////////////
  962. void Move_Starfield(void)
  963. {
  964. // move the stars
  965. int index; // looping var
  966. // the stars are technically stationary,but we are going
  967. // to move them to simulate motion of the viewpoint
  968. for (index=0; index<NUM_STARS; index++)
  969.     {
  970.     // move the next star
  971.     stars[index].z-=(player_z_vel+3*diff_level);
  972.     // test for past near clipping plane
  973.     if (stars[index].z <= NEAR_Z)
  974.         stars[index].z = FAR_Z;
  975.     } // end for index
  976. } // end Move_Starfield
  977. /////////////////////////////////////////////////////////
  978. void Draw_Starfield(UCHAR *video_buffer, int lpitch)
  979. {
  980. // draw the stars in 3D using perspective transform
  981. int index; // looping var
  982. // convert pitch to words
  983. lpitch>>=1;
  984. // draw each star
  985. for (index=0; index < NUM_STARS; index++)
  986.     {
  987.     // draw the next star
  988.     // step 1: perspective transform
  989.     float x_per = VIEW_DISTANCE*stars[index].x/stars[index].z;
  990.     float y_per = VIEW_DISTANCE*stars[index].y/stars[index].z;
  991.     
  992.     // step 2: compute screen coords
  993.     int x_screen = WINDOW_WIDTH/2  + x_per;
  994.     int y_screen = WINDOW_HEIGHT/2 - y_per;
  995.     // clip to screen coords
  996.     if (x_screen>=WINDOW_WIDTH || x_screen < 0 || 
  997.         y_screen >= WINDOW_HEIGHT || y_screen < 0)
  998.        {
  999.        // continue to next star
  1000.        continue; 
  1001.        } // end if
  1002.     else
  1003.        {
  1004.        // else render to buffer
  1005.        int i = ((float)(10000*NEAR_Z) / stars[index].z);
  1006.        if (i > 255) i = 255;
  1007.        ((USHORT *)video_buffer)[x_screen + y_screen*lpitch] = RGB16Bit(i,i,i);
  1008.        } // end else
  1009.     } // end for index
  1010. }  // Draw_Starfield
  1011. /////////////////////////////////////////////////////////////
  1012. // T3D II GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
  1013. int Game_Init(void *parms)
  1014. {
  1015. // this function is where you do all the initialization 
  1016. // for your game
  1017. int index; // looping var
  1018. // start up DirectDraw (replace the parms as you desire)
  1019. DDraw_Init(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, WINDOWED_APP);
  1020. // initialize directinput
  1021. DInput_Init();
  1022. // acquire the keyboard and mouse
  1023. DInput_Init_Keyboard();
  1024. DInput_Init_Mouse();
  1025. // add calls to acquire other directinput devices here...
  1026. // initialize directsound and directmusic
  1027. DSound_Init();
  1028. DMusic_Init();
  1029. // load in sound fx
  1030. explosion_id       = DSound_Load_WAV("exp1.wav");
  1031. laser_id           = DSound_Load_WAV("shocker.wav");
  1032. game_over_id       = DSound_Load_WAV("gameover.wav");
  1033. ambient_systems_id = DSound_Load_WAV("stationthrob2.wav");
  1034. // initialize directmusic
  1035. DMusic_Init();
  1036. // load main music track
  1037. main_track_id = DMusic_Load_MIDI("midifile2.mid");
  1038. // hide the mouse
  1039. //if (!WINDOWED_APP)
  1040.     ShowCursor(FALSE);
  1041. // seed random number generator
  1042. srand(Start_Clock()); 
  1043. Open_Error_File("ERROR.TXT");
  1044. // initialize math engine
  1045. Build_Sin_Cos_Tables();
  1046. // initialize the camera with 90 FOV, normalized coordinates
  1047. Init_CAM4DV1(&cam,      // the camera object
  1048.              CAM_MODEL_EULER, // the euler model
  1049.              &cam_pos,  // initial camera position
  1050.              &cam_dir,  // initial camera angles
  1051.              &cam_target,    // no target
  1052.              150.0,          // near and far clipping planes
  1053.              20000.0,
  1054.              120.0,      // field of view in degrees
  1055.              WINDOW_WIDTH,   // size of final screen viewport
  1056.              WINDOW_HEIGHT);
  1057. // load flat shaded cube
  1058. VECTOR4D_INITXYZ(&vscale,18.00,18.00,18.00);
  1059. Load_OBJECT4DV2_COB(&obj_alien,"tie04.cob",  
  1060.                         &vscale, &vpos, &vrot, VERTEX_FLAGS_SWAP_YZ | VERTEX_FLAGS_SWAP_XZ |
  1061.                                                VERTEX_FLAGS_INVERT_WINDING_ORDER |
  1062.                                                VERTEX_FLAGS_TRANSFORM_LOCAL | 
  1063.                                                VERTEX_FLAGS_TRANSFORM_LOCAL_WORLD );
  1064. // create system colors
  1065. rgb_green = RGB16Bit(0,255,0);
  1066. rgb_white = RGB16Bit(255,255,255);
  1067. rgb_blue  = RGB16Bit(0,0,255);
  1068. rgb_red   = RGB16Bit(255,0,0);
  1069. // set up lights
  1070. Reset_Lights_LIGHTV1();
  1071. // create some working colors
  1072. white.rgba      = _RGBA32BIT(255,255,255,0);
  1073. light_gray.rgba = _RGBA32BIT(100,100,100,0);
  1074. gray.rgba       = _RGBA32BIT(50,50,50,0);
  1075. black.rgba      = _RGBA32BIT(0,0,0,0);
  1076. red.rgba        = _RGBA32BIT(255,0,0,0);
  1077. green.rgba      = _RGBA32BIT(0,255,0,0);
  1078. blue.rgba       = _RGBA32BIT(0,0,255,0);
  1079. // ambient light
  1080. Init_Light_LIGHTV1(AMBIENT_LIGHT_INDEX,   
  1081.                    LIGHTV1_STATE_ON,      // turn the light on
  1082.                    LIGHTV1_ATTR_AMBIENT,  // ambient light type
  1083.                    gray, black, black,    // color for ambient term only
  1084.                    NULL, NULL,            // no need for pos or dir
  1085.                    0,0,0,                 // no need for attenuation
  1086.                    0,0,0);                // spotlight info NA
  1087. VECTOR4D dlight_dir = {-1,-1,1,0};
  1088. // directional sun light
  1089. Init_Light_LIGHTV1(INFINITE_LIGHT_INDEX,  
  1090.                    LIGHTV1_STATE_ON,      // turn the light on
  1091.                    LIGHTV1_ATTR_INFINITE, // infinite light type
  1092.                    black, light_gray, black,    // color for diffuse term only
  1093.                    NULL, &dlight_dir,     // need direction only
  1094.                    0,0,0,                 // no need for attenuation
  1095.                    0,0,0);                // spotlight info NA
  1096. // the red giant
  1097. VECTOR4D plight_pos = {-2700,-1600,8000,0};
  1098. // point light
  1099. Init_Light_LIGHTV1(POINT_LIGHT_INDEX,
  1100.                    LIGHTV1_STATE_ON,      // turn the light on
  1101.                    LIGHTV1_ATTR_POINT,    // pointlight type
  1102.                    black, red, black,     // color for diffuse term only
  1103.                    &plight_pos, NULL,     // need pos only
  1104.                    0,.001,0,              // linear attenuation only
  1105.                    0,0,1);                // spotlight info NA
  1106. // the weapons blast green glow point light from front of ship
  1107. VECTOR4D plight2_pos = {0,0,200,0};
  1108. // point light2
  1109. Init_Light_LIGHTV1(POINT_LIGHT2_INDEX,
  1110.                    LIGHTV1_STATE_OFF,       // turn the light on
  1111.                    LIGHTV1_ATTR_POINT,     //  pointlight
  1112.                    black, green, black,      // color for diffuse term only
  1113.                    &plight2_pos, NULL, // need pos only
  1114.                    0,.0005,0,                 // linear attenuation only
  1115.                    0,0,1);    
  1116. // create lookup for lighting engine
  1117. RGB_16_8_IndexedRGB_Table_Builder(DD_PIXEL_FORMAT565,  // format we want to build table for
  1118.                                   palette,             // source palette
  1119.                                   rgblookup);          // lookup table
  1120. // load in the cockpit image
  1121. Load_Bitmap_File(&bitmap16bit, "cockpit03.BMP");
  1122. Create_BOB(&cockpit, 0,0,800,600,2, BOB_ATTR_VISIBLE | BOB_ATTR_SINGLE_FRAME, DDSCAPS_SYSTEMMEMORY, 0, 16); 
  1123. Load_Frame_BOB16(&cockpit, &bitmap16bit,0,0,0,BITMAP_EXTRACT_MODE_ABS);
  1124. Unload_Bitmap_File(&bitmap16bit);
  1125. Load_Bitmap_File(&bitmap16bit, "cockpit03b.BMP");
  1126. Load_Frame_BOB16(&cockpit, &bitmap16bit,1,0,0,BITMAP_EXTRACT_MODE_ABS);
  1127. Unload_Bitmap_File(&bitmap16bit);
  1128. // load in the background starscape(s)
  1129. Create_BOB(&starscape, 0,0,800,600,3, BOB_ATTR_VISIBLE | BOB_ATTR_SINGLE_FRAME, DDSCAPS_SYSTEMMEMORY, 0, 16); 
  1130. Load_Bitmap_File(&bitmap16bit, "nebblue01.bmp");
  1131. Load_Frame_BOB16(&starscape, &bitmap16bit,0,0,0,BITMAP_EXTRACT_MODE_ABS);
  1132. Load_Bitmap_File(&bitmap16bit, "nebred01.bmp");
  1133. Load_Frame_BOB16(&starscape, &bitmap16bit,1,0,0,BITMAP_EXTRACT_MODE_ABS);
  1134. Load_Bitmap_File(&bitmap16bit, "nebgreen03.bmp");
  1135. Load_Frame_BOB16(&starscape, &bitmap16bit,2,0,0,BITMAP_EXTRACT_MODE_ABS);
  1136. Unload_Bitmap_File(&bitmap16bit);
  1137. // load the crosshair image
  1138. Load_Bitmap_File(&bitmap16bit, "crosshair01.bmp");
  1139. Create_BOB(&crosshair, 0,0,CROSS_WIDTH, CROSS_HEIGHT,1, BOB_ATTR_VISIBLE | BOB_ATTR_SINGLE_FRAME, DDSCAPS_SYSTEMMEMORY, 0, 16); 
  1140. Load_Frame_BOB16(&crosshair, &bitmap16bit,0,0,0,BITMAP_EXTRACT_MODE_ABS);
  1141. Unload_Bitmap_File(&bitmap16bit); 
  1142. // set single precission
  1143. //_control87( _PC_24, MCW_PC );
  1144. return(1);
  1145. } // end Game_Init 
  1146.  
  1147. ///////////////////////////////////////////////////////////
  1148. int Game_Shutdown(void *parms)
  1149. {
  1150. // this function is where you shutdown your game and
  1151. // release all resources that you allocated
  1152. // shut everything down
  1153. // release all your resources created for the game here....
  1154. // now directsound
  1155. DSound_Stop_All_Sounds();
  1156. DSound_Delete_All_Sounds();
  1157. DSound_Shutdown();
  1158. // directmusic
  1159. DMusic_Delete_All_MIDI();
  1160. DMusic_Shutdown();
  1161. // shut down directinput
  1162. DInput_Release_Keyboard();
  1163. // shutdown directinput
  1164. DInput_Shutdown();
  1165. // shutdown directdraw last
  1166. DDraw_Shutdown();
  1167. Close_Error_File();
  1168. // return success
  1169. return(1);
  1170. } // end Game_Shutdown
  1171. //////////////////////////////////////////////////////////
  1172. int Game_Main(void *parms)
  1173. {
  1174. // this is the workhorse of your game it will be called
  1175. // continuously in real-time this is like main() in C
  1176. // all the calls for you game go here!
  1177. static MATRIX4X4 mrot;   // general rotation matrix
  1178. // these are used to create a circling camera
  1179. static float view_angle = 0; 
  1180. static float camera_distance = 6000;
  1181. static VECTOR4D pos = {0,0,0,0};
  1182. static float tank_speed;
  1183. static float turning = 0;
  1184. // state variables for different rendering modes and help
  1185. static int wireframe_mode = 0;
  1186. static int backface_mode  = 1;
  1187. static int lighting_mode  = 1;
  1188. static int zsort_mode     = 1;
  1189. char work_string[256]; // temp string
  1190. int index; // looping var
  1191. // what state is game in?
  1192. switch(game_state)
  1193.       {
  1194.       case GAME_STATE_INIT:
  1195.       {
  1196.       // load the font
  1197.       Load_Bitmap_Font("tech_char_set_01.bmp", &tech_font);
  1198.      
  1199.       // transition to un state
  1200.       game_state = GAME_STATE_RESTART;
  1201.       } break;
  1202.       case GAME_STATE_RESTART:
  1203.       {
  1204.       // start music
  1205.       DMusic_Play(main_track_id);
  1206.       DSound_Play(ambient_systems_id, DSBPLAY_LOOPING);
  1207.       // initialize the stars
  1208.       Init_Starfield();      
  1209.       // initialize all the aliens
  1210.       Init_Aliens();
  1211.       // reset all vars
  1212.       player_z_vel = 4; // virtual speed of viewpoint/ship
  1213.       cross_x = CROSS_START_X; // cross hairs
  1214.       cross_y = CROSS_START_Y;
  1215.       cross_x_screen  = CROSS_START_X;   // used for cross hair
  1216.       cross_y_screen  = CROSS_START_Y; 
  1217.       target_x_screen = CROSS_START_X;   // used for targeter
  1218.       target_y_screen = CROSS_START_Y;
  1219.       escaped       = 0;   // tracks number of missed ships
  1220.       hits          = 0;   // tracks number of hits
  1221.       score         = 0;   // take a guess :)
  1222.       weapon_energy = 100; // weapon energy
  1223.       weapon_active = 0;   // weapons are off
  1224.       
  1225.       game_state_count1    = 0;    // general counters
  1226.       game_state_count2    = 0;
  1227.       restart_state        = 0;    // state when game is restarting
  1228.       restart_state_count1 = 0;    // general counter
  1229.       // difficulty
  1230.       diff_level           = 1;
  1231.       // transition to run state
  1232.       game_state = GAME_STATE_RUN;
  1233.       } break;
  1234.       case GAME_STATE_RUN:
  1235.       case GAME_STATE_OVER: // keep running sim, but kill diff_level, and player input
  1236.       {
  1237.       // start the clock
  1238.       Start_Clock();
  1239.       // clear the drawing surface 
  1240.       //DDraw_Fill_Surface(lpddsback, 0);
  1241.       // blt to destination surface
  1242.       lpddsback->Blt(NULL, starscape.images[starscape.curr_frame], NULL, DDBLT_WAIT, NULL); 
  1243.       // reset the render list
  1244.       Reset_RENDERLIST4DV2(&rend_list);
  1245.       // read keyboard and other devices here
  1246.       DInput_Read_Keyboard();
  1247.       DInput_Read_Mouse();
  1248.       // game logic begins here...
  1249. #ifdef DEBUG_ON      
  1250.       if (keyboard_state[DIK_UP])
  1251.          {
  1252.          py+=10;        
  1253.          } // end if
  1254.  
  1255.       if (keyboard_state[DIK_DOWN])
  1256.          {
  1257.          py-=10;     
  1258.          } // end if
  1259.       if (keyboard_state[DIK_RIGHT])
  1260.          {
  1261.          px+=10;
  1262.          } // end if
  1263.       if (keyboard_state[DIK_LEFT])
  1264.          {
  1265.          px-=10;
  1266.          } // end if
  1267.       if (keyboard_state[DIK_1])
  1268.          {
  1269.          pz+=20;
  1270.          } // end if
  1271.       if (keyboard_state[DIK_2])
  1272.          {
  1273.          pz-=20;
  1274.          } // end if
  1275. #endif
  1276.       // modes and lights
  1277.       // wireframe mode
  1278.       if (keyboard_state[DIK_W])
  1279.         {
  1280.         // toggle wireframe mode
  1281.         if (++wireframe_mode > 1)
  1282.            wireframe_mode = 0;
  1283.            Wait_Clock(100); // wait, so keyboard doesn't bounce
  1284.         } // end if
  1285.       // change nebula
  1286.       if (keyboard_state[DIK_N])
  1287.         {
  1288.         if (++starscape.curr_frame >= starscape.num_frames)
  1289.            starscape.curr_frame = 0;
  1290.         Wait_Clock(100); // wait, so keyboard doesn't bounce
  1291.         } // end if
  1292.      // backface removal
  1293.      if (keyboard_state[DIK_B])
  1294.         {
  1295.         // toggle backface removal
  1296.         backface_mode = -backface_mode;
  1297.         Wait_Clock(100); // wait, so keyboard doesn't bounce
  1298.         } // end if
  1299.      // lighting
  1300.      if (keyboard_state[DIK_L])
  1301.         {
  1302.         // toggle lighting engine completely
  1303.         lighting_mode = -lighting_mode;
  1304.         Wait_Clock(100); // wait, so keyboard doesn't bounce
  1305.         } // end if
  1306.      // toggle ambient light
  1307.      if (keyboard_state[DIK_A])
  1308.         {
  1309.         // toggle ambient light
  1310.         if (lights[AMBIENT_LIGHT_INDEX].state == LIGHTV1_STATE_ON)
  1311.            lights[AMBIENT_LIGHT_INDEX].state = LIGHTV1_STATE_OFF;
  1312.         else
  1313.            lights[AMBIENT_LIGHT_INDEX].state = LIGHTV1_STATE_ON;
  1314.         Wait_Clock(100); // wait, so keyboard doesn't bounce
  1315.         } // end if
  1316.       // toggle infinite light
  1317.       if (keyboard_state[DIK_I])
  1318.          {
  1319.          // toggle ambient light
  1320.          if (lights[INFINITE_LIGHT_INDEX].state == LIGHTV1_STATE_ON)
  1321.             lights[INFINITE_LIGHT_INDEX].state = LIGHTV1_STATE_OFF;
  1322.          else
  1323.             lights[INFINITE_LIGHT_INDEX].state = LIGHTV1_STATE_ON;
  1324.          Wait_Clock(100); // wait, so keyboard doesn't bounce
  1325.           } // end if
  1326.       // toggle point light
  1327.       if (keyboard_state[DIK_P])
  1328.          {
  1329.          // toggle point light
  1330.          if (lights[POINT_LIGHT_INDEX].state == LIGHTV1_STATE_ON)
  1331.             lights[POINT_LIGHT_INDEX].state = LIGHTV1_STATE_OFF;
  1332.         else
  1333.             lights[POINT_LIGHT_INDEX].state = LIGHTV1_STATE_ON;
  1334.          Wait_Clock(100); // wait, so keyboard doesn't bounce
  1335.          } // end if
  1336.        // toggle spot light
  1337.        if (keyboard_state[DIK_S])
  1338.           {
  1339.           // toggle spot light
  1340.           if (lights[SPOT_LIGHT2_INDEX].state == LIGHTV1_STATE_ON)
  1341.              lights[SPOT_LIGHT2_INDEX].state = LIGHTV1_STATE_OFF;
  1342.           else
  1343.              lights[SPOT_LIGHT2_INDEX].state = LIGHTV1_STATE_ON;
  1344.           Wait_Clock(100); // wait, so keyboard doesn't bounce
  1345.           } // end if
  1346.        // z-sorting
  1347.        if (keyboard_state[DIK_Z])
  1348.           {
  1349.           // toggle z sorting
  1350.           zsort_mode = -zsort_mode;
  1351.           Wait_Clock(100); // wait, so keyboard doesn't bounce
  1352.           } // end if
  1353.        // track cross hair
  1354.        cross_x+=(mouse_state.lX);
  1355.        cross_y-=(mouse_state.lY); 
  1356.        // check bounds (x,y) are in 2D space coords, not screen coords
  1357.        if (cross_x >= (WINDOW_WIDTH/2-CROSS_WIDTH/2))
  1358.            cross_x = (WINDOW_WIDTH/2-CROSS_WIDTH/2) - 1;
  1359.        else
  1360.        if (cross_x <= -(WINDOW_WIDTH/2-CROSS_WIDTH/2))
  1361.            cross_x = -(WINDOW_WIDTH/2-CROSS_WIDTH/2) + 1;
  1362.        if (cross_y >= (WINDOW_HEIGHT/2-CROSS_HEIGHT/2))
  1363.            cross_y = (WINDOW_HEIGHT/2-CROSS_HEIGHT/2) - 1;
  1364.        else
  1365.        if (cross_y <= -(WINDOW_HEIGHT/2-CROSS_HEIGHT/2))
  1366.            cross_y = -(WINDOW_HEIGHT/2-CROSS_HEIGHT/2) + 1;
  1367.        // player is done moving create camera matrix //////////////////////////
  1368.        Build_CAM4DV1_Matrix_Euler(&cam, CAM_ROT_SEQ_ZYX);
  1369.        // perform all non-player game AI and motion here /////////////////////
  1370.        // move starfield
  1371.        Move_Starfield();
  1372.        // move aliens
  1373.        Process_Aliens();
  1374.        // update difficulty of game
  1375.        if ((diff_level+=DIFF_RATE) > DIFF_PMAX)
  1376.            diff_level = DIFF_PMAX;
  1377.        // start a random alien as a function of game difficulty
  1378.        if ( (rand()%(DIFF_PMAX - (int)diff_level+2)) == 1)
  1379.           Start_Alien();
  1380.        
  1381.        // perform animation and transforms on lights //////////////////////////
  1382.        // lock the back buffer
  1383.        DDraw_Lock_Back_Surface();
  1384.        // draw all 3D entities
  1385.        Draw_Aliens();
  1386.        // draw mesh explosions
  1387.        Draw_Mesh_Explosions();
  1388.     
  1389.        // entire into final 3D pipeline /////////////////////////////////////// 
  1390.    
  1391.        // remove backfaces
  1392.        if (backface_mode==1)
  1393.           Remove_Backfaces_RENDERLIST4DV2(&rend_list, &cam);
  1394.        // light scene all at once 
  1395.        if (lighting_mode==1)
  1396.           Light_RENDERLIST4DV2_World16(&rend_list, &cam, lights, 4);
  1397.        // apply world to camera transform
  1398.        World_To_Camera_RENDERLIST4DV2(&rend_list, &cam);
  1399.        // sort the polygon list (hurry up!)
  1400.        if (zsort_mode == 1)
  1401.           Sort_RENDERLIST4DV2(&rend_list,  SORT_POLYLIST_AVGZ);
  1402.        // apply camera to perspective transformation
  1403.        Camera_To_Perspective_RENDERLIST4DV2(&rend_list, &cam);
  1404.        // apply screen transform
  1405.        Perspective_To_Screen_RENDERLIST4DV2(&rend_list, &cam);
  1406.        // draw the starfield now
  1407.        Draw_Starfield(back_buffer, back_lpitch);
  1408.        // reset number of polys rendered
  1409.        debug_polys_rendered_per_frame = 0;
  1410.        // render the list
  1411.        if (wireframe_mode  == 0)
  1412.           {
  1413.           Draw_RENDERLIST4DV2_Solid16(&rend_list, back_buffer, back_lpitch);
  1414.           }
  1415.        else
  1416.        if (wireframe_mode  == 1)
  1417.           {
  1418.           Draw_RENDERLIST4DV2_Wire16(&rend_list, back_buffer, back_lpitch);
  1419.           } // end if
  1420.        // draw energy bindings
  1421.        Render_Energy_Bindings(energy_bindings, 1, 8, 16, RGB16Bit(0,255,0), back_buffer, back_lpitch);
  1422.        // fire the weapon
  1423.        if (game_state == GAME_STATE_RUN && mouse_state.rgbButtons[0] && weapon_energy > 20)
  1424.           {
  1425.           // set endpoints of energy bolts
  1426.           weapon_bursts[1].x = cross_x_screen + RAND_RANGE(-4,4);
  1427.           weapon_bursts[1].y = cross_y_screen + RAND_RANGE(-4,4);
  1428.           weapon_bursts[3].x = cross_x_screen + RAND_RANGE(-4,4);
  1429.           weapon_bursts[3].y = cross_y_screen + RAND_RANGE(-4,4);
  1430.           // draw the weapons firing
  1431.           Render_Weapon_Bursts(weapon_bursts, 2, 8, 16, RGB16Bit(0,255,0), back_buffer, back_lpitch);
  1432.           // decrease weapon energy
  1433.           if ((weapon_energy-=5) < 0)
  1434.              weapon_energy = 0;
  1435.           // make sound
  1436.           DSound_Play(laser_id);
  1437.           // energize weapons
  1438.           weapon_active  = 1; 
  1439.           // turn the lights on!
  1440.           lights[POINT_LIGHT2_INDEX].state = LIGHTV1_STATE_ON;
  1441.           cockpit.curr_frame = 1;
  1442.           } // end if
  1443.         else
  1444.            {
  1445.            weapon_active  = 0; 
  1446.            // turn the lights off!
  1447.            lights[POINT_LIGHT2_INDEX].state = LIGHTV1_STATE_OFF;
  1448.            cockpit.curr_frame = 0;
  1449.            } // end else
  1450.           if ((weapon_energy+=1) > 100)
  1451.              weapon_energy = 100;
  1452.        // draw any overlays ///////////////////////////////////////////////////
  1453.        // unlock the back buffer
  1454.        DDraw_Unlock_Back_Surface();
  1455.        // draw cockpit
  1456.        Draw_BOB16(&cockpit, lpddsback);
  1457.        // draw information
  1458.        sprintf(work_string, "SCORE:%d", score);  
  1459.        Draw_Bitmap_Font_String(&tech_font, TPOS_SCORE_X,TPOS_SCORE_Y, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1460.        sprintf(work_string, "HITS:%d", hits);  
  1461.        Draw_Bitmap_Font_String(&tech_font, TPOS_HITS_X,TPOS_HITS_Y, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1462.        sprintf(work_string, "ESCAPED:%d", escaped);  
  1463.        Draw_Bitmap_Font_String(&tech_font, TPOS_ESCAPED_X,TPOS_ESCAPED_Y, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1464.        sprintf(work_string, "LEVEL:%2.4f", diff_level);  
  1465.        Draw_Bitmap_Font_String(&tech_font, TPOS_GLEVEL_X,TPOS_GLEVEL_Y, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1466.        sprintf(work_string, "VEL:%3.2fK/S", player_z_vel+diff_level);  
  1467.        Draw_Bitmap_Font_String(&tech_font, TPOS_SPEED_X,TPOS_SPEED_Y, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1468.        sprintf(work_string, "NRG:%d", weapon_energy);  
  1469.        Draw_Bitmap_Font_String(&tech_font, TPOS_ENERGY_X,TPOS_ENERGY_Y, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1470.        
  1471.        // process game over stuff
  1472.        if (game_state == GAME_STATE_OVER)
  1473.           {
  1474.           // do rendering
  1475.           sprintf(work_string, "GAME OVER");  
  1476.           Draw_Bitmap_Font_String(&tech_font, TPOS_GINFO_X-(FONT_HPITCH/2)*strlen(work_string),TPOS_GINFO_Y, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1477.  
  1478.           sprintf(work_string, "PRESS ENTER TO PLAY AGAIN");  
  1479.           Draw_Bitmap_Font_String(&tech_font, TPOS_GINFO_X-(FONT_HPITCH/2)*strlen(work_string),TPOS_GINFO_Y + 2*FONT_VPITCH, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1480.           // logic...
  1481.           if (keyboard_state[DIK_RETURN])
  1482.              {
  1483.              game_state = GAME_STATE_RESTART;
  1484.              } // end if
  1485.           } // end if
  1486. #ifdef DEBUG_ON
  1487.        // display diagnostics
  1488.        sprintf(work_string,"LE[%s]:AMB=%d,INFL=%d,PNTL=%d,SPTL=%d,ZS[%s],BFRM[%s], WF=%s", 
  1489.                                                                                  ((lighting_mode == 1) ? "ON" : "OFF"),
  1490.                                                                                  lights[AMBIENT_LIGHT_INDEX].state,
  1491.                                                                                  lights[INFINITE_LIGHT_INDEX].state, 
  1492.                                                                                  lights[POINT_LIGHT_INDEX].state,
  1493.                                                                                  lights[SPOT_LIGHT2_INDEX].state,
  1494.                                                                                  ((zsort_mode == 1) ? "ON" : "OFF"),
  1495.                                                                                  ((backface_mode == 1) ? "ON" : "OFF"),
  1496.                                                                                  ((wireframe_mode == 1) ? "ON" : "OFF"));
  1497.        Draw_Bitmap_Font_String(&tech_font, 4,WINDOW_HEIGHT-16, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1498. #endif
  1499.        // draw startup information for first few seconds of restart
  1500.        if (restart_state == 0)
  1501.           {
  1502.           sprintf(work_string, "GET READY!");  
  1503.           Draw_Bitmap_Font_String(&tech_font, TPOS_GINFO_X-(FONT_HPITCH/2)*strlen(work_string),TPOS_GINFO_Y, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1504.           // update counter
  1505.           if (++restart_state_count1 > 100)
  1506.              restart_state = 1; 
  1507.           } // end if
  1508.  
  1509. #ifdef DEBUG_ON
  1510.        sprintf(work_string, "p=[%d, %d, %d]", px,py,pz);  
  1511.        Draw_Bitmap_Font_String(&tech_font, TPOS_GINFO_X-(FONT_HPITCH/2)*strlen(work_string),TPOS_GINFO_Y+24, work_string, FONT_HPITCH, FONT_VPITCH, lpddsback);
  1512. #endif
  1513.        if (game_state == GAME_STATE_RUN)
  1514.        {
  1515.        // draw cross on top of everything, it's holographic :)
  1516.        cross_x_screen = WINDOW_WIDTH/2  + cross_x;
  1517.        cross_y_screen = WINDOW_HEIGHT/2 - cross_y;
  1518.      
  1519.        crosshair.x = cross_x_screen - CROSS_WIDTH/2+1;
  1520.        crosshair.y = cross_y_screen - CROSS_HEIGHT/2;
  1521.        Draw_BOB16(&crosshair, lpddsback);
  1522.        } // end if
  1523.        // flip the surfaces
  1524.        DDraw_Flip();
  1525.        // sync to 30ish fps
  1526.        Wait_Clock(30);
  1527.        // check if player has lost?
  1528.        if (escaped == MAX_MISSES_GAME_OVER)
  1529.           {
  1530.           game_state = GAME_STATE_OVER;
  1531.           DSound_Play(game_over_id);
  1532.           escaped++;
  1533.           } // end if
  1534.        // check of user is trying to exit
  1535.        if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE])
  1536.           {
  1537.           PostMessage(main_window_handle, WM_DESTROY,0,0);
  1538.           game_state = GAME_STATE_EXIT;
  1539.           } // end if      
  1540.       } break;
  1541.       case GAME_STATE_DEMO:
  1542.       {
  1543.       } break;
  1544.       case GAME_STATE_EXIT:
  1545.       {
  1546.       } break;
  1547.       default: break;
  1548.       } // end switch game state
  1549. // return success
  1550. return(1);
  1551.  
  1552. } // end Game_Main
  1553. //////////////////////////////////////////////////////////