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 / donuts / donuts.c < prev    next >
C/C++ Source or Header  |  1997-07-14  |  53KB  |  1,942 lines

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