#include "stdhdr.h"
#include "ddutil.h"
#include "Debug.h"
#include "Sound.h"
#include "Input.h"
#include "Draw.h"
#include "DrawText.h"
#include "Window.h"
#include "Sprites.h"
#include "Logic.h"
GUID g_guidApp =
{ 0x5447976e, 0x1120, 0x4762, { 0x87, 0xe5, 0x61, 0xac, 0xc5, 0x39, 0x74, 0x6a } };
DWORD g_dwGenre = DIVIRTUAL_ARCADE_SIDE2SIDE;
LPCTSTR g_tszActionMapName = _T("Xonix");
enum Actions
{
ACTIONS_LEFTRIGHT,
ACTIONS_UPDOWN,
ACTIONS_LEFT,
ACTIONS_RIGHT,
ACTIONS_UP,
ACTIONS_DOWN,
ACTIONS_QUIT,
ACTIONS_HELP,
ACTIONS_CONFIGURE,
ACTIONS_MUSIC,
ACTIONS_PAUSE,
ACTIONS_START,
ACTIONS_NONE
};
bool g_bQuit, g_bShowHelp, g_bPaused, g_bDoConfig, g_bStart;
bool g_bLeft, g_bRight, g_bUp, g_bDown;
DIACTION g_rgActions[] =
{
{ ACTIONS_LEFTRIGHT, DIAXIS_ARCADES_LATERAL, 0, "Left/Right" },
{ ACTIONS_UPDOWN, DIAXIS_ARCADES_MOVE, 0, "Up/Down" },
{ ACTIONS_LEFT, DIBUTTON_ARCADES_LEFT_LINK, 0, "Left" },
{ ACTIONS_RIGHT, DIBUTTON_ARCADES_RIGHT_LINK, 0, "Right" },
{ ACTIONS_UP, DIBUTTON_ARCADES_FORWARD_LINK, 0, "Up" },
{ ACTIONS_DOWN, DIBUTTON_ARCADES_BACK_LINK, 0, "Down" },
{ ACTIONS_PAUSE, DIBUTTON_ARCADES_PAUSE, 0, "Pause" },
{ ACTIONS_START, DIBUTTON_ARCADES_ATTACK, 0, "Start" },
{ ACTIONS_START, DIKEYBOARD_RETURN, 0, "Start" },
{ ACTIONS_START, DIKEYBOARD_SPACE, 0, "Start" },
{ ACTIONS_LEFT, DIKEYBOARD_LEFT, 0, "Left" },
{ ACTIONS_LEFT, DIKEYBOARD_NUMPAD4, 0, "Left" },
{ ACTIONS_RIGHT, DIKEYBOARD_RIGHT, 0, "Right" },
{ ACTIONS_RIGHT, DIKEYBOARD_NUMPAD6, 0, "Right" },
{ ACTIONS_UP, DIKEYBOARD_UP, 0, "Up" },
{ ACTIONS_UP, DIKEYBOARD_NUMPAD8, 0, "Up" },
{ ACTIONS_DOWN, DIKEYBOARD_DOWN, 0, "Down" },
{ ACTIONS_DOWN, DIKEYBOARD_NUMPAD2, 0, "Down" },
{ ACTIONS_PAUSE, DIKEYBOARD_P, DIA_APPFIXED, "Pause" },
{ ACTIONS_MUSIC, DIKEYBOARD_M, DIA_APPFIXED, "Music on/off" },
{ ACTIONS_HELP, DIKEYBOARD_F1, DIA_APPFIXED, "Help" },
{ ACTIONS_CONFIGURE, DIKEYBOARD_F2, DIA_APPFIXED, "Configure" },
{ ACTIONS_QUIT, DIKEYBOARD_ESCAPE, DIA_APPFIXED, "Quit" },
};
DWORD g_nActions = sizeof(g_rgActions) / sizeof(DIACTION);
IDirectDrawSurface7 *lpImages;
IDirectDrawSurface7 *lpSplash;
CTextFont *g_lpFont;
void ReloadAllSurfaces()
{
DDReLoadBitmap(lpImages, "Main.bmp");
DDReLoadBitmap(lpSplash, "Splash.bmp");
}
IDirectMusicSegment8 *g_pLevelUp, *g_pDie, *g_pFill;
#define NUMMUSICLEVELS 4
IDirectMusicSegment8 *g_pIntroMusic, *g_pLevelMusic[NUMMUSICLEVELS];
bool g_bIntroMusicPlaying, g_bLevelMusicPlaying[NUMMUSICLEVELS];
bool g_bMusicEnabled;
BOOL LoadMusic()
{
g_pIntroMusic = LoadSound(L"passport.mid");
if (g_pIntroMusic == NULL)
return FALSE;
g_pLevelMusic[0] = LoadSound(L"Dance of the Sugar-Plum Fairy.mid");
if (g_pLevelMusic[0] == NULL)
return FALSE;
g_pLevelMusic[1] = LoadSound(L"canyon.mid");
if (g_pLevelMusic[1] == NULL)
return FALSE;
g_pLevelMusic[2] = LoadSound(L"Beethoven's 5th Symphony.mid");
if (g_pLevelMusic[2] == NULL)
return FALSE;
g_pLevelMusic[3] = LoadSound(L"In the Hall of the Mountain King.mid");
if (g_pLevelMusic[3] == NULL)
return FALSE;
g_pIntroMusic->SetRepeats(DMUS_SEG_REPEAT_INFINITE);
g_pIntroMusic->SetParam(GUID_StandardMIDIFile,
0xFFFFFFFF, DMUS_SEG_ALLTRACKS, 0, NULL);
for (int i = 0; i < NUMMUSICLEVELS; i++)
{
g_pLevelMusic[i]->SetRepeats(DMUS_SEG_REPEAT_INFINITE);
g_pLevelMusic[i]->SetParam(GUID_StandardMIDIFile,
0xFFFFFFFF, DMUS_SEG_ALLTRACKS, 0, NULL);
}
return TRUE;
}
void UnloadMusic()
{
UnloadSound(g_pIntroMusic);
g_pIntroMusic->Release();
for (int i = 0; i < NUMMUSICLEVELS; i++)
{
UnloadSound(g_pLevelMusic[i]);
g_pLevelMusic[i]->Release();
}
}
void PlayBackgroundMusic()
{
int n;
if (!g_bMusicEnabled)
return;
switch (g_nGameState)
{
case Intro:
if (g_bIntroMusicPlaying)
return;
StopBackgroundMusic();
DownloadSound(g_pIntroMusic);
PlaySound(g_pIntroMusic);
g_bIntroMusicPlaying = true;
break;
case LevelScreen:
case InGame:
case InGamePaused:
n = (g_nLevel - 1) % NUMMUSICLEVELS;
if (g_bLevelMusicPlaying[n])
return;
StopBackgroundMusic();
DownloadSound(g_pLevelMusic[n]);
PlaySound(g_pLevelMusic[n]);
g_bLevelMusicPlaying[n] = true;
break;
}
}
void StopBackgroundMusic()
{
StopAllSound();
g_bIntroMusicPlaying = false;
memset(g_bLevelMusicPlaying, 0, sizeof(g_bLevelMusicPlaying));
}
#define AXIS_THRESHOLD 20
void HandleAction(UINT nAction, DWORD dwData)
{
int nAxisPos = (int)dwData;
switch (nAction)
{
case ACTIONS_LEFTRIGHT:
if (nAxisPos < -AXIS_THRESHOLD)
{
g_bLeft = true;
g_bRight = false;
}
else if (nAxisPos > AXIS_THRESHOLD)
{
g_bRight = true;
g_bLeft = false;
}
else
{
g_bLeft = g_bRight = false;
}
break;
case ACTIONS_UPDOWN:
if (nAxisPos < -AXIS_THRESHOLD)
{
g_bUp = true;
g_bDown = false;
}
else if (nAxisPos > AXIS_THRESHOLD)
{
g_bDown = true;
g_bUp = false;
}
else
{
g_bUp = g_bDown = false;
}
break;
case ACTIONS_LEFT:
g_bLeft = ((dwData & 0x80) != 0);
break;
case ACTIONS_RIGHT:
g_bRight = ((dwData & 0x80) != 0);
break;
case ACTIONS_UP:
g_bUp = ((dwData & 0x80) != 0);
break;
case ACTIONS_DOWN:
g_bDown = ((dwData & 0x80) != 0);
break;
case ACTIONS_QUIT:
g_bQuit = true;
break;
case ACTIONS_MUSIC:
if (dwData & 0x80)
{
g_bMusicEnabled = !g_bMusicEnabled;
if (g_bMusicEnabled)
PlayBackgroundMusic();
else
StopBackgroundMusic();
}
break;
case ACTIONS_HELP:
if (dwData & 0x80)
g_bShowHelp = true;
break;
case ACTIONS_CONFIGURE:
if (dwData & 0x80)
g_bDoConfig = true;
break;
case ACTIONS_PAUSE:
g_bPaused = (dwData & 0x80) ? true : false;
break;
case ACTIONS_START:
if (dwData & 0x80)
g_bStart = true;
break;
default:
break;
}
}
int g_nFrames, g_nFrameRate, g_nFrameTime;
LARGE_INTEGER g_liStartTime;
void DrawFrame()
{
RECT r;
int x, y, i;
LARGE_INTEGER liStart, liEnd, liFreq;
static BYTE DrawGrid[YBLOCKS][XBLOCKS];
static TCHAR szBuffer[256];
QueryPerformanceCounter(&liStart);
switch (g_nGameState)
{
case Intro:
r.left = r.top = 0;
r.right = 640;
r.bottom = 480;
BackBlt(0, 0, lpSplash, &r, DDBLTFAST_NOCOLORKEY);
break;
case LevelScreen:
ClearScreen();
_stprintf(szBuffer, _T("Level %d"), g_nLevel);
g_lpFont->DrawText(szBuffer, 320, 240, DT_CENTER | DT_VCENTER);
break;
case InGame:
case InGamePaused:
ClearScreen();
memcpy(DrawGrid, Grid, sizeof(Grid));
for (y = 0; y < YBLOCKS; y++)
{
for (x = 0; x < XBLOCKS; x++)
{
if (DrawGrid[y][x] == GRID_EMPTY)
continue;
for (i = 1; ((x + i) < XBLOCKS) && (DrawGrid[y][x + i] == DrawGrid[y][x]); i++)
DrawGrid[y][x + i] = GRID_EMPTY;
if (i > 1)
{
SetRect(&r, x * BLOCKSIZE, y * BLOCKSIZE, (x + i) * BLOCKSIZE, (y + 1) * BLOCKSIZE);
}
else
{
for (i = 1; ((y + i) < YBLOCKS) && (DrawGrid[y + i][x] == DrawGrid[y][x]); i++)
DrawGrid[y + i][x] = GRID_EMPTY;
SetRect(&r, x * BLOCKSIZE, y * BLOCKSIZE, (x + 1) * BLOCKSIZE, (y + i) * BLOCKSIZE);
}
switch (DrawGrid[y][x])
{
case GRID_EMPTY:
break;
case GRID_FULL:
BackBlt(x * BLOCKSIZE, y * BLOCKSIZE, lpImages, &r, DDBLTFAST_NOCOLORKEY);
break;
case GRID_MID:
r.top += MIDTOP;
r.bottom += MIDTOP;
BackBlt(x * BLOCKSIZE, y * BLOCKSIZE, lpImages, &r, DDBLTFAST_NOCOLORKEY);
break;
}
}
}
g_spritePlayer->Draw();
for (i = 0; i < g_nBalls; i++)
{
g_spriteBalls[i]->NextFrame();
g_spriteBalls[i]->Draw();
}
_stprintf(szBuffer, _T("%d%%"), g_nPercentFilled);
g_lpFont->DrawText(szBuffer, 0, YBLOCKS * BLOCKSIZE, DT_LEFT | DT_TOP);
if (g_nLives > 1)
_stprintf(szBuffer, _T("%d lives"), g_nLives);
else
_tcscpy(szBuffer, _T("1 life"));
g_lpFont->DrawText(szBuffer, XSCREEN / 2, YBLOCKS * BLOCKSIZE, DT_CENTER | DT_TOP);
_stprintf(szBuffer, _T("%d FPS (%dms)"),
g_nFrameRate,
g_nFrameTime);
g_lpFont->DrawText(szBuffer, XSCREEN, YBLOCKS * BLOCKSIZE, DT_RIGHT | DT_TOP);
break;
default:
ClearScreen();
break;
}
QueryPerformanceCounter(&liEnd);
QueryPerformanceFrequency(&liFreq);
g_nFrames++;
if (g_nFrames > 100)
{
g_nFrameRate = MulDiv((int)liFreq.QuadPart,
g_nFrames, (int)(liEnd.QuadPart - g_liStartTime.QuadPart));
g_liStartTime = liEnd;
g_nFrames = 0;
}
g_nFrameTime = MulDiv((int)(liEnd.QuadPart - liStart.QuadPart),
1000, (int)liFreq.QuadPart);
g_lpPrimary->Flip(NULL, DDFLIP_WAIT);
}
void OnIdle(void)
{
if (g_lpPrimary == NULL)
return;
if (!g_bActive)
return;
if ((g_nGameState == Initialising) || (g_nGameState == Quitting))
return;
CheckInput();
if (g_bQuit)
{
g_nGameState = Quitting;
PostMessage(hWndMain, WM_CLOSE, 0, 0);
return;
}
if (g_bShowHelp)
{
StopBackgroundMusic();
g_bShowHelp = false;
DisplayInput();
}
if (g_bDoConfig)
{
StopBackgroundMusic();
g_bDoConfig = false;
ConfigureInput();
}
switch (g_nGameState)
{
case Intro:
if (g_bStart)
{
g_bStart = false;
ResetGame();
}
break;
case LevelScreen:
if ((GetTickCount() - g_dwLevelScreenStartTime) > LEVELSCREEN_TIME)
ChangeToGameState(InGame);
break;
case InGamePaused:
if (g_bPaused)
ChangeToGameState(InGame);
break;
case InGame:
if (g_bPaused)
ChangeToGameState(InGamePaused);
if (g_bUp)
{
g_bUp = false;
g_spritePlayer->m_nNextDirection = CPlayerSprite::Direction::UP;
}
if (g_bDown)
{
g_bDown = false;
g_spritePlayer->m_nNextDirection = CPlayerSprite::Direction::DOWN;
}
if (g_bLeft)
{
g_bLeft = false;
g_spritePlayer->m_nNextDirection = CPlayerSprite::Direction::LEFT;
}
if (g_bRight)
{
g_bRight = false;
g_spritePlayer->m_nNextDirection = CPlayerSprite::Direction::RIGHT;
}
UpdateGameState();
break;
}
DrawFrame();
}
BOOL InitApplication(HINSTANCE hInstance)
{
g_nGameState = Initialising;
if (!InitWindow("DirectX Sample Application with configuration"))
return FALSE;
if (!InitDirectMusic())
return FALSE;
g_pLevelUp = LoadSound(L"chimes.wav");
g_pDie = LoadSound(L"explode.wav");
g_pFill = LoadSound(L"camera.wav");
if ((g_pLevelUp == NULL) ||
(g_pDie == NULL) ||
(g_pFill == NULL) ||
!LoadMusic())
{
ExitDirectMusic();
DISPLAYERROR("Could not load music and sound effects.");
return FALSE;
}
g_pLevelUp->SetRepeats(0);
g_pDie->SetRepeats(0);
g_pFill->SetRepeats(0);
DownloadSound(g_pLevelUp);
DownloadSound(g_pDie);
DownloadSound(g_pFill);
if (!InitDirectInput())
{
DISPLAYERROR("Failed to initialise DirectInput.");
ExitDirectMusic();
return FALSE;
}
if (!InitDirectDraw())
{
ExitDirectInput();
ExitDirectMusic();
DestroyWindow(hWndMain);
return FALSE;
}
lpImages = LoadSurface(_T("Main.bmp"));
if (lpImages == NULL)
{
ExitDirectDraw();
ExitDirectInput();
DestroyWindow(hWndMain);
DISPLAYERROR("Could not load sprites.");
return FALSE;
}
DDSetColorKey(lpImages, RGB(0, 0, 0));
lpSplash = LoadSurface(_T("Splash.bmp"));
if (lpSplash == NULL)
{
ExitDirectDraw();
ExitDirectInput();
DestroyWindow(hWndMain);
DISPLAYERROR("Could not load splash screen.");
return FALSE;
}
g_lpFont = new CTextFont(lpImages, TEXTX, TEXTY, TEXTCX, TEXTCY,
_T("abcdefghijklmnopqrstuvwxyz")
_T("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
_T("01234567890-=_+[]{};'#:@~,")
_T("./<>?\\|!\"£$%^&*() "), _T('\0'), 26);
AcquireDevices();
g_bMusicEnabled = true;
ChangeToGameState(Intro);
g_nFrameRate = 60;
QueryPerformanceCounter(&g_liStartTime);
return TRUE;
}
void OnClose()
{
StopBackgroundMusic();
DeletePlayer();
DeleteLevel();
delete g_lpFont;
g_lpFont = NULL;
lpImages->Release();
lpImages = NULL;
lpSplash->Release();
lpSplash = NULL;
ExitDirectDraw();
UnloadMusic();
UnloadSound(g_pLevelUp);
UnloadSound(g_pDie);
UnloadSound(g_pFill);
g_pLevelUp->Release();
g_pLevelUp = NULL;
g_pDie->Release();
g_pDie = NULL;
g_pFill->Release();
g_pFill = NULL;
ExitDirectMusic();
UnacquireDevices();
ExitDirectInput();
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
if (!InitApplication(hInstance))
return 1;
Run();
return 0;
}