/* 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/boflib/misc.h" #include "bagel/hodjnpodj/dfa/dfa.h" #include "bagel/hodjnpodj/dfa/dialogs.h" #include "bagel/hodjnpodj/hodjnpodj.h" namespace Bagel { namespace HodjNPodj { namespace DFA { #define SPLASHSPEC ".\\ART\\DFA.BMP" #ifdef BACKWARDSTIMER #define TIMERSPRITE ".\\ART\\WATCHES2.BMP" #else #define TIMERSPRITE ".\\ART\\WATCHES.BMP" #endif // // Cursor and mallet animation // #define MALLET ".\\ART\\MALLET.BMP" #define MALLETCELS 5 #define MALLET_WIDTH 32 #define MALLET_HEIGHT 32 #define RULESFILE "DFA.TXT" #define TIMERSPRITECELS 13 #define GAMETIMER 99 extern CMainDFAWindow *pMainGameWnd; CPalette *pGamePalette = nullptr; // Palette to be used throughout the game CBmpButton *pOptionButton = nullptr; // Option button object for getting to the options dialog CSprite *pMalletSprite = nullptr; // The cursor will be a sprite that animates on LButtonDown CSprite *pTimerSprite = nullptr; int nCurrentCel; CSprite *apBeaverSprite[NUM_BEAVERS]; int anBeaverShown[NUM_BEAVERS]; static CSound *pGameSound = nullptr; // Game theme song int nCurrentTimer; bool bEndGame; bool bResetGame; bool bStart; /***************************************************************** * * CMainDFAWindow * * FUNCTIONAL DESCRIPTION: * * 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. * * FORMAL PARAMETERS: * * lUserAmount = initial amount of money that user starts with * defaults to zero * nRounds = the number of rounds to play, if 0 then not playing rounds * = defaults to zero * * IMPLICIT INPUT PARAMETERS: * * n/a * * IMPLICIT OUTPUT PARAMETERS: * * n/a * * RETURN VALUE: * * n/a * ****************************************************************/ CMainDFAWindow::CMainDFAWindow(HWND hCallingWnd, LPGAMESTRUCT lpGameStruct) : rNewGame(21, 3, 227, 20) { CDC *pDC = nullptr; // device context for the screen // CPalette *pOldPalette = nullptr; CPalette *pOldPal = nullptr; CString WndClass; CSize mySize; bool bTestCreate, bTestDibDoc; // bool for testing the creation of each button CText atxtDisplayRow[NUMBEROFROWS]; CDibDoc *pDibDoc = nullptr; int x, i; CString BeaverFiles[NUM_BEAVERS]; BeginWaitCursor(); // 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); // set the seed for the random number generator //srand( (unsigned)time( nullptr )); // initialize private members m_lpGameStruct = lpGameStruct; m_lpGameStruct->lScore = 0L; m_hCallAppWnd = hCallingWnd; // load splash screen pDC = GetDC(); // get a device context for our window pDibDoc = new CDibDoc(); // create an object to hold our splash screen ASSERT(pDibDoc); // ... and verify we got it bTestDibDoc = pDibDoc->OpenDocument(SPLASHSPEC); // next load in the actual DIB based artwork ASSERT(bTestDibDoc); pGamePalette = (*pDibDoc).DetachPalette(); // grab its palette and save it for later use delete pDibDoc; // now discard the splash screen // set window coordinates to center game on screeen MainRect.left = (pDC->GetDeviceCaps(HORZRES) - GAME_WIDTH) >> 1; MainRect.top = (pDC->GetDeviceCaps(VERTRES) - GAME_HEIGHT) >> 1; MainRect.right = MainRect.left + GAME_WIDTH; // determine where to place the game window MainRect.bottom = MainRect.top + GAME_HEIGHT; // ... so it is centered on the screen pDC->SelectPalette(pOldPal, false); // replace old palette ReleaseDC(pDC); // release our window context // Create the window as a POPUP so that 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 - Dam Furry Animals", WS_POPUP, MainRect, nullptr, 0); ClipCursor(&MainRect); // // create button // pOptionButton = new CBmpButton; // create the Options button ASSERT(pOptionButton); OptionRect.SetRect(OPTION_LEFT, OPTION_TOP, OPTION_LEFT + OPTION_WIDTH, OPTION_TOP + OPTION_HEIGHT); bTestCreate = pOptionButton->Create("Options", BS_OWNERDRAW | WS_CHILD | WS_VISIBLE, OptionRect, this, IDC_OPTION); ASSERT(bTestCreate != 0); // test for button's creation bTestCreate = pOptionButton->LoadBitmaps(SCROLLUP, SCROLLDOWN, SCROLLUP, SCROLLUP); ASSERT(bTestCreate != 0); // test for button's creation // Since we have the screen & button, let's put it up to amuse the player-in-waiting m_nTimeForGame = 0; // will be checked in SplashScreen(), so initialize ShowWindow(SW_SHOWNORMAL); UpdateWindow(); aHitFile[0] = "OwOneSound"; aHitFile[1] = "OwTwoSound"; aHitFile[2] = "OwThreeSound"; aHitFile[3] = "OwFourSound"; aHitFile[4] = "OwFiveSound"; aHitFile[5] = "OwSixSound"; aHitFile[6] = "OwSevenSound"; aHitFile[7] = "OwEightSound"; aHitFile[8] = "OwNineSound"; aHitFile[9] = "OwTenSound"; aHitFile[10] = "OwElevenSound"; aMissFile[0] = "MissOneSound"; aMissFile[1] = "MissTwoSound"; aMissFile[2] = "MissTwoSound"; for (i = 0; i < NUM_HIT_SOUNDS; i++) { m_pHitSound[i] = nullptr; m_hHitRes[i] = nullptr; } for (i = 0; i < NUM_MISS_SOUNDS; i++) { m_pMissSound[i] = nullptr; m_hMissRes[i] = nullptr; } // WORKAROUND: Original uses pDC after calling ReleaseDC pDC = GetDC(); pTimerSprite = new CSprite; pTimerSprite->SharePalette(pGamePalette); bTestCreate = pTimerSprite->LoadCels(pDC, TIMERSPRITE, TIMERSPRITECELS); ASSERT(bTestCreate); // test for sprite's creation pTimerSprite->SetMasked(true); pTimerSprite->SetMobile(true); pTimerSprite->SetOptimizeSpeed(true); // // Set up the Mallet // pMalletSprite = new CSprite; pMalletSprite->SharePalette(pGamePalette); bTestCreate = pMalletSprite->LoadCels(pDC, MALLET, MALLETCELS); ASSERT(bTestCreate); // test for sprite's creation pMalletSprite->SetMasked(true); pMalletSprite->SetMobile(true); pMalletSprite->SetOptimizeSpeed(true); pMalletSprite->SetHotspot(0, 12); // Set HotSpot to center of Sprite pMalletSprite->LinkSprite(); pMalletSprite->SetZOrder(SPRITE_TOPMOST); BeaverFiles[0] = BEAVER1; BeaverFiles[1] = BEAVER2; BeaverFiles[2] = BEAVER3; BeaverFiles[3] = BEAVER4; BeaverFiles[4] = BEAVER5; BeaverFiles[5] = BEAVER6; BeaverFiles[6] = BEAVER7; for (x = 0; x < NUM_BEAVERS; x++) { apBeaverSprite[x] = nullptr; apBeaverSprite[x] = new CSprite; apBeaverSprite[x]->SharePalette(pGamePalette); bTestCreate = apBeaverSprite[x]->LoadSprite(pDC, BeaverFiles[x]); ASSERT(bTestCreate); // test for sprite's creation apBeaverSprite[x]->SetMasked(true); apBeaverSprite[x]->SetMobile(true); apBeaverSprite[x]->SetOptimizeSpeed(true); apBeaverSprite[x]->LinkSprite(); apBeaverSprite[x]->SetZOrder(SPRITE_BACKGROUND); anBeaverShown[x] = 0; } arBeaver[0].SetRect(93, 190, 179, 2276); arBeaver[1].SetRect(47, 289, 133, 375); arBeaver[2].SetRect(198, 242, 284, 328); arBeaver[3].SetRect(331, 196, 417, 282); arBeaver[4].SetRect(421, 265, 507, 351); arBeaver[5].SetRect(471, 154, 557, 240); arBeaver[6].SetRect(558, 216, 623, 302); // // Set up artwork-area // ArtRect.SetRect(0, TOP_BORDER, GAME_WIDTH, GAME_HEIGHT - TOP_BORDER); bResetGame = false; bEndGame = false; m_lScore = 0L; if (m_lpGameStruct->bPlayingMetagame == true) { switch (m_lpGameStruct->nSkillLevel) { case SKILLLEVEL_LOW: m_nTimeForGame = 30; m_nBeaverDuration = 4; break; case SKILLLEVEL_MEDIUM: m_nTimeForGame = 30; m_nBeaverDuration = 3; break; case SKILLLEVEL_HIGH: m_nTimeForGame = 30; m_nBeaverDuration = 2; break; } nCurrentCel = -1; bStart = true; } else { m_nTimeForGame = 30; m_nBeaverDuration = 3; nCurrentCel = -1; bStart = false; } if (LoadBeaverSounds() == false) { MessageBox("Could not load sound files.", "Error in Dam Furry Animals", MB_ICONINFORMATION | MB_OK); } pGameSound = new CSound(this, GAME_THEME, SOUND_MIDI | SOUND_LOOP | SOUND_DONT_LOOP_TO_END); if (m_lpGameStruct->bMusicEnabled) { if (pGameSound != nullptr) (*pGameSound).midiLoopPlaySegment(1480, 30700, 0, FMT_MILLISEC); } // end if pGameSound EndWaitCursor(); if (m_lpGameStruct->bPlayingMetagame) SetTimer(GAMETIMER, 500, nullptr); // WORKAROUND: Free re-allocated DC ReleaseDC(pDC); } /***************************************************************** * * 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 SplashScreen(); * * 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 CMainDFAWindow::OnPaint() { PAINTSTRUCT lpPaint; BeginPaint(&lpPaint); // bracket start of window update SplashScreen(); // repaint our window's content EndPaint(&lpPaint); // bracket end of window update } /***************************************************************** * * SplashScreen * * FUNCTIONAL DESCRIPTION: * * Repaint the background artwork, together with all sprites in the * sprite chain queue. The entire window is redrawn, rather than just * the updated area, to ensure that the sprites end up with the correct * background bitmaps saved for their image areas. * * FORMAL PARAMETERS: * * n/a * * IMPLICIT INPUT PARAMETERS: * * n/a * * IMPLICIT OUTPUT PARAMETERS: * * n/a * * RETURN VALUE: * * n/a * ****************************************************************/ void CMainDFAWindow::SplashScreen() { CDC *pDC = GetDC(); // get a device context for the window CPalette *pOldPalette = pDC->SelectPalette(pGamePalette, false); // load game palette; CDibDoc myDoc; bool bTestDibDoc; CRect rcDest; // defines where the art gets painted CRect rcDIB; // defines where the art comes from HDIB hDIB; // a handle to the DIB itself ASSERT(pDC); pDC->RealizePalette(); // realize game palette bTestDibDoc = myDoc.OpenDocument(SPLASHSPEC); ASSERT(bTestDibDoc); hDIB = myDoc.GetHDIB(); // ... get a handle to its DIB ASSERT(hDIB); pDC = GetDC(); // get a device context for the window ASSERT(pDC); GetClientRect(rcDest); // get the rectangle to where we paint int cxDIB = (int) DIBWidth(hDIB); int cyDIB = (int) DIBHeight(hDIB); rcDIB.top = rcDIB.left = 0; // setup the source rectangle from which rcDIB.right = cxDIB; // ... we'll do the painting rcDIB.bottom = cyDIB; PaintDIB((*pDC).m_hDC, &rcDest, hDIB, &rcDIB, pGamePalette); // transfer the image to the screen if (m_nTimeForGame > 0) { pTimerSprite->SetCel(nCurrentCel); pTimerSprite->PaintSprite(pDC, WATCH_X, WATCH_Y); } pDC->SelectPalette(pOldPalette, false); // replace old palette ReleaseDC(pDC); // release the window's context } /***************************************************************** * * ResetGame * * FUNCTIONAL DESCRIPTION: * * Start a new game, and reset all arrays and buttons * * FORMAL PARAMETERS: * * n/a * * IMPLICIT INPUT PARAMETERS: * * aDealtArray, apHold * * IMPLICIT OUTPUT PARAMETERS: * * n/a * * RETURN VALUE: * * n/a * ****************************************************************/ void CMainDFAWindow::ResetGame() { CDC *pDC = GetDC(); int i; KillTimer(GAMETIMER); pTimerSprite->EraseSprite(pDC); for (i = 0; i < NUM_BEAVERS; i++) { if (anBeaverShown[i] != 0) { apBeaverSprite[i]->EraseSprite(pDC); anBeaverShown[i] = 0; } } nCurrentTimer = 0; bEndGame = false; m_lScore = 0L; ReleaseDC(pDC); nCurrentCel = -1; if (m_nTimeForGame > 0) { #ifdef BACKWARDSTIMER switch (m_nTimeForGame) { case 15: nCurrentCel = 8; break; case 30: nCurrentCel = 5; break; case 45: nCurrentCel = 2; break; case 60: nCurrentCel = -1; break; } #else nCurrentCel = -1; #endif pTimerSprite->SetCel(nCurrentCel); pTimerSprite->PaintSprite(pDC, WATCH_X, WATCH_Y); } SetTimer(GAMETIMER, 500, nullptr); return; } /***************************************************************** * * 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 // void CALLBACK lpfnOptionCallback(CWnd * pWnd) { // do the mini options dialog int nOption = 0; // return from the Options dialog //unsigned int x = IDD_MINIOPTIONS_DIALOG; CDFAOptDlg dlgMiniOptDlg(pWnd, pGamePalette, IDD_MINIOPTIONS_DIALOG); dlgMiniOptDlg.SetInitialOptions(pMainGameWnd->m_nTimeForGame, pMainGameWnd->m_nBeaverDuration); nOption = dlgMiniOptDlg.DoModal(); if (nOption > 0) { pMainGameWnd->m_nBeaverDuration = nOption / 1000; switch (nOption % 1000) { case 1: pMainGameWnd->m_nTimeForGame = 15; #ifdef BACKWARDSTIMER nCurrentCel = 8; #else nCurrentCel = -1; #endif break; case 2: pMainGameWnd->m_nTimeForGame = 30; #ifdef BACKWARDSTIMER nCurrentCel = 5; #else nCurrentCel = -1; #endif break; case 3: pMainGameWnd->m_nTimeForGame = 45; #ifdef BACKWARDSTIMER nCurrentCel = 2; #else nCurrentCel = -1; #endif break; case 4: pMainGameWnd->m_nTimeForGame = 60; #ifdef BACKWARDSTIMER nCurrentCel = -1; #else nCurrentCel = -1; #endif break; // case 8: default: pMainGameWnd->m_nTimeForGame = 0; #ifdef BACKWARDSTIMER nCurrentCel = -1; #else nCurrentCel = -1; #endif break; } } // end if nOption > 0 return; } bool CMainDFAWindow::OnCommand(WPARAM wParam, LPARAM lParam) { int nMainOption = 0; // return from the Options dialog if (HIWORD(lParam) == BN_CLICKED) { // only want to look at button clicks switch (wParam) { // Option button clicked, then put up the Options dialog case IDC_OPTION: KillTimer(GAMETIMER); CDC *pDC; pDC = GetDC(); pMalletSprite->EraseSprite(pDC); SetCursor(LoadCursor(nullptr, IDC_ARROW)); ReleaseDC(pDC); pOptionButton->EnableWindow(false); bResetGame = false; if (m_lpGameStruct->bPlayingMetagame == true) { CMainMenu dlgMainOpts((CWnd *)this, pGamePalette, (NO_NEWGAME | NO_OPTIONS), lpfnOptionCallback, RULESFILE, (m_lpGameStruct->bSoundEffectsEnabled ? RULES_WAV : nullptr), m_lpGameStruct); nMainOption = dlgMainOpts.DoModal(); switch (nMainOption) { case IDC_OPTIONS_QUIT: // if Quit buttons was hit, quit PostMessage(WM_CLOSE, 0, 0); break; } } else { CMainMenu dlgMainOpts((CWnd *)this, pGamePalette, 0, lpfnOptionCallback, RULESFILE, (m_lpGameStruct->bSoundEffectsEnabled ? RULES_WAV : nullptr), m_lpGameStruct); nMainOption = dlgMainOpts.DoModal(); switch (nMainOption) { case IDC_OPTIONS_QUIT: // if Quit buttons was hit, quit PostMessage(WM_CLOSE, 0, 0); break; case IDC_OPTIONS_NEWGAME: // reset the game and start a new hand bResetGame = true; break; } } pOptionButton->EnableWindow(true); SetFocus(); if ((m_lpGameStruct->bMusicEnabled == false) && (pGameSound != nullptr)) { if (pGameSound->playing()) (*pGameSound).stop(); } else if (m_lpGameStruct->bMusicEnabled == true) { if (pGameSound == nullptr) { pGameSound = new CSound(this, GAME_THEME, SOUND_MIDI | SOUND_LOOP | SOUND_DONT_LOOP_TO_END); } if (pGameSound != nullptr) { (*pGameSound).midiLoopPlaySegment(1480, 30700, 0, FMT_MILLISEC); } // end if pGameSound } if (bResetGame && !m_lpGameStruct->bPlayingMetagame) { ResetGame(); } else { if (m_nTimeForGame > 0) { pDC = GetDC(); pTimerSprite->SetCel(nCurrentCel); pTimerSprite->PaintSprite(pDC, WATCH_X, WATCH_Y); ReleaseDC(pDC); } SetTimer(GAMETIMER, 500, nullptr); } break; } } (*this).SetFocus(); // Reset focus back to the main window return true; } void CMainDFAWindow::OnRButtonDown(unsigned int nFlags, CPoint point) { if (bStart) { bStart = false; } CWnd::OnRButtonDown(nFlags, point); } void CMainDFAWindow::OnLButtonDown(unsigned int nFlags, CPoint point) { CSound *pEffect = nullptr; CRect rWatch, rLake, rMount, rFlowers; int x, nPick; rWatch.SetRect(WATCH_X, WATCH_Y, WATCH_X + WATCH_DX, WATCH_Y + WATCH_DY); rLake.SetRect(LAKE_X, LAKE_Y, LAKE_X + LAKE_DX, LAKE_Y + LAKE_DY); rMount.SetRect(MOUNT_X, MOUNT_Y, MOUNT_X + MOUNT_DX, MOUNT_Y + MOUNT_DY); rFlowers.SetRect(FLOWERS_X, FLOWERS_Y, FLOWERS_X + FLOWERS_DX, FLOWERS_Y + FLOWERS_DY); if (rNewGame.PtInRect(point) && !m_lpGameStruct->bPlayingMetagame) { ResetGame(); return; } else if (bStart) { bStart = false; return; } else if (!bEndGame && ArtRect.PtInRect(point)) { CDC *pDC; pDC = GetDC(); pMalletSprite->SetCel(1); pMalletSprite->PaintSprite(pDC, pMalletSprite->GetPosition()); ReleaseDC(pDC); } if (rWatch.PtInRect(point) && m_lpGameStruct->bSoundEffectsEnabled) { CSound::clearWaveSounds(); sndPlaySound(nullptr, 0); pEffect = new CSound((CWnd *)this, WATCH_WAV, SOUND_WAVE | SOUND_ASYNCH | SOUND_AUTODELETE); //...Wave file, to delete itself (*pEffect).play(); //...play the narration } else if (rLake.PtInRect(point) && m_lpGameStruct->bSoundEffectsEnabled) { CSound::clearWaveSounds(); sndPlaySound(nullptr, 0); pEffect = new CSound((CWnd *)this, LAKE_WAV, SOUND_WAVE | SOUND_ASYNCH | SOUND_AUTODELETE); //...Wave file, to delete itself (*pEffect).play(); //...play the narration } else if (rMount.PtInRect(point) && m_lpGameStruct->bSoundEffectsEnabled) { CSound::clearWaveSounds(); sndPlaySound(nullptr, 0); pEffect = new CSound((CWnd *)this, MOUNT_WAV, SOUND_WAVE | SOUND_ASYNCH | SOUND_AUTODELETE); //...Wave file, to delete itself (*pEffect).play(); //...play the narration } else if (rFlowers.PtInRect(point) && m_lpGameStruct->bSoundEffectsEnabled) { CSound::clearWaveSounds(); sndPlaySound(nullptr, 0); pEffect = new CSound((CWnd *)this, BEE_WAV, SOUND_WAVE | SOUND_ASYNCH | SOUND_AUTODELETE); //...Wave file, to delete itself (*pEffect).play(); //...play the narration } if (bEndGame) return; for (x = 0; x < NUM_BEAVERS; x ++) { // for each beaver if (arBeaver[x].PtInRect(point)) { // see if it was hit if (anBeaverShown[x] > 0) { // if it was there at hit-time CDC *pDC = GetDC(); if (m_lpGameStruct->bSoundEffectsEnabled) { // Play the hit sound nPick = (brand() % NUM_HIT_SOUNDS); CSound::clearWaveSounds(); sndPlaySound(m_pHitSound[nPick], SND_MEMORY | SND_ASYNC | SND_NODEFAULT); } // end if apBeaverSprite[x]->EraseSprite(pDC); // erase beaver anBeaverShown[x] = 0; ReleaseDC(pDC); m_lScore++; } // end if Shown else { // no beaver there at hit-time if (m_lpGameStruct->bSoundEffectsEnabled) { // Play the hit sound nPick = (brand() % NUM_MISS_SOUNDS); // randomly select a miss sound CSound::clearWaveSounds(); sndPlaySound(m_pMissSound[nPick], SND_MEMORY | SND_ASYNC | SND_NODEFAULT); } // end if bSoundEffectsEnabled } // end else } // end if PtInRect } CWnd::OnLButtonDown(nFlags, point); } void CMainDFAWindow::OnMouseMove(unsigned int nFlags, CPoint point) { CDC *pDC; pDC = GetDC(); if (ArtRect.PtInRect(point) && !bEndGame) { SetCursor(LoadCursor(nullptr, nullptr)); pMalletSprite->SetCel(-1); pMalletSprite->PaintSprite(pDC, point); } else { pMalletSprite->EraseSprite(pDC); SetCursor(LoadCursor(nullptr, IDC_ARROW)); } ReleaseDC(pDC); CWnd::OnMouseMove(nFlags, point); } void CMainDFAWindow::OnLButtonUp(unsigned int nFlags, CPoint point) { if (!bEndGame && ArtRect.PtInRect(point)) { CDC *pDC; pDC = GetDC(); pMalletSprite->SetCel(-1); pMalletSprite->PaintSprite(pDC, pMalletSprite->GetPosition()); ReleaseDC(pDC); } CWnd::OnLButtonUp(nFlags, point); } void CMainDFAWindow::OnSysKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) { // terminate app on ALT_F4 // if ((nChar == VK_F4) && (nFlags & 0x2000)) { PostMessage(WM_CLOSE, 0, 0); } else { // default action CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags); } } void CMainDFAWindow::OnKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) { CRules dlgRules((CWnd *)this, RULESFILE, pGamePalette, (m_lpGameStruct->bSoundEffectsEnabled ? RULES_WAV : nullptr)); switch (nChar) { case VK_F1: KillTimer(GAMETIMER); // stop the beavers for now CSound::waitWaveSounds(); pOptionButton->ShowWindow(SW_HIDE); // hide furled scroll dlgRules.DoModal(); // invoke the help dialog box pOptionButton->ShowWindow(SW_SHOWNORMAL); // show furled scroll SetFocus(); if (m_nTimeForGame > 0) { CDC *pDC = GetDC(); pTimerSprite->SetCel(nCurrentCel); pTimerSprite->PaintSprite(pDC, WATCH_X, WATCH_Y); ReleaseDC(pDC); } SetTimer(GAMETIMER, 500, nullptr); break; case VK_F2: SendMessage(WM_COMMAND, IDC_OPTION, BN_CLICKED); break; default: CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags); break; } return; } void CMainDFAWindow::OnTimer(uintptr nWhichTimer) { CSound *pEffect = nullptr; if (nWhichTimer == GAMETIMER) { CDC *pDC = GetDC(); int x = brand() % NUM_BEAVERS; if (bStart) { ReleaseDC(pDC); return; } if (bEndGame) { ReleaseDC(pDC); return; } if (m_nTimeForGame > 0) nCurrentTimer++; else nCurrentTimer = 0; if (((nCurrentTimer % 10) == 0) && (m_nTimeForGame != 0)) { pDC = GetDC(); nCurrentCel++; pTimerSprite->SetCel(nCurrentCel); /* if (m_lpGameStruct->bSoundEffectsEnabled) { pEffect = new CSound( (CWnd *)this, TICK_WAV, SOUND_WAVE | SOUND_ASYNCH | SOUND_AUTODELETE); //...Wave file, to delete itself (*pEffect).play(); //...play the narration } */ pTimerSprite->PaintSprite(pDC, WATCH_X, WATCH_Y); ReleaseDC(pDC); } if (nCurrentTimer > (int)(2 * m_nTimeForGame)) { CMsgDlg msgBox((CWnd*)this, pGamePalette); KillTimer(GAMETIMER); bEndGame = true; for (x = 0; x < NUM_BEAVERS; x++) { apBeaverSprite[x]->EraseSprite(pDC); anBeaverShown[x] = 0; } pMalletSprite->EraseSprite(pDC); // Get rid of color mallet cursor ReleaseDC(pDC); MSG lpmsg; // Remove any messages in the queue before doing msgbox while (PeekMessage(&lpmsg, m_hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) ; // prevent random 'hits' if (m_lpGameStruct->bSoundEffectsEnabled) { CSound::clearWaveSounds(); sndPlaySound(nullptr, 0); pEffect = new CSound((CWnd *)this, TIME_WAV, SOUND_WAVE | SOUND_ASYNCH /*| SOUND_QUEUE*/ | SOUND_AUTODELETE); //...Wave file, to delete itself (*pEffect).play(); //...play the narration } msgBox.SetInitialOptions(1, m_lScore); while (PeekMessage(&lpmsg, m_hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) ; // prevent random 'hits' msgBox.DoModal(); if (m_lpGameStruct->bPlayingMetagame) PostMessage(WM_CLOSE, 0, 0); ReleaseDC(pDC); return; } if (anBeaverShown[x] == 0) { apBeaverSprite[x]->PaintSprite(pDC, arBeaver[x].left, arBeaver[x].top); anBeaverShown[x]++; } for (x = 0; x < NUM_BEAVERS; x++) { if (anBeaverShown[x] > m_nBeaverDuration) { apBeaverSprite[x]->EraseSprite(pDC); anBeaverShown[x] = 0; } else { if (anBeaverShown[x] > 0) anBeaverShown[x]++; } } ReleaseDC(pDC); } return; } /***************************************************************** * * 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] * ****************************************************************/ bool CMainDFAWindow::OnEraseBkgnd(CDC *pDC) { // eat this return true; } void CMainDFAWindow::OnActivate(unsigned int nState, CWnd *pWndOther, bool bMinimized) { if (!bMinimized) switch (nState) { case WA_ACTIVE: case WA_CLICKACTIVE: InvalidateRect(nullptr, false); break; } return; } /***************************************************************** * * 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 CMainDFAWindow::OnClose() { CDC *pDC = GetDC(); CRect rctFillRect(0, 0, 640, 480); CBrush Brush(RGB(0, 0, 0)); ClipCursor(nullptr); pDC->FillRect(&rctFillRect, &Brush); ReleaseDC(pDC); ReleaseResources(); ReleaseBeaverSounds(); CFrameWnd ::OnClose(); } /***************************************************************** * * OnDestroy * * FUNCTIONAL DESCRIPTION: * * This function is called when after the window has been destroyed. * For poker, we post a message bak to the calling app to tell it * that the user has quit the game, and therefore the app can unload * this DLLL * * FORMAL PARAMETERS: * * n/a * * IMPLICIT INPUT PARAMETERS: * * n/a * * IMPLICIT OUTPUT PARAMETERS: * * n/a * * RETURN VALUE: * * n/a * ****************************************************************/ void CMainDFAWindow::OnDestroy() { // send a message to the calling app to tell it the user has quit the game m_lpGameStruct->lScore = m_lScore; MFC::PostMessage(m_hCallAppWnd, WM_PARENTNOTIFY, WM_DESTROY, (LPARAM)m_lpGameStruct); m_lpGameStruct = nullptr; CFrameWnd::OnDestroy(); } /***************************************************************** * * ReleaseResources * * FUNCTIONAL DESCRIPTION: * * Release all resources that were created and retained during the * course of the game. This includes sprites in the sprite chain, * the game color palette, and button controls. * * FORMAL PARAMETERS: * * n/a * * IMPLICIT INPUT PARAMETERS: * * n/a * * IMPLICIT OUTPUT PARAMETERS: * * n/a * * RETURN VALUE: * * n/a * ****************************************************************/ void CMainDFAWindow::ReleaseResources() { int x; if (pGameSound != nullptr) { delete pGameSound; // delete the game theme song pGameSound = nullptr; } CSound::clearSounds(); if (pTimerSprite != nullptr) { delete pTimerSprite; } if (pMalletSprite != nullptr) { delete pMalletSprite; } for (x = 0; x < NUM_BEAVERS; x++) { if (apBeaverSprite[x] != nullptr) delete apBeaverSprite[x]; } if (pGamePalette != nullptr) { pGamePalette->DeleteObject(); // release the game color palette delete pGamePalette; } delete pOptionButton; // release the buttons we used return; } /***************************************************************** * * FlushInputEvents * * FUNCTIONAL DESCRIPTION: * * Remove all keyboard and mouse related events from the message * so that they will not be sent to us for processing; i.e. this * flushes keyboard type ahead and extra mouse clicks and movement. * * FORMAL PARAMETERS: * * n/a * * IMPLICIT INPUT PARAMETERS: * * n/a * * IMPLICIT OUTPUT PARAMETERS: * * n/a * * RETURN VALUE: * * n/a * ****************************************************************/ void CMainDFAWindow::FlushInputEvents() { MSG msg; while (true) { // find and remove all keyboard events if (!PeekMessage(&msg, nullptr, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) break; } while (true) { // find and remove all mouse events if (!PeekMessage(&msg, nullptr, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) break; } } //////////// Additional Sound Notify routines ////////////// LRESULT CMainDFAWindow::OnMCINotify(WPARAM wParam, LPARAM lParam) { CSound *pSound; pSound = CSound::OnMCIStopped(wParam, lParam); if (pSound != nullptr) OnSoundNotify(pSound); return 0; } LRESULT CMainDFAWindow::OnMMIONotify(WPARAM wParam, LPARAM lParam) { CSound *pSound; pSound = CSound::OnMMIOStopped(wParam, lParam); if (pSound != nullptr) OnSoundNotify(pSound); return 0; } void CMainDFAWindow::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. // } bool CMainDFAWindow::LoadBeaverSounds() { HANDLE hResInfo; HINSTANCE hInst; bool bSuccess; int i; // assume no error bSuccess = true; hInst = (HINSTANCE)GetWindowWord(m_hWnd, GWW_HINSTANCE); for (i = 0; i < NUM_HIT_SOUNDS; i++) { // Load and lock // if ((hResInfo = FindResource(hInst, aHitFile[i], "WAVE")) != nullptr) { if ((m_hHitRes[i] = LoadResource(hInst, (HRSRC)hResInfo)) != nullptr) { if ((m_pHitSound[i] = (char *)LockResource((HGLOBAL)m_hHitRes[i])) != nullptr) { // we have now loaded at least one of the master sounds } else bSuccess = false; } else bSuccess = false; } else bSuccess = false; } for (i = 0; i < NUM_MISS_SOUNDS; i++) { // Load and lock // if ((hResInfo = FindResource(hInst, aMissFile[i], "WAVE")) != nullptr) { if ((m_hMissRes[i] = LoadResource(hInst, (HRSRC)hResInfo)) != nullptr) { if ((m_pMissSound[i] = (char *)LockResource((HGLOBAL)m_hMissRes[i])) != nullptr) { // we have now loaded at least one of the master sounds } else bSuccess = false; } else bSuccess = false; } else bSuccess = false; } return bSuccess; } // end LoadBeaverSounds void CMainDFAWindow::ReleaseBeaverSounds() { int i; for (i = 0; i < NUM_HIT_SOUNDS; i++) { if (m_hHitRes[i] != nullptr) { FreeResource(m_hHitRes[i]); m_hHitRes[i] = nullptr; } } for (i = 0; i < NUM_MISS_SOUNDS; i++) { if (m_hMissRes[i] != nullptr) { FreeResource(m_hMissRes[i]); m_hMissRes[i] = nullptr; } } } // CMainDFAWindow message map: // Associate messages with member functions. // BEGIN_MESSAGE_MAP(CMainDFAWindow, CFrameWnd) //{{AFX_MSG_MAP( CMainDFAWindow ) ON_WM_PAINT() ON_WM_LBUTTONDOWN() ON_WM_RBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_CLOSE() ON_WM_DESTROY() ON_WM_TIMER() ON_WM_ERASEBKGND() ON_WM_SYSKEYDOWN() ON_WM_KEYDOWN() ON_WM_ACTIVATE() ON_MESSAGE(MM_MCINOTIFY, CMainDFAWindow::OnMCINotify) ON_MESSAGE(MM_WOM_DONE, CMainDFAWindow::OnMMIONotify) //}}AFX_MSG_MAP END_MESSAGE_MAP() } // namespace DFA } // namespace HodjNPodj } // namespace Bagel