Proper event loop, menus, and more

* Added a proper event loop
* Added minimal menu bars
* Added about menu
* GameWindow initializes a GameEngine (even if you can't play it yet)
* Updated variable naming conventions
This commit is contained in:
Jon Thysell 2021-10-15 17:29:07 -07:00
parent 6184d31e6a
commit 2ce4236ea7
11 changed files with 251 additions and 65 deletions

View File

@ -12,53 +12,55 @@ const uint8_t MinHalfStars = 1;
const uint16_t PerfectScore = 300; // LevelCount * MaxHalfStars const uint16_t PerfectScore = 300; // LevelCount * MaxHalfStars
void GameEngine_LoadLevel(GameEngine *engine, const int8_t level, const bool setB) void GameEngine_ToggleSingleLight(GameEngine *pGameEngine, const int8_t x, const int8_t y);
void GameEngine_LoadLevel(GameEngine *pGameEngine, const int8_t level, const bool setB)
{ {
engine->Level = Levels_BoundLevel(level); pGameEngine->Level = Levels_BoundLevel(level);
engine->Lights = Levels_GetLightsForLevel(engine->Level, setB); pGameEngine->Lights = Levels_GetLightsForLevel(pGameEngine->Level, setB);
engine->Par = Levels_GetParForLevel(engine->Level); pGameEngine->Par = Levels_GetParForLevel(pGameEngine->Level);
engine->Moves = 0; pGameEngine->Moves = 0;
} }
bool GameEngine_GetLight(const GameEngine *engine, const int8_t x, const int8_t y) bool GameEngine_GetLight(const GameEngine *pGameEngine, const int8_t x, const int8_t y)
{ {
if (x >= 0 && x < PuzzleSize && y >= 0 && y < PuzzleSize) if (x >= 0 && x < PuzzleSize && y >= 0 && y < PuzzleSize)
{ {
return bitRead(engine->Lights, y * PuzzleSize + x); return bitRead(pGameEngine->Lights, y * PuzzleSize + x);
} }
return false; return false;
} }
bool GameEngine_IsCompleted(const GameEngine *engine) bool GameEngine_IsCompleted(const GameEngine *pGameEngine)
{ {
return engine->Lights == 0; return pGameEngine->Lights == 0;
} }
uint8_t GameEngine_GetHalfStars(const GameEngine *engine) uint8_t GameEngine_GetHalfStars(const GameEngine *pGameEngine)
{ {
uint8_t halfStarsLost = engine->Moves <= engine->Par ? 0 : max(0, (1 + engine->Moves - engine->Par) / 2); uint8_t halfStarsLost = pGameEngine->Moves <= pGameEngine->Par ? 0 : max(0, (1 + pGameEngine->Moves - pGameEngine->Par) / 2);
return max(MinHalfStars, MaxHalfStars - halfStarsLost); return max(MinHalfStars, MaxHalfStars - halfStarsLost);
} }
void GameEngine_ToggleSingleLight(GameEngine *engine, const int8_t x, const int8_t y) void GameEngine_ToggleLights(GameEngine *pGameEngine, const int8_t x, const int8_t y)
{
if (x >= 0 && x < PuzzleSize && y >= 0 && y < PuzzleSize)
{
bitToggle(engine->Lights, y * PuzzleSize + x);
}
}
void GameEngine_ToggleLights(GameEngine *engine, const int8_t x, const int8_t y)
{ {
int8_t targetX = max(0, min(x, PuzzleSize - 1)); int8_t targetX = max(0, min(x, PuzzleSize - 1));
int8_t targetY = max(0, min(y, PuzzleSize - 1)); int8_t targetY = max(0, min(y, PuzzleSize - 1));
GameEngine_ToggleSingleLight(engine, targetX, targetY); GameEngine_ToggleSingleLight(pGameEngine, targetX, targetY);
GameEngine_ToggleSingleLight(engine, targetX + 1, targetY); GameEngine_ToggleSingleLight(pGameEngine, targetX + 1, targetY);
GameEngine_ToggleSingleLight(engine, targetX, targetY + 1); GameEngine_ToggleSingleLight(pGameEngine, targetX, targetY + 1);
GameEngine_ToggleSingleLight(engine, targetX - 1, targetY); GameEngine_ToggleSingleLight(pGameEngine, targetX - 1, targetY);
GameEngine_ToggleSingleLight(engine, targetX, targetY - 1); GameEngine_ToggleSingleLight(pGameEngine, targetX, targetY - 1);
engine->Moves++; pGameEngine->Moves++;
}
void GameEngine_ToggleSingleLight(GameEngine *pGameEngine, const int8_t x, const int8_t y)
{
if (x >= 0 && x < PuzzleSize && y >= 0 && y < PuzzleSize)
{
bitToggle(pGameEngine->Lights, y * PuzzleSize + x);
}
} }

View File

@ -16,20 +16,20 @@ extern const uint16_t PerfectScore;
typedef struct GameEngine typedef struct GameEngine
{ {
int8_t Level; int8_t Level;
uint32_t Lights; uint32_t Lights;
uint16_t Par; uint16_t Par;
uint16_t Moves; uint16_t Moves;
} GameEngine; } GameEngine;
void GameEngine_LoadLevel(GameEngine *engine, const int8_t level, const bool setB); void GameEngine_LoadLevel(GameEngine *pGameEngine, const int8_t level, const bool setB);
bool GameEngine_GetLight(const GameEngine *engine, const int8_t x, const int8_t y); bool GameEngine_GetLight(const GameEngine *pGameEngine, const int8_t x, const int8_t y);
bool GameEngine_IsCompleted(const GameEngine *engine); bool GameEngine_IsCompleted(const GameEngine *pGameEngine);
uint8_t GameEngine_GetHalfStars(const GameEngine *engine); uint8_t GameEngine_GetHalfStars(const GameEngine *pGameEngine);
void GameEngine_ToggleLights(GameEngine *engine, const int8_t x, const int8_t y); void GameEngine_ToggleLights(GameEngine *pGameEngine, const int8_t x, const int8_t y);
#endif #endif

View File

@ -3,27 +3,34 @@
#include "GameWindow.h" #include "GameWindow.h"
void GameWindow_Init(GameWindow *gameWindow) void GameWindow_Init(GameWindow *pGameWindow)
{ {
if (gameWindow->Window != nil) if (pGameWindow->Window != nil)
{ {
ShowError("\pGameWindow already initialized!", false); ShowError("\pGameWindow already initialized!", false);
} }
gameWindow->Window = GetNewWindow(kBaseResID, nil, kMoveToFront); pGameWindow->Window = GetNewWindow(BaseResID, nil, MoveToFront);
if (gameWindow->Window == nil) if (pGameWindow->Window == nil)
{ {
ShowError("\pGameWindow resource WIND kBaseResID missing!", true); ShowError("\pGameWindow resource WIND BaseResID missing!", true);
} }
CenterWindow(gameWindow->Window); GameEngine_LoadLevel(&(pGameWindow->Engine), 0, false);
ShowWindow(gameWindow->Window); CenterWindow(pGameWindow->Window);
SetPort(gameWindow->Window); }
void GameWindow_Draw(GameWindow *pGameWindow)
{
SetPort(pGameWindow->Window);
MoveTo(10, 20); MoveTo(10, 20);
DrawString("\pHello MacLO"); DrawString("\pHello MacLO");
} }
void GameWindow_Show(GameWindow *pGameWindow)
{
ShowWindow(pGameWindow->Window);
}

View File

@ -5,12 +5,16 @@
#define GAMEWINDOW_H #define GAMEWINDOW_H
#include "MacCommon.h" #include "MacCommon.h"
#include "GameEngine.h"
typedef struct GameWindow typedef struct GameWindow
{ {
WindowPtr Window; WindowPtr Window;
GameEngine Engine;
} GameWindow; } GameWindow;
void GameWindow_Init(GameWindow *gameWindow); void GameWindow_Init(GameWindow *pGameWindow);
void GameWindow_Draw(GameWindow *pGameWindow);
void GameWindow_Show(GameWindow *pGameWindow);
#endif #endif

View File

@ -5,19 +5,13 @@
void CenterWindow(WindowPtr window) void CenterWindow(WindowPtr window)
{ {
// TODO
}
Boolean IsCompactDisplay()
{
return screenBits.bounds.right == 512
&& screenBits.bounds.bottom == 342;
} }
void ShowError(Str255 message, Boolean isFatal) void ShowError(Str255 message, Boolean isFatal)
{ {
ParamText(message, kEmptyString, kEmptyString, kEmptyString); ParamText(message, EmptyString, EmptyString, EmptyString);
StopAlert(kErrorAlertID, kNilFilterProc); StopAlert(ErrorAlertResID, NilFilterProc);
if (isFatal) if (isFatal)
{ {

View File

@ -4,13 +4,13 @@
#ifndef MACCOMMON_H #ifndef MACCOMMON_H
#define MACCOMMON_H #define MACCOMMON_H
#define kBaseResID 128 #define BaseResID 128
#define kMoveToFront (WindowPtr)-1L #define MoveToFront (WindowPtr)-1L
#define kEmptyString "\p" #define EmptyString "\p"
#define kNilFilterProc nil #define NilFilterProc nil
#define kErrorAlertID kBaseResID #define ErrorAlertResID BaseResID
void CenterWindow(WindowPtr window); void CenterWindow(WindowPtr window);
Boolean IsCompactDisplay(); Boolean IsCompactDisplay();

View File

@ -4,10 +4,33 @@
#include "GameWindow.h" #include "GameWindow.h"
#include "MacLO.h" #include "MacLO.h"
GameWindow gGameWindow; #define AppleMenuResID BaseResID
#define AboutMenuItemID 1
void MacLO_InitToolBox() #define GameMenuResID BaseResID+1
#define QuitMenuItemID 1
#define AboutDialogResID BaseResID
#define AboutDialogOKID 1
GameWindow gGameWindow;
Boolean gExitApp;
void MacLO_HandleUpdate(const EventRecord *pEvent);
void MacLO_HandleMouseDown(const EventRecord *pEvent);
void MacLO_HandleMenuChoice(const long menuChoice);
void MacLO_HandleAppleMenuChoice(const short item);
void MacLO_ShowAboutDialog();
void MacLO_LaunchAppleMenuItem(const short item);
void MacLO_HandleGameMenuChoice(const short item);
void MacLO_ToolBoxInit()
{ {
MaxApplZone();
InitGraf(&thePort); InitGraf(&thePort);
InitFonts(); InitFonts();
InitWindows(); InitWindows();
@ -18,13 +41,169 @@ void MacLO_InitToolBox()
InitCursor(); InitCursor();
} }
void MacLO_InitWindows() void MacLO_AppInit()
{ {
Handle menuBar;
MenuHandle appleMenu;
// Add the menu bar
menuBar = GetNewMBar(BaseResID);
SetMenuBar(menuBar);
// Populate the apple menu
appleMenu = GetMHandle(AppleMenuResID);
AddResMenu(appleMenu, 'DRVR');
DrawMenuBar();
// Setup the game window
GameWindow_Init(&gGameWindow); GameWindow_Init(&gGameWindow);
GameWindow_Draw(&gGameWindow);
GameWindow_Show(&gGameWindow);
} }
void MacLO_MainLoop() void MacLO_MainLoop()
{ {
while (!Button()) { } EventRecord event;
char cmdChar;
while (!gExitApp)
{
if (WaitNextEvent(everyEvent, &event, LONG_MAX, nil))
{
switch (event.what)
{
case updateEvt:
MacLO_HandleUpdate(&event);
break;
case mouseDown:
MacLO_HandleMouseDown(&event);
break;
case keyDown:
case autoKey:
// Translate command key combos to menu items
cmdChar = event.message & charCodeMask;
if ((event.modifiers & cmdKey) != 0)
{
MacLO_HandleMenuChoice(MenuKey(cmdChar));
}
break;
}
}
}
} }
void MacLO_HandleUpdate(const EventRecord *pEvent)
{
WindowPtr window;
window = (WindowPtr)pEvent->message;
BeginUpdate(window);
if (window == gGameWindow.Window)
{
GameWindow_Draw(&gGameWindow);
}
EndUpdate(window);
}
void MacLO_HandleMouseDown(const EventRecord *pEvent)
{
WindowPtr window;
long windowPart;
long menuChoice;
windowPart = FindWindow(pEvent->where, &window);
switch (windowPart)
{
case inMenuBar:
menuChoice = MenuSelect(pEvent->where);
MacLO_HandleMenuChoice(menuChoice);
case inSysWindow:
SystemClick(pEvent, window);
break;
case inDrag:
DragWindow(window, pEvent->where, &((*GetGrayRgn())->rgnBBox));
break;
}
}
void MacLO_HandleMenuChoice(const long menuChoice)
{
short menu;
short item;
if (menuChoice != 0)
{
menu = HiWord(menuChoice);
item = LoWord(menuChoice);
switch (menu)
{
case AppleMenuResID:
MacLO_HandleAppleMenuChoice(item);
break;
case GameMenuResID:
MacLO_HandleGameMenuChoice(item);
break;
}
HiliteMenu(0);
}
}
void MacLO_HandleAppleMenuChoice(const short item)
{
MenuHandle appleMenu;
Str255 accName;
short accNumber;
switch (item)
{
case AboutMenuItemID:
MacLO_ShowAboutDialog();
break;
default:
MacLO_LaunchAppleMenuItem(item);
break;
}
}
void MacLO_ShowAboutDialog()
{
DialogPtr dialog;
int itemHit;
dialog = GetNewDialog(AboutDialogResID, nil, MoveToFront);
SetPort(dialog);
ShowWindow(dialog);
ModalDialog(nil, &itemHit);
DisposDialog(dialog);
}
void MacLO_LaunchAppleMenuItem(const short item)
{
MenuHandle appleMenu;
Str255 accName;
appleMenu = GetMHandle(AppleMenuResID);
GetItem(appleMenu, item, accName);
OpenDeskAcc(accName);
}
void MacLO_HandleGameMenuChoice(const short item)
{
switch (item)
{
case QuitMenuItemID:
gExitApp = true;
break;
}
}

View File

@ -4,8 +4,8 @@
#ifndef MACLO_H #ifndef MACLO_H
#define MACLO_H #define MACLO_H
void MacLO_InitToolBox(); void MacLO_ToolBoxInit();
void MacLO_InitWindows(); void MacLO_AppInit();
void MacLO_MainLoop(); void MacLO_MainLoop();
#endif #endif

Binary file not shown.

Binary file not shown.

View File

@ -5,7 +5,7 @@
void main(void) void main(void)
{ {
MacLO_InitToolBox(); MacLO_ToolBoxInit();
MacLO_InitWindows(); MacLO_AppInit();
MacLO_MainLoop(); MacLO_MainLoop();
} }