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

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4.  *
  5.  *  File:       ffdonuts.c
  6.  *  Content:    DirectInput ForceFeedback sample
  7.  *
  8.  *
  9.  ***************************************************************************/
  10.  
  11. #define INITGUID
  12.  
  13. #include "ffdonuts.h"
  14.  
  15.  
  16. LPDIRECTDRAWSURFACE     lpFrontBuffer;
  17. LPDIRECTDRAWSURFACE     lpBackBuffer;
  18. LPDIRECTDRAWSURFACE     lpDonut;
  19. LPDIRECTDRAWSURFACE     lpPyramid;
  20. LPDIRECTDRAWSURFACE     lpCube;
  21. LPDIRECTDRAWSURFACE     lpSphere;
  22. LPDIRECTDRAWSURFACE     lpShip;
  23. LPDIRECTDRAWSURFACE     lpNum;
  24. LPDIRECTDRAW            lpDD;
  25. LPDIRECTDRAWPALETTE     lpArtPalette;
  26. LPDIRECTDRAWPALETTE     lpSplashPalette;
  27. BOOL                    bPlayIdle = FALSE;
  28. BOOL                    bPlayBuzz = FALSE;
  29. BOOL                    bPlayRev = FALSE;
  30. DWORD                   lastInput = 0;
  31. BOOL                    lastThrust = FALSE;
  32. BOOL                    lastShield = FALSE;
  33. int                     showDelay = 0;
  34. HWND                    hWndMain;
  35. BOOL                    bShowFrameCount=TRUE;
  36. BOOL                    bIsActive;
  37. BOOL                    bMouseVisible;
  38. DWORD                   dwFrameCount;
  39. DWORD                   dwFrameTime;
  40. DWORD                   dwFrames;
  41. DWORD                   dwFramesLast;
  42. BOOL                    bUseEmulation;
  43. BOOL                    bTest=FALSE;
  44. BOOL                    bStress=FALSE;
  45. DWORD                   dwTransType;
  46. RGBQUAD                 SPalette[256];
  47. DWORD                   lastTickCount;
  48. int                     score;
  49. int                     ProgramState;
  50. int                     level;
  51. int                     restCount;
  52. DWORD                   dwFillColor;
  53. BOOL                    bSpecialEffects = FALSE;
  54. DWORD                   ShowLevelCount = 3000;
  55. DWORD                   ScreenX;
  56. DWORD                   ScreenY;
  57. DWORD                   ScreenBpp;
  58. #ifdef USE_DSOUND
  59. BOOL                    bWantSound = TRUE;  //global hack to turn off sound
  60. BOOL                    bSoundEnabled = FALSE;
  61. #endif
  62.  
  63. int getint(char**p, int def);
  64.  
  65. #ifdef DEBUG
  66. char                    DebugBuf[256];
  67. BOOL                    bHELBlt = FALSE;
  68. #endif
  69.  
  70. DBLNODE                 DL;             // Display List
  71.  
  72. #ifdef USE_DSOUND
  73. LPDIRECTSOUND           lpDS;
  74. HSNDOBJ                 hsoBeginLevel     = NULL;
  75. HSNDOBJ                 hsoEngineIdle     = NULL;
  76. HSNDOBJ                 hsoEngineRev      = NULL;
  77. HSNDOBJ                 hsoSkidToStop     = NULL;
  78. HSNDOBJ                 hsoShieldBuzz     = NULL;
  79. HSNDOBJ                 hsoShipExplode    = NULL;
  80. HSNDOBJ                 hsoFireBullet     = NULL;
  81. HSNDOBJ                 hsoShipBounce     = NULL;
  82. HSNDOBJ                 hsoDonutExplode   = NULL;
  83. HSNDOBJ                 hsoPyramidExplode = NULL;
  84. HSNDOBJ                 hsoCubeExplode    = NULL;
  85. HSNDOBJ                 hsoSphereExplode  = NULL;
  86. #endif
  87.  
  88. void setup_game(void)
  89. {
  90.     restCount = GetTickCount();
  91.     initLevel( ++level );
  92.     // set the palette
  93.     lpFrontBuffer->lpVtbl->SetPalette( lpFrontBuffer, lpArtPalette );
  94. }
  95.  
  96. /*
  97.  * MainWndproc
  98.  *
  99.  * Callback for all Windows messages
  100.  */
  101. long FAR PASCAL MainWndproc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  102. {
  103.     PAINTSTRUCT ps;
  104.     HDC         hdc;
  105.  
  106.     switch( message )
  107.     {
  108.     case WM_ACTIVATEAPP:
  109.         bIsActive = (BOOL) wParam;
  110.         if( bIsActive )
  111.         {
  112.             bMouseVisible = FALSE;
  113.             lastTickCount = GetTickCount();
  114.             bSpecialEffects = FALSE;
  115.             // we have just been reactivated...
  116.             // time to acquire our device(s) again
  117.             inputAcquireDevices();
  118.         }
  119.         else
  120.         {
  121.             bMouseVisible = TRUE;
  122.         }
  123.         break;
  124.  
  125.     case WM_CREATE:
  126.         break;
  127.  
  128.     case WM_SETCURSOR:
  129.         if( !bMouseVisible )
  130.         {
  131.             SetCursor(NULL);
  132.         }
  133.         else
  134.         {
  135.             SetCursor(LoadCursor( NULL, IDC_ARROW ));
  136.         }
  137.         return TRUE;
  138.  
  139.     case WM_KEYDOWN:
  140.         switch( wParam )
  141.         {
  142.         case VK_F3:
  143. #ifdef USE_DSOUND
  144.             if(bWantSound)
  145.             {
  146.                 if( bSoundEnabled )
  147.                 {
  148.                     DestroySound();
  149.                 }
  150.                 else
  151.                 {
  152.                     InitializeSound();
  153.                 }
  154.             }
  155. #endif
  156.             break;
  157.         case VK_F5:
  158.             bShowFrameCount = !bShowFrameCount;
  159.             if( bShowFrameCount )
  160.             {
  161.                 dwFrameCount = 0;
  162.                 dwFrameTime = timeGetTime();
  163.             }
  164.             break;
  165.         case VK_RETURN:
  166.             if( ProgramState == PS_SPLASH )
  167.             {
  168.                 ProgramState = PS_BEGINREST;
  169.                 setup_game();
  170.             }
  171.             break;
  172.         case VK_ESCAPE:
  173.         case VK_F12:
  174.             PostMessage( hWnd, WM_CLOSE, 0, 0 );
  175.             return 0;
  176.         case VK_F1:
  177.             bSpecialEffects = !bSpecialEffects;
  178.             break;
  179.         }
  180.         break;
  181.  
  182.  
  183.     case WM_KEYUP:
  184.         switch( wParam )
  185.         {
  186.         case VK_NUMPAD7:
  187.             lastInput &= ~KEY_SHIELD;
  188.             break;
  189.         case VK_NUMPAD5:
  190.             lastInput &= ~KEY_STOP;
  191.             break;
  192.         case VK_DOWN:
  193.         case VK_NUMPAD2:
  194.             lastInput &= ~KEY_DOWN;
  195.             break;
  196.         case VK_LEFT:
  197.         case VK_NUMPAD4:
  198.             lastInput &= ~KEY_LEFT;
  199.             break;
  200.         case VK_RIGHT:
  201.         case VK_NUMPAD6:
  202.             lastInput &= ~KEY_RIGHT;
  203.             break;
  204.         case VK_UP:
  205.         case VK_NUMPAD8:
  206.             lastInput &= ~KEY_UP;
  207.             break;
  208.         case VK_NUMPAD3:
  209.             lastInput &= ~KEY_THROW;
  210.             break;
  211.         case VK_SPACE:
  212.             lastInput &= ~KEY_FIRE;
  213.             break;
  214.         }
  215.         break;
  216.  
  217.     case WM_ERASEBKGND:
  218.         return 1;
  219.  
  220.     case WM_PAINT:
  221.         hdc = BeginPaint( hWnd, &ps );
  222.         EndPaint( hWnd, &ps );
  223.         return 1;
  224.  
  225.     case WM_DESTROY:
  226.         lastInput=0;
  227.         DestroyGame();
  228.         inputCleanupDirectInput();
  229.         PostQuitMessage( 0 );
  230.         break;
  231.  
  232.     default:
  233.         break;
  234.     }
  235.     return DefWindowProc(hWnd, message, wParam, lParam);
  236.  
  237. } /* MainWndproc */
  238.  
  239. /*
  240.  * initApplication
  241.  *
  242.  * Do that Windows initialization stuff...
  243.  */
  244. static BOOL initApplication( HANDLE hInstance, int nCmdShow )
  245. {
  246.     WNDCLASS    wc;
  247.     BOOL        rc;
  248.  
  249.     wc.style = CS_DBLCLKS;
  250.     wc.lpfnWndProc = MainWndproc;
  251.     wc.cbClsExtra = 0;
  252.     wc.cbWndExtra = 0;
  253.     wc.hInstance = hInstance;
  254.     wc.hIcon = LoadIcon( hInstance, "DONUTS_ICON");
  255.     wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  256.     wc.hbrBackground = GetStockObject( BLACK_BRUSH );
  257.     wc.lpszMenuName =  NULL;
  258.     wc.lpszClassName = "DonutsClass";
  259.     rc = RegisterClass( &wc );
  260.     if( !rc )
  261.     {
  262.         return FALSE;
  263.     }
  264.  
  265.     hWndMain = CreateWindowEx(0,  // WS_EX_TOPMOST,
  266.         "DonutsClass",
  267.         "Donuts",
  268.         WS_VISIBLE | // so we don't have to call ShowWindow
  269.         WS_POPUP |   // non-app window
  270.         WS_SYSMENU,  // so we get an icon in the tray
  271.         0,
  272.         0,
  273.         GetSystemMetrics(SM_CXSCREEN),
  274.         GetSystemMetrics(SM_CYSCREEN),
  275.         NULL,
  276.         NULL,
  277.         hInstance,
  278.         NULL );
  279.  
  280.     if( !hWndMain )
  281.     {
  282.         return FALSE;
  283.     }
  284.  
  285.     UpdateWindow( hWndMain );
  286.  
  287.     return TRUE;
  288.  
  289. } /* initApplication */
  290.  
  291. /*
  292.  * WinMain
  293.  */
  294. int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
  295.                         int nCmdShow )
  296. {
  297.     MSG     msg;
  298.  
  299.     while( lpCmdLine[0] == '-' )
  300.     {
  301.         lpCmdLine++;
  302.  
  303.         switch (*lpCmdLine++)
  304.         {
  305.         case 'e':
  306.             bUseEmulation = TRUE;
  307.             break;
  308.         case 't':
  309.             bTest = TRUE;
  310.             break;
  311.         case 'x':
  312.             bStress= TRUE;
  313.             bTest = TRUE;
  314.             break;
  315.         }
  316.         while( IS_SPACE(*lpCmdLine) )
  317.         {
  318.             lpCmdLine++;
  319.         }
  320.     }
  321.  
  322.     ScreenX = getint(&lpCmdLine, 640);
  323.     ScreenY = getint(&lpCmdLine, 480);
  324.     ScreenBpp = getint(&lpCmdLine, 8);
  325.  
  326.     if( !initApplication(hInstance, nCmdShow) )
  327.     {
  328.         return FALSE;
  329.     }
  330.  
  331.     // initialize DirectInput functionality
  332.     if( !inputInitDirectInput(hInstance, hWndMain) )
  333.     {
  334.         inputCleanupDirectInput();
  335.         DestroyWindow( hWndMain );
  336.         return FALSE;
  337.     }
  338.  
  339.     if( !InitializeGame() )
  340.     {
  341.         DestroyWindow( hWndMain );
  342.         return FALSE;
  343.     }
  344.  
  345.     dwFrameTime = timeGetTime();
  346.  
  347.     while( 1 )
  348.     {
  349.         if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  350.         {
  351.             if( !GetMessage( &msg, NULL, 0, 0 ) )
  352.             {
  353.                 return msg.wParam;
  354.             }
  355.             TranslateMessage(&msg);
  356.             DispatchMessage(&msg);
  357.         }
  358.         else if ( bIsActive )
  359.         {
  360.             UpdateFrame();
  361.         }
  362.         else
  363.         {
  364.             WaitMessage();
  365.         }
  366.     }
  367. } /* WinMain */
  368.  
  369.  
  370. void DestroyGame( void )
  371. {
  372. }
  373.  
  374. BOOL InitializeGame( void )
  375. {
  376.     DDCAPS          ddcaps;
  377.     HRESULT         ddrval;
  378.     DDSURFACEDESC   ddsd;
  379.     DDSCAPS         ddscaps;
  380. #ifdef NT_HACK
  381.     DDSURFACEDESC DDSurfDesc;
  382. #endif
  383.  
  384.     score = 0;
  385.     if( bTest )
  386.         ShowLevelCount = 1000;
  387.  
  388.     if( bUseEmulation )
  389.         ddrval = DirectDrawCreate( (LPVOID) DDCREATE_EMULATIONONLY, &lpDD, NULL );
  390.     else
  391.         ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
  392.  
  393.     if( ddrval != DD_OK )
  394.         return CleanupAndExit("DirectDrawCreate Failed!");
  395.  
  396.     ddrval = lpDD->lpVtbl->SetCooperativeLevel( lpDD, hWndMain,
  397.                             DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
  398.     if( ddrval != DD_OK )
  399.         return CleanupAndExit("SetCooperativeLevel Failed");
  400.  
  401.     #ifdef NT_HACK
  402.         DDSurfDesc.dwSize = sizeof(DDSurfDesc);
  403.         ddrval = lpDD->lpVtbl->GetDisplayMode(lpDD,&DDSurfDesc);
  404.         if(ddrval == DD_OK)
  405.         ScreenBpp = DDSurfDesc.ddpfPixelFormat.dwRGBBitCount;
  406.     #endif
  407.  
  408.     // set the mode
  409.     ddrval = lpDD->lpVtbl->SetDisplayMode( lpDD, ScreenX, ScreenY, ScreenBpp );
  410.     if( ddrval != DD_OK )
  411.         return CleanupAndExit("SetDisplayMode Failed!");
  412.  
  413.     // check the color key hardware capabilities
  414.     dwTransType = DDBLTFAST_SRCCOLORKEY;
  415.     ddcaps.dwSize = sizeof( ddcaps );
  416.  
  417. #ifdef DEBUG
  418.     if( GetProfileInt( "Donuts", "force_dest_blt", 0) )
  419.     {
  420.         dwTransType = DDBLTFAST_DESTCOLORKEY;
  421.     }
  422.     bHELBlt = GetProfileInt( "Donuts", "force_HEL_blt", bHELBlt );
  423. #endif
  424.  
  425.     // Create surfaces
  426.     memset( &ddsd, 0, sizeof( ddsd ) );
  427.     ddsd.dwSize = sizeof( ddsd );
  428.     ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  429.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
  430.                           DDSCAPS_FLIP |
  431.                           DDSCAPS_COMPLEX;
  432.     ddsd.dwBackBufferCount = 1;
  433.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL );
  434.     if( ddrval != DD_OK )
  435.         return CleanupAndExit("CreateSurface FrontBuffer Failed!");
  436.  
  437.     // get a pointer to the back buffer
  438.     ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  439.     ddrval = lpFrontBuffer->lpVtbl->GetAttachedSurface(
  440.                 lpFrontBuffer,
  441.                 &ddscaps,
  442.                 &lpBackBuffer );
  443.     if( ddrval != DD_OK )
  444.         return CleanupAndExit("GetAttachedDurface Failed!");
  445.  
  446.     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
  447.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  448. #ifdef DEBUG
  449.     if( bHELBlt )
  450.         ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  451. #endif
  452.     ddsd.dwWidth = 320;
  453.     ddsd.dwHeight = 384;
  454.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpDonut, NULL );
  455.     if( ddrval != DD_OK )
  456.         return CleanupAndExit("CreateSurface lpDonut Failed!");
  457.  
  458.     ddsd.dwHeight = 128;
  459.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpPyramid, NULL );
  460.     if( ddrval != DD_OK )
  461.         return CleanupAndExit("CreateSurface lpPyramid Failed!");
  462.  
  463.     ddsd.dwHeight = 32;
  464.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpCube, NULL );
  465.     if( ddrval != DD_OK )
  466.         return CleanupAndExit("CreateSurface lpCube Failed!");
  467.  
  468.     ddsd.dwHeight = 32;
  469.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpSphere, NULL );
  470.     if( ddrval != DD_OK )
  471.         return CleanupAndExit("CreateSurface lpSphere Failed!");
  472.     // Set the background color fill color
  473.  
  474.     ddsd.dwHeight = 256;
  475.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpShip, NULL );
  476.     if( ddrval != DD_OK )
  477.         return CleanupAndExit("CreateSurface lpShip Failed!");
  478.  
  479.     ddsd.dwHeight = 16;
  480.     ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpNum, NULL );
  481.     if( ddrval != DD_OK )
  482.         return CleanupAndExit("CreateSurface lpNum Failed!");
  483.  
  484.     if( !RestoreSurfaces() )
  485.         return CleanupAndExit("RestoreSurfaces Failed!");
  486.  
  487.     DL.next = DL.prev = &DL;            // null display list
  488.     DL.type = OBJ_SHIP;
  489.     DL.surf = lpShip;
  490.     lastTickCount = GetTickCount();
  491.  
  492. #ifdef USE_DSOUND
  493.     if(bWantSound)
  494.     {
  495.         InitializeSound();
  496.     }
  497. #endif
  498.  
  499.     if(bTest)
  500.     {
  501.         ProgramState = PS_ACTIVE;
  502.         setup_game();
  503.     }
  504.     else
  505.     {
  506.         ProgramState = PS_SPLASH;
  507.     }
  508.     return TRUE;
  509. }
  510.  
  511. BOOL CleanupAndExit( char *err)
  512. {
  513. #ifdef DEBUG
  514.     wsprintf(DebugBuf, "___CleanupAndExit  err = %s\n", err );
  515.     OutputDebugString( DebugBuf );
  516. #endif
  517.  
  518.     // make the cursor visible
  519.     SetCursor(LoadCursor( NULL, IDC_ARROW ));
  520.     bMouseVisible = TRUE;
  521.  
  522.     if( lpDonut != NULL )
  523.         lpDonut->lpVtbl->Release( lpDonut );
  524.  
  525.     if( lpPyramid != NULL )
  526.         lpPyramid->lpVtbl->Release( lpPyramid );
  527.  
  528.     if( lpCube != NULL )
  529.         lpCube->lpVtbl->Release( lpCube );
  530.  
  531.     if( lpSphere != NULL )
  532.         lpSphere->lpVtbl->Release( lpSphere );
  533.  
  534.     if( lpShip != NULL )
  535.         lpShip->lpVtbl->Release( lpShip );
  536.  
  537.     if( lpNum != NULL )
  538.         lpNum->lpVtbl->Release( lpNum );
  539.  
  540.     if( lpFrontBuffer != NULL )
  541.         lpFrontBuffer->lpVtbl->Release( lpFrontBuffer );
  542.  
  543.     if( lpArtPalette != NULL )
  544.         lpArtPalette->lpVtbl->Release( lpArtPalette );
  545.  
  546.     if( lpSplashPalette != NULL )
  547.         lpSplashPalette->lpVtbl->Release( lpSplashPalette );
  548.  
  549.     if( lpDD != NULL )
  550.         lpDD->lpVtbl->Release( lpDD );
  551.  
  552.     //
  553.     // warn user if there is one
  554.     //
  555.  
  556.     if( !bStress )
  557.     {
  558.         MessageBox( hWndMain, err, "ERROR", MB_OK );
  559.     }
  560.     return FALSE;
  561. }
  562.  
  563. void bltSplash( void )
  564. {
  565.     HRESULT     ddrval;
  566.     HBITMAP     hbm;
  567.  
  568.     // set the palette before loading the splash screen
  569.     lpFrontBuffer->lpVtbl->SetPalette( lpFrontBuffer, lpSplashPalette );
  570.  
  571.     hbm = (HBITMAP)LoadImage( GetModuleHandle( NULL ), "SPLASH", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
  572.     if ( NULL == hbm )
  573.         return;
  574.  
  575.     // if the surface is lost, DDCopyBitmap will fail and the surface will
  576.     // be restored in FlipScreen.
  577.     ddrval = DDCopyBitmap( lpBackBuffer, hbm, 0, 0, 0, 0 );
  578.  
  579.     DeleteObject( hbm );
  580.  
  581.     FlipScreen();
  582. }
  583.  
  584.  
  585. #ifdef USE_DSOUND
  586. //
  587. // play a sound, but first set the panning according to where the
  588. // object is on the screen.  fake 3D sound.
  589. //
  590. void playPanned(HSNDOBJ hSO, DBLNODE *object)
  591. {
  592.     IDirectSoundBuffer *pDSB = SndObjGetFreeBuffer(hSO);
  593.  
  594.         if(!bWantSound)
  595.                 return;   // No sound our Work is done
  596.  
  597.     if (pDSB)
  598.     {
  599.         switch(ScreenX)
  600.         {
  601.         case 320:
  602.             IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 *
  603.                 ((object->dst.right + object->dst.left) / 2) / 320.0) - 10000.0));
  604.             break;
  605.         case 640:
  606.             IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 *
  607.                 ((object->dst.right + object->dst.left) / 2) / 640.0) - 10000.0));
  608.             break;
  609.         case 1024:
  610.             IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 *
  611.                 ((object->dst.right + object->dst.left) / 2) / 1024.0) - 10000.0));
  612.             break;
  613.         case 1280:
  614.             IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 *
  615.                 ((object->dst.right + object->dst.left) / 2) / 1280.0) - 10000.0));
  616.             break;
  617.         }
  618.  
  619.         IDirectSoundBuffer_Play(pDSB, 0, 0, 0);
  620.     }
  621. }
  622. #endif
  623.  
  624.  
  625. void UpdateFrame( void )
  626. {
  627.     switch( ProgramState )
  628.     {
  629.         case PS_SPLASH:
  630.             // display the splash screen
  631.             bltSplash();
  632.             return;
  633.         case PS_ACTIVE:
  634.             UpdateDisplayList();
  635.             CheckForHits();
  636.             DrawDisplayList();
  637.             if ( isDisplayListEmpty() )
  638.             {
  639. #ifdef USE_DSOUND
  640.                 if(bWantSound)
  641.                 {
  642.                     SndObjStop(hsoEngineIdle);
  643.                     SndObjStop(hsoEngineRev);
  644.                 }
  645. #endif
  646.                 bPlayIdle = FALSE;
  647.                 bPlayRev = FALSE;
  648.                 lastThrust = lastShield = FALSE;
  649.                 ProgramState = PS_BEGINREST;
  650.                 restCount = GetTickCount();
  651.                 initLevel( ++level );
  652.             }
  653.             return;
  654.         case PS_BEGINREST:
  655. #ifdef USE_DSOUND
  656.             if(bWantSound)
  657.             {
  658.                 SndObjPlay(hsoBeginLevel, 0);
  659.             }
  660. #endif
  661.             ProgramState = PS_REST;
  662.             //
  663.             // FALLTHRU
  664.             //
  665.         case PS_REST:
  666.             if( ( GetTickCount() - restCount ) > ShowLevelCount )
  667.             {
  668. #ifdef USE_DSOUND
  669.                 if(bWantSound)
  670.                 {
  671.                     SndObjPlay(hsoEngineIdle, DSBPLAY_LOOPING);
  672.                 }
  673. #endif
  674.                 bPlayIdle = TRUE;
  675.                 lastTickCount = GetTickCount();
  676.                 ProgramState = PS_ACTIVE;
  677.             }
  678.             else
  679.             {
  680.                 DisplayLevel();
  681.             }
  682.             return;
  683.     }
  684. }
  685.  
  686. void DisplayLevel( void )
  687. {
  688.     char buf[10];
  689.  
  690.     EraseScreen();
  691.     buf[0] = 10 + '0';
  692.     buf[1] = 11 + '0';
  693.     buf[2] = 12 + '0';
  694.     buf[3] = 11 + '0';
  695.     buf[4] = 10 + '0';
  696.     buf[5] = '\0';
  697.     bltScore( buf, ScreenX/2-64, ScreenY/2-8 );
  698.     buf[0] = level / 100 + '0';
  699.     buf[1] = level / 10 + '0';
  700.     buf[2] = level % 10 + '0';
  701.     buf[3] = '\0';
  702.     bltScore( buf, ScreenX/2+22, ScreenY/2-8 );
  703.     FlipScreen();
  704. }
  705.  
  706. void bltScore( char *num, int x, int y )
  707. {
  708.     char *c;
  709.     RECT    src;
  710.     int     i;
  711.     HRESULT ddrval;
  712.  
  713.     for(c=num; *c != '\0'; c++)
  714.     {
  715.         while( 1 )
  716.         {
  717.             i = *c - '0';
  718.             src.left = i*16;
  719.             src.top = 0;
  720.             src.right = src.left + 16;
  721.             src.bottom = src.top + 16;
  722.             ddrval = lpBackBuffer->lpVtbl->BltFast( lpBackBuffer, x, y, lpNum, &src, dwTransType );
  723.             if( ddrval == DD_OK )
  724.             {
  725.                 break;
  726.             }
  727.             if( ddrval == DDERR_SURFACELOST )
  728.             {
  729.                 if( !RestoreSurfaces() )
  730.                     return;
  731.             }
  732.             if( ddrval != DDERR_WASSTILLDRAWING )
  733.             {
  734.                 return;
  735.             }
  736.         }
  737.         x += 16;
  738.     }
  739. }
  740.  
  741. void CheckForHits( void )
  742. {
  743.     LPDBLNODE   bullet, target, save;
  744.     int         frame, x, y, l, t;
  745.     BOOL        hit;
  746.  
  747.     // update screen rects
  748.     target = &DL;
  749.     do
  750.     {
  751.         frame = (DWORD)target->frame;
  752.         switch( target->type )
  753.         {
  754.             case OBJ_DONUT:
  755.                 target->dst.left = (DWORD)target->posx;
  756.                 target->dst.top = (DWORD)target->posy;
  757.                 target->dst.right = target->dst.left + 64;
  758.                 target->dst.bottom = target->dst.top + 64;
  759.                 target->src.left = 64 * (frame % 5);
  760.                 target->src.top = 64 * (frame /5);
  761.                 target->src.right = target->src.left + 64;
  762.                 target->src.bottom = target->src.top + 64;
  763.                 break;
  764.             case OBJ_PYRAMID:
  765.                 target->dst.left = (DWORD)target->posx;
  766.                 target->dst.top = (DWORD)target->posy;
  767.                 target->dst.right = target->dst.left + 32;
  768.                 target->dst.bottom = target->dst.top + 32;
  769.                 target->src.left = 32 * (frame % 10);
  770.                 target->src.top = 32 * (frame /10);
  771.                 target->src.right = target->src.left + 32;
  772.                 target->src.bottom = target->src.top + 32;
  773.                 break;
  774.             case OBJ_SPHERE:
  775.                 target->dst.left = (DWORD)target->posx;
  776.                 target->dst.top = (DWORD)target->posy;
  777.                 target->dst.right = target->dst.left + 16;
  778.                 target->dst.bottom = target->dst.top + 16;
  779.                 target->src.left = 16 * (frame % 20);
  780.                 target->src.top = 16 * (frame /20);
  781.                 target->src.right = target->src.left + 16;
  782.                 target->src.bottom = target->src.top + 16;
  783.                 break;
  784.             case OBJ_CUBE:
  785.                 target->dst.left = (DWORD)target->posx;
  786.                 target->dst.top = (DWORD)target->posy;
  787.                 target->dst.right = target->dst.left + 16;
  788.                 target->dst.bottom = target->dst.top + 16;
  789.                 target->src.left = 16 * (frame % 20);
  790.                 target->src.top = 16 * (frame /20);
  791.                 target->src.right = target->src.left + 16;
  792.                 target->src.bottom = target->src.top + 16;
  793.                 break;
  794.             case OBJ_SHIP:
  795.                 target->dst.left = (DWORD)target->posx;
  796.                 target->dst.top = (DWORD)target->posy;
  797.                 target->dst.right = target->dst.left + 32;
  798.                 target->dst.bottom = target->dst.top + 32;
  799.                 if( lastShield )
  800.                     target->src.top = 32 * (frame / 10) + 128;
  801.                 else
  802.                     target->src.top = 32 * (frame /10);
  803.                 target->src.left = 32 * (frame % 10);
  804.                 target->src.right = target->src.left + 32;
  805.                 target->src.bottom = target->src.top + 32;
  806.                 break;
  807.             case OBJ_BULLET:
  808.                 frame = (DWORD)target->frame/20 % 4;
  809.                 target->dst.left = (DWORD)target->posx;
  810.                 target->dst.top = (DWORD)target->posy;
  811.                 target->dst.right = target->dst.left + 3;
  812.                 target->dst.bottom = target->dst.top + 3;
  813.                 target->src.left = BULLET_X + frame*4;
  814.                 target->src.top = BULLET_Y;
  815.                 target->src.right = target->src.left + 3;
  816.                 target->src.bottom = target->src.top + 3;
  817.                 break;
  818.         }
  819.         target = target->next;
  820.     }
  821.     while( target != &DL );
  822.  
  823.     bullet=&DL;
  824.     do
  825.     {
  826.         hit = FALSE;
  827.         if((bullet->type != OBJ_BULLET) && (bullet != &DL))
  828.         {
  829.             bullet = bullet->next;
  830.             continue;
  831.         }
  832.  
  833.         x = (bullet->dst.left + bullet->dst.right) / 2;
  834.         y = (bullet->dst.top + bullet->dst.bottom) / 2;
  835.         for(target=DL.next; target != &DL; target = target->next)
  836.         {
  837.             if( ( target->type != OBJ_DONUT ) &&
  838.                 ( target->type != OBJ_PYRAMID ) &&
  839.                 ( target->type != OBJ_SPHERE ) &&
  840.                 ( target->type != OBJ_CUBE ) )
  841.                 continue;
  842.  
  843.             if( (x >= target->dst.left) &&
  844.                 (x <  target->dst.right) &&
  845.                 (y >= target->dst.top) &&
  846.                 (y <  target->dst.bottom) )
  847.             {
  848.                 if ((bullet != &DL) || !lastShield)
  849.                 {
  850.                     // the bullet hit the target
  851.                     switch( target->type )
  852.                     {
  853.                     case OBJ_DONUT:
  854. #ifdef USE_DSOUND
  855.                         if(bWantSound)
  856.                         {
  857.                             playPanned(hsoDonutExplode, target);
  858.                         }
  859. #endif
  860.                         addObject( OBJ_PYRAMID, target->dst.left,
  861.                             target->dst.top, -1.0, -1.0 );
  862.                         addObject( OBJ_PYRAMID, target->dst.left,
  863.                             target->dst.top, -1.0, -1.0 );
  864.                         addObject( OBJ_PYRAMID, target->dst.left,
  865.                             target->dst.top, -1.0, -1.0 );
  866.                         score += 10;
  867.                         break;
  868.                     case OBJ_PYRAMID:
  869. #ifdef USE_DSOUND
  870.                         if(bWantSound)
  871.                         {
  872.                             playPanned(hsoPyramidExplode, target);
  873.                         }
  874. #endif
  875.                         addObject( OBJ_SPHERE, target->dst.left,
  876.                             target->dst.top, -1.0, -1.0 );
  877.                         addObject( OBJ_CUBE, target->dst.left,
  878.                             target->dst.top, -1.0, -1.0 );
  879.                         addObject( OBJ_CUBE, target->dst.left,
  880.                             target->dst.top, -1.0, -1.0 );
  881.                         score += 20;
  882.                         break;
  883.                     case OBJ_CUBE:
  884. #ifdef USE_DSOUND
  885.                         if(bWantSound)
  886.                         {
  887.                             playPanned(hsoCubeExplode, target);
  888.                         }
  889. #endif
  890.                         addObject( OBJ_SPHERE, target->dst.left,
  891.                             target->dst.top, -1.0, -1.0 );
  892.                         addObject( OBJ_SPHERE, target->dst.left,
  893.                             target->dst.top, -1.0, -1.0 );
  894.                         break;
  895.                         score += 40;
  896.                     case OBJ_SPHERE:
  897. #ifdef USE_DSOUND
  898.                         if(bWantSound)
  899.                         {
  900.                             playPanned(hsoSphereExplode, target);
  901.                         }
  902. #endif
  903.                         score += 20;
  904.                     }
  905.  
  906.                     l = target->dst.left;
  907.                     t = target->dst.top;
  908.                     DeleteFromList( target );
  909.                 }
  910.  
  911.                 hit = TRUE;
  912.             }
  913.  
  914.             if( hit )
  915.             {
  916.                 if( bullet == &DL )
  917.                 {
  918.                     hit = FALSE;
  919.                     if (!lastShield && !showDelay && !bTest)
  920.                     {
  921.                         // ship has exploded
  922. #ifdef USE_DSOUND
  923.                         if(bWantSound)
  924.                         {
  925.                             playPanned(hsoShipExplode, bullet);
  926.                         }
  927. #endif
  928.                         inputPlayEffect(EF_EXPLODE, 0);
  929.  
  930.                         score -= 150;
  931.                         if (score < 0)
  932.                             score = 0;
  933.  
  934.                         addObject( OBJ_SPHERE, l, t, -1.0, -1.0 );
  935.                         addObject( OBJ_SPHERE, l, t, -1.0, -1.0 );
  936.                         addObject( OBJ_SPHERE, l, t, -1.0, -1.0 );
  937.                         addObject( OBJ_SPHERE, l, t, -1.0, -1.0 );
  938.                         addObject( OBJ_BULLET, l, t,
  939.                             randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) );
  940.                         addObject( OBJ_BULLET, l, t,
  941.                             randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) );
  942.                         addObject( OBJ_BULLET, l, t,
  943.                             randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) );
  944.                         addObject( OBJ_BULLET, l, t,
  945.                             randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) );
  946.                         addObject( OBJ_BULLET, l, t,
  947.                             randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) );
  948.                         addObject( OBJ_BULLET, l, t,
  949.                             randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) );
  950.                         addObject( OBJ_BULLET, l, t,
  951.                             randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) );
  952.                         addObject( OBJ_BULLET, l, t,
  953.                             randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) );
  954.                         addObject( OBJ_BULLET, l, t,
  955.                             randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) );
  956.                         addObject( OBJ_BULLET, l, t,
  957.                             randDouble( -0.5, 0.5 ), randDouble( -0.5, 0.5 ) );
  958.                         initShip(TRUE);
  959.                     }
  960.                 }
  961.  
  962.                 break;
  963.             }
  964.         }
  965.  
  966.         if( hit )
  967.         {
  968.             save = bullet;
  969.             bullet = bullet->next;
  970.  
  971.             DeleteFromList( save );
  972.         }
  973.         else
  974.         {
  975.             bullet = bullet->next;
  976.         }
  977.  
  978.     } while (bullet != &DL);
  979. }
  980.  
  981. void EraseScreen( void )
  982. {
  983.     DDBLTFX     ddbltfx;
  984.     HRESULT     ddrval;
  985.  
  986.     if( bSpecialEffects )   // cool looking screen with no colorfill
  987.         return;
  988.  
  989.     // Erase the background
  990.     ddbltfx.dwSize = sizeof( ddbltfx );
  991.     ddbltfx.dwFillColor = dwFillColor;
  992.     while( 1 )
  993.     {
  994.         ddrval = lpBackBuffer->lpVtbl->Blt( lpBackBuffer, NULL, NULL,
  995.                  NULL, DDBLT_COLORFILL, &ddbltfx );
  996.  
  997.         if( ddrval == DD_OK )
  998.         {
  999.             break;
  1000.         }
  1001.         if( ddrval == DDERR_SURFACELOST )
  1002.         {
  1003.             if( !RestoreSurfaces() )
  1004.                 return;
  1005.         }
  1006.         if( ddrval != DDERR_WASSTILLDRAWING )
  1007.         {
  1008.             return;
  1009.         }
  1010.     }
  1011. }
  1012.  
  1013. void FlipScreen( void )
  1014. {
  1015.     HRESULT     ddrval;
  1016.  
  1017.     // Flip the surfaces
  1018.     while( 1 )
  1019.     {
  1020.         ddrval = lpFrontBuffer->lpVtbl->Flip( lpFrontBuffer, NULL, 0 );
  1021.         if( ddrval == DD_OK )
  1022.         {
  1023.             break;
  1024.         }
  1025.         if( ddrval == DDERR_SURFACELOST )
  1026.         {
  1027.             if( !RestoreSurfaces() )
  1028.             {
  1029.                 return;
  1030.             }
  1031.         }
  1032.         if( ddrval != DDERR_WASSTILLDRAWING )
  1033.         {
  1034.             break;
  1035.         }
  1036.     }
  1037. }
  1038.  
  1039. void DrawDisplayList( void )
  1040. {
  1041.     LPDBLNODE   this;
  1042.     LPDBLNODE   last;
  1043.     HRESULT     ddrval;
  1044.     char        scorebuf[11];
  1045.     int         rem;
  1046.  
  1047.     // blt everything in reverse order if we are doing destination transparency
  1048.     // calculate score string
  1049.     scorebuf[0] = score/10000000 + '0';
  1050.     rem = score % 10000000;
  1051.     scorebuf[1] = rem/1000000 + '0';
  1052.     rem = score % 1000000;
  1053.     scorebuf[2] = rem/100000 + '0';
  1054.     rem = score % 100000;
  1055.     scorebuf[3] = rem/10000 + '0';
  1056.     rem = score % 10000;
  1057.     scorebuf[4] = rem/1000 + '0';
  1058.     rem = score % 1000;
  1059.     scorebuf[5] = rem/100 + '0';
  1060.     rem = score % 100;
  1061.     scorebuf[6] = rem/10 + '0';
  1062.     rem = score % 10;
  1063.     scorebuf[7] = rem + '0';
  1064. #ifdef USE_DSOUND
  1065.     if( bSoundEnabled )
  1066.     {
  1067.         scorebuf[8] = 14 + '0';
  1068.         scorebuf[9] = 13 + '0';
  1069.             scorebuf[10] = '\0';
  1070.     }
  1071.     else
  1072. #endif
  1073.     {
  1074.         scorebuf[8] = '\0';
  1075.     }
  1076.  
  1077.     EraseScreen();
  1078.     if( dwTransType == DDBLTFAST_DESTCOLORKEY )
  1079.     {
  1080.         bltScore(scorebuf, 10, ScreenY-26);
  1081.  
  1082.         if( bShowFrameCount )
  1083.             DisplayFrameRate();
  1084.  
  1085.         this = DL.next; // start with the topmost bitmap
  1086.         last = DL.next; // don't blt it twice
  1087.  
  1088.         if (showDelay)
  1089.             last = &DL;
  1090.     }
  1091.     else
  1092.     {
  1093.         this = &DL;     // start with the bottommost bitmap (the ship)
  1094.         last = &DL;     // don't blt it twice
  1095.  
  1096.         if (showDelay)
  1097.             this = this->prev;
  1098.     }
  1099.  
  1100.     do
  1101.     {
  1102.         while( 1 )
  1103.         {
  1104.             ddrval = lpBackBuffer->lpVtbl->BltFast( lpBackBuffer, this->dst.left, this->dst.top, this->surf, &(this->src), dwTransType );
  1105.             if( ddrval == DD_OK )
  1106.             {
  1107.                 break;
  1108.             }
  1109.             if( ddrval == DDERR_SURFACELOST )
  1110.             {
  1111.                 if( !RestoreSurfaces() )
  1112.                     return;
  1113.             }
  1114.             if( ddrval != DDERR_WASSTILLDRAWING )
  1115.             {
  1116.                 return;
  1117.             }
  1118.         }
  1119.         if( dwTransType != DDBLTFAST_DESTCOLORKEY )
  1120.         {
  1121.             this = this->prev;
  1122.         }
  1123.         else
  1124.         {
  1125.             this = this->next;
  1126.         }
  1127.     }
  1128.     while( this != last );
  1129.  
  1130.     if( dwTransType != DDBLTFAST_DESTCOLORKEY )
  1131.     {
  1132.         bltScore(scorebuf, 10, ScreenY-26);
  1133.  
  1134.         if( bShowFrameCount )
  1135.             DisplayFrameRate();
  1136.     }
  1137.  
  1138.     FlipScreen();
  1139. }
  1140.  
  1141. void DisplayFrameRate( void )
  1142. {
  1143.     DWORD               time2;
  1144.     char                buff[256];
  1145.  
  1146.     dwFrameCount++;
  1147.     time2 = timeGetTime() - dwFrameTime;
  1148.     if( time2 > 1000 )
  1149.     {
  1150.         dwFrames = (dwFrameCount*1000)/time2;
  1151.         dwFrameTime = timeGetTime();
  1152.         dwFrameCount = 0;
  1153.     }
  1154.     if( dwFrames == 0 )
  1155.     {
  1156.         return;
  1157.     }
  1158.  
  1159.     if (dwFrames != dwFramesLast)
  1160.     {
  1161.         dwFramesLast = dwFrames;
  1162.     }
  1163.  
  1164.     if( dwFrames > 99 )
  1165.     {
  1166.         dwFrames = 99;
  1167.     }
  1168.     buff[0] = (char)((dwFrames / 10) + '0');
  1169.     buff[1] = (char)((dwFrames % 10) + '0');
  1170.     buff[2] = '\0';
  1171.     bltScore(buff, ScreenX/2-25, 10);
  1172. }
  1173.  
  1174. void DeleteFromList( LPDBLNODE this )
  1175. {
  1176.     this->next->prev = this->prev;
  1177.     this->prev->next = this->next;
  1178.     LocalFree( this );
  1179. }
  1180.  
  1181. void UpdateDisplayList( void )
  1182. {
  1183.     LPDBLNODE   this;
  1184.     LPDBLNODE   save;
  1185.     DWORD       thisTickCount = GetTickCount();
  1186.     DWORD       tickDiff = thisTickCount - lastTickCount;
  1187.     double      maxx, maxy;
  1188.     double      maxframe;
  1189.     DWORD       input = lastInput;
  1190.     BOOL        event = FALSE;
  1191.     BOOL        fBounce = FALSE;
  1192.     LONG        lAngle = 0;
  1193.  
  1194.     if( bTest )
  1195.     {
  1196.         input |= (KEY_RIGHT | KEY_FIRE);
  1197.     }
  1198.     lastTickCount = thisTickCount;
  1199.  
  1200.     // get the state of the input device
  1201.     input = inputProcessDeviceInput();
  1202.  
  1203.     if (showDelay)
  1204.     {
  1205.         showDelay -= (int)tickDiff;
  1206.         if (showDelay < 0)
  1207.         {
  1208.             showDelay = 0;
  1209.             lastShield = FALSE;
  1210.             initShip( FALSE );
  1211.         }
  1212.     }
  1213.  
  1214.     // update the ship
  1215.     if( !showDelay )
  1216.     {
  1217.         DL.posx += DL.velx * (double)tickDiff;
  1218.         DL.posy += DL.vely * (double)tickDiff;
  1219.     }
  1220.     if( DL.posx > MAX_SHIP_X )
  1221.     {
  1222.         DL.posx = MAX_SHIP_X;
  1223.         DL.velx = -DL.velx;
  1224.         event = TRUE;
  1225.         // set the bounce angle
  1226.         // (bouncing off the right edge of the screen)
  1227.         fBounce = TRUE;
  1228.         lAngle = 90;
  1229.     }
  1230.     else if ( DL.posx < 0 )
  1231.     {
  1232.         DL.posx =0;
  1233.         DL.velx = -DL.velx;
  1234.         event = TRUE;
  1235.         // set the bounce angle
  1236.         // (bouncing off the left edge of the screen)
  1237.         fBounce = TRUE;
  1238.         lAngle = 270;
  1239.     }
  1240.     if( DL.posy > MAX_SHIP_Y )
  1241.     {
  1242.         DL.posy = MAX_SHIP_Y;
  1243.         DL.vely = -DL.vely;
  1244.         event = TRUE;
  1245.         // set the bounce angle
  1246.         // (bouncing off the bottom edge of the screen)
  1247.         fBounce = TRUE;
  1248.         lAngle = 180;
  1249.     }
  1250.     else if ( DL.posy < 0 )
  1251.     {
  1252.         DL.posy =0;
  1253.         DL.vely = -DL.vely;
  1254.         event = TRUE;
  1255.         // set the bounce angle
  1256.         // (bouncing off the top edge of the screen)
  1257.         fBounce = TRUE;
  1258.         lAngle = 0;
  1259.     }
  1260.  
  1261.     if (event)
  1262.     {
  1263. #ifdef USE_DSOUND
  1264.         if(bWantSound)
  1265.         {
  1266.             playPanned(hsoShipBounce, &DL);
  1267.         }
  1268. #endif
  1269.         event = FALSE;
  1270.     }
  1271.  
  1272.     if(fBounce)
  1273.     {
  1274.         // "bounce" the ship
  1275.         inputPlayEffect(EF_BOUNCE, lAngle);
  1276.     }
  1277.  
  1278.     if ((event = (showDelay || ((input & KEY_SHIELD) == KEY_SHIELD))) !=
  1279.         lastShield)
  1280.     {
  1281.         if (event && !showDelay)
  1282.         {
  1283. #ifdef USE_DSOUND
  1284.             if(bWantSound)
  1285.             {
  1286.                 SndObjPlay(hsoShieldBuzz, DSBPLAY_LOOPING);
  1287.             }
  1288. #endif
  1289.             bPlayBuzz = TRUE;
  1290.         }
  1291.         else
  1292.         {
  1293. #ifdef USE_DSOUND
  1294.             if(bWantSound)
  1295.             {
  1296.                 SndObjStop(hsoShieldBuzz);
  1297.             }
  1298. #endif
  1299.             bPlayBuzz = FALSE;
  1300.         }
  1301.         lastShield = event;
  1302.     }
  1303.     if (event)
  1304.     {
  1305.         input &= ~(KEY_FIRE);
  1306.     }
  1307.  
  1308.     if (input & KEY_FIRE)
  1309.     {
  1310.         if( !showDelay )
  1311.         {
  1312.             // add a bullet to the scene
  1313.             score--;
  1314.             if(score < 0)
  1315.                 score = 0;
  1316.  
  1317. #ifdef USE_DSOUND
  1318.             if(bWantSound)
  1319.             {
  1320.                 SndObjPlay(hsoFireBullet, 0);
  1321.             }
  1322. #endif
  1323.  
  1324.            // play the "fire" effect
  1325.            inputPlayEffect(EF_FIRE, 0);
  1326.  
  1327.             addObject( OBJ_BULLET, Dirx[(int)DL.frame]*6.0 + 16.0 + DL.posx,
  1328.                                    Diry[(int)DL.frame]*6.0 + 16.0 + DL.posy,
  1329.                                    Dirx[(int)DL.frame]*500.0/1000.0,
  1330.                                    Diry[(int)DL.frame]*500.0/1000.0 );
  1331.         }
  1332.     }
  1333.  
  1334.     event = FALSE;
  1335.     if( input & KEY_LEFT )
  1336.     {
  1337.             DL.frame -= 1.0;
  1338.             if( DL.frame < 0.0 )
  1339.                 DL.frame += MAX_SHIP_FRAME;
  1340.     }
  1341.     if( input & KEY_RIGHT )
  1342.     {
  1343.             DL.frame += 1.0;
  1344.             if( DL.frame >= MAX_SHIP_FRAME)
  1345.                 DL.frame -= MAX_SHIP_FRAME;
  1346.     }
  1347.     if( input & KEY_UP )
  1348.     {
  1349.             DL.velx += Dirx[(int)DL.frame] * 10.0/1000.0;
  1350.             DL.vely += Diry[(int)DL.frame] * 10.0/1000.0;
  1351.             event = TRUE;
  1352.     }
  1353.     if( input & KEY_DOWN )
  1354.     {
  1355.             DL.velx -= Dirx[(int)DL.frame] * 10.0/1000.0;
  1356.             DL.vely -= Diry[(int)DL.frame] * 10.0/1000.0;
  1357.             event = TRUE;
  1358.     }
  1359.  
  1360.     if (event != lastThrust)
  1361.     {
  1362.         if (event)
  1363.         {
  1364.             input &= ~KEY_STOP;
  1365. #ifdef USE_DSOUND
  1366.             if(bWantSound)
  1367.             {
  1368.                 SndObjStop(hsoSkidToStop);
  1369.                 SndObjPlay(hsoEngineRev, DSBPLAY_LOOPING);
  1370.             }
  1371. #endif
  1372.             bPlayRev = TRUE;
  1373.         }
  1374.         else
  1375.         {
  1376. #ifdef USE_DSOUND
  1377.             if(bWantSound)
  1378.             {
  1379.                 SndObjStop(hsoEngineRev);
  1380.             }
  1381. #endif
  1382.             bPlayRev = FALSE;
  1383.         }
  1384.  
  1385.         lastThrust = event;
  1386.     }
  1387.  
  1388.     if( input & KEY_STOP )
  1389.     {
  1390. #ifdef USE_DSOUND
  1391.         if(bWantSound)
  1392.         {
  1393.             if (DL.velx || DL.vely)
  1394.             {
  1395.                 playPanned(hsoSkidToStop, &DL);
  1396.             }
  1397.         }
  1398. #endif
  1399.         DL.velx = 0;
  1400.         DL.vely = 0;
  1401.     }
  1402.  
  1403.     this = DL.next;
  1404.     do
  1405.     {
  1406.         this->posx += this->velx * (double)tickDiff;
  1407.         this->posy += this->vely * (double)tickDiff;
  1408.         this->frame += this->delay * (double)tickDiff;
  1409.         switch( this->type )
  1410.         {
  1411.             case OBJ_DONUT:
  1412.                 maxx = (double)MAX_DONUT_X;
  1413.                 maxy = (double)MAX_DONUT_Y;
  1414.                 maxframe = (double)MAX_DONUT_FRAME;
  1415.                 break;
  1416.             case OBJ_PYRAMID:
  1417.                 maxx = (double)MAX_PYRAMID_X;
  1418.                 maxy = (double)MAX_PYRAMID_Y;
  1419.                 maxframe = (double)MAX_PYRAMID_FRAME;
  1420.                 break;
  1421.             case OBJ_SPHERE:
  1422.                 maxx = (double)MAX_SPHERE_X;
  1423.                 maxy = (double)MAX_SPHERE_Y;
  1424.                 maxframe = (double)MAX_SPHERE_FRAME;
  1425.                 break;
  1426.             case OBJ_CUBE:
  1427.                 maxx = (double)MAX_CUBE_X;
  1428.                 maxy = (double)MAX_CUBE_Y;
  1429.                 maxframe = (double)MAX_CUBE_FRAME;
  1430.                 break;
  1431.             case OBJ_BULLET:
  1432.                 maxx = (double)MAX_BULLET_X;
  1433.                 maxy = (double)MAX_BULLET_Y;
  1434.                 maxframe = (double)MAX_BULLET_FRAME;
  1435.                 if( this->frame >= (double)MAX_BULLET_FRAME )
  1436.                 {
  1437.                     save = this;
  1438.                     this = this->next;
  1439.                     DeleteFromList( save );
  1440.                     continue;
  1441.                 }
  1442.                 break;
  1443.         }
  1444.         if( this != &DL )
  1445.         {
  1446.             if( this->posx > maxx )
  1447.             {
  1448.                 this->posx = maxx;
  1449.                 this->velx = -this->velx;
  1450.             }
  1451.             else if ( this->posx < 0 )
  1452.             {
  1453.                 this->posx =0;
  1454.                 this->velx = -this->velx;
  1455.             }
  1456.             if( this->posy > maxy )
  1457.             {
  1458.                 this->posy = maxy;
  1459.                 this->vely = -this->vely;
  1460.             }
  1461.             else if ( this->posy < 0 )
  1462.             {
  1463.                 this->posy =0;
  1464.                 this->vely = -this->vely;
  1465.             }
  1466.             if( this->frame >= maxframe )
  1467.             {
  1468.                 this->frame -= maxframe;
  1469.             }
  1470.             this = this->next;
  1471.         }
  1472.     }
  1473.     while( this != &DL );
  1474. }
  1475.  
  1476. BOOL isDisplayListEmpty( void )
  1477. {
  1478.     LPDBLNODE ptr;
  1479.  
  1480.     for(ptr=DL.next; ptr != &DL; ptr = ptr->next)
  1481.     {
  1482.         if(ptr->type != OBJ_BULLET)
  1483.             return FALSE;
  1484.     }
  1485.     return TRUE;
  1486. }
  1487.  
  1488. void initShip( BOOL delay )
  1489. {
  1490.     DL.posx = (double)(ScreenX/2-16);       // center the ship
  1491.     DL.posy = (double)(ScreenY/2-16);
  1492.     DL.frame = 0.0;
  1493.     if( bTest )
  1494.     {
  1495.         DL.velx = 0.25;
  1496.         DL.vely = 0.5;
  1497.     }
  1498.     else
  1499.     {
  1500.         DL.velx = DL.vely = 0.0;        // not moving
  1501.     }
  1502.     if( !bTest && delay )
  1503.         showDelay = DEF_SHOW_DELAY;
  1504. }
  1505.  
  1506. void initLevel( int level )
  1507. {
  1508.     int     i;
  1509.  
  1510.     // clear any stray bullets out of the display list
  1511.     while( DL.next != &DL )
  1512.     {
  1513.         DeleteFromList( DL.next );
  1514.     }
  1515.     for(i=0; i<(2*level-1); i++)
  1516.     {
  1517.         addObject( OBJ_DONUT, -1.0, -1.0, -1.0, -1.0 );
  1518.     }
  1519.     initShip(TRUE);
  1520. }
  1521.  
  1522. void addObject( SHORT type, double x, double y, double vx, double vy )
  1523. {
  1524.     LPDBLNODE   new;
  1525.  
  1526.     new = (LPDBLNODE) LocalAlloc( LPTR, sizeof( DBLNODE ) );
  1527.     if( new == NULL)
  1528.         return;
  1529.  
  1530.     new->type = type;
  1531.     switch( type )
  1532.     {
  1533.         case OBJ_DONUT:
  1534.             if( x < 0.0) // no position specified?
  1535.             {
  1536.                 new->posx = randDouble( 0.0, (double)MAX_DONUT_X );
  1537.                 new->posy = randDouble( 0.0, (double)MAX_DONUT_Y );
  1538.             }
  1539.             else
  1540.             {
  1541.                 new->posx = x;
  1542.                 new->posy = y;
  1543.             }
  1544.             new->velx = randDouble( -50.0/1000.0, 50.0/1000.0 );
  1545.             new->vely = randDouble( -50.0/1000.0, 50.0/1000.0 );
  1546.             new->frame = randDouble( 0, 30 );
  1547.             new->delay = 30.0*randDouble( 0.1, 0.4 )/1000.0;
  1548.             new->surf = lpDonut;
  1549.             linkObject( new );
  1550.             break;
  1551.         case OBJ_PYRAMID:
  1552.             if( x < 0) // no position specified?
  1553.             {
  1554.                 new->posx = randDouble( 0.0, (double)MAX_PYRAMID_X );
  1555.                 new->posy = randDouble( 0.0, (double)MAX_PYRAMID_Y );
  1556.             }
  1557.             else
  1558.             {
  1559.                 new->posx = x;
  1560.                 new->posy = y;
  1561.             }
  1562.             new->velx = 1.5*randDouble( -50.0/1000.0, 50.0/1000.0 );
  1563.             new->vely = 1.5*randDouble( -50.0/1000.0, 50.0/1000.0 );
  1564.             new->frame = randDouble( 0, 30 );
  1565.             new->delay = 40.0*randDouble( 0.3, 1.0 )/1000.0;
  1566.             new->surf = lpPyramid;
  1567.             linkObject( new );
  1568.             break;
  1569.         case OBJ_SPHERE:
  1570.             if( x < 0) // no position specified?
  1571.             {
  1572.                 new->posx = randDouble( 0.0, (double)MAX_SPHERE_X );
  1573.                 new->posy = randDouble( 0.0, (double)MAX_SPHERE_Y );
  1574.             }
  1575.             else
  1576.             {
  1577.                 new->posx = x;
  1578.                 new->posy = y;
  1579.             }
  1580.             new->velx = 3.0*randDouble( -50.0/1000.0, 50.0/1000.0 );
  1581.             new->vely = 3.0*randDouble( -50.0/1000.0, 50.0/1000.0 );
  1582.             new->frame = randDouble( 0, 30 );
  1583.             new->delay = 40.0*randDouble( 1.5, 2.0 )/1000.0;
  1584.             new->surf = lpSphere;
  1585.             linkObject( new );
  1586.             break;
  1587.         case OBJ_CUBE:
  1588.             if( x < 0) // no position specified?
  1589.             {
  1590.                 new->posx = randDouble( 0.0, (double)MAX_CUBE_X );
  1591.                 new->posy = randDouble( 0.0, (double)MAX_CUBE_Y );
  1592.             }
  1593.             else
  1594.             {
  1595.                 new->posx = x;
  1596.                 new->posy = y;
  1597.             }
  1598.             new->velx = 4.0*randDouble( -50.0/1000.0, 50.0/1000.0 );
  1599.             new->vely = 4.0*randDouble( -50.0/1000.0, 50.0/1000.0 );
  1600.             new->frame = randDouble( 0, 30 );
  1601.             new->delay = 40.0*randDouble( 0.8, 2.0 )/1000.0;
  1602.             new->surf = lpCube;
  1603.             linkObject( new );
  1604.             break;
  1605.         case OBJ_BULLET:
  1606.             new->posx = x;
  1607.             new->posy = y;
  1608.             new->velx = vx;
  1609.             new->vely = vy;
  1610.             new->frame = 0.0;
  1611.             new->delay = 1.0;
  1612.             new->surf = lpNum;
  1613.             linkObject( new );
  1614.             break;
  1615.     }
  1616. }
  1617.  
  1618. void linkObject( LPDBLNODE new )
  1619. {
  1620.     new->next = DL.next;
  1621.     new->prev = &DL;
  1622.     DL.next->prev = new;
  1623.     DL.next = new;
  1624. }
  1625.  
  1626. void linkLastObject( LPDBLNODE new )
  1627. {
  1628.     new->prev = DL.prev;
  1629.     new->next = &DL;
  1630.     DL.prev->next = new;
  1631.     DL.prev = new;
  1632. }
  1633.  
  1634.  
  1635. BOOL RestoreSurfaces( void )
  1636. {
  1637.     HRESULT     ddrval;
  1638.     HBITMAP     hbm;
  1639.  
  1640.     ddrval = lpFrontBuffer->lpVtbl->Restore(lpFrontBuffer);
  1641.     if( ddrval != DD_OK )
  1642.         return FALSE;
  1643.     ddrval = lpDonut->lpVtbl->Restore(lpDonut);
  1644.     if( ddrval != DD_OK )
  1645.         return FALSE;
  1646.     ddrval = lpPyramid->lpVtbl->Restore(lpPyramid);
  1647.     if( ddrval != DD_OK )
  1648.         return FALSE;
  1649.     ddrval = lpCube->lpVtbl->Restore(lpCube);
  1650.     if( ddrval != DD_OK )
  1651.         return FALSE;
  1652.     ddrval = lpSphere->lpVtbl->Restore(lpSphere);
  1653.     if( ddrval != DD_OK )
  1654.         return FALSE;
  1655.     ddrval = lpShip->lpVtbl->Restore(lpShip);
  1656.     if( ddrval != DD_OK )
  1657.         return FALSE;
  1658.     ddrval = lpNum->lpVtbl->Restore(lpNum);
  1659.     if( ddrval != DD_OK )
  1660.         return FALSE;
  1661.  
  1662.     // Create and set the palette for the splash bitmap
  1663.     lpSplashPalette = DDLoadPalette( lpDD, "SPLASH" );
  1664.     if( NULL == lpSplashPalette )
  1665.         return CleanupAndExit("DDLoadPalette SPLASH");
  1666.  
  1667.     // Create and set the palette for the art bitmap
  1668.     lpArtPalette = DDLoadPalette( lpDD, "DONUTS8" );
  1669.     if( NULL == lpArtPalette )
  1670.         return CleanupAndExit("DDLoadPalette DONUTS");
  1671.  
  1672.     // set the palette before loading the art
  1673.     lpFrontBuffer->lpVtbl->SetPalette( lpFrontBuffer, lpArtPalette );
  1674.  
  1675.     hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "DONUTS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
  1676.  
  1677.     if( NULL == hbm )
  1678.         return FALSE;
  1679.  
  1680.     ddrval = DDCopyBitmap( lpDonut, hbm, 0, 0, 320, 384 );
  1681.     if( ddrval != DD_OK )
  1682.     {
  1683.         DeleteObject( hbm );
  1684.         return FALSE;
  1685.     }
  1686.  
  1687.     // NOTE: Why are we calling LoadImage again?  StretchBlt (which is
  1688.     // called in DDCopyBitmap) does not work properly when performing
  1689.     // an 8-bpp to 24- or 32-bpp blt multiple times from the same
  1690.     // bitmap.  The workaround is to call LoadImage before each
  1691.     // StretchBlt because the first StretchBlt after a LoadImage will
  1692.     // work.
  1693.     if(ScreenBpp >= 24)
  1694.     {
  1695.         DeleteObject( hbm );
  1696.         hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "DONUTS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
  1697.         
  1698.         if( NULL == hbm )
  1699.             return FALSE;
  1700.     }
  1701.  
  1702.     ddrval = DDCopyBitmap( lpPyramid, hbm, 0, 384, 320, 128 );
  1703.     if( ddrval != DD_OK )
  1704.     {
  1705.         DeleteObject( hbm );
  1706.         return FALSE;
  1707.     }
  1708.  
  1709.     if(ScreenBpp >= 24)
  1710.     {
  1711.         DeleteObject( hbm );
  1712.         hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "DONUTS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
  1713.         
  1714.         if( NULL == hbm )
  1715.             return FALSE;
  1716.     }
  1717.  
  1718.     ddrval = DDCopyBitmap( lpSphere, hbm, 0, 512, 320, 32 );
  1719.     if( ddrval != DD_OK )
  1720.     {
  1721.         DeleteObject( hbm );
  1722.         return FALSE;
  1723.     }
  1724.  
  1725.     if(ScreenBpp >= 24)
  1726.     {
  1727.         DeleteObject( hbm );
  1728.         hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "DONUTS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
  1729.         
  1730.         if( NULL == hbm )
  1731.             return FALSE;
  1732.     }
  1733.  
  1734.     ddrval = DDCopyBitmap( lpCube, hbm, 0, 544, 320, 32 );
  1735.     if( ddrval != DD_OK )
  1736.     {
  1737.         DeleteObject( hbm );
  1738.         return FALSE;
  1739.     }
  1740.  
  1741.     if(ScreenBpp >= 24)
  1742.     {
  1743.         DeleteObject( hbm );
  1744.         hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "DONUTS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
  1745.         
  1746.         if( NULL == hbm )
  1747.             return FALSE;
  1748.     }
  1749.  
  1750.     ddrval = DDCopyBitmap( lpShip, hbm, 0, 576, 320, 256 );
  1751.     if( ddrval != DD_OK )
  1752.     {
  1753.         DeleteObject( hbm );
  1754.         return FALSE;
  1755.     }
  1756.  
  1757.     if(ScreenBpp >= 24)
  1758.     {
  1759.         DeleteObject( hbm );
  1760.         hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), "DONUTS8", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
  1761.         
  1762.         if( NULL == hbm )
  1763.             return FALSE;
  1764.     }
  1765.  
  1766.     ddrval = DDCopyBitmap( lpNum, hbm, 0, 832, 320, 16 );
  1767.     if( ddrval != DD_OK )
  1768.     {
  1769.         DeleteObject( hbm );
  1770.         return FALSE;
  1771.     }
  1772.  
  1773.     DeleteObject( hbm );
  1774.  
  1775.     // set colorfill colors and color keys according to bitmap contents
  1776.     dwFillColor = DDColorMatch( lpDonut, CLR_INVALID );
  1777.  
  1778.     DDSetColorKey( lpDonut, CLR_INVALID );
  1779.     DDSetColorKey( lpPyramid, CLR_INVALID );
  1780.     DDSetColorKey( lpCube, CLR_INVALID );
  1781.     DDSetColorKey( lpSphere, CLR_INVALID );
  1782.     DDSetColorKey( lpShip, CLR_INVALID );
  1783.     DDSetColorKey( lpNum, CLR_INVALID );
  1784.  
  1785.     return TRUE;
  1786. }
  1787.  
  1788.  
  1789. int randInt( int low, int high )
  1790. {
  1791.     int range = high - low;
  1792.     int num = rand() % range;
  1793.     return( num + low );
  1794. }
  1795.  
  1796. double randDouble( double low, double high )
  1797. {
  1798.     double range = high - low;
  1799.     double num = range * (double)rand()/(double)RAND_MAX;
  1800.     return( num + low );
  1801. }
  1802.  
  1803.  
  1804. #ifdef USE_DSOUND
  1805. void InitializeSound( void )
  1806. {
  1807.         if(!bWantSound)
  1808.                 return; // out of here
  1809.     bSoundEnabled = FALSE;
  1810.     if (SUCCEEDED(DirectSoundCreate(NULL, &lpDS, NULL)))
  1811.     {
  1812.         if (SUCCEEDED(lpDS->lpVtbl->SetCooperativeLevel(lpDS, hWndMain,
  1813.             DSSCL_NORMAL)))
  1814.         {
  1815.             hsoBeginLevel     = SndObjCreate(lpDS, "BeginLevel",      1);
  1816.             hsoEngineIdle     = SndObjCreate(lpDS, "EngineIdle",      1);
  1817.             hsoEngineRev      = SndObjCreate(lpDS, "EngineRev",       1);
  1818.             hsoSkidToStop     = SndObjCreate(lpDS, "SkidToStop",      1);
  1819.             hsoShieldBuzz     = SndObjCreate(lpDS, "ShieldBuzz",      1);
  1820.             hsoShipExplode    = SndObjCreate(lpDS, "ShipExplode",     1);
  1821.             hsoFireBullet     = SndObjCreate(lpDS, "Gunfire",        25);
  1822.             hsoShipBounce     = SndObjCreate(lpDS, "ShipBounce",      4);
  1823.             hsoDonutExplode   = SndObjCreate(lpDS, "DonutExplode",   10);
  1824.             hsoPyramidExplode = SndObjCreate(lpDS, "PyramidExplode", 12);
  1825.             hsoCubeExplode    = SndObjCreate(lpDS, "CubeExplode",    15);
  1826.             hsoSphereExplode  = SndObjCreate(lpDS, "SphereExplode",  10);
  1827.             bSoundEnabled = TRUE;
  1828.  
  1829.             if( bPlayIdle )
  1830.                 SndObjPlay(hsoEngineIdle, DSBPLAY_LOOPING);
  1831.  
  1832.             if( bPlayBuzz )
  1833.                 SndObjPlay(hsoShieldBuzz, DSBPLAY_LOOPING);
  1834.  
  1835.             if( bPlayRev )
  1836.                 SndObjPlay(hsoEngineRev, DSBPLAY_LOOPING);
  1837.         }
  1838.         else
  1839.         {
  1840.             lpDS->lpVtbl->Release(lpDS);
  1841.             lpDS = NULL;
  1842.         }
  1843.     }
  1844. }
  1845.  
  1846. void DestroySound( void )
  1847. {
  1848.         if(!bWantSound)
  1849.                 return; //No work to be done
  1850.     bSoundEnabled = FALSE;
  1851.     if (lpDS)
  1852.     {
  1853.         SndObjDestroy(hsoBeginLevel);
  1854.         hsoBeginLevel = NULL;
  1855.         SndObjDestroy(hsoEngineIdle);
  1856.         hsoEngineIdle = NULL;
  1857.         SndObjDestroy(hsoEngineRev);
  1858.         hsoEngineRev = NULL;
  1859.         SndObjDestroy(hsoSkidToStop);
  1860.         hsoSkidToStop = NULL;
  1861.         SndObjDestroy(hsoShieldBuzz);
  1862.         hsoShieldBuzz = NULL;
  1863.         SndObjDestroy(hsoShipExplode);
  1864.         hsoShipExplode = NULL;
  1865.         SndObjDestroy(hsoFireBullet);
  1866.         hsoFireBullet = NULL;
  1867.         SndObjDestroy(hsoShipBounce);
  1868.         hsoShipBounce = NULL;
  1869.         SndObjDestroy(hsoDonutExplode);
  1870.         hsoDonutExplode = NULL;
  1871.         SndObjDestroy(hsoPyramidExplode);
  1872.         hsoPyramidExplode = NULL;
  1873.         SndObjDestroy(hsoCubeExplode);
  1874.         hsoCubeExplode = NULL;
  1875.         SndObjDestroy(hsoSphereExplode);
  1876.         hsoSphereExplode = NULL;
  1877.  
  1878.         lpDS->lpVtbl->Release(lpDS);
  1879.         lpDS = NULL;
  1880.     }
  1881. }
  1882. #endif
  1883.  
  1884.  
  1885. int getint(char**p, int def)
  1886. {
  1887.     int i=0;                                 
  1888.  
  1889.  
  1890.     while (IS_SPACE(**p))
  1891.         (*p)++;
  1892.  
  1893.     if (!IS_NUM(**p))
  1894.         return def;
  1895.  
  1896.     while (IS_NUM(**p))
  1897.         i = i*10 + *(*p)++ - '0';
  1898.  
  1899.     while (IS_SPACE(**p))
  1900.         (*p)++;
  1901.  
  1902.     return i;
  1903. }
  1904.  
  1905.