home *** CD-ROM | disk | FTP | other *** search
/ NEXT Generation 27 / NEXT27.iso / pc / demos / emperor / dx3.exe / SDK / SAMPLES / DONUTS / DONUTS.C < prev    next >
C/C++ Source or Header  |  1996-08-28  |  53KB  |  1,881 lines

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