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