/* 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/cmessbox.h"
#include "bagel/boflib/misc.h"
#include "bagel/hodjnpodj/peggle/resource.h"
#include "bagel/hodjnpodj/hnplibs/gamedll.h"
#include "bagel/hodjnpodj/hnplibs/dibdoc.h"
#include "bagel/hodjnpodj/hnplibs/sprite.h"
#include "bagel/hodjnpodj/globals.h"
#include "bagel/hodjnpodj/peggle/game.h"
#include "bagel/hodjnpodj/peggle/game2.h"
#include "bagel/hodjnpodj/peggle/options.h"
#include "bagel/hodjnpodj/hnplibs/rules.h"
#include "bagel/hodjnpodj/hnplibs/button.h"
#include "bagel/boflib/sound.h"
#include "bagel/hodjnpodj/hodjnpodj.h"

namespace Bagel {
namespace HodjNPodj {
namespace Peggle {

#define SHOW_CURSOR true


// Board definitions:

static const int8 Board_Triangle[GRID_SIZE][GRID_SIZE] = {
	{PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, NO_HOLE, NO_HOLE},
	{PEGGED, EMPTY, PEGGED, PEGGED, NO_HOLE, NO_HOLE, NO_HOLE},
	{PEGGED, PEGGED, PEGGED, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE},
	{PEGGED, PEGGED, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE},
	{PEGGED, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE},
	{NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE},
	{NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE},
};
static const int8 Board_TrianglePlus[GRID_SIZE][GRID_SIZE] = {
	{NO_HOLE, PEGGED, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, PEGGED},
	{PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED},
	{NO_HOLE, PEGGED, EMPTY, PEGGED, PEGGED, NO_HOLE, NO_HOLE},
	{NO_HOLE, PEGGED, PEGGED, PEGGED, NO_HOLE, NO_HOLE, NO_HOLE},
	{NO_HOLE, PEGGED, PEGGED, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE},
	{NO_HOLE, PEGGED, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE},
	{PEGGED, PEGGED, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE, NO_HOLE},
};
static const int8 Board_CrossPlus[GRID_SIZE][GRID_SIZE] = {
	{NO_HOLE, NO_HOLE, PEGGED, PEGGED, PEGGED, NO_HOLE, NO_HOLE},
	{NO_HOLE, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, NO_HOLE},
	{PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED},
	{PEGGED, PEGGED, PEGGED, EMPTY, PEGGED, PEGGED, PEGGED},
	{PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED},
	{NO_HOLE, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, NO_HOLE},
	{NO_HOLE, NO_HOLE, PEGGED, PEGGED, PEGGED, NO_HOLE, NO_HOLE},
};
static const int8 Board_Cross[GRID_SIZE][GRID_SIZE] = {
	{NO_HOLE, NO_HOLE, PEGGED, PEGGED, PEGGED, NO_HOLE, NO_HOLE},
	{NO_HOLE, NO_HOLE, PEGGED, PEGGED, PEGGED, NO_HOLE, NO_HOLE},
	{PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED},
	{PEGGED, PEGGED, PEGGED, EMPTY, PEGGED, PEGGED, PEGGED},
	{PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED, PEGGED},
	{NO_HOLE, NO_HOLE, PEGGED, PEGGED, PEGGED, NO_HOLE, NO_HOLE},
	{NO_HOLE, NO_HOLE, PEGGED, PEGGED, PEGGED, NO_HOLE, NO_HOLE},
};


extern  LPGAMESTRUCT    pGameInfo;

void setup_cursor();
void set_wait_cursor();
void reset_wait_cursor();

CBmpButton  *pScrollButton = nullptr;

int             sprite_count = 0,
                counter = 0 ;

CPalette        *pGamePalette = nullptr ;
static CSound   *pGameSound = nullptr;                 // Game theme song

// Board Selection stuff
bool bRandomBoard = false;

int8 BoardSelected = CROSS;

//static char MaxPegs[2][4] = {
//	{CROSS, CROSS_PLUS, TRIANGLE,   TRIANGLE_PLUS},
//	{32,    36,         14,         20},
//} ;
char fState [GRID_SIZE][GRID_SIZE];
const char *BoardSpec[BOARD_COUNT] = {
	".\\ART\\CROSS.BMP",
	".\\ART\\CROSSX.BMP",
	".\\ART\\TRIANGLE.BMP",
	".\\ART\\TRIANGLX.BMP"
};

// Move co-ordinates. 1 peg can be removed per move.
static POINT Moves[70];

CSprite *pCursorSprite = nullptr;

CSprite *pShotGlass = nullptr;
CSprite *pTableSlot = nullptr;
CSprite *pInvalidSlot = nullptr;

static int nBoard_DX = TRI_BOARD_DX,
           nBoard_DY = TRI_BOARD_DY;

static bool bIgnoreScroll = false;
static bool bPegMoving = false;

/////////////////////////////////////////////////////////////////////////////

// CMainWindow constructor:
// Create the window with the appropriate style, size, menu, etc.;
// it will be later revealed by CTheApp::InitInstance().  Then
// create our splash screen object by opening and loading its DIB.
//
CMainWindow::CMainWindow(HWND hCallingApp) {
	CString WndClass;
	CDC     *pDC;
	CPalette    *pPalOld;
	CDibDoc *pDibDoc;
	CRect   MainRect;
	bool    bSuccess;


	BeginWaitCursor();
	initStatics();

	m_hCallAppWnd = hCallingApp;

// select a type!
// 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);

// Center our window on the screen

	pDC = GetDC();
	MainRect.left = (pDC->GetDeviceCaps(HORZRES) - GAME_WIDTH) >> 1;
	MainRect.top = (pDC->GetDeviceCaps(VERTRES) - GAME_HEIGHT) >> 1;
	MainRect.right = MainRect.left + GAME_WIDTH;
	MainRect.bottom = MainRect.top + GAME_HEIGHT;
	ReleaseDC(pDC);

//MainRect.SetRect(10,10,GAME_WIDTH + 10,GAME_HEIGHT + 10);

// 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 640x40 area.
	Create(WndClass, "Boffo Games -- Peggleboz", WS_POPUP, MainRect, nullptr, 0);

	SplashScreen();

	setup_cursor();

// Acquire the shared palete for our game from the splash screen art
	pDibDoc = new CDibDoc();
	bSuccess = (*pDibDoc).OpenDocument(BoardSpec[BoardSelected - BOARD_BASE]);
	ASSERT(bSuccess);

	pGamePalette = (*pDibDoc).DetachPalette();
	delete pDibDoc;

	pDC = GetDC();
	pPalOld = (*pDC).SelectPalette(pGamePalette, false);

	pScrollButton = new CBmpButton;             // build a bitmapped OKAY button for resetting
	ASSERT(pScrollButton);                            // ... the sprites, again as an example
	ScrollRect.SetRect(SCROLL_BUTTON_X,
	                   SCROLL_BUTTON_Y,
	                   SCROLL_BUTTON_X + SCROLL_BUTTON_DX - 1,
	                   SCROLL_BUTTON_Y + SCROLL_BUTTON_DY - 1);
	bSuccess = (*pScrollButton).Create(nullptr, BS_OWNERDRAW | WS_CHILD | WS_VISIBLE, ScrollRect, this, IDC_SCROLL);
	ASSERT(bSuccess);
	bSuccess = (*pScrollButton).LoadBitmaps("SCROLLUP", "SCROLLDOWN", "SCROLLFOCUS", "SCROLLDISABLED");
	ASSERT(bSuccess);

	pShotGlass = new CSprite;

	(*pShotGlass).SharePalette(pGamePalette);
	bSuccess = (*pShotGlass).LoadResourceSprite(pDC, "SHOTGLASS");
	ASSERT(bSuccess);
	(*pShotGlass).SetMasked(true);
	(*pShotGlass).SetMobile(true);
	(*pShotGlass).SetTypeCode(SPRITE_GLASS);

	pTableSlot = new CSprite;

	(*pTableSlot).SharePalette(pGamePalette);
	bSuccess = (*pTableSlot).LoadResourceSprite(pDC, "TABLESLOT");
	ASSERT(bSuccess);
	(*pTableSlot).SetMasked(true);
	(*pTableSlot).SetMobile(true);
	(*pTableSlot).SetTypeCode(SPRITE_HOLE);

	pInvalidSlot = new CSprite;

	(*pInvalidSlot).SharePalette(pGamePalette);
	bSuccess = (*pInvalidSlot).LoadResourceSprite(pDC, "INVALIDSLOT");
	ASSERT(bSuccess);
	(*pInvalidSlot).SetMasked(true);
	(*pInvalidSlot).SetMobile(true);
	(*pInvalidSlot).SetTypeCode(SPRITE_INVALID);

	pCursorSprite = new CSprite;

	(*pCursorSprite).SharePalette(pGamePalette);
	bSuccess = (*pCursorSprite).LoadResourceSprite(pDC, "SHOTGLASS");
	ASSERT(bSuccess);
	(*pCursorSprite).SetMasked(true);
	(*pCursorSprite).SetMobile(true);

	//srand((unsigned)time(nullptr));

	if ((*pGameInfo).bPlayingMetagame)
		bRandomBoard = true;
//		BoardSelected = (brand() % BOARD_COUNT) + BOARD_BASE;

	SetUpBoard(pDC);

	(*pDC).SelectPalette(pPalOld, false);
	ReleaseDC(pDC);

	if ((*pGameInfo).bMusicEnabled) {
		if ((pGameSound = new CSound(this, GAME_THEME,
		                            SOUND_MIDI | SOUND_LOOP | SOUND_DONT_LOOP_TO_END))) {
			(*pGameSound).midiLoopPlaySegment(1000, 30000, 0, FMT_MILLISEC);
		} // end if pGameSound
	}

	if ((*pGameInfo).bPlayingMetagame == false) {
		PostMessage(WM_COMMAND, IDC_SCROLL, BN_CLICKED);
	}

	#ifndef SHOW_CURSOR
	::ShowCursor(false);
	#endif
	EndWaitCursor();
}

void CMainWindow::initStatics() {
	pScrollButton = nullptr;
	sprite_count = counter = 0;
	pGamePalette = nullptr;
	pGameSound = nullptr;

	bRandomBoard = false;
	BoardSelected = g_engine->isDemo() ? TRIANGLE_PLUS : CROSS;
	Common::fill(&fState[0][0], &fState[0][0] + GRID_SIZE * GRID_SIZE, 0);

	for (POINT &pt : Moves)
		pt.x = pt.y = 0;

	pCursorSprite = nullptr;
	pShotGlass = nullptr;
	pTableSlot = nullptr;
	pInvalidSlot = nullptr;

	nBoard_DX = TRI_BOARD_DX;
	nBoard_DY = TRI_BOARD_DY;

	bIgnoreScroll = false;
	bPegMoving = false;
}

void CMainWindow::OnActivateApp(bool bActive, HTASK hTask) {
	m_bProgramActive = bActive;
}


// OnPaint:
// This 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).
//
void CMainWindow::OnPaint() {
	PAINTSTRUCT lpPaint;

	InvalidateRect(nullptr, false);
	BeginPaint(&lpPaint);
	SplashScreen();
	EndPaint(&lpPaint);
}


// Paint the background art (splash screen) in the client area;
// called by both OnPaint and InitInstance.
void CMainWindow::SplashScreen() {
	CRect   rcDest;
	CRect   rcDIB;
	CDC     *pDC;
	CDibDoc myDoc;
	HDIB    hDIB;
	CSprite *pSprite;
	bool    bSuccess;

	bSuccess = myDoc.OpenDocument(BoardSpec[BoardSelected - BOARD_BASE]);
	ASSERT(bSuccess);
	hDIB = myDoc.GetHDIB();

	pDC = GetDC();
	if (pDC && hDIB) {
		GetClientRect(rcDest);

		int cxDIB = (int) DIBWidth(hDIB);
		int cyDIB = (int) DIBHeight(hDIB);

		rcDIB.top = rcDIB.left = 0;
		rcDIB.right = cxDIB;
		rcDIB.bottom = cyDIB;
		PaintDIB((*pDC).m_hDC, &rcDest, hDIB, &rcDIB, pGamePalette);
	}

	pSprite = CSprite::GetSpriteChain();
	while (pSprite) {
		(*pSprite).ClearBackground();
		bSuccess = (*pSprite).RefreshSprite(pDC);
		ASSERT(bSuccess);
		pSprite = (*pSprite).GetNextSprite();
	}

	ReleaseDC(pDC);
}


void SetUpBoard(CDC *pDC) {
	int     i, j;
	CSprite *pNewSprite;
	CPoint  cPoint;

	CSprite::EraseSprites(pDC);
	CSprite::FlushSpriteChain();

	if (bRandomBoard)                                           // want a random board selected
		BoardSelected = (brand() % BOARD_COUNT) + BOARD_BASE;

	switch (BoardSelected) {
	case CROSS_PLUS:
		nBoard_DX = CROSS_PLUS_BOARD_DX;
		nBoard_DY = CROSS_PLUS_BOARD_DY;
		for (i = 0; i < GRID_SIZE; i++) {
			for (j = 0; j < GRID_SIZE; j++) {
				fState [i][j] = Board_CrossPlus [i][j] ;
			}
		}
		break ;
	case CROSS:
		nBoard_DX = CROSS_BOARD_DX;
		nBoard_DY = CROSS_BOARD_DY;
		for (i = 0; i < GRID_SIZE; i++) {
			for (j = 0; j < GRID_SIZE; j++) {
				fState [i][j] = Board_Cross [i][j] ;
			}
		}
		break ;
	case TRIANGLE:
		nBoard_DX = TRI_BOARD_DX;
		nBoard_DY = TRI_BOARD_DY;
		for (i = 0; i < GRID_SIZE; i++) {
			for (j = 0; j < GRID_SIZE; j++) {
				fState [i][j] = Board_Triangle [i][j] ;
			}
		}
		break ;
	case TRIANGLE_PLUS:
		nBoard_DX = TRI_PLUS_BOARD_DX;
		nBoard_DY = TRI_PLUS_BOARD_DY;
		for (i = 0; i < GRID_SIZE; i++) {
			for (j = 0; j < GRID_SIZE; j++) {
				fState [i][j] = Board_TrianglePlus [i][j] ;
			}
		}
		break ;
	}

	for (j = 0; j < GRID_SIZE; j++) {
		for (i = 0; i < GRID_SIZE; i++) {
			pNewSprite = nullptr;
			if (fState[i][j] == PEGGED)
				pNewSprite = (*pShotGlass).DuplicateSprite(pDC);
			else if (fState[i][j] == EMPTY)
				pNewSprite = (*pTableSlot).DuplicateSprite(pDC);
			else
//		if ((fState[i][j] == NO_HOLE) && ((BoardSelected == CROSS) || (BoardSelected == CROSS_PLUS)))
				pNewSprite = (*pInvalidSlot).DuplicateSprite(pDC);
			ASSERT(pNewSprite != nullptr);
			cPoint = CMainWindow::GridToPoint(i, j);
			if ((*pNewSprite).GetTypeCode() == SPRITE_HOLE)
				cPoint.x -= (SPRITE_SIZE_DX >> 1);
			(*pNewSprite).SetPosition(cPoint);
			(*pNewSprite).LinkSprite();
		}
	}

	pNewSprite = nullptr;

	counter = 0;

}

/////////////////////////////////////////////////////////////////////////////
//
// Process messages and controls
//
/////////////////////////////////////////////////////////////////////////////

// OnCommand
// This function is called when a WM_COMMAND message is issued,
// typically in order to process control related activities.
//

bool CMainWindow::OnCommand(WPARAM wParam, LPARAM lParam) {
	CDC         *pDC;
	CPoint      sprite_loc;
	CRules      RulesDlg((CWnd *)this, RULESSPEC, pGamePalette,
	                     ((*pGameInfo).bSoundEffectsEnabled ? NARRATIVESPEC : nullptr));
	COptions    COptionsWind((CWnd *)this, pGamePalette, IDD_OPTIONS_DIALOG) ;


	if (HIWORD(lParam) == BN_CLICKED) {

		if (counter & 0x01) {
			pDC = GetDC();
			UndoMove(pDC);
			ReleaseDC(pDC);
		}

		switch (wParam) {

		case IDC_RULES:
			bIgnoreScroll = true;
			(*pScrollButton).SendMessage(BM_SETSTATE, true, 0L);
			RulesDlg.DoModal();                          // invoke the help dialog box
			break;

		case IDC_NEWGAME:
			if (!(*pGameInfo).bPlayingMetagame) {
				pDC = GetDC();
				SetUpBoard(pDC);
				ReleaseDC(pDC);
				InvalidateRect(nullptr, false);
			}
			break;

		case IDC_SCROLL:
			if (bIgnoreScroll) {
				(*pScrollButton).SendMessage(BM_SETSTATE, true, 0L);
				break;
			}
			bIgnoreScroll = true;
			(*pScrollButton).SendMessage(BM_SETSTATE, true, 0L);
			SendDlgItemMessage(IDC_SCROLL, BM_SETSTATE, true, 0L);

			switch (COptionsWind.DoModal()) {

			case IDC_RETURN:
				(*pScrollButton).SendMessage(BM_SETSTATE, false, 0L);
				bIgnoreScroll = false;
				break;

			case IDC_RESTART:
			case IDC_NEWGAME:
				(*pScrollButton).SendMessage(BM_SETSTATE, false, 0L);
				bIgnoreScroll = false;
				pDC = GetDC();
				SetUpBoard(pDC);
				ReleaseDC(pDC);
				InvalidateRect(nullptr, false);
				break;

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

			default:
				(*pScrollButton).SendMessage(BM_SETSTATE, false, 0L);
				bIgnoreScroll = false;

			} //end switch(ComDlg.DoModal())

			if ((*pGameInfo).bMusicEnabled) {
				if (pGameSound == nullptr) {
					pGameSound = new CSound(this, GAME_THEME,
					                        SOUND_MIDI | SOUND_LOOP | SOUND_DONT_LOOP_TO_END);
					if (pGameSound != nullptr)
						(*pGameSound).midiLoopPlaySegment(6370, 33000, 0, FMT_MILLISEC);
				}
			} // end if pGameSound
			else {
				if (pGameSound != nullptr) {
					pGameSound->stop();
					delete pGameSound;
					pGameSound = nullptr;
				}
			}

		} //end switch(wParam)

	}

	(*this).SetFocus();                     // Reset focus back to the main window
	return true;
}


// OnChar and OnSysChar
// These functions are called when keyboard input generates a character.
//

void CMainWindow::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 CMainWindow::OnSysChar(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
	// TODO: Add your message handler code here and/or call default

	if ((nChar == 'q') && (nFlags & 0x2000)) {      // terminate app on ALT-q
		CSprite::FlushSpriteChain();
		PostMessage(WM_CLOSE, 0, 0);
	}                   // *** remove later ***
	else
		CFrameWnd ::OnChar(nChar, nRepCnt, nFlags); // default action
}


void CMainWindow::OnKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
	if (nChar == VK_F1) {                                  // F1 key is hit
		SendMessage(WM_COMMAND, IDC_RULES, BN_CLICKED);  // Activate the Options dialog
		(*pScrollButton).SendMessage(BM_SETSTATE, false, 0L);
		bIgnoreScroll = false;
	} else if (nChar == VK_F2) {                                 // F2 key is hit
		SendMessage(WM_COMMAND, IDC_SCROLL, BN_CLICKED);     // Activate the Options dialog
		(*pScrollButton).SendMessage(BM_SETSTATE, false, 0L);
		bIgnoreScroll = false;
	}
}


// OnMouseMove and OnButtonXXX:
// These functions are called whenever the corresponding WM_ mouse
// related message occurs.
//

void CMainWindow::OnMouseMove(unsigned int nFlags, CPoint point) {
	CDC    *pDC;
	CPoint real_loc;

	if (counter % 2) {
		real_loc.x = point.x - (SPRITE_SIZE_DX / 2);
		real_loc.y = point.y - (SPRITE_SIZE_DY / 2);
		pDC = GetDC();
		(*pCursorSprite).PaintSprite(pDC, real_loc);
		ReleaseDC(pDC);
	}

	setup_cursor();
}


void CMainWindow::OnLButtonDown(unsigned int nFlags, CPoint myPoint) {
// if you want to do click and click, just check the counter % 2
// if true, then store oldx, oldy, and first click case ("click")
// if false, then do newx, newy, and second click case ("drag")
	CSprite *pSprite;
	int score = 0;
	int num_left ;
	int moves_left = 0;
	int i, j;
	char score_string[40];
	const char *score_blurb;
	CDC     *pDC;
	CPoint  sprite_loc;
	CPoint  grid_loc;
	CSound  *pEffect = nullptr;
	int newx, newy ;
	int oldx, oldy, neighborx, neighbory;
	bool    bSuccess;
	CRect   bottleRect,
	        titleRect,
	        dartRect,
	        kegRect,
	        stoolRect,
	        netRect,
	        oarRect,
	        signRect,
	        tableRect,
	        candlenrRect,
	        candlefrRect;

	bottleRect.SetRect(BOTTLE_X, BOTTLE_Y, BOTTLE_X + BOTTLE_DX, BOTTLE_Y + BOTTLE_DY);
	titleRect.SetRect(TITLE_X, TITLE_Y, TITLE_X + TITLE_DX, TITLE_Y + TITLE_DY);
	dartRect.SetRect(EE_DART_X, EE_DART_Y, EE_DART_X + EE_DART_DX, EE_DART_Y + EE_DART_DY);
	kegRect.SetRect(KEG_X, KEG_Y, KEG_X + KEG_DX, KEG_Y + KEG_DY);
	stoolRect.SetRect(STOOL_X, STOOL_Y, STOOL_X + STOOL_DX, STOOL_Y + STOOL_DY);
	netRect.SetRect(NET_X, NET_Y, NET_X + NET_DX, NET_Y + NET_DY);
	oarRect.SetRect(OAR_X, OAR_Y, OAR_X + OAR_DX, OAR_Y + OAR_DY);
	signRect.SetRect(SIGN_X, SIGN_Y, SIGN_X + SIGN_DX, SIGN_Y + SIGN_DY);
	tableRect.SetRect(TABLE_X, TABLE_Y, TABLE_X + TABLE_DX, TABLE_Y + TABLE_DY);
	candlenrRect.SetRect(CANDLENR_X, CANDLENR_Y, CANDLENR_X + CANDLENR_DX, CANDLENR_Y + CANDLENR_DY);
	candlefrRect.SetRect(CANDLEFR_X, CANDLEFR_Y, CANDLEFR_X + CANDLEFR_DX, CANDLEFR_Y + CANDLEFR_DY);


	if (((*pGameInfo).bPlayingMetagame == false) && titleRect.PtInRect(myPoint)) {
		if (!(counter & 0x01))
			UndoTurn();
		else {
			pDC = GetDC();
			UndoMove(pDC);
			ReleaseDC(pDC);
		}
		SendMessage(WM_COMMAND, IDC_NEWGAME, BN_CLICKED);
	} else if (((*pGameInfo).bPlayingMetagame == false) && bottleRect.PtInRect(myPoint)) {
		if (!(counter & 0x01))
			UndoTurn();
		else {
			pDC = GetDC();
			UndoMove(pDC);
			ReleaseDC(pDC);
		}
	} else if (dartRect.PtInRect(myPoint)) {
		CSound::waitWaveSounds();
		sndPlaySound(nullptr, 0);
		pDC = GetDC();
		pSprite = new CSprite;
		(*pSprite).SharePalette(pGamePalette);
		bSuccess = (*pSprite).LoadCels(pDC, ".\\art\\dart.bmp", NUM_DART_CELS);
		if (!bSuccess) {
			delete pSprite;
			ReleaseDC(pDC);
			return;
		}
		(*pSprite).SetMasked(false);
		(*pSprite).SetMobile(false);

		if ((*pGameInfo).bSoundEffectsEnabled) {
			pEffect = new CSound((CWnd *)this, ".\\sound\\darts.wav",                // Load up the sound file as a
			                     SOUND_WAVE | SOUND_QUEUE | SOUND_ASYNCH | SOUND_AUTODELETE);    //...Wave file, to delete itself
		}
		for (i = 0; i < NUM_DART_CELS; i++) {
			(*pSprite).PaintSprite(pDC, DART_X, DART_Y);
			Sleep(DART_SLEEP - (i));     // * 2
			if ((i == 0) && (pEffect != nullptr)) {
				bSuccess = (*pEffect).play();                                                       //...play the narration
				if (!bSuccess)
					delete pEffect;
			}
		}
		if (pSprite != nullptr)
			delete pSprite;

		ReleaseDC(pDC);
	} else if (kegRect.PtInRect(myPoint)) {
		CSound::waitWaveSounds();
		sndPlaySound(nullptr, 0);
		pDC = GetDC();
		pSprite = new CSprite;
		(*pSprite).SharePalette(pGamePalette);
		bSuccess = (*pSprite).LoadCels(pDC, ".\\art\\keg.bmp", NUM_KEG_CELS);
		if (!bSuccess) {
			delete pSprite;
			ReleaseDC(pDC);
			return;
		}
		(*pSprite).SetMasked(false);
		(*pSprite).SetMobile(false);

		if ((*pGameInfo).bSoundEffectsEnabled) {
			pEffect = new CSound((CWnd *)this, ".\\sound\\barglass.wav",             // Load up the sound file as a
			                     SOUND_WAVE | SOUND_QUEUE | SOUND_ASYNCH | SOUND_AUTODELETE);                //...Wave file, to delete itself
		}
		if (pEffect != nullptr) {
			bSuccess = (*pEffect).play();
			if (!bSuccess)
				delete pEffect;
		}
		(*pSprite).SetCel(NUM_KEG_CELS - KEG_CEL_OFFSET);
		for (i = 0; i < NUM_KEG_CELS; i++) {
			(*pSprite).PaintSprite(pDC, KEG_X, KEG_Y);
			Sleep(KEG_SLEEP);
		}
		if (pSprite != nullptr)
			delete pSprite;

		ReleaseDC(pDC);
	} else if (stoolRect.PtInRect(myPoint)) {
		CSound::waitWaveSounds();
		sndPlaySound(nullptr, 0);
		pDC = GetDC();
		pSprite = new CSprite;
		(*pSprite).SharePalette(pGamePalette);
		bSuccess = (*pSprite).LoadCels(pDC, ".\\art\\stool.bmp", NUM_STOOL_CELS);
		if (!bSuccess) {
			delete pSprite;
			ReleaseDC(pDC);
			return;
		}
		(*pSprite).SetMasked(false);
		(*pSprite).SetMobile(false);

		if ((*pGameInfo).bSoundEffectsEnabled) {
			pEffect = new CSound((CWnd *)this, ".\\sound\\chrdance.wav",             // Load up the sound file as a
			                     SOUND_WAVE | SOUND_QUEUE |  SOUND_ASYNCH | SOUND_AUTODELETE);               //...Wave file, to delete itself
		}
		if (pEffect != nullptr) {
			bSuccess = (*pEffect).play();
			if (!bSuccess)
				delete pEffect;
		}
		for (i = 0; i < NUM_STOOL_CELS; i++) {
			(*pSprite).PaintSprite(pDC, STOOL_X, STOOL_Y);
			Sleep(STOOL_SLEEP);
		}

		delete pSprite;
		ReleaseDC(pDC);

	} else if (oarRect.PtInRect(myPoint) && (*pGameInfo).bSoundEffectsEnabled) {
		CSound::waitWaveSounds();
		sndPlaySound(nullptr, 0);
		pEffect = new CSound((CWnd *)this, OAR_SOUND,                                // Load up the sound file as a
		                     SOUND_WAVE | SOUND_QUEUE |  SOUND_ASYNCH | SOUND_AUTODELETE);   //...Wave file, to delete itself
		if (pEffect != nullptr) {
			bSuccess = (*pEffect).play();
			if (!bSuccess)
				delete pEffect;
		}
	} else if (netRect.PtInRect(myPoint) && (*pGameInfo).bSoundEffectsEnabled) {
		CSound::waitWaveSounds();
		sndPlaySound(nullptr, 0);
		pEffect = new CSound((CWnd *)this, NET_SOUND,                                // Load up the sound file as a
		                     SOUND_WAVE | SOUND_QUEUE |  SOUND_ASYNCH | SOUND_AUTODELETE);   //...Wave file, to delete itself
		if (pEffect != nullptr) {
			bSuccess = (*pEffect).play();
			if (!bSuccess)
				delete pEffect;
		}
	} else if (signRect.PtInRect(myPoint) && (*pGameInfo).bSoundEffectsEnabled) {
		CSound::waitWaveSounds();
		sndPlaySound(nullptr, 0);
		pEffect = new CSound((CWnd *)this, SIGN_SOUND,                               // Load up the sound file as a
		                     SOUND_WAVE | SOUND_QUEUE |  SOUND_ASYNCH | SOUND_AUTODELETE);   //...Wave file, to delete itself
		if (pEffect != nullptr) {
			bSuccess = (*pEffect).play();
			if (!bSuccess)
				delete pEffect;
		}
	} else if (tableRect.PtInRect(myPoint) && (*pGameInfo).bSoundEffectsEnabled) {
		CSound::waitWaveSounds();
		sndPlaySound(nullptr, 0);
		pEffect = new CSound((CWnd *)this, TABLE_SOUND,                              // Load up the sound file as a
		                     SOUND_WAVE | SOUND_QUEUE |  SOUND_ASYNCH | SOUND_AUTODELETE);   //...Wave file, to delete itself
		if (pEffect != nullptr) {
			bSuccess = (*pEffect).play();
			if (!bSuccess)
				delete pEffect;
		}
	} else if ((candlenrRect.PtInRect(myPoint) || candlefrRect.PtInRect(myPoint)) && (*pGameInfo).bSoundEffectsEnabled) {
		CSound::waitWaveSounds();
		sndPlaySound(nullptr, 0);
		pEffect = new CSound((CWnd *)this, CANDLE_SOUND,                                 // Load up the sound file as a
		                     SOUND_WAVE | SOUND_QUEUE |  SOUND_ASYNCH | SOUND_AUTODELETE);   //...Wave file, to delete itself
		if (pEffect != nullptr) {
			bSuccess = (*pEffect).play();
			if (!bSuccess)
				delete pEffect;
		}
	} else if (!(counter & 0x01)) {
		pSprite = CSprite::Touched(myPoint);
		if (pSprite != nullptr) {
			sprite_loc = (*pSprite).GetPosition();
			grid_loc = PointToGrid(sprite_loc);
			if (fState [grid_loc.x][grid_loc.y] == PEGGED) {
				counter += 1;
				Moves[counter].x = grid_loc.x;
				Moves[counter].y = grid_loc.y;
				pDC = GetDC();
				UpdatePegPosition(pDC, pTableSlot, grid_loc.x, grid_loc.y);
				if (counter % 2)
					(*pCursorSprite).PaintSprite(pDC, sprite_loc);
				ReleaseDC(pDC);
				bPegMoving = true;
			} else {             // illegal move
//			    MessageBeep(-1);
				if ((*pGameInfo).bSoundEffectsEnabled)
					sndPlaySound(nullptr, 0);
				sndPlaySound(WAV_NOMOVE, SND_ASYNC);
			}
		}
	} else { // this is the second click
		oldx = Moves[counter].x;
		oldy = Moves[counter].y;
		pSprite = CSprite::Touched(myPoint);
		if (pSprite != nullptr) {
			sprite_loc = (*pSprite).GetPosition();
			if ((*pSprite).GetTypeCode() == SPRITE_HOLE)
				sprite_loc.x += (SPRITE_SIZE_DX >> 1);
			grid_loc = PointToGrid(sprite_loc);
			newx = grid_loc.x;
			newy = grid_loc.y;
			if (fState [newx][newy] == EMPTY) {
				neighborx = ((oldx + newx) / 2);
				neighbory = ((oldy + newy) / 2);
				if ((((newx == oldx - 2) && (newy == oldy + 2)) && (BoardSelected == TRIANGLE || BoardSelected == TRIANGLE_PLUS)) ||
				        ((newx == oldx)     && (newy == oldy + 2)) ||
				        ((newx == oldx + 2) && (newy == oldy))     ||
				        ((newx == oldx - 2) && (newy == oldy))     ||
				        (((newx == oldx + 2) && (newy == oldy - 2)) && (BoardSelected == TRIANGLE || BoardSelected == TRIANGLE_PLUS)) ||
				        ((newx == oldx)     && (newy == oldy - 2))) {
					if (fState [neighborx][neighbory] == PEGGED) {
						fState [oldx][oldy] = EMPTY;
						fState [neighborx][neighbory] = EMPTY;
						fState [newx][newy] = PEGGED ;
						counter += 1;
						bPegMoving = false;
						Moves[counter].x = newx ;
						Moves[counter].y = newy ;
						pDC = GetDC();

						(*pCursorSprite).EraseSprite(pDC);

						UpdatePegPosition(pDC, pShotGlass, newx, newy);

						UpdatePegPosition(pDC, pTableSlot, neighborx, neighbory);

						ReleaseDC(pDC);

						if ((*pGameInfo).bSoundEffectsEnabled) {
							sndPlaySound(nullptr, 0);
							sndPlaySound(WAV_MOVE, SND_ASYNC);
						}

						// check for neighbors and hole after neighbors

						for (i = 0; i < GRID_SIZE; i++) {
							for (j = 0; j < GRID_SIZE; j++) {
								if (fState[i][j] == PEGGED) {
									if (((i <= 4) && (fState [i + 1][j] == PEGGED) && (fState [i + 2][j] == EMPTY)) ||
									        ((i >= 2) && (fState [i - 1][j] == PEGGED) && (fState [i - 2][j] == EMPTY)) ||
									        ((j <= 4) && (fState [i][j + 1] == PEGGED) && (fState [i][j + 2] == EMPTY)) ||
									        ((j <= 4) && (i >= 2) && (fState [i - 1][j + 1] == PEGGED) && (fState [i - 2][j + 2] == EMPTY) && (BoardSelected == TRIANGLE || BoardSelected == TRIANGLE_PLUS)) ||
									        ((i <= 4) && (j >= 2) && (fState [i + 1][j - 1] == PEGGED) && (fState [i + 2][j - 2] == EMPTY) && (BoardSelected == TRIANGLE || BoardSelected == TRIANGLE_PLUS)) ||
									        ((j >= 2) && (fState [i][j - 1] == PEGGED) && (fState [i][j - 2] == EMPTY))) {
										moves_left++;
									}
								}
							}
						}

						if (moves_left == 0) {
							// check for end conditions
							// is counter == maxmoves ?   i.e. only one peg left

							if (((counter == 62) && (BoardSelected == CROSS)) ||
							        ((counter == 70) && (BoardSelected == CROSS_PLUS)) ||
							        ((counter == 26) && (BoardSelected == TRIANGLE)) ||
							        ((counter == 38) && (BoardSelected == TRIANGLE_PLUS))) {

								// if so --> is fState [center] == PEGGED?

								if ((((BoardSelected == CROSS)      || (BoardSelected == CROSS_PLUS))       && (fState [3][3] == PEGGED)) ||
								        ((BoardSelected == TRIANGLE) && (fState [1][1] == PEGGED)) ||
								        ((BoardSelected == TRIANGLE_PLUS) && (fState [2][2] == PEGGED))) {

									// if both true, then WIN!!!!
									score = 25;
								}
								// one left but not in center
								else {
									score = 10;
								}
							}
							// else, just score...  # left = maxchips - ((counter+1)/2) .. counter starts at 0, not 1...
							num_left = (((BoardSelected == CROSS) * 64) +
							            ((BoardSelected == CROSS_PLUS) * 72) +
							            ((BoardSelected == TRIANGLE) * 28) +
							            ((BoardSelected == TRIANGLE_PLUS) * 40) -
							            counter) / 2;
							if (num_left == 2) {
								score = 5;
							} else if (num_left == 3) {
								score = 4;
							} else if (num_left == 4) {
								score = 3;
							} else if (num_left == 5) {
								score = 2;
							} else if ((num_left > 5) && (num_left < 11)) {
								score = 1;
							}
							// display the score
							// display two buttons, Quit or Again?
							#ifndef SHOW_CURSOR
							::ShowCursor(true);
							#endif

							if (score == 25) {
								if ((*pGameInfo).bSoundEffectsEnabled) {
									sndPlaySound(nullptr, 0);
									sndPlaySound(WAV_WON, SND_ASYNC);
								}
								score_blurb = "You have won!";
							} else {
								if ((*pGameInfo).bSoundEffectsEnabled) {
									sndPlaySound(nullptr, 0);
									sndPlaySound(WAV_DONE, SND_ASYNC);
								}
								score_blurb = "Game over.";
							}

							if (score == 1)
								Common::sprintf_s(score_string, "Score:  %d point.", score) ;
							else
								Common::sprintf_s(score_string, "Score:  %d points.", score) ;

							CMessageBox GameOverDlg((CWnd *)this, pGamePalette, score_blurb, score_string);
//						UpdateWindow();
//						GameOverDlg.DoModal();

							if ((*pGameInfo).bPlayingMetagame) {
								#ifndef SHOW_CURSOR
								::ShowCursor(false);
								#endif
								(*pGameInfo).lScore += score;
								PostMessage(WM_CLOSE, 0, 0);
							} else {
								pDC = GetDC();
								SetUpBoard(pDC);
								ReleaseDC(pDC);
								InvalidateRect(nullptr, false);
								// if Restart --> IDC_RESTART
//		            PostMessage(WM_COMMAND, IDC_RESTART, BN_CLICKED);
								#ifndef SHOW_CURSOR
								::ShowCursor(false);
								#endif
							}
						}

						else {
							// do nothing, it's not the last move...
						}
					} else { // Wrong move, ... must jump over a peg!!!!!
						pDC = GetDC();
						UndoMove(pDC);
						ReleaseDC(pDC);
					}
				} else {
					pDC = GetDC();
					UndoMove(pDC);
					ReleaseDC(pDC);

					// Wrong move ... must be 2 away
					// restore hole to a peg
				}
			} else {
				pDC = GetDC();
				UndoMove(pDC);
				ReleaseDC(pDC);

				// Wrong move ... must jump to a hole
				// must restore hole [old] to a peg
			}
		} else {
			counter -= 1;
//			MessageBeep(-1);
			if ((*pGameInfo).bSoundEffectsEnabled) {
				sndPlaySound(nullptr, 0);
				sndPlaySound(WAV_NOMOVE, SND_ASYNC);
			}
			pDC = GetDC();
			(*pCursorSprite).EraseSprite(pDC);

			UpdatePegPosition(pDC, pShotGlass, oldx, oldy);

			ReleaseDC(pDC);
		}
		// Wrong move ... must jump within the board
	}
}


void CMainWindow::OnLButtonUp(unsigned int nFlags, CPoint point) {
	if (bPegMoving)
		OnLButtonDown(nFlags, point);
}


void CMainWindow::OnLButtonDblClk(unsigned int nFlags, CPoint point) {
//  insert mouse button processing code here
}


void CMainWindow::OnMButtonDown(unsigned int nFlags, CPoint point) {
//  insert mouse button processing code here
}


void CMainWindow::OnMButtonUp(unsigned int nFlags, CPoint point) {
//  insert mouse button processing code here
}

void CMainWindow::OnMButtonDblClk(unsigned int nFlags, CPoint point) {
//  insert mouse button processing code here
}


void CMainWindow::OnRButtonDown(unsigned int nFlags, CPoint point) {
//  insert mouse button processing code here
}


void CMainWindow::OnRButtonUp(unsigned int nFlags, CPoint point) {
//  insert mouse button processing code here
}

void CMainWindow::OnRButtonDblClk(unsigned int nFlags, CPoint point) {
//  insert mouse button processing code here
}

//////////// Additional Sound Notify routines //////////////

LRESULT CMainWindow::OnMCINotify(WPARAM wParam, LPARAM lParam) {
	CSound  *pSound;

	pSound = CSound::OnMCIStopped(wParam, lParam);
	if (pSound != nullptr)
		OnSoundNotify(pSound);
	return 0;
}


LRESULT CMainWindow::OnMMIONotify(WPARAM wParam, LPARAM lParam) {
	CSound  *pSound;

	pSound = CSound::OnMMIOStopped(wParam, lParam);
	if (pSound != nullptr)
		OnSoundNotify(pSound);
	return 0;
}

void CMainWindow::OnSoundNotify(CSound *pSound) {
	//
	// Add your code to process explicit notification of a sound "done" event here.
	// pSound is a pointer to a CSound object for which you requested SOUND_NOTIFY.
	//
}



void CMainWindow::UpdatePegPosition(CDC *pDC, CSprite *pBaseSprite, int x, int y) {
	CSprite *pSprite;
	CPoint  sprite_loc,
	        hotspot_loc;

	sprite_loc = GridToPoint(x, y);
	hotspot_loc.x = sprite_loc.x + (SPRITE_SIZE_DX / 2);
	hotspot_loc.y = sprite_loc.y + (SPRITE_SIZE_DY / 2);
	pSprite = CSprite::Touched(hotspot_loc);
	ASSERT(pSprite != nullptr);
	(*pSprite).EraseSprite(pDC);
	(*pSprite).UnlinkSprite();
	delete pSprite;
	pSprite = (*pBaseSprite).DuplicateSprite(pDC);
	ASSERT(pSprite != nullptr);
	(*pSprite).LinkSprite();
	if ((*pSprite).GetTypeCode() == SPRITE_HOLE)
		sprite_loc.x -= (SPRITE_SIZE_DX >> 1);
	(*pSprite).PaintSprite(pDC, sprite_loc.x, sprite_loc.y);
}


void CMainWindow::UndoTurn() {
	CDC     *pDC;
	int     newx, newy, oldx, oldy,
	        neighborx, neighbory;

	if (counter > 0) {
		if ((*pGameInfo).bSoundEffectsEnabled) {
			sndPlaySound(nullptr, 0);
			sndPlaySound(WAV_UNDO, SND_ASYNC);
		}
		bPegMoving = false;
		newx = Moves[counter].x;
		newy = Moves[counter].y;
		counter -= 1;
		pDC = GetDC();
		(*pCursorSprite).EraseSprite(pDC);
		oldx = Moves[counter].x;
		oldy = Moves[counter].y;
		neighborx = (oldx + newx) / 2 ;
		neighbory = (oldy + newy) / 2 ;
		fState [neighborx][neighbory] = PEGGED ;
		fState [oldx][oldy] = PEGGED ;
		fState [newx][newy] = EMPTY ;
		counter -= 1;

		UpdatePegPosition(pDC, pShotGlass, neighborx, neighbory);

		UpdatePegPosition(pDC, pShotGlass, oldx, oldy);

		UpdatePegPosition(pDC, pTableSlot, newx, newy);

		ReleaseDC(pDC);
	}
}


void CMainWindow::UndoMove(CDC *pDC) {
// CSprite  *pSprite;
	CPoint  sprite_loc;
	int     oldx, oldy;

	oldx = Moves[counter].x;
	oldy = Moves[counter].y;

	counter -= 1;
	bPegMoving = false;

//MessageBeep(-1);
	if ((*pGameInfo).bSoundEffectsEnabled)  {
		sndPlaySound(nullptr, 0);
		sndPlaySound(WAV_NOMOVE, SND_ASYNC);
	}

	(*pCursorSprite).EraseSprite(pDC);

	UpdatePegPosition(pDC, pShotGlass, oldx, oldy);
}


CPoint CMainWindow::GridToPoint(int i, int j) {
	CPoint  sprite_loc;

	if (BoardSelected == CROSS) {
		sprite_loc.x = - (CROSS_SHOTGLASS_DX * j) +
		               ((CROSS_SHOTGLASS_DDX + (CROSS_SHOTGLASS_DDDX * j)) * i) +
		               j - 1 + i;
		sprite_loc.y = (CROSS_SHOTGLASS_DY * (j + 1)) + j;
	} else if (BoardSelected == CROSS_PLUS) {
		sprite_loc.x = - (CROSS_PLUS_SHOTGLASS_DX * j) +
		               ((CROSS_PLUS_SHOTGLASS_DDX + (CROSS_PLUS_SHOTGLASS_DDDX * j)) * i) +
		               j - 1 + i;
		sprite_loc.y = (CROSS_PLUS_SHOTGLASS_DY * (j + 1)) + j;
	} else if (BoardSelected == TRIANGLE) {
		sprite_loc.x = (TRI_SHOTGLASS_DX * (i - j));
		sprite_loc.y = (TRI_SHOTGLASS_DY * (i + j + 1));
	} else if (BoardSelected == TRIANGLE_PLUS)  {
		if ((i + j) == 1) {
			sprite_loc.x = (TRI_PLUS_SHOTGLASS_DX * (i - j));
			sprite_loc.y = TRI_PLUS_SHOTGLASS_DY;
		} else if ((i + j) == 2) {
			if ((i != 0) && (j != 0)) {
				sprite_loc.x = 0;
				sprite_loc.y = TRI_PLUS_SHOTGLASS_DY * 2;
			}
		} else if ((i + j) > 2) {
			sprite_loc.x = (TRI_PLUS_SHOTGLASS_DX * (i - j));
			sprite_loc.y = (TRI_PLUS_SHOTGLASS_DY * (i + j));
		}
	}

	sprite_loc.x += nBoard_DX;
	sprite_loc.y += nBoard_DY;

	return (sprite_loc);
}


CPoint CMainWindow::PointToGrid(CPoint myPoint) {
	int     x, y;
	CPoint  sprite_loc;
	CPoint  point;

	point.x = myPoint.x - nBoard_DX;
	point.y = myPoint.y - nBoard_DY;

	if (BoardSelected == CROSS) {
		sprite_loc.y = (point.y - CROSS_SHOTGLASS_DY) /
		               (CROSS_SHOTGLASS_DY + 1);
		sprite_loc.x = (point.x + 1 + (sprite_loc.y * (CROSS_SHOTGLASS_DX - 1))) /
		               (CROSS_SHOTGLASS_DDX + (sprite_loc.y * CROSS_SHOTGLASS_DDDX) + 1);
	} else if (BoardSelected == CROSS_PLUS) {
		sprite_loc.y = (point.y - CROSS_PLUS_SHOTGLASS_DY) /
		               (CROSS_PLUS_SHOTGLASS_DY + 1);
		sprite_loc.x = (point.x + 1 + (sprite_loc.y * (CROSS_PLUS_SHOTGLASS_DX - 1))) /
		               (CROSS_PLUS_SHOTGLASS_DDX + (sprite_loc.y * CROSS_PLUS_SHOTGLASS_DDDX) + 1);
	} else if (BoardSelected == TRIANGLE) {
		x = (point.x / TRI_SHOTGLASS_DX) ; // x1 = int (i-j)
		y = ((point.y / TRI_SHOTGLASS_DY) - 1) ; // y1 = int(i+j)
		sprite_loc.x = ((x + y) / 2) ;
		sprite_loc.y = ((y - x + 1) / 2) ; // +1 because of the size of the sprite
	} else { // Triangle Plus case
		y = (point.y / TRI_PLUS_SHOTGLASS_DY) ; // y1 = int(i+j)
		if (y == 1) {
			if ((point.x < TRI_PLUS_SHOTGLASS_DX) && (point.x >= - TRI_PLUS_SHOTGLASS_DX)) {
				sprite_loc.x = 0;
				sprite_loc.y = 1;
			} else if ((point.x < TRI_PLUS_SHOTGLASS_DX * 2) && (point.x >= TRI_PLUS_SHOTGLASS_DX)) {
				sprite_loc.x = 1;
				sprite_loc.y = 0;
			} else {
				sprite_loc.x = 0;
				sprite_loc.y = 0; // error case (didn't click on a shotglass)
			}
		} else if (y == 2) {
			if ((point.x >= 0) && (point.x <= TRI_PLUS_SHOTGLASS_DX * 2)) {
				sprite_loc.x = 1;
				sprite_loc.y = 1;
			} else {
				sprite_loc.x = 0;
				sprite_loc.y = 0; // error case (didn't click on a shotglass)
			}
		} else if (y > 2) {
			x = (point.x / TRI_PLUS_SHOTGLASS_DX) ; // int(i-j)
			sprite_loc.x = ((x + y) / 2);
			sprite_loc.y = ((y - x + 1) / 2);
		}
	}

	return (sprite_loc);
}

void CMainWindow::OnDestroy() {
//  send a message to the calling app to tell it the user has quit the game
	MFC::PostMessage(m_hCallAppWnd, WM_PARENTNOTIFY, WM_DESTROY, 0L);
	CFrameWnd::OnDestroy();
}

// CMainWindow message map:
// Associate messages with member functions.
//
BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd)
	//{{AFX_MSG_MAP( CMainWindow )
	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_KEYDOWN()
	ON_WM_ACTIVATEAPP()
	ON_WM_DESTROY()
	ON_MESSAGE(MM_MCINOTIFY, CMainWindow::OnMCINotify)
	ON_MESSAGE(MM_WOM_DONE, CMainWindow::OnMMIONotify)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CMainWindow::OnClose() {
	CDC     *pDC;
	CBrush  myBrush;
	CRect   myRect;

	// Remove the linked sprites
	CSprite::FlushSpriteChain();

	pDC = GetDC();
	myRect.SetRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
	myBrush.CreateStockObject(BLACK_BRUSH);
	(*pDC).FillRect(&myRect, &myBrush);
	ReleaseDC(pDC);

	if ((*pGameInfo).bMusicEnabled) {
		CSound::clearSounds();
	}

	CFrameWnd ::OnClose();
}


void setup_cursor() {
	HCURSOR hNewCursor;
	CWinApp *pMyApp;

	pMyApp = AfxGetApp();

	hNewCursor = (*pMyApp).LoadStandardCursor(IDC_ARROW);

	ASSERT(hNewCursor != nullptr);
	MFC::SetCursor(hNewCursor);
}


void set_wait_cursor() {
	CWinApp *pMyApp;

	pMyApp = AfxGetApp();

	(*pMyApp).BeginWaitCursor();
}


void reset_wait_cursor() {
	CWinApp *pMyApp;

	pMyApp = AfxGetApp();

	(*pMyApp).EndWaitCursor();
}

} // namespace Peggle
} // namespace HodjNPodj
} // namespace Bagel
