Files
2026-02-02 04:50:13 +01:00

1766 lines
54 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "bagel/hodjnpodj/hnplibs/stdafx.h"
#include "bagel/boflib/sound.h"
#include "bagel/hodjnpodj/hnplibs/mainmenu.h"
#include "bagel/hodjnpodj/hnplibs/cmessbox.h"
#include "bagel/hodjnpodj/hnplibs/rules.h"
#include "bagel/hodjnpodj/hnplibs/button.h"
#include "bagel/hodjnpodj/hnplibs/text.h"
#include "bagel/hodjnpodj/hnplibs/gamedll.h"
#include "bagel/hodjnpodj/beacon/resource.h"
#include "bagel/hodjnpodj/beacon/globals.h"
#include "bagel/hodjnpodj/beacon/beacon.h"
#include "bagel/hodjnpodj/beacon/optndlg.h"
#include "bagel/hodjnpodj/hodjnpodj.h"
namespace Bagel {
namespace HodjNPodj {
namespace Beacon {
void CALLBACK GetSubOptions(CWnd *pParentWind);
void CALLBACK StepAlongLine(int xpos, int ypos, CDC *cdc);
bool InArtRegion(CPoint point);
void MyFocusRect(CDC *pDC, CRect rect, bool bPressed);
CBmpButton *m_pScrollButton; // Scroll button
CBitmap *pScrollUp = nullptr,
*pScrollDown = nullptr;
CPalette *pOldPal1 = nullptr,
*pOldPal2 = nullptr,
*pGamePalette = nullptr; // Palette of current artwork
CBitmap *pBeaconBitmap = nullptr, // Lighthouse bitmap
*pBackBitmap = nullptr, // Offscreen bitmap of border, pie wedges and lighthouse
*pOldBmp1 = nullptr,
*pArtBitmap = nullptr, // Holds the latest piece of art
*pOldBmp2 = nullptr;
CDC *pArtDC = nullptr,
*pBackDC = nullptr;
CText *m_pScoreTxt = nullptr;
CText *m_pSweepTxt = nullptr;
bool bSuccess;
bool m_bIgnoreScrollClick;
bool bChanged;
bool bPlaying = false;
bool bNewGame = false; // Not playing a game right now
unsigned int nCurrentIndex = BUTTON_ENTRY; // The current beacon color index
unsigned int nNextIndex = BUTTON_ENTRY; // The next beacon color index
unsigned int nSlice = START_ENTRY;
int nLastPick = 0;
int m_nSweepCount = 0;
constexpr int m_nTotalSquares = (NUM_COLUMNS * NUM_ROWS) -
((START_WIDTH / GRID_WIDTH) * (START_HEIGHT / GRID_HEIGHT));
int m_nRemoved = 0; // Count blocks removed
unsigned int m_nSweeps = MAX_SWEEPS;
unsigned int m_nSpeed = MAX_SPEED;
unsigned int tempSweeps = 100; // default sweeps = 100
unsigned int tempSpeed = MAX_SPEED; // default speed = Hovercraft
bool m_bAutomatic = false;
bool m_bChangeAtTwelve = false;
float m_Score = 0;
bool PictureGrid[NUM_COLUMNS][NUM_ROWS];
static CSound *pGameSound = nullptr; // Game theme song
extern LPGAMESTRUCT pGameInfo;
extern HWND ghParentWnd;
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// 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() {
CDC *pDC;
CPalette *pOldPal;
CBitmap *pBeamBitmap = nullptr, // Beam bitmap
*pBorderBitmap = nullptr; // Border bitmap
CString WndClass;
CRect MainRect, ScrollRect, statRect;
CBrush *pMyBrush = nullptr;
int i;
BeginWaitCursor();
initStatics();
// 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_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);
// Create the window as a POPUP so no boarders, title, or menu are present;
// this is because the game's background art will fill the entire 640x480 area.
Create(WndClass, "Boffo Games -- Beacon", WS_POPUP, MainRect, nullptr, 0);
pDC = GetDC();
pBorderBitmap = FetchBitmap(pDC, &pGamePalette, MAINSCREEN);
pOldPal = pDC->SelectPalette(pGamePalette, false); // select the game palette
pDC->RealizePalette(); //...and realize it
// SetBeamEntries( pDC );
// Build Scroll Command button
pScrollUp = FetchResourceBitmap(pDC, nullptr, SCROLLUP); // Get the up scroll button
pScrollDown = FetchResourceBitmap(pDC, nullptr, SCROLLDOWN); // Get the dowm scroll button
ShowWindow(SW_SHOWNORMAL);
PaintBitmap(pDC, pGamePalette, pBorderBitmap, 0, 0);
PaintMaskedBitmap(pDC, pGamePalette, pScrollUp, SCROLL_BUTTON_X, SCROLL_BUTTON_Y);
m_pScrollButton = new CBmpButton;
ASSERT(m_pScrollButton != nullptr);
ScrollRect.SetRect(SCROLL_BUTTON_X, SCROLL_BUTTON_Y,
SCROLL_BUTTON_X + SCROLL_BUTTON_DX - 1,
SCROLL_BUTTON_Y + SCROLL_BUTTON_DY - 1);
bSuccess = (*m_pScrollButton).Create(nullptr, BS_OWNERDRAW | WS_CHILD | WS_VISIBLE, ScrollRect, this, IDC_SCROLL);
ASSERT(bSuccess);
bSuccess = (*m_pScrollButton).LoadBitmaps(pGamePalette, pScrollUp, pScrollDown, nullptr, nullptr);
pScrollUp = nullptr;
pScrollDown = nullptr;
ASSERT(bSuccess);
m_bIgnoreScrollClick = false;
pBackBitmap = new CBitmap();
pBackDC = new CDC();
pBackBitmap->CreateCompatibleBitmap(pDC, GAME_WIDTH, GAME_HEIGHT);
pBackDC->CreateCompatibleDC(pDC);
pOldBmp1 = pBackDC->SelectObject(pBackBitmap);
pOldPal1 = pBackDC->SelectPalette(pGamePalette, false);
pBackDC->RealizePalette();
pArtBitmap = new CBitmap();
pArtDC = new CDC();
pArtBitmap->CreateCompatibleBitmap(pDC, GAME_WIDTH, GAME_HEIGHT);
pArtDC->CreateCompatibleDC(pDC);
pOldBmp2 = pArtDC->SelectObject(pArtBitmap);
pOldPal2 = pArtDC->SelectPalette(pGamePalette, false);
pArtDC->RealizePalette();
PaintBitmap(pArtDC, pGamePalette, pBorderBitmap, 0, 0); //SplashScreen to art bitmap
pBorderBitmap->DeleteObject();
delete pBorderBitmap;
#ifndef BACKDROP
pBeamBitmap = FetchBitmap(pDC, nullptr, BEAMSCREEN);
PaintBitmap(pBackDC, pGamePalette, pBeamBitmap, 0, 0); //SplashScreen to back
pBeamBitmap->DeleteObject();
#endif
delete pBeamBitmap;
for (i = 0; i < NUM_BUTTONS; i++) {
int level = i / 2;
colorBlock[i].rLocation.SetRect(
BLOCK_OFFSET_X + ((BLOCK_WIDTH + BLOCK_SPACE_X) * ((i + 2) % 2)),
BLOCK_OFFSET_Y + ((BLOCK_HEIGHT + BLOCK_SPACE_Y) * level),
BLOCK_OFFSET_X + ((BLOCK_WIDTH + BLOCK_SPACE_X) * ((i + 2) % 2)) + BLOCK_WIDTH,
BLOCK_OFFSET_Y +
((BLOCK_HEIGHT + BLOCK_SPACE_Y) * level) + BLOCK_HEIGHT);
colorBlock[i].nColorIndex = BUTTON_ENTRY + i;
pMyBrush = new CBrush(); // Construct new brush
(*pMyBrush).CreateSolidBrush(PALETTEINDEX((uint16)(colorBlock[i].nColorIndex)));
(*pArtDC).FillRect(colorBlock[i].rLocation, pMyBrush);
MyFocusRect(pArtDC, colorBlock[i].rLocation, false); // standard highlight on button
pMyBrush->DeleteObject();
delete pMyBrush;
pMyBrush = nullptr;
}
statRect.SetRect(SIDE_BORDER + ART_WIDTH, TOP_BORDER,
GAME_WIDTH - SIDE_BORDER, GAME_HEIGHT - BOTTOM_BORDER);
MyFocusRect(pArtDC, statRect, false); // highlight button area
statRect.SetRect(BLOCK_OFFSET_X + 5, TOP_BORDER + 5, GAME_WIDTH - SIDE_BORDER, TOP_BORDER + 25);
if ((m_pScoreTxt = new CText()) != nullptr) {
(*m_pScoreTxt).SetupText(pDC, pGamePalette, &statRect, JUSTIFY_LEFT);
}
statRect.SetRect(BLOCK_OFFSET_X + 5, TOP_BORDER + 25, GAME_WIDTH - SIDE_BORDER, TOP_BORDER + 45);
if ((m_pSweepTxt = new CText()) != nullptr) {
(*m_pSweepTxt).SetupText(pDC, pGamePalette, &statRect, JUSTIFY_LEFT);
}
(*pDC).SelectPalette(pOldPal, false); // Select back the old palette
ReleaseDC(pDC);
//srand((unsigned) time(nullptr)); // seed the random number generator
NewGame();
if (pGameInfo->bMusicEnabled) {
pGameSound = new CSound(this, GAME_THEME, SOUND_MIDI | SOUND_LOOP | SOUND_DONT_LOOP_TO_END);
if (pGameSound != nullptr) {
(*pGameSound).midiLoopPlaySegment(1300, 36500, 0, FMT_MILLISEC);
} // end if pGameSound
}
EndWaitCursor();
if (pGameInfo->bPlayingMetagame) {
bNewGame = true; // in meta start out in a game
pGameInfo->lScore = 0L; // Make sure if they bail out it's 0
} else
PostMessage(WM_COMMAND, IDC_SCROLL, BN_CLICKED); // Activate the Options dialog
} //End of CMainWindow
void CMainWindow::initStatics() {
m_pScrollButton = nullptr;
pScrollUp = pScrollDown = nullptr;
pOldPal1 = pOldPal2 = pGamePalette = nullptr;
pBeaconBitmap = pBackBitmap = pOldBmp1 = nullptr;
pArtBitmap = pOldBmp2 = nullptr;
pArtDC = pBackDC = nullptr;
m_pScoreTxt = m_pSweepTxt = nullptr;
bSuccess = false;
m_bIgnoreScrollClick = false;
bChanged = false;
bPlaying = false;
bNewGame = false;
nCurrentIndex = BUTTON_ENTRY;
nNextIndex = BUTTON_ENTRY;
nSlice = START_ENTRY;
nLastPick = 0;
m_nSweepCount = 0;
m_nRemoved = 0;
m_nSweeps = MAX_SWEEPS;
m_nSpeed = MAX_SPEED;
tempSweeps = 100;
tempSpeed = MAX_SPEED;
m_bAutomatic = false;
m_bChangeAtTwelve = false;
m_Score = 0;
}
// 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() {
CDC *pDC;
CPalette *pOldPal = nullptr;
PAINTSTRUCT lpPaint;
char msg[64];
pDC = GetDC();
pOldPal = (*pDC).SelectPalette(pGamePalette, false);
(*pDC).RealizePalette();
InvalidateRect(nullptr, false); // invalidate the entire window
BeginPaint(&lpPaint);
pBeaconBitmap = FetchResourceBitmap(pArtDC, nullptr, IDB_BEACON_BMP);
PaintMaskedBitmap(pArtDC, pGamePalette, pBeaconBitmap,
SIDE_BORDER + (ART_WIDTH / 2) - LTHOUSE_OFFSET_X,
TOP_BORDER + (ART_HEIGHT / 2) - LTHOUSE_OFFSET_Y);
pDC->BitBlt(0, 0, GAME_WIDTH, GAME_HEIGHT, pArtDC, 0, 0, SRCCOPY);
Common::sprintf_s(msg, "Score: %.0f %%", m_Score);
(*m_pScoreTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
if ((m_nSweeps < MAX_SWEEPS) && bPlaying)
Common::sprintf_s(msg, "Sweeps: %d", m_nSweepCount - 1); // Update text on screen
else
Common::sprintf_s(msg, "Sweeps: %d", m_nSweepCount);
(*m_pSweepTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
EndPaint(&lpPaint);
(*pDC).SelectPalette(pOldPal, false);
ReleaseDC(pDC);
}
void CMainWindow::DrawBeams(CDC *pDC) {
CDC *pBigDC = nullptr;
CBitmap *pBigBmp = nullptr,
*pBigBmpOld = nullptr;
CBrush *pMyBrush = nullptr; // New Brush
CBrush *pOldBrush = nullptr; // Pointer to old brush
CPen *pMyPen = nullptr; // New Brush
CPen *pOldPen = nullptr; // Pointer to old brush
CPalette *pPalOld = nullptr, // Pointer to old palette
*pBigPalOld = nullptr;
CRect rect;
CPoint StartPt, EndPt, Center;
unsigned int i;
int radius;
float degrees, x, y, radians, rads;
pPalOld = (*pDC).SelectPalette(pGamePalette, false); // Select in game palette
(*pDC).RealizePalette(); // Use it
pBigBmp = new CBitmap();
pBigDC = new CDC();
bSuccess = pBigBmp->CreateCompatibleBitmap(pDC, ART_WIDTH * 2, ART_HEIGHT * 2);
ASSERT(bSuccess);
bSuccess = pBigDC->CreateCompatibleDC(pDC);
ASSERT(bSuccess);
pBigBmpOld = pBigDC->SelectObject(pBigBmp);
ASSERT(pBigBmpOld != nullptr);
pBigPalOld = pBigDC->SelectPalette(pGamePalette, false);
pBigDC->RealizePalette();
Center.x = ART_WIDTH;
Center.y = ART_HEIGHT;
rect.SetRect(0, 0, ART_WIDTH * 2, ART_HEIGHT * 2);
radius = ART_WIDTH;
x = (float)cos(0.0);
y = (float)sin(0.0);
EndPt.x = Center.x + (int)(x * radius); // + radius
EndPt.y = Center.y + (int)(y * radius); //- radius;
for (i = 0; i < NUM_BEAMS; i++) {
degrees = ((float)(i + 1)) * (float)(360 / NUM_BEAMS);
radians = degrees * (float)0.017453292;
rads = (degrees + 0.5F) * (float)0.017453292;
x = (float)cos(rads);
y = (float)sin(rads);
StartPt.x = Center.x + (int)(x * radius);
StartPt.y = Center.y + (int)(y * radius);
pMyPen = new CPen(); // Construct new pen
(*pMyPen).CreatePen(PS_SOLID, 1, PALETTEINDEX((uint16)(i + START_ENTRY)));
pOldPen = (*pBigDC).SelectObject(pMyPen);
pMyBrush = new CBrush(); // Construct new brush
(*pMyBrush).CreateSolidBrush(PALETTEINDEX((uint16)(i + START_ENTRY)));
pOldBrush = (*pBigDC).SelectObject(pMyBrush);
(*pBigDC).Pie(&rect, StartPt, EndPt);
(*pBigDC).SelectObject(pOldPen);
pMyPen->DeleteObject();
delete pMyPen;
pMyPen = nullptr;
(*pBigDC).SelectObject(pOldBrush);
pMyBrush->DeleteObject();
delete pMyBrush;
pMyBrush = nullptr;
x = (float)cos(radians);
y = (float)sin(radians);
EndPt.x = Center.x + (int)(x * radius);
EndPt.y = Center.y + (int)(y * radius);
}
(*pDC).BitBlt(SIDE_BORDER, TOP_BORDER, ART_WIDTH, ART_HEIGHT, pBigDC, ART_WIDTH / 2, ART_HEIGHT / 2, SRCCOPY);
(*pDC).SelectPalette(pPalOld, false); // Select back the old palette
if (pBigBmpOld != nullptr) // Get rid of Big stuff
pBigDC->SelectObject(pBigBmpOld);
if (pBigPalOld != nullptr)
pBigDC->SelectPalette(pBigPalOld, false);
if (pBigDC->m_hDC != nullptr) {
pBigDC->DeleteDC();
delete pBigDC;
}
pBigBmp->DeleteObject();
delete pBigBmp;
}
/////////////////////////////////////////////////////////////////////////////
//
// 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 = nullptr;
if (HIWORD(lParam) == BN_CLICKED) {
pDC = GetDC();
CRules RulesDlg((CWnd *)this, RULES_TEXT, pGamePalette, pGameInfo->bSoundEffectsEnabled ? RULES_WAV : nullptr); // Construct Rules dialog
CMainMenu COptionsWind((CWnd *)this, pGamePalette,
pGameInfo->bPlayingMetagame ? (NO_NEWGAME | NO_OPTIONS) : 0,
GetSubOptions, RULES_TEXT, pGameInfo->bSoundEffectsEnabled ? RULES_WAV : nullptr, pGameInfo) ; // Construct Option dialog
KillTimer(BEACON_TIMER);
switch (wParam) {
case IDC_RULES:
CSound::waitWaveSounds();
m_bIgnoreScrollClick = true;
(*m_pScrollButton).SendMessage(BM_SETSTATE, true, 0L);
RulesDlg.DoModal();
m_bIgnoreScrollClick = false;
(*m_pScrollButton).SendMessage(BM_SETSTATE, false, 0L);
if (bPlaying) SetTimer(BEACON_TIMER, SPEED_BASE - (m_nSpeed * SPEED_STEP), nullptr);
SetBeamEntries(pDC);
break;
case IDC_SCROLL:
if (m_bIgnoreScrollClick) {
(*m_pScrollButton).SendMessage(BM_SETSTATE, true, 0L);
break;
}
m_bIgnoreScrollClick = true;
(*m_pScrollButton).SendMessage(BM_SETSTATE, true, 0L);
SendDlgItemMessage(IDC_SCROLL, BM_SETSTATE, true, 0L);
switch (COptionsWind.DoModal()) {
case IDC_OPTIONS_NEWGAME: // Selected New Game
bPlaying = false;
MyFocusRect(pDC, colorBlock[nNextIndex - BUTTON_ENTRY].rLocation, false); // erase highlight on nNextIndex
NewGame();
char msg[64];
Common::sprintf_s(msg, "Score: %.0f %%", m_Score);
(*m_pScoreTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
Common::sprintf_s(msg, "Sweeps: %d", m_nSweepCount);
(*m_pSweepTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
(*m_pScrollButton).SendMessage(BM_SETSTATE, false, 0L);
m_bIgnoreScrollClick = false;
break;
case IDC_OPTIONS_RETURN:
(*m_pScrollButton).SendMessage(BM_SETSTATE, false, 0L);
m_bIgnoreScrollClick = false;
if (bPlaying)
SetTimer(BEACON_TIMER, SPEED_BASE - (m_nSpeed * SPEED_STEP), nullptr);
break;
case IDC_OPTIONS_QUIT: // Quit button was clicked
PostMessage(WM_CLOSE, 0, 0); // Post a program exit
ReleaseDC(pDC);
return false;
} //end switch(ComDlg.DoModal())
SetBeamEntries(pDC); // Make sure the palette is black
//
// Check to see if the music state was changed and adjust to match it
//
if ((pGameInfo->bMusicEnabled == false) && (pGameSound != nullptr)) {
if (pGameSound->playing())
pGameSound->stop();
} else if (pGameInfo->bMusicEnabled) {
if (pGameSound == nullptr) {
pGameSound = new CSound(this, GAME_THEME, SOUND_MIDI | SOUND_LOOP | SOUND_DONT_LOOP_TO_END);
}
if (pGameSound != nullptr) {
if (!pGameSound->playing())
(*pGameSound).midiLoopPlaySegment(1300, 36500, 0, FMT_MILLISEC);
} // end if pGameSound
} // end else..musicenabled check
} //end switch(wParam)
} // end if
ReleaseDC(pDC);
(*this).SetFocus(); // Reset focus back to the main window
return true;
}
/*****************************************************************
*
* OnLButtonDown
*
* FUNCTIONAL DESCRIPTION:
*
* Left mouse button processing function
*
* FORMAL PARAMETERS:
*
* unsigned int nFlags Virtual key info
* CPoint point Location of cursor
*
* IMPLICIT INPUT PARAMETERS:
*
* [External data read]
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* void
*
****************************************************************/
void CMainWindow::OnLButtonDown(unsigned int nFlags, CPoint point) {
CDC *pDC;
CRect rectTitle;
pDC = GetDC();
rectTitle.SetRect(NEWGAME_LOCATION_X, NEWGAME_LOCATION_Y,
NEWGAME_LOCATION_X + NEWGAME_WIDTH,
NEWGAME_LOCATION_Y + NEWGAME_HEIGHT);
if (rectTitle.PtInRect(point) && (pGameInfo->bPlayingMetagame == false)) {
KillTimer(BEACON_TIMER);
bPlaying = false; // Want to get a new piece of artwork
bNewGame = false; // Will be reset to true in NewGame()
MyFocusRect(pDC, colorBlock[nNextIndex - BUTTON_ENTRY].rLocation, false); // erase highlight on nNextIndex
NewGame(); // Activate New Game
char msg[64];
Common::sprintf_s(msg, "Score: %.0f %%", m_Score);
(*m_pScoreTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
if (m_nSweepCount < 0) m_nSweepCount = 0; // Make sure it doesn't go neg
Common::sprintf_s(msg, "Sweeps: %d", m_nSweepCount);
(*m_pSweepTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
}
ReleaseDC(pDC);
CFrameWnd ::OnLButtonDown(nFlags, point);
}
/*****************************************************************
*
* OnLButtonUp
*
* FUNCTIONAL DESCRIPTION:
*
* Standard Left mouse button processing function
*
* FORMAL PARAMETERS:
*
* unsigned int nFlags Virtual key info
* CPoint point Location of cursor
*
* IMPLICIT INPUT PARAMETERS:
*
* [External data read]
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* void
*
****************************************************************/
void CMainWindow::OnLButtonUp(unsigned int nFlags, CPoint point) {
CDC *pDC;
int i;
bool bHit = false;
char msg[64];
pDC = GetDC();
if (!m_bAutomatic && bNewGame) {
for (i = 0; i < NUM_BUTTONS; i++) {
if (colorBlock[i].rLocation.PtInRect(point)) {
bHit = true;
if (pGameInfo->bSoundEffectsEnabled)
sndPlaySound(PICK_SOUND, SND_ASYNC); // Make a noise
MyFocusRect(pDC, colorBlock[nNextIndex - BUTTON_ENTRY].rLocation, false); // erase highlight on nNextIndex
MyFocusRect(pArtDC, colorBlock[nNextIndex - BUTTON_ENTRY].rLocation, false); // erase highlight on nNextIndex
nNextIndex = colorBlock[i].nColorIndex; // make this the next beam color
MyFocusRect(pDC, colorBlock[i].rLocation, true); // draw hightlight on nNextIndex
MyFocusRect(pArtDC, colorBlock[i].rLocation, true); // draw hightlight on nNextIndex
//bar
// SWITCH ON DEMAND:
//bar if ( m_bChangeAtTwelve == false )
//bar nCurrentIndex = nNextIndex; //...switch to the new beacon color
}
} // end for
if (!bPlaying && bHit) { // first time
bPlaying = true;
nCurrentIndex = nNextIndex;
SetTimer(BEACON_TIMER, SPEED_BASE - (m_nSpeed * SPEED_STEP), nullptr);
if (m_nSweeps < MAX_SWEEPS)
Common::sprintf_s(msg, "Sweeps: %d", m_nSweepCount - 1); // Update text on screen
else
Common::sprintf_s(msg, "Sweeps: %d", m_nSweepCount); // Update text on screen
(*m_pSweepTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
}
}
ReleaseDC(pDC);
CFrameWnd ::OnLButtonUp(nFlags, point);
}
/*****************************************************************
*
* OnMouseMove
*
* FUNCTIONAL DESCRIPTION:
*
* Mouse movement processing function
*
* FORMAL PARAMETERS:
*
* unsigned int nFlags Virtual key info
* CPoint point Location of cursor
*
* IMPLICIT INPUT PARAMETERS:
*
* [External data read]
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* void
*
****************************************************************/
void CMainWindow::OnMouseMove(unsigned int nFlags, CPoint point) {
SetCursor(LoadCursor(nullptr, IDC_ARROW)); // Refresh cursor object
CFrameWnd ::OnMouseMove(nFlags, point);
}
/*****************************************************************
*
* OnChar / OnSysKeyDown / OnKeyDown
*
* FUNCTIONAL DESCRIPTION:
*
* Keyboard input handling functions
*
* FORMAL PARAMETERS:
*
* unsigned int nChar Virtual key info
* unsigned int nRepCnt Virtual key info
* unsigned int nFlags Virtual key info
*
* IMPLICIT INPUT PARAMETERS:
*
* [External data read]
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* void
*
****************************************************************/
void CMainWindow::OnChar(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
CFrameWnd ::OnChar(nChar, nRepCnt, nFlags); // default action
}
void CMainWindow::OnSysKeyDown(unsigned int nChar, unsigned int nRepCnt, unsigned int nFlags) {
if ((nChar == VK_F4) && (nFlags & 0x2000)) // terminate app on ALT-F4
PostMessage(WM_CLOSE, 0, 0);
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 Rules dialog
} else if (nChar == VK_F2) { // F2 key is hit
SendMessage(WM_COMMAND, IDC_SCROLL, BN_CLICKED); // Activate the Options dialog
}
}
/*****************************************************************
*
* OnTimer
*
* FUNCTIONAL DESCRIPTION:
*
* Processes Timer events
*
* FORMAL PARAMETERS:
*
* unsigned int nIDEvent The ID of the timer event activated
*
* IMPLICIT INPUT PARAMETERS:
*
* [External data read]
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* void
*
****************************************************************/
void CMainWindow::OnTimer(uintptr nIDEvent) {
CDC *pDC;
char msg[64];
pDC = GetDC();
switch (nIDEvent) {
case BEACON_TIMER:
CheckUnderBeam();
MoveBeam();
if (nSlice == CHANGE_BEAM) { // At the turnover point,
if (pGameInfo->bSoundEffectsEnabled)
sndPlaySound(MID_SOUND, SND_ASYNC); // Make a "you lost" noise
if (m_nSweeps < MAX_SWEEPS) m_nSweepCount--; // If limited sweeps, count down
else m_nSweepCount++; //...or for unlimited, count up
if ((m_nSweeps < MAX_SWEEPS) && (m_nSweepCount != 0))
Common::sprintf_s(msg, "Sweeps: %d", m_nSweepCount - 1); // Update text on screen
else
Common::sprintf_s(msg, "Sweeps: %d", m_nSweepCount); // Update text on screen
(*m_pSweepTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
m_Score = ((float) m_nRemoved / (float) m_nTotalSquares) * 100; // Score is the percentage
if ((m_Score > 99.00) && (m_nRemoved < m_nTotalSquares))
Common::sprintf_s(msg, "Score: 99%%");
else
Common::sprintf_s(msg, "Score: %.0f %%", m_Score); // Update score on screen
(*m_pScoreTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
if (m_bAutomatic) { // Game plays by itself
if (++nNextIndex >= (BUTTON_ENTRY + NUM_BUTTONS)) // Step through colors
nNextIndex = BUTTON_ENTRY;
MyFocusRect(pDC, colorBlock[nCurrentIndex - BUTTON_ENTRY].rLocation, false); // erase highlight on nNextIndex
MyFocusRect(pDC, colorBlock[nNextIndex - BUTTON_ENTRY].rLocation, true); // draw hightlight on nNextIndex
MyFocusRect(pArtDC, colorBlock[nCurrentIndex - BUTTON_ENTRY].rLocation, false); // erase highlight on nNextIndex
MyFocusRect(pArtDC, colorBlock[nNextIndex - BUTTON_ENTRY].rLocation, true); // draw hightlight on nNextIndex
nCurrentIndex = nNextIndex; //...switch to the new beacon color
}
if (m_bChangeAtTwelve)
nCurrentIndex = nNextIndex; //...switch to the new beacon color
if (m_nRemoved >= m_nTotalSquares) {
KillTimer(BEACON_TIMER);
bPlaying = false; // Want to get a new piece of artwork
bNewGame = false; // Will be set to true in NewGame()
if (m_bAutomatic) {
MyFocusRect(pDC, colorBlock[nNextIndex - BUTTON_ENTRY].rLocation, false); // erase highlight on nNextIndex
NewGame();
Common::sprintf_s(msg, "Score: %.0f %%", m_Score);
(*m_pScoreTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
Common::sprintf_s(msg, "Sweeps: %d", m_nSweepCount);
(*m_pSweepTxt).DisplayString(pDC, msg, 16, FW_BOLD, OPTIONS_COLOR);
} else {
if (pGameInfo->bSoundEffectsEnabled)
sndPlaySound(WIN_SOUND, SND_ASYNC); // Make a "you won" noise
CMessageBox GameOverDlg((CWnd *)this, pGamePalette,
"Whooooopeeee!", "You removed them all!");
if (pGameInfo->bPlayingMetagame) {
PostMessage(WM_CLOSE, 0, 0); // and post a program exit
}
}
}
if (m_nSweepCount == 0) {
KillTimer(BEACON_TIMER);
bPlaying = false;
bNewGame = false; // Will be set to true in NewGame()
if (pGameInfo->bSoundEffectsEnabled)
sndPlaySound(LOSE_SOUND, SND_ASYNC); // Make a "you lost" noise
CMessageBox GameOverDlg((CWnd *)this, pGamePalette, "Game over.", "Out of sweeps.");
if (pGameInfo->bPlayingMetagame) {
PostMessage(WM_CLOSE, 0, 0); // and post a program exit
}
}
}
break;
default:
CFrameWnd ::OnTimer(nIDEvent);
break;
}
ReleaseDC(pDC);
}
/**********************************************************
Other functions:
***********************************************************/
/*****************************************************************
*
* MoveBeam
*
* FUNCTIONAL DESCRIPTION:
*
* Moves the lit beam one pie-slice clockwise
*
* FORMAL PARAMETERS:
*
*
* IMPLICIT INPUT PARAMETERS:
*
* [External data read]
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* void
*
****************************************************************/
void CMainWindow::MoveBeam() {
CDC *pDC;
CPalette *pOldPal = nullptr; // Pointer to old palette
PALETTEENTRY tempent[2];
pDC = GetDC();
pOldPal = (*pDC).SelectPalette(pGamePalette, false); // Select in game palette
tempent[1].peRed = 255; // Make entry [1] white
tempent[1].peGreen = 255;
tempent[1].peBlue = 254;
tempent[1].peFlags = PC_RESERVED; // Assign it the "changeable" flag
(*pGamePalette).GetPaletteEntries(nCurrentIndex, 1, (LPPALETTEENTRY)&tempent[0]); // Entry [0] is the chosen
tempent[0].peFlags = PC_RESERVED; //...color & changeable
if (nSlice == START_ENTRY) {
(*pGamePalette).AnimatePalette(nSlice, 1, (LPPALETTEENTRY)&tempent[1]);
(*pGamePalette).AnimatePalette(NUM_BEAMS + START_ENTRY - 1, 1,
(LPPALETTEENTRY)&tempent[0]);
} else
(*pGamePalette).AnimatePalette(nSlice - 1, 2, (LPPALETTEENTRY)tempent);
if (++nSlice >= (NUM_BEAMS + START_ENTRY)) {
nSlice = START_ENTRY;
}
(*pDC).SelectPalette(pOldPal, false); // Select back the old palette
ReleaseDC(pDC);
} // end MoveBeam
/*****************************************************************
*
* CheckUnderBeam
*
* FUNCTIONAL DESCRIPTION:
*
* Checks for beam-matching grid spaces currently under the beam
*
* FORMAL PARAMETERS:
*
*
* IMPLICIT INPUT PARAMETERS:
*
* int nSlice Which pie-slice is currently 'lit' by the beam
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* void
0 deg is at 3 o'clock, and the slices are in order going clockwise
*
****************************************************************/
void CMainWindow::CheckUnderBeam() {
CDC *pDC;
CPoint Start, End;
int radius;
float degrees, x, y, radians, endAngle;
pDC = GetDC();
Start.x = SIDE_BORDER + ART_WIDTH / 2; // Start at the center
Start.y = TOP_BORDER + ART_HEIGHT / 2;
radius = 330; //SQRT(ART_HEIGHT^2 + ART_WIDTH^2)
if (nSlice == START_ENTRY) {
degrees = (float)(NUM_BEAMS - 1) * (float)(360 / NUM_BEAMS);
endAngle = (float)(NUM_BEAMS) * (float)(360 / NUM_BEAMS);
} else {
degrees = ((float)(nSlice - START_ENTRY - 1)) * (float)(360 / NUM_BEAMS); // Get degrees cc-wise from 3 o'clock
endAngle = ((float)(nSlice - START_ENTRY)) * (float)(360 / NUM_BEAMS);
}
while (degrees < endAngle) {
radians = degrees * (float)0.017453292; // Convert to radians
x = (float)cos(radians);
y = (float)sin(radians);
End.x = Start.x + (int)(x * radius);
End.y = Start.y + (int)(y * radius);
bChanged = true;
LineDDA(Start.x, Start.y, End.x, End.y, StepAlongLine, pDC);
degrees += 1.0F;
} // end while
if ((!m_bChangeAtTwelve) && (nCurrentIndex != nNextIndex)) // If we're changing colors on the fly
nCurrentIndex = nNextIndex; //...switch to the new beacon color
//...only at the end of a beam traversal
ReleaseDC(pDC);
} // end CheckUnderBeam
void CALLBACK StepAlongLine(int xpos, int ypos, CDC *cdc) {
CDC *pDC = cdc;
CPoint point;
if (bChanged) {
point.x = xpos;
point.y = ypos;
if (InArtRegion(point) && ((CMainWindow::UnderLighthouse(point) == false) &&
CMainWindow::InPictureSquare(point))) {
bChanged = CMainWindow::CompareColors(pDC, point);
}
}
}
/*****************************************************************
*
* CompareColors
*
* FUNCTIONAL DESCRIPTION:
*
* Compares the color at point with the beam's current color
*
* FORMAL PARAMETERS:
*
*
* IMPLICIT INPUT PARAMETERS:
*
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* bool True if a grid space matched and was modified,
* False if the space did not match
*
****************************************************************/
bool CMainWindow::CompareColors(CDC *pDC, CPoint point) {
CPoint square;
COLORREF test;
byte ar, ag, ab, br, bg, bb;
PALETTEENTRY tempent[1];
unsigned int index;
test = (*pDC).GetPixel(point);
ar = GetRValue(test);
ag = GetGValue(test);
ab = GetBValue(test);
(*pGamePalette).GetPaletteEntries(nCurrentIndex, 1, (LPPALETTEENTRY)tempent);
br = tempent[0].peRed;
bg = tempent[0].peGreen;
bb = tempent[0].peBlue;
if ((ar == br) && ((ag == bg) && (ab == bb))) { // Matches the beam
square = PointToGrid(point);
square.x = (square.x * GRID_WIDTH) + SIDE_BORDER;
square.y = (square.y * GRID_HEIGHT) + TOP_BORDER;
DrawPart(pDC, square, square, GRID_WIDTH, GRID_HEIGHT);
DrawPart(pArtDC, square, square, GRID_WIDTH, GRID_HEIGHT);
m_nRemoved++;
square = PointToGrid(point);
PictureGrid[square.x][square.y] = false;
return true;
}
index = (*pGamePalette).GetNearestPaletteIndex(test); // get the nearest index of test color
if (((index < BUTTON_ENTRY) && (index >= START_ENTRY)) // if it's in the beam area
&& (index != nSlice)) // and doesn't match the beam's index
return false; //true ); //
return false;
} // end CompareColors
/*****************************************************************
*
* UnderLighthouse
*
* FUNCTIONAL DESCRIPTION:
*
* Checks to see if the point lies under the lighthouse area
*
* FORMAL PARAMETERS:
*
* CPoint point point to check
*
* IMPLICIT INPUT PARAMETERS:
*
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* bool True if point lies under the lighthouse area,
* False if the point isn't
*
****************************************************************/
bool CMainWindow::UnderLighthouse(CPoint point) {
if ((point.x >= (SIDE_BORDER + ART_WIDTH / 2 - START_OFFSET_X)) &&
(point.x <= (SIDE_BORDER + ART_WIDTH / 2 + START_OFFSET_X))) {
if ((point.y >= (TOP_BORDER + ART_HEIGHT / 2 - START_OFFSET_Y)) &&
(point.y <= (TOP_BORDER + ART_HEIGHT / 2 + (START_HEIGHT - START_OFFSET_Y)))) {
return true;
}
}
return false;
} // end CompareColors
/*****************************************************************
*
* InPictureSquare()
*
* FUNCTIONAL DESCRIPTION:
*
* Checks to see if the point lies in a grid space filled with picture color
*
* FORMAL PARAMETERS:
*
* CPoint point point to check
*
* IMPLICIT INPUT PARAMETERS:
*
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* bool True if point lies in a picture-filled grid space,
* False if the point doesn't
*
****************************************************************/
bool CMainWindow::InPictureSquare(CPoint point) {
CPoint Grid;
Grid = PointToGrid(point);
return PictureGrid[Grid.x][Grid.y];
}
/*****************************************************************
*
* PointToGrid()
*
* FUNCTIONAL DESCRIPTION:
*
* Finds the x & y gridspace for the given point
*
* FORMAL PARAMETERS:
*
* CPoint point point to check
*
* IMPLICIT INPUT PARAMETERS:
*
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* CPoint NewPoint The grid coords for the given point
*
****************************************************************/
CPoint CMainWindow::PointToGrid(CPoint point) {
CPoint New;
New.x = point.x - SIDE_BORDER; // Put point into Art Space
New.y = point.y - TOP_BORDER;
New.x = (int) New.x / GRID_WIDTH; // Get the grid space coord's
New.y = (int) New.y / GRID_HEIGHT;
return New; // Return the coord's
}
/*****************************************************************
*
* LoadArtWork
*
* FUNCTIONAL DESCRIPTION:
*
* Loads the Artwork to the Screen
*
* FORMAL PARAMETERS:
*
* none
*
* IMPLICIT INPUT PARAMETERS:
*
* none
*
* IMPLICIT OUTPUT PARAMETERS:
*
* none
*
* RETURN VALUE:
*
* none
*
****************************************************************/
bool CMainWindow::LoadArtWork(CDC *pDC) {
// CBitmap *pNextArt = nullptr;
CPalette *pTempPalette = nullptr,
*pPalOld = nullptr;
CPoint Src;
CRect rcDest; // Art work - frame bitmap dims
CRect rcDIB; // Source area for Art Work bmp
HDIB hDIB;
char ArtName[MAX_FILE_LENGTH];
int nNumEntries;
char chNumEntries[5];
int i, pick = 1;
ifstream inFile;
inFile.open(DATA_FILE); // open the data store
if (inFile.fail()) {
return false;
}
inFile.getline(chNumEntries, sizeof(chNumEntries)); // read number of names in file
nNumEntries = atoi(chNumEntries);
pick = nLastPick;
assert(nNumEntries > 0);
while (pick == nLastPick) {
pick = (brand() % nNumEntries) + 1;
}
Common::strcpy_s(ArtName, "");
for (i = 0; i < pick; i++) {
if (!inFile.eof())
inFile.getline(ArtName, sizeof(ArtName)); // load a name
}
inFile.close(); // close the data store
nLastPick = pick;
CDibDoc *pSourceDoc;
pSourceDoc = new CDibDoc();
ASSERT(pSourceDoc != nullptr);
if (pSourceDoc == nullptr) {
return false;
}
char bufName[MAX_FILE_LENGTH + 10];
Common::sprintf_s(bufName, ".\\ART\\%s", ArtName);
(*pSourceDoc).OpenDocument(bufName);
ASSERT(pTempPalette == nullptr);
pTempPalette = (*pSourceDoc).DetachPalette(); // Acquire the shared palette for our game from the art
pPalOld = (*pDC).SelectPalette(pGamePalette, false); // Select Game Palette
(*pDC).RealizePalette(); // Use it
// Transfer the button colors to Game Palette
LPPALETTEENTRY ButtonEntry[NUM_BUTTONS];
(*pTempPalette).GetPaletteEntries(BUTTON_ENTRY, NUM_BUTTONS, (LPPALETTEENTRY)ButtonEntry);
(*pGamePalette).SetPaletteEntries(BUTTON_ENTRY, NUM_BUTTONS, (LPPALETTEENTRY)ButtonEntry);
(*pDC).RealizePalette();
hDIB = (*pSourceDoc).GetHDIB();
if (hDIB) {
rcDest.SetRect(SIDE_BORDER, TOP_BORDER, ART_WIDTH + SIDE_BORDER, ART_HEIGHT + TOP_BORDER);
int cxDIB = (int) DIBWidth(hDIB);
int cyDIB = (int) DIBHeight(hDIB);
if (cxDIB > ART_WIDTH) { // Center and crop
rcDIB.left = (cxDIB - ART_WIDTH) / 2; //...too wide art
while (rcDIB.left % 5 != 0) {
rcDIB.left++;
}
rcDIB.right = rcDIB.left + ART_WIDTH;
} else { // Stretch too thin art
rcDIB.left = 0;
rcDIB.right = ART_WIDTH; //cxDIB;
}
if (cyDIB > ART_HEIGHT) { // Center and crop
rcDIB.top = (cyDIB - ART_HEIGHT) / 2; //...too long art
while (rcDIB.top % 5 != 0) {
rcDIB.top++;
}
rcDIB.bottom = rcDIB.top + ART_HEIGHT;
} else { // Stretch too short art
rcDIB.top = 0;
rcDIB.bottom = ART_HEIGHT; //cyDIB;
}
PaintDIB((*pDC).m_hDC, &rcDest, hDIB, &rcDIB, pGamePalette);
}
Src.x = SIDE_BORDER + (ART_WIDTH / 2) - START_OFFSET_X;
Src.y = TOP_BORDER + (ART_HEIGHT / 2) - START_OFFSET_Y;
DrawPart(pDC, Src, Src, START_WIDTH, START_HEIGHT);
for (i = 0; i < NUM_BUTTONS; i++) {
CBrush *pMyBrush = nullptr;
pMyBrush = new CBrush(); // Construct new brush
(*pMyBrush).CreateSolidBrush(PALETTEINDEX((uint16)(colorBlock[i].nColorIndex)));
(*pArtDC).FillRect(colorBlock[i].rLocation, pMyBrush);
MyFocusRect(pArtDC, colorBlock[i].rLocation, false); // standard highlight on button
pMyBrush->DeleteObject();
delete pMyBrush;
pMyBrush = nullptr;
}
pBeaconBitmap = FetchResourceBitmap(pDC, nullptr, IDB_BEACON_BMP); // Add the lighthouse
(*pDC).SelectPalette(pPalOld, false);
pTempPalette->DeleteObject();
delete pTempPalette;
delete pSourceDoc;
pSourceDoc = nullptr;
return true;
} // end LoadArtWork()
/*****************************************************************
*
* DrawPart
*
* FUNCTIONAL DESCRIPTION:
*
* Draws a section of the source artwork to the scratch bitmap
*
* FORMAL PARAMETERS:
*
* CPoint Src Location of source area
* CPoint Dst Location of destination area
*
* IMPLICIT INPUT PARAMETERS:
*
* [External data read]
*
* IMPLICIT OUTPUT PARAMETERS:
*
* [External data modified]
*
* RETURN VALUE:
*
* void
*
****************************************************************/
void CMainWindow::DrawPart(CDC *pDC, CPoint Src, CPoint Dst, int nWidth, int nHeight) {
pDC->BitBlt(Dst.x, Dst.y, nWidth, nHeight, pBackDC, Src.x, Src.y, SRCCOPY);
} //End DrawPart();
/*****************************************************************
*
* InArtRegion
*
* FUNCTIONAL DESCRIPTION:
*
* Checks to see if a point is within the Artwork region of the window
*
* FORMAL PARAMETERS:
*
* CPoint point The point to check
*
* IMPLICIT INPUT PARAMETERS:
*
* Extents of the main game window, and the extents of the artwork
*
* IMPLICIT OUTPUT PARAMETERS:
*
* none
*
* RETURN VALUE:
*
* bool: true if point is within the Art Region,
* false if point is outside the Art Region
*
****************************************************************/
bool InArtRegion(CPoint point) {
if ((point.x > SIDE_BORDER && point.x < (ART_WIDTH + SIDE_BORDER)) && // See if point lies within
(point.y > TOP_BORDER && point.y < (ART_HEIGHT + TOP_BORDER))) //...ArtWork area
return true; // Return true if it's inside
else return false; //...and false if not
}
/*****************************************************************
*
* MyFocusRect( CDC *pDC, CRect rect, int nDrawMode )
*
* FUNCTIONAL DESCRIPTION:
*
* Draws a rectangle which inverts the current pixels,
* thereby delineating the current area of focus.
*
* FORMAL PARAMETERS:
*
* CDC *pDC The Device context in which the FocusRect is to be drawn
* CRect rect The CRect object holding the location of the FocusRect
*
* IMPLICIT INPUT PARAMETERS:
*
* pMyPen and pMyBrush, global pointers to the Pen and Brush used
*
* IMPLICIT OUTPUT PARAMETERS:
*
* none
*
* RETURN VALUE:
*
* void
*
****************************************************************/
void MyFocusRect(CDC *pDC, CRect rect, bool nPressed) {
CBrush *pMyBrush = nullptr; // New Brush
CBrush *pOldBrush = nullptr; // Pointer to old brush
CPen *pLitePen = nullptr; // New Pen
CPen *pDarkPen = nullptr; // Dark Pen
CPen *pOldPen = nullptr; // Pointer to old pen
CPalette *pPalOld = nullptr; // Pointer to old palette
LOGBRUSH lb; // log brush type
lb.lbStyle = BS_HOLLOW; // Don't fill in area
pMyBrush = new CBrush(); // Construct new brush
pMyBrush->CreateBrushIndirect(&lb); // Create a new brush
pDarkPen = new CPen(); // Construct new pen
pLitePen = new CPen(); // Construct new pen
pLitePen->CreatePen(PS_INSIDEFRAME, HILITE_BORDER,
PALETTEINDEX((uint16)(LITE_TRIM))); // Create a new pen
pDarkPen->CreatePen(PS_INSIDEFRAME, HILITE_BORDER,
PALETTEINDEX((uint16)(DARK_TRIM))); // Create a new pen
pPalOld = (*pDC).SelectPalette(pGamePalette, false); // Select in game palette
(*pDC).RealizePalette(); // Use it
pOldBrush = pDC->SelectObject(pMyBrush); // Select the new brush & save old
if (nPressed)
pOldPen = pDC->SelectObject(pDarkPen); // Select the new pen & save old
else
pOldPen = pDC->SelectObject(pLitePen); // Select the new pen & save old
pDC->MoveTo(rect.TopLeft().x + HILITE_BORDER / 2, rect.BottomRight().y - HILITE_BORDER / 2);
pDC->LineTo(rect.TopLeft().x + HILITE_BORDER / 2, rect.TopLeft().y + HILITE_BORDER / 2);
pDC->LineTo(rect.BottomRight().x - HILITE_BORDER / 2, rect.TopLeft().y + HILITE_BORDER / 2);
if (nPressed)
pDC->SelectObject(pLitePen); // Select the new pen & save old
else
pDC->SelectObject(pDarkPen); // Select the new pen & save old
pDC->LineTo(rect.BottomRight().x - HILITE_BORDER / 2, rect.BottomRight().y - HILITE_BORDER / 2);
pDC->LineTo(rect.TopLeft().x + HILITE_BORDER / 2, rect.BottomRight().y - HILITE_BORDER / 2);
pDC->SelectObject(pOldPen); // Select the old pen
pDC->SelectObject(pOldBrush); // Select the old brush
(*pDC).SelectPalette(pPalOld, false); // Select back the old palette
pMyBrush->DeleteObject();
delete pMyBrush;
pMyBrush = nullptr;
pLitePen->DeleteObject();
delete pLitePen;
pLitePen = nullptr;
pDarkPen->DeleteObject();
delete pDarkPen;
pDarkPen = nullptr;
} // End MyFocusRect()
/*****************************************************************
*
* NewGame
*
* FUNCTIONAL DESCRIPTION:
*
* Sets several global variables to their default or initial states
*
* FORMAL PARAMETERS:
*
* none
*
* IMPLICIT INPUT PARAMETERS:
*
*
*
* IMPLICIT OUTPUT PARAMETERS:
*
* none
*
* RETURN VALUE:
*
* void
*
****************************************************************/
void CMainWindow::NewGame() {
CDC *pDC;
CPalette *pOldPal = nullptr;
CBrush *pBrushNew = nullptr,
*pBrushOld = nullptr;
int i, j;
for (i = 0; i < NUM_COLUMNS; i++) {
for (j = 0; j < NUM_ROWS; j++) {
PictureGrid[i][j] = true; // Assume they all start with picture in 'em
}
}
pDC = GetDC();
pOldPal = pDC->SelectPalette(pGamePalette, false); // select the game palette
pDC->RealizePalette(); //...and realize it
pBrushNew = new CBrush(); // Construct a new brush object
if (pBrushNew != nullptr) { // If the constructor was successful:
pBrushNew->CreateSolidBrush(PALETTERGB(0, 0, 0)); // Create my backdrop color brush
pBrushOld = (*pDC).SelectObject(pBrushNew); // Select into the DC my new brush
(*pDC).Rectangle(SIDE_BORDER, TOP_BORDER, ART_WIDTH + SIDE_BORDER, ART_HEIGHT + TOP_BORDER);
(*pDC).SelectObject(pBrushOld); // Select in the old brush
(*pDC).SelectPalette(pOldPal, false); // Select in the old palette
delete pBrushNew; // Delete the new brush
}
LoadArtWork(pArtDC); // Get a new picture
SetBeamEntries(pDC);
pOldPal = pDC->SelectPalette(pGamePalette, false); // select the game palette
pDC->RealizePalette(); //...and realize it
pDC->BitBlt(SIDE_BORDER, TOP_BORDER, GAME_WIDTH - (2 * SIDE_BORDER), GAME_HEIGHT - (2 * BOTTOM_BORDER),
pArtDC, SIDE_BORDER, TOP_BORDER, SRCCOPY); // Put it on-screen
PaintMaskedBitmap(pDC, pGamePalette, pBeaconBitmap,
SIDE_BORDER + (ART_WIDTH / 2) - LTHOUSE_OFFSET_X,
TOP_BORDER + (ART_HEIGHT / 2) - LTHOUSE_OFFSET_Y);
nSlice = CHANGE_BEAM; // Start at 12 o'clock
m_nRemoved = 0;
m_Score = 0;
if (pGameInfo->bPlayingMetagame) {
switch (pGameInfo->nSkillLevel) {
case SKILLLEVEL_LOW:
m_nSweeps = 20;
m_nSpeed = MIN_SPEED + 1; // middle speed = 1
break;
case SKILLLEVEL_MEDIUM:
m_nSweeps = 18;
m_nSpeed = MAX_SPEED;
break;
case SKILLLEVEL_HIGH:
default:
m_nSweeps = 15;
m_nSpeed = MAX_SPEED;
break;
} //end switch
} else {
m_nSweeps = tempSweeps;
m_nSpeed = tempSpeed;
}
if (m_nSweeps == MAX_SWEEPS)
m_nSweepCount = 0;
else
m_nSweepCount = m_nSweeps;
if (m_bAutomatic) {
nCurrentIndex = BUTTON_ENTRY;
nNextIndex = BUTTON_ENTRY;
SetTimer(BEACON_TIMER, SPEED_BASE - (m_nSpeed * SPEED_STEP), nullptr);
MyFocusRect(pDC, colorBlock[nNextIndex - BUTTON_ENTRY].rLocation, true); // draw hightlight on nNextIndex
}
(*pDC).SelectPalette(pOldPal, false);
ReleaseDC(pDC);
bNewGame = true;
} // End NewGame()
void CMainWindow::SetBeamEntries(CDC *pDC) {
PALETTEENTRY entry[NUM_BEAMS];
int i;
pDC->SelectPalette(pGamePalette, false); // select the game palette
pDC->RealizePalette(); //...and realize it
for (i = 0; i < (NUM_BEAMS); i++) { // Set palette area to animate for beacon + NUM_BUTTONS
entry[i].peRed = 0;//i*2; //...light and button colors to black, and
entry[i].peGreen = 0; //...make peFlags Reserved, so they can
entry[i].peBlue = 1;//i*2; //...be changed later
entry[i].peFlags = PC_RESERVED;
}
(*pGamePalette).SetPaletteEntries(START_ENTRY, NUM_BEAMS, (LPPALETTEENTRY)entry);
pDC->RealizePalette(); //...and realize it
} // End SetBeamEntries
void CMainWindow::OnClose() {
CDC *pDC;
CBrush myBrush;
CRect myRect;
KillTimer(BEACON_TIMER);
pDC = GetDC();
myRect.SetRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
myBrush.CreateStockObject(BLACK_BRUSH);
(*pDC).FillRect(&myRect, &myBrush);
ReleaseDC(pDC);
sndPlaySound(nullptr, SND_ASYNC); // kill any wav that's playing
m_Score = ((float) m_nRemoved / (float) m_nTotalSquares) * 100; // Score is the percentage
if (pGameInfo->bPlayingMetagame)
pGameInfo->lScore = (long)(m_Score + 0.5);
if (pGameSound != nullptr) {
delete pGameSound;
pGameSound = nullptr;
}
if (m_pScoreTxt != nullptr)
delete m_pScoreTxt;
if (m_pSweepTxt != nullptr)
delete m_pSweepTxt;
if (pScrollUp != nullptr) {
pScrollUp->DeleteObject();
pScrollUp = nullptr;
}
if (pScrollDown != nullptr) {
pScrollDown->DeleteObject();
pScrollDown = nullptr;
}
if (m_pScrollButton != nullptr)
delete m_pScrollButton;
if (pBeaconBitmap != nullptr) {
pBeaconBitmap->DeleteObject();
delete pBeaconBitmap;
}
if (pOldBmp1 != nullptr) // Get rid of Source
pBackDC->SelectObject(pOldBmp1);
if (pOldPal1 != nullptr)
pBackDC->SelectPalette(pOldPal1, false);
if (pBackDC->m_hDC != nullptr) {
pBackDC->DeleteDC();
delete pBackDC;
}
pBackBitmap->DeleteObject();
delete pBackBitmap;
if (pOldBmp2 != nullptr) // Get rid of Source
pArtDC->SelectObject(pOldBmp2);
if (pOldPal2 != nullptr)
pArtDC->SelectPalette(pOldPal2, false);
if (pArtDC->m_hDC != nullptr) {
pArtDC->DeleteDC();
delete pArtDC;
}
pArtBitmap->DeleteObject();
delete pArtBitmap;
if (pGamePalette != nullptr) {
pGamePalette->DeleteObject();
delete pGamePalette;
}
CFrameWnd::OnClose();
MFC::PostMessage(ghParentWnd, WM_PARENTNOTIFY, WM_DESTROY, 0L);
}
void CALLBACK GetSubOptions(CWnd* pParentWind) {
COptnDlg OptionsDlg(pParentWind, pGamePalette); // Call Specific Game
m_Score = ((float) m_nRemoved / (float) m_nTotalSquares) * 100;
OptionsDlg.m_nSweeps = m_nSweeps;
OptionsDlg.m_bAutomatic = m_bAutomatic;
OptionsDlg.m_bChangeAtTwelve = m_bChangeAtTwelve;
OptionsDlg.m_nSpeed = m_nSpeed;
if (OptionsDlg.DoModal() == IDOK) { // save values set in dialog box
tempSweeps = OptionsDlg.m_nSweeps; // sweeps takes effect on new game
m_bAutomatic = OptionsDlg.m_bAutomatic;
m_bChangeAtTwelve = OptionsDlg.m_bChangeAtTwelve; // change point takes effect immediately
tempSpeed = OptionsDlg.m_nSpeed;
m_nSpeed = tempSpeed; // speed takes effect immediately
}
}
//////////// 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.
//
}
// CMainWindow message map:
// Associate messages with member functions.
//
BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd)
//{{AFX_MSG_MAP( CMainWindow )
ON_WM_PAINT()
ON_WM_CHAR()
ON_WM_SYSKEYDOWN()
ON_WM_KEYDOWN()
ON_WM_TIMER()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_DESTROY()
ON_WM_CLOSE()
ON_MESSAGE(MM_MCINOTIFY, CMainWindow::OnMCINotify)
ON_MESSAGE(MM_WOM_DONE, CMainWindow::OnMMIONotify)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
} // namespace Beacon
} // namespace HodjNPodj
} // namespace Bagel