home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / duel / gameproc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-15  |  50.3 KB  |  2,019 lines

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