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

游戏

开发平台:

Visual C++

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