GAMEPROC.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:50k
源码类别:

Windows编程

开发平台:

Visual C++

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