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

Windows编程

开发平台:

Visual C++

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