home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / directx2 / sdk / samples / duel / duel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-28  |  45.0 KB  |  1,780 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved.
  4.  *
  5.  *  File:       duel.c
  6.  *  Content:    Multi-player duel
  7.  *
  8.  *
  9.  ***************************************************************************/
  10. #include "duel.h"
  11.  
  12. // Duel 09438c20-e06a-11ce-8681-00aa006c5d58
  13. DEFINE_GUID(DUEL_GUID,0x09438c20,0xe06a,0x11CE,0x86,0x81,0x00,0xaa,0x00,0x6c,0x5d,0x58);
  14.  
  15. LPDIRECTPLAY            lpIDC=NULL;     // DirectPlay Object
  16. DPID                    dcoID=0;        // our DirectPlay ID
  17. LPGUID                  g_lpGuid;
  18. HANDLE                  dphEvent = NULL;
  19.  
  20. LPDIRECTDRAWSURFACE     lpFrontBuffer;
  21. LPDIRECTDRAWSURFACE     lpBackBuffer;
  22. LPDIRECTDRAWSURFACE     lpShip0;
  23. LPDIRECTDRAWSURFACE     lpShip1;
  24. LPDIRECTDRAWSURFACE     lpShip2;
  25. LPDIRECTDRAWSURFACE     lpShip3;
  26. LPDIRECTDRAWSURFACE     lpNum;
  27. LPDIRECTDRAW            lpDD;
  28. LPDIRECTDRAWPALETTE     lpArtPalette;
  29. LPDIRECTDRAWPALETTE     lpSplashPalette;
  30. int                     showDelay = 0;
  31. HWND                    hWndMain;
  32. BOOL                    bShowFrameCount=TRUE;
  33. BOOL                    bIsActive;
  34. DWORD                   dwFrameCount;
  35. DWORD                   dwFrameTime;
  36. DWORD                   dwFrames;
  37. DWORD                   dwFramesLast;
  38. BOOL                    bUseEmulation;
  39. RGBQUAD                 SPalette[256];
  40. int                     ProgramState;
  41. int                     level;
  42. int                     restCount;
  43. DWORD                   dwFillColor;
  44. BOOL                    IsHost;
  45. BOOL                    HaveHostInit;
  46. BYTE                    WhoIAm;
  47. #ifdef DEBUG
  48. char                    DebugBuf[256];
  49. BOOL                    bHELBlt = FALSE;
  50. #endif
  51.  
  52. BLOCKS                  Blocks;
  53. GLOBALSHIP              Ships[16];
  54. DWORD                   Keys;
  55. BYTE                    CommBuff[256];
  56. int                     CountDown=0;
  57. FRAG                    Frags[64];
  58.  
  59. /*
  60.  * MainWndproc
  61.  *
  62.  * Callback for all Windows messages
  63.  */
  64. long FAR PASCAL MainWndproc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  65. {
  66.     PAINTSTRUCT ps;
  67.     HDC         hdc;
  68.  
  69.     switch( message )
  70.     {
  71.     case WM_ACTIVATEAPP:
  72.         bIsActive = (BOOL) wParam;
  73.         break;
  74.  
  75.     case WM_CREATE:
  76.         break;
  77.  
  78.     case WM_SETCURSOR:
  79.         SetCursor(NULL);
  80.         return TRUE;
  81.  
  82.     case WM_KEYDOWN:
  83.         switch( wParam )
  84.         {
  85.         case VK_NUMPAD5:
  86.             Keys |= KEY_STOP;
  87.             break;
  88.         case VK_DOWN:
  89.         case VK_NUMPAD2:
  90.             Keys |= KEY_DOWN;
  91.             break;
  92.         case VK_LEFT:
  93.         case VK_NUMPAD4:
  94.             Keys |= KEY_LEFT;
  95.             break;
  96.         case VK_RIGHT:
  97.         case VK_NUMPAD6:
  98.             Keys |= KEY_RIGHT;
  99.             break;
  100.         case VK_UP:
  101.         case VK_NUMPAD8:
  102.             Keys |= KEY_UP;
  103.             break;
  104.         case VK_SPACE:
  105.             Keys |= KEY_FIRE;
  106.             break;
  107.         case VK_F5:
  108.             bShowFrameCount = !bShowFrameCount;
  109.             if( bShowFrameCount )
  110.             {
  111.                 dwFrameCount = 0;
  112.                 dwFrameTime = timeGetTime();
  113.             }
  114.             break;
  115.         case VK_RETURN:
  116.             if( ProgramState == PS_SPLASH )
  117.             {
  118.                 lpDD->lpVtbl->FlipToGDISurface( lpDD );
  119.                 if ( RemoteCreate(DUEL_GUID, "Duel", "Ship") )
  120.                 {
  121.                     ProgramState = PS_REST;
  122.                     // set the palette
  123.                     if( !IsHost )
  124.                     {
  125.                         SendGameMessage(MSG_HEREIAM, 0, 0, 0, 0);
  126.                         HaveHostInit = FALSE;
  127.                     }
  128.                     else
  129.                     {
  130.                         HaveHostInit = TRUE;
  131.                         WhoIAm = 0;
  132.                         InitGame();
  133.                     }
  134.                 }
  135.             }
  136.             break;
  137.         case VK_ESCAPE:
  138.         case VK_F12:
  139.             PostMessage( hWnd, WM_CLOSE, 0, 0 );
  140.             return 0;
  141.         }
  142.         break;
  143.  
  144.     case WM_KEYUP:
  145.         switch( wParam )
  146.         {
  147.         case VK_NUMPAD5:
  148.             Keys &= ~KEY_STOP;
  149.             break;
  150.         case VK_DOWN:
  151.         case VK_NUMPAD2:
  152.             Keys &= ~KEY_DOWN;
  153.             break;
  154.         case VK_LEFT:
  155.         case VK_NUMPAD4:
  156.             Keys &= ~KEY_LEFT;
  157.             break;
  158.         case VK_RIGHT:
  159.         case VK_NUMPAD6:
  160.             Keys &= ~KEY_RIGHT;
  161.             break;
  162.         case VK_UP:
  163.         case VK_NUMPAD8:
  164.             Keys &= ~KEY_UP;
  165.             break;
  166.         case VK_SPACE:
  167.             Keys &= ~KEY_FIRE;
  168.             break;
  169.         }
  170.         break;
  171.  
  172.     case WM_ERASEBKGND:
  173.         return 1;
  174.  
  175.     case WM_PAINT:
  176.         hdc = BeginPaint( hWnd, &ps );
  177.         EndPaint( hWnd, &ps );
  178.         return 1;
  179.  
  180.     case WM_DESTROY:
  181.         DestroyGame();
  182.         PostQuitMessage( 0 );
  183.         break;
  184.  
  185.     default:
  186.         break;
  187.     }
  188.     return DefWindowProc(hWnd, message, wParam, lParam);
  189.  
  190. } /* MainWndproc */
  191.  
  192. /*
  193.  * initApplication
  194.  *
  195.  * Do that Windows initialization stuff...
  196.  */
  197. static BOOL initApplication( HINSTANCE hInstance, int nCmdShow )
  198. {
  199.     WNDCLASS    wc;
  200.     BOOL        rc;
  201.  
  202.     wc.style = CS_DBLCLKS;
  203.     wc.lpfnWndProc = MainWndproc;
  204.     wc.cbClsExtra = 0;
  205.     wc.cbWndExtra = 0;
  206.     wc.hInstance = hInstance;
  207.     wc.hIcon = LoadIcon( hInstance, "DUEL_ICON");
  208.     wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  209.     wc.hbrBackground = GetStockObject( BLACK_BRUSH );
  210.     wc.lpszMenuName =  NULL;
  211.     wc.lpszClassName = "DuelClass";
  212.     rc = RegisterClass( &wc );
  213.     if( !rc )
  214.     {
  215.         return FALSE;
  216.     }
  217.  
  218.     hWndMain = CreateWindowEx(0,  // WS_EX_TOPMOST,
  219.         "DuelClass",
  220.         "Duel",
  221.         WS_VISIBLE | // so we don't have to call ShowWindow
  222.         WS_POPUP |   // non-app window POPUP
  223.         WS_SYSMENU,  // so we get an icon in the tray
  224.         0,
  225.         0,
  226.         GetSystemMetrics(SM_CXSCREEN),
  227.         GetSystemMetrics(SM_CYSCREEN),
  228.         NULL,
  229.         NULL,
  230.         hInstance,
  231.         NULL );
  232.  
  233.     if( !hWndMain )
  234.     {
  235.         return FALSE;
  236.     }
  237.  
  238.     UpdateWindow( hWndMain );
  239.  
  240.     return TRUE;
  241.  
  242. } /* initApplication */
  243.  
  244. /*
  245.  * WinMain
  246.  */
  247. int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
  248.                         int nCmdShow )
  249. {
  250.     MSG     msg;
  251.  
  252.     if( lpCmdLine[0] == '-' )
  253.     {
  254.         bUseEmulation = TRUE;
  255.     }
  256.  
  257.     if( !initApplication(hInstance, nCmdShow) )
  258.     {
  259.         return FALSE;
  260.     }
  261.  
  262.     if( !InitializeGame() )
  263.     {
  264.         DestroyWindow( hWndMain );
  265.         return FALSE;
  266.     }
  267.  
  268.     dwFrameTime = timeGetTime();
  269.  
  270.     while( 1 )
  271.     {
  272.         if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  273.         {
  274.             if( !GetMessage( &msg, NULL, 0, 0 ) )
  275.             {
  276.                 return msg.wParam;
  277.             }
  278.             TranslateMessage(&msg);
  279.             DispatchMessage(&msg);
  280.         }
  281.         else
  282.         {
  283.             ReceiveGameMessages();
  284.             if( bIsActive )
  285.             {
  286.                 UpdateFrame();
  287.             }
  288.         }
  289.     }
  290. } /* WinMain */
  291.  
  292.  
  293. void DestroyGame( void )
  294. {
  295.     if( dcoID != 0 )
  296.     {
  297.         lpIDC->lpVtbl->DestroyPlayer(lpIDC, dcoID);
  298.     }
  299. }
  300.  
  301. BOOL InitializeGame( void )
  302. {
  303.     DDCAPS          ddcaps;
  304.     HRESULT         ddrval;
  305.     DDSURFACEDESC   ddsd;
  306.     DDSCAPS         ddscaps;
  307.  
  308.     if( bUseEmulation )
  309.         ddrval = DirectDrawCreate( (LPVOID) DDCREATE_EMULATIONONLY, &lpDD, NULL );
  310.     else
  311.         ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
  312.  
  313.     if( ddrval != DD_OK )
  314.         return CleanupAndExit(1);
  315.  
  316.     ddrval = lpDD->lpVtbl->SetCooperativeLevel( lpDD, hWndMain,
  317.                             DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
  318.     if( ddrval != DD_OK )
  319.         return CleanupAndExit(2);
  320.  
  321.     // set the mode to 640 by 480 by 8
  322. #ifdef DEBUG
  323.     if( GetProfileInt( "Duel", "force_16_bit", 0) )
  324.     {
  325.         ddrval = lpDD->lpVtbl->SetDisplayMode( lpDD, 640, 480, 16 );
  326.     }
  327.     else
  328. #endif
  329.     {
  330.         ddrval = lpDD->lpVtbl->SetDisplayMode( lpDD, 640, 480, 8 );
  331.     }
  332.     if( ddrval != DD_OK )
  333.         return CleanupAndExit(3);
  334.  
  335.     // check the color key hardware capabilities
  336.     ddcaps.dwSize = sizeof( ddcaps );
  337.  
  338. #ifdef DEBUG
  339.     bHELBlt = GetProfileInt( "Duel", "force_HEL_blt", bHELBlt );
  340. #endif
  341.  
  342.     // Create surfaces
  343.     memset( &ddsd, 0, sizeof( ddsd ) );
  344.     ddsd.dwSize = sizeof( ddsd );
  345.     ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  346.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
  347.                           DDSCAPS_FLIP |
  348.                           DDSCAPS_COMPLEX;
  349.     ddsd.dwBackBufferCount = 1;
  350.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL );
  351.     if( ddrval != DD_OK )
  352.         return CleanupAndExit(4);
  353.  
  354.     // get a pointer to the back buffer
  355.     ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  356.     ddrval = lpFrontBuffer->lpVtbl->GetAttachedSurface(
  357.                 lpFrontBuffer,
  358.                 &ddscaps,
  359.                 &lpBackBuffer );
  360.     if( ddrval != DD_OK )
  361.         return CleanupAndExit(5);
  362.  
  363.     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;        
  364.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  365. #ifdef DEBUG
  366.     if( bHELBlt )
  367.         ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  368. #endif
  369.  
  370.     ddsd.dwWidth = 320;
  371.     ddsd.dwHeight = 128;
  372.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpShip0, NULL );
  373.     if( ddrval != DD_OK )
  374.         return CleanupAndExit(6);
  375.  
  376.     ddsd.dwWidth = 320;
  377.     ddsd.dwHeight = 128;
  378.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpShip1, NULL );
  379.     if( ddrval != DD_OK )
  380.         return CleanupAndExit(7);
  381.  
  382.     ddsd.dwWidth = 320;
  383.     ddsd.dwHeight = 128;
  384.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpShip2, NULL );
  385.     if( ddrval != DD_OK )
  386.         return CleanupAndExit(8);
  387.  
  388.     ddsd.dwWidth = 320;
  389.     ddsd.dwHeight = 128;
  390.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpShip3, NULL );
  391.     if( ddrval != DD_OK )
  392.         return CleanupAndExit(9);
  393.  
  394.     ddsd.dwHeight = 16;
  395.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpNum, NULL );
  396.     if( ddrval != DD_OK )
  397.         return CleanupAndExit(10);
  398.  
  399.     if( !RestoreSurfaces() )
  400.         return CleanupAndExit(11);
  401.         
  402.     Keys = 0;
  403.     ProgramState = PS_SPLASH;
  404.     return TRUE;
  405. }
  406.  
  407. BOOL CleanupAndExit( int err)
  408. {
  409.     char buf[256];
  410.     
  411. #ifdef DEBUG
  412.     wsprintf(DebugBuf, "___CleanupAndExit  err = %d\n", err );
  413.     OutputDebugString( DebugBuf );
  414. #endif
  415.  
  416.     if( lpShip0 != NULL )
  417.         lpShip0->lpVtbl->Release( lpShip0 );
  418.         
  419.     if( lpShip1 != NULL )
  420.         lpShip1->lpVtbl->Release( lpShip1 );
  421.         
  422.     if( lpShip2 != NULL )
  423.         lpShip2->lpVtbl->Release( lpShip2 );
  424.         
  425.     if( lpShip3 != NULL )
  426.         lpShip3->lpVtbl->Release( lpShip3 );
  427.         
  428.     if( lpNum != NULL )
  429.         lpNum->lpVtbl->Release( lpNum );
  430.         
  431.     if( lpFrontBuffer != NULL )
  432.         lpFrontBuffer->lpVtbl->Release( lpFrontBuffer );
  433.         
  434.     if( lpArtPalette != NULL )
  435.         lpArtPalette->lpVtbl->Release( lpArtPalette );
  436.         
  437.     if( lpSplashPalette != NULL )
  438.         lpSplashPalette->lpVtbl->Release( lpSplashPalette );
  439.         
  440.     if( lpDD != NULL )
  441.         lpDD->lpVtbl->Release( lpDD );
  442.  
  443.     wsprintf(buf, "Game could not start (%d)", err);
  444.     MessageBox( hWndMain, buf, "ERROR", MB_OK );
  445.     return FALSE;
  446. }
  447.  
  448. void bltSplash( LPRECT rc)
  449. {
  450.     HRESULT     ddrval;
  451.     HBITMAP     hbm;
  452.  
  453.     if( ( lpFrontBuffer == NULL ) ||
  454.         ( lpSplashPalette == NULL ) ||
  455.         ( lpBackBuffer == NULL ) )
  456.     {
  457.         return;
  458.     }
  459.  
  460.     // set the palette before loading the splash screen
  461.     lpFrontBuffer->lpVtbl->SetPalette( lpFrontBuffer, lpSplashPalette );
  462.  
  463.     hbm = (HBITMAP)LoadImage( GetModuleHandle( NULL ), "SPLASH", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
  464.     if ( NULL == hbm )
  465.         return;
  466.         
  467.     // if the surface is lost, DDCopyBitmap will fail and the surface will
  468.     // be restored below.
  469.     ddrval = DDCopyBitmap( lpBackBuffer, hbm, 0, 0, 0, 0 );
  470.  
  471.     DeleteObject( hbm );
  472.  
  473.     while( 1 )
  474.     {
  475.         if( rc != NULL )
  476.         {
  477.             ddrval = lpFrontBuffer->lpVtbl->BltFast( lpFrontBuffer, 
  478.                 rc->left, rc->top, lpBackBuffer, rc, 0);
  479.         }
  480.         else
  481.         {
  482.             ddrval = lpFrontBuffer->lpVtbl->BltFast( lpFrontBuffer, 
  483.                 0, 0, lpBackBuffer, NULL, 0);
  484.         }
  485.         if( ddrval == DD_OK )
  486.             return;
  487.         if( ddrval == DDERR_SURFACELOST )
  488.             if( !RestoreSurfaces() )
  489.                 return;
  490.         if( ddrval != DDERR_WASSTILLDRAWING )
  491.             return;
  492.     }
  493. }
  494.  
  495. void UpdateFrame( void )
  496. {
  497.     int i;
  498.     
  499.     switch( ProgramState )
  500.     {
  501.         case PS_SPLASH:
  502.             // display the splash screen
  503.             bltSplash(NULL);
  504.             return;
  505.         case PS_ACTIVE:
  506.             ReadKey();
  507.             for(i=0; i<16; i++)
  508.                 UpdatePosition(&Ships[i]);
  509.             for(i=0; i<64; i++)
  510.                 UpdateFragment(i);
  511.             SendGameMessage(MSG_UPDATE, 0, 0, 0, 0);
  512.             DrawScreen();
  513.             return;
  514.         case PS_REST:
  515.             if( HaveHostInit )
  516.             {
  517.                 lpFrontBuffer->lpVtbl->SetPalette( lpFrontBuffer, lpArtPalette );
  518.                 ProgramState = PS_ACTIVE;
  519.             }
  520.             break;
  521.     }
  522. }
  523.  
  524. void ReadKey( void )
  525. {
  526.     if( Keys & KEY_LEFT )
  527.     {
  528.         Ships[WhoIAm].frame -= 0.5;
  529.         if( Ships[WhoIAm].frame < 0.0 )
  530.             Ships[WhoIAm].frame += MAX_SHIP_FRAME;
  531.     }
  532.     if( Keys & KEY_RIGHT )
  533.     {
  534.         Ships[WhoIAm].frame += 0.5;
  535.         if( Ships[WhoIAm].frame >= MAX_SHIP_FRAME )
  536.             Ships[WhoIAm].frame -= MAX_SHIP_FRAME;
  537.     }
  538.     if( Keys & KEY_UP )
  539.     {
  540.         Ships[WhoIAm].velx += Dirx[(int)Ships[WhoIAm].frame] * 10.0 / 1000.0;
  541.         Ships[WhoIAm].vely += Diry[(int)Ships[WhoIAm].frame] * 10.0 / 1000.0;
  542.     }
  543.     if( Keys & KEY_DOWN )
  544.     {
  545.         Ships[WhoIAm].velx -= Dirx[(int)Ships[WhoIAm].frame] * 10.0 / 1000.0;
  546.         Ships[WhoIAm].vely -= Diry[(int)Ships[WhoIAm].frame] * 10.0 / 1000.0;
  547.     }
  548.     if( Keys & KEY_STOP )
  549.     {
  550.         Ships[WhoIAm].velx = 0.0;
  551.         Ships[WhoIAm].vely = 0.0;
  552.     }
  553.     if( !Ships[WhoIAm].benable && Ships[WhoIAm].enable )
  554.     {
  555.         if( Keys & KEY_FIRE )
  556.         {
  557.             // launch a new bullet
  558.             Ships[WhoIAm].bposx = Dirx[(int)Ships[WhoIAm].frame]*6.0 + 16.0 + Ships[WhoIAm].posx;
  559.             Ships[WhoIAm].bposy = Diry[(int)Ships[WhoIAm].frame]*6.0 + 16.0 + Ships[WhoIAm].posy;
  560.             Ships[WhoIAm].bvelx = Dirx[(int)Ships[WhoIAm].frame]*500.0/1000.0;
  561.             Ships[WhoIAm].bvely = Diry[(int)Ships[WhoIAm].frame]*500.0/1000.0;
  562.             Ships[WhoIAm].benable = TRUE;
  563.             Ships[WhoIAm].bframe = 0;
  564.         }
  565.     }
  566. }
  567.  
  568. void UpdatePosition( LPGLOBALSHIP ship )
  569. {
  570.     int     x,y,j;
  571.     BYTE    mask, col, row, oldxCell, oldyCell, newxCell, newyCell;
  572.     double  thisTick, totalTick, xtick, ytick;
  573.     DWORD   TickCnt;
  574.     DWORD   tickDiff;
  575.     LPGLOBALSHIP  target;
  576.     
  577.     TickCnt = GetTickCount();
  578.     tickDiff = TickCnt - ship->lastTick;
  579.     ship->lastTick = TickCnt;
  580.         
  581.     if( ship == &(Ships[WhoIAm]) && !ship->enable)
  582.     {
  583.         CountDown -= tickDiff;
  584.         if( CountDown < 0 )
  585.         {
  586.             Ships[WhoIAm].enable = TRUE;
  587.         }
  588.     }
  589.  
  590.     if( !ship->enable )
  591.         return;
  592.         
  593.     if( ( (TickCnt - ship->timeStamp ) > 2000 ) &&
  594.         ( ship != &(Ships[WhoIAm]) ) )
  595.     {
  596.         ship->enable = FALSE;
  597.         return;
  598.     }
  599.         
  600.     
  601.     // incrementally update the position of the ship
  602.     // find out the number of ticks needed to move 8 pixels
  603.     if( ship->velx != 0.0 )
  604.         xtick = 8.0/ship->velx;
  605.     else
  606.         xtick = 999999.0;
  607.  
  608.     if( ship->vely != 0.0 )
  609.         ytick = 8.0/ship->vely;
  610.     else
  611.         ytick = 999999.0;
  612.  
  613.     if( xtick < 0.0 )
  614.         xtick = -xtick;
  615.     if( ytick < 0.0 )
  616.         ytick = -ytick;
  617.  
  618.     if( xtick < ytick )
  619.         thisTick = xtick;
  620.     else
  621.         thisTick = ytick;
  622.         
  623.     if( thisTick > tickDiff )
  624.         thisTick = tickDiff;
  625.                 
  626.     for( totalTick = 0.0; totalTick < tickDiff; )
  627.     {
  628.         totalTick += tickDiff;
  629.         oldxCell = (int)(ship->posx+16.0) >> 4;
  630.         oldyCell = (int)(ship->posy+16.0) >> 4;
  631.         ship->posx += ship->velx * thisTick;
  632.         ship->posy += ship->vely * thisTick;
  633.         newxCell = (int)(ship->posx+16.0) >> 4;
  634.         newyCell = (int)(ship->posy+16.0) >> 4;
  635.         if(oldxCell != newxCell)
  636.         {
  637.             if( IsHit( newxCell, newyCell ) )
  638.             {
  639.                 if( ship->velx > 0.0 )
  640.                     ship->posx = (oldxCell << 4) + 15 - 16;
  641.                 else
  642.                     ship->posx = (oldxCell << 4) - 16;
  643.                 ship->velx = -ship->velx*0.9;
  644.                 newxCell = oldxCell;
  645.             }
  646.         }
  647.         if(oldyCell != newyCell)
  648.         {
  649.             if( IsHit( newxCell, newyCell ) )
  650.             {
  651.                 if( ship->vely > 0.0 )
  652.                     ship->posy = (oldyCell << 4) + 15 - 16;
  653.                 else
  654.                     ship->posy = (oldyCell << 4) - 16;
  655.                 ship->vely = -ship->vely*0.9;
  656.             }
  657.         }
  658.         if( ship->posx > MAX_SHIP_X )
  659.         {
  660.             ship->posx = MAX_SHIP_X;
  661.             ship->velx = -ship->velx*0.9;
  662.         }
  663.         else if ( ship->posx < 0 )
  664.         {
  665.             ship->posx =0;
  666.             ship->velx = -ship->velx*0.9;
  667.         }
  668.         if( ship->posy > MAX_SHIP_Y )
  669.         {
  670.             ship->posy = MAX_SHIP_Y;
  671.             ship->vely = -ship->vely*0.9;
  672.         }
  673.         else if ( ship->posy < 0 )
  674.         {
  675.             ship->posy =0;
  676.             ship->vely = -ship->vely*0.9;
  677.         }
  678.     }
  679.  
  680.     if( !ship->benable )
  681.         return;
  682.  
  683.     // update the active bullet
  684.     ship->bframe += tickDiff;
  685.     if( ship->bframe >= MAX_BULLET_FRAME )
  686.     {
  687.         ship->benable = FALSE;
  688.         return;
  689.     }
  690.  
  691.     if( ship->bvelx != 0.0 )
  692.         xtick = 8.0/ship->bvelx;
  693.     else
  694.         xtick = 999999.0;
  695.  
  696.     if( ship->bvely != 0.0 )
  697.         ytick = 8.0/ship->bvely;
  698.     else
  699.         ytick = 999999.0;
  700.  
  701.     if( xtick < 0.0 )
  702.         xtick = -xtick;
  703.     if( ytick < 0.0 )
  704.         ytick = -ytick;
  705.  
  706.     if( xtick < ytick )
  707.         thisTick = xtick;
  708.     else
  709.         thisTick = ytick;
  710.         
  711.     if( thisTick > tickDiff )
  712.         thisTick = tickDiff;
  713.                 
  714.     for( totalTick = 0.0; totalTick < tickDiff; )
  715.     {
  716.         totalTick += thisTick;
  717.  
  718.         ship->bposx += ship->bvelx * thisTick;
  719.         ship->bposy += ship->bvely * thisTick;
  720.         
  721.         // see if it hit a ship
  722.         for(j=0; j<16; j++)
  723.         {
  724.             target = &(Ships[j]);
  725.             if( ( target == ship ) || !target->enable )
  726.                 continue;
  727.             if( (ship->bposx > target->posx) &&
  728.                 (ship->bposx < (target->posx + 32.0) ) &&
  729.                 (ship->bposy > target->posy) &&
  730.                 (ship->bposy < (target->posy + 32.0) ) )
  731.             {
  732.                 SendGameMessage(MSG_SHIPHIT, 0, (BYTE)j, 0, 0);
  733.                 DestroyShip( j );
  734.                 target->enable = FALSE;
  735.                 ship->benable = FALSE;
  736.                 ship->score += 1000;
  737.                 return;
  738.             }
  739.         }
  740.     
  741.         if( ship->bposx > MAX_BULLET_X )
  742.         {
  743.             ship->bposx = MAX_BULLET_X;
  744.             ship->bvelx = -ship->bvelx*0.9;
  745.         }
  746.         else if ( ship->bposx < 0 )
  747.         {
  748.             ship->bposx =0;
  749.             ship->bvelx = -ship->bvelx*0.9;
  750.         }
  751.         if( ship->bposy > MAX_BULLET_Y )
  752.         {
  753.             ship->bposy = MAX_BULLET_Y;
  754.             ship->bvely = -ship->bvely*0.9;
  755.         }
  756.         else if ( ship->bposy < 0 )
  757.         {
  758.             ship->bposy =0;
  759.             ship->bvely = -ship->bvely*0.9;
  760.         }
  761.     
  762.         // check to see if it hit anything
  763.         x = (int)(ship->bposx + 0.5) + 1;
  764.         y = (int)(ship->bposy + 0.5) + 1;
  765.         
  766.         row = y >> 4;
  767.         col = x >> 4;
  768.         mask = 1 << (col & 0x7);
  769.         col = col >> 3;
  770.         if( Blocks.bits[row][col] & mask )
  771.         {
  772.             // scored a block hit
  773.             SendGameMessage(MSG_BLOCKHIT, 0, row, col, mask);
  774.             Blocks.bits[row][col] &= ~mask;
  775.             ship->score += 10;
  776.             ship->benable = FALSE;
  777.             return;
  778.         }
  779.     }
  780. }
  781.  
  782. BOOL IsHit( int x, int y )
  783. {
  784.     int col, mask;
  785.     
  786.     // outside screen boundaries?
  787.     if( (x < 0) || (y < 0) || (x >= 40) || (y >= 30) )
  788.         return TRUE;
  789.         
  790.     // look at the block bits
  791.     mask = 1 << (x & 0x7);
  792.     col = x >> 3;
  793.     if( Blocks.bits[y][col] & mask )
  794.         return TRUE;
  795.     else
  796.         return FALSE;
  797. }
  798.  
  799. void DrawScreen( void )
  800. {
  801.     int     i;
  802.     BYTE    mask, col;
  803.     int     x, y;
  804.  
  805.     EraseScreen();
  806.     
  807.     for(i=0; i<16; i++)
  808.     {
  809.         if( Ships[i].benable )
  810.         {
  811.             DrawBullet( i );
  812.         }
  813.     }
  814.     
  815.     for(i=0; i<16; i++)
  816.     {
  817.         if( Ships[i].enable )
  818.         {
  819.             DrawShip( i );
  820.         }
  821.     }
  822.  
  823.     for( y=0; y<30; y++)
  824.     {
  825.         for( x=0; x<40; x++)
  826.         {
  827.             mask = 1 << (x & 0x7);
  828.             col = x >> 3;
  829.             if( Blocks.bits[y][col] & mask )
  830.                 DrawBlock( x, y );
  831.         }
  832.     }
  833.     
  834.     DrawScore();
  835.  
  836.     DrawFragments();    
  837.     if( bShowFrameCount )
  838.         DisplayFrameRate();
  839.  
  840.     FlipScreen();
  841. }
  842.  
  843. void DrawScore( void )
  844. {
  845.     char        scorebuf[11];
  846.     int         rem;
  847.  
  848.     // blt everything in reverse order if we are doing destination transparency
  849.     // calculate score string
  850.     scorebuf[0] = Ships[WhoIAm].score/100000 + '0';
  851.     rem = Ships[WhoIAm].score % 100000;
  852.     scorebuf[1] = rem/10000 + '0';
  853.     rem = Ships[WhoIAm].score % 10000;
  854.     scorebuf[2] = rem/1000 + '0';
  855.     rem = Ships[WhoIAm].score % 1000;
  856.     scorebuf[3] = rem/100 + '0';
  857.     rem = Ships[WhoIAm].score % 100;
  858.     scorebuf[4] = rem/10 + '0';
  859.     rem = Ships[WhoIAm].score % 10;
  860.     scorebuf[5] = rem + '0';
  861.     scorebuf[6] = '\0';
  862.  
  863.     bltScore(scorebuf, 8, 8);
  864. }
  865.  
  866. void DrawBlock( int x, int y )
  867. {
  868.     RECT    src;
  869.     
  870.     src.top = 0;
  871.     src.left = 224;
  872.     src.right = src.left + 16;
  873.     src.bottom = src.top + 16;
  874.     bltObject( x << 4, y << 4, lpNum, &src, DDBLTFAST_SRCCOLORKEY );
  875. }
  876.  
  877. void DrawShip( int i )
  878. {
  879.     RECT    src;
  880.     LPDIRECTDRAWSURFACE surf;
  881.     
  882.     src.top = 32 * ( (int)Ships[i].frame / 10 );
  883.     src.left = 32 * ( (int)Ships[i].frame % 10 );
  884.     src.right = src.left + 32;
  885.     src.bottom = src.top + 32;
  886.     switch( i % 4 )
  887.     {
  888.     case 0: surf = lpShip0; break;
  889.     case 1: surf = lpShip1; break;
  890.     case 2: surf = lpShip2; break;
  891.     case 3: surf = lpShip3; break;
  892.     }
  893.     bltObject( (int)Ships[i].posx, (int)Ships[i].posy, surf, &src, DDBLTFAST_SRCCOLORKEY );
  894. }
  895.  
  896. void DrawBullet( int i )
  897. {
  898.     RECT    src;
  899.     
  900.     src.top = BULLET_Y;
  901.     src.left = BULLET_X + (i%4)*4;
  902.     src.right = src.left + 3;
  903.     src.bottom = src.top + 3;
  904.     bltObject( (int)Ships[i].bposx, (int)Ships[i].bposy, lpNum, &src, DDBLTFAST_SRCCOLORKEY );
  905. }
  906.  
  907. void bltScore( char *num, int x, int y )
  908. {
  909.     char *c;
  910.     RECT    src;
  911.     int     i;
  912.  
  913.     for(c=num; *c != '\0'; c++)
  914.     {
  915.         i = *c - '0';
  916.         src.left = i*16;
  917.         src.top = 0;
  918.         src.right = src.left + 16;
  919.         src.bottom = src.top + 16;
  920.         bltObject( x, y, lpNum, &src, DDBLTFAST_SRCCOLORKEY );
  921.         x += 16;
  922.     }
  923. }
  924.  
  925. void bltObject( int x, int y, LPDIRECTDRAWSURFACE surf, LPRECT src, DWORD flags )
  926. {
  927.     HRESULT ddrval;
  928.  
  929.     while( 1 )
  930.     {
  931.         ddrval = lpBackBuffer->lpVtbl->BltFast( lpBackBuffer, x, y, surf, src, flags );
  932.         if( ddrval == DD_OK )
  933.             return;
  934.         if( ddrval == DDERR_SURFACELOST )
  935.             if( !RestoreSurfaces() )
  936.                 return;
  937.         if( ddrval != DDERR_WASSTILLDRAWING )
  938.             return;
  939.     }
  940. }
  941.  
  942. void EraseScreen( void )
  943. {
  944.     DDBLTFX     ddbltfx;
  945.     HRESULT     ddrval;
  946.  
  947.     // Erase the background
  948.     ddbltfx.dwSize = sizeof( ddbltfx );
  949.     ddbltfx.dwFillColor = dwFillColor;
  950.     while( 1 )
  951.     {
  952.         ddrval = lpBackBuffer->lpVtbl->Blt( lpBackBuffer, NULL, NULL,
  953.                  NULL, DDBLT_COLORFILL, &ddbltfx );
  954.  
  955.         if( ddrval == DD_OK )
  956.         {
  957.             break;
  958.         }
  959.         if( ddrval == DDERR_SURFACELOST )
  960.         {
  961.             if( !RestoreSurfaces() )
  962.                 return;
  963.         }
  964.         if( ddrval != DDERR_WASSTILLDRAWING )
  965.         {
  966.             return;
  967.         }
  968.     }
  969. }
  970.  
  971. void FlipScreen( void )
  972. {
  973.     HRESULT     ddrval;
  974.  
  975.     // Flip the surfaces
  976.     while( 1 )
  977.     {
  978.         ddrval = lpFrontBuffer->lpVtbl->Flip( lpFrontBuffer, NULL, 0 );
  979.         if( ddrval == DD_OK )
  980.         {
  981.             break;
  982.         }
  983.         if( ddrval == DDERR_SURFACELOST )
  984.         {
  985.             if( !RestoreSurfaces() )
  986.             {
  987.                 return;
  988.             }
  989.         }
  990.         if( ddrval != DDERR_WASSTILLDRAWING )
  991.         {
  992.             break;
  993.         }
  994.     }
  995. }
  996.  
  997. void DisplayFrameRate( void )
  998. {
  999.     DWORD               time2;
  1000.     char                buff[256];
  1001.  
  1002.     dwFrameCount++;
  1003.     time2 = timeGetTime() - dwFrameTime;
  1004.     if( time2 > 1000 )
  1005.     {
  1006.         dwFrames = (dwFrameCount*1000)/time2;
  1007.         dwFrameTime = timeGetTime();
  1008.         dwFrameCount = 0;
  1009.     }
  1010.     if( dwFrames == 0 )
  1011.     {
  1012.         return;
  1013.     }
  1014.  
  1015.     if (dwFrames != dwFramesLast)
  1016.     {
  1017.         dwFramesLast = dwFrames;
  1018.     }
  1019.  
  1020.     if( dwFrames > 99 )
  1021.     {
  1022.         dwFrames = 99;
  1023.     }
  1024.     buff[0] = (char)((dwFrames / 10) + '0');
  1025.     buff[1] = (char)((dwFrames % 10) + '0');
  1026.     buff[2] = '\0';
  1027.     bltScore(buff, 295, 10);
  1028. }
  1029.  
  1030. void InitGame(void)
  1031. {
  1032.     int i, x, y;
  1033.     
  1034.     // clear all blocks
  1035.     for(x=0; x<5; x++)
  1036.         for(y=0; y<30; y++)
  1037.             Blocks.bits[y][x] = 0;
  1038.  
  1039.     // set random blocks
  1040.     for(i=0; i<400; i++)
  1041.     {
  1042.         x = randInt(0, 40);
  1043.         y = randInt(0, 30);
  1044.         if( !setBlock(x, y) )
  1045.             i--;
  1046.     }
  1047.  
  1048.     // initialize the host ship
  1049.     initShip(&(Ships[0]));
  1050. }
  1051.         
  1052. BOOL setBlock( int x, int y )
  1053. {
  1054.     BYTE  mask, col;
  1055.  
  1056.     mask = 1 << (x & 0x7);
  1057.     col = x >> 3;
  1058.     
  1059.     // is Block already set?
  1060.     if( Blocks.bits[y][col] & mask )
  1061.         return FALSE;
  1062.         
  1063.     // set the block and return success
  1064.     Blocks.bits[y][col] |= mask;
  1065.     return TRUE;
  1066. }
  1067.         
  1068. void initShip( LPGLOBALSHIP ship )
  1069. {
  1070.     int i;
  1071.     
  1072.     ship->velx = ship->vely = 0.0;
  1073.  
  1074.     ship->enable = TRUE;
  1075.     ship->posx = HomeX[WhoIAm];
  1076.     ship->posy = HomeY[WhoIAm];
  1077.     ship->frame = HomeFrame[WhoIAm];
  1078.     ship->benable = FALSE;
  1079.     ship->timeStamp = GetTickCount();
  1080.     ship->lastTick = ship->timeStamp;
  1081.     
  1082.     // no ship fragments
  1083.     for(i=0; i<64; i++)
  1084.         Frags[i].valid = FALSE;
  1085. }
  1086.  
  1087. BOOL RestoreSurfaces( void )
  1088. {
  1089.     HRESULT     ddrval;
  1090.     HBITMAP     hbm;
  1091.  
  1092.     ddrval = lpFrontBuffer->lpVtbl->Restore(lpFrontBuffer);
  1093.     if( ddrval != DD_OK )
  1094.         return FALSE;
  1095.     ddrval = lpShip0->lpVtbl->Restore(lpShip0);
  1096.     if( ddrval != DD_OK )
  1097.         return FALSE;
  1098.     ddrval = lpShip1->lpVtbl->Restore(lpShip1);
  1099.     if( ddrval != DD_OK )
  1100.         return FALSE;
  1101.     ddrval = lpShip2->lpVtbl->Restore(lpShip2);
  1102.     if( ddrval != DD_OK )
  1103.         return FALSE;
  1104.     ddrval = lpShip3->lpVtbl->Restore(lpShip3);
  1105.     if( ddrval != DD_OK )
  1106.         return FALSE;
  1107.     ddrval = lpNum->lpVtbl->Restore(lpNum);
  1108.     if( ddrval != DD_OK )
  1109.         return FALSE;
  1110.  
  1111.     // Create and set the palette for the splash bitmap
  1112.     lpSplashPalette = DDLoadPalette( lpDD, "SPLASH" );
  1113.     if( NULL == lpSplashPalette )
  1114.         return FALSE;
  1115.  
  1116.     // Create and set the palette for the art bitmap
  1117.     lpArtPalette = DDLoadPalette( lpDD, "Duel8" );
  1118.     if( NULL == lpArtPalette )
  1119.         return FALSE;
  1120.  
  1121.     // set the palette before loading the art
  1122.     lpFrontBuffer->lpVtbl->SetPalette( lpFrontBuffer, lpArtPalette );
  1123.  
  1124.     hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "Duel8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
  1125.  
  1126.     if( NULL == hbm )
  1127.         return FALSE;
  1128.  
  1129.     ddrval = DDCopyBitmap( lpShip0, hbm, 0, 0, 320, 128 );
  1130.     if( ddrval != DD_OK )
  1131.     {
  1132.         DeleteObject( hbm );
  1133.         return FALSE;
  1134.     }
  1135.  
  1136.     ddrval = DDCopyBitmap( lpShip1, hbm, 0, 128, 320, 128 );
  1137.     if( ddrval != DD_OK )
  1138.     {
  1139.         DeleteObject( hbm );
  1140.         return FALSE;
  1141.     }
  1142.  
  1143.     ddrval = DDCopyBitmap( lpShip2, hbm, 0, 256, 320, 128 );
  1144.     if( ddrval != DD_OK )
  1145.     {
  1146.         DeleteObject( hbm );
  1147.         return FALSE;
  1148.     }
  1149.  
  1150.     ddrval = DDCopyBitmap( lpShip3, hbm, 0, 384, 320, 128 );
  1151.     if( ddrval != DD_OK )
  1152.     {
  1153.         DeleteObject( hbm );
  1154.         return FALSE;
  1155.     }
  1156.  
  1157.     ddrval = DDCopyBitmap( lpNum, hbm, 0, 512, 320, 16 );
  1158.     if( ddrval != DD_OK )
  1159.     {
  1160.         DeleteObject( hbm );
  1161.         return FALSE;
  1162.     }
  1163.  
  1164.     DeleteObject( hbm );
  1165.  
  1166.     // set colorfill colors and color keys according to bitmap contents
  1167.     dwFillColor = DDColorMatch( lpShip0, CLR_INVALID );
  1168.     
  1169.     DDSetColorKey( lpShip0, CLR_INVALID );
  1170.     DDSetColorKey( lpShip1, CLR_INVALID );
  1171.     DDSetColorKey( lpShip2, CLR_INVALID );
  1172.     DDSetColorKey( lpShip3, CLR_INVALID );
  1173.     DDSetColorKey( lpNum, CLR_INVALID );
  1174.  
  1175.     return TRUE;
  1176. }
  1177.  
  1178.  
  1179. int randInt( int low, int high )
  1180. {
  1181.     int range = high - low;
  1182.     int num = rand() % range;
  1183.     return( num + low );
  1184. }
  1185.  
  1186. double randDouble( double low, double high )
  1187. {
  1188.     double range = high - low;
  1189.     double num = range * (double)rand()/(double)RAND_MAX;
  1190.     return( num + low );
  1191. }
  1192.  
  1193.  
  1194. BOOL RemoteCreate(GUID pGuid, LPSTR FullName, LPSTR NickName)
  1195. {
  1196.     HRESULT hr;
  1197.     DPSESSIONDESC dpDesc;
  1198.  
  1199.     // Be sure we aren't already initialized.
  1200.     if (lpIDC != NULL)
  1201.     {
  1202.         return( FALSE );
  1203.     }
  1204.  
  1205.     GetProvider();
  1206.  
  1207.     if (lpIDC == NULL)
  1208.         return(FALSE);
  1209.  
  1210.     switch( CreateGame())
  1211.     {
  1212.     case 1:             // Create
  1213.         IsHost = TRUE;
  1214.         memset(&dpDesc, 0x00, sizeof(DPSESSIONDESC));
  1215.         dpDesc.dwSize = sizeof(dpDesc);
  1216.         dpDesc.dwMaxPlayers = 16;
  1217.         dpDesc.dwFlags = DPOPEN_CREATESESSION;
  1218.         dpDesc.guidSession = pGuid;
  1219.         strcpy( dpDesc.szSessionName, FullName);
  1220.         
  1221.         if ((hr = lpIDC->lpVtbl->Open(lpIDC, &dpDesc)) != DP_OK)
  1222.         {
  1223.             lpIDC->lpVtbl->Release(lpIDC);
  1224.             lpIDC = NULL;
  1225.             return(FALSE);
  1226.         }
  1227.         
  1228.         break;
  1229.  
  1230.     case 2:             // Connect
  1231.         IsHost = FALSE;
  1232.         g_lpGuid = (LPGUID) &pGuid;
  1233.  
  1234.         GetGame();
  1235.  
  1236.         if (lpIDC == NULL)
  1237.             return(FALSE);
  1238.  
  1239.         break;
  1240.  
  1241.     default:
  1242.         return(FALSE);
  1243.     }
  1244.  
  1245.     if ((hr = lpIDC->lpVtbl->CreatePlayer(lpIDC, &dcoID, NickName,
  1246.                                   "Duel Player", &dphEvent)) != DP_OK)
  1247.     {
  1248.         lpIDC->lpVtbl->Close(lpIDC);
  1249.         lpIDC->lpVtbl->Release(lpIDC);
  1250.         lpIDC = NULL;
  1251.         return(FALSE);
  1252.     }
  1253.     
  1254.     return(TRUE);
  1255.  
  1256. }
  1257.  
  1258.  
  1259. int GetProvider()
  1260. {
  1261.   return(DialogBox (NULL, (LPCTSTR)IDD_CHOOSEPROVIDER, hWndMain,
  1262.                     (DLGPROC)DlgProcChooseProvider));
  1263. }
  1264.  
  1265. int CreateGame()
  1266. {
  1267.   return(DialogBox (NULL, (LPCTSTR) IDD_Q_CREATE, hWndMain, 
  1268.                     (DLGPROC) DlgProcQCreate));
  1269. }
  1270.  
  1271. int GetGame()
  1272. {
  1273.  
  1274.   return(DialogBox (NULL, (LPCTSTR) IDD_SELSESSION, hWndMain, 
  1275.                     (DLGPROC) DlgProcSelSession));
  1276. }
  1277.  
  1278.  
  1279. BOOL CALLBACK DlgProcChooseProvider(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  1280. {
  1281.     LPGUID  lpGuid;
  1282.     static  LONG    iIndex;
  1283.     static  HWND hWndCtl;
  1284.     
  1285.     switch (msg)
  1286.     {
  1287.     case WM_INITDIALOG:
  1288.  
  1289.         hWndCtl = GetDlgItem(hDlg, IDC_LIST1);
  1290.         if (hWndCtl == NULL)
  1291.         {
  1292.             EndDialog(hDlg, TRUE);
  1293.             return(TRUE);
  1294.         }
  1295.         DirectPlayEnumerate(EnumSP, (LPVOID) hWndCtl);
  1296.         SetFocus(hWndCtl);
  1297.         SendMessage(hWndCtl, LB_SETCURSEL, 0, 0);
  1298.         return(FALSE);
  1299.  
  1300.     case WM_COMMAND:
  1301.         switch( HIWORD(wParam))
  1302.         {
  1303.         case LBN_SELCHANGE:
  1304.             iIndex = SendMessage((HWND) lParam, LB_GETCURSEL, 0, 0);
  1305.             hWndCtl = (HWND) lParam;
  1306.             return(FALSE);
  1307.  
  1308.         case LBN_DBLCLK:
  1309.             iIndex = SendMessage((HWND) lParam, LB_GETCURSEL, 0, 0);
  1310.             if (iIndex != LB_ERR)
  1311.             {
  1312.                 lpGuid = (LPGUID) SendMessage((HWND) lParam, LB_GETITEMDATA, iIndex, 0);
  1313.                 DirectPlayCreate(lpGuid, &lpIDC, NULL);
  1314.                 EndDialog(hDlg, TRUE);
  1315.                 return(TRUE);
  1316.             }
  1317.             break;
  1318.  
  1319.         case 0:
  1320.             if (LOWORD(wParam) == IDOK)
  1321.             {
  1322.                 if (iIndex != LB_ERR)
  1323.                 {
  1324.                     lpGuid = (LPGUID) SendMessage(hWndCtl, LB_GETITEMDATA, iIndex, 0);
  1325.                     if (lpGuid)
  1326.                     {
  1327.                         DirectPlayCreate(lpGuid, &lpIDC, NULL);
  1328.                         EndDialog(hDlg, TRUE);
  1329.                     }
  1330.                     else
  1331.                         EndDialog(hDlg, FALSE);
  1332.                     return(TRUE);
  1333.                 }
  1334.             }
  1335.             else if (LOWORD(wParam) == IDCANCEL)
  1336.             {
  1337.                 EndDialog(hDlg, FALSE);
  1338.                 return(TRUE);
  1339.             }
  1340.             break;
  1341.  
  1342.         }
  1343.     }
  1344.     return (FALSE);
  1345. }
  1346.  
  1347. BOOL FAR PASCAL EnumSession(LPDPSESSIONDESC lpDPGameDesc, LPVOID lpContext, 
  1348.                             LPDWORD lpdwTimeOut, DWORD dwFlags)
  1349. {
  1350.     LONG iIndex;
  1351.     HWND hWnd = (HWND) lpContext;
  1352.  
  1353.     if( dwFlags & DPESC_TIMEDOUT )
  1354.     {
  1355.         return FALSE;       // don't try again
  1356.     }
  1357.  
  1358.     iIndex = SendMessage(hWnd, LB_ADDSTRING, 0, (LPARAM) lpDPGameDesc->szSessionName);
  1359.     if (iIndex != LB_ERR)
  1360.         SendMessage(hWnd, LB_SETITEMDATA, iIndex, (LPARAM) lpDPGameDesc->dwSession);
  1361.  
  1362.     SetFocus(hWnd);
  1363.     SendMessage(hWnd, LB_SETCURSEL, 0, 0);
  1364.     return(TRUE);
  1365.  
  1366. }
  1367.  
  1368. BOOL FAR PASCAL EnumSP(LPGUID lpGuid, LPSTR lpDesc, DWORD dwMajorVersion,
  1369.                        DWORD dwMinorVersion, LPVOID lpv)
  1370. {
  1371.     LONG iIndex;
  1372.     HWND hWnd = (HWND) lpv;
  1373.  
  1374.     iIndex = SendMessage(hWnd, LB_ADDSTRING, 0, (LPARAM) lpDesc);
  1375.     if (iIndex != LB_ERR)
  1376.         SendMessage(hWnd, LB_SETITEMDATA, iIndex, (LPARAM) lpGuid);
  1377.  
  1378.     SetFocus(hWnd);
  1379.     SendMessage(hWnd, LB_SETCURSEL, 0, 0);
  1380.     return(TRUE);
  1381. }
  1382.  
  1383.  
  1384. BOOL CALLBACK DlgProcQCreate (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  1385. {
  1386.     switch (msg)
  1387.     {
  1388.     case WM_COMMAND:
  1389.         switch(wParam)
  1390.         {
  1391.         case IDC_CREATE:
  1392.             EndDialog(hDlg, 1);
  1393.             return(TRUE);
  1394.  
  1395.         case IDC_CONNECT:
  1396.             EndDialog(hDlg, 2);
  1397.             return(TRUE);
  1398.  
  1399.         case IDCANCEL:
  1400.             EndDialog(hDlg, -1);
  1401.             return(TRUE);
  1402.         }
  1403.         break;
  1404.  
  1405.     }
  1406.     return(FALSE);
  1407. }
  1408.  
  1409. BOOL CALLBACK DlgProcSelSession (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  1410. {
  1411.     static  LONG    iIndex;
  1412.     static  HWND hWndCtl;
  1413.     DPSESSIONDESC dpDesc;
  1414.     HRESULT hr = DP_OK + 10;
  1415.  
  1416.     switch (msg)
  1417.     {
  1418.     case WM_INITDIALOG:
  1419.  
  1420.         hWndCtl = GetDlgItem(hDlg, IDC_LB_SESSION);
  1421.         if (hWndCtl == NULL)
  1422.         {
  1423.             EndDialog(hDlg, TRUE);
  1424.             return(TRUE);
  1425.         }
  1426.         memset(&dpDesc, 0x00, sizeof(DPSESSIONDESC));
  1427.         dpDesc.dwSize = sizeof(dpDesc);
  1428.         dpDesc.guidSession = *g_lpGuid;
  1429.         // enum sessions with 5 second timeout
  1430.         lpIDC->lpVtbl->EnumSessions(lpIDC, &dpDesc, (DWORD)5000, EnumSession, (LPVOID) hWndCtl, (DWORD)NULL);
  1431.  
  1432.         SetFocus(hWndCtl);
  1433.         return(FALSE);
  1434.  
  1435.     case WM_COMMAND:
  1436.  
  1437.         switch( HIWORD(wParam))
  1438.         {
  1439.         case LBN_SELCHANGE:
  1440.             iIndex = SendMessage((HWND) lParam, LB_GETCURSEL, 0, 0);
  1441.             hWndCtl = (HWND) lParam;
  1442.             return(FALSE);
  1443.  
  1444.         case 0:
  1445.             if (LOWORD(wParam) == IDCANCEL)
  1446.             {
  1447.                 lpIDC->lpVtbl->Close(lpIDC);
  1448.                 lpIDC->lpVtbl->Release(lpIDC);
  1449.                 lpIDC = NULL;
  1450.                 EndDialog(hDlg, FALSE);
  1451.                 return(TRUE);
  1452.             }
  1453.             //
  1454.             // Fall Through.
  1455.             //
  1456.         case LBN_DBLCLK:
  1457.             if (HIWORD(wParam) == LBN_DBLCLK)
  1458.             {
  1459.                 hWndCtl = (HWND) lParam;
  1460.                 iIndex = SendMessage(hWndCtl, LB_GETCURSEL, 0, 0);
  1461.             }
  1462.  
  1463.             if (iIndex != LB_ERR)
  1464.             {
  1465.                 memset(&dpDesc, 0x00, sizeof(DPSESSIONDESC));
  1466.                 dpDesc.dwSize       = sizeof(dpDesc);
  1467.                 dpDesc.guidSession  = *g_lpGuid;
  1468.                 dpDesc.dwFlags      = DPOPEN_OPENSESSION;
  1469.                 dpDesc.dwSession    = SendMessage((HWND) hWndCtl, LB_GETITEMDATA, iIndex, 0);
  1470.                 hr = lpIDC->lpVtbl->Open(lpIDC, &dpDesc);
  1471.  
  1472.                 if (hr != DP_OK)
  1473.                 {
  1474.                     lpIDC->lpVtbl->Close(lpIDC);
  1475.                     lpIDC->lpVtbl->Release(lpIDC);
  1476.                     lpIDC = NULL;
  1477.                     EndDialog(hDlg, FALSE);
  1478.                 }
  1479.  
  1480.                 EndDialog(hDlg, TRUE);
  1481.                 return(TRUE);
  1482.  
  1483.             }
  1484.         }
  1485.     }
  1486.     return (FALSE);
  1487. }
  1488.  
  1489. void ReceiveGameMessages( void )
  1490. {
  1491.     DPID                fromID, dcoReceiveID;
  1492.     DWORD               nBytes;
  1493.     int                 x,y;
  1494.  
  1495.     if ( lpIDC )
  1496.     {
  1497.         // maybe add a block?
  1498.         if( ( randInt( 0, 100 ) > 98 ) && IsHost && bIsActive)
  1499.         {
  1500.             x = randInt( 0, 40);
  1501.             y = randInt( 0, 30);
  1502.             if( setBlock( x, y) )
  1503.             {
  1504.                 SendGameMessage(MSG_ADDBLOCK, 0, (BYTE)x, (BYTE)y, 0);
  1505.             }
  1506.         }
  1507.         // read all messages in queue
  1508.         while(1)
  1509.         {
  1510.             HRESULT status;
  1511.             nBytes = MAX_BUFFER_SIZE;
  1512.             status = lpIDC->lpVtbl->Receive( lpIDC,
  1513.                         &fromID,
  1514.                         &dcoReceiveID,
  1515.                         DPRECEIVE_ALL,
  1516.                         CommBuff,
  1517.                         &nBytes);
  1518.             switch( status )
  1519.             {
  1520.             case DP_OK:
  1521.                 if ( fromID == 0 )
  1522.                 {
  1523.                     // ignore system messages
  1524.                 }
  1525.                 else
  1526.                 {
  1527.                     EvaluateMessage( nBytes );
  1528.                 }
  1529.                 break;
  1530.  
  1531.             default:
  1532.  
  1533.                 // Error condition of some kind - we just stop
  1534.                 // checking for now
  1535.                 return;
  1536.             }
  1537.         }
  1538.     }
  1539. }
  1540.  
  1541. void EvaluateMessage( DWORD len )
  1542. {
  1543.     LPUPDATEMSG     lpUpdate;
  1544.     LPHEREIAMMSG    lpHereIAm;
  1545.     LPINITMSG       lpInit;
  1546.     LPBLOCKHITMSG   lpBlockHit;
  1547.     LPSHIPHITMSG    lpShipHit;
  1548.     LPADDBLOCKMSG   lpAddBlock;
  1549.     
  1550.     char dBuf[256];
  1551.     
  1552.     switch( CommBuff[0] )
  1553.     {
  1554.     case MSG_UPDATE:
  1555.         lpUpdate = (LPUPDATEMSG)CommBuff;
  1556.         Ships[lpUpdate->WhoIAm] = lpUpdate->Ship;
  1557.         Ships[lpUpdate->WhoIAm].timeStamp = GetTickCount();
  1558.         Ships[lpUpdate->WhoIAm].lastTick = Ships[lpUpdate->WhoIAm].timeStamp;
  1559.         break;
  1560.         
  1561.     case MSG_HEREIAM:
  1562.         if( IsHost )
  1563.         {
  1564.             lpHereIAm = (LPHEREIAMMSG)CommBuff;
  1565.             SendGameMessage(MSG_INIT, lpHereIAm->ID, 0, 0, 0);
  1566.         }
  1567.         break;
  1568.     case MSG_INIT:
  1569.         if( !IsHost )
  1570.         {
  1571.             lpInit = (LPINITMSG)CommBuff;
  1572.             WhoIAm = lpInit->YouAre;
  1573.             initShip(&Ships[lpInit->YouAre]);
  1574.             Blocks = lpInit->Blocks;
  1575.             HaveHostInit = TRUE;
  1576.         }
  1577.         break;
  1578.  
  1579.     case MSG_BLOCKHIT:
  1580.         lpBlockHit = (LPBLOCKHITMSG)CommBuff;
  1581.         Blocks.bits[lpBlockHit->row][lpBlockHit->col] &= ~lpBlockHit->mask;
  1582.         break;
  1583.  
  1584.     case MSG_ADDBLOCK:
  1585.         lpAddBlock = (LPADDBLOCKMSG)CommBuff;
  1586.         setBlock( lpAddBlock->x, lpAddBlock->y);
  1587.         break;
  1588.  
  1589.     case MSG_SHIPHIT:
  1590.         lpShipHit = (LPSHIPHITMSG)CommBuff;
  1591.         Ships[lpShipHit->You].enable = FALSE;
  1592.         DestroyShip( lpShipHit->You );
  1593.         if( lpShipHit->You == WhoIAm )
  1594.         {
  1595.             Ships[WhoIAm].posx = HomeX[WhoIAm];
  1596.             Ships[WhoIAm].posy = HomeY[WhoIAm];
  1597.             Ships[WhoIAm].frame = HomeFrame[WhoIAm];
  1598.             CountDown = 5000;
  1599.         }
  1600.         break;
  1601.                 
  1602.     default:
  1603.         wsprintf(dBuf, "Unknown message: %d\n", CommBuff[0]);
  1604.         OutputDebugString( dBuf );
  1605.         break;
  1606.     }
  1607. }
  1608.  
  1609. void SendGameMessage( BYTE msg, DWORD to, BYTE row, BYTE col, BYTE mask )
  1610. {
  1611.     LPUPDATEMSG     lpUpdate;
  1612.     LPHEREIAMMSG    lpHereIAm;
  1613.     LPINITMSG       lpInit;
  1614.     LPBLOCKHITMSG   lpBlockHit;
  1615.     LPSHIPHITMSG    lpShipHit;
  1616.     LPADDBLOCKMSG   lpAddBlock;
  1617.     int             nBytes;
  1618.     int             i;
  1619.     DWORD           send_to = 0;
  1620.     
  1621.     switch( msg )
  1622.     {
  1623.     case MSG_HEREIAM:
  1624.         lpHereIAm = (LPHEREIAMMSG)CommBuff;
  1625.         lpHereIAm->MsgCode = msg;
  1626.         lpHereIAm->ID = (DWORD)dcoID;
  1627.         nBytes = sizeof( HEREIAMMSG );
  1628.         break;
  1629.  
  1630.     case MSG_INIT:
  1631.         lpInit = (LPINITMSG)CommBuff;
  1632.         lpInit->MsgCode = msg;
  1633.         send_to = to;
  1634.         for(i=0; i<16; i++)
  1635.         {
  1636.             if( !Ships[i].enable )
  1637.                 break;
  1638.         }
  1639.         if( i == 16 )
  1640.         {
  1641.             // no room for more players
  1642.             return;
  1643.         }
  1644.         lpInit->YouAre = i;
  1645.         lpInit->Blocks = Blocks;
  1646.         nBytes = sizeof( INITMSG );
  1647.         break;
  1648.         
  1649.     case MSG_UPDATE:
  1650.         lpUpdate = (LPUPDATEMSG)CommBuff;
  1651.         lpUpdate->MsgCode = msg;
  1652.         lpUpdate->WhoIAm = WhoIAm;
  1653.         lpUpdate->Ship = Ships[WhoIAm];
  1654.         nBytes = sizeof( UPDATEMSG );
  1655.         break;
  1656.     case MSG_BLOCKHIT:
  1657.         lpBlockHit = (LPBLOCKHITMSG)CommBuff;
  1658.         lpBlockHit->MsgCode = msg;
  1659.         lpBlockHit->row = row;
  1660.         lpBlockHit->col = col;
  1661.         lpBlockHit->mask = mask;
  1662.         nBytes = sizeof( BLOCKHITMSG );
  1663.         break;
  1664.     case MSG_SHIPHIT:
  1665.         lpShipHit = (LPSHIPHITMSG)CommBuff;
  1666.         lpShipHit->MsgCode = msg;
  1667.         lpShipHit->You = row;
  1668.         nBytes = sizeof( SHIPHITMSG );
  1669.         break;
  1670.     case MSG_ADDBLOCK:
  1671.         lpAddBlock = (LPADDBLOCKMSG)CommBuff;
  1672.         lpAddBlock->MsgCode = msg;
  1673.         lpAddBlock->x = row;
  1674.         lpAddBlock->y = col;
  1675.         nBytes = sizeof( ADDBLOCKMSG );
  1676.         break;
  1677.     }
  1678.     // Broadcast it to everyone in the group.
  1679.     lpIDC->lpVtbl->Send( lpIDC,
  1680.                          dcoID,   // From
  1681.                          send_to, // send to everybody
  1682.                          0,
  1683.                          (LPSTR)CommBuff,
  1684.                          nBytes);       
  1685.  
  1686. }
  1687.         
  1688.         
  1689. void AddFrag(int which, int offX, int offY)
  1690. {
  1691.     int i;
  1692.     for(i=0; i<64; i++) // find available fragment
  1693.     {
  1694.         if( !Frags[i].valid )
  1695.             break;
  1696.     }
  1697.     if( i == 64 )
  1698.         return;
  1699.         
  1700.     
  1701.     Frags[i].posx = (double)offX + Ships[which].posx;
  1702.     Frags[i].posy = (double)offY + Ships[which].posy;
  1703.     switch( which % 4 )
  1704.     {
  1705.     case 0: Frags[i].surf = lpShip0;    break;
  1706.     case 1: Frags[i].surf = lpShip1;    break;
  1707.     case 2: Frags[i].surf = lpShip2;    break;
  1708.     case 3: Frags[i].surf = lpShip3;    break;
  1709.     }
  1710.     Frags[i].src.top = 32 * ( (int)Ships[which].frame / 10 ) + offX;
  1711.     Frags[i].src.left = 32 * ( (int)Ships[which].frame % 10 ) + offY;
  1712.     Frags[i].src.right = Frags[i].src.left + 8;
  1713.     Frags[i].src.bottom = Frags[i].src.top + 8;
  1714.     Frags[i].velx = ((double)offX - 12.0)/24.0;
  1715.     Frags[i].vely = ((double)offY - 12.0)/24.0;
  1716.     Frags[i].valid = TRUE;
  1717. }
  1718.  
  1719.  
  1720. void UpdateFragment(int i)
  1721. {
  1722.     DWORD   TickCnt;
  1723.     static DWORD   tickDiff;
  1724.     static DWORD lastTick;
  1725.  
  1726.     if( i == 0)
  1727.     {
  1728.         TickCnt = GetTickCount();
  1729.         tickDiff = TickCnt - lastTick;
  1730.         lastTick = TickCnt;
  1731.     }
  1732.     
  1733.     if( !Frags[i].valid )
  1734.         return;
  1735.         
  1736.     Frags[i].posx += Frags[i].velx * tickDiff;
  1737.     Frags[i].posy += Frags[i].vely * tickDiff;
  1738.     if( (Frags[i].posx < 0.0) || (Frags[i].posx >= 632.0) ||
  1739.         (Frags[i].posy < 0.0) || (Frags[i].posy >= 472.0) )
  1740.     {
  1741.         Frags[i].valid = FALSE;
  1742.     }
  1743. }
  1744.  
  1745. void DrawFragments( void )
  1746. {
  1747.     int     i;
  1748.     
  1749.     for(i=0; i<64; i++)
  1750.     {
  1751.         if( Frags[i].valid )
  1752.         {
  1753.             bltObject( (int)Frags[i].posx, (int)Frags[i].posy, Frags[i].surf,
  1754.                 &(Frags[i].src), DDBLTFAST_SRCCOLORKEY );
  1755.         }
  1756.     }
  1757. }
  1758.  
  1759.  
  1760. void DestroyShip( int which )
  1761. {
  1762.     // add ship fragments
  1763.     AddFrag(which, 0, 0);
  1764.     AddFrag(which, 8, 0);
  1765.     AddFrag(which, 16, 0);
  1766.     AddFrag(which, 24, 0);
  1767.     AddFrag(which, 0, 8);
  1768.     AddFrag(which, 8, 8);
  1769.     AddFrag(which, 16, 8);
  1770.     AddFrag(which, 24, 8);
  1771.     AddFrag(which, 0, 16);
  1772.     AddFrag(which, 8, 16);
  1773.     AddFrag(which, 16, 16);
  1774.     AddFrag(which, 24, 16);
  1775.     AddFrag(which, 0, 24);
  1776.     AddFrag(which, 8, 24);
  1777.     AddFrag(which, 16, 24);
  1778.     AddFrag(which, 24, 24);
  1779. }
  1780.