Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1907 lines
56 KiB

//-----------------------------------------------------------------------------
// File: ffdonuts.cpp
//
// Desc: DirectInput Semantic Mapper version of Donuts game
//
// Copyright (C) 1995-2000 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------
#define STRICT
#define INITGUID
#include <windows.h>
#include <cguid.h>
#include <mmsystem.h>
#include <ddraw.h>
#include <dsound.h>
#include <stdio.h>
#include "DDUtil.h"
#include "DIUtil.h"
#include "DSUtil.h"
#include "resource.h"
#include "ffdonuts.h"
// DirectDraw objects
LPDIRECTDRAW7 g_pDD = NULL;
LPDIRECTDRAWPALETTE g_pArtPalette = NULL;
LPDIRECTDRAWPALETTE g_pSplashPalette = NULL;
LPDIRECTDRAWSURFACE7 g_pddsFrontBuffer = NULL;
LPDIRECTDRAWSURFACE7 g_pddsBackBuffer = NULL;
LPDIRECTDRAWSURFACE7 g_pddsDonut = NULL;
LPDIRECTDRAWSURFACE7 g_pddsPyramid = NULL;
LPDIRECTDRAWSURFACE7 g_pddsCube = NULL;
LPDIRECTDRAWSURFACE7 g_pddsSphere = NULL;
LPDIRECTDRAWSURFACE7 g_pddsShip = NULL;
LPDIRECTDRAWSURFACE7 g_pddsNumbers = NULL;
LPDIRECTDRAWSURFACE7 g_pddsDIConfig = NULL;
// DirectSound and DSUtil sound objects
LPDIRECTSOUND g_pDS = NULL;
SoundObject* g_pBeginLevelSound = NULL;
SoundObject* g_pEngineIdleSound = NULL;
SoundObject* g_pEngineRevSound = NULL;
SoundObject* g_pSkidToStopSound = NULL;
SoundObject* g_pShieldBuzzSound = NULL;
SoundObject* g_pShipExplodeSound = NULL;
SoundObject* g_pFireBulletSound = NULL;
SoundObject* g_pShipBounceSound = NULL;
SoundObject* g_pDonutExplodeSound = NULL;
SoundObject* g_pPyramidExplodeSound = NULL;
SoundObject* g_pCubeExplodeSound = NULL;
SoundObject* g_pSphereExplodeSound = NULL;
#if 0 //not used for mapper
BOOL g_bEngineIdle = FALSE;
BOOL g_bShieldsOn = FALSE;
BOOL g_bThrusting = FALSE;
DWORD lastInput = 0;
BOOL g_bLastShield = FALSE;
#endif //not used for mapper
BOOL lastThrust = FALSE;
FLOAT g_fShowDelay = 0.0f;
HWND g_hWndMain;
BOOL g_bIsActive;
BOOL g_bIsReady = FALSE;
BOOL g_bMouseVisible;
DWORD g_dwLastTickCount;
DWORD g_dwScore = 0;
int g_ProgramState;
DWORD g_dwLevel = 0;
DWORD g_dwFillColor;
BOOL g_bLeaveTrails = FALSE;
DWORD g_dwScreenWidth = 1024;
DWORD g_dwScreenHeight = 768;
DWORD g_dwScreenDepth = 16;
BOOL g_bSoundEnabled = FALSE;
DisplayObject* g_pDisplayList = NULL; // Display List
DisplayObject* g_pShip = NULL; // Main ship
DisplayObject* g_pShipsArray[NUMBER_OF_PLAYERS]; //array for all the players' ships
extern IDirectInput8* g_pDI; // DirectInput object
extern DWORD g_dwNumDevices[NUMBER_OF_PLAYERS];
extern IDirectInputDevice8* g_pDevices[NUMBER_OF_PLAYERS][MAX_INPUT_DEVICES+1];
extern DIACTIONFORMAT diActF;
extern LPTSTR lpUserName;
DWORD dwInputState[NUMBER_OF_PLAYERS]; //to persist the input state
BOOL CALLBACK ConfigureDevicesCallback(LPVOID lpVoid, LPVOID lpUserData)
{
UpdateFrame((LPDIRECTDRAWSURFACE7)lpVoid);
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: SetupGame()
// Desc:
//-----------------------------------------------------------------------------
VOID SetupGame()
{
AdvanceLevel();
// Set the palette
g_pddsFrontBuffer->SetPalette( g_pArtPalette );
}
//-----------------------------------------------------------------------------
// Name: MainWndproc()
// Desc: Callback for all Windows messages
//-----------------------------------------------------------------------------
long FAR PASCAL MainWndproc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
PAINTSTRUCT ps;
HDC hdc;
switch( msg )
{
case WM_ACTIVATEAPP:
g_bIsActive = (BOOL) wParam;
if( g_bIsActive )
{
g_bMouseVisible = FALSE;
g_dwLastTickCount = GetTickCount();
g_bLeaveTrails = FALSE;
// Need to reacquire the device
#if 0 //not used in the Semantic Mapper demo
if( g_pdidJoystick )
g_pdidJoystick->Acquire();
#endif //not used in the Semantic Mapper demo
}
else
{
g_bMouseVisible = TRUE;
}
break;
case WM_CREATE:
break;
case WM_SETCURSOR:
if( !g_bMouseVisible && g_bIsReady )
SetCursor(NULL);
else
SetCursor(LoadCursor( NULL, IDC_ARROW ));
return TRUE;
case WM_KEYDOWN:
switch( wParam )
{
case VK_F3:
if( g_bSoundEnabled )
DestroySound();
else
InitializeSound( hWnd );
break;
case VK_ESCAPE:
case VK_F12:
PostMessage( hWnd, WM_CLOSE, 0, 0 );
return 0;
case VK_F1:
g_bLeaveTrails = !g_bLeaveTrails;
break;
case VK_F2:
{
DIUtil_ConfigureDevices(hWnd, g_pddsDIConfig, DICD_DEFAULT);
break;
}
case VK_F4:
{
DIUtil_ConfigureDevices(hWnd, g_pddsDIConfig, DICD_EDIT);
break;
}
}
break;
#if 0 //not used in the Semantic Mapper demo
case WM_KEYUP:
switch( wParam )
{
case VK_NUMPAD7:
lastInput &= ~KEY_SHIELD;
break;
case VK_NUMPAD5:
lastInput &= ~KEY_STOP;
break;
case VK_DOWN:
case VK_NUMPAD2:
lastInput &= ~KEY_DOWN;
break;
case VK_LEFT:
case VK_NUMPAD4:
lastInput &= ~KEY_LEFT;
break;
case VK_RIGHT:
case VK_NUMPAD6:
lastInput &= ~KEY_RIGHT;
break;
case VK_UP:
case VK_NUMPAD8:
lastInput &= ~KEY_UP;
break;
case VK_NUMPAD3:
lastInput &= ~KEY_THROW;
break;
case VK_SPACE:
lastInput &= ~KEY_FIRE;
break;
}
break;
#endif //not used in the Semantic Mapper demo
case WM_ERASEBKGND:
return 1;
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
return 1;
case WM_DESTROY:
#if 0 //not used for mapper
lastInput=0;
#endif //not used for mapper
DestroyGame();
PostQuitMessage( 0 );
break;
}
return (LONG) DefWindowProc( hWnd, msg, wParam, lParam );
}
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Application entry point
//-----------------------------------------------------------------------------
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow )
{
// Register the window class
WNDCLASS wndClass = { CS_DBLCLKS, (WNDPROC)MainWndproc, 0, 0, hInstance,
LoadIcon( hInstance, MAKEINTRESOURCE(DONUTS_ICON) ),
LoadCursor( NULL, IDC_ARROW ),
(HBRUSH)GetStockObject( BLACK_BRUSH ),
NULL, TEXT("DonutsClass") };
RegisterClass( &wndClass );
// Create our main window
g_hWndMain = CreateWindowEx( 0, TEXT("DonutsClass"), TEXT("Donuts"),
WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU,
0, 0, GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN), NULL, NULL,
hInstance, NULL );
if( NULL == g_hWndMain )
return FALSE;
UpdateWindow( g_hWndMain );
g_bIsReady = TRUE;
if( FAILED( InitializeGame( g_hWndMain ) ) )
{
DestroyWindow( g_hWndMain );
return FALSE;
}
while( 1 )
{
MSG msg;
if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
if( FALSE == GetMessage( &msg, NULL, 0, 0 ) )
return (int) msg.wParam;
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else if( g_bIsActive )
{
UpdateFrame();
}
else
{
WaitMessage();
}
}
}
//-----------------------------------------------------------------------------
// Name: DestroyGame()
// Desc:
//-----------------------------------------------------------------------------
VOID DestroyGame()
{
DestroySound();
DestroyInput();
}
//-----------------------------------------------------------------------------
// Name: UpdateShips()
// Desc:
//-----------------------------------------------------------------------------
VOID UpdateShips()
{
//the main ship will always be there
//but update all the others, based on whether
//the particular user has any devices
for (int pl = 1; pl < NUMBER_OF_PLAYERS; pl ++)
{
//if the corresponding player is still playing
if (g_pDevices[pl][0] != NULL)
{
//if not created already, create new
if (g_pShipsArray[pl] == NULL)
{
g_pShipsArray[pl] = CreateObject(OBJ_SHIP, (FLOAT)(g_dwScreenWidth/(pl+1)-16), (FLOAT)(g_dwScreenHeight/(pl+1)-16), 0, 0, pl);
}
//if already created, keep it
}
else //player is gone
{
//if there is a ship for this player, delete it
if (g_pShipsArray[pl] != NULL)
{
DeleteFromList(g_pShipsArray[pl]);
g_pShipsArray[pl] = NULL;
}
}
}
}
//-----------------------------------------------------------------------------
// Name: InitializeGame()
// Desc:
//-----------------------------------------------------------------------------
HRESULT InitializeGame( HWND hWnd )
{
LPDIRECTDRAW pDD;
HRESULT hr;
DDSURFACEDESC2 ddsd;
// Create DirectDraw
if( SUCCEEDED( hr = DirectDrawCreate( NULL, &pDD, NULL ) ) )
{
// Get DirectDraw4 interface
hr = pDD->QueryInterface( IID_IDirectDraw7, (VOID**)&g_pDD );
pDD->Release();
}
if( FAILED(hr) )
{
CleanupAndDisplayError("DirectDrawCreate Failed!");
return E_FAIL;
}
// Set the cooperative level for fullscreen mode
hr = g_pDD->SetCooperativeLevel( hWnd,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
if( FAILED(hr) )
{
CleanupAndDisplayError("SetCooperativeLevel Failed");
return E_FAIL;
}
// Set the display mode
hr = g_pDD->SetDisplayMode( g_dwScreenWidth, g_dwScreenHeight,
g_dwScreenDepth, 0, 0 );
if( FAILED(hr) )
{
CleanupAndDisplayError("SetDisplayMode Failed!");
return E_FAIL;
}
// Create surfaces
ZeroMemory( &ddsd, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
// Create the front buffer
hr = g_pDD->CreateSurface( &ddsd, &g_pddsFrontBuffer, NULL );
if( FAILED(hr) )
{
CleanupAndDisplayError("CreateSurface FrontBuffer Failed!");
return E_FAIL;
}
// Get a pointer to the back buffer
DDSCAPS2 ddscaps;
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddscaps.dwCaps2 = 0;
ddscaps.dwCaps3 = 0;
ddscaps.dwCaps4 = 0;
hr = g_pddsFrontBuffer->GetAttachedSurface( &ddscaps, &g_pddsBackBuffer );
if( FAILED(hr) )
{
CleanupAndDisplayError("GetAttachedSurface Failed!");
return E_FAIL;
}
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth = 320;
// Create the surfaces for the object images. (We're OR'ing the HRESULTs
// together, so we only need to check for failure once).
ddsd.dwHeight = 384;
hr |= g_pDD->CreateSurface( &ddsd, &g_pddsDonut, NULL );
ddsd.dwHeight = 128;
hr |= g_pDD->CreateSurface( &ddsd, &g_pddsPyramid, NULL );
ddsd.dwHeight = 32;
hr |= g_pDD->CreateSurface( &ddsd, &g_pddsCube, NULL );
ddsd.dwHeight = 32;
hr |= g_pDD->CreateSurface( &ddsd, &g_pddsSphere, NULL );
ddsd.dwHeight = 256;
hr |= g_pDD->CreateSurface( &ddsd, &g_pddsShip, NULL );
ddsd.dwHeight = 16;
hr |= g_pDD->CreateSurface( &ddsd, &g_pddsNumbers, NULL );
ddsd.dwWidth = 640;
ddsd.dwHeight = 480;
hr |= g_pDD->CreateSurface( &ddsd, &g_pddsDIConfig, NULL );
if( FAILED(hr) )
{
CleanupAndDisplayError("Could not create surfaces!");
return E_FAIL;
}
if( FAILED( RestoreSurfaces() ) )
{
CleanupAndDisplayError("RestoreSurfaces Failed!");
return E_FAIL;
}
//zero out the ship ptrs
for (int ship = 0; ship < NUMBER_OF_PLAYERS; ship++)
{
g_pShipsArray[ship] = NULL;
}
// Add a ship to the displaylist
g_pDisplayList = new DisplayObject;
g_pDisplayList->next = NULL;
g_pDisplayList->prev = NULL;
g_pDisplayList->type = OBJ_SHIP;
g_pDisplayList->pddsSurface = g_pddsShip;
g_pShip = g_pDisplayList;
//and save the ptr
g_pShipsArray[0] = g_pShip;
//initialize input
for (ship = 0; ship < NUMBER_OF_PLAYERS; ship ++)
{
dwInputState[ship] = 0;
}
g_dwLastTickCount = GetTickCount();
if( FAILED( InitializeInput( hWnd ) ) )
return E_FAIL;
//if( FAILED( InitializeSound( hWnd ) ) )
// return E_FAIL;
g_ProgramState = PS_SPLASH;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: CleanupAndDisplayError()
// Desc:
//-----------------------------------------------------------------------------
VOID CleanupAndDisplayError( CHAR* strError )
{
CHAR buffer[80];
sprintf( buffer, "Error: %s\n", strError );
OutputDebugString( buffer );
// Make the cursor visible
SetCursor( LoadCursor( NULL, IDC_ARROW ) );
g_bMouseVisible = TRUE;
if( g_pddsDonut )
g_pddsDonut->Release();
if( g_pddsPyramid )
g_pddsPyramid->Release();
if( g_pddsCube )
g_pddsCube->Release();
if( g_pddsSphere )
g_pddsSphere->Release();
if( g_pddsShip )
g_pddsShip->Release();
if( g_pddsNumbers )
g_pddsNumbers->Release();
if( g_pddsDIConfig )
g_pddsDIConfig->Release();
if( g_pddsFrontBuffer )
g_pddsFrontBuffer->Release();
if( g_pArtPalette )
g_pArtPalette->Release();
if( g_pSplashPalette )
g_pSplashPalette->Release();
if( g_pDD )
g_pDD->Release();
MessageBox( g_hWndMain, strError, "ERROR", MB_OK );
}
//-----------------------------------------------------------------------------
// Name: DisplaySplashScreen()
// Desc:
//-----------------------------------------------------------------------------
HRESULT DisplaySplashScreen()
{
HBITMAP hbm;
hbm = (HBITMAP)LoadImage( GetModuleHandle( NULL ), "SPLASH", IMAGE_BITMAP,
0, 0, LR_CREATEDIBSECTION );
if( NULL == hbm )
return E_FAIL;
// Set the palette before loading the splash screen
g_pddsFrontBuffer->SetPalette( g_pSplashPalette );
// If the surface is lost, DDCopyBitmap will fail and the surface will
// be restored in FlipScreen().
DDUtil_CopyBitmap( g_pddsBackBuffer, hbm, 0, 0, 0, 0 );
// Done with the bitmap
DeleteObject( hbm );
// Show the backbuffer contents on the frontbuffer
if( FAILED( FlipScreen() ) )
return E_FAIL;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: PlayPannedSound()
// Desc: Play a sound, but first set the panning according to where the
// object is on the screen.
//-----------------------------------------------------------------------------
VOID PlayPannedSound( SoundObject* pSound, DisplayObject* pObject )
{
if( NULL == pObject )
return;
DWORD dwCenter = ( pObject->rcDst.right + pObject->rcDst.left ) / 2;
FLOAT fCenter = ( 2.0f * ((FLOAT)dwCenter)/g_dwScreenWidth ) - 1.0f;
DSUtil_PlayPannedSound( pSound, fCenter );
}
//-----------------------------------------------------------------------------
// Name: UpdateFrame()
// Desc:
//-----------------------------------------------------------------------------
VOID UpdateFrame(LPDIRECTDRAWSURFACE7 lpddsConfigDlg)
{
static FLOAT fLevelIntroTime;
switch( g_ProgramState )
{
case PS_SPLASH:
// Display the splash screen
//DisplaySplashScreen();
g_ProgramState = PS_BEGINREST;
SetupGame();
break;
case PS_ACTIVE:
UpdateDisplayList();
CheckForHits();
DrawDisplayList(lpddsConfigDlg);
if( IsDisplayListEmptyExceptShips() )
{
DSUtil_StopSound( g_pEngineIdleSound );
DSUtil_StopSound( g_pEngineRevSound );
#if 0 //not used for the mulit-user mapper
g_bEngineIdle = FALSE;
g_bThrusting = FALSE;
lastThrust = FALSE;
g_bLastShield = FALSE;
#endif //not used for the mulit-user mapper
g_ProgramState = PS_BEGINREST;
AdvanceLevel();
}
break;
case PS_BEGINREST:
DSUtil_PlaySound(g_pBeginLevelSound, 0);
fLevelIntroTime = GetTickCount()/1000.0f;
g_ProgramState = PS_REST;
// Fall through to PS_REST state
case PS_REST:
// Show the Level intro screen for 3 seconds
if( ( GetTickCount()/1000.0f - fLevelIntroTime ) > 3.0f )
{
DSUtil_PlaySound( g_pEngineIdleSound, DSBPLAY_LOOPING );
#if 0 //not used for the mulit-user mapper
g_bEngineIdle = TRUE;
#endif //not used for the mulit-user mapper
g_dwLastTickCount = GetTickCount();
g_ProgramState = PS_ACTIVE;
}
else
{
DisplayLevelIntroScreen( g_dwLevel );
}
break;
}
}
//-----------------------------------------------------------------------------
// Name: DisplayLevelIntroScreen()
// Desc:
//-----------------------------------------------------------------------------
VOID DisplayLevelIntroScreen( DWORD dwLevel )
{
// Erase the screen
EraseScreen();
// Output the bitmapped letters for the word "Level"
CHAR buffer[10];
buffer[0] = 10 + '0';
buffer[1] = 11 + '0';
buffer[2] = 12 + '0';
buffer[3] = 11 + '0';
buffer[4] = 10 + '0';
buffer[5] = '\0';
BltBitmappedText( buffer, g_dwScreenWidth/2-64, g_dwScreenHeight/2-8 );
// Output the bitmapped numbers for the level number
buffer[0] = (CHAR)(dwLevel/100) + '0';
buffer[1] = (CHAR)(dwLevel/ 10) + '0';
buffer[2] = (CHAR)(dwLevel% 10) + '0';
buffer[3] = '\0';
BltBitmappedText( buffer, g_dwScreenWidth/2+22, g_dwScreenHeight/2-8 );
// Show the backbuffer screen on the front buffer
FlipScreen();
}
//-----------------------------------------------------------------------------
// Name: BltBitmappedText()
// Desc:
//-----------------------------------------------------------------------------
VOID BltBitmappedText( CHAR* num, int x, int y )
{
for( CHAR* c = num; *c != '\0'; c++ )
{
HRESULT hr = DDERR_WASSTILLDRAWING;
RECT rcSrc;
rcSrc.left = (*c - '0')*16;
rcSrc.top = 0;
rcSrc.right = rcSrc.left + 16;
rcSrc.bottom = rcSrc.top + 16;
while( hr == DDERR_WASSTILLDRAWING )
{
hr = g_pddsBackBuffer->BltFast( x, y, g_pddsNumbers, &rcSrc,
DDBLTFAST_SRCCOLORKEY );
}
x += 16;
}
}
//-----------------------------------------------------------------------------
// Name: CheckForHits()
// Desc:
//-----------------------------------------------------------------------------
VOID CheckForHits()
{
DisplayObject* pObject;
DisplayObject* bullet;
// Update screen rects
for( pObject = g_pDisplayList; pObject; pObject = pObject->next )
{
int frame = (DWORD)pObject->frame;
switch( pObject->type )
{
case OBJ_DONUT:
pObject->rcDst.left = (DWORD)pObject->posx;
pObject->rcDst.top = (DWORD)pObject->posy;
pObject->rcDst.right = pObject->rcDst.left + DONUT_WIDTH;
pObject->rcDst.bottom = pObject->rcDst.top + DONUT_HEIGHT;
pObject->rcSrc.left = DONUT_WIDTH * (frame % 5);
pObject->rcSrc.top = DONUT_HEIGHT * (frame /5);
pObject->rcSrc.right = pObject->rcSrc.left + DONUT_WIDTH;
pObject->rcSrc.bottom = pObject->rcSrc.top + DONUT_HEIGHT;
break;
case OBJ_PYRAMID:
pObject->rcDst.left = (DWORD)pObject->posx;
pObject->rcDst.top = (DWORD)pObject->posy;
pObject->rcDst.right = pObject->rcDst.left + PYRAMID_WIDTH;
pObject->rcDst.bottom = pObject->rcDst.top + PYRAMID_HEIGHT;
pObject->rcSrc.left = PYRAMID_WIDTH * (frame % 10);
pObject->rcSrc.top = PYRAMID_HEIGHT * (frame /10);
pObject->rcSrc.right = pObject->rcSrc.left + PYRAMID_WIDTH;
pObject->rcSrc.bottom = pObject->rcSrc.top + PYRAMID_HEIGHT;
break;
case OBJ_SPHERE:
pObject->rcDst.left = (DWORD)pObject->posx;
pObject->rcDst.top = (DWORD)pObject->posy;
pObject->rcDst.right = pObject->rcDst.left + SPHERE_WIDTH;
pObject->rcDst.bottom = pObject->rcDst.top + SPHERE_HEIGHT;
pObject->rcSrc.left = SPHERE_WIDTH * (frame % 20);
pObject->rcSrc.top = SPHERE_HEIGHT * (frame /20);
pObject->rcSrc.right = pObject->rcSrc.left + SPHERE_WIDTH;
pObject->rcSrc.bottom = pObject->rcSrc.top + SPHERE_HEIGHT;
break;
case OBJ_CUBE:
pObject->rcDst.left = (DWORD)pObject->posx;
pObject->rcDst.top = (DWORD)pObject->posy;
pObject->rcDst.right = pObject->rcDst.left + CUBE_WIDTH;
pObject->rcDst.bottom = pObject->rcDst.top + CUBE_HEIGHT;
pObject->rcSrc.left = CUBE_WIDTH * (frame % 20);
pObject->rcSrc.top = CUBE_HEIGHT * (frame /20);
pObject->rcSrc.right = pObject->rcSrc.left + CUBE_WIDTH;
pObject->rcSrc.bottom = pObject->rcSrc.top + CUBE_HEIGHT;
break;
case OBJ_SHIP:
pObject->rcDst.left = (DWORD)pObject->posx;
pObject->rcDst.top = (DWORD)pObject->posy;
pObject->rcDst.right = pObject->rcDst.left + SHIP_WIDTH;
pObject->rcDst.bottom = pObject->rcDst.top + SHIP_HEIGHT;
#if 0 //not used for the mulit-user mapper
if( g_bLastShield )
pObject->rcSrc.top = SHIP_HEIGHT * (frame / 10) + 128;
else
#endif //not used for the mulit-user mapper
pObject->rcSrc.top = SHIP_HEIGHT * (frame /10);
pObject->rcSrc.left = SHIP_WIDTH * (frame % 10);
pObject->rcSrc.right = pObject->rcSrc.left + SHIP_WIDTH;
pObject->rcSrc.bottom = pObject->rcSrc.top + SHIP_HEIGHT;
break;
case OBJ_BULLET:
frame = (DWORD)pObject->frame/20 % 4;
pObject->rcDst.left = (DWORD)pObject->posx;
pObject->rcDst.top = (DWORD)pObject->posy;
pObject->rcDst.right = pObject->rcDst.left + BULLET_WIDTH;
pObject->rcDst.bottom = pObject->rcDst.top + BULLET_HEIGHT;
pObject->rcSrc.left = BULLET_XOFFSET + frame*4;
pObject->rcSrc.top = BULLET_YOFFSET;
pObject->rcSrc.right = pObject->rcSrc.left + BULLET_WIDTH;
pObject->rcSrc.bottom = pObject->rcSrc.top + BULLET_HEIGHT;
break;
}
}
for( bullet = g_pDisplayList; bullet; bullet = bullet->next )
{
// Only bullet objects and the ship (if shields are on) can hit
// other objects. Skip all others.
if( (bullet->type != OBJ_BULLET) && (bullet->type != OBJ_SHIP) )
continue;
#if 0 //not used for the mulit-user mapper
// The ship cannot hit anything with shields on
if( bullet->type == OBJ_SHIP && TRUE == g_bLastShield )
continue;
#endif //not used for the mulit-user mapper
BOOL bBulletHit = FALSE;
WORD wBulletX = (WORD)(bullet->rcDst.left + bullet->rcDst.right) / 2;
WORD wBulletY = (WORD)(bullet->rcDst.top + bullet->rcDst.bottom) / 2;
for( pObject = g_pDisplayList; pObject; pObject = pObject->next )
{
FLOAT left = (FLOAT)pObject->rcDst.left;
FLOAT right = (FLOAT)pObject->rcDst.right;
FLOAT top = (FLOAT)pObject->rcDst.top;
FLOAT bottom = (FLOAT)pObject->rcDst.bottom;
// Only trying to hit explodable targets
if( ( pObject->type != OBJ_DONUT ) &&
( pObject->type != OBJ_PYRAMID ) &&
( pObject->type != OBJ_SPHERE ) &&
( pObject->type != OBJ_SHIP ) &&
( pObject->type != OBJ_CUBE ) )
continue;
if( ( wBulletX >= left ) && ( wBulletX < right ) &&
( wBulletY >= top ) && ( wBulletY < bottom ) )
{
// The object was hit
switch( pObject->type )
{
case OBJ_DONUT:
PlayPannedSound( g_pDonutExplodeSound, pObject );
CreateObject( OBJ_PYRAMID, left, top, -1.0f, -1.0f, NO_PLAYER);
CreateObject( OBJ_PYRAMID, left, top, -1.0f, -1.0f, NO_PLAYER );
CreateObject( OBJ_PYRAMID, left, top, -1.0f, -1.0f, NO_PLAYER );
g_dwScore += 10;
break;
case OBJ_PYRAMID:
PlayPannedSound( g_pPyramidExplodeSound, pObject );
CreateObject( OBJ_SPHERE, left, top, -1.0f, -1.0f, NO_PLAYER );
CreateObject( OBJ_CUBE, left, top, -1.0f, -1.0f, NO_PLAYER );
CreateObject( OBJ_CUBE, left, top, -1.0f, -1.0f, NO_PLAYER );
g_dwScore += 20;
break;
case OBJ_CUBE:
PlayPannedSound( g_pCubeExplodeSound, pObject );
CreateObject( OBJ_SPHERE, left, top, -1.0f, -1.0f, NO_PLAYER );
CreateObject( OBJ_SPHERE, left, top, -1.0f, -1.0f, NO_PLAYER );
g_dwScore += 40;
break;
case OBJ_SPHERE:
PlayPannedSound( g_pSphereExplodeSound, pObject );
g_dwScore += 20;
break;
case OBJ_SHIP:
//can't be hit by bullets that come from us
if (bullet->Player != pObject->Player)
{
if(pObject->bVisible )
{
// Ship has exploded
PlayPannedSound( g_pShipExplodeSound, pObject);
if( g_dwScore < 150 )
g_dwScore = 0;
else
g_dwScore -= 150;
FLOAT x = pObject->posx;
FLOAT y = pObject->posy;
CreateObject( OBJ_SPHERE, x, y, -1.0f, -1.0f, NO_PLAYER);
CreateObject( OBJ_SPHERE, x, y, -1.0f, -1.0f, NO_PLAYER);
CreateObject( OBJ_SPHERE, x, y, -1.0f, -1.0f, NO_PLAYER);
CreateObject( OBJ_SPHERE, x, y, -1.0f, -1.0f, NO_PLAYER);
CreateObject( OBJ_BULLET, x, y, rnd()/2, rnd()/2, bullet->Player );
CreateObject( OBJ_BULLET, x, y, rnd()/2, rnd()/2, bullet->Player );
CreateObject( OBJ_BULLET, x, y, rnd()/2, rnd()/2, bullet->Player );
CreateObject( OBJ_BULLET, x, y, rnd()/2, rnd()/2, bullet->Player );
CreateObject( OBJ_BULLET, x, y, rnd()/2, rnd()/2, bullet->Player );
CreateObject( OBJ_BULLET, x, y, rnd()/2, rnd()/2, bullet->Player );
CreateObject( OBJ_BULLET, x, y, rnd()/2, rnd()/2, bullet->Player );
CreateObject( OBJ_BULLET, x, y, rnd()/2, rnd()/2, bullet->Player );
CreateObject( OBJ_BULLET, x, y, rnd()/2, rnd()/2, bullet->Player );
CreateObject( OBJ_BULLET, x, y, rnd()/2, rnd()/2, bullet->Player );
// Delay for 2 seconds before displaying ship
InitializeShips();
g_fShowDelay = 2.0f;
pObject->bVisible = FALSE;
}
}
break;
}
//only delete non-"ships"
if (pObject->type != OBJ_SHIP)
{
DisplayObject* pVictim = pObject;
pObject = pObject->prev;
DeleteFromList( pVictim );
bBulletHit = TRUE;
}
}
}
}
}
//-----------------------------------------------------------------------------
// Name: EraseScreen()
// Desc:
//-----------------------------------------------------------------------------
VOID EraseScreen()
{
// Erase the background
DDBLTFX ddbltfx;
ZeroMemory( &ddbltfx, sizeof(ddbltfx) );
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = g_dwFillColor;
while( 1 )
{
HRESULT hr = g_pddsBackBuffer->Blt( NULL, NULL, NULL, DDBLT_COLORFILL,
&ddbltfx );
if( SUCCEEDED(hr) )
break;
if( hr == DDERR_SURFACELOST )
if( FAILED( RestoreSurfaces() ) )
return;
if( hr != DDERR_WASSTILLDRAWING )
return;
}
}
//-----------------------------------------------------------------------------
// Name: FlipScreen()
// Desc:
//-----------------------------------------------------------------------------
HRESULT FlipScreen()
{
HRESULT hr = DDERR_WASSTILLDRAWING;
// Flip the surfaces
while( DDERR_WASSTILLDRAWING == hr )
{
hr = g_pddsFrontBuffer->Flip( NULL, 0 );
if( hr == DDERR_SURFACELOST )
if( FAILED( RestoreSurfaces() ) )
return E_FAIL;
}
return hr;
}
//-----------------------------------------------------------------------------
// Name: DrawDisplayList()
// Desc:
//-----------------------------------------------------------------------------
VOID DrawDisplayList(LPDIRECTDRAWSURFACE7 lpConfigDlgSurf)
{
if( FALSE == g_bLeaveTrails )
EraseScreen();
char scorebuf[11];
int rem;
rem = g_dwScore;
scorebuf[0] = rem/10000000 + '0';
rem = g_dwScore % 10000000;
scorebuf[1] = rem/1000000 + '0';
rem = g_dwScore % 1000000;
scorebuf[2] = rem/100000 + '0';
rem = g_dwScore % 100000;
scorebuf[3] = rem/10000 + '0';
rem = g_dwScore % 10000;
scorebuf[4] = rem/1000 + '0';
rem = g_dwScore % 1000;
scorebuf[5] = rem/100 + '0';
rem = g_dwScore % 100;
scorebuf[6] = rem/10 + '0';
rem = g_dwScore % 10;
scorebuf[7] = rem + '0';
scorebuf[8] = '\0';
// Draw the sound icon, if sound is enabled
if( g_bSoundEnabled )
{
scorebuf[8] = 14 + '0';
scorebuf[9] = 13 + '0';
scorebuf[10] = '\0';
}
// Display the score
BltBitmappedText( scorebuf, 10, g_dwScreenHeight-26 );
// Display all visible objects in the display list
for( DisplayObject* pObject = g_pDisplayList; pObject;
pObject = pObject->next )
{
if( !pObject->bVisible )
continue;
HRESULT hr = DDERR_WASSTILLDRAWING;
if( pObject->rcSrc.right - pObject->rcSrc.left == 0 )
continue; // New objects do not have a src rect yet.
while( hr == DDERR_WASSTILLDRAWING )
{
hr = g_pddsBackBuffer->BltFast( pObject->rcDst.left,
pObject->rcDst.top, pObject->pddsSurface,
&pObject->rcSrc, DDBLTFAST_SRCCOLORKEY );
}
}
// Flip the backbuffer contents to the front buffer
if (lpConfigDlgSurf)
{
g_pddsBackBuffer->BltFast((g_dwScreenWidth-640)/2, (g_dwScreenHeight-480)/2, lpConfigDlgSurf, NULL, DDBLTFAST_WAIT);
}
FlipScreen();
}
//-----------------------------------------------------------------------------
// Name: DeleteFromList()
// Desc:
//-----------------------------------------------------------------------------
VOID DeleteFromList( DisplayObject* pObject )
{
if( pObject->next )
pObject->next->prev = pObject->prev;
if( pObject->prev )
pObject->prev->next = pObject->next;
delete( pObject );
}
//-----------------------------------------------------------------------------
// Name: UpdateDisplayList()
// Desc:
//-----------------------------------------------------------------------------
VOID UpdateDisplayList()
{
DisplayObject* thisnode;
FLOAT maxx, maxy;
FLOAT maxframe;
DWORD input[NUMBER_OF_PLAYERS];//= lastInput;
for (int pl = 0; pl < NUMBER_OF_PLAYERS; pl ++)
{
input[pl] = 0;
}
// Update the game clock parameters
DWORD dwTickCount = GetTickCount();
FLOAT fTickDiff = ( dwTickCount - g_dwLastTickCount )/1000.0f;
g_dwLastTickCount = dwTickCount;
// Read input from the players' devices
GetDeviceInput(input);
for (int pl = 0; pl < NUMBER_OF_PLAYERS; pl ++)
{
BOOL bShieldState = FALSE;
BOOL bThrustState = FALSE;
BOOL bBounce = FALSE;
LONG lAngle = 0;
//if KEY_QUIT is pressed, exit
if (input[pl] & KEY_QUIT)
{
PostMessage( g_hWndMain, WM_CLOSE, 0, 0 );
return;
}
//if KEY_DISPLAY is pressed, call ConfigureDevices() in normal mode
if (input[pl] & KEY_DISPLAY)
{
//call ConfigureDevices() in default mode
DIUtil_ConfigureDevices(g_hWndMain, g_pddsDIConfig, DICD_DEFAULT);
}
//if KEY_EDIT is pressed, call ConfigureDevices() in edit mode
if (input[pl] & KEY_EDIT)
{
//call ConfigureDevices() in edit mode
DIUtil_ConfigureDevices(g_hWndMain, g_pddsDIConfig, DICD_EDIT);
}
if( g_fShowDelay > 0.0f )
{
g_fShowDelay -= fTickDiff;
if( g_fShowDelay < 0.0f )
{
InitializeShips();
#if 0 //not used for the mulit-user mapper
g_bLastShield = FALSE;
#endif //not used for the mulit-user mapper
g_fShowDelay = 0.0f;
if (g_pShipsArray[pl] != NULL)
{
g_pShipsArray[pl]->bVisible = TRUE;
}
}
}
// Update the ships
if (g_pShipsArray[pl] != NULL)
{
if( g_pShipsArray[pl]->bVisible )
{
g_pShipsArray[pl]->posx += g_pShipsArray[pl]->velx * fTickDiff;
g_pShipsArray[pl]->posy += g_pShipsArray[pl]->vely * fTickDiff;
}
if( g_pShipsArray[pl]->posx > (FLOAT)(MAX_SCREEN_X - SHIP_WIDTH) )
{
g_pShipsArray[pl]->posx = (FLOAT)(MAX_SCREEN_X - SHIP_WIDTH);
g_pShipsArray[pl]->velx = -g_pShipsArray[pl]->velx;
// Bounce off the right edge of the screen
bBounce = TRUE;
lAngle = 90;
}
else if( g_pShipsArray[pl]->posx < 0 )
{
g_pShipsArray[pl]->posx = 0;
g_pShipsArray[pl]->velx = -g_pShipsArray[pl]->velx;
// Bounce off the left edge of the screen
bBounce = TRUE;
lAngle = 270;
}
if( g_pShipsArray[pl]->posy > (FLOAT)(MAX_SCREEN_Y - SHIP_HEIGHT) )
{
g_pShipsArray[pl]->posy = (FLOAT)(MAX_SCREEN_Y - SHIP_HEIGHT);
g_pShipsArray[pl]->vely = -g_pShipsArray[pl]->vely;
// Bounce off the bottom edge of the screen
bBounce = TRUE;
lAngle = 180;
}
else if( g_pShipsArray[pl]->posy < 0 )
{
g_pShipsArray[pl]->posy =0;
g_pShipsArray[pl]->vely = -g_pShipsArray[pl]->vely;
// Bounce off the top edge of the screen
bBounce = TRUE;
lAngle = 0;
}
if( bBounce )
{
// "Bounce" the ship
PlayPannedSound( g_pShipBounceSound, g_pShipsArray[pl] );
#if 0 //not used in the Semantic Mapper demo
DIUtil_PlayDirectionalEffect( g_pBounceFFEffect, lAngle );
#endif //not used in the Semantic Mapper demo
}
bShieldState = ( !g_pShipsArray[pl]->bVisible || ( input[pl] & KEY_SHIELD ) );
#if 0 //not used for the mulit-user mapper
if( bShieldState != g_bLastShield )
{
#endif //not used for the mulit-user mapper
if( bShieldState && g_pShipsArray[pl]->bVisible )
{
DSUtil_PlaySound( g_pShieldBuzzSound, DSBPLAY_LOOPING );
#if 0 //not used for the mulit-user mapper
g_bShieldsOn = TRUE;
#endif //not used for the mulit-user mapper
}
else
{
DSUtil_StopSound( g_pShieldBuzzSound );
#if 0 //not used for the mulit-user mapper
g_bShieldsOn = FALSE;
#endif //not used for the mulit-user mapper
}
#if 0 //not used for the mulit-user mapper
g_bLastShield = bShieldState;
}
#endif //not used for the mulit-user mapper
if( bShieldState )
{
input[pl] &= ~(KEY_FIRE);
}
if( input[pl] & KEY_FIRE )
{
// Add a bullet to the scene
if( g_pShipsArray[pl]->bVisible )
{
// Bullets cost one score point
if( g_dwScore )
g_dwScore--;
// Play the "fire" sound
DSUtil_PlaySound( g_pFireBulletSound, 0);
// Play the "fire" forcefeedback effect
#if 0 //not used in the Semantic Mapper demo
DIUtil_PlayEffect( g_pFireFFEffect );
#endif //not used in the Semantic Mapper demo
// Add a bullet to the display list
CreateObject( OBJ_BULLET,
Dirx[(int)g_pShipsArray[pl]->frame]*6.0f + 16.0f + g_pShipsArray[pl]->posx,
Diry[(int)g_pShipsArray[pl]->frame]*6.0f + 16.0f + g_pShipsArray[pl]->posy,
Dirx[(int)g_pShipsArray[pl]->frame]*500.0f,
Diry[(int)g_pShipsArray[pl]->frame]*500.0f,
pl);
}
}
if( input[pl] & KEY_LEFT )
{
g_pShipsArray[pl]->frame -= 1.0;
if( g_pShipsArray[pl]->frame < 0.0 )
g_pShipsArray[pl]->frame += MAX_SHIP_FRAME;
}
if( input[pl] & KEY_RIGHT )
{
g_pShipsArray[pl]->frame += 1.0;
if( g_pShipsArray[pl]->frame >= MAX_SHIP_FRAME )
g_pShipsArray[pl]->frame -= MAX_SHIP_FRAME;
}
if( input[pl] & KEY_UP )
{
g_pShipsArray[pl]->velx += Dirx[(int)g_pShipsArray[pl]->frame] * 10.0f;
g_pShipsArray[pl]->vely += Diry[(int)g_pShipsArray[pl]->frame] * 10.0f;
bThrustState = TRUE;
}
if( input[pl] & KEY_DOWN )
{
g_pShipsArray[pl]->velx -= Dirx[(int)g_pShipsArray[pl]->frame] * 10.0f;
g_pShipsArray[pl]->vely -= Diry[(int)g_pShipsArray[pl]->frame] * 10.0f;
bThrustState = TRUE;
}
if( bThrustState != lastThrust )
{
if( bThrustState )
{
input[pl] &= ~KEY_STOP;
DSUtil_StopSound( g_pSkidToStopSound );
DSUtil_PlaySound( g_pEngineRevSound, DSBPLAY_LOOPING );
#if 0 //not used for the mulit-user mapper
g_bThrusting = TRUE;
#endif //not used for the mulit-user mapper
}
else
{
DSUtil_StopSound( g_pEngineRevSound );
#if 0 //not used for the mulit-user mapper
g_bThrusting = FALSE;
#endif //not used for the mulit-user mapper
}
lastThrust = bThrustState;
}
if( input[pl] & KEY_STOP )
{
if( g_pShipsArray[pl]->velx || g_pShipsArray[pl]->vely )
PlayPannedSound( g_pSkidToStopSound, g_pShipsArray[pl] );
g_pShipsArray[pl]->velx = 0.0f;
g_pShipsArray[pl]->vely = 0.0f;
}
}
}
for( thisnode = g_pDisplayList->next; thisnode; )
{
//for things other than ships, which were handled above
if (thisnode->type != OBJ_SHIP)
{
thisnode->posx += thisnode->velx * fTickDiff;
thisnode->posy += thisnode->vely * fTickDiff;
thisnode->frame += thisnode->delay * fTickDiff;
switch( thisnode->type )
{
case OBJ_DONUT:
maxx = (FLOAT)(MAX_SCREEN_X - DONUT_WIDTH);
maxy = (FLOAT)(MAX_SCREEN_Y - DONUT_HEIGHT);
maxframe = MAX_DONUT_FRAME;
break;
case OBJ_PYRAMID:
maxx = (FLOAT)(MAX_SCREEN_X - PYRAMID_WIDTH);
maxy = (FLOAT)(MAX_SCREEN_Y - PYRAMID_HEIGHT);
maxframe = MAX_PYRAMID_FRAME;
break;
case OBJ_SPHERE:
maxx = (FLOAT)(MAX_SCREEN_X - SPHERE_WIDTH);
maxy = (FLOAT)(MAX_SCREEN_Y - SPHERE_HEIGHT);
maxframe = MAX_SPHERE_FRAME;
break;
case OBJ_CUBE:
maxx = (FLOAT)(MAX_SCREEN_X - CUBE_WIDTH);
maxy = (FLOAT)(MAX_SCREEN_Y - CUBE_HEIGHT);
maxframe = MAX_CUBE_FRAME;
break;
case OBJ_BULLET:
maxx = (FLOAT)(MAX_SCREEN_X - BULLET_WIDTH);
maxy = (FLOAT)(MAX_SCREEN_Y - BULLET_HEIGHT);
maxframe = MAX_BULLET_FRAME;
// If bullet "expired", removed it from list
if( thisnode->frame >= MAX_BULLET_FRAME )
{
DisplayObject* pVictim = thisnode;
thisnode = thisnode->next;
DeleteFromList( pVictim );
continue;
}
break;
}
if( thisnode != g_pDisplayList )
{
if( thisnode->posx > maxx )
{
thisnode->posx = maxx;
thisnode->velx = -thisnode->velx;
}
else if ( thisnode->posx < 0 )
{
thisnode->posx =0;
thisnode->velx = -thisnode->velx;
}
if( thisnode->posy > maxy )
{
thisnode->posy = maxy;
thisnode->vely = -thisnode->vely;
}
else if ( thisnode->posy < 0 )
{
thisnode->posy =0;
thisnode->vely = -thisnode->vely;
}
if( thisnode->frame >= maxframe )
{
thisnode->frame -= maxframe;
}
}
}
thisnode = thisnode->next;
}
}
//-----------------------------------------------------------------------------
// Name: IsDisplayListEmpty()
// Desc:
//-----------------------------------------------------------------------------
BOOL IsDisplayListEmpty()
{
DisplayObject* pObject = g_pDisplayList->next;
while( pObject )
{
if( pObject->type != OBJ_BULLET )
return FALSE;
pObject = pObject->next;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: IsDisplayListEmptyExceptShips()
// Desc:
//-----------------------------------------------------------------------------
BOOL IsDisplayListEmptyExceptShips()
{
DisplayObject* pObject = g_pDisplayList->next;
while( pObject )
{
if(( pObject->type != OBJ_BULLET ) && (pObject->type != OBJ_SHIP))
return FALSE;
pObject = pObject->next;
}
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: InitializeShips()
// Desc:
//-----------------------------------------------------------------------------
VOID InitializeShips()
{
for (int ship = 0; ship < NUMBER_OF_PLAYERS; ship++)
{
if (g_pShipsArray[ship] != NULL)
{
g_pShipsArray[ship]->posx = (FLOAT)(g_dwScreenWidth/(ship+2)-16); // Center the ship
g_pShipsArray[ship]->posy = (FLOAT)(g_dwScreenHeight/(ship+2)-16);
g_pShipsArray[ship]->frame = 0.0f;
g_pShipsArray[ship]->velx = 0.0f; // Not moving
g_pShipsArray[ship]->vely = 0.0f;
g_pShipsArray[ship]->bVisible = TRUE;
g_pShipsArray[ship]->Player = ship;
}
}
}
//-----------------------------------------------------------------------------
// Name: AdvanceLevel()
// Desc:
//-----------------------------------------------------------------------------
VOID AdvanceLevel()
{
// Up the level
g_dwLevel++;
// Clear any stray objects (anything but the ships) out of the display list
while( (g_pShip->next != NULL) && (g_pShip->next->type != OBJ_SHIP ))
{
DeleteFromList( g_pShip->next );
}
// Create donuts for the new level
for( WORD i=0; i<(2*g_dwLevel-1); i++ )
{
FLOAT x = rnd( 0.0f, (FLOAT)(MAX_SCREEN_X - DONUT_WIDTH) );
FLOAT y = rnd( 0.0f, (FLOAT)(MAX_SCREEN_Y - DONUT_HEIGHT) );
CreateObject( OBJ_DONUT, x, y, 0.0f, 0.0f, NO_PLAYER );
}
// Delay for 2 seconds before displaying ships
InitializeShips();
g_fShowDelay = 2.0f;
}
//-----------------------------------------------------------------------------
// Name: CreateObject()
// Desc:
//-----------------------------------------------------------------------------
DisplayObject* CreateObject( SHORT type, FLOAT x, FLOAT y, FLOAT vx, FLOAT vy, int Player )
{
// Create a new display object
DisplayObject* pObject = new DisplayObject;
if( NULL == pObject )
return NULL;
// Add the object to the global display list
AddToList( pObject );
// Set object attributes
pObject->bVisible = TRUE;
pObject->type = type;
pObject->posx = x;
pObject->posy = y;
pObject->velx = vx;
pObject->vely = vy;
pObject->Player = NO_PLAYER;
switch( type )
{
case OBJ_DONUT:
pObject->velx = rnd( -50.0f, 50.0f );
pObject->vely = rnd( -50.0f, 50.0f );
pObject->frame = rnd( 0.0f, 30.0f );
pObject->delay = rnd( 3.0f, 12.0f );
pObject->pddsSurface = g_pddsDonut;
break;
case OBJ_PYRAMID:
pObject->velx = rnd( -75.0f, 75.0f );
pObject->vely = rnd( -75.0f, 75.0f );
pObject->frame = rnd( 0.0f, 30.0f );
pObject->delay = rnd( 12.0f, 40.0f );
pObject->pddsSurface = g_pddsPyramid;
break;
case OBJ_SPHERE:
pObject->velx = rnd( -150.0f, 150.0f );
pObject->vely = rnd( -150.0f, 150.0f );
pObject->frame = rnd( 0.0f, 30.0f );
pObject->delay = rnd( 60.0f, 80.0f );
pObject->pddsSurface = g_pddsSphere;
break;
case OBJ_CUBE:
pObject->velx = rnd( -200.0f, 200.0f );
pObject->vely = rnd( -200.0f, 200.0f );
pObject->frame = rnd( 0.0f, 30.0f );
pObject->delay = rnd( 32.0f, 80.0f );
pObject->pddsSurface = g_pddsCube;
break;
case OBJ_SHIP:
pObject->frame = 0.0f;
pObject->posx = x;
pObject->posy = y;
pObject->velx = 0.0f; // Not moving
pObject->vely = 0.0f;
pObject->Player = Player; //which player the ship belongs to
pObject->pddsSurface = g_pddsShip;
break;
case OBJ_BULLET:
pObject->frame = 0.0f;
pObject->delay = 1000.0f;
pObject->Player = Player; //which player's ship shot the bullet
pObject->pddsSurface = g_pddsNumbers;
break;
}
return pObject;
};
//-----------------------------------------------------------------------------
// Name: AddToList()
// Desc:
//-----------------------------------------------------------------------------
VOID AddToList( DisplayObject* pObject )
{
pObject->next = g_pDisplayList->next;
pObject->prev = g_pDisplayList;
if( g_pDisplayList->next )
g_pDisplayList->next->prev = pObject;
g_pDisplayList->next = pObject;
}
//-----------------------------------------------------------------------------
// Name: RestoreSurfaces()
// Desc:
//-----------------------------------------------------------------------------
HRESULT RestoreSurfaces()
{
HRESULT hr;
HBITMAP hbm;
if( FAILED( hr = g_pddsFrontBuffer->Restore() ) )
return E_FAIL;
if( FAILED( hr = g_pddsDonut->Restore() ) )
return E_FAIL;
if( FAILED( hr = g_pddsPyramid->Restore() ) )
return E_FAIL;
if( FAILED( hr = g_pddsCube->Restore() ) )
return E_FAIL;
if( FAILED( hr = g_pddsSphere->Restore() ) )
return E_FAIL;
if( FAILED( hr = g_pddsShip->Restore() ) )
return E_FAIL;
if( FAILED( hr = g_pddsNumbers->Restore() ) )
return E_FAIL;
// Create and set the palette for the splash bitmap
g_pSplashPalette = DDUtil_LoadPalette( g_pDD, "SPLASH" );
// Create and set the palette for the art bitmap
g_pArtPalette = DDUtil_LoadPalette( g_pDD, "DONUTS8" );
if( NULL == g_pSplashPalette || NULL == g_pArtPalette )
{
CleanupAndDisplayError("Could not load palettes");
return E_FAIL;
}
// Set the palette before loading the art
g_pddsFrontBuffer->SetPalette( g_pArtPalette );
hbm = (HBITMAP)LoadImage( GetModuleHandle(NULL), "DONUTS8", IMAGE_BITMAP, 0, 0,
LR_CREATEDIBSECTION );
if( NULL == hbm )
{
CleanupAndDisplayError("Could not load bitmap");
return E_FAIL;
}
// Copy the bitmaps. (We're OR'ing the hresults together so we only have to
// do one check for a failure case.)
hr |= DDUtil_CopyBitmap( g_pddsDonut, hbm, 0, 0, 320, 384 );
hr |= DDUtil_CopyBitmap( g_pddsPyramid, hbm, 0, 384, 320, 128 );
hr |= DDUtil_CopyBitmap( g_pddsSphere, hbm, 0, 512, 320, 32 );
hr |= DDUtil_CopyBitmap( g_pddsCube, hbm, 0, 544, 320, 32 );
hr |= DDUtil_CopyBitmap( g_pddsShip, hbm, 0, 576, 320, 256 );
hr |= DDUtil_CopyBitmap( g_pddsNumbers, hbm, 0, 832, 320, 16 );
if( FAILED(hr) )
{
CleanupAndDisplayError("Could not copy bitmaps to surfaces");
DeleteObject( hbm );
return E_FAIL;
}
// Done with the bitmap
DeleteObject( hbm );
// Set colorfill colors and color keys according to bitmap contents
g_dwFillColor = DDUtil_ColorMatch( g_pddsDonut, CLR_INVALID );
DDUtil_SetColorKey( g_pddsDonut, CLR_INVALID );
DDUtil_SetColorKey( g_pddsPyramid, CLR_INVALID );
DDUtil_SetColorKey( g_pddsCube, CLR_INVALID );
DDUtil_SetColorKey( g_pddsSphere, CLR_INVALID );
DDUtil_SetColorKey( g_pddsShip, CLR_INVALID );
DDUtil_SetColorKey( g_pddsNumbers, CLR_INVALID );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: rnd()
// Desc:
//-----------------------------------------------------------------------------
FLOAT rnd( FLOAT low, FLOAT high )
{
return low + ( high - low ) * ((FLOAT)rand())/RAND_MAX;
}
//-----------------------------------------------------------------------------
// Name: InitializeSound()
// Desc:
//-----------------------------------------------------------------------------
HRESULT InitializeSound( HWND hWnd )
{
g_bSoundEnabled = FALSE;
if( FAILED( DirectSoundCreate( NULL, &g_pDS, NULL ) ) )
//return E_FAIL;
//per Marcus's request, to run on his machine
return S_FALSE;
if( FAILED( g_pDS->SetCooperativeLevel( hWnd, DSSCL_NORMAL ) ) )
{
g_pDS->Release();
g_pDS = NULL;
return E_FAIL;
}
g_pBeginLevelSound = DSUtil_CreateSound( g_pDS, "BeginLevel", 1 );
g_pEngineIdleSound = DSUtil_CreateSound( g_pDS, "EngineIdle", 1 );
g_pEngineRevSound = DSUtil_CreateSound( g_pDS, "EngineRev", 1 );
g_pSkidToStopSound = DSUtil_CreateSound( g_pDS, "SkidToStop", 1 );
g_pShieldBuzzSound = DSUtil_CreateSound( g_pDS, "ShieldBuzz", 1 );
g_pShipExplodeSound = DSUtil_CreateSound( g_pDS, "ShipExplode", 1 );
g_pFireBulletSound = DSUtil_CreateSound( g_pDS, "Gunfire", 25 );
g_pShipBounceSound = DSUtil_CreateSound( g_pDS, "ShipBounce", 4 );
g_pDonutExplodeSound = DSUtil_CreateSound( g_pDS, "DonutExplode", 10 );
g_pPyramidExplodeSound = DSUtil_CreateSound( g_pDS, "PyramidExplode", 12 );
g_pCubeExplodeSound = DSUtil_CreateSound( g_pDS, "CubeExplode", 15 );
g_pSphereExplodeSound = DSUtil_CreateSound( g_pDS, "SphereExplode", 10 );
g_bSoundEnabled = TRUE;
// Start sounds that should be playing
#if 0 //not used for the mulit-user mapper
if( g_bEngineIdle ) DSUtil_PlaySound( g_pEngineIdleSound, DSBPLAY_LOOPING );
if( g_bShieldsOn ) DSUtil_PlaySound( g_pShieldBuzzSound, DSBPLAY_LOOPING );
if( g_bThrusting ) DSUtil_PlaySound( g_pEngineRevSound, DSBPLAY_LOOPING );
#endif //not used for the mulit-user mapper
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DestroySound()
// Desc:
//-----------------------------------------------------------------------------
VOID DestroySound()
{
if( g_pDS )
{
DSUtil_DestroySound( g_pBeginLevelSound );
DSUtil_DestroySound( g_pEngineIdleSound );
DSUtil_DestroySound( g_pEngineRevSound );
DSUtil_DestroySound( g_pSkidToStopSound );
DSUtil_DestroySound( g_pShieldBuzzSound );
DSUtil_DestroySound( g_pShipExplodeSound );
DSUtil_DestroySound( g_pFireBulletSound );
DSUtil_DestroySound( g_pShipBounceSound );
DSUtil_DestroySound( g_pDonutExplodeSound );
DSUtil_DestroySound( g_pPyramidExplodeSound );
DSUtil_DestroySound( g_pCubeExplodeSound );
DSUtil_DestroySound( g_pSphereExplodeSound );
g_pDS->Release();
}
g_pBeginLevelSound = NULL;
g_pEngineIdleSound = NULL;
g_pEngineRevSound = NULL;
g_pSkidToStopSound = NULL;
g_pShieldBuzzSound = NULL;
g_pShipExplodeSound = NULL;
g_pFireBulletSound = NULL;
g_pShipBounceSound = NULL;
g_pDonutExplodeSound = NULL;
g_pPyramidExplodeSound = NULL;
g_pCubeExplodeSound = NULL;
g_pSphereExplodeSound = NULL;
g_pDS = NULL;
g_bSoundEnabled = FALSE;
}
//-----------------------------------------------------------------------------
// Name: InitializeInput()
// Desc:
//-----------------------------------------------------------------------------
HRESULT InitializeInput( HWND hWnd )
{
// Initialize DirectInpu
if( FAILED( DIUtil_Initialize( hWnd ) ) )
{
MessageBox( hWnd, "Can't Initialize DirectInput", "TDonuts", MB_OK );
return E_FAIL;
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DestroyInput()
// Desc:
//-----------------------------------------------------------------------------
VOID DestroyInput()
{
// Release DirectInput
DIUtil_CleanupDirectInput();
}
//-----------------------------------------------------------------------------
// Name: GetDeviceInput(input[])
// Desc: Processes data from the input device. Uses GetDeviceData().
//-----------------------------------------------------------------------------
VOID GetDeviceInput(DWORD input[NUMBER_OF_PLAYERS])
{
HRESULT hr = S_OK;
for (int pl = 0; pl < NUMBER_OF_PLAYERS; pl++)
{
printf("pl = %i", pl);
for (int dv = 0; dv < (int) g_dwNumDevices[pl]; dv++)
{
printf("dv = %i", dv);
if (g_pDevices[pl][dv] != NULL)
{
DWORD dwItems = 10;
DIDEVICEOBJECTDATA rgdod[10];
hr = g_pDevices[pl][dv]->Poll();
if (SUCCEEDED(hr))
{
hr = g_pDevices[pl][dv]->GetDeviceData(
sizeof(DIDEVICEOBJECTDATA),
rgdod,
&dwItems,
0);
if (SUCCEEDED(hr))
{
//get the sematics codes
for (int j=0; j < (int)dwItems; j++)
{
//for axes, do axes stuff
if (rgdod[j].uAppData & AXIS_MASK)
{
//blow out all of the axis data
dwInputState[pl] &= ~(KEY_RIGHT);
dwInputState[pl] &= ~(KEY_LEFT);
dwInputState[pl] &= ~(KEY_UP);
dwInputState[pl] &= ~(KEY_DOWN);
if( ((int)rgdod[j].dwData) > 10 )
{
dwInputState[pl] |= ( rgdod[j].uAppData == AXIS_LR ) ? KEY_RIGHT : KEY_DOWN;
}
if( ((int)rgdod[j].dwData) < -10 )
{
dwInputState[pl] |= ( rgdod[j].uAppData == AXIS_LR ) ? KEY_LEFT : KEY_UP;
}
}
else //do buttons
{
//if rgdod[j].dwData & 0x80, it means the button went down,
//else it went up
if (rgdod[j].dwData & 0x80)
{
//set the new state
dwInputState[pl] |= rgdod[j].uAppData;
}
else
{
dwInputState[pl] &= ~(rgdod[j].uAppData);
}
}
}
}
}
}
}
//set the new state
if (SUCCEEDED(hr))
{
input[pl] = dwInputState[pl];
}
}
}