1057 lines
28 KiB
C++
1057 lines
28 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/hodjnpodj/hnplibs/stdafx.h"
|
|
#include "bagel/hodjnpodj/hnplibs/gamedll.h"
|
|
#include "bagel/hodjnpodj/libs/macros.h"
|
|
#include "bagel/boflib/sound.h"
|
|
#include "bagel/boflib/misc.h"
|
|
#include "bagel/hodjnpodj/mankala/mnk.h"
|
|
#include "bagel/hodjnpodj/mankala/resource.h"
|
|
|
|
namespace Bagel {
|
|
namespace HodjNPodj {
|
|
namespace Mankala {
|
|
|
|
//#define _MACROS3
|
|
#define IDC_PITBUTTON 1
|
|
#define PITBUTTON_TIMER 2
|
|
|
|
LPGAMESTRUCT pGameParams;
|
|
extern HWND ghParentWnd;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
char m_szText[80]; // descriptive text
|
|
int m_iHeaderSize; // size of header (# bytes)
|
|
int m_iVersion; // version number
|
|
int m_iTableStones; // # stones in stored best win table
|
|
long m_lTableSize; // length of stored best win table
|
|
|
|
void CFileHeader::sync(Common::Serializer &s) {
|
|
s.syncBytes((byte *)m_szText, 80);
|
|
s.syncAsUint16LE(m_iHeaderSize);
|
|
s.syncAsUint16LE(m_iVersion);
|
|
s.syncAsUint16LE(m_iTableStones);
|
|
s.syncAsUint32LE(m_lTableSize);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// theMnkApp:
|
|
// Just creating this application object runs the whole application.
|
|
//
|
|
//CMnkApp NEAR theMnkApp ;
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/*****************************************************************
|
|
*
|
|
* CMnkWindow
|
|
*
|
|
* FUNCTIONAL DESCRIPTION:
|
|
*
|
|
* Create the window with the appropriate style, size, menu, etc. ;
|
|
* it will be later revealed by CMnkApp::InitInstance(). Then
|
|
* create our splash screen object by opening and loading its DIB.
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* n/a
|
|
*
|
|
****************************************************************/
|
|
|
|
static HCURSOR hHourGlassCursor;
|
|
extern bool gbTurnSoundsOff;
|
|
|
|
//* CMnkWindow::CMnkWindow() -- mankala window constructor function
|
|
CMnkWindow::CMnkWindow() {
|
|
CDC* pDC = nullptr ; // device context for the screen
|
|
CString xpszWndClass ;
|
|
CDibDoc *xpDibDoc = nullptr ; // pointer to the background art DIB
|
|
CSize cMySize ;
|
|
HCURSOR hOldCursor;
|
|
|
|
m_bJustStarted = true;
|
|
m_bStartGame = true ; // set flag - game just starting
|
|
m_bRulesActive = false; //flag to indicate the rules scroll is unfurled.
|
|
// this flag is set only when rules are invoked via the F1 key.
|
|
|
|
m_bPlaySound = pGameParams->bSoundEffectsEnabled;
|
|
pGameParams->lScore = 0L;
|
|
gbTurnSoundsOff = GetPrivateProfileInt("Mankala", "MuteCrab", 0, INI_FILENAME) ; // Crab talks
|
|
|
|
hHourGlassCursor = LoadCursor(nullptr, IDC_WAIT);
|
|
SetCursor(hHourGlassCursor);
|
|
hOldCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
|
|
if (pGameParams->bMusicEnabled)
|
|
m_pSound = new CSound(this, MIDI_BCKGND, SOUND_MIDI | SOUND_DONT_LOOP_TO_END);
|
|
|
|
// initialize default game options
|
|
m_iStartStones = GetPrivateProfileInt("Mankala", "StartStones", 3, INI_FILENAME) ; // 3 stones per pit
|
|
|
|
m_bComputer[1] = true ; // player 1 is computer (0 is human)
|
|
m_iTableStones = MAXTABLESTONES ;
|
|
m_bInitData = false ; // don't init table
|
|
m_iMaxDepth[0] = m_iMaxDepth[1] = 5 ; // minimax depth
|
|
m_iCapDepth[0] = m_iCapDepth[1] = 3 ; // capture depth
|
|
|
|
// *** debugging defaults
|
|
// m_bDumpPopulate = m_bDumpMoves = m_bDumpTree = true ;
|
|
// m_bInitData = true ;
|
|
// m_iTableStones = 3 ;
|
|
|
|
Common::strcpy_s(m_szDataDirectory, DATADIR) ; // data directory
|
|
// containing the bitmap files
|
|
|
|
// 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.
|
|
|
|
xpszWndClass = AfxRegisterWndClass(CS_DBLCLKS |
|
|
CS_BYTEALIGNWINDOW | CS_OWNDC,
|
|
nullptr, nullptr, nullptr) ;
|
|
|
|
|
|
xpDibDoc = new CDibDoc() ; // create an object to hold our screen
|
|
if (! xpDibDoc) {
|
|
MFC::SetCursor(hOldCursor);
|
|
MFC::MessageBox(nullptr, "Abnormal MiniGame Termination", "Internal Error", MB_ICONSTOP);
|
|
delete this;
|
|
return;
|
|
} // ... and verify we got it
|
|
|
|
if (!(*xpDibDoc).OpenDocument(".\\ART\\MANKALA.BMP")) {
|
|
MFC::SetCursor(hOldCursor);
|
|
MFC::MessageBox(nullptr, "Cannot Open Background Bitmap. Please Check for file path and/or system resources. Terminating Game", "Open Error", MB_ICONEXCLAMATION | MB_OK) ;
|
|
delete xpDibDoc;
|
|
delete this;
|
|
return;
|
|
}
|
|
|
|
// next load in the actual DIB based artwork for screen
|
|
if (!(CMnkWindow::m_xpGamePalette = (*xpDibDoc).DetachPalette())) {
|
|
// grab its palette and save it for later use
|
|
MFC::SetCursor(hOldCursor);
|
|
MFC::MessageBox(nullptr, "Cannot acquire a non nullptr Palette. Game Terminated", "Palette Error", MB_OK | MB_ICONEXCLAMATION);
|
|
delete xpDibDoc;
|
|
delete this;
|
|
return;
|
|
}
|
|
delete xpDibDoc ; // now discard the splash screen
|
|
|
|
if ((pDC = GetDC())) { // get a device context for our window
|
|
|
|
// determine where to place the game window
|
|
// ... so it is centered on the screen
|
|
#ifndef _CODEVIEW
|
|
m_cMainRect.SetRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
|
|
#else
|
|
m_cMainRect.SetRect(300, 300, 300 + GAME_WIDTH, 300 + GAME_HEIGHT);
|
|
#endif
|
|
|
|
m_cMainRect.left = (pDC->GetDeviceCaps(HORZRES) - GAME_WIDTH) >> 1 ;
|
|
m_cMainRect.top = (pDC->GetDeviceCaps(VERTRES) - GAME_HEIGHT) >> 1 ;
|
|
m_cMainRect.right = m_cMainRect.left + GAME_WIDTH ;
|
|
m_cMainRect.bottom = m_cMainRect.top + GAME_HEIGHT ;
|
|
|
|
// Create the window as a POPUP so that no borders, title, or menu are
|
|
// present ; this is because the game's background art will fill the
|
|
// entire 640x480 area.
|
|
|
|
#define WSTYLE WS_POPUP|WS_CLIPCHILDREN
|
|
|
|
pDC->SelectPalette(CMnkWindow::m_xpGamePalette, false);
|
|
pDC->RealizePalette();
|
|
ReleaseDC(pDC);
|
|
pDC = nullptr ; // zero out context pointer
|
|
} else {
|
|
return;
|
|
}
|
|
if (!Create(xpszWndClass, "Boffo Games -- Mankala", WSTYLE,
|
|
m_cMainRect, nullptr, 0)) {
|
|
MFC::MessageBox(nullptr, "Cannot open window. Close some other windows to continue", "Error", MB_ICONSTOP) ;
|
|
delete this;
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Put up the splash screen so they have somethin' to look at:
|
|
//
|
|
ShowWindow(SW_SHOWNORMAL);
|
|
PaintBitmapObject(&m_cBmpMain, BMT_MAIN) ; // paint main screen bitmap
|
|
m_cBmpScroll.m_bSprite = true ; // scroll is a sprite
|
|
PaintBitmapObject(&m_cBmpScroll, BMT_SCROLL) ;
|
|
|
|
|
|
if (!pGameParams->bPlayingMetagame) {
|
|
switch (GetPrivateProfileInt("Mankala", "StartLevel", 3, INI_FILENAME)) { // minimax algorithm is the default ...
|
|
case 0:
|
|
m_eLevel[0] = m_eLevel[1] = LEV_RANDOM;
|
|
break;
|
|
case 1:
|
|
m_eLevel[0] = m_eLevel[1] = LEV_LOWEST;
|
|
break;
|
|
case 2:
|
|
m_eLevel[0] = m_eLevel[1] = LEV_HIGHEST;
|
|
break;
|
|
default:
|
|
case 3:
|
|
m_eLevel[0] = m_eLevel[1] = LEV_EVAL;
|
|
break;
|
|
}
|
|
} else {
|
|
/* ...unless you're playing Meta Game, Levels 2,3,4 are mapped
|
|
into nSKilllevel=0,1,2 respectively, and the initial number of
|
|
stones are 3,4, 5 respectively.
|
|
*/
|
|
|
|
switch (pGameParams->nSkillLevel) {
|
|
case SKILLLEVEL_LOW:
|
|
m_iStartStones = 3;
|
|
m_eLevel[0] = m_eLevel[1] = LEV_LOWEST;
|
|
break;
|
|
case SKILLLEVEL_MEDIUM :
|
|
m_iStartStones = 4;
|
|
m_eLevel[0] = m_eLevel[1] = LEV_HIGHEST;
|
|
break;
|
|
case SKILLLEVEL_HIGH :
|
|
m_iStartStones = 5;
|
|
m_eLevel[0] = m_eLevel[1] = LEV_EVAL;
|
|
break;
|
|
default :
|
|
m_iStartStones = 3;
|
|
m_eLevel[0] = m_eLevel[1] = LEV_EVAL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
AllocatePits() ; // allocate pit objects
|
|
//CMnk::InitData() ; // initialize data tables
|
|
|
|
//otherwise test for flag before playing music.
|
|
if (pGameParams->bMusicEnabled && m_pSound) {
|
|
if (!(m_pSound->midiLoopPlaySegment(1004L, 34040L, 1004L, FMT_MILLISEC)))
|
|
MFC::MessageBox("Unable to Play Background Music", "Internal Error");
|
|
}
|
|
|
|
MFC::SetCursor(hOldCursor);
|
|
}
|
|
|
|
//* CMnkWindow::~CMnkWindow -- Mankala window destructor function
|
|
CMnkWindow::~CMnkWindow() {
|
|
}
|
|
|
|
/*****************************************************************
|
|
*
|
|
* OnPaint
|
|
*
|
|
* FUNCTIONAL DESCRIPTION:
|
|
*
|
|
* Repaint the screen whenever needed ; e.g. when uncovered by an
|
|
* overlapping window, when maximized from an icon, and when it the
|
|
* window is initially created. Ensures that the entire client area
|
|
* of the main screen window is repainted, not just the portion in the
|
|
* update region ; see PaintScreen() ;
|
|
*
|
|
* This routine is called whenever Windows sends a WM_PAINT message.
|
|
* Note that creating a CPaintDC automatically does a BeginPaint and
|
|
* an EndPaint call is done when it is destroyed at the end of this
|
|
* function. CPaintDC's constructor needs the window (this).
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* n/a
|
|
*
|
|
****************************************************************/
|
|
|
|
void CMnkWindow::OnPaint() {
|
|
PAINTSTRUCT lpPaint ;
|
|
|
|
InvalidateRect(nullptr, false) ; // invalidate the entire window
|
|
BeginPaint(&lpPaint) ; // bracket start of window update
|
|
PaintScreen() ; // repaint our window's content
|
|
EndPaint(&lpPaint) ; // bracket end of window update
|
|
}
|
|
|
|
/*****************************************************************
|
|
*
|
|
* OnCommand
|
|
*
|
|
* FUNCTIONAL DESCRIPTION:
|
|
*
|
|
* Process the QUIT and OKAY buttons when they are clicked.
|
|
*
|
|
* This function is called when a WM_COMMAND message is issued,
|
|
* typically in order to process control related activities.
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
*
|
|
* wParam identifier for the button to be processed
|
|
* lParam type of message to be processed
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* n/a
|
|
*
|
|
****************************************************************/
|
|
|
|
// OnCommand
|
|
//
|
|
|
|
bool CMnkWindow::OnCommand(WPARAM wParam, LPARAM lParam) {
|
|
|
|
if (HIWORD(lParam) == BN_CLICKED)
|
|
// only want to look at button clicks
|
|
switch (wParam) {
|
|
|
|
case IDC_SCROLL:
|
|
if (!m_bInMenu) {
|
|
OptionsDialog() ; //bring up main menu.
|
|
(*this).SetFocus() ; // Reset focus back to the main window
|
|
} //end if !m_bInMenu
|
|
break ; // ... to force a repaint
|
|
default :
|
|
break;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
*
|
|
* OnChar
|
|
*
|
|
* FUNCTIONAL DESCRIPTION:
|
|
*
|
|
....... * This function is called when keyboard input generates a character.
|
|
*
|
|
* (Add game-specific processing)
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
*
|
|
* [Show arguments]
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
*
|
|
* [External data read]
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
*
|
|
* [External data modified]
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* [Discuss return value]
|
|
*
|
|
****************************************************************/
|
|
|
|
void CMnkWindow::OnChar(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
|
|
// TODO: Add your message handler code here and/or call default
|
|
|
|
|
|
CFrameWnd ::OnChar(nChar, nRepCnt, nFlags) ; // default action
|
|
|
|
}
|
|
|
|
void CMnkWindow::OnKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
|
|
int iRVal;
|
|
|
|
if (nChar == VK_F1) {
|
|
m_bRulesActive = false;
|
|
CRules cRulesDlg(this, RULES, m_xpGamePalette, pGameParams->bSoundEffectsEnabled ? RULES_NARRATION : nullptr) ;
|
|
CSound::waitWaveSounds();
|
|
if ((iRVal = cRulesDlg.DoModal()) == -1)
|
|
MessageBox("The Mankala Rules Text File Can't Be Opened", "Error Opening File");
|
|
m_bRulesActive = false;
|
|
} else if (nChar == VK_F2) {
|
|
OptionsDialog();
|
|
} else {
|
|
CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags);
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
*
|
|
* OnSysChar
|
|
*
|
|
* FUNCTIONAL DESCRIPTION:
|
|
*
|
|
* This function is called when keyboard input generates a
|
|
* system character.
|
|
*
|
|
* (Add game-specific processing)
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
*
|
|
* [Show arguments]
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
*
|
|
* [External data read]
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
*
|
|
* [External data modified]
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* [Discuss return value]
|
|
*
|
|
****************************************************************/
|
|
|
|
void CMnkWindow::OnSysChar(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
|
|
// terminate game on ALT-Q
|
|
if ((nChar == 'q') && (nFlags & 0x2000))
|
|
PostMessage(WM_CLOSE, 0, 0) ; // same as clicking QUIT button
|
|
else
|
|
CFrameWnd ::OnSysChar(nChar, nRepCnt, nFlags) ; // default action
|
|
}
|
|
|
|
|
|
void CMnkWindow::OnSysKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
|
|
// terminate game on ALT-F4
|
|
if ((nChar == VK_F4) && (nFlags & 0x2000))
|
|
PostMessage(WM_CLOSE, 0, 0) ; // same as clicking QUIT button
|
|
else
|
|
CFrameWnd ::OnSysChar(nChar, nRepCnt, nFlags) ; // default action
|
|
|
|
}
|
|
/*****************************************************************
|
|
*
|
|
* OnXXXXXX
|
|
*
|
|
* FUNCTIONAL DESCRIPTION:
|
|
*
|
|
* These functions are called when ever the corresponding WM_
|
|
* event message is generated for the mouse.
|
|
*
|
|
* (Add game-specific processing)
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
*
|
|
* [Show arguments]
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
*
|
|
* [External data read]
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
*
|
|
* [External data modified]
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* [Discuss return value]
|
|
*
|
|
****************************************************************/
|
|
|
|
void CMnkWindow::OnMouseMove(unsigned int nFlags, CPoint point) {
|
|
MFC::SetCursor(LoadCursor(nullptr, IDC_ARROW));
|
|
|
|
static int dxCursor = GetSystemMetrics(SM_CXCURSOR); //cursor size.
|
|
static int dyCursor = GetSystemMetrics(SM_CYCURSOR);
|
|
|
|
int iPlayer = 0, iPit = 0;
|
|
bool bFound;
|
|
CDC *pDC;
|
|
CRect crctPitBounds, crctTxt;
|
|
HLOCAL hlocShells;
|
|
char *npszShells;
|
|
CBmpObject *pcBmpObject;
|
|
|
|
/*
|
|
DETERMINE the current location of the mouse visavis the pit locations
|
|
if not in the main menu (scroll down mode).
|
|
*/
|
|
for (iPlayer = 0, bFound = false; !(m_bRulesActive || m_bInMenu) && iPlayer < 2; iPlayer++) {
|
|
for (iPit = -1; !bFound && iPit < NUMPITS ; bFound || ++iPit) {
|
|
pcBmpObject = &(m_xpcPits[iPlayer][iPit + 2]->m_cBmpObject) ;
|
|
crctPitBounds = CRect(pcBmpObject->m_cPosition, pcBmpObject->m_cSize);
|
|
if (crctPitBounds.PtInRect(point))
|
|
bFound = true ;
|
|
}
|
|
if (bFound) break;
|
|
}//end for
|
|
|
|
if (bFound && (m_cCurrentMove.m_iNumStones[iPlayer][iPit + 2])) {
|
|
|
|
if ((pDC = GetDC())) {
|
|
if ((hlocShells = MFC::LocalAlloc(GHND, 16))) {
|
|
npszShells = (char *)MFC::LocalLock(hlocShells);
|
|
Common::sprintf_s(npszShells, 16, "%2d shell%c", m_cCurrentMove.m_iNumStones[iPlayer][iPit + 2], (m_cCurrentMove.m_iNumStones[iPlayer][iPit + 2] > 1) ? 's' : 0x0);
|
|
|
|
if (m_pText) {
|
|
m_pText->RestoreBackground(pDC);
|
|
delete m_pText;
|
|
m_pText = nullptr;
|
|
}
|
|
|
|
/* the following values are arrived thru trial and error */
|
|
/* "Attach" the text to the cursor */
|
|
crctTxt.SetRect(point.x + dxCursor - 20, point.y + dyCursor - 20, point.x + dxCursor + 40, point.y + dyCursor + 10);
|
|
if ((m_pText = new CText(pDC, m_xpGamePalette, &crctTxt, JUSTIFY_CENTER))) {
|
|
m_pText->DisplayString(pDC, npszShells, 20, FW_NORMAL, CTEXT_COLOR);
|
|
}
|
|
|
|
MFC::LocalUnlock(hlocShells);
|
|
MFC::LocalFree(hlocShells);
|
|
}
|
|
ReleaseDC(pDC);
|
|
pDC = nullptr;
|
|
}
|
|
} else {
|
|
|
|
if (m_pText) {
|
|
pDC = GetDC();
|
|
m_pText->RestoreBackground(pDC);
|
|
delete m_pText;
|
|
m_pText = nullptr;
|
|
ReleaseDC(pDC);
|
|
pDC = nullptr;
|
|
}
|
|
}//end if bFound&&...
|
|
|
|
|
|
CFrameWnd ::OnMouseMove(nFlags, point) ; // default action
|
|
}
|
|
|
|
|
|
void CMnkWindow::OnLButtonDown(unsigned int nFlags, CPoint point) {
|
|
CRect rectTemp;
|
|
CSprite *pSpriteGlobe, *pSpriteChair;
|
|
CDC *pDC = nullptr;
|
|
HCURSOR hOldCur;
|
|
int i;
|
|
CSound *pChairWaveSound = nullptr,
|
|
*pGlobeWaveSound = nullptr;
|
|
|
|
const POINT pointGlobeSprite = {14, 30}; // Top-Left Corner of painting Globe animation.
|
|
const POINT pointChairSprite = {202, 21}; // Top-Left Corner to paint Chair animation.
|
|
|
|
const RECT InkWell = {534, 41, 584, 66};
|
|
const RECT NetShells = {324, 20, 384, 58};
|
|
const RECT Pails = {197, 81, 246, 165};
|
|
const RECT FishHook = {118, 34, 152, 98};
|
|
const RECT ArmChair = {110, 116, 174, 209};
|
|
const RECT TrvBrch = {580, 58, 618, 157};
|
|
const RECT Globe = {15, 104, 83, 218};
|
|
const RECT Chair = {266, 64, 317, 183};
|
|
//const RECT Chair={273,103,351,180};
|
|
const RECT Wheel = {427, 75, 500, 146};
|
|
|
|
/*Delete any cText objects upon Mouse Click */
|
|
if (m_pText) {
|
|
pDC = GetDC();
|
|
m_pText->RestoreBackground(pDC);
|
|
ReleaseDC(pDC);
|
|
pDC = nullptr;
|
|
delete m_pText;
|
|
m_pText = nullptr;
|
|
}
|
|
|
|
rectTemp.SetRect(NEWGAME_LOCATION_X, NEWGAME_LOCATION_Y,
|
|
NEWGAME_LOCATION_X + NEWGAME_WIDTH,
|
|
NEWGAME_LOCATION_Y + NEWGAME_HEIGHT);
|
|
|
|
if (rectTemp.PtInRect(point)) {
|
|
if ((pGameParams->bPlayingMetagame && !bPlayedGameOnce) || (!pGameParams->bPlayingMetagame)) {
|
|
bPlayedGameOnce = true;
|
|
StartGame();
|
|
}
|
|
} else {
|
|
|
|
if (pGameParams->bSoundEffectsEnabled) {
|
|
|
|
rectTemp.SetRect(Globe.left, Globe.top, Globe.right, Globe.bottom);
|
|
if (rectTemp.PtInRect(point)) {
|
|
CSound::waitWaveSounds();
|
|
sndPlaySound(nullptr, 0);
|
|
if ((pDC = GetDC())) {
|
|
if ((pSpriteGlobe = new CSprite())) {
|
|
hOldCur = MFC::SetCursor(hHourGlassCursor);
|
|
|
|
if (pSpriteGlobe->LoadCels(pDC, GLOBE_SPRITE, 25)) {
|
|
pSpriteGlobe->SetCel(-1);
|
|
pSpriteGlobe->LinkSprite();
|
|
|
|
if (pGameParams->bSoundEffectsEnabled)
|
|
pGlobeWaveSound = new CSound(this, POP,
|
|
SOUND_WAVE | SOUND_ASYNCH | SOUND_AUTODELETE | SOUND_QUEUE);
|
|
for (i = 0; i < 25; i++) {
|
|
if (pGameParams->bSoundEffectsEnabled && i == 4) pGlobeWaveSound->play(); //begin playing sound at the 4th loop cycle, for sync.
|
|
if (!pSpriteGlobe->PaintSprite(pDC, pointGlobeSprite.x, pointGlobeSprite.y)) {
|
|
MFC::SetCursor(hOldCur);
|
|
MessageBox("Can't Conduct Animation Anymore", "Insufficient Memory");
|
|
break;
|
|
}
|
|
//MFC::Sleep(gSleepTime);
|
|
}
|
|
pSpriteGlobe->EraseSprite(pDC);
|
|
pSpriteGlobe->UnlinkSprite();
|
|
|
|
MFC::SetCursor(hOldCur);
|
|
} else {
|
|
MFC::SetCursor(hOldCur);
|
|
MessageBox("Unable to Play Animation", " Out Of Memory");
|
|
}
|
|
delete pSpriteGlobe;
|
|
}
|
|
ReleaseDC(pDC);
|
|
pDC = nullptr;
|
|
} // end if pDC
|
|
} // if rectTemp.SetRect(Globe.left,....) over.
|
|
else if ((point.x < Chair.right) && (point.x > Chair.left) && (point.y < Chair.bottom) && (point.y > Chair.top)) {
|
|
CSound::waitWaveSounds();
|
|
sndPlaySound(nullptr, 0);
|
|
if ((pDC = GetDC())) {
|
|
if ((pSpriteChair = new CSprite())) {
|
|
hOldCur = MFC::SetCursor(hHourGlassCursor);
|
|
if (pSpriteChair->LoadCels(pDC, CHAIR_SPRITE, 25)) {
|
|
pSpriteChair->SetCel(-1);
|
|
pSpriteChair->LinkSprite();
|
|
|
|
if (pGameParams->bSoundEffectsEnabled) {
|
|
pChairWaveSound = new CSound(this, HONK, SOUND_WAVE | SOUND_ASYNCH | SOUND_AUTODELETE | SOUND_QUEUE);
|
|
// pChairWaveSound->play();
|
|
}
|
|
for (i = 0; i < 25; i++) {
|
|
if (pGameParams->bSoundEffectsEnabled && i == 7) pChairWaveSound->play(); //begin playing sound at the 4th loop cycle, for sync.
|
|
if (!pSpriteChair->PaintSprite(pDC, pointChairSprite.x, pointChairSprite.y)) {
|
|
MFC::SetCursor(hOldCur);
|
|
MessageBox("Can't paint anymore animation", "Insufficient Memory");
|
|
break;
|
|
}
|
|
MFC::Sleep(110); //10);
|
|
}
|
|
pSpriteChair->EraseSprite(pDC);
|
|
pSpriteChair->UnlinkSprite();
|
|
} else {
|
|
MFC::SetCursor(hOldCur);
|
|
MessageBox("Unable To Play Animation", "Insufficient Memory");
|
|
}//end if pSpriteChair->LoadCels...
|
|
MFC::SetCursor(hOldCur);
|
|
delete pSpriteChair;
|
|
}//end if pSpriteChair=new...
|
|
ReleaseDC(pDC);
|
|
pDC = nullptr;
|
|
} // end if pDC
|
|
} else { // elseif (point.x <Chair.right....) over.
|
|
if (pGameParams->bSoundEffectsEnabled) { // play EasterEggs only if sounds enabled
|
|
rectTemp.SetRect(InkWell.left, InkWell.top, InkWell.right, InkWell.bottom);
|
|
if (rectTemp.PtInRect(point))
|
|
sndPlaySound(INK, SND_ASYNC);
|
|
|
|
rectTemp.SetRect(Wheel.left, Wheel.top, Wheel.right, Wheel.bottom);
|
|
if (rectTemp.PtInRect(point))
|
|
sndPlaySound(WHEEL, SND_ASYNC);
|
|
|
|
rectTemp.SetRect(NetShells.left, NetShells.top, NetShells.right, NetShells.bottom);
|
|
if (rectTemp.PtInRect(point))
|
|
sndPlaySound(NETSHELL, SND_ASYNC);
|
|
|
|
rectTemp.SetRect(Pails.left, Pails.top, Pails.right, Pails.bottom);
|
|
if (rectTemp.PtInRect(point))
|
|
sndPlaySound(PAILS, SND_ASYNC);
|
|
|
|
rectTemp.SetRect(FishHook.left, FishHook.top, FishHook.right, FishHook.bottom);
|
|
if (rectTemp.PtInRect(point))
|
|
sndPlaySound(FISHHOOK, SND_ASYNC);
|
|
|
|
rectTemp.SetRect(ArmChair.left, ArmChair.top, ArmChair.right, ArmChair.bottom);
|
|
if (rectTemp.PtInRect(point))
|
|
sndPlaySound(ARMCHAIR, SND_ASYNC);
|
|
|
|
rectTemp.SetRect(TrvBrch.left, TrvBrch.top, TrvBrch.right, TrvBrch.bottom);
|
|
if (rectTemp.PtInRect(point))
|
|
sndPlaySound(BROCHURE, SND_ASYNC);
|
|
}//end if pGameParams->...
|
|
}// end else .... rectTemp block.
|
|
}//END if pGameParams->bsoundEffectsEnabled
|
|
} // end else .
|
|
}
|
|
|
|
|
|
void CMnkWindow::OnLButtonUp(unsigned int nFlags, CPoint point) {
|
|
|
|
CDC *pDC = nullptr;
|
|
|
|
/*Delete any cText objects upon Mouse Click */
|
|
if (m_pText) {
|
|
if ((pDC = GetDC())) {
|
|
m_pText->RestoreBackground(pDC);
|
|
ReleaseDC(pDC);
|
|
pDC = nullptr;
|
|
delete m_pText;
|
|
m_pText = nullptr;
|
|
}//end if pDC.
|
|
}
|
|
|
|
|
|
|
|
// insert mouse button processing code here
|
|
if (nFlags & (MK_CONTROL | MK_SHIFT | MK_RBUTTON))
|
|
// if control key, shift key, or right button down
|
|
; // ignore the click
|
|
else {
|
|
|
|
|
|
#ifdef _DEMO
|
|
#define TOGGLE(x) ((x)=!(x))
|
|
CMove* xpcMove = &m_cCurrentMove;
|
|
int iPitToStartWith;
|
|
|
|
xpcMove->m_iPlayer = 0; //start from the human side.
|
|
|
|
UpdateWindow();
|
|
|
|
do {
|
|
while (!m_bGameOver && !m_bComputer[xpcMove->m_iPlayer] && !(CMnk *)this->SearchMove(xpcMove, iPitToStartWith)) {
|
|
(CMnk*)this->Move((CPit*)(m_xpcPits[xpcMove->m_iPlayer][iPitToStartWith + 2]));
|
|
SetCrabSign(false);
|
|
}
|
|
while (!m_bGameOver && m_bComputer[xpcMove->m_iPlayer] && !(CMnk *)this->SearchMove(xpcMove, iPitToStartWith)) {
|
|
(CMnk*)this->Move((CPit*)(m_xpcPits[xpcMove->m_iPlayer][iPitToStartWith + 2]));
|
|
SetCrabSign(true);
|
|
}
|
|
} while (!m_bGameOver);
|
|
#endif //_DEMO
|
|
|
|
|
|
AcceptClick(point) ; // process the mouse click
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void CMnkWindow::OnLButtonDblClk(unsigned int nFlags, CPoint point) {
|
|
// insert mouse button processing code here
|
|
}
|
|
|
|
|
|
void CMnkWindow::OnMButtonDown(unsigned int nFlags, CPoint point) {
|
|
// insert mouse button processing code here
|
|
}
|
|
|
|
|
|
void CMnkWindow::OnMButtonUp(unsigned int nFlags, CPoint point) {
|
|
// insert mouse button processing code here
|
|
}
|
|
|
|
|
|
void CMnkWindow::OnMButtonDblClk(unsigned int nFlags, CPoint point) {
|
|
// insert mouse button processing code here
|
|
}
|
|
|
|
|
|
void CMnkWindow::OnRButtonDown(unsigned int nFlags, CPoint point) {
|
|
if (nFlags & MK_CONTROL) {
|
|
gbTurnSoundsOff = !gbTurnSoundsOff; //F12 is pressed, toggle sounds ON/OFF.
|
|
WritePrivateProfileString("Mankala", "MuteCrab", gbTurnSoundsOff ? "1" : "0", INI_FILENAME);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void CMnkWindow::OnRButtonUp(unsigned int nFlags, CPoint point) {
|
|
|
|
}
|
|
|
|
void CMnkWindow::OnRButtonDblClk(unsigned int nFlags, CPoint point) {
|
|
// insert mouse button processing code here
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************
|
|
*
|
|
* OnTimer
|
|
*
|
|
* FUNCTIONAL DESCRIPTION:
|
|
*
|
|
* Update sprite positions on the screen ; this is cyclic based on
|
|
* the interval specified when the timer was initiated.
|
|
*
|
|
* This function is called when ever the interval timer generates
|
|
* an event message ; i.e. the timer fires.
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
*
|
|
* nIDEvent identifies the particular timer that fired
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* n/a
|
|
*
|
|
****************************************************************/
|
|
|
|
void CMnkWindow::OnTimer(uintptr nIDEvent) {
|
|
// CDC *m_xpcDC ;
|
|
|
|
|
|
if (nIDEvent == PITBUTTON_TIMER) {
|
|
PostMessage(WM_RBUTTONUP, 0, 0L);
|
|
MFC::KillTimer(this->m_hWnd, nIDEvent);
|
|
} else {
|
|
CFrameWnd::OnTimer(nIDEvent) ;
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
*
|
|
* OnClose
|
|
*
|
|
* FUNCTIONAL DESCRIPTION:
|
|
*
|
|
* This function is called when a Close event is generated. For
|
|
* this sample application we need only kill our event timer ;
|
|
* The ExitInstance will handle releasing resources.
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* n/a
|
|
*
|
|
****************************************************************/
|
|
|
|
void CMnkWindow::OnClose() {
|
|
CBrush Brush;
|
|
CDC *pDC = nullptr;
|
|
CRect rctTmp;
|
|
char *npszTmp;
|
|
HLOCAL hlocTmp;
|
|
int level;
|
|
|
|
KillTimer(SPRITE_TIMER) ;
|
|
|
|
if ((pDC = GetDC())) { // paint black
|
|
if (Brush.CreateStockObject(BLACK_BRUSH)) {
|
|
rctTmp.SetRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
|
|
pDC->FillRect(&rctTmp, &Brush);
|
|
}
|
|
ReleaseDC(pDC);
|
|
pDC = nullptr;
|
|
}
|
|
|
|
hlocTmp = MFC::LocalAlloc(LHND, 16);
|
|
npszTmp = (char *)MFC::LocalLock(hlocTmp);
|
|
|
|
Common::sprintf_s(npszTmp, 16, "%d", m_iStartStones);
|
|
WritePrivateProfileString("Mankala", "StartStones", npszTmp, INI_FILENAME);
|
|
|
|
switch (m_eLevel[0]) {
|
|
case LEV_RANDOM:
|
|
level = 0;
|
|
break;
|
|
case LEV_LOWEST:
|
|
level = 1;
|
|
break;
|
|
case LEV_HIGHEST:
|
|
level = 2;
|
|
break;
|
|
default:
|
|
case LEV_EVAL:
|
|
level = 3;
|
|
break;
|
|
}
|
|
Common::sprintf_s(npszTmp, 16, "%d", level);
|
|
WritePrivateProfileString("Mankala", "StartLevel", npszTmp, INI_FILENAME);
|
|
|
|
MFC::LocalUnlock(hlocTmp);
|
|
MFC::LocalFree(hlocTmp);
|
|
|
|
if (m_xpGamePalette != nullptr) {
|
|
m_xpGamePalette->DeleteObject();
|
|
delete m_xpGamePalette;
|
|
m_xpGamePalette = nullptr;
|
|
}
|
|
|
|
if (m_pText) {
|
|
delete (m_pText);
|
|
m_pText = nullptr;
|
|
}
|
|
|
|
ReleaseResources() ; // release game specific resources
|
|
|
|
CFrameWnd ::OnClose() ;
|
|
|
|
MFC::PostMessage(ghParentWnd, WM_PARENTNOTIFY, WM_DESTROY, MAKELPARAM(m_hWnd, 0));
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
*
|
|
* InitInstance
|
|
*
|
|
* FUNCTIONAL DESCRIPTION:
|
|
*
|
|
* This routine is automatically called when the application is
|
|
* started.
|
|
*
|
|
* FORMAL PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* IMPLICIT INPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* IMPLICIT OUTPUT PARAMETERS:
|
|
*
|
|
* n/a
|
|
*
|
|
* RETURN VALUE:
|
|
*
|
|
* bool Success (true) / Failure (false) status
|
|
*
|
|
****************************************************************/
|
|
/*
|
|
bool CMnkApp::InitInstance()
|
|
{
|
|
CMnkWindow *pMyMain ;
|
|
|
|
SetDialogBkColor() ; // hook gray dialogs (was default in MFC V1)
|
|
|
|
m_pMainWnd = pMyMain = m_xpcMnkWindow = new CMnkWindow() ;
|
|
// make the main window visible
|
|
m_pMainWnd->ShowWindow( m_nCmdShow ) ;
|
|
m_pMainWnd->UpdateWindow() ;
|
|
|
|
return(true) ;
|
|
}
|
|
*/
|
|
|
|
inline void FlushMouseMessages(HWND hWnd) {
|
|
MSG msg;
|
|
// find and remove all mouse events
|
|
while (PeekMessage(&msg, hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE));
|
|
}
|
|
|
|
|
|
LRESULT CMnkWindow::OnMCINotify(WPARAM wParam, LPARAM lParam) {
|
|
//CSound* pSnd;
|
|
|
|
CSound::OnMCIStopped(wParam, lParam);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CMnkWindow::OnMMIONotify(WPARAM wParam, LPARAM lParam) {
|
|
//CSound* pSnd;
|
|
|
|
CSound::OnMMIOStopped(wParam, lParam);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// CMnkWindow message map:
|
|
// Associate messages with member functions.
|
|
//
|
|
BEGIN_MESSAGE_MAP(CMnkWindow, CFrameWnd)
|
|
//{{AFX_MSG_MAP( CMnkWindow )
|
|
ON_WM_PAINT()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_LBUTTONDBLCLK()
|
|
ON_WM_MBUTTONDOWN()
|
|
ON_WM_MBUTTONUP()
|
|
ON_WM_MBUTTONDBLCLK()
|
|
ON_WM_RBUTTONDOWN()
|
|
ON_WM_RBUTTONUP()
|
|
ON_WM_RBUTTONDBLCLK()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_CHAR()
|
|
ON_WM_SYSCHAR()
|
|
ON_WM_TIMER()
|
|
ON_WM_CLOSE()
|
|
ON_WM_SYSKEYDOWN()
|
|
ON_WM_KEYDOWN()
|
|
ON_MESSAGE(MM_MCINOTIFY, CMnkWindow::OnMCINotify)
|
|
ON_MESSAGE(MM_WOM_DONE, CMnkWindow::OnMMIONotify)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
} // namespace Mankala
|
|
} // namespace HodjNPodj
|
|
} // namespace Bagel
|