MAIN.CPP

/*========================================================================== 
*
* Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
*
* File: main.cpp
*
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 15-sep-97 t-craigs Created
*@@END_MSINTERNAL
*
***************************************************************************/

#include "donuts.h"

// globals defined elsewhere
externCMyMonitorMonitor[9];
externCShipDL;
externdoubleDirx[40];
externdoubleDiry[40];

// globals
#ifdef DEBUG
char DebugBuf[256];
#endif

BOOL bSoundEnabled = FALSE;
BOOL bPlayIdle = FALSE;
BOOL bPlayBuzz = FALSE;
BOOL bPlayRev = FALSE;
#ifdef USE_DSOUND
LPDIRECTSOUND lpDS;
HSNDOBJ hsoBeginLevel = NULL;
HSNDOBJ hsoEngineIdle = NULL;
HSNDOBJ hsoEngineRev = NULL;
HSNDOBJ hsoSkidToStop = NULL;
HSNDOBJ hsoShieldBuzz = NULL;
HSNDOBJ hsoShipExplode = NULL;
HSNDOBJ hsoFireBullet = NULL;
HSNDOBJ hsoShipBounce = NULL;
HSNDOBJ hsoDonutExplode = NULL;
HSNDOBJ hsoPyramidExplode = NULL;
HSNDOBJ hsoCubeExplode = NULL;
HSNDOBJ hsoSphereExplode = NULL;
#endif

// global data
HWND hWndMain;
HACCEL hAccel;
HINSTANCE hInst;
BOOL bIsActive;

BOOL bSpecialEffects = FALSE;
BOOL bWantSound = TRUE;
BOOL bShowFrameCount=TRUE;

BOOL lastThrust = FALSE;
int showDelay = 0;
BOOL bMouseVisible;
DWORD dwFrameCount;
DWORD dwFrameTime;
DWORD dwFrames;
DWORD dwFramesLast;
DWORD lastTickCount;
int score;
int ProgramState;
int level;
int restCount;
DWORD ShowLevelCount = 3000;
intiForceErase = 0;
RECTrcVirtualDesktop;


//
// FUNCTION:WinMain
//
// DESCRIPTION:Contains main program loop
//
// NOTES:- program starts here!
//
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow )
{
MSG msg;

// save application instance
hInst = hInstance;

while( lpCmdLine[0] == '-' )
{
lpCmdLine++;

switch (*lpCmdLine++)
{
case 'S': case 's':
bWantSound = FALSE;
break;
}
while( IS_SPACE(*lpCmdLine) )
{
lpCmdLine++;
}
}

// initialize display system
if ( CMyMonitor::Initialize() != DD_OK )
{
CleanupAndExit("Couldn't initialize multimonitor system");
return -1;
}

rcVirtualDesktop.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
rcVirtualDesktop.right = rcVirtualDesktop.left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
rcVirtualDesktop.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
rcVirtualDesktop.bottom = rcVirtualDesktop.left + GetSystemMetrics(SM_CYVIRTUALSCREEN);

if( !InitApplication(hInstance, nCmdShow) )
{
DestroyWindow( hWndMain );
return FALSE;
}

if( !InitializeGame() )
{
DestroyWindow( hWndMain );
return FALSE;
}

dwFrameTime = timeGetTime();

while( 1 )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
if( !GetMessage( &msg, NULL, 0, 0 ) )
{
return msg.wParam;
}
if ( !TranslateAccelerator( hWndMain, hAccel, &msg ) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else if ( bIsActive )
{
UpdateFrame();
}
else
{
WaitMessage();
}
}
} /* WinMain */


//
// FUNCTION:MainWndproc
//
// DESCRIPTION:Window procedure for message handling
//
// NOTES:
//
long FAR PASCAL MainWndproc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
UINT cmd;
//PAINTSTRUCT ps;

switch( message )
{
case WM_ACTIVATEAPP:
bIsActive = (BOOL) wParam;
if( bIsActive )
{
bMouseVisible = FALSE;
lastTickCount = GetTickCount();
bSpecialEffects = FALSE;
// we are active, need to reacquire the keyboard
ReacquireInput();
}
else
{
bMouseVisible = TRUE;
// DirectInput automatically unacquires for us in FOREGROUND mode
}
break;

case WM_CREATE:
break;

case WM_SETCURSOR:
if( !bMouseVisible )
{
SetCursor(NULL);
}
else
{
SetCursor(LoadCursor( NULL, IDC_ARROW ));
}
return TRUE;

case WM_COMMAND:
cmd = GET_WM_COMMAND_ID(wParam, lParam);

if (cmd >= IDC_DEVICES && cmd < IDC_DEVICES + 100)
{
PickInputDevice(cmd - IDC_DEVICES);
}
else
{
switch (cmd)
{
case IDC_FRAMERATE:
bShowFrameCount = !bShowFrameCount;
if( bShowFrameCount )
{
dwFrameCount = 0;
dwFrameTime = timeGetTime();
}
break;

case IDC_STARTGAME:
if( ProgramState == PS_SPLASH )
{
ProgramState = PS_BEGINREST;
SetupGame();
}
break;

case IDC_QUIT:
PostMessage( hWnd, WM_CLOSE, 0, 0 );
return 0;

case IDC_AUDIO:
#ifdef USE_DSOUND
if(bWantSound)
{
if( bSoundEnabled )
{
DestroySound();
}
else
{
InitializeSound();
}
}
#endif
break;

case IDC_TRAILS:
bSpecialEffects = !bSpecialEffects;
break;
}
break;
}

case WM_INITMENU:
CheckMenuItems(hWndMain);
break;

case WM_ERASEBKGND:
return 1;
/*
case WM_PAINT:
BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
return 1;
*/
case WM_DESTROY:
CleanupAndExit(NULL);
PostQuitMessage( 0 );
break;

case WM_ENTERMENULOOP:
AppPause();
break;

case WM_EXITMENULOOP:
AppUnpause();
break;

default:
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);

} /* MainWndproc */



//
// FUNCTION:InitApplication
//
// DESCRIPTION:Perform window creation
//
// NOTES:
//
BOOL InitApplication( HANDLE hInstance, int nCmdShow )
{
WNDCLASS wc;
BOOL rc;

wc.style = CS_DBLCLKS;
wc.lpfnWndProc = MainWndproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(DONUTS_ICON));
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = GetStockObject( BLACK_BRUSH );
wc.lpszMenuName = MAKEINTRESOURCE(DONUTS_MENU);
wc.lpszClassName = "DonutsClass";
rc = RegisterClass( &wc );
if( !rc )
{
return FALSE;
}

hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(DONUTS_ACCEL));
if ( !hAccel )
{
return FALSE;
}

hWndMain = CreateWindowEx(
0,
"DonutsClass",
"Donuts",
WS_VISIBLE | // so we don't have to call ShowWindow
WS_POPUP | // non-app window
WS_CAPTION | // so our menu doesn't look ultra-goofy
WS_SYSMENU, // so we get an icon in the tray
0,
0,
Monitor[0].dwWidth,
Monitor[0].dwHeight,
NULL,
NULL,
hInstance,
NULL );

if( !hWndMain )
{
return FALSE;
}

UpdateWindow( hWndMain );

#ifdef USE_DSOUND
/*
* If sound is globally disabled, then disable the sound menu.
*/
if (!bWantSound)
{
EnableMenuItem(GetMenu(hWndMain), IDC_AUDIO, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
}
#endif
return TRUE;

} /* InitApplication */


//
// FUNCTION:MainWndproc
//
// DESCRIPTION:Initialize DirectX et al
//
// NOTES:
//
BOOL InitializeGame( void )
{
HRESULT ddrval;
for (int i = 0; i < CMonitor::iNumberOfMonitors; i++)
{
ddrval = Monitor[i].DDInit( hWndMain, TRUE );
if ( ddrval != DD_OK )
{
return CleanupAndExit( Monitor[i].szErrMsg, ddrval );
}
ddrval = Monitor[i].RestoreSurfaces();
if ( ddrval != DD_OK )
{
return CleanupAndExit("CMyMonitor::RestoreSurfaces failed", ddrval );
}
}

#ifdef USE_DSOUND
if(bWantSound)
{
InitializeSound();
}
#endif

// initialize DirectInput
if( !InitInput(hInst, hWndMain) )
{
return CleanupAndExit("DirectInput initialization failed");
}

score = 0;

lastTickCount = GetTickCount();

ProgramState = PS_SPLASH;

return TRUE;
}


//
// FUNCTION:AppPause
//
// DESCRIPTION:Draw menu bar
//
// NOTES:
//
void AppPause(void)
{
DrawMenuBar(hWndMain);
RedrawWindow(hWndMain, NULL, NULL, RDW_FRAME);
Monitor[0].lpDD->FlipToGDISurface();
}

//
// FUNCTION:AppUnpause
//
// DESCRIPTION:Reset the various time counters so the donuts don't suddenly
//jump halfway across the screen and so the frame rate remains accurate.
//
// NOTES:
//
void AppUnpause(void)
{
iForceErase = 2;
lastTickCount = dwFrameTime = timeGetTime();
}

//
// FUNCTION:CheckOneMenuItem
//
// DESCRIPTION:Checks a single item in a menu
//
// NOTES:
//
void CheckOneMenuItem(HMENU hmenu, UINT idc, BOOL fCheck)
{
CheckMenuItem(hmenu, idc,
fCheck ? (MF_BYCOMMAND | MF_CHECKED)
: (MF_BYCOMMAND | MF_UNCHECKED));
}

//
// FUNCTION:AppUnpause
//
// DESCRIPTION:Sync menu checkmarks with internal variables
//
// NOTES:
//
void CheckMenuItems(HWND hwnd)
{
HMENU hmenu = GetMenu(hwnd);

CheckOneMenuItem(hmenu, IDC_TRAILS, bSpecialEffects);

#ifdef USE_DSOUND
CheckOneMenuItem(hmenu, IDC_AUDIO, bWantSound && bSoundEnabled);
#endif

CheckOneMenuItem(hmenu, IDC_FRAMERATE, bShowFrameCount);

}


//
// FUNCTION:DisplayLevel
//
// DESCRIPTION:Blit "Level ###"
//
// NOTES:
//
void DisplayLevel( void )
{
char buf[10];
int left, top;

EraseScreen();
buf[0] = 10 + '0';
buf[1] = 11 + '0';
buf[2] = 12 + '0';
buf[3] = 11 + '0';
buf[4] = 10 + '0';
buf[5] = '\0';

top = Monitor[DL.iMonitor].dwHeight / 2 - 8;
left = (Monitor[DL.iMonitor].dwWidth - 16 * 9) / 2;
BltScore( buf, left, top );

buf[0] = level / 100 + '0';
buf[1] = level / 10 + '0';
buf[2] = level % 10 + '0';
buf[3] = '\0';

left += 16 * 6;
BltScore( buf, left, top );
FlipScreen();
}


//
// FUNCTION:DisplayFrameRate
//
// DESCRIPTION:Blit the frame rate
//
// NOTES:
//
void DisplayFrameRate( void )
{
DWORDtime2;
char buff[256];

dwFrameCount++;
time2 = timeGetTime() - dwFrameTime;
if( time2 > 1000 )
{
dwFrames = (dwFrameCount*1000)/time2;
dwFrameTime = timeGetTime();
dwFrameCount = 0;
}
if( dwFrames == 0 )
{
return;
}

if (dwFrames != dwFramesLast)
{
dwFramesLast = dwFrames;
}

if( dwFrames > 99 )
{
dwFrames = 99;
}
buff[0] = (char)((dwFrames / 10) + '0');
buff[1] = (char)((dwFrames % 10) + '0');
buff[2] = '\0';
BltScore(buff, (int)(0.02 * (double) Monitor[DL.iMonitor].dwWidth), (int)(0.02 * (double) Monitor[DL.iMonitor].dwHeight) );
}


//
// FUNCTION:BltScore
//
// DESCRIPTION:Performs letter & number blitting for frame rate, score, and level ###
//
// NOTES:
//
void BltScore( char *num, int x, int y )
{
int i;
HRESULT ddrval;
DDBLTFX ddbltfx;
DWORDdwFlag;
RECT src;
RECTdst = { x, y, x + 16, y + 16 };

ddbltfx.dwSize = sizeof( ddbltfx );
dwFlag = DDBLT_KEYSRC;

for(char* c=num; *c != '\0'; c++)
{
while( 1 )
{
i = *c - '0';
src.left = i*16;
src.top = 0;
src.right = src.left + 16;
src.bottom = src.top + 16;

ddrval = Monitor[DL.iMonitor].lpBackBuffer->Blt( &dst, Monitor[DL.iMonitor].lpNum, &src, dwFlag, &ddbltfx );
if( ddrval == DD_OK )
{
break;
}
if( ddrval == DDERR_SURFACELOST )
{
ddrval = Monitor[DL.iMonitor].RestoreSurfaces();
if ( ddrval != DD_OK )
{
CleanupAndExit("BltScore (CMyMonitor::RestoreSurfaces) failed", ddrval );
return;
}
}
if( ddrval != DDERR_WASSTILLDRAWING )
{
return;
}
}
dst.left += 16;
dst.right += 16;
}
}

//
// FUNCTION:BltSplash
//
// DESCRIPTION:Display intro screen on the primary monitor
//
// NOTES:
//
void BltSplash( void )
{
HRESULT ddrval;
HBITMAP hbm;
intiMonitor;

// set the palette
Monitor[0].lpFrontBuffer->SetPalette( Monitor[0].lpSplashPalette );

hbm = (HBITMAP)LoadImage( GetModuleHandle( NULL ), "SPLASH", IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION );
if ( hbm == NULL )
return;

// if the surface is lost, DDCopyBitmap will fail and the surface will
// be restored in FlipScreen.
ddrval = DDCopyBitmap( Monitor[0].lpBackBuffer, hbm, 0, 0, 0, 0 );

// blank out other monitors
for (iMonitor = 1; iMonitor < CMonitor::iNumberOfMonitors; iMonitor++)
{
ddrval = Monitor[iMonitor].Blank();
if ( ddrval != DD_OK )
{
CleanupAndExit( "BltSplash (CMyMonitor::Blank) failed", ddrval );
return;
}
}

DeleteObject( hbm );

FlipScreen();
}


//
// FUNCTION:SetupGame
//
// DESCRIPTION:Perform start time initialization
//
// NOTES:
//
void SetupGame(void)
{
restCount = GetTickCount();
InitLevel( ++level );

for(int i=0; i< CMonitor::iNumberOfMonitors; i++)
{
Monitor[i].lpFrontBuffer->SetPalette( Monitor[i].lpArtPalette );
};
}

//
// FUNCTION:EraseScreen
//
// DESCRIPTION:Fill back buffers with background color and draws a border
//
// NOTES:
//
BOOL EraseScreen( void )
{
if ( iForceErase > 0 )
{
--iForceErase;
}
else if( bSpecialEffects )
{
return TRUE;
}

HRESULT ddrval;
for(int iMonitor=0;iMonitor<CMonitor::iNumberOfMonitors;iMonitor++)
{
ddrval = Monitor[iMonitor].Blank();
if ( ddrval != DD_OK )
{
return CleanupAndExit("EraseScreen (CMyMonitor::Blank) failed", ddrval );
}

ddrval = Monitor[iMonitor].DrawBorder();
if ( ddrval != DD_OK )
{
return CleanupAndExit("EraseScreen (CMyMonitor::DrawBorder) failed", ddrval );
}
}
return TRUE;
}

//
// FUNCTION:FlipScreen
//
// DESCRIPTION:Flip back buffers to front buffers
//
// NOTES:
//
BOOL FlipScreen( void )
{
HRESULT ddrval;
for(int iMonitor=0;iMonitor<CMonitor::iNumberOfMonitors;iMonitor++)
{
ddrval = Monitor[iMonitor].Flip();
if ( ddrval != DD_OK )
{
return CleanupAndExit("FlipScreen (CMyMonitor::Flip) failed", ddrval );
}
}
return TRUE;
}


//
// FUNCTION:InitLevel
//
// DESCRIPTION:Perform new level initialization
//
// NOTES:
//
void InitLevel( int level )
{
int i;
doublestartx, starty;

// clear any stray bullets out of the display list
while( DL.next != &DL )
{
DL.next->DeleteFromList();
}

// add some donuts
for(i=0; i<(2*level-1); i++)
{
CObject* pObj = new CDonut;
startx = randDouble( Monitor[DL.iMonitor].lpMonitorRect->left, Monitor[DL.iMonitor].lpMonitorRect->right - pObj->km_iSize );
starty = randDouble( Monitor[DL.iMonitor].lpMonitorRect->top, Monitor[DL.iMonitor].lpMonitorRect->bottom - pObj->km_iSize );

// virtual fct call
pObj->Init( startx, starty );
}
DL.Init();
showDelay = DEF_SHOW_DELAY;
}



//
// FUNCTION:UpdateFrame
//
// DESCRIPTION:Draw the next frame
//
// NOTES:- depends on program state
//- called from main program loop when no messages to process
//
void UpdateFrame( void )
{
switch( ProgramState )
{
case PS_SPLASH:
// display the splash screen
BltSplash();
return;

case PS_ACTIVE:
UpdateDisplayList();
CheckForHits();
DrawDisplayList();

// check if display list is empty
if ( DL.next == &DL && DL.prev == &DL )
{
#ifdef USE_DSOUND
if(bWantSound)
{
SndObjStop(hsoEngineIdle);
SndObjStop(hsoEngineRev);
}
#endif
bPlayIdle = FALSE;
bPlayRev = FALSE;
lastThrust = DL.lastShield = FALSE;
ProgramState = PS_BEGINREST;
restCount = GetTickCount();
InitLevel( ++level );
}
return;

case PS_BEGINREST:
#ifdef USE_DSOUND
if(bWantSound)
{
SndObjPlay(hsoBeginLevel, 0);
}
#endif
ProgramState = PS_REST;
//
// FALLTHRU
//
case PS_REST:
if( ( GetTickCount() - restCount ) > ShowLevelCount )
{
#ifdef USE_DSOUND
if(bWantSound)
{
SndObjPlay(hsoEngineIdle, DSBPLAY_LOOPING);
}
#endif
bPlayIdle = TRUE;
lastTickCount = GetTickCount();
ProgramState = PS_ACTIVE;
}
else
{
DisplayLevel();
}
return;
}
}


//
// FUNCTION:UpdateDisplayList
//
// DESCRIPTION:Add and remove objects from the display list
//
// NOTES:- reads user input
//- adjust position, speed, and animation frame of objects
//
void UpdateDisplayList( void )
{
CObject*cur;
CObject*save;
DWORD input;
DWORD thisTickCount = GetTickCount();
DWORD tickDiff = thisTickCount - lastTickCount;
BOOL event = FALSE;

lastTickCount = thisTickCount;

input = ReadGameInput();

if (showDelay)
{
showDelay -= (int)tickDiff;
if (showDelay < 0)
{
showDelay = 0;
DL.lastShield = FALSE;
DL.Init();
}
}

event = DL.CheckPosition( tickDiff );

if (event)
{
#ifdef USE_DSOUND
if(bWantSound)
{
PlayPanned(hsoShipBounce, DL.posx);
}
#endif
event = FALSE;
}

if ((event = (showDelay || ((input & KEY_SHIELD) == KEY_SHIELD))) != DL.lastShield)
{
if (event && !showDelay)
{
#ifdef USE_DSOUND
if(bWantSound)
{
SndObjPlay(hsoShieldBuzz, DSBPLAY_LOOPING);
}
#endif
bPlayBuzz = TRUE;
}
else
{
#ifdef USE_DSOUND
if(bWantSound)
{
SndObjStop(hsoShieldBuzz);
}
#endif
bPlayBuzz = FALSE;
}
DL.lastShield = event;
}
if (event)
{
input &= ~(KEY_FIRE);
}

if (input & KEY_FIRE)
{
if( !showDelay )
{
// add a bullet to the scene
--score;
if(score < 0)
score = 0;

#ifdef USE_DSOUND
if(bWantSound)
{
SndObjPlay(hsoFireBullet, 0);
}
#endif
CObject* pObj = new CBullet;
// virtual fct. call
pObj->Init( Dirx[(int)DL.frame]*6.0 + 16.0 + DL.posx, Diry[(int)DL.frame]*6.0 + 16.0 + DL.posy );
pObj->velx = Dirx[(int)DL.frame]*500.0/1000.0;
pObj->vely = Diry[(int)DL.frame]*500.0/1000.0;

}
}

event = FALSE;
if( input & KEY_LEFT )
{
DL.frame -= 1.0;
if( DL.frame < 0.0 )
DL.frame += DL.km_iMaxFrame;
}
if( input & KEY_RIGHT )
{
DL.frame += 1.0;
if( DL.frame >= DL.km_iMaxFrame )
DL.frame -= DL.km_iMaxFrame;
}
if( input & KEY_UP )
{
DL.velx += Dirx[(int)DL.frame] * 10.0/1000.0;
DL.vely += Diry[(int)DL.frame] * 10.0/1000.0;
event = TRUE;
}
if( input & KEY_DOWN )
{
DL.velx -= Dirx[(int)DL.frame] * 10.0/1000.0;
DL.vely -= Diry[(int)DL.frame] * 10.0/1000.0;
event = TRUE;
}

if (event != lastThrust)
{
if (event)
{
input &= ~KEY_STOP;
#ifdef USE_DSOUND
if(bWantSound)
{
SndObjStop(hsoSkidToStop);
SndObjPlay(hsoEngineRev, DSBPLAY_LOOPING);
}
#endif
bPlayRev = TRUE;
}
else
{
#ifdef USE_DSOUND
if(bWantSound)
{
SndObjStop(hsoEngineRev);
}
#endif
bPlayRev = FALSE;
}
lastThrust = event;
}

if( input & KEY_STOP )
{
#ifdef USE_DSOUND
if(bWantSound)
{
if (DL.velx || DL.vely)
PlayPanned(hsoSkidToStop, DL.posx);
}
#endif
DL.velx = 0;
DL.vely = 0;
}

cur = DL.next;
do
{
cur->CheckPosition( tickDiff );
cur = cur->next;
}
while( cur != &DL );

cur = DL.next;
do
{
// virtual fct. call
if ( cur->CheckFrame() )
{
save = cur;
cur = cur->next;
save->DeleteFromList();
}
else
{
cur = cur->next;
}
}
while( cur != &DL );
}


//
// FUNCTION:CheckForHits
//
// DESCRIPTION:Handle object collisions
//
// NOTES:- updates object bounding boxes
//- look for intersections of bullet-like objects with target-like objects
//
void CheckForHits( void )
{
CObject*bullet, *target, *save;
int x, y, l ,t;
BOOL hit;

// update screen rects
target = &DL;
do
{
target->UpdateRect();
target = target->next;
}
while( target != &DL );

// look for intersections of bullet-like objects with target-like objects
bullet=&DL;
do
{
hit = FALSE;
if( !bullet->CanBeBullet() )
{
bullet = bullet->next;
continue;
}

x = (bullet->dst.left + bullet->dst.right) / 2;
y = (bullet->dst.top + bullet->dst.bottom) / 2;

for( target = DL.next; target != &DL; target = target->next)
{
if( !target->CanBeTarget() )
continue;

if( (x >= target->dst.left) &&
(x < target->dst.right) &&
(y >= target->dst.top) &&
(y < target->dst.bottom) )
{
// do we have a bullet or the ship with shields on
if ((bullet != &DL) || !DL.lastShield)
{
// the bullet hit the target
l = target->dst.left;
t = target->dst.top;

// virtual fct call
score += target->Hit( l, t );

target->DeleteFromList();
}
hit = TRUE;
}

if( hit )
{
if( bullet == &DL )
{
hit = FALSE;
if ( !DL.lastShield && !showDelay )
{
score += DL.Hit( l ,t );
if (score < 0)
score = 0;
showDelay = DEF_SHOW_DELAY;
}
}
break;
}
} //for

if( hit )
{
// get rid of the bullet
save = bullet;
bullet = bullet->next;

save->DeleteFromList();
}
else
{
bullet = bullet->next;
}
} while (bullet != &DL);
}


//
// FUNCTION:DrawDisplayList
//
// DESCRIPTION:Blits everything the the screen
//
// NOTES:
//
void DrawDisplayList( void )
{
CObject*cur;
CObject*last;
char scorebuf[11];
int rem;

// calculate score string
scorebuf[0] = score/10000000 + '0';
rem = score % 10000000;
scorebuf[1] = rem/1000000 + '0';
rem = score % 1000000;
scorebuf[2] = rem/100000 + '0';
rem = score % 100000;
scorebuf[3] = rem/10000 + '0';
rem = score % 10000;
scorebuf[4] = rem/1000 + '0';
rem = score % 1000;
scorebuf[5] = rem/100 + '0';
rem = score % 100;
scorebuf[6] = rem/10 + '0';
rem = score % 10;
scorebuf[7] = rem + '0';
#ifdef USE_DSOUND
if( bSoundEnabled )
{
scorebuf[8] = 14 + '0';
scorebuf[9] = 13 + '0';
scorebuf[10] = '\0';
}
else
#endif
{
scorebuf[8] = '\0';
}

EraseScreen();

cur = &DL;// start with the bottommost bitmap (the ship)
last = &DL;// don't blt it twice

if (showDelay)
cur = cur->prev;

do
{
cur->Blt();
cur = cur->prev;
}
while( cur != last );

BltScore(scorebuf, (int)(0.05 * Monitor[DL.iMonitor].dwWidth), (int)(0.95 * Monitor[DL.iMonitor].dwHeight));

if( bShowFrameCount )
DisplayFrameRate();

FlipScreen();
}



//
// FUNCTION:CleanupAndExit
//
// DESCRIPTION:Shut everything down and display a box if an error occured
//
// NOTES:
//
BOOL CleanupAndExit( char *err )
{

#ifdef DEBUG
wsprintf(DebugBuf, "CleanupAndExit: %s\n", err );
OutputDebugString( DebugBuf );
#endif

// make the cursor visible
SetCursor(LoadCursor( NULL, IDC_ARROW ));
bMouseVisible = TRUE;

// release monitors
CMyMonitor::Uninit();

// clean up DirectInput objects
CleanupInput();

// warn user
if( err )
{
MessageBox( hWndMain, err, "ERROR", MB_OK );
}
return FALSE;
}

BOOL CleanupAndExit( char* err, HRESULT ddrval )
{
char* szText;
BOOL rc;

if ( !err )
{
szText = new char[256];
wsprintf( szText, "Err: ddrval = %x", ddrval );
}
else
{
szText = new char[strlen(err) + 256];
wsprintf( szText, "Err: %s (ddrval = %x)", err, ddrval );
}
rc = CleanupAndExit( szText );

delete [] szText;
return rc;
}

#ifdef USE_DSOUND

//
// FUNCTION:PlayPanned
//
// DESCRIPTION:Play a sound with left-right relative volume adjusted depending on location
//within the virtual desktop.
//
// NOTES:
//
void PlayPanned(HSNDOBJ hSO, double posx )
{
static int nMiddle = (rcVirtualDesktop.left + rcVirtualDesktop.right) / 2;
static int nWidth = rcVirtualDesktop.right - rcVirtualDesktop.left;

if(!bWantSound)
return;

IDirectSoundBuffer *pDSB = SndObjGetFreeBuffer(hSO);

if (pDSB)
{
LONG pos = (LONG)((posx - nMiddle) / (double) nWidth * 20000.0);
pDSB->SetPan(pos);

pDSB->Play( 0, 0, 0);
}
}

//
// FUNCTION:InitializeSound
//
// DESCRIPTION:Initialize DirectSound objects
//
// NOTES:
//
void InitializeSound( void )
{
if(!bWantSound)
return;

bSoundEnabled = FALSE;

if (SUCCEEDED(DirectSoundCreate(NULL, &lpDS, NULL)))
{
if (SUCCEEDED(lpDS->SetCooperativeLevel(hWndMain, DSSCL_NORMAL)))

{ 
hsoBeginLevel = SndObjCreate(lpDS, "BeginLevel", 1);
hsoEngineIdle = SndObjCreate(lpDS, "EngineIdle", 1);
hsoEngineRev = SndObjCreate(lpDS, "EngineRev", 1);
hsoSkidToStop = SndObjCreate(lpDS, "SkidToStop", 1);
hsoShieldBuzz = SndObjCreate(lpDS, "ShieldBuzz", 1);
hsoShipExplode = SndObjCreate(lpDS, "ShipExplode", 1);
hsoFireBullet = SndObjCreate(lpDS, "Gunfire", 25);
hsoShipBounce = SndObjCreate(lpDS, "ShipBounce", 4);
hsoDonutExplode = SndObjCreate(lpDS, "DonutExplode", 10);
hsoPyramidExplode = SndObjCreate(lpDS, "PyramidExplode", 12);
hsoCubeExplode = SndObjCreate(lpDS, "CubeExplode", 15);
hsoSphereExplode = SndObjCreate(lpDS, "SphereExplode", 10);
bSoundEnabled = TRUE;

//#ifdef USE_DSOUND this should be dead code Josephc
if( bPlayIdle )
SndObjPlay(hsoEngineIdle, DSBPLAY_LOOPING);

if( bPlayBuzz )
SndObjPlay(hsoShieldBuzz, DSBPLAY_LOOPING);

if( bPlayRev )
SndObjPlay(hsoEngineRev, DSBPLAY_LOOPING);

//#endif
}
else
{
lpDS->Release();
lpDS = NULL;
}
}
}

//
// FUNCTION:DestroySound
//
// DESCRIPTION:Release DirectSound objects
//
// NOTES:
//
void DestroySound( void )
{
if(!bWantSound)
return;

bSoundEnabled = FALSE;
if (lpDS)
{
SndObjDestroy(hsoBeginLevel);
hsoBeginLevel = NULL;
SndObjDestroy(hsoEngineIdle);
hsoEngineIdle = NULL;
SndObjDestroy(hsoEngineRev);
hsoEngineRev = NULL;
SndObjDestroy(hsoSkidToStop);
hsoSkidToStop = NULL;
SndObjDestroy(hsoShieldBuzz);
hsoShieldBuzz = NULL;
SndObjDestroy(hsoShipExplode);
hsoShipExplode = NULL;
SndObjDestroy(hsoFireBullet);
hsoFireBullet = NULL;
SndObjDestroy(hsoShipBounce);
hsoShipBounce = NULL;
SndObjDestroy(hsoDonutExplode);
hsoDonutExplode = NULL;
SndObjDestroy(hsoPyramidExplode);
hsoPyramidExplode = NULL;
SndObjDestroy(hsoCubeExplode);
hsoCubeExplode = NULL;
SndObjDestroy(hsoSphereExplode);
hsoSphereExplode = NULL;

lpDS->Release();
lpDS = NULL;
}
}
#endif