1830 lines
57 KiB
C++
1830 lines
57 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "bagel/afxwin.h"
|
|
#include "bagel/hodjnpodj/hnplibs/dibdoc.h"
|
|
#include "bagel/hodjnpodj/hnplibs/stdinc.h"
|
|
#include "bagel/hodjnpodj/hnplibs/text.h"
|
|
#include "bagel/hodjnpodj/globals.h"
|
|
#include "bagel/hodjnpodj/hnplibs/gamedll.h"
|
|
#include "bagel/hodjnpodj/hnplibs/sprite.h"
|
|
#include "bagel/hodjnpodj/hnplibs/mainmenu.h"
|
|
#include "bagel/hodjnpodj/hnplibs/cmessbox.h"
|
|
#include "bagel/hodjnpodj/hnplibs/bitmaps.h"
|
|
#include "bagel/boflib/misc.h"
|
|
#include "bagel/hodjnpodj/hnplibs/rules.h"
|
|
#include "bagel/boflib/error.h"
|
|
#include "bagel/hodjnpodj/hnplibs/button.h"
|
|
#include "bagel/hodjnpodj/novacancy/main.h"
|
|
#include "bagel/hodjnpodj/novacancy/dimens.h"
|
|
#include "bagel/boflib/sound.h"
|
|
#include "bagel/hodjnpodj/libs/macros.h"
|
|
#include "bagel/hodjnpodj/hodjnpodj.h"
|
|
|
|
namespace Bagel {
|
|
namespace HodjNPodj {
|
|
namespace NoVacancy {
|
|
|
|
//
|
|
// Button ID constants
|
|
//
|
|
#define IDC_MENU 100
|
|
#define TIMER_ID 10
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
static CBitmap *pCLDieBmp[7];
|
|
static CBitmap *pCRDieBmp[7];
|
|
|
|
static CSprite *pCDoorBmp[10];
|
|
|
|
CPalette *pGamePalette;
|
|
LPGAMESTRUCT pGameParams;
|
|
const char *INI_SECTION = "No Vacancy";
|
|
|
|
static int gnLDieLeftFinal, // final positions of dice.
|
|
gnLDieTopFinal,
|
|
gnRDieTopFinal,
|
|
gnRDieLeftFinal; //these are set in AnimateDice
|
|
|
|
extern HWND ghParentWnd;
|
|
|
|
CMainWindow::CMainWindow() {
|
|
CString WndClass;
|
|
CRect tmpRect;
|
|
CDibDoc *pDibDoc;
|
|
ERROR_CODE errCode;
|
|
bool bSuccess;
|
|
short i;
|
|
char szMapFile[256];
|
|
|
|
// assume no error
|
|
errCode = ERR_NONE;
|
|
MFC::SetCursor(LoadCursor(nullptr, IDC_WAIT)); //hourglass cursor (wait!)
|
|
|
|
/* Initialize members */
|
|
m_pScrollButton = nullptr;
|
|
m_pGamePalette = nullptr;
|
|
m_bIgnoreScrollClick = false;
|
|
m_bSound = true;
|
|
m_pCLRollingDie = nullptr;
|
|
m_pCRRollingDie = nullptr;
|
|
|
|
|
|
m_bGameLoadUp = true; //this flag is reset to false as soon as the first paint message is processed.
|
|
//It is used so that at the first paint message (as invoked from the UpdateWindow() call
|
|
// in gamedll.cpp) whether or not Meta Game is being played,
|
|
// the doors won't be painted when not a single door is closed as in the case of
|
|
// game load up. (The splash screen has doors open all the way.)
|
|
m_bPause = false;
|
|
m_bGameActive = false;
|
|
m_cActiveDoor = OPEN; // the game has just begun and no door is active. The 0-th door is always open.
|
|
m_cDoorCount = 0; // no door is closed.
|
|
|
|
m_cUnDoableThrows = 0; // no undoable throw has been registered yet.
|
|
m_bDiceJustThrown = false; // dice haven't been thrown yet
|
|
m_bOneDieCase = false; // always start w/ two dice on floor.
|
|
|
|
// Set the coordinates for the "Start New Game" button
|
|
//
|
|
m_rNewGameButton.SetRect(15, 4, 233, 20);
|
|
|
|
// Define a special window class which traps double-clicks, is byte aligned
|
|
// to maximize BITBLT performance, and creates "owned" DCs rather than sharing
|
|
// the five system defined DCs which are not guaranteed to be available;
|
|
// this adds a bit to our app size but avoids hangs/freezes/lockups.
|
|
WndClass = AfxRegisterWndClass(CS_DBLCLKS | CS_BYTEALIGNWINDOW | CS_OWNDC, nullptr, nullptr, nullptr);
|
|
gWndClass = WndClass;
|
|
|
|
// play this game if the background art is available
|
|
Common::strcpy_s(szMapFile, GetStringFromResource(IDS_MINI_GAME_MAP));
|
|
if (FileExists(szMapFile)) {
|
|
// Acquire the shared palette for our game from the splash screen art
|
|
if ((pDibDoc = new CDibDoc()) != nullptr) {
|
|
if (pDibDoc->OpenDocument(szMapFile) != false)
|
|
pGamePalette = m_pGamePalette = pDibDoc->DetachPalette();
|
|
else
|
|
errCode = ERR_UNKNOWN;
|
|
delete pDibDoc;
|
|
pDibDoc = nullptr;
|
|
} else {
|
|
errCode = ERR_MEMORY;
|
|
}
|
|
} else {
|
|
errCode = ERR_FFIND;
|
|
}
|
|
|
|
// Center our window on the screen in the RELEASE mode.
|
|
m_rectGameArea.SetRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
|
|
|
|
// Create the window as a POPUP so no boarders, title, or menu are present;
|
|
// this is because the game's background art will fill the entire 640x480 area.
|
|
if (!Create(WndClass, "Boffo Games -- No Vacancy", WS_POPUP | WS_CLIPCHILDREN, m_rectGameArea, nullptr, 0)) {
|
|
errCode = ERR_UNKNOWN;
|
|
MFC::SetCursor(LoadCursor(nullptr, IDC_ARROW)); //reset cursor
|
|
HandleError(errCode);
|
|
return ;
|
|
}
|
|
|
|
// only continue if there was no error
|
|
if (errCode == ERR_NONE) {
|
|
|
|
if ((m_pScrollButton = new CBmpButton) != nullptr) {
|
|
|
|
m_bIgnoreScrollClick = false;
|
|
tmpRect.SetRect(SCROLL_BUTTON_X, SCROLL_BUTTON_Y, SCROLL_BUTTON_X + SCROLL_BUTTON_DX, SCROLL_BUTTON_Y + SCROLL_BUTTON_DY);
|
|
bSuccess = m_pScrollButton->Create(nullptr, BS_OWNERDRAW | WS_CHILD | WS_VISIBLE, tmpRect, this, IDC_MENU);
|
|
assert(bSuccess);
|
|
if (bSuccess) {
|
|
bSuccess = m_pScrollButton->LoadBitmaps(SCROLLUP, SCROLLDOWN, SCROLLUP, SCROLLUP);
|
|
assert(bSuccess);
|
|
} else {
|
|
errCode = ERR_UNKNOWN;
|
|
}
|
|
} else {
|
|
errCode = ERR_MEMORY;
|
|
}
|
|
}
|
|
|
|
// Automatically bring up the main menu
|
|
if ((errCode == ERR_NONE) && !pGameParams->bPlayingMetagame) {
|
|
PostMessage(WM_COMMAND, IDC_MENU, BN_CLICKED);
|
|
}//ELSE WAIT until UpdateWindow and SetActiveWindow, etc, are executed in GameDLL.cpp
|
|
|
|
//
|
|
// Give them something to look at while loading stuff
|
|
//
|
|
ShowWindow(SW_SHOWNORMAL); // Make window visible
|
|
UpdateWindow(); // Send an OnPaint message to it
|
|
|
|
// Set the coordinates for the Dice Locations.
|
|
m_rLDie.SetRect(LDIE_LEFT, LDIE_TOP, LDIE_RIGHT, LDIE_BOTTOM);
|
|
m_rRDie.SetRect(RDIE_LEFT, RDIE_TOP, RDIE_RIGHT, RDIE_BOTTOM);
|
|
|
|
// Set the coordinates for the Doors.
|
|
m_rDoor1.SetRect(DOOR1_LEFT, DOOR1_TOP, DOOR1_RIGHT, DOOR1_BOTTOM);
|
|
m_rDoor[1].SetRect(DOOR1_LEFT, DOOR1_TOP, DOOR1_RIGHT, DOOR1_BOTTOM);
|
|
m_rDoor[2].SetRect(DOOR2_LEFT, DOOR2_TOP, DOOR2_RIGHT, DOOR2_BOTTOM);
|
|
m_rDoor[3].SetRect(DOOR3_LEFT, DOOR3_TOP, DOOR3_RIGHT, DOOR3_BOTTOM);
|
|
m_rDoor[4].SetRect(DOOR4_LEFT, DOOR4_TOP, DOOR4_RIGHT, DOOR4_BOTTOM);
|
|
m_rDoor[5].SetRect(DOOR5_LEFT, DOOR5_TOP, DOOR5_RIGHT, DOOR5_BOTTOM);
|
|
m_rDoor[6].SetRect(DOOR6_LEFT, DOOR6_TOP, DOOR6_RIGHT, DOOR6_BOTTOM);
|
|
m_rDoor[7].SetRect(DOOR7_LEFT, DOOR7_TOP, DOOR7_RIGHT, DOOR7_BOTTOM);
|
|
m_rDoor[8].SetRect(DOOR8_LEFT, DOOR8_TOP, DOOR8_RIGHT, DOOR8_BOTTOM);
|
|
m_rDoor[9].SetRect(DOOR9_LEFT, DOOR9_TOP, DOOR9_RIGHT, DOOR9_BOTTOM);
|
|
|
|
//set coordinates for paper, bottle,etc.
|
|
Paper.SetRect(PAPER_L, PAPER_T, PAPER_R, PAPER_B);
|
|
aBrShoes.SetRect(aBRSHOES_L, aBRSHOES_T, aBRSHOES_R, aBRSHOES_B);
|
|
bBrShoes.SetRect(bBRSHOES_L, bBRSHOES_T, bBRSHOES_R, bBRSHOES_B);
|
|
BluShoes.SetRect(BLSHOES_L, BLSHOES_T, BLSHOES_R, BLSHOES_B);
|
|
Bottle.SetRect(BOTTLE_L, BOTTLE_T, BOTTLE_R, BOTTLE_B);
|
|
Glass.SetRect(GLASS_L, GLASS_T, GLASS_R, GLASS_B); // ... not used.
|
|
UmbrStand.SetRect(STAND_L, STAND_T, STAND_R, STAND_B);
|
|
Cat.SetRect(HAT4_L, HAT4_T, HAT4_R, HAT4_B);
|
|
Hat6.SetRect(HAT6_L, HAT6_T, HAT6_R, HAT6_B);
|
|
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
m_iDoorStatus[i] = OPEN; // every door is preset to open, the 0-th door is ALWAYS open.
|
|
}
|
|
|
|
/* preload dice cell sprites */
|
|
m_bDiceBmpsLoaded = false;
|
|
|
|
memset(m_bDoorBmpLoaded, false, 10 * sizeof(bool));
|
|
for (i = 1; i < 10; pCDoorBmp[i] = new CSprite(), i++);
|
|
|
|
// only continue if there was no error
|
|
if (errCode == ERR_NONE) {
|
|
|
|
// seed the random number generator
|
|
//srand((unsigned int)timeGetTime());
|
|
|
|
// begin playing bckgnd music when the game begins
|
|
if (pGameParams->bMusicEnabled) {
|
|
if ((m_psndBkgndMusic = new CSound(this, GetStringFromResource(IDS_MIDI_FILE), SOUND_MIDI | SOUND_LOOP | SOUND_DONT_LOOP_TO_END))) {
|
|
m_psndBkgndMusic->midiLoopPlaySegment(4000L, 31030L, 0L, FMT_MILLISEC);
|
|
}//end if m_psndBkgndMusic=new...
|
|
} else {
|
|
m_psndBkgndMusic = nullptr;
|
|
}
|
|
|
|
}
|
|
|
|
MFC::SetCursor(LoadCursor(nullptr, IDC_ARROW));
|
|
HandleError(errCode);
|
|
}
|
|
|
|
void CMainWindow::HandleError(ERROR_CODE errCode) {
|
|
// Exit this application on fatal errors
|
|
if (errCode != ERR_NONE) {
|
|
// pause the current game (if any)
|
|
GamePause();
|
|
|
|
// Display Error Message to the user
|
|
MessageBox(errList[errCode], "Fatal Error!", MB_OK | MB_ICONSTOP);
|
|
|
|
// Force this application to terminate
|
|
PostMessage(WM_CLOSE, 0, 0);
|
|
|
|
// Don't allow a repaint (remove all WM_PAINT messages)
|
|
ValidateRect(nullptr);
|
|
}
|
|
}
|
|
|
|
|
|
void CMainWindow::OnPaint() {
|
|
PAINTSTRUCT lpPaint;
|
|
|
|
Invalidate(false);
|
|
BeginPaint(&lpPaint);
|
|
|
|
PaintScreen();
|
|
EndPaint(&lpPaint);
|
|
}
|
|
|
|
|
|
void CMainWindow::PaintScreen() {
|
|
CDibDoc myDoc;
|
|
CRect rcDest;
|
|
char szMapFile[256];
|
|
|
|
/*nish adds*/
|
|
CRect rcDoor,
|
|
rcDie;
|
|
CDibDoc dieDoc,
|
|
doorDoc;
|
|
short ii;
|
|
/*end nish add*/
|
|
|
|
CRect rcDIB;
|
|
HDIB hDIB;
|
|
CDC *pDC;
|
|
|
|
|
|
//
|
|
// Paint the background art and upadate any sprites
|
|
// called by OnPaint
|
|
//
|
|
Common::strcpy_s(szMapFile, GetStringFromResource(IDS_MINI_GAME_MAP));
|
|
if (FileExists(szMapFile)) {
|
|
myDoc.OpenDocument(szMapFile);
|
|
hDIB = myDoc.GetHDIB();
|
|
|
|
pDC = GetDC();
|
|
assert(pDC != nullptr);
|
|
|
|
if (pDC && m_pGamePalette) {
|
|
|
|
if (hDIB) {
|
|
GetClientRect(rcDest);
|
|
|
|
rcDIB.top = rcDIB.left = 0;
|
|
rcDIB.right = (int) DIBWidth(hDIB);
|
|
rcDIB.bottom = (int) DIBHeight(hDIB);
|
|
|
|
PaintDIB(pDC->m_hDC, &rcDest, hDIB, &rcDIB, m_pGamePalette);
|
|
} //end-if (hDIB)
|
|
|
|
if (m_bGameActive) {
|
|
|
|
/* dont animate dice in the paint message, just paint 'em*/
|
|
|
|
PaintMaskedBitmap(pDC, m_pGamePalette, pCLDieBmp[m_LDie], \
|
|
m_rLDie.left, m_rLDie.top, (int) m_rLDie.Width(), (int) m_rLDie.Height());
|
|
if (!m_bOneDieCase) {
|
|
PaintMaskedBitmap(pDC, m_pGamePalette, pCRDieBmp[m_RDie], \
|
|
m_rRDie.left, m_rRDie.top, (int) m_rRDie.Width(), (int) m_rRDie.Height());
|
|
}
|
|
|
|
/* paint doors except when open or upon GameLoadUp. */
|
|
for (ii = 1; !m_bGameLoadUp && ii < 10; ii++) { //repaint all doors, except on start up.
|
|
if (m_iDoorStatus[ii] == OPEN) continue; //don't need to paint an open door.
|
|
if (!m_bDoorBmpLoaded[ii]) {
|
|
if (!pCDoorBmp[ii]) // the door bmp might have been freed, because the door was locked.
|
|
if ((pCDoorBmp[ii] = new CSprite())) // ...in which case load a new CSprite.
|
|
pCDoorBmp[ii]->LoadCels(pDC, GetStringFromResource(IDS_D1 + ii - 1), NUM_DOOR_CELS);
|
|
//else errCode=ERR_MEMORY;
|
|
m_bDoorBmpLoaded[ii] = true;
|
|
}
|
|
if (m_iDoorStatus[ii] != OPEN) pCDoorBmp[ii]->SetCel(-1); //paint the 1st cel.
|
|
// /* bypassed because of line #1 in the for loop*/ else pCDoorBmp[ii]->SetCel(NUM_DOOR_CELS-2); //paint the last cel.
|
|
|
|
pCDoorBmp[ii]->PaintSprite(pDC, m_rDoor[ii].left, m_rDoor[ii].top);
|
|
|
|
}//end for(ii)
|
|
|
|
m_bGameJustBegun = false;
|
|
m_bGameActive = true;
|
|
ReleaseDC(pDC);
|
|
} //END -if (m_bGameActive)
|
|
|
|
m_bGameLoadUp = false; // the next paint message is not a game load up paint.
|
|
} //end if(pDC && GamePalette)
|
|
} //end if FileExists(MINIGAME_MAP)
|
|
}// end of function.
|
|
|
|
|
|
bool CMainWindow::OnCommand(WPARAM wParam, LPARAM lParam) {
|
|
CMainMenu COptionsWind((CWnd *)this, m_pGamePalette, \
|
|
(pGameParams->bPlayingMetagame ? NO_NEWGAME : 0X00) | (m_bGameActive ? 0X0 : NO_RETURN) | NO_OPTIONS, \
|
|
nullptr, RULES,
|
|
pGameParams->bSoundEffectsEnabled ? GetStringFromResource(IDS_RULES_WAV) : nullptr,
|
|
pGameParams); //DLL CHNG.
|
|
|
|
if (HIWORD(lParam) == BN_CLICKED) {
|
|
switch (wParam) {
|
|
//
|
|
// must bring up our menu of controls
|
|
//
|
|
case IDC_MENU:
|
|
|
|
// hide the command scroll
|
|
//
|
|
m_pScrollButton->SendMessage(BM_SETSTATE, true, 0);
|
|
|
|
if (!m_bIgnoreScrollClick) {
|
|
|
|
m_bIgnoreScrollClick = true;
|
|
|
|
GamePause();
|
|
|
|
// Get users choice from command menu
|
|
//
|
|
switch (COptionsWind.DoModal()) {
|
|
|
|
// User has chosen to play a new game; this is possible only in StandAlone mode.
|
|
//
|
|
case IDC_OPTIONS_NEWGAME:
|
|
if (!pGameParams->bPlayingMetagame) PlayGame();
|
|
|
|
break;
|
|
|
|
// User has chosen to quit this mini-game
|
|
//
|
|
case IDC_OPTIONS_QUIT:
|
|
PostMessage(WM_CLOSE, 0, 0);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// show the command scroll
|
|
//
|
|
m_pScrollButton->SendMessage(BM_SETSTATE, false, 0);
|
|
m_bIgnoreScrollClick = false;
|
|
|
|
//
|
|
// Check to see if the music state was changed and adjust to match it
|
|
//
|
|
if ((pGameParams->bMusicEnabled == false) && (m_psndBkgndMusic != nullptr)) {
|
|
if (m_psndBkgndMusic->playing())
|
|
m_psndBkgndMusic->stop();
|
|
} else if (pGameParams->bMusicEnabled) {
|
|
if (m_psndBkgndMusic == nullptr) {
|
|
m_psndBkgndMusic = new CSound(this, GetStringFromResource(IDS_MIDI_FILE), SOUND_MIDI | SOUND_LOOP | SOUND_DONT_LOOP_TO_END);
|
|
}
|
|
if (m_psndBkgndMusic != nullptr) {
|
|
if (!m_psndBkgndMusic->playing())
|
|
m_psndBkgndMusic->midiLoopPlaySegment(4000L, 31030L, 0L, FMT_MILLISEC);
|
|
}
|
|
}
|
|
|
|
GameResume();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void CMainWindow::GamePause() {
|
|
m_bPause = true;
|
|
}
|
|
|
|
|
|
void CMainWindow::GameResume() {
|
|
m_bPause = false;
|
|
}
|
|
|
|
void CMainWindow::PlayGame() {
|
|
ERROR_CODE errCode;
|
|
CDibDoc myDoc;
|
|
CRect rcDest;
|
|
CRect rcDIB;
|
|
HDIB hDIB;
|
|
CDC *pDC;
|
|
// assume no error
|
|
errCode = ERR_NONE;
|
|
HCURSOR hOldCursor;
|
|
char szMapFile[256];
|
|
CBitmap *pCMonolithDiceBmp = nullptr;
|
|
|
|
//used to ExtractBitmap from the monolithic DiceBmp.
|
|
int xDice[RIGHT + 1][7] = {{0, 60, 120, 180, 240, 300, 360}, {0, 58, 116, 174, 232, 290, 348}};
|
|
int yDice[RIGHT + 1][7] = {{0, 0, 0, 0, 0, 0, 0}, {62, 62, 62, 62, 62, 62, 62}};
|
|
int dxDice[RIGHT + 1][7] = {{60, 60, 60, 60, 60, 60, 60}, {57, 58, 58, 58, 58, 58, 58}};
|
|
int dyDice[RIGHT + 1][7] = {{62, 62, 62, 62, 62, 62, 62}, {60, 61, 61, 61, 61, 61, 61}};
|
|
|
|
|
|
TRACE("Starting New Game...");
|
|
|
|
// reset all game parameters
|
|
//
|
|
GameReset();
|
|
|
|
if (!m_bDiceBmpsLoaded) {
|
|
hOldCursor = MFC::SetCursor(LoadCursor(nullptr, IDC_WAIT));
|
|
if ((pDC = GetDC()) != nullptr) {
|
|
if ((m_pCLRollingDie = new CSprite()) != nullptr) {
|
|
m_pCLRollingDie->SetMobile(true);
|
|
m_pCLRollingDie->SetMasked(false);
|
|
if (m_pCLRollingDie->LoadCels(pDC, GetStringFromResource(IDS_ROLLING_LDIE_ANIMATION), NUM_LDIE_CELS))
|
|
m_pCLRollingDie->LinkSprite();
|
|
else {
|
|
errCode = ERR_MEMORY;
|
|
MFC::SetCursor(LoadCursor(nullptr, IDC_ARROW)); //reset cursor
|
|
HandleError(errCode);
|
|
return ;
|
|
}
|
|
} else {
|
|
errCode = ERR_MEMORY;
|
|
MFC::SetCursor(LoadCursor(nullptr, IDC_ARROW)); //reset cursor
|
|
HandleError(errCode);
|
|
return ;
|
|
} // end if m_pCLRollingDie
|
|
|
|
if ((m_pCRRollingDie = new CSprite)) {
|
|
m_pCRRollingDie->SetMobile(true);
|
|
m_pCRRollingDie->SetMasked(false);
|
|
if (m_pCRRollingDie->LoadCels(pDC, GetStringFromResource(IDS_ROLLING_RDIE_ANIMATION), NUM_RDIE_CELS))
|
|
m_pCRRollingDie->LinkSprite();
|
|
else {
|
|
errCode = ERR_MEMORY;
|
|
MFC::SetCursor(LoadCursor(nullptr, IDC_ARROW)); //reset cursor
|
|
HandleError(errCode);
|
|
return ;
|
|
}
|
|
} else {
|
|
errCode = ERR_MEMORY;
|
|
MFC::SetCursor(LoadCursor(nullptr, IDC_ARROW)); //reset cursor
|
|
HandleError(errCode);
|
|
return ;
|
|
} // end if m_pCRRollingDie
|
|
|
|
|
|
if ((pCMonolithDiceBmp = FetchBitmap(pDC, nullptr, GetStringFromResource(IDS_DICE_MONOLITHE))) != nullptr) {
|
|
pCLDieBmp[0] = ExtractBitmap(pDC, pCMonolithDiceBmp, m_pGamePalette, xDice[LEFT][0], yDice[LEFT][0], dxDice[LEFT][0], dyDice[LEFT][0]); //flr under Ldie
|
|
pCRDieBmp[0] = ExtractBitmap(pDC, pCMonolithDiceBmp, m_pGamePalette, xDice[RIGHT][0], yDice[RIGHT][0], dxDice[RIGHT][0], dyDice[RIGHT][0]); //flr under Rdie
|
|
for (int i = 1; i < 7; i++) {
|
|
pCLDieBmp[i] = ExtractBitmap(pDC, pCMonolithDiceBmp, m_pGamePalette, xDice[LEFT][i], yDice[LEFT][i], dxDice[LEFT][i], dyDice[LEFT][i]);
|
|
pCRDieBmp[i] = ExtractBitmap(pDC, pCMonolithDiceBmp, m_pGamePalette, xDice[RIGHT][i], yDice[RIGHT][i], dxDice[RIGHT][i], dyDice[RIGHT][i]);
|
|
}//end for i
|
|
if (pCMonolithDiceBmp) delete pCMonolithDiceBmp;
|
|
pCMonolithDiceBmp = nullptr;
|
|
|
|
} else {
|
|
errCode = ERR_MEMORY;
|
|
MFC::SetCursor(LoadCursor(nullptr, IDC_ARROW)); //reset cursor
|
|
HandleError(errCode);
|
|
return ;
|
|
} // end if pCMonolithDiceBmp
|
|
|
|
|
|
|
|
|
|
ReleaseDC(pDC);
|
|
|
|
} else { // pDC
|
|
errCode = ERR_MEMORY;
|
|
MFC::SetCursor(hOldCursor);
|
|
HandleError(errCode);
|
|
}//end if pDC
|
|
MFC::SetCursor(hOldCursor);
|
|
m_bDiceBmpsLoaded = true;
|
|
} // m_bDiceBmpsLoaded
|
|
|
|
Common::strcpy_s(szMapFile, GetStringFromResource(IDS_MINI_GAME_MAP));
|
|
if (FileExists(szMapFile)) {
|
|
myDoc.OpenDocument(szMapFile);
|
|
hDIB = myDoc.GetHDIB();
|
|
|
|
pDC = GetDC();
|
|
if (hDIB) {
|
|
GetClientRect(rcDest);
|
|
|
|
rcDIB.top = rcDIB.left = 0;
|
|
rcDIB.right = (int) DIBWidth(hDIB);
|
|
rcDIB.bottom = (int) DIBHeight(hDIB);
|
|
|
|
PaintDIB(pDC->m_hDC, &rcDest, hDIB, &rcDIB, m_pGamePalette);
|
|
}//end if (hDIB)
|
|
|
|
AnimateDice();
|
|
|
|
m_LDie = (byte)(((uint32)(unsigned int)brand() * 6L) / ((uint32)(unsigned int)RAND_MAX + 1L)) + 1;
|
|
m_RDie = (byte)(((uint32)(unsigned int)brand() * 6L) / ((uint32)(unsigned int)RAND_MAX + 1L)) + 1;
|
|
|
|
PaintMaskedBitmap(pDC, m_pGamePalette, pCRDieBmp[m_RDie], \
|
|
m_rRDie.left, m_rRDie.top, (int) m_rRDie.Width(), (int) m_rRDie.Height());
|
|
|
|
PaintMaskedBitmap(pDC, m_pGamePalette, pCLDieBmp[m_LDie], \
|
|
m_rLDie.left, m_rLDie.top, (int) m_rLDie.Width(), (int) m_rLDie.Height());
|
|
|
|
m_bDiceJustThrown = true;
|
|
m_bGameActive = true;
|
|
|
|
ReleaseDC(pDC);
|
|
|
|
} //end if(FileExists())
|
|
HandleError(errCode);
|
|
}
|
|
|
|
|
|
|
|
void CMainWindow::GameReset() {
|
|
m_bGameActive = false; // there is no currently active game
|
|
|
|
for (short i = 0; i < 10; i++) {
|
|
m_bDoorBmpLoaded[i] = false;
|
|
m_iDoorStatus[i] = OPEN; //every door is open.
|
|
}// end i
|
|
|
|
m_bGameJustBegun = true;
|
|
m_cActiveDoor = OPEN; // the game has just begun and no door is active. The 0-th door is always open.
|
|
m_cDoorCount = 0; // no door is closed.
|
|
m_cUnDoableThrows = 0; // no undoable throw has been registered yet.
|
|
|
|
m_bDiceJustThrown = false; //dice haven't been thrown yet
|
|
m_bPause = false; // the game is not paused
|
|
|
|
m_bOneDieCase = false;
|
|
m_iMoveValid = 0;
|
|
//srand(LOWORD(timeGetTime()));
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
*******************************************************************************************************************
|
|
*
|
|
* OnMouseMove
|
|
*
|
|
* FUNCTIONAL DESCRIPTION
|
|
* Handles the Window Message WM_MOUSEMOVE. In _Debug mode it is used to
|
|
* reset recursion count of the midi looping.
|
|
*
|
|
* CALLING SEQUENCE:
|
|
* Called By MFC/Windows;
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
* Refer to MFC doc.
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
* Refer to MFC doc.
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
* Refer to MFC doc.
|
|
*
|
|
* RETURN VALUE:
|
|
* void
|
|
*
|
|
***********************************************************************************************************************************
|
|
*/
|
|
void CMainWindow::OnMouseMove(unsigned int, CPoint) {
|
|
SetCursor(LoadCursor(nullptr, IDC_ARROW));
|
|
}
|
|
|
|
|
|
/*
|
|
*******************************************************************************************************************
|
|
*
|
|
* OnLButtonDown
|
|
*
|
|
* FUNCTIONAL DESCRIPTION
|
|
* Handles the Window Message WM_LBUTTONDOWN.
|
|
* For the game it processes all easter egg animations,
|
|
* determines if doors/dice have been clicked and initiates appropriates
|
|
* logical steps to that effect using procedures such as CMainWindow::LegalizeMove() and others.
|
|
* It also checks if the game is over and computes score.
|
|
*
|
|
* CALLING SEQUENCE:
|
|
* Called By MFC/Windows;
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
* Refer to MFC doc.
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
* Refer to MFC doc.
|
|
* m_r?Die CRect rectangle spanned by each die.
|
|
* m_bGameActive bool is game on?
|
|
* m_bOneDieCase bool is just one die to be rolled (from now on)?
|
|
* m_pC?RollingDie CSprite cell animation for each die.
|
|
* gn?DieLeft, gn?DieTop int Final positions for dice.
|
|
* m_?Die int The face value of the throw for each die.
|
|
* pGameParams LPGAMESTRUCT defined by Meta game.
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
* Refer to MFC doc.
|
|
*
|
|
* RETURN VALUE:
|
|
* void
|
|
*
|
|
***********************************************************************************************************************************
|
|
*/
|
|
|
|
void CMainWindow::OnLButtonDown(unsigned int nFlags, CPoint point) {
|
|
short i,
|
|
iDoor;
|
|
short jj;
|
|
bool AllFxd, //flag to indicate all fixed (locked) doors.
|
|
AllClosed; //flag to indicate all closed doors.
|
|
uint32 V;
|
|
CDC* pDC;
|
|
short int cel;
|
|
CSprite* pBottleSprite,
|
|
*pCatSprite;
|
|
HLOCAL hlocScore;
|
|
char *npszScore; //to display score in case of SA mode
|
|
const int iMaxScore = 45; //1+2+3+4+5+6+7+8+9 to be used for score computation.
|
|
ERROR_CODE errCode = ERR_NONE;
|
|
|
|
//reset recursion count of midi music loop
|
|
|
|
// User clicked on the Title - NewGame button
|
|
//
|
|
if (m_rNewGameButton.PtInRect(point) && !pGameParams->bPlayingMetagame) {
|
|
|
|
// start a new game only if not in meta game mode.
|
|
PlayGame();
|
|
|
|
} else {
|
|
if (pGameParams->bSoundEffectsEnabled) { //play sound effects (Easter Eggs) only if this flag is enabled
|
|
pDC = GetDC();
|
|
|
|
if (Paper.PtInRect(point)) { //NewsPaper EasterEgg,
|
|
sndPlaySound(GetStringFromResource(IDS_EXTRA), SND_SYNC);
|
|
}
|
|
|
|
if (Glass.PtInRect(point)) { //ShotGlass EasterEgg,
|
|
sndPlaySound(GetStringFromResource(IDS_HICCUPS), SND_SYNC);
|
|
}
|
|
|
|
|
|
if (Bottle.PtInRect(point)) { //AINMATE bottle when door is closed and just play "GHOST.WAV" otherwise.
|
|
if (m_iDoorStatus[3] != OPEN) {
|
|
sndPlaySound(GetStringFromResource(IDS_GHOST), SND_ASYNC);
|
|
if ((pBottleSprite = new CSprite()) != nullptr) {
|
|
if (!pBottleSprite->LoadCels(pDC, GetStringFromResource(IDS_BOTTLE_STRIP_door_closed), BOTTLE_CELS)) {
|
|
errCode = ERR_MEMORY;
|
|
MFC::SetCursor(LoadCursor(nullptr, IDC_ARROW)); //reset cursor
|
|
HandleError(errCode);
|
|
return ;
|
|
} else {
|
|
pBottleSprite->LinkSprite();
|
|
for (cel = 0; cel < BOTTLE_CELS; cel ++) {
|
|
pBottleSprite->SetCel(cel - 1);
|
|
pBottleSprite->PaintSprite(pDC, BOTTLE_SPRITE_L, BOTTLE_SPRITE_T);
|
|
Sleep(3 * 1810 / BOTTLE_CELS);
|
|
}
|
|
pBottleSprite->EraseSprite(pDC);
|
|
}
|
|
delete pBottleSprite;
|
|
pBottleSprite = nullptr;
|
|
}//end if pBottleSprite
|
|
} else {
|
|
sndPlaySound(GetStringFromResource(IDS_HICCUPS), SND_SYNC);
|
|
}//end if m_iDoorStatus
|
|
}//end if Bottle.PtInRect
|
|
|
|
if (aBrShoes.PtInRect(point) || bBrShoes.PtInRect(point) || BluShoes.PtInRect(point)) {
|
|
sndPlaySound(GetStringFromResource(IDS_FOOTSTEP), SND_SYNC); //BROWN SHOES EasterEgg.
|
|
}
|
|
|
|
if (Cat.PtInRect(point)) { // Hat4 is the CAT.
|
|
if ((pCatSprite = new CSprite()) != nullptr) {
|
|
sndPlaySound(GetStringFromResource(IDS_MEOW), SND_ASYNC);
|
|
if (m_iDoorStatus[4] != OPEN) {
|
|
pCatSprite->LoadCels(pDC, GetStringFromResource(IDS_HAT4_STRIP_door_closed), HAT4_CELS);
|
|
pCatSprite->LinkSprite();
|
|
for (cel = 0; cel < HAT4_CELS; cel ++) {
|
|
pCatSprite->SetCel(cel - 1);
|
|
pCatSprite->PaintSprite(pDC, HAT4_SPRITE_L, HAT4_SPRITE_T);
|
|
Sleep(2020 / HAT4_CELS);
|
|
}
|
|
} else {
|
|
pCatSprite->LoadCels(pDC, GetStringFromResource(IDS_HAT4_STRIP_door_open), HAT4_CELS);
|
|
for (cel = 0; cel < HAT4_CELS; cel ++) {
|
|
pCatSprite->SetCel(cel - 1);
|
|
pCatSprite->PaintSprite(pDC, HAT4_SPRITE_L, HAT4_SPRITE_T);
|
|
Sleep(2020 / HAT4_CELS);
|
|
}
|
|
}
|
|
pCatSprite->EraseSprite(pDC);
|
|
delete pCatSprite;
|
|
pCatSprite = nullptr;
|
|
}
|
|
}
|
|
if (Hat6.PtInRect(point)) { //Hat EasterEgg.
|
|
sndPlaySound(GetStringFromResource(IDS_HAT), SND_SYNC);
|
|
}
|
|
if (UmbrStand.PtInRect(point)) { //Umbrella Stand EasterEgg.
|
|
sndPlaySound(GetStringFromResource(IDS_SINGRAIN), SND_SYNC);
|
|
}
|
|
|
|
|
|
ReleaseDC(pDC);
|
|
}
|
|
|
|
/*
|
|
Detect if dice were clicked, if Game is active.
|
|
*/
|
|
if (((m_rLDie.PtInRect(point) || m_rRDie.PtInRect(point)) && m_bGameActive && !m_bOneDieCase)
|
|
|| (m_rLDie.PtInRect(point) && m_bOneDieCase && m_bGameActive)) {
|
|
|
|
if (m_iMoveValid > 0) { //dice can be clicked only if doors are correctly opened.When
|
|
// the game has just begun, everything is taken care of in the WM_PAINT message..
|
|
m_bDiceJustThrown = true; //set flag if click is to be accepted.
|
|
|
|
for (i = 1; i < 10; i++) {
|
|
if (m_iDoorStatus[i] == CLOSED) {
|
|
m_iDoorStatus[i] = FIXED; // lock all closed doors, before permitting player to click on door(s),
|
|
if (pCDoorBmp[i]) {
|
|
delete pCDoorBmp[i]; // and free up those sprites.
|
|
pCDoorBmp[i] = nullptr;
|
|
m_bDoorBmpLoaded[i] = false;
|
|
}
|
|
} // end if m_iDoorStatus[i]==CLOSED
|
|
}// end for i
|
|
|
|
|
|
/*
|
|
determine if this throw is to be done with a single die. (ie. if throws 7 and above are all undoable)
|
|
*/
|
|
for (i = 7, AllFxd = true; i < 13; i++) { // i<13 because i==12 is the max doable throw with two dice.
|
|
/***** note that this was a bug in versions 1.0 thru 1.5 ******/
|
|
if (AllFxd) AllFxd = !IsThrowDoable((byte)i);
|
|
else break;
|
|
}
|
|
m_bOneDieCase = AllFxd;
|
|
|
|
/* randomise throws */
|
|
|
|
V = (uint32)((unsigned int)RAND_MAX + 1);
|
|
m_LDie = (byte)(((uint32)(unsigned int)brand() * 6L) / V) +1; // left Die
|
|
m_RDie = m_bOneDieCase ? 0 : (byte)(((uint32)(unsigned int)brand() * 6) / V) +1; // right Die
|
|
|
|
|
|
pDC = GetDC();
|
|
|
|
|
|
/* animate dice with audio FX*/
|
|
AnimateDice();
|
|
|
|
/*
|
|
Paint dice/ (die and flr).
|
|
*/
|
|
PaintMaskedBitmap(pDC, m_pGamePalette, pCLDieBmp[m_LDie], \
|
|
m_rLDie.left, m_rLDie.top, (int) m_rLDie.Width(), (int) m_rLDie.Height());
|
|
|
|
PaintMaskedBitmap(pDC, m_pGamePalette, pCRDieBmp[m_RDie], \
|
|
m_rRDie.left, m_rRDie.top, (int) m_rRDie.Width(), (int) m_rRDie.Height());
|
|
ReleaseDC(pDC);
|
|
|
|
/*
|
|
see if current throw is doable. If not increment count of undoable throws.
|
|
Bring up MessageBox to that effect and in case it's 3 throws terminate current
|
|
game. If the throw is doable reset the count of undoable throws to 0.
|
|
*/
|
|
if (!IsThrowDoable((byte)(m_LDie + m_RDie))) {
|
|
/*
|
|
if the #of successive undoable throws is 3 then you 've lost game.
|
|
Else: display message box and continue
|
|
*/
|
|
|
|
switch (++m_cUnDoableThrows) {
|
|
default:
|
|
case 3:
|
|
if (pGameParams->bSoundEffectsEnabled) sndPlaySound(GetStringFromResource(IDS_SOSORRY), SND_ASYNC);
|
|
CMessageBox(this, m_pGamePalette, "Game over.", "You have lost!");
|
|
|
|
pDC = GetDC();
|
|
if (!m_bOneDieCase) {
|
|
m_pCLRollingDie->SetCel(-1); //repaint floor with no dice.
|
|
m_pCRRollingDie->SetCel(-1);
|
|
m_pCLRollingDie->PaintSprite(pDC, gnLDieLeftFinal, gnLDieTopFinal);
|
|
m_pCRRollingDie->PaintSprite(pDC, gnRDieLeftFinal, gnRDieTopFinal);
|
|
} else {
|
|
|
|
m_pCLRollingDie->SetCel(-1); /*single*/
|
|
m_pCLRollingDie->PaintSprite(pDC, gnLDieLeftFinal, gnLDieTopFinal);/*single*/
|
|
}
|
|
ReleaseDC(pDC);
|
|
/*
|
|
Compute Score as the number of open doors
|
|
*/
|
|
for (iDoor = 1, pGameParams->lScore = 0x00L; iDoor < 10; iDoor++) {
|
|
if (m_iDoorStatus[iDoor] == OPEN) pGameParams->lScore += iDoor;
|
|
}
|
|
/*
|
|
Display Score if not in Meta mode
|
|
*/
|
|
//if(!pGameParams->bPlayingMetagame){
|
|
if ((hlocScore = LocalAlloc(LHND, 32)) != nullptr) {
|
|
npszScore = (char *)LocalLock(hlocScore);
|
|
Common::sprintf_s(npszScore, 32, "%lu point%c out of 45.", iMaxScore - pGameParams->lScore, ((iMaxScore - pGameParams->lScore) == 1) ? ' ' : 's'); //imaxScore is 45.
|
|
CMessageBox(this, m_pGamePalette, "Your score is", npszScore);
|
|
LocalUnlock(hlocScore);
|
|
LocalFree(hlocScore);
|
|
}
|
|
//}
|
|
m_bGameActive = false; //set game over flag.
|
|
if (pGameParams->bPlayingMetagame) PostMessage(WM_CLOSE, 0, 0L); //quit if in Meta game mode.
|
|
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
char *npszInfo;
|
|
HLOCAL hInfo;
|
|
|
|
if ((hInfo = LocalAlloc(LHND, 32)) == nullptr)
|
|
error("TODO: Memory alloc");
|
|
|
|
npszInfo = (char *)LocalLock(hInfo);
|
|
Common::sprintf_s(npszInfo, 32, "Only %d throw%c left.", (3 - m_cUnDoableThrows), (m_cUnDoableThrows == 1) ? 's' : ' ');
|
|
|
|
GamePause();
|
|
sndPlaySound(GetStringFromResource(IDS_SORRY), SND_ASYNC);
|
|
CMessageBox(this, m_pGamePalette, "Undoable throw!", npszInfo ? (char *)npszInfo : "");
|
|
|
|
LocalUnlock(hInfo);
|
|
LocalFree(hInfo);
|
|
|
|
pDC = GetDC();
|
|
if (!m_bOneDieCase) {
|
|
m_pCLRollingDie->SetCel(-1); //repaint floor with no dice.
|
|
m_pCRRollingDie->SetCel(-1);
|
|
m_pCLRollingDie->PaintSprite(pDC, gnLDieLeftFinal, gnLDieTopFinal);
|
|
m_pCRRollingDie->PaintSprite(pDC, gnRDieLeftFinal, gnRDieTopFinal);
|
|
} else {
|
|
m_pCLRollingDie->SetCel(-1);/*Single*/
|
|
m_pCLRollingDie->PaintSprite(pDC, gnLDieLeftFinal, gnLDieTopFinal);/*Single*/
|
|
}
|
|
ReleaseDC(pDC);
|
|
GameResume();
|
|
Sleep(200); //wait for a while
|
|
break;
|
|
|
|
} //end switch(m_cUnDoableThrows)
|
|
|
|
m_iMoveValid = 1; //this is an invalid throw; so reset indicators and roll dice, then exit the func.
|
|
// m_iMoveValid is set to 1, because the move is valid even though the throw is invalid.
|
|
|
|
if (!m_bOneDieCase) PostMessage(WM_LBUTTONDOWN, 0, MAKELPARAM(LDIE_MIDPOINT_X, LDIE_MIDPOINT_Y));
|
|
else PostMessage(WM_LBUTTONDOWN, 0, MAKELPARAM(SINGLE_DIE_MIDPOINT_X, SINGLE_DIE_MIDPOINT_Y));
|
|
PostMessage(WM_LBUTTONUP, 0, 0L);
|
|
return;
|
|
|
|
} else {
|
|
m_cUnDoableThrows = 0;
|
|
} //end if(!IsThrowdoable...)
|
|
|
|
|
|
m_iMoveValid = 0; // indicators.
|
|
|
|
} else {
|
|
sndPlaySound(GetStringFromResource(IDS_NOPE), SND_ASYNC);
|
|
}//end !Ism_iMoveValid
|
|
|
|
} //end if(m_rLDie.PtInRect(point)...
|
|
|
|
if (m_bDiceJustThrown || (m_iMoveValid >= 0)) { // can doors be clicked upon?
|
|
pDC = GetDC();
|
|
for (i = 1; i < 10; i++) {
|
|
if (m_rDoor[i].PtInRect(point) && m_bGameActive) {
|
|
/*first:
|
|
if the corresponding cel strip is not loaded, then load it
|
|
*/
|
|
if (!m_bDoorBmpLoaded[i]) {
|
|
if (!pCDoorBmp[i])
|
|
pCDoorBmp[i] = new CSprite; // the sprite might have been deleted in prev game if that door was locked @end of game.
|
|
if (pCDoorBmp[i]) (void)pCDoorBmp[i]->LoadCels(pDC, GetStringFromResource(IDS_D1 + i - 1), NUM_DOOR_CELS);
|
|
m_bDoorBmpLoaded[i] = true;
|
|
}
|
|
|
|
/*
|
|
if door is not FIXED( LOCKED) check for validity of move and/or throw.
|
|
*/
|
|
if (m_iDoorStatus[i] != FIXED) { //you can click only on an unlocked door.
|
|
m_iMoveValid = LegalizeMove(i);
|
|
if (m_iMoveValid != -1) { //valid move.
|
|
m_iDoorStatus[i] = !(m_iDoorStatus[i]); //m_idoorStatus reflects the new door status.
|
|
|
|
if (m_iDoorStatus[i] == OPEN) { //open a closed door.
|
|
if (pGameParams->bSoundEffectsEnabled) sndPlaySound(GetStringFromResource(IDS_CREAKING_DOOR_OPENING), SND_ASYNC);
|
|
|
|
/*animate doorsprite.*/
|
|
for (jj = 0; jj < NUM_DOOR_CELS; jj++) {
|
|
pCDoorBmp[i]->SetCel(jj - 1);
|
|
pCDoorBmp[i]->PaintSprite(pDC, m_rDoor[i].left, m_rDoor[i].top);
|
|
Sleep(SLEEP_OPENING_TIME); //sync the audio and video of animation.
|
|
} //end for jj
|
|
} else { //shut the open door.
|
|
if (pGameParams->bSoundEffectsEnabled) sndPlaySound(GetStringFromResource(IDS_CREAKING_DOOR_CLOSING), SND_ASYNC);
|
|
for (jj = NUM_DOOR_CELS; jj > 0; jj--) {
|
|
pCDoorBmp[i]->SetCel(jj - 2); // because PaintSprite automatically advances to the next cel.
|
|
pCDoorBmp[i]->PaintSprite(pDC, m_rDoor[i].left, m_rDoor[i].top);
|
|
if (jj < 5) Sleep(SLEEP_CLOSING_TIME); //sync the audio and video of animation.
|
|
}//end for jj
|
|
} //end if m_iDoorStatus==Open.
|
|
|
|
|
|
m_cActiveDoor = (byte)i; //set active door. //this flag is now obsolete, but retained only for compatibility.
|
|
} else { //if m_iMoveValid ==-1 i.e. invalid move
|
|
sndPlaySound(GetStringFromResource(IDS_NOPE), SND_ASYNC);
|
|
if ((m_iMoveValid = LegalizeMove(0)) == 1);
|
|
/* Consider the following case:
|
|
All Doors are open;
|
|
You Roll 9, Click on Door 9 to close it, m_iMoveValid is 1.
|
|
click on door 1,(it beeps; door sum is still 9), but m_iMoveValid is -1.
|
|
Thus the move is erroneously interpreted as invalid.
|
|
To take care of such cases, re-check the status of the move,
|
|
by passing in the 0-th door (this door is always open). It does not
|
|
afffect the door sum and hence is a beautiful verification mechanism.
|
|
*/
|
|
else m_iMoveValid = 0; //the move is genuinely invalid.
|
|
} //end if (m_iMoveValid...)
|
|
} //end if(m_iDoorStatus...)
|
|
break; //breaks the for loop cos there's only one mouse strike for a given loop.
|
|
} //end if(m_rDoor[i]...)
|
|
} // end -for(i)
|
|
ReleaseDC(pDC);
|
|
} else {
|
|
//indicate that you are clicking on doors one too many, or you have an incorrect sum !
|
|
sndPlaySound(GetStringFromResource(IDS_NOPE), SND_ASYNC);
|
|
} //end if (m_bDiceJustThrown ...)
|
|
|
|
if (m_iMoveValid > 0) { //if valid move, check for the YOU WIN case.
|
|
for (AllClosed = true, i = 1; i < 10; i++) {
|
|
if (AllClosed) AllClosed = (m_iDoorStatus[i] != OPEN);
|
|
else break;
|
|
}
|
|
|
|
if (AllClosed) { //you have won!
|
|
if (pGameParams->bSoundEffectsEnabled) sndPlaySound(GetStringFromResource(IDS_APPLAUSE), SND_ASYNC);
|
|
CMessageBox(this, m_pGamePalette, "Game over.", "You have won!");
|
|
pGameParams->lScore = 0x00L; //make game result available to meta game.; no door open
|
|
|
|
m_iMoveValid = 0;
|
|
m_bDiceJustThrown = false;
|
|
m_bGameActive = false;
|
|
/* you have to quit the mini game if in MetaGame Mode */
|
|
if (pGameParams->bPlayingMetagame) PostMessage(WM_CLOSE, 0, 0L);
|
|
}//end if AllClosed
|
|
}//end if (m_iMoveValid>0)
|
|
|
|
}//end else if not in new button rect.
|
|
(void)nFlags;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
*******************************************************************************************************************
|
|
*
|
|
* OnRButtonDown
|
|
*
|
|
* FUNCTIONAL DESCRIPTION
|
|
* Handles the Window Message WM_RBUTTONDOWN.
|
|
* For the game it undoes the last sequence of closing/opening of doors,
|
|
* and restores'em to a state just prior to the last roll of dice.
|
|
*
|
|
* CALLING SEQUENCE:
|
|
* Called By MFC/Windows;
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
* Refer to MFC doc.
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
* Refer to MFC doc.
|
|
* m_rDoor[ ] CRect rectangle spanned by each door.
|
|
* m_bGameActive bool is game on?
|
|
* m_iDoorStatus[ ] int The Status of each door.
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
* Refer to MFC doc.
|
|
*
|
|
* RETURN VALUE:
|
|
* void
|
|
*
|
|
***********************************************************************************************************************************
|
|
*/
|
|
void CMainWindow::OnRButtonDown(unsigned int nFlags, CPoint point) {
|
|
short i;
|
|
int xx,
|
|
yy;
|
|
CDC* pDC;
|
|
|
|
/*
|
|
Restores (Undoes) m_iDoorStatus to that just prior to rolling of dice
|
|
*/
|
|
if (m_bGameActive) {
|
|
|
|
pDC = GetDC();
|
|
for (i = 1; i < 10; i++) {
|
|
/*open all unlocked doors*/
|
|
if (m_iDoorStatus[i] == CLOSED) {
|
|
/*
|
|
simulate clicking (with L Mouse Button) on each closed door individually
|
|
*/
|
|
xx = m_rDoor[i].left + m_rDoor[i].Width() / 2;
|
|
yy = m_rDoor[i].top + m_rDoor[i].Height() / 2;
|
|
|
|
PostMessage(WM_LBUTTONDOWN, 0, MAKELPARAM(xx, yy));
|
|
PostMessage(WM_LBUTTONUP, 0, MAKELPARAM(xx, yy));
|
|
} //end if m_iDoorStatus[i]...
|
|
|
|
} // end -for(i)
|
|
ReleaseDC(pDC);
|
|
(void)nFlags;
|
|
} else {
|
|
CFrameWnd::OnRButtonDown(nFlags, point);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*******************************************************************************************************************
|
|
*
|
|
* OnMCINotify
|
|
*
|
|
* FUNCTIONAL DESCRIPTION
|
|
* Handles the Window Message MM_MCINOTIFY.
|
|
* For the game it calls the CSound member func OnMCIStopped.
|
|
*
|
|
* CALLING SEQUENCE:
|
|
* Called By MFC/Windows MMSYSTEM.DLL when sound (in this case
|
|
* m_psndBkndMusic) is over.
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
* Refer to MFC doc.
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
* Refer to MFC doc.
|
|
* m_psndBkgndMusic CSound Midi Music.
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
*
|
|
* RETURN VALUE:
|
|
* Refer to MMSystem doc.
|
|
*
|
|
***********************************************************************************************************************************
|
|
*/
|
|
LRESULT CMainWindow::OnMCINotify(WPARAM wParam, LPARAM lParam) {
|
|
CSound::OnMCIStopped(wParam, lParam);
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMainWindow::OnMMIONotify(WPARAM wParam, LPARAM lParam) {
|
|
CSound::OnMMIOStopped(wParam, lParam);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*******************************************************************************************************************
|
|
*
|
|
* DeleteSprite
|
|
*
|
|
* FUNCTIONAL DESCRIPTION
|
|
* Deletes a Sprite.
|
|
*
|
|
* CALLING SEQUENCE:
|
|
* Called by OnClose() when deleting a CSprite object.
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
* pSprite CSprite The Sprite to be deleted.
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
* n/a
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
* n/a
|
|
*
|
|
* RETURN VALUE:
|
|
* void
|
|
*
|
|
***********************************************************************************************************************************
|
|
*/
|
|
void CMainWindow::DeleteSprite(CSprite *pSprite) {
|
|
CDC *pDC;
|
|
|
|
// can't delete a null pointer
|
|
assert(pSprite != nullptr);
|
|
|
|
if ((pDC = GetDC()) != nullptr) {
|
|
pSprite->EraseSprite(pDC); // erase it from screen
|
|
ReleaseDC(pDC);
|
|
}
|
|
pSprite->UnlinkSprite(); // unlink it
|
|
|
|
delete pSprite; // delete it
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainWindow::OnSysChar(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
|
|
// Terminate app on ALT_Q
|
|
if ((nChar == 'q') && (nFlags & 0x2000)) {
|
|
|
|
PostMessage(WM_CLOSE, 0, 0);
|
|
|
|
} else {
|
|
|
|
// default action
|
|
CFrameWnd ::OnSysChar(nChar, nRepCnt, nFlags);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void CMainWindow::OnSysKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
|
|
switch (nChar) {
|
|
|
|
// User has hit ALT_F4 so close down this App
|
|
//
|
|
case VK_F4:
|
|
PostMessage(WM_CLOSE, 0, 0);
|
|
break;
|
|
|
|
default:
|
|
CFrameWnd::OnSysKeyDown(nChar, nRepCnt, nFlags);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CMainWindow::OnKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
|
|
// Handle keyboard input
|
|
//
|
|
|
|
switch (nChar) {
|
|
|
|
//
|
|
// Bring up the Rules
|
|
//
|
|
case VK_F1: {
|
|
GamePause();
|
|
CSound::waitWaveSounds();
|
|
CRules RulesDlg(this, ".\\novac.txt", m_pGamePalette, \
|
|
(pGameParams->bSoundEffectsEnabled) ? GetStringFromResource(IDS_RULES_WAV) : nullptr);
|
|
RulesDlg.DoModal();
|
|
GameResume();
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Bring up the options menu
|
|
//
|
|
case VK_F2:
|
|
SendMessage(WM_COMMAND, IDC_MENU, BN_CLICKED);
|
|
break;
|
|
|
|
case 'D': //use 'd' to roll the dice; Send (do NOT Post) Messages to preserve Message Queue order.
|
|
SendMessage(WM_LBUTTONDOWN, 0, MAKELPARAM(LDIE_MIDPOINT_X, LDIE_MIDPOINT_Y));
|
|
SendMessage(WM_LBUTTONUP, 0, 0L);
|
|
break;
|
|
|
|
default: // use the NUM_KEYpad or the number keys to close/open doors.
|
|
if ((nChar >= VK_NUMPAD1) && (nChar <= VK_NUMPAD9)) nChar -= VK_NUMPAD1 - '1'; //map numpad keys to regular keys.
|
|
if ((nChar >= '1') && (nChar <= '9')) {
|
|
SendMessage(WM_LBUTTONDOWN, 0, MAKELPARAM((nChar - '1')*DOOR_SPACING + DOOR1_MIDPOINT_X, DOOR1_MIDPOINT_Y));
|
|
SendMessage(WM_LBUTTONUP, 0, 0L);
|
|
} else {
|
|
CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void CMainWindow::OnActivate(unsigned int nState, CWnd *pWndOther, bool bMinimized) {
|
|
if (!bMinimized) {
|
|
switch (nState) {
|
|
case WA_ACTIVE:
|
|
case WA_CLICKACTIVE:
|
|
InvalidateRect(nullptr, false);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
(void)pWndOther;
|
|
}
|
|
|
|
|
|
short CMainWindow::LegalizeMove(short j) {
|
|
/*
|
|
*******************************************************************************************************************
|
|
*
|
|
* LegalizeMove
|
|
*
|
|
* FUNCTIONAL DESCRIPTION
|
|
* checks if a given move is valid. A move is defined as a sequence of rolling the dice and
|
|
* opening or closing of doors. To do this, it computes the roll of the dice, sums up doors as
|
|
* they are opened or closed adding or subracting appropriately. The variable DoorSum is
|
|
* statically maintained to this end, and set to zero as soon as the dice are rolled (as indicated
|
|
* by m_bDiceJustThrown).
|
|
*
|
|
* CALLING SEQUENCE:
|
|
* short LegalizeMove(short j);
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
* j short indicates the last door cliked on by the user.
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
* m_LDie, m_RDie(if applicable) the rolls of the left and right dice.
|
|
* m_iDoorStatus[10] the open/closd/fixed status of every door just befor this func was
|
|
* called; i.e, before the door "j" was clicked on.
|
|
* m_bDiceJustThrown this flag indicates if "j" is the first door clicked upon after the dice
|
|
* were thrown.
|
|
* m_cDoorCount # of doors open at any pt of time.
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
* m_cDoorCount. Updates the count of doors open.
|
|
*
|
|
* RETURN VALUE:
|
|
* -1 if doorSum > DiceSum which implies that the player can't go anhead unless he/she opens or
|
|
* shuts doors, enough to meet the DOORSUM criterion.
|
|
* Dice can't be clicked if no possible combinations are
|
|
* available or unless the right combination is struck.
|
|
* 1 if doorSum==DiceSum which implies that the move is valid and dice can be clicked again, if desired.
|
|
*
|
|
* 0 if doorSum< DiceSum which implies that the move is in construction and could possibly be valid.
|
|
* the player can click on any door, but not on the dice.
|
|
*
|
|
* LegalizeMove keeps track of the number of open doors.
|
|
***********************************************************************************************************************************
|
|
*/
|
|
static byte DoorSum,
|
|
DiceSum;
|
|
short int ReadyForDiceClick = 0;
|
|
|
|
if (m_bDiceJustThrown) {
|
|
DoorSum = 0; // reset door sum if "j" is the first open door to be clicked upon
|
|
// ... after the dice were rolled in.
|
|
m_bDiceJustThrown = false;
|
|
}
|
|
|
|
DiceSum = (byte)(m_LDie + m_RDie);
|
|
if (m_iDoorStatus[j] == OPEN) {
|
|
//increment door count if the door is initially open (i.e. the mouse is clicked on an open door) and decrement otherwise
|
|
|
|
if ((DoorSum += (byte)j) > DiceSum) {
|
|
DoorSum -= (byte)j; // disallow clicking on such a door so as to exceed door sum.
|
|
return -1;
|
|
} else {
|
|
if (DoorSum == DiceSum) ReadyForDiceClick = 1;
|
|
if (!j) ++m_cDoorCount; //0-th door should not affect door count
|
|
return (ReadyForDiceClick); // return (1) if all set, 0 if door sum < dice sum.
|
|
}
|
|
} else { // if door is initially closed decrement doorsum.
|
|
DoorSum -= (byte)j;
|
|
if (DoorSum > DiceSum) {
|
|
DoorSum += (byte)j;
|
|
return -1;
|
|
}
|
|
if (DoorSum == DiceSum) ReadyForDiceClick = 1;
|
|
if (!j) --m_cDoorCount; //0-th door should not affect door count
|
|
return (ReadyForDiceClick);
|
|
}
|
|
}
|
|
|
|
|
|
bool CMainWindow::IsThrowDoable(byte DiceSum) {
|
|
/*****************************************************************************************************************
|
|
* [IsThrowDoable]
|
|
*
|
|
* FUNCTIONAL DESCRIPRION:
|
|
* the algo is to look at list of all the open doors just before the dice were rolled in and
|
|
* generate a set of all possible sums with an # of doors taken at a time; see if the dice
|
|
* combination just rolled in is a member of this set; if yes, the throw is doable, else not.
|
|
*
|
|
* CALLING SEQUENCE:
|
|
* bool _pascal IsThrowDoable(byte DiceSum)
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
* DiceSum is the current throw of the dice.
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
* m_iDoorStatus[10]; indicates if a door is CLOSED, OPEN or FIXED. these constants are
|
|
* defined in main.h. Once a door is FIXED, it's locked and can never be opened again.
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
* N/A
|
|
*
|
|
* RETURN VALUE:
|
|
* returns true if Throw is Doable.
|
|
* false if Undoable.
|
|
*
|
|
* ENVIRONMENT:
|
|
* n/a
|
|
****************************************************************************************************************
|
|
*/
|
|
|
|
byte s[9]; //Open doors.
|
|
byte Count, //# of open doors.
|
|
i,
|
|
k,
|
|
sum,
|
|
i1, i2, i3, i4, i5, i6, i7, i8, i9,
|
|
temp, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9;
|
|
|
|
for (i = 1, Count = 0; i < 10; i++) {
|
|
if (m_iDoorStatus[i] == OPEN) s[Count++] = i; //feeds in a list of open doors.
|
|
}
|
|
for (k = 1; k < Count + 1; k++) {
|
|
switch (k) {
|
|
case 1:
|
|
if (DiceSum < 10) if (m_iDoorStatus[DiceSum] == OPEN) return true;
|
|
break;
|
|
|
|
case 2:
|
|
for (i1 = 0; i1 < Count; i1++) {
|
|
temp = s[i1];
|
|
for (i2 = i1 + 1; i2 < Count; i2++) {
|
|
sum = temp;
|
|
sum += s[i2];
|
|
if (sum == DiceSum) return true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
for (i3 = 0; i3 < Count; i3++) {
|
|
temp3 = s[i3];
|
|
for (i2 = i3 + 1; i2 < Count; i2++) {
|
|
temp2 = temp3;
|
|
temp2 += s[i2];
|
|
for (i1 = i2 + 1; i1 < Count; i1++) {
|
|
sum = temp2;
|
|
sum += s[i1];
|
|
if (sum == DiceSum) return true;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
for (i4 = 0; i4 < Count; i4++) {
|
|
temp4 = s[i4];
|
|
for (i3 = i4 + 1; i3 < Count; i3++) {
|
|
temp3 = temp4;
|
|
temp3 += s[i3];
|
|
for (i2 = i3 + 1; i2 < Count; i2++) {
|
|
temp2 = temp3;
|
|
temp2 += s[i2];
|
|
for (i1 = i2 + 1; i1 < Count; i1++) {
|
|
sum = temp2;
|
|
sum += s[i1];
|
|
if (sum == DiceSum) return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case 5:
|
|
|
|
|
|
for (i5 = 0; i5 < Count; i5++) {
|
|
temp5 = s[i5];
|
|
for (i4 = i5 + 1; i4 < Count; i4++) {
|
|
temp4 = temp5;
|
|
temp4 += s[i4];
|
|
for (i3 = i4 + 1; i3 < Count; i3++) {
|
|
temp3 = temp4;
|
|
temp3 += s[i3];
|
|
for (i2 = i3 + 1; i2 < Count; i2++) {
|
|
temp2 = temp3;
|
|
temp2 += s[i2];
|
|
for (i1 = i2 + 1; i1 < Count; i1++) {
|
|
sum = temp2;
|
|
sum += s[i1];
|
|
if (sum == DiceSum) return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case 6:
|
|
|
|
for (i6 = 0; i6 < Count; i6++) {
|
|
temp6 = s[i6];
|
|
for (i5 = i6 + 1; i5 < Count; i5++) {
|
|
temp5 = temp6;
|
|
temp5 += s[i5];
|
|
for (i4 = i5 + 1; i4 < Count; i4++) {
|
|
temp4 = temp5;
|
|
temp4 += s[i4];
|
|
for (i3 = i4 + 1; i3 < Count; i3++) {
|
|
temp3 = temp4;
|
|
temp3 += s[i3];
|
|
for (i2 = i3 + 1; i2 < Count; i2++) {
|
|
temp2 = temp3;
|
|
temp2 += s[i2];
|
|
for (i1 = i2 + 1; i1 < Count; i1++) {
|
|
sum = temp2;
|
|
sum += s[i1];
|
|
if (sum == DiceSum) return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 7:
|
|
|
|
for (i7 = 0; i7 < Count; i7++) {
|
|
temp7 = s[i7];
|
|
for (i6 = i7 + 1; i6 < Count; i6++) {
|
|
temp6 = temp7;
|
|
temp6 += s[i6];
|
|
for (i5 = i6 + 1; i5 < Count; i5++) {
|
|
temp5 = temp6;
|
|
temp5 += s[i5];
|
|
for (i4 = i5 + 1; i4 < Count; i4++) {
|
|
temp4 = temp5;
|
|
temp4 += s[i4];
|
|
for (i3 = i4 + 1; i3 < Count; i3++) {
|
|
temp3 = temp4;
|
|
temp3 += s[i3];
|
|
for (i2 = i3 + 1; i2 < Count; i2++) {
|
|
temp2 = temp3;
|
|
temp2 += s[i2];
|
|
for (i1 = i2 + 1; i1 < Count; i1++) {
|
|
sum = temp2;
|
|
sum += s[i1];
|
|
if (sum == DiceSum) return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
for (i8 = 0; i8 < Count; i8++) {
|
|
temp8 = s[i8];
|
|
for (i7 = i8 + 1; i7 < Count; i7++) {
|
|
temp7 = temp8;
|
|
temp7 += s[i7];
|
|
for (i6 = i7 + 1; i6 < Count; i6++) {
|
|
temp6 = temp7;
|
|
temp6 += s[i6];
|
|
for (i5 = i6 + 1; i5 < Count; i5++) {
|
|
temp5 = temp6;
|
|
temp5 += s[i5];
|
|
for (i4 = i5 + 1; i4 < Count; i4++) {
|
|
temp4 = temp5;
|
|
temp4 += s[i4];
|
|
for (i4 = 0; i4 < Count; i4++) {
|
|
temp4 = s[i4];
|
|
for (i3 = i4 + 1; i3 < Count; i3++) {
|
|
temp3 = temp4;
|
|
temp3 += s[i3];
|
|
for (i2 = i3 + 1; i2 < Count; i2++) {
|
|
temp2 = temp3;
|
|
temp2 += s[i2];
|
|
for (i1 = i2 + 1; i1 < Count; i1++) {
|
|
sum = temp2;
|
|
sum += s[i1];
|
|
if (sum == DiceSum) return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 9:
|
|
for (i9 = 0; i9 < Count; i9++) {
|
|
temp9 = s[i9];
|
|
for (i8 = i9 + 1; i8 < Count; i8++) {
|
|
temp8 = temp9;
|
|
temp8 += s[i8];
|
|
for (i7 = i8 + 1; i7 < Count; i7++) {
|
|
temp7 = temp8;
|
|
temp7 += s[i7];
|
|
for (i6 = i7 + 1; i6 < Count; i6++) {
|
|
temp6 = temp7;
|
|
temp6 += s[i6];
|
|
for (i5 = i6 + 1; i5 < Count; i5++) {
|
|
temp5 = temp6;
|
|
temp5 += s[i5];
|
|
for (i4 = i5 + 1; i4 < Count; i4++) {
|
|
temp4 = temp5;
|
|
temp4 += s[i4];
|
|
for (i3 = i4 + 1; i3 < Count; i3++) {
|
|
temp3 = temp4;
|
|
temp3 += s[i3];
|
|
for (i2 = i3 + 1; i2 < Count; i2++) {
|
|
temp2 = temp3;
|
|
temp2 += s[i2];
|
|
for (i1 = i2 + 1; i1 < Count; i1++) {
|
|
sum = temp2;
|
|
sum += s[i1];
|
|
if (sum == DiceSum) return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
} //end switch(count)
|
|
}//end for -k
|
|
return false; //Undoable by default.
|
|
}
|
|
|
|
|
|
void CMainWindow::OnClose() {
|
|
CBrush cbrBlack;
|
|
CRect crectSplashScr;
|
|
CDC *pDC;
|
|
|
|
/*
|
|
if playing meta game then (re)compute score should the user choose to quit before end of play.
|
|
(if the user hits quit when the scroll is first brought up, then the score is 1+2+...+9 because all
|
|
doors are set to open in the constructor.
|
|
*/
|
|
pGameParams->lScore = 0x00L;
|
|
for (int iDoor = 1; pGameParams->bPlayingMetagame && iDoor < 10; iDoor++) {
|
|
if (m_iDoorStatus[iDoor] == OPEN) pGameParams->lScore += iDoor;
|
|
}
|
|
|
|
GameReset();
|
|
|
|
CSound::clearSounds(); //ONLY A TEST; this works.
|
|
|
|
for (int i = 0; i < 7; i++) {
|
|
if (pCLDieBmp[i]) {
|
|
delete pCLDieBmp[i]; //clear dice bmps.
|
|
pCLDieBmp[i] = nullptr;
|
|
}
|
|
if (pCRDieBmp[i]) {
|
|
delete pCRDieBmp[i];
|
|
pCRDieBmp[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// de-allocate the main menu scroll button
|
|
//
|
|
assert(m_pScrollButton != nullptr);
|
|
if (m_pScrollButton != nullptr) {
|
|
delete m_pScrollButton;
|
|
m_pScrollButton = nullptr;
|
|
}
|
|
|
|
|
|
//
|
|
// need to de-allocate the game palette
|
|
//
|
|
assert(m_pGamePalette != nullptr);
|
|
if (m_pGamePalette != nullptr) {
|
|
m_pGamePalette->DeleteObject();
|
|
delete m_pGamePalette;
|
|
m_pGamePalette = nullptr;
|
|
}
|
|
|
|
for (int i = 1; i < 10; i++) {
|
|
if (pCDoorBmp[i]) {
|
|
DeleteSprite(pCDoorBmp[i]); /* clear door sprites */
|
|
pCDoorBmp[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
/*clear dice sprites*/
|
|
if (m_pCRRollingDie) {
|
|
DeleteSprite(m_pCRRollingDie);
|
|
m_pCRRollingDie = nullptr;
|
|
}
|
|
|
|
if (m_pCLRollingDie) {
|
|
DeleteSprite(m_pCLRollingDie);
|
|
m_pCLRollingDie = nullptr;
|
|
}
|
|
|
|
if ((pDC = GetDC()) != nullptr) { // paint black screen after all's over.
|
|
crectSplashScr.SetRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
|
|
cbrBlack.CreateStockObject(BLACK_BRUSH);
|
|
pDC->FillRect(&crectSplashScr, &cbrBlack);
|
|
ReleaseDC(pDC);
|
|
}
|
|
|
|
CFrameWnd::OnClose();
|
|
|
|
MFC::PostMessage(ghParentWnd, WM_PARENTNOTIFY, WM_DESTROY, 0L);
|
|
}
|
|
|
|
|
|
//
|
|
// CMainWindow message map:
|
|
// Associate messages with member functions.
|
|
//
|
|
BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd)
|
|
ON_WM_PAINT()
|
|
ON_WM_CLOSE()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_SYSCHAR()
|
|
ON_WM_KEYDOWN()
|
|
ON_WM_SYSKEYDOWN()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_RBUTTONDOWN()
|
|
|
|
ON_MESSAGE(MM_MCINOTIFY, CMainWindow::OnMCINotify)
|
|
ON_MESSAGE(MM_WOM_DONE, CMainWindow::OnMMIONotify)
|
|
END_MESSAGE_MAP()
|
|
|
|
/*****************************************************************************************************************
|
|
* [AnimateDice]
|
|
*
|
|
* FUNCTIONAL DESCRIPRION:
|
|
* Animates dice by using cell sprites.
|
|
*
|
|
* CALLING SEQUENCE:
|
|
* void AnimateDice()
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
* none.
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
* m_pC?RollingDie, the sprite animation for ?die (?=L, R, single).
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
* N/A
|
|
*
|
|
* RETURN VALUE:
|
|
* none
|
|
*
|
|
* ENVIRONMENT:
|
|
* n/a
|
|
****************************************************************************************************************
|
|
*/
|
|
void CMainWindow::AnimateDice() {
|
|
CDC* pDC;
|
|
|
|
// Coordinates of each cel from cell strip on splash screen.
|
|
// make these static so as not to encroach upon the limited stack.
|
|
static const int16 LDieLeft[NUM_LDIE_CELS] = {234, 442, 400, 384, 365, 346, 310, 264, 242, 235, 235, 236};
|
|
static const int16 LDieTop[NUM_LDIE_CELS] = {344, 395, 340, 323, 323, 379, 372, 336, 365, 365, 347, 344};
|
|
static const int16 RDieLeft[NUM_RDIE_CELS] = {336, 595, 571, 527, 480, 442, 398, 373, 356, 341, 337};
|
|
static const int16 RDieTop[NUM_RDIE_CELS] = {345, 374, 353, 324, 334, 387, 342, 349, 376, 357, 346};
|
|
|
|
int ii;
|
|
|
|
// Coordinates of where to place dice on splash screen from cell strips.
|
|
gnLDieLeftFinal = LDieLeft[0];
|
|
gnLDieTopFinal = LDieTop[0];
|
|
gnRDieLeftFinal = RDieLeft[0];
|
|
gnRDieTopFinal = RDieTop[0];
|
|
|
|
///////// Paint sprites ////////////
|
|
pDC = GetDC();
|
|
|
|
m_pCLRollingDie->EraseSprite(pDC);
|
|
m_pCRRollingDie->EraseSprite(pDC);
|
|
|
|
if (pGameParams->bSoundEffectsEnabled)
|
|
sndPlaySound(GetStringFromResource(IDS_SHAKE), SND_ASYNC);
|
|
|
|
if (!m_bOneDieCase) {
|
|
m_pCLRollingDie->SetCel(0);
|
|
m_pCRRollingDie->SetCel(0);
|
|
|
|
m_pCLRollingDie->PaintSprite(pDC, LDieLeft[1], LDieTop[1]);
|
|
|
|
for (ii = 2; ii < NUM_LDIE_CELS ; ii++) {
|
|
m_pCLRollingDie->PaintSprite(pDC, *(LDieLeft + ii), *(LDieTop + ii));
|
|
m_pCRRollingDie->PaintSprite(pDC, *(RDieLeft + ii - 1), *(RDieTop + ii - 1));
|
|
pause();
|
|
}
|
|
|
|
if (pGameParams->bSoundEffectsEnabled) {
|
|
sndPlaySound(nullptr, 0); // kill rattle
|
|
sndPlaySound(GetStringFromResource(IDS_ROLL), SND_ASYNC); // and roll!
|
|
}
|
|
m_pCRRollingDie->SetCel(NUM_RDIE_CELS - 2); //paint LAST CEL
|
|
m_pCRRollingDie->PaintSprite(pDC, *(RDieLeft + NUM_RDIE_CELS - 1), *(RDieTop + NUM_RDIE_CELS - 1));
|
|
|
|
} else {
|
|
// The single die case...
|
|
m_pCLRollingDie->SetCel(0); /*Single*/
|
|
for (ii = 1; ii < NUM_SINGLE_DIE_CELS; ii++) {
|
|
m_pCLRollingDie->PaintSprite(pDC, *(LDieLeft + ii), *(LDieTop + ii)); /*Single*/
|
|
pause();
|
|
|
|
if (ii < NUM_SINGLE_DIE_CELS - 1) {
|
|
// Slow down animation, except for the last cel (this enables quick
|
|
// repainting of actual dice throws .)
|
|
Sleep(22);
|
|
|
|
} else if (pGameParams->bSoundEffectsEnabled) {
|
|
sndPlaySound(nullptr, 0); // kill rattle
|
|
sndPlaySound(GetStringFromResource(IDS_ROLL), SND_ASYNC); // and roll!
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
ReleaseDC(pDC);
|
|
|
|
}
|
|
|
|
|
|
/*****************************************************************************************************************
|
|
* [GetStringFromResource]
|
|
*
|
|
* FUNCTIONAL DESCRIPRION:
|
|
* Retrieves a string in a static buffer from a resource object.
|
|
*
|
|
* CALLING SEQUENCE:
|
|
* char* GetStringFromResource(unsigned int nResourceID)
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
* unsigned int nID The ID of the string resource from the resource file.
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
* static szBuffer[ ], the buffer for storing the string.
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
* N/A
|
|
*
|
|
* RETURN VALUE:
|
|
* static &szBuffer[0]
|
|
|
|
* ENVIRONMENT:
|
|
* n/a
|
|
****************************************************************************************************************
|
|
*/
|
|
|
|
char *GetStringFromResource(unsigned int nID) {
|
|
static char szBuffer[256];
|
|
|
|
if (LoadString(AfxGetResourceHandle(), nID, szBuffer, 256))
|
|
return szBuffer;
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
} // namespace NoVacancy
|
|
} // namespace HodjNPodj
|
|
} // namespace Bagel
|