home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Demos / Duel / gameproc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  55.7 KB  |  1,900 lines

  1. //-----------------------------------------------------------------------------
  2. // File: GameProc.cpp
  3. //
  4. // Desc: Game processing routines
  5. //
  6. // Copyright (C) 1995-2001 Microsoft Corporation. All Rights Reserved.
  7. //-----------------------------------------------------------------------------
  8. #include <math.h>
  9. #include "duel.h"
  10. #include "gameproc.h"
  11. #include "gfx.h"
  12. #include "DPUtil.h"
  13. #include "diutil.h"
  14. #include "dsutil.h"
  15. #include "lobby.h"
  16. #include "dsound.h"
  17. #include "stdio.h"
  18.  
  19.  
  20. //-----------------------------------------------------------------------------
  21. // Globals
  22. //-----------------------------------------------------------------------------
  23. extern DWORD               g_dwKeys;
  24. extern LPDIRECTDRAWSURFACE g_pddsShip[NUM_SHIP_TYPES];
  25. extern BOOL                g_bShowFrameCount;
  26. extern LPDIRECTDRAWSURFACE g_pddsNumbers;
  27. extern BOOL                g_bHostPlayer;
  28. extern BOOL                g_bIsActive;
  29. extern DPSESSIONDESC2*     g_pdpsd;
  30. extern HWND                g_hwndMain;
  31. extern HINSTANCE           g_hInst;
  32. extern BOOL                g_bReliable;
  33. extern BOOL                g_bAsync;
  34. extern BOOL                g_bUseProtocol;
  35.  
  36. FRAG        g_Frags[64];                    // ship framents
  37. BLOCKS      g_Blocks;                   // field layout
  38. VOID*       g_pvReceiveBuffer = NULL;   // buffer to store received messages
  39. DWORD       g_dwReceiveBufferSize = 0;  // size of buffer
  40. DPID        g_LocalPlayerDPID;                    // our player id
  41. BOOL        g_bHaveHostInit;                // do we need to do host initializaton
  42. int         g_nProgramState;            // current state of the game
  43. DWORD       g_dwFrameCount;             // used for fps calc
  44. DWORD       g_dwFramesLast;             // ..
  45. DWORD       g_dwFrameTime;              // ..
  46. BOOL        g_bUpdate;                   // TRUE if player data needs to be updated
  47. BOOL        g_bSessionLost;              // did we get disconnected ?
  48. HOSTMSG     g_HostMsg;                   // message buffer
  49. BLOCKHITMSG g_BlockHitMsg;               // ..
  50. SHIPHITMSG  g_ShipHitMsg;                // ..
  51. ADDBLOCKMSG g_AddBlockMsg;               // ..
  52. CONTROLMSG  g_ControlMsg;                // .. 
  53. SYNCMSG     g_SyncMsg;                   // ..
  54.  
  55. SoundObject* g_pBulletFiringSound = NULL;
  56. SoundObject* g_pShipExplodeSound  = NULL;
  57. SoundObject* g_pShipEngineSound   = NULL;
  58. SoundObject* g_pShipStartSound  = NULL;
  59. SoundObject* g_pShipStopSound   = NULL;
  60. SoundObject* g_pShipBounceSound   = NULL;
  61. SoundObject* g_pBlockExplodeSound = NULL;
  62.  
  63.  
  64. // Used to determine new joiner's ship type
  65. static int g_ShipTypesUsed[NUM_SHIP_TYPES];
  66.  
  67.  
  68.  
  69.  
  70. //-----------------------------------------------------------------------------
  71. // Name: InitMessageBuffers()
  72. // Desc: Sets up buffes used for sending different types of messages
  73. //-----------------------------------------------------------------------------
  74. VOID InitMessageBuffers()
  75. {
  76.     g_HostMsg.byType     = MSG_HOST;
  77.     g_BlockHitMsg.byType = MSG_BLOCKHIT;
  78.     g_ShipHitMsg.byType  = MSG_SHIPHIT;    
  79.     g_AddBlockMsg.byType = MSG_ADDBLOCK;
  80.     g_ControlMsg.byType  = MSG_CONTROL; 
  81.     g_SyncMsg.byType     = MSG_SYNC;
  82. }
  83.  
  84.  
  85.  
  86.  
  87. //-----------------------------------------------------------------------------
  88. // Name: LaunchGame()
  89. // Desc: Sets up the game layout and launches
  90. //-----------------------------------------------------------------------------
  91. VOID LaunchGame()
  92. {
  93.     HRESULT hr;
  94.  
  95.     // initialize message buffers and other module globals
  96.     InitMessageBuffers();
  97.     g_bSessionLost = FALSE;
  98.  
  99.     // get current session description (g_pdpsd is initialized in here)
  100.     hr = DPUtil_GetSessionDesc();
  101.     if (FAILED(hr) || (!g_pdpsd))
  102.     {
  103.         ShowError(IDS_DPLAY_ERROR_GSD);
  104.         ExitGame();
  105.         return;
  106.     }
  107.  
  108.     // Is this session using the DirectPlay Protocol?
  109.     g_bUseProtocol = (g_pdpsd->dwFlags & DPSESSION_DIRECTPLAYPROTOCOL) != 0;
  110.  
  111.     // update window title
  112.     UpdateTitle();
  113.  
  114.     // initialize random number seed
  115.     srand((int)GetTickCount());
  116.  
  117.     // clear front buffer before changing palette
  118.     EraseScreen();
  119.     FlipScreen();
  120.  
  121.     // Begin collecting input
  122.     DIUtil_ReacquireInputDevices();
  123.  
  124.     // init the ship type tracking
  125.     ZeroMemory( g_ShipTypesUsed, sizeof(g_ShipTypesUsed) );
  126.  
  127.     // initialize us
  128.     hr = InitOurShip();
  129.     if( FAILED(hr) )
  130.     {
  131.         ExitGame();
  132.         return;
  133.     }
  134.  
  135.     // get the field layout
  136.     if( g_bHostPlayer )
  137.     {
  138.         // initialize field (done only by host)
  139.        InitField();
  140.  
  141.         // we have host initialization
  142.         g_bHaveHostInit = TRUE;
  143.  
  144.         // start updating screen
  145.         g_bIsActive = TRUE;
  146.     }
  147.     else
  148.     {
  149.         // get it from host, if we are joining
  150.         g_bHaveHostInit = FALSE;
  151.     }
  152.  
  153.     return;
  154. }
  155.  
  156.  
  157.  
  158.  
  159. //-----------------------------------------------------------------------------
  160. // Name: ExitGame()
  161. // Desc: Game termination code
  162. //-----------------------------------------------------------------------------
  163. VOID ExitGame()
  164. {
  165.     // shut down app
  166.     PostMessage( g_hwndMain, WM_CLOSE, 0, 0 );
  167. }
  168.  
  169.  
  170.  
  171.  
  172. //-----------------------------------------------------------------------------
  173. // Name: InitOurShip()
  174. // Desc: Initializes our ship's initial attributes
  175. //-----------------------------------------------------------------------------
  176. HRESULT InitOurShip()
  177. {
  178.     SHIP    ship;
  179.     HRESULT hr;
  180.  
  181.     // Wipe out everything
  182.     ZeroMemory( &ship, sizeof(ship) );
  183.  
  184.     // Calculate ship type based on the number of players in the game
  185.     // we cycle through four ships (Y,R,G,B) for now.
  186.     // This old algorithm's computation will be overridden by HOST_MSG 
  187.     ship.byType = (BYTE) ((g_pdpsd->dwCurrentPlayers-1) % NUM_SHIP_TYPES);
  188.     g_ShipTypesUsed[ship.byType] = 1;   // our color
  189.  
  190.     ship.dPosX   = randInt( 0, MAX_SHIP_X );
  191.     ship.dPosY   = randInt( 0, MAX_SHIP_Y );
  192.     ship.cFrame  = (char)randInt( 0, MAX_SHIP_FRAME );
  193.     ship.bEnable = TRUE;
  194.  
  195.     // Set our local data
  196.     hr = DPUtil_SetPlayerLocalData( g_LocalPlayerDPID, &ship, sizeof(ship) );
  197.     if( FAILED(hr) )
  198.     {
  199.         ShowError(IDS_DPLAY_ERROR_SPLD);
  200.         return hr;
  201.     }
  202.  
  203.     // No ship fragments
  204.     for( int i=0; i<64; i++ )
  205.         g_Frags[i].valid = FALSE;
  206.  
  207.     return S_OK;
  208. }
  209.  
  210.  
  211.  
  212.  
  213. //-----------------------------------------------------------------------------
  214. // Name: SetPlayerLocalSoundDataCB()
  215. // Desc: Initializes and registers a player's local SOUND data ONLY.
  216. //-----------------------------------------------------------------------------
  217. BOOL WINAPI SetPlayerLocalSoundDataCB( DPID dpId, DWORD dwPlayerType,
  218.                                        LPCDPNAME lpName, DWORD dwFlags,
  219.                                        VOID* lpContext )
  220. {
  221.     SHIP ship;
  222.     DWORD dwSize = sizeof(ship);
  223.     HRESULT hr;
  224.  
  225.     DPUtil_GetPlayerLocalData(dpId, &ship, &dwSize); 
  226.  
  227.     // no player data yet
  228.     if (0 == dwSize)
  229.         return TRUE;
  230.  
  231.     hr = DPUtil_GetPlayerLocalData( dpId, &ship, &dwSize );
  232.     return (DP_OK == hr);
  233. };
  234.  
  235.  
  236.  
  237.  
  238. //-----------------------------------------------------------------------------
  239. // Name: InitLocalSoundData()
  240. // Desc: Initializes and registers all players' sound data ONLY
  241. //-----------------------------------------------------------------------------
  242. HRESULT InitLocalSoundData()
  243. {
  244.     return DPUtil_EnumPlayers(&(g_pdpsd->guidInstance), SetPlayerLocalSoundDataCB, NULL, 0);
  245. }
  246.  
  247.  
  248.  
  249.  
  250. //-----------------------------------------------------------------------------
  251. // Name: ReleaseLocalSoundData()
  252. // Desc: Releases a single ship's local sound buffers.
  253. //-----------------------------------------------------------------------------
  254. VOID ReleasePlayerLocalSoundData( SHIP* pShip )
  255. {
  256. /*
  257.     if( FALSE == g_bSoundInitialized )
  258.         return;
  259.  
  260.     for( int i=0; i<MAX_SOUNDS; i++)
  261.     {
  262.         if( pShip->pDSBuffer[i] )
  263.         {
  264.             pShip->pDSBuffer[i]->Stop();
  265.             pShip->pDSBuffer[i]->Release();
  266.             pShip->pDSBuffer[i] = NULL;
  267.         }
  268.  
  269.         if( pShip->pDS3DBuffer[i] )
  270.         {
  271.             pShip->pDS3DBuffer[i]->Release();   
  272.             pShip->pDS3DBuffer[i] = NULL;
  273.         }
  274.     }
  275. */
  276. }
  277.  
  278.  
  279.  
  280.  
  281. //-----------------------------------------------------------------------------
  282. // Name: ReleasePlayerLocalData()
  283. // Desc: Retrieves and releases a player's local data from dplay.
  284. //-----------------------------------------------------------------------------
  285. BOOL WINAPI ReleasePlayerLocalDataCB( DPID dpId, DWORD dwPlayerType,
  286.                                       LPCDPNAME lpName, DWORD dwFlags,
  287.                                       VOID* lpContext)
  288. {
  289.     SHIP ship;
  290.     DWORD dwSize = sizeof(SHIP);    
  291.     HRESULT hr;
  292.     
  293.     hr = DPUtil_GetPlayerLocalData( dpId, &ship, &dwSize );
  294.     if( FAILED(hr) )
  295.         goto FAIL;
  296.  
  297.     // no player data yet
  298.     if (0 == dwSize)
  299.         return TRUE;
  300.  
  301.     ReleasePlayerLocalSoundData(&ship);
  302.  
  303.     hr = DPUtil_SetPlayerLocalData(dpId, &ship,  dwSize );
  304.     if (FAILED(hr))
  305.         goto FAIL;
  306.  
  307.     // success
  308.     return TRUE;
  309. FAIL:
  310.     // we failed
  311.     return FALSE;
  312. }
  313.  
  314.  
  315.  
  316.  
  317. //-----------------------------------------------------------------------------
  318. // Name: ReleaseLocalData()
  319. // Desc: Releases local data of ALL players.
  320. //-----------------------------------------------------------------------------
  321. VOID ReleaseLocalData()
  322. {
  323.      if( g_nProgramState == PS_ACTIVE )
  324.      {
  325.          if( FAILED( DPUtil_EnumPlayers( &g_pdpsd->guidInstance,
  326.                                          ReleasePlayerLocalDataCB,
  327.                                          NULL, 0 ) ) )
  328.          {
  329.              ShowError(IDS_DPLAY_ERROR_EP);
  330.          }
  331.      }
  332. };
  333.  
  334.  
  335.  
  336.  
  337. //-----------------------------------------------------------------------------
  338. // Name: ProcessUserInput()
  339. // Desc: Processes any input from the user and updates our ship state
  340. //-----------------------------------------------------------------------------
  341. VOID ProcessUserInput( SHIP* pShip )
  342. {
  343.     static dwOldKeys = 0;
  344.  
  345.     g_bUpdate = FALSE;
  346.  
  347.     // DSOUND: check if the engine was turned off
  348.     if( !(g_dwKeys & (KEY_DOWN | KEY_UP)) && 
  349.         (dwOldKeys & (KEY_DOWN | KEY_UP)) )
  350.     {
  351.         g_dwKeys |= KEY_ENGINEOFF;
  352.  
  353.         g_ControlMsg.byState = (BYTE)g_dwKeys;
  354.         // let everyone know that we just turned our engine off
  355.         SendGameMessage( (GENERICMSG*)&g_ControlMsg, DPID_ALLPLAYERS );
  356.     }
  357.  
  358.     // update our ship state
  359.     UpdateState( pShip, g_dwKeys );
  360.  
  361.     // remember current keys for next frame
  362.     dwOldKeys = g_dwKeys;
  363. }
  364.  
  365.  
  366.  
  367.  
  368. //-----------------------------------------------------------------------------
  369. // Name: UpdateState()
  370. // Desc: Updates the current state of our ship, given user input
  371. //-----------------------------------------------------------------------------
  372. VOID UpdateState( SHIP* pShip, DWORD dwControls )
  373. {
  374.     static DWORD dwTimePrevUpdate = 0;
  375.     DWORD dwTimeNow = timeGetTime();
  376.     
  377.     pShip->dwKeys = dwControls;
  378.  
  379.     // Ship orientation
  380.     FLOAT fAngle = (FLOAT)( ( pShip->cFrame / 40.0f ) * 2 * 3.1415926283 );
  381.         
  382.     // Don't accept these keyboard inputs faster than 50
  383.     // times per second (every 20 ms)
  384.     if( dwTimeNow - dwTimePrevUpdate > 20 )
  385.     {
  386.         if( dwControls & KEY_LEFT )
  387.         {
  388.             g_bUpdate = TRUE;
  389.             pShip->cFrame--;
  390.             if( pShip->cFrame < 0 )
  391.                 pShip->cFrame += MAX_SHIP_FRAME;
  392.         }
  393.         if( dwControls & KEY_RIGHT )
  394.         {
  395.             g_bUpdate = TRUE;
  396.             pShip->cFrame++;
  397.             if( pShip->cFrame >= MAX_SHIP_FRAME )
  398.                 pShip->cFrame -= MAX_SHIP_FRAME;
  399.         }
  400.  
  401.         if( dwControls & KEY_UP )
  402.         {
  403.             g_bUpdate = TRUE;
  404.             pShip->dVelX +=  sin(fAngle) * 10.0 / 1000.0;
  405.             pShip->dVelY += -cos(fAngle) * 10.0 / 1000.0;
  406.         }
  407.         if( dwControls & KEY_DOWN )
  408.         {
  409.             g_bUpdate = TRUE;
  410.             pShip->dVelX -=  sin(fAngle) * 10.0 / 1000.0;
  411.             pShip->dVelY -= -cos(fAngle) * 10.0 / 1000.0;
  412.         }
  413.         dwTimePrevUpdate = dwTimeNow;
  414.     }
  415.  
  416.     if( dwControls & KEY_STOP )
  417.     {
  418.         g_bUpdate = TRUE;
  419.         pShip->dVelX = 0.0;
  420.         pShip->dVelY = 0.0;
  421.     }
  422.     if( !pShip->bBulletEnable && pShip->bEnable )
  423.     {
  424.         if( dwControls & KEY_FIRE )
  425.         {
  426.             g_bUpdate = TRUE;
  427.             // launch a new bullet
  428.             pShip->dBulletPosX = (WORD)( sin(fAngle)*6.0 + 16.0 + pShip->dPosX );
  429.             pShip->dBulletPosY = (WORD)(-cos(fAngle)*6.0 + 16.0 + pShip->dPosY );
  430.             pShip->dBulletVelX =  sin(fAngle)*500.0/1000.0;
  431.             pShip->dBulletVelY = -cos(fAngle)*500.0/1000.0;
  432.             pShip->bBulletEnable = TRUE;
  433.             pShip->dwBulletFrame = 0;
  434.         }
  435.     }
  436. }
  437.  
  438.  
  439.  
  440.  
  441. //-----------------------------------------------------------------------------
  442. // Name: SendSync()
  443. // Desc: Sends a sync message with the rendevous position. We are using a
  444. //       synchronization technique in which every player informs everyone else
  445. //       where the player is going to be at the end of the next sync interval.
  446. //       Based on this rendezvous position, everyone tries to move their
  447. //       corresponding ghosts to the rendezvous position by the end of the
  448. //       interval.
  449. //-----------------------------------------------------------------------------
  450. VOID SendSync( SHIP* pShip )
  451. {
  452.     g_SyncMsg.byShipType = pShip->byType;
  453.     g_SyncMsg.cFrame     = pShip->cFrame;
  454.     g_SyncMsg.dPosX      = pShip->dPosX + pShip->dVelX*1000;
  455.     g_SyncMsg.dPosY      = pShip->dPosY + pShip->dVelY*1000;
  456.  
  457.     SendGameMessage( (GENERICMSG*)&g_SyncMsg, DPID_ALLPLAYERS );
  458. }
  459.  
  460.  
  461.  
  462.  
  463. //-----------------------------------------------------------------------------
  464. // Name: UpdateDisplayStatus()
  465. // Desc: Updates the disable timeout. Enables the ship if disable timeout has
  466. //       elapsed.
  467. //-----------------------------------------------------------------------------
  468. VOID UpdateDisplayStatus( SHIP* pShip )
  469. {
  470.     DWORD dwTickDiff;
  471.     DWORD dwTickCount;
  472.  
  473.     // current time
  474.     dwTickCount = timeGetTime();
  475.  
  476.     // time elapsed since last update
  477.     dwTickDiff = dwTickCount - pShip->dwLastTick;
  478.  
  479.     // timestamp
  480.     pShip->dwLastTick = dwTickCount;
  481.  
  482.     // update time-out
  483.     pShip->iCountDown -= dwTickDiff;
  484.  
  485.     // time-out ?
  486.     if( pShip->iCountDown < 0 )
  487.     {
  488.         // get new position and enable our lpShip
  489.         pShip->dPosX   = randInt( 0, MAX_SHIP_X );
  490.         pShip->dPosY   = randInt( 0, MAX_SHIP_Y );
  491.         pShip->cFrame  = (char)randInt( 0, MAX_SHIP_FRAME );
  492.         pShip->bEnable = TRUE;
  493.     }
  494. }
  495.  
  496.  
  497.  
  498.  
  499. //-----------------------------------------------------------------------------
  500. // Name: UpdatePosition()
  501. // Desc: Updates our ship's position
  502. //-----------------------------------------------------------------------------
  503. VOID UpdatePosition( DPID dpId, SHIP* lpShip )
  504. {
  505.     int     x,y;
  506.     BYTE    oldxCell, oldyCell, newxCell, newyCell, mask, col, row;
  507.     double  thisTick, totalTick, xtick, ytick;
  508.     DWORD   dwTickCount;
  509.     DWORD   dwTickDiff;
  510.  
  511.     if( !lpShip->bEnable )
  512.         return;
  513.  
  514.     // how long has it been since we last updated
  515.     dwTickCount = timeGetTime();
  516.     dwTickDiff = dwTickCount - lpShip->dwLastTick;
  517.  
  518.     // current timestamp
  519.     lpShip->dwLastTick = dwTickCount;
  520.  
  521.     oldxCell = (int)(lpShip->dPosX+16.0) >> 4;
  522.     oldyCell = (int)(lpShip->dPosY+16.0) >> 4;
  523.  
  524.     // compute new position
  525.     lpShip->dPosX += lpShip->dVelX * dwTickDiff;
  526.     lpShip->dPosY += lpShip->dVelY * dwTickDiff;
  527.  
  528.     newxCell = (int)(lpShip->dPosX+16.0) >> 4;
  529.     newyCell = (int)(lpShip->dPosY+16.0) >> 4;
  530.     if(oldxCell != newxCell)
  531.     {
  532.         // we allow ghosts to pass through the blocks
  533.         if( (dpId == g_LocalPlayerDPID) && IsHit( newxCell, newyCell ) )
  534.         {
  535.             if( lpShip->dVelX > 0.0 )
  536.                 lpShip->dPosX = (oldxCell << 4) + 15 - 16;
  537.             else
  538.                 lpShip->dPosX = (oldxCell << 4) - 16;
  539.             lpShip->dVelX = -lpShip->dVelX*0.9;
  540.             newxCell = oldxCell;
  541.             lpShip->bBounced = TRUE;
  542.         }
  543.     }
  544.     if(oldyCell != newyCell)
  545.     {
  546.         // we allow ghosts to pass through the blocks
  547.         if( (dpId == g_LocalPlayerDPID) && IsHit( newxCell, newyCell ) )
  548.         {
  549.             if( lpShip->dVelY > 0.0 )
  550.                 lpShip->dPosY = (oldyCell << 4) + 15 - 16;
  551.             else
  552.                 lpShip->dPosY = (oldyCell << 4) - 16;
  553.  
  554.             lpShip->dVelY = -lpShip->dVelY*0.9;
  555.             lpShip->bBounced = TRUE;
  556.         }
  557.     }
  558.  
  559.     if( lpShip->dPosX > MAX_SHIP_X )
  560.     {
  561.         lpShip->dPosX = MAX_SHIP_X;
  562.         lpShip->dVelX = -lpShip->dVelX*0.9;
  563.         lpShip->bBounced = TRUE;
  564.     }
  565.     else if ( lpShip->dPosX < 0 )
  566.     {
  567.         lpShip->dPosX =0;
  568.         lpShip->dVelX = -lpShip->dVelX*0.9;
  569.         lpShip->bBounced = TRUE;
  570.     }
  571.     if( lpShip->dPosY > MAX_SHIP_Y )
  572.     {
  573.         lpShip->dPosY = MAX_SHIP_Y;
  574.         lpShip->dVelY = -lpShip->dVelY*0.9;
  575.         lpShip->bBounced = TRUE;
  576.     }
  577.     else if ( lpShip->dPosY < 0 )
  578.     {
  579.         lpShip->dPosY =0;
  580.         lpShip->dVelY = -lpShip->dVelY*0.9;
  581.         lpShip->bBounced = TRUE;
  582.     }    
  583.  
  584.     if ((dpId == g_LocalPlayerDPID) && lpShip->bBounced)
  585.     {
  586.         SendSync(lpShip);
  587.     }
  588.  
  589.     if( !lpShip->bBulletEnable )
  590.         return;
  591.  
  592.     // update the active bullet
  593.     lpShip->dwBulletFrame += dwTickDiff;
  594.     if( lpShip->dwBulletFrame >= MAX_BULLET_FRAME )
  595.     {
  596.         lpShip->bFiring = FALSE;
  597.         lpShip->bBulletEnable = FALSE;
  598.         return;
  599.     }
  600.  
  601.  
  602.     if( lpShip->dBulletVelX != 0.0 )
  603.         xtick = 8.0/lpShip->dBulletVelX;
  604.     else
  605.         xtick = 999999.0;
  606.  
  607.     if( lpShip->dBulletVelY != 0.0 )
  608.         ytick = 8.0/lpShip->dBulletVelY;
  609.     else
  610.         ytick = 999999.0;
  611.  
  612.     if( xtick < 0.0 )
  613.         xtick = -xtick;
  614.     if( ytick < 0.0 )
  615.         ytick = -ytick;
  616.  
  617.     if( xtick < ytick )
  618.         thisTick = xtick;
  619.     else
  620.         thisTick = ytick;
  621.     
  622.     if( thisTick > dwTickDiff )
  623.         thisTick = dwTickDiff;
  624.             
  625.     for( totalTick = 0.0; totalTick < dwTickDiff; )
  626.     {
  627.         totalTick += thisTick;
  628.  
  629.         lpShip->dBulletPosX += lpShip->dBulletVelX * thisTick;
  630.         lpShip->dBulletPosY += lpShip->dBulletVelY * thisTick;
  631.  
  632.         if( lpShip->dBulletPosX > MAX_BULLET_X )
  633.         {
  634.             lpShip->dBulletPosX = MAX_BULLET_X;
  635.             lpShip->dBulletVelX = -lpShip->dBulletVelX*0.9;
  636.         }
  637.         else if ( lpShip->dBulletPosX < 0 )
  638.         {
  639.             lpShip->dBulletPosX =0;
  640.             lpShip->dBulletVelX = -lpShip->dBulletVelX*0.9;
  641.         }
  642.         if( lpShip->dBulletPosY > MAX_BULLET_Y )
  643.         {
  644.             lpShip->dBulletPosY = MAX_BULLET_Y;
  645.             lpShip->dBulletVelY = -lpShip->dBulletVelY*0.9;
  646.         }
  647.         else if ( lpShip->dBulletPosY < 0 )
  648.         {
  649.             lpShip->dBulletPosY =0;
  650.             lpShip->dBulletVelY = -lpShip->dBulletVelY*0.9;
  651.         }
  652.     
  653.         // check to see if it hit anything
  654.         x = (int)(lpShip->dBulletPosX + 0.5) + 1;
  655.         y = (int)(lpShip->dBulletPosY + 0.5) + 1;
  656.     
  657.         row = y >> 4;
  658.         col = x >> 4;
  659.         mask = 1 << (col & 0x7);
  660.         col = col >> 3;
  661.         if( g_Blocks.bits[row][col] & mask )
  662.         {
  663.             // dwScored a block hit
  664.             g_BlockHitMsg.byRow = row;
  665.             g_BlockHitMsg.byCol = col;
  666.             g_BlockHitMsg.byMask = mask;
  667.             SendGameMessage( (GENERICMSG*)&g_BlockHitMsg, DPID_ALLPLAYERS);
  668.  
  669.             g_Blocks.bits[row][col] &= ~mask;
  670.             lpShip->dwScore += 10;
  671.             lpShip->bBulletEnable = FALSE;
  672.             lpShip->bBlockHit = TRUE;
  673.             lpShip->bFiring   = FALSE;
  674.         }
  675.     }
  676. }
  677.  
  678.  
  679.  
  680.  
  681. //-----------------------------------------------------------------------------
  682. // Name: IsHit()
  683. // Desc: Tells if there is a block at (x,y) location
  684. //-----------------------------------------------------------------------------
  685. BOOL IsHit( int x, int y )
  686. {
  687.     int col, mask;
  688.     
  689.     // outside screen boundaries?
  690.     if( (x < 0) || (y < 0) || (x >= 40) || (y >= 30) )
  691.         return TRUE;
  692.     
  693.     // look at the block bits
  694.     mask = 1 << (x & 0x7);
  695.     col = x >> 3;
  696.     if( g_Blocks.bits[y][col] & mask )
  697.         return TRUE;
  698.     else
  699.         return FALSE;
  700. }
  701.  
  702.  
  703.  
  704.  
  705. //-----------------------------------------------------------------------------
  706. // Name: InitField
  707. // Desc: Initializes block positions on the field
  708. //-----------------------------------------------------------------------------
  709. VOID InitField()
  710. {
  711.     int i, x, y;
  712.     
  713.     // clear all g_Blocks
  714.     for(x=0; x<5; x++)
  715.         for(y=0; y<30; y++)
  716.             g_Blocks.bits[y][x] = 0;
  717.  
  718.     // set random gBlocks
  719.     for(i=0; i<400; i++)
  720.     {
  721.         x = randInt(0, 40);
  722.         y = randInt(0, 30);
  723.         if( !setBlock(x, y) ) i--;
  724.     }
  725. }
  726.  
  727.  
  728.  
  729.  
  730. //-----------------------------------------------------------------------------
  731. // Name: AddBlock()
  732. // Desc: Adds a block to the field
  733. //-----------------------------------------------------------------------------
  734. VOID AddBlock()
  735. {
  736.     // Maybe add a block?
  737.     if( g_bHostPlayer && g_bIsActive && ( randInt( 0, 100 ) > 98 ) )
  738.     {
  739.         int x = randInt( 0, 40);
  740.         int y = randInt( 0, 30);
  741.         if( setBlock( x, y) )
  742.         {
  743.             g_AddBlockMsg.byX = (BYTE)x;
  744.             g_AddBlockMsg.byY = (BYTE)y;
  745.             SendGameMessage( (GENERICMSG*)&g_AddBlockMsg, DPID_ALLPLAYERS );
  746.         }
  747.     }
  748. }
  749.  
  750.  
  751.  
  752.  
  753. //-----------------------------------------------------------------------------
  754. // Name: setBlock()
  755. // Desc: Turns on a block
  756. //-----------------------------------------------------------------------------
  757. BOOL setBlock( int x, int y )
  758. {
  759.     BYTE  mask, col;
  760.  
  761.     mask = 1 << (x & 0x7);
  762.     col = x >> 3;
  763.     
  764.     // is Block already set?
  765.     if( g_Blocks.bits[y][col] & mask )
  766.         return FALSE;
  767.     
  768.     // set the block and return success
  769.     g_Blocks.bits[y][col] |= mask;
  770.     return TRUE;
  771. }
  772.  
  773.  
  774.  
  775.  
  776. //-----------------------------------------------------------------------------
  777. // Name: AddFrag()
  778. // Desc: Turns on a fragment
  779. //-----------------------------------------------------------------------------
  780. VOID AddFrag( SHIP* pShip, int offX, int offY )
  781. {
  782.     for( int i=0; i<64; i++ ) // Find available fragment
  783.     {
  784.         if( !g_Frags[i].valid )
  785.             break;
  786.     }
  787.     if( i == 64 )
  788.         return;
  789.         
  790.     g_Frags[i].dPosX      = offX + pShip->dPosX;
  791.     g_Frags[i].dPosY      = offY + pShip->dPosY;
  792.     g_Frags[i].pdds       = g_pddsShip[pShip->byType];
  793.     g_Frags[i].src.top    = 32 * ( (int)pShip->cFrame / 10 ) + offX;
  794.     g_Frags[i].src.left   = 32 * ( (int)pShip->cFrame % 10 ) + offY;
  795.     g_Frags[i].src.right  = g_Frags[i].src.left + 8;
  796.     g_Frags[i].src.bottom = g_Frags[i].src.top + 8;
  797.     g_Frags[i].dVelX      = ((double)offX - 12.0)/24.0;
  798.     g_Frags[i].dVelY      = ((double)offY - 12.0)/24.0;
  799.     g_Frags[i].valid      = TRUE;
  800. }
  801.  
  802.  
  803.  
  804.  
  805. //-----------------------------------------------------------------------------
  806. // Name: UpdateFragment()
  807. // Desc: Updates the position of a fragment
  808. //-----------------------------------------------------------------------------
  809. VOID UpdateFragment( int i )
  810. {
  811.     DWORD dwTickCount;
  812.     static DWORD dwTickDiff;
  813.     static DWORD dwLastTick;
  814.  
  815.     if( i == 0 )
  816.     {
  817.         dwTickCount = timeGetTime();
  818.         dwTickDiff = dwTickCount - dwLastTick;
  819.         dwLastTick = dwTickCount;
  820.  
  821.         // If the FPS is high, keep the fragments moving
  822.         if( dwTickDiff < 10 )
  823.             dwTickDiff = 10;
  824.     }
  825.     
  826.     if( !g_Frags[i].valid )
  827.         return;
  828.     
  829.     g_Frags[i].dPosX += (int) (g_Frags[i].dVelX * dwTickDiff);
  830.     g_Frags[i].dPosY += (int) (g_Frags[i].dVelY * dwTickDiff);
  831.     if( (g_Frags[i].dPosX < 0.0) || (g_Frags[i].dPosX >= 632.0) ||
  832.         (g_Frags[i].dPosY < 0.0) || (g_Frags[i].dPosY >= 472.0) )
  833.     {
  834.         g_Frags[i].valid = FALSE;
  835.     }
  836. }
  837.  
  838.  
  839.  
  840.  
  841. //-----------------------------------------------------------------------------
  842. // Name: DestroyShip()
  843. // Desc: Adds a bunch of fragments to show that the ship is destroyed
  844. //-----------------------------------------------------------------------------
  845. VOID DestroyShip( SHIP* pShip )
  846. {
  847.     // Set flag for explosion sound
  848.     pShip->bDeath  = TRUE;
  849.  
  850.     // Add ship fragments
  851.     AddFrag( pShip,  0,  0 );
  852.     AddFrag( pShip,  8,  0 );
  853.     AddFrag( pShip, 16,  0 );
  854.     AddFrag( pShip, 24,  0 );
  855.     AddFrag( pShip,  0,  8 );
  856.     AddFrag( pShip,  8,  8 );
  857.     AddFrag( pShip, 16,  8 );
  858.     AddFrag( pShip, 24,  8 );
  859.     AddFrag( pShip,  0, 16 );
  860.     AddFrag( pShip,  8, 16 );
  861.     AddFrag( pShip, 16, 16 );
  862.     AddFrag( pShip, 24, 16 );
  863.     AddFrag( pShip,  0, 24 );
  864.     AddFrag( pShip,  8, 24 );
  865.     AddFrag( pShip, 16, 24 );
  866.     AddFrag( pShip, 24, 24 );
  867.  
  868.     // Play explosion sound
  869.     ProcessSoundFlags( pShip );
  870. }
  871.  
  872.  
  873.  
  874.  
  875. //-----------------------------------------------------------------------------
  876. // Name: UpdateFrame()
  877. // Desc: Refreshes the screen
  878. //-----------------------------------------------------------------------------
  879. BOOL UpdateFrame()
  880. {
  881.     static DWORD dwSyncLastTick     = 0L;
  882.     static DWORD dwUpdateLastTick   = 0L;
  883.     static DWORD dwLobbyMsgLastTick = 0L;
  884.     DWORD   dwTickCount;
  885.     SHIP    ship;
  886.     DWORD   dwSize;
  887.     HRESULT hr;
  888.     int     i;
  889.     
  890.     switch( g_nProgramState )
  891.     {
  892.         case PS_ACTIVE:
  893.             // Use DirectInput to read game-play keys
  894.             DIUtil_ReadKeys( &g_dwKeys );
  895.  
  896.             // get our local data
  897.             dwSize = sizeof(ship);
  898.             hr = DPUtil_GetPlayerLocalData( g_LocalPlayerDPID, &ship, &dwSize );
  899.             if( FAILED(hr) )
  900.                 return FALSE;
  901.  
  902.             if( !ship.bEnable )
  903.             {
  904.                 // Ppdate disable timeout and display status
  905.                 UpdateDisplayStatus( &ship );
  906.             }
  907.             else
  908.             {
  909.                 // Process any change in game controls 
  910.                 ProcessUserInput( &ship );
  911.  
  912.                 dwTickCount = timeGetTime();
  913.  
  914.                 // Synchronize if it's time
  915.                 if( g_bIsActive && ((dwTickCount - dwSyncLastTick) > SYNC_INTERVAL) )
  916.                 {
  917.                     SendSync( &ship );
  918.                     dwSyncLastTick = dwTickCount;
  919.                 }
  920.  
  921.                 // If our player changed any keys, let everyone know
  922.                 if( g_bUpdate )
  923.                 {
  924.                     // Control the number of packets we send
  925.                     if( (dwTickCount - dwUpdateLastTick) > UPDATE_INTERVAL )
  926.                     {
  927.                         // Let others know
  928.                         g_ControlMsg.byState = (BYTE)g_dwKeys;
  929.                         SendGameMessage( (GENERICMSG*)&g_ControlMsg, DPID_ALLPLAYERS );
  930.                         dwUpdateLastTick = dwTickCount;
  931.                     }
  932.                 }
  933.  
  934.                 // If connected to a lobby, occasionally report score as a property
  935.                 if( DoingLobbyMessages() && 
  936.                     (dwTickCount - dwLobbyMsgLastTick) > 10000 )    // every 10 sec
  937.                 {
  938.                     DPLDATA_PLAYERSCORE playerScore;
  939.                     ZeroMemory(&playerScore, sizeof(DPLDATA_PLAYERSCORE));
  940.                     playerScore.dwScoreCount = 1;
  941.                     playerScore.Score[0] = (LONG)ship.dwScore;
  942.                     LobbyMessageSetProperty( &DPLPROPERTY_PlayerScore, &playerScore,
  943.                                              sizeof(DPLDATA_PLAYERSCORE));
  944.                     dwLobbyMsgLastTick = dwTickCount;
  945.                 }
  946.             }
  947.  
  948.             // Save ship data as RenderPlayerCB reads stored data
  949.             hr = DPUtil_SetPlayerLocalData( g_LocalPlayerDPID, &ship, sizeof(ship) );
  950.             if( FAILED(hr) )
  951.             {
  952.                 ShowError(IDS_DPLAY_ERROR_SPLD);
  953.                 return FALSE;
  954.             }   
  955.  
  956.             // Update fragments
  957.             for( i=0; i<64; i++ )
  958.                 UpdateFragment(i);
  959.  
  960.             // Add a block
  961.             AddBlock();
  962.  
  963.             // Render everything        
  964.             if( !DrawScreen() )
  965.             {
  966.                 return FALSE;
  967.             }
  968.             break;
  969.  
  970.         case PS_REST:
  971.             if( g_bHaveHostInit )
  972.             {
  973.                 SetGamePalette();
  974.                 g_nProgramState = PS_ACTIVE;
  975.             }
  976.             break;
  977.     }
  978.  
  979.     return TRUE;
  980. }
  981.  
  982.  
  983.  
  984.  
  985. //-----------------------------------------------------------------------------
  986. // Name: ProcessSoundFlags()
  987. // Desc: 
  988. //-----------------------------------------------------------------------------
  989. VOID ProcessSoundFlags( SHIP* pShip )
  990. {
  991.     // Get object positions for panning sounds
  992.     RECT rc;
  993.     GetClientRect( g_hwndMain, &rc );
  994.     FLOAT fShipXPos   = (FLOAT)( ( 2 * pShip->dPosX ) / rc.right )  - 1;
  995.     FLOAT fShipYpos   = (FLOAT)( (-2 * pShip->dPosY ) / rc.bottom ) - 1;
  996.     FLOAT fBulletXPos = (FLOAT)( ( 2 * pShip->dPosX ) / rc.right )  - 1;
  997.     FLOAT fBulletYpos = (FLOAT)( (-2 * pShip->dPosY ) / rc.bottom ) - 1;
  998.  
  999.     // Set sound state based on user input and ship state
  1000.     if( pShip->bDeath )          // nothing but the boom
  1001.     {
  1002.         DSUtil_StopSound( g_pBulletFiringSound );
  1003.         DSUtil_StopSound( g_pShipBounceSound );
  1004.         DSUtil_StopSound( g_pShipStopSound );
  1005.         DSUtil_StopSound( g_pShipStartSound );
  1006.         DSUtil_StopSound( g_pShipEngineSound );
  1007.         DSUtil_PlaySound( g_pShipExplodeSound, 0 );
  1008.  
  1009.         pShip->bEngineRunning = FALSE;
  1010.         pShip->bMoving        = FALSE;
  1011.         pShip->dwKeys         = 0;      // No input for a dead ship
  1012.         pShip->bDeath         = FALSE;  // Turn off sound flag.
  1013.     }
  1014.  
  1015.     if( pShip->dwKeys & KEY_STOP )
  1016.     {
  1017.         if( pShip->bMoving )
  1018.         {
  1019.             DSUtil_StopSound( g_pShipEngineSound );
  1020.             DSUtil_PlaySound( g_pShipStopSound, 0 );
  1021.             pShip->bEngineRunning = FALSE;
  1022.             pShip->bMoving        = FALSE;
  1023.         }
  1024.     }
  1025.  
  1026.     if( pShip->dwKeys & KEY_ENGINEOFF )
  1027.     {
  1028.         DSUtil_StopSound( g_pShipEngineSound );
  1029.         pShip->bEngineRunning = FALSE;
  1030.     }
  1031.  
  1032.     if( pShip->dwKeys & (KEY_UP | KEY_DOWN) )
  1033.     {
  1034.         if( !pShip->bEngineRunning ) // Turn on engine
  1035.         {
  1036.             DSUtil_PlaySound( g_pShipEngineSound, DSBPLAY_LOOPING );
  1037.             if( !pShip->bMoving )   //"fire-up-engine" sound
  1038.             {
  1039.                 DSUtil_PlayPannedSound( g_pShipStartSound, fShipXPos );
  1040.                 pShip->bMoving = TRUE;
  1041.             }
  1042.             pShip->bEngineRunning = TRUE;
  1043.         }
  1044.     }
  1045.  
  1046.     if( pShip->dwKeys & KEY_FIRE )
  1047.     {
  1048.         if( !pShip->bFiring )
  1049.         {
  1050.             DSUtil_PlayPannedSound( g_pBulletFiringSound, fShipXPos );
  1051.  
  1052.             pShip->bFiring = TRUE;
  1053.         }
  1054.     }
  1055.  
  1056.     if( pShip->bBlockHit )
  1057.     {
  1058.         DSUtil_PlayPannedSound( g_pBlockExplodeSound, fBulletXPos );
  1059.         pShip->bBlockHit = FALSE;
  1060.     }
  1061.  
  1062.     if( pShip->bBounced )
  1063.     {
  1064.         DSUtil_PlayPannedSound( g_pShipBounceSound, fShipXPos );
  1065.         pShip->bBounced = FALSE;
  1066.     }
  1067.  
  1068.     pShip->dwKeys = 0;
  1069. }
  1070.  
  1071.  
  1072.  
  1073.  
  1074. //-----------------------------------------------------------------------------
  1075. // Name: RenderPlayerCB()
  1076. // Desc: Renders a ship in its current state. Also checks if we hit the ship
  1077. //       and informs the ship that it has been destroyed.
  1078. //-----------------------------------------------------------------------------
  1079. BOOL WINAPI RenderPlayerCB( DPID dpId, DWORD dwPlayerType, LPCDPNAME lpName, 
  1080.                             DWORD dwFlags, VOID* lpContext )
  1081. {
  1082.     SHIP    ship;
  1083.     SHIP    ourShip;
  1084.     DWORD   dwSize = sizeof(ship);
  1085.     BOOL    bHit = FALSE;
  1086.     HRESULT hr;
  1087.     DWORD   dwTickCount;
  1088.     
  1089.     // Get ship data
  1090.     hr = DPUtil_GetPlayerLocalData( dpId, &ship, &dwSize );
  1091.     if( FAILED(hr) )
  1092.         return FALSE;
  1093.  
  1094.     // No player data yet
  1095.     if( 0 == dwSize )
  1096.         return TRUE; 
  1097.  
  1098.     // Ignore current ship ?
  1099.     if( ship.bIgnore )
  1100.     {
  1101.         // If this ship was being ignored, update ignore time-out
  1102.         // A time-out is used here to ensure that this ship doesn't get ignored
  1103.         // forever on our screen in case the destroy message was dropped.
  1104.         dwTickCount = timeGetTime();
  1105.         ship.iCountDown -= dwTickCount - ship.dwLastTick;
  1106.         ship.dwLastTick = dwTickCount;
  1107.         if( ship.iCountDown < 0 ) 
  1108.         {
  1109.             ship.bIgnore = FALSE;
  1110.         }
  1111.  
  1112.         // Save ship data
  1113.         hr = DPUtil_SetPlayerLocalData( dpId, &ship, sizeof(ship) );
  1114.         if( FAILED(hr) )
  1115.             return FALSE;
  1116.         
  1117.         // We are ignoring this ship, so just bail
  1118.         return TRUE;
  1119.     }
  1120.  
  1121.     // Bail if ship is disabled
  1122.     if( !ship.bEnable)
  1123.         return TRUE;
  1124.  
  1125.     // Update ship's position
  1126.     UpdatePosition( dpId, &ship );
  1127.  
  1128.     // Get our player data to compare with others
  1129.     dwSize = sizeof(ship);
  1130.     hr = DPUtil_GetPlayerLocalData( g_LocalPlayerDPID, &ourShip, &dwSize );
  1131.     if( FAILED(hr) )
  1132.         return FALSE;
  1133.  
  1134.     // Check if our bullet hit the current ship
  1135.     if( (dpId != g_LocalPlayerDPID) && ourShip.bBulletEnable && ship.bEnable )
  1136.     {
  1137.         if( (ourShip.dBulletPosX > ship.dPosX) &&
  1138.             (ourShip.dBulletPosX < (ship.dPosX + 32.0) ) &&
  1139.             (ourShip.dBulletPosY > ship.dPosY) &&
  1140.             (ourShip.dBulletPosY < (ship.dPosY + 32.0) ) )
  1141.         {
  1142.             // Hasta-la-vista baby
  1143.             DestroyShip( &ship );
  1144.             // We nailed it
  1145.             bHit = TRUE;
  1146.             // Turn off ship locally
  1147.             ship.bEnable = FALSE;
  1148.             // Temporarily ignore ship until we get a response
  1149.             ship.bIgnore = TRUE;
  1150.             // Set its ignore time-out
  1151.             ship.iCountDown = HIDE_TIMEOUT;
  1152.             // Time-stamp
  1153.             ship.dwLastTick = timeGetTime();
  1154.             // Turn our bullet off
  1155.             ship.bBulletEnable = FALSE;
  1156.             // Update our score
  1157.             ourShip.dwScore += 1000;
  1158.             // Save our score
  1159.             hr = DPUtil_SetPlayerLocalData( g_LocalPlayerDPID, &ourShip, sizeof(ourShip) );
  1160.             if( FAILED(hr) )
  1161.             {
  1162.                 ShowError(IDS_DPLAY_ERROR_SPLD);
  1163.                 return FALSE;
  1164.             }
  1165.         }
  1166.     }
  1167.  
  1168.     // Render the ship
  1169.     if( ship.bBulletEnable ) DrawBullet(&ship);
  1170.     if( ship.bEnable )       DrawShip(&ship);
  1171.  
  1172.     ProcessSoundFlags( &ship );
  1173.  
  1174.     // Save ship data
  1175.     hr = DPUtil_SetPlayerLocalData( dpId, &ship, sizeof(ship) );
  1176.     if( FAILED(hr) )
  1177.         return FALSE;
  1178.  
  1179.     // Inform the player
  1180.     if( bHit )
  1181.     {
  1182.         g_ShipHitMsg.Id = dpId;
  1183.         SendGameMessage( (GENERICMSG*)&g_ShipHitMsg, dpId );
  1184.     }
  1185.  
  1186.     return TRUE;
  1187. }
  1188.  
  1189.  
  1190.  
  1191.  
  1192. //-----------------------------------------------------------------------------
  1193. // Name: DrawScreen()
  1194. // Desc: Renders the current frame
  1195. //-----------------------------------------------------------------------------
  1196. BOOL DrawScreen()
  1197. {
  1198.     HRESULT hr;
  1199.  
  1200.     // Clear screen
  1201.     EraseScreen();
  1202.     
  1203.     // Render players
  1204.     hr = DPUtil_EnumPlayers( NULL, RenderPlayerCB, NULL, 0 );
  1205.     if( FAILED(hr) )
  1206.     {
  1207.         ShowError(IDS_DPLAY_ERROR_EP);
  1208.         return FALSE;
  1209.     }
  1210.  
  1211.     // Render field
  1212.     for( int y=0; y<30; y++ )
  1213.     {
  1214.         for( int x=0; x<40; x++ )
  1215.         {
  1216.             BYTE mask = 1 << (x & 0x7);
  1217.             BYTE col  = x >> 3;
  1218.             if( g_Blocks.bits[y][col] & mask )
  1219.                 DrawBlock( x, y );
  1220.         }
  1221.     }
  1222.     
  1223.     // Render score
  1224.     if (!DrawScore())
  1225.         return FALSE;
  1226.  
  1227.     // Render fragments
  1228.     DrawFragments();    
  1229.  
  1230.     // Render frame rate
  1231.     if( g_bShowFrameCount )
  1232.         DisplayFrameRate();
  1233.  
  1234.     // Show
  1235.     FlipScreen();
  1236.  
  1237.     return TRUE;
  1238. }
  1239.  
  1240.  
  1241.  
  1242.  
  1243. //-----------------------------------------------------------------------------
  1244. // Name: DisplayFrameRate()
  1245. // Desc: Renders current frame rate
  1246. //-----------------------------------------------------------------------------
  1247. VOID DisplayFrameRate()
  1248. {
  1249.     static DWORD dwFrames = 0;
  1250.     
  1251.     g_dwFrameCount++;
  1252.  
  1253.     DWORD dwTime = timeGetTime() - g_dwFrameTime;
  1254.     if( dwTime > 1000 )
  1255.     {
  1256.         dwFrames      = (g_dwFrameCount*1000)/dwTime;
  1257.         g_dwFrameTime  = timeGetTime();
  1258.         g_dwFrameCount = 0;
  1259.     }
  1260.  
  1261.     if( dwFrames == 0 )
  1262.         return;
  1263.  
  1264.     if (dwFrames != g_dwFramesLast)
  1265.         g_dwFramesLast = dwFrames;
  1266.  
  1267.     char strFPS[256];
  1268.     sprintf( strFPS, "%d", dwFrames );
  1269.     BltNumber( strFPS, 295, 10);
  1270. }
  1271.  
  1272.  
  1273.  
  1274.  
  1275. //-----------------------------------------------------------------------------
  1276. // Name: DrawScore()
  1277. // Desc: Renders our current score
  1278. //-----------------------------------------------------------------------------
  1279. BOOL DrawScore()
  1280. {
  1281.     SHIP    ship;
  1282.     DWORD   dwSize;
  1283.     CHAR    strScore[11];
  1284.     int     rem;
  1285.     HRESULT hr;
  1286.  
  1287.     dwSize = sizeof(ship);
  1288.     hr = DPUtil_GetPlayerLocalData( g_LocalPlayerDPID, &ship, &dwSize );
  1289.     if( FAILED(hr) )
  1290.         return FALSE;
  1291.  
  1292.     // Calculate dwScore string
  1293.     strScore[0] = (BYTE)ship.dwScore/100000 + '0';
  1294.     rem = ship.dwScore % 100000;
  1295.     strScore[1] = rem/10000 + '0';
  1296.     rem = ship.dwScore % 10000;
  1297.     strScore[2] = rem/1000 + '0';
  1298.     rem = ship.dwScore % 1000;
  1299.     strScore[3] = rem/100 + '0';
  1300.     rem = ship.dwScore % 100;
  1301.     strScore[4] = rem/10 + '0';
  1302.     rem = ship.dwScore % 10;
  1303.     strScore[5] = rem + '0';
  1304.     strScore[6] = '\0';
  1305.  
  1306.     // Blt score
  1307.     BltNumber( strScore, 8, 8 );
  1308.  
  1309.     // Save ship data
  1310.     hr = DPUtil_SetPlayerLocalData( g_LocalPlayerDPID, &ship, sizeof(ship) );
  1311.     if( FAILED(hr) )
  1312.     {
  1313.         ShowError(IDS_DPLAY_ERROR_SPLD);
  1314.         return FALSE;
  1315.     }
  1316.  
  1317.     return TRUE;
  1318. }
  1319.  
  1320.  
  1321.  
  1322.  
  1323. //-----------------------------------------------------------------------------
  1324. // Name: DrawBlock()
  1325. // Desc: Renders a block
  1326. //-----------------------------------------------------------------------------
  1327. VOID DrawBlock( int x, int y )
  1328. {
  1329.     RECT src;
  1330.     src.top    = 0;
  1331.     src.left   = 224;
  1332.     src.right  = src.left + 16;
  1333.     src.bottom = src.top + 16;
  1334.     BltObject( x << 4, y << 4, g_pddsNumbers, &src, DDBLTFAST_SRCCOLORKEY );
  1335. }
  1336.  
  1337.  
  1338.  
  1339.  
  1340. //-----------------------------------------------------------------------------
  1341. // Name: DrawShip()
  1342. // Desc: Renders a ship
  1343. //-----------------------------------------------------------------------------
  1344. VOID DrawShip( SHIP* pShip )
  1345. {
  1346.     RECT src;
  1347.     src.top    = 32 * (pShip->cFrame / 10 );
  1348.     src.left   = 32 * (pShip->cFrame % 10 );
  1349.     src.right  = src.left + 32;
  1350.     src.bottom = src.top + 32;
  1351.     BltObject( (int)pShip->dPosX, (int)pShip->dPosY, g_pddsShip[pShip->byType],
  1352.                &src, DDBLTFAST_SRCCOLORKEY );
  1353. }
  1354.  
  1355.  
  1356.  
  1357.  
  1358. //-----------------------------------------------------------------------------
  1359. // Name: DrawBullet()
  1360. // Desc: Renders a bullet 
  1361. //-----------------------------------------------------------------------------
  1362. VOID DrawBullet( SHIP* pShip )
  1363. {
  1364.     RECT src;
  1365.     src.top    = BULLET_Y;
  1366.     src.left   = BULLET_X + (pShip->byType)*4;
  1367.     src.right  = src.left + 3;
  1368.     src.bottom = src.top + 3;
  1369.     BltObject( (int)pShip->dBulletPosX, (int)pShip->dBulletPosY, g_pddsNumbers,
  1370.                &src, DDBLTFAST_SRCCOLORKEY );
  1371. }
  1372.  
  1373.  
  1374.  
  1375.  
  1376. //-----------------------------------------------------------------------------
  1377. // Name: DrawFragments()
  1378. // Desc: Renders the fragments
  1379. //-----------------------------------------------------------------------------
  1380. VOID DrawFragments()
  1381. {
  1382.     for( int i=0; i<64; i++)
  1383.     {
  1384.         if( g_Frags[i].valid )
  1385.         {
  1386.             BltObject( (int)g_Frags[i].dPosX, (int)g_Frags[i].dPosY,
  1387.                        g_Frags[i].pdds, &g_Frags[i].src,
  1388.                        DDBLTFAST_SRCCOLORKEY );
  1389.         }
  1390.     }
  1391. }
  1392.  
  1393.  
  1394.  
  1395.  
  1396. //-----------------------------------------------------------------------------
  1397. // Name: ReceiveGameMessages()
  1398. // Desc: Checks if there are any messages for us and receives them
  1399. //-----------------------------------------------------------------------------
  1400. HRESULT ReceiveMessages()
  1401. {
  1402.     DPID    idFrom, idTo;
  1403.     LPVOID  pvMsgBuffer;
  1404.     DWORD   dwMsgBufferSize;
  1405.     HRESULT hr;
  1406.  
  1407.     // read all messages in queue
  1408.     dwMsgBufferSize = g_dwReceiveBufferSize;
  1409.     pvMsgBuffer     = g_pvReceiveBuffer;
  1410.     
  1411.     while( TRUE )
  1412.     {
  1413.         // See what's out there
  1414.         idFrom = 0;
  1415.         idTo   = 0;
  1416.  
  1417.         hr = DPUtil_Receive( &idFrom, &idTo, DPRECEIVE_ALL, pvMsgBuffer,
  1418.                              &dwMsgBufferSize );
  1419.         if( hr == DPERR_BUFFERTOOSMALL )
  1420.         {
  1421.             if( pvMsgBuffer == NULL )
  1422.             {
  1423.                 pvMsgBuffer = GlobalAllocPtr( GHND, dwMsgBufferSize );
  1424.                 if( pvMsgBuffer == NULL )
  1425.                     return DPERR_NOMEMORY;
  1426.                 g_pvReceiveBuffer     = pvMsgBuffer;
  1427.                 g_dwReceiveBufferSize = dwMsgBufferSize;
  1428.             }
  1429.             else if( dwMsgBufferSize > g_dwReceiveBufferSize )
  1430.             {
  1431.                 pvMsgBuffer = GlobalReAllocPtr( pvMsgBuffer, dwMsgBufferSize, 0 );
  1432.                 if( pvMsgBuffer == NULL )
  1433.                     return DPERR_NOMEMORY;
  1434.                 g_pvReceiveBuffer     = pvMsgBuffer;
  1435.                 g_dwReceiveBufferSize = dwMsgBufferSize;
  1436.             }
  1437.         }
  1438.         else if( SUCCEEDED(hr) &&
  1439.                  ( (dwMsgBufferSize >= sizeof(GENERICMSG)) || 
  1440.                    (dwMsgBufferSize >= sizeof(DPMSG_GENERIC) ) ) )
  1441.         {
  1442.             if( idFrom == DPID_SYSMSG )
  1443.             {
  1444.                 DoSystemMessage( (DPMSG_GENERIC*)pvMsgBuffer, dwMsgBufferSize,
  1445.                                  idFrom, idTo );
  1446.             }
  1447.             else
  1448.             {
  1449.                 DoApplicationMessage( (GENERICMSG*)pvMsgBuffer, dwMsgBufferSize,
  1450.                                       idFrom, idTo );
  1451.             }
  1452.         }
  1453.         else
  1454.             break;
  1455.     }
  1456.  
  1457.     return hr;
  1458. }
  1459.  
  1460.  
  1461.  
  1462.  
  1463. //-----------------------------------------------------------------------------
  1464. // Name: DoSystemMessage()
  1465. // Desc: Evaluates system messages and performs appropriate actions
  1466. //-----------------------------------------------------------------------------
  1467. VOID DoSystemMessage( DPMSG_GENERIC* pMsg, DWORD dwMsgSize, DPID idFrom,
  1468.                       DPID idTo )
  1469. {
  1470.     switch( pMsg->dwType )
  1471.     {
  1472.         case DPSYS_CREATEPLAYERORGROUP:
  1473.         {
  1474.             DPMSG_CREATEPLAYERORGROUP* pAddMsg = (DPMSG_CREATEPLAYERORGROUP*)pMsg;
  1475.             int iLeastAmt  = -1;
  1476.             int iLeastType = -1;
  1477.             int i;
  1478.  
  1479.             if( g_bHostPlayer)
  1480.             {
  1481.                 g_HostMsg.Blocks = g_Blocks;
  1482.                 
  1483.                 //Copy the used ship types array into the message to be sent
  1484.                 for( i = 0; i < NUM_SHIP_TYPES; i++ )
  1485.                     g_HostMsg.usedShipTypes[i] = g_ShipTypesUsed[i];
  1486.  
  1487.                 SendGameMessage( (GENERICMSG*)&g_HostMsg, pAddMsg->dpId );
  1488.             }
  1489.  
  1490.             // Loop through the used ship types array and find the one that's been used the least
  1491.             for( i = 0; i < NUM_SHIP_TYPES; i++ )
  1492.             {
  1493.                 if( (iLeastAmt < 0) || (g_ShipTypesUsed[i] < iLeastAmt) )
  1494.                 {
  1495.                     iLeastAmt = g_ShipTypesUsed[i];
  1496.                     iLeastType = i;
  1497.                 }
  1498.             }
  1499.             g_ShipTypesUsed[iLeastType]++; // update our copy of the used ship types
  1500.             break;
  1501.         }
  1502.  
  1503.         case DPSYS_DESTROYPLAYERORGROUP:
  1504.         {
  1505.             SHIP* pShip;
  1506.             DPMSG_DESTROYPLAYERORGROUP* pDestroyMsg = (DPMSG_DESTROYPLAYERORGROUP*)pMsg;
  1507.  
  1508.             if( (sizeof(SHIP) != pDestroyMsg->dwLocalDataSize) || 
  1509.                 (NULL == pDestroyMsg->lpLocalData))
  1510.                 break;
  1511.  
  1512.             pShip = (SHIP*)pDestroyMsg->lpLocalData;
  1513.             g_ShipTypesUsed[pShip->byType]--; // decrement the leaving players' ship type usage counter
  1514.             ReleasePlayerLocalSoundData(pShip);
  1515.             break;
  1516.         }
  1517.  
  1518.         case DPSYS_HOST:
  1519.         {
  1520.             g_bHostPlayer = TRUE;
  1521.             UpdateTitle();
  1522.             break;
  1523.         }
  1524.  
  1525.         case DPSYS_SESSIONLOST:
  1526.             // inform user that session was lost
  1527.             TRACE(_T("Session lost\n"));
  1528.             if( !g_bSessionLost )
  1529.             {
  1530.                 g_bSessionLost = TRUE;
  1531.                 ShowError(IDS_DPLAY_ERROR_SL);
  1532.             }
  1533.             break;
  1534.  
  1535.         case DPSYS_SENDCOMPLETE:
  1536.         // Async send status
  1537.         {
  1538.             DPMSG_SENDCOMPLETE* pComplete = (DPMSG_SENDCOMPLETE*)pMsg;
  1539.  
  1540.             if( FAILED(pComplete->hr) )
  1541.             {
  1542.                 TCHAR* strErr;
  1543.                 switch( pComplete->hr )
  1544.                 {
  1545.                     case DPERR_CANCELLED:   strErr = _T("Cancelled"); break;
  1546.                     case DPERR_ABORTED:     strErr = _T("Aborted");   break;
  1547.                     case DPERR_TIMEOUT:     strErr = _T("Timed out"); break;
  1548.                     case DPERR_GENERIC:     strErr = _T("Generic");   break;
  1549.                     default:                strErr = _T("Unknown");
  1550.                 }
  1551.                 TRACE(_T("Async msg %u to %u transmission failed. err = %s %#08X\n"),
  1552.                          pComplete->dwMsgID, pComplete->idTo, strErr,
  1553.                          pComplete->hr );
  1554.             }
  1555.             break;
  1556.         }
  1557.     }
  1558. }
  1559.  
  1560.  
  1561.  
  1562.  
  1563. //-----------------------------------------------------------------------------
  1564. // Name: DoApplicationMessage()
  1565. // Desc: Evaluates an application message and performs appropriate actions
  1566. //-----------------------------------------------------------------------------
  1567. VOID DoApplicationMessage( GENERICMSG* pMsg, DWORD dwMsgSize, DPID idFrom,
  1568.                            DPID idTo )
  1569. {        
  1570.     HRESULT hr;
  1571.  
  1572.     switch( pMsg->byType )
  1573.     {
  1574.         case MSG_HOST:
  1575.         {
  1576.             HOSTMSG* pHostMsg = (HOSTMSG*)pMsg;
  1577.             SHIP     ship;
  1578.             DWORD    dwSize = sizeof (ship);
  1579.             int      leastUsed = -1;
  1580.  
  1581.             if( !g_bHostPlayer )
  1582.             {
  1583.                 // receive the field layout
  1584.                 g_Blocks = pHostMsg->Blocks;
  1585.  
  1586.                 // The Host keeps the official record of ship colors in use.
  1587.                 // Sync up our data and recompute our color
  1588.                 hr = DPUtil_GetPlayerLocalData( g_LocalPlayerDPID, &ship, &dwSize );
  1589.  
  1590.                 // Insure that host is not a Beta version of Duel that does not
  1591.                 // send the additional ShipTypesUsed.
  1592.                 if( SUCCEEDED(hr) && dwMsgSize >= sizeof(HOSTMSG) )
  1593.                 {
  1594.                     // Loop through the used ship types array we were given,
  1595.                     // copying it and finding the least used type for ourself.
  1596.                     for( int i = 0; i < NUM_SHIP_TYPES; i++ )
  1597.                     {
  1598.                         g_ShipTypesUsed[i] = pHostMsg->usedShipTypes[i];
  1599.                         if( (leastUsed < 0) || (g_ShipTypesUsed[i] < leastUsed) )
  1600.                         {
  1601.                             leastUsed   = g_ShipTypesUsed[i];
  1602.                             ship.byType = (BYTE)i;
  1603.                         }
  1604.                     }
  1605.                     g_ShipTypesUsed[ship.byType]++; // increment it because we used one
  1606.  
  1607.                     hr = DPUtil_SetPlayerLocalData( g_LocalPlayerDPID, &ship, dwSize );
  1608.                 }
  1609.  
  1610.                 // Have host initializtion at this point
  1611.                 g_bHaveHostInit = TRUE;
  1612.                 
  1613.                 // Start updating screen
  1614.                 g_bIsActive = TRUE;
  1615.             }
  1616.             break;
  1617.         }
  1618.  
  1619.         case MSG_BLOCKHIT:
  1620.         {
  1621.             BLOCKHITMSG* pBlockHitMsg = (BLOCKHITMSG*)pMsg;
  1622.             g_Blocks.bits[pBlockHitMsg->byRow][pBlockHitMsg->byCol] &= ~pBlockHitMsg->byMask;
  1623.             break;
  1624.         }
  1625.  
  1626.         case MSG_ADDBLOCK:
  1627.         {
  1628.             ADDBLOCKMSG* pAddBlockMsg = (ADDBLOCKMSG*)pMsg;
  1629.             setBlock( pAddBlockMsg->byX, pAddBlockMsg->byY );
  1630.             break;
  1631.         }
  1632.  
  1633.         case MSG_SHIPHIT:
  1634.         {
  1635.             SHIPHITMSG* pShipHitMsg = (SHIPHITMSG*)pMsg;
  1636.             SHIP        ship;
  1637.             DWORD       dwSize;
  1638.  
  1639.             dwSize = sizeof(SHIP);
  1640.             // Get player local data
  1641.             hr = DPUtil_GetPlayerLocalData( pShipHitMsg->Id, &ship, &dwSize );
  1642.             if( FAILED(hr) )
  1643.                 return;
  1644.  
  1645.             // No player data yet
  1646.             if( 0 == dwSize )
  1647.                 return;
  1648.  
  1649.             if( !ship.bIgnore ) 
  1650.             {
  1651.                 // Explode the ship on our screen
  1652.                 DestroyShip( &ship );
  1653.  
  1654.                 // Turn it off
  1655.                 ship.bEnable       = FALSE;
  1656.                 ship.bBulletEnable = FALSE;
  1657.  
  1658.                 // If it is us
  1659.                 if( pShipHitMsg->Id == g_LocalPlayerDPID )
  1660.                 {
  1661.                     // Set our hide time-out
  1662.                     ship.iCountDown = HIDE_TIMEOUT;
  1663.                     ship.dwLastTick = timeGetTime();
  1664.                     // Let the world know that we are dead
  1665.                     g_ShipHitMsg.Id = g_LocalPlayerDPID;
  1666.                     SendGameMessage( (GENERICMSG*)&g_ShipHitMsg, DPID_ALLPLAYERS );
  1667.                 }
  1668.             }
  1669.             // Ppdate player local data
  1670.             DPUtil_SetPlayerLocalData( pShipHitMsg->Id, &ship, sizeof(ship) );
  1671.             break;
  1672.         }
  1673.  
  1674.         case MSG_CONTROL:
  1675.         {
  1676.             CONTROLMSG* pControlMsg = (CONTROLMSG*)pMsg;
  1677.             SHIP ship;
  1678.             DWORD dwSize;
  1679.  
  1680.             dwSize = sizeof(SHIP);
  1681.             // Get player local data
  1682.             hr = DPUtil_GetPlayerLocalData( idFrom, &ship, &dwSize );
  1683.             if( FAILED(hr) )
  1684.                 return;
  1685.  
  1686.             // No player data yet
  1687.             if( 0 == dwSize )
  1688.                 return;
  1689.  
  1690.             // Update its State
  1691.             UpdateState( &ship, (DWORD)pControlMsg->byState );
  1692.  
  1693.             // Save it back
  1694.             DPUtil_SetPlayerLocalData( idFrom, &ship, dwSize );
  1695.             break;
  1696.         }
  1697.  
  1698.         case MSG_SYNC:
  1699.         {
  1700.             SYNCMSG* pSyncMsg = (SYNCMSG*)pMsg;
  1701.             SHIP     ship;
  1702.             DWORD    dwSize;
  1703.  
  1704.             dwSize = sizeof(SHIP);
  1705.             // Get player local data
  1706.             hr = DPUtil_GetPlayerLocalData( idFrom, &ship, &dwSize );
  1707.             if( FAILED(hr) )
  1708.                 return;
  1709.  
  1710.             // We are seeing this player for the first time
  1711.             // so do the initialization
  1712.             if( 0 == dwSize )
  1713.             {
  1714.                 ZeroMemory( &ship, sizeof(ship) );
  1715.  
  1716.                 ship.byType     = pSyncMsg->byShipType;
  1717.                 ship.dPosX      = pSyncMsg->dPosX;
  1718.                 ship.dPosY      = pSyncMsg->dPosY;
  1719.                 ship.cFrame     = pSyncMsg->cFrame;
  1720.                 ship.dwLastTick = timeGetTime();
  1721.                 ship.bEnable    = TRUE;
  1722.             }
  1723.             
  1724.             if( ship.bEnable )
  1725.             {
  1726.                 // Head towards rendezvous location (accelerate/decelerate as necessary)
  1727.                 ship.dVelX  = (pSyncMsg->dPosX - ship.dPosX)/1000;
  1728.                 ship.dVelY  = (pSyncMsg->dPosY - ship.dPosY)/1000;
  1729.                 ship.cFrame = pSyncMsg->cFrame;
  1730.             }
  1731.             else if( !ship.bIgnore )
  1732.             {
  1733.                 // Ship is alive, but we just don't know it.
  1734.                 // So, display it at the rendezvous location.
  1735.                 ship.dPosX      = pSyncMsg->dPosX;
  1736.                 ship.dPosY      = pSyncMsg->dPosY;
  1737.                 ship.cFrame     = pSyncMsg->cFrame;
  1738.                 ship.dwLastTick = timeGetTime();
  1739.                 ship.bEnable    = TRUE;
  1740.             }
  1741.  
  1742.             // Save it back
  1743.             DPUtil_SetPlayerLocalData( idFrom, &ship, sizeof(ship) );
  1744.             break;
  1745.         }
  1746.  
  1747.         default:
  1748.         {
  1749.             TRACE( TEXT("Unknown message type %d\n"), pMsg->byType );
  1750.             break;
  1751.         }
  1752.     }
  1753. }
  1754.  
  1755.  
  1756.  
  1757.  
  1758. //-----------------------------------------------------------------------------
  1759. // Name: SendGameMessage()
  1760. // Desc: Sends a message to specified player(s)
  1761. //-----------------------------------------------------------------------------
  1762. VOID SendGameMessage( GENERICMSG* pMsg, DPID idTo )
  1763. {
  1764.     int   nBytes;
  1765.     DWORD dwFlags = 0;
  1766.  
  1767.     // No sends when we are not in the session
  1768.     if( g_bSessionLost )
  1769.         return;
  1770.  
  1771.     switch( pMsg->byType )
  1772.     {
  1773.         case MSG_HOST:
  1774.             nBytes = sizeof( HOSTMSG );
  1775.             dwFlags = DPSEND_GUARANTEED;
  1776.             break;
  1777.  
  1778.         case MSG_BLOCKHIT:
  1779.             nBytes = sizeof( BLOCKHITMSG );
  1780.             break;
  1781.  
  1782.         case MSG_SHIPHIT:
  1783.             nBytes = sizeof( SHIPHITMSG );
  1784.             break;
  1785.  
  1786.         case MSG_ADDBLOCK:
  1787.             nBytes = sizeof( ADDBLOCKMSG );
  1788.             break;
  1789.  
  1790.         case MSG_CONTROL:
  1791.             nBytes = sizeof( CONTROLMSG );
  1792.             break;
  1793.  
  1794.         case MSG_SYNC:
  1795.             nBytes = sizeof( SYNCMSG );
  1796.             break;
  1797.  
  1798.         default:
  1799.             return;
  1800.     }
  1801.  
  1802.     if( g_bAsync )
  1803.         dwFlags |= DPSEND_ASYNC;
  1804.     if( g_bReliable )
  1805.         dwFlags |= DPSEND_GUARANTEED;
  1806.  
  1807.     // Send the message to the relevant player(s)
  1808.     DPUtil_Send( g_LocalPlayerDPID, idTo, dwFlags, (VOID*)pMsg, nBytes );
  1809. }
  1810.  
  1811.  
  1812.  
  1813.  
  1814. //-----------------------------------------------------------------------------
  1815. // Name: CleanupComm()
  1816. // Desc: Cleans up communication stuff
  1817. //-----------------------------------------------------------------------------
  1818. VOID CleanupComm()
  1819. {
  1820.     HRESULT hr;
  1821.  
  1822.     // Free up all the local sound buffers
  1823.     ReleaseLocalData();
  1824.  
  1825.     // Free the receive buffer
  1826.     if( g_pvReceiveBuffer )
  1827.     {
  1828.         GlobalFreePtr(g_pvReceiveBuffer);
  1829.         g_pvReceiveBuffer = NULL;
  1830.     }
  1831.  
  1832.     // Delete our player
  1833.     if( g_LocalPlayerDPID ) 
  1834.     {
  1835.         hr = DPUtil_DestroyPlayer( g_LocalPlayerDPID );
  1836.         if( FAILED(hr) )
  1837.         {
  1838.             ShowError(IDS_DPLAY_ERROR_DP);
  1839.         }
  1840.         g_LocalPlayerDPID = 0;
  1841.     }
  1842.  
  1843.     // Cleanup DPlay objects
  1844.     hr = DPUtil_FreeDirectPlay();
  1845.     hr = DPUtil_Release();
  1846. }
  1847.  
  1848.  
  1849.  
  1850.  
  1851. //-----------------------------------------------------------------------------
  1852. // Name: InitializeGameSounds()
  1853. // Desc: 
  1854. //-----------------------------------------------------------------------------
  1855. HRESULT InitializeGameSounds()
  1856. {
  1857.     if( FAILED( DSUtil_InitDirectSound( g_hwndMain ) ) )
  1858.         return E_FAIL;
  1859.  
  1860.     g_pShipEngineSound   = DSUtil_CreateSound( TEXT("SENGINE"), 1 );
  1861.     g_pBulletFiringSound = DSUtil_CreateSound( TEXT("BFIRE"),   NUM_SHIP_TYPES );
  1862.     g_pShipExplodeSound  = DSUtil_CreateSound( TEXT("SBOOM"),   NUM_SHIP_TYPES );
  1863.     g_pShipStartSound    = DSUtil_CreateSound( TEXT("SSTART"),  NUM_SHIP_TYPES );
  1864.     g_pShipStopSound     = DSUtil_CreateSound( TEXT("SSTOP"),   NUM_SHIP_TYPES );
  1865.     g_pShipBounceSound   = DSUtil_CreateSound( TEXT("SBOUNCE"), NUM_SHIP_TYPES );
  1866.     g_pBlockExplodeSound = DSUtil_CreateSound( TEXT("LBOOM"),   NUM_SHIP_TYPES );
  1867.  
  1868.     return S_OK;
  1869. }
  1870.  
  1871.  
  1872.  
  1873.  
  1874. //-----------------------------------------------------------------------------
  1875. // Name: CleanupGameSounds()
  1876. // Desc: 
  1877. //-----------------------------------------------------------------------------
  1878. VOID CleanupGameSounds()
  1879. {
  1880.     DSUtil_DestroySound( g_pBulletFiringSound );
  1881.     DSUtil_DestroySound( g_pShipExplodeSound );
  1882.     DSUtil_DestroySound( g_pShipEngineSound );
  1883.     DSUtil_DestroySound( g_pShipStartSound );
  1884.     DSUtil_DestroySound( g_pShipStopSound );
  1885.     DSUtil_DestroySound( g_pShipBounceSound );
  1886.     DSUtil_DestroySound( g_pBlockExplodeSound );
  1887.     g_pBulletFiringSound = NULL;
  1888.     g_pShipExplodeSound  = NULL;
  1889.     g_pShipEngineSound   = NULL;
  1890.     g_pShipStartSound    = NULL;
  1891.     g_pShipStopSound     = NULL;
  1892.     g_pShipBounceSound   = NULL;
  1893.     g_pBlockExplodeSound = NULL;
  1894.  
  1895.     DSUtil_FreeDirectSound();
  1896. }
  1897.  
  1898.  
  1899.  
  1900.