/* 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 . * */ #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