From 66794a224128fa17299e4f6cdbfabd5ef627d634 Mon Sep 17 00:00:00 2001 From: Jon Thysell Date: Sun, 31 Oct 2021 15:13:51 -0700 Subject: [PATCH] Refactored scenes into separate files, added game end, added title logo --- img/title.png | Bin 0 -> 2300 bytes src/GameEndScene.c | 36 ++++++ src/GameEndScene.h | 13 ++ src/GameEngine.c | 7 +- src/GameEngine.h | 2 + src/GameWindow.c | 294 +++++++----------------------------------- src/GameWindow.h | 36 ++---- src/LevelEndScene.c | 51 ++++++++ src/LevelEndScene.h | 13 ++ src/Levels.c | 21 +-- src/Levels.h | 2 - src/MacCommon.c | 18 +++ src/MacCommon.h | 4 + src/MacLO.c | 6 +- src/MacLO.pi.bin | Bin 11520 -> 11776 bytes src/MacLO.pi.rsrc.bin | Bin 3712 -> 8064 bytes src/PlayScene.c | 151 ++++++++++++++++++++++ src/PlayScene.h | 13 ++ src/Scenes.h | 29 +++++ src/TitleScene.c | 64 +++++++++ src/TitleScene.h | 13 ++ 21 files changed, 488 insertions(+), 285 deletions(-) create mode 100644 img/title.png create mode 100644 src/GameEndScene.c create mode 100644 src/GameEndScene.h create mode 100644 src/LevelEndScene.c create mode 100644 src/LevelEndScene.h create mode 100644 src/PlayScene.c create mode 100644 src/PlayScene.h create mode 100644 src/Scenes.h create mode 100644 src/TitleScene.c create mode 100644 src/TitleScene.h diff --git a/img/title.png b/img/title.png new file mode 100644 index 0000000000000000000000000000000000000000..ab096a1b86185de4111fc30141fd61db5606ce99 GIT binary patch literal 2300 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 Wx>0R}Xkfhn0000rsRN literal 0 HcmV?d00001 diff --git a/src/GameEndScene.c b/src/GameEndScene.c new file mode 100644 index 0000000..29a5900 --- /dev/null +++ b/src/GameEndScene.c @@ -0,0 +1,36 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#include "GameEndScene.h" + +void GameEndScene_Init(GameWindow *pGameWindow) +{ +} + +void GameEndScene_Draw(const GameWindow *pGameWindow, bool fullRefresh) +{ + Str255 scoreStr; + + SetPort(pGameWindow->Window); + + // TODO: Proper level end + if (fullRefresh) + { + } + + MoveTo(100, 100); + DrawString("\pGame complete! Click to continue."); + + MoveTo(100, 125); + DrawString("\pScore: "); + NumToString((long)(pGameWindow->Engine.Score), &scoreStr); + DrawString(scoreStr); + DrawString("\p/300"); +} + +void GameEndScene_Click(GameWindow *pGameWindow, const Point *pPosition) +{ + // TODO: Proper click handling + + GameWindow_SetScene(pGameWindow, Title); +} diff --git a/src/GameEndScene.h b/src/GameEndScene.h new file mode 100644 index 0000000..fcfee87 --- /dev/null +++ b/src/GameEndScene.h @@ -0,0 +1,13 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#ifndef GAMEENDSCENE_H +#define GAMEENDSCENE_H + +#include "GameWindow.h" + +void GameEndScene_Init(GameWindow *pGameWindow); +void GameEndScene_Draw(const GameWindow *pGameWindow, bool fullRefresh); +void GameEndScene_Click(GameWindow *pGameWindow, const Point *pPosition); + +#endif diff --git a/src/GameEngine.c b/src/GameEngine.c index 17db1e9..ccb10ab 100644 --- a/src/GameEngine.c +++ b/src/GameEngine.c @@ -37,7 +37,7 @@ void GameEngine_ResetLevel(GameEngine *pGameEngine) void GameEngine_LoadLevel(GameEngine *pGameEngine, const int8_t level, const bool setB) { - pGameEngine->Level = Levels_BoundLevel(level); + pGameEngine->Level = level; pGameEngine->SetB = setB; pGameEngine->Lights = Levels_GetLightsForLevel(pGameEngine->Level, setB); pGameEngine->Par = Levels_GetParForLevel(pGameEngine->Level); @@ -59,6 +59,11 @@ bool GameEngine_IsCompleted(const GameEngine *pGameEngine) return pGameEngine->Lights == 0; } +bool GameEngine_IsGameOver(const GameEngine *pGameEngine) +{ + return pGameEngine->Level >= LevelCount; +} + uint8_t GameEngine_GetHalfStars(const GameEngine *pGameEngine) { uint8_t halfStarsLost = pGameEngine->Moves <= pGameEngine->Par ? 0 : max(0, (1 + pGameEngine->Moves - pGameEngine->Par) / 2); diff --git a/src/GameEngine.h b/src/GameEngine.h index b922306..124bfb2 100644 --- a/src/GameEngine.h +++ b/src/GameEngine.h @@ -34,6 +34,8 @@ bool GameEngine_GetLight(const GameEngine *pGameEngine, const int8_t x, const in bool GameEngine_IsCompleted(const GameEngine *pGameEngine); +bool GameEngine_IsGameOver(const GameEngine *pGameEngine); + uint8_t GameEngine_GetHalfStars(const GameEngine *pGameEngine); void GameEngine_ToggleLights(GameEngine *pGameEngine, const int8_t x, const int8_t y); diff --git a/src/GameWindow.c b/src/GameWindow.c index 57cacec..b929d52 100644 --- a/src/GameWindow.c +++ b/src/GameWindow.c @@ -2,16 +2,10 @@ // Licensed under the MIT License. #include "GameWindow.h" - -void GameWindow_SetLightRect(const GameWindow *pGameWindow, Rect *pRect, const int8_t c, const int8_t r); - -void GameWindow_DrawTitleMode(const GameWindow *pGameWindow, bool fullRefresh); -void GameWindow_DrawPlayMode(const GameWindow *pGameWindow, bool fullRefresh); -void GameWindow_DrawLevelCompleteMode(const GameWindow *pGameWindow, bool fullRefresh); - -void GameWindow_ClickTitleMode(GameWindow *pGameWindow, const Point *pPosition); -void GameWindow_ClickPlayMode(GameWindow *pGameWindow, const Point *pPosition); -void GameWindow_ClickLevelCompleteMode(GameWindow *pGameWindow, const Point *pPosition); +#include "TitleScene.h" +#include "PlayScene.h" +#include "LevelEndScene.h" +#include "GameEndScene.h" void GameWindow_Init(GameWindow *pGameWindow) { @@ -24,24 +18,10 @@ void GameWindow_Init(GameWindow *pGameWindow) if (pGameWindow->Window == nil) { - ShowError("\pGameWindow resource WIND BaseResID missing!", true); + ShowError("\pGameWindow WIND resource missing!", true); } - pGameWindow->GameMode = Title; - - // Setup rects - pGameWindow->PlayfieldRect.top = PlayfieldMargin; - pGameWindow->PlayfieldRect.bottom = pGameWindow->Window->portRect.bottom - PlayfieldMargin; - pGameWindow->PlayfieldRect.left = pGameWindow->PlayfieldRect.top; - pGameWindow->PlayfieldRect.right = pGameWindow->PlayfieldRect.bottom; - - pGameWindow->HUDRect.top = HUDMargin; - pGameWindow->HUDRect.bottom = pGameWindow->Window->portRect.bottom - HUDMargin; - pGameWindow->HUDRect.left = pGameWindow->PlayfieldRect.right + HUDMargin; - pGameWindow->HUDRect.right = pGameWindow->Window->portRect.right - HUDMargin; - - // Load first level - GameEngine_LoadLevel(&(pGameWindow->Engine), 0, false); + GameWindow_SetScene(pGameWindow, Title); } void GameWindow_Draw(const GameWindow *pGameWindow, bool fullRefresh) @@ -56,245 +36,69 @@ void GameWindow_Draw(const GameWindow *pGameWindow, bool fullRefresh) FillRect(pContentRect, WindowPattern); } - switch (pGameWindow->GameMode) + switch (pGameWindow->CurrentSceneId) { case Title: - GameWindow_DrawTitleMode(pGameWindow, fullRefresh); + TitleScene_Draw(pGameWindow, fullRefresh); break; case Play: - GameWindow_DrawPlayMode(pGameWindow, fullRefresh); + PlayScene_Draw(pGameWindow, fullRefresh); break; - case LevelComplete: - GameWindow_DrawLevelCompleteMode(pGameWindow, fullRefresh); + case LevelEnd: + LevelEndScene_Draw(pGameWindow, fullRefresh); + break; + case GameEnd: + GameEndScene_Draw(pGameWindow, fullRefresh); break; } } -void GameWindow_SetLightRect(const GameWindow *pGameWindow, Rect *pRect, const int8_t c, const int8_t r) +void GameWindow_Click(GameWindow *pGameWindow, const Point *pPosition) { - pRect->top = pGameWindow->PlayfieldRect.top + PlayfieldPadding + LightMargin + (r * (LightMargin + LightSize)); - pRect->bottom = pRect->top + LightSize; - pRect->left = pGameWindow->PlayfieldRect.left + PlayfieldPadding + LightMargin + (c * (LightMargin + LightSize)); - pRect->right = pRect->left + LightSize; + switch (pGameWindow->CurrentSceneId) + { + case Title: + TitleScene_Click(pGameWindow, pPosition); + break; + case Play: + PlayScene_Click(pGameWindow, pPosition); + break; + case LevelEnd: + LevelEndScene_Click(pGameWindow, pPosition); + break; + case GameEnd: + GameEndScene_Click(pGameWindow, pPosition); + break; + } } -void GameWindow_DrawTitleMode(const GameWindow *pGameWindow, bool fullRefresh) +void GameWindow_SetScene(GameWindow *pGameWindow, const SceneId sceneId) { - SetPort(pGameWindow->Window); - - // TODO: Proper title - if (fullRefresh) + GameWindow_Draw(pGameWindow, false); + if (!(pGameWindow->SceneIsInitialized[sceneId])) { - } - - ForeColor(blackColor); - TextFace(bold + outline); - - MoveTo(100, 100); - DrawString("\pMacLO! Click to continue."); - - MoveTo(25, 200); - DrawString("\pSet A."); - - MoveTo(250, 200); - DrawString("\pSet B."); -} - -void GameWindow_DrawPlayMode(const GameWindow *pGameWindow, bool fullRefresh) -{ - int8_t r, c; - Rect lightRect; - Str255 levelStr, parStr, movesStr, halfStarsStr, scoreStr; - - SetPort(pGameWindow->Window); - - if (fullRefresh) - { - // Fill backgrounds - FillRoundRect(&(pGameWindow->PlayfieldRect), PlayfieldCornerSize, PlayfieldCornerSize, PlayfieldPattern); - FillRoundRect(&(pGameWindow->HUDRect), HUDCornerSize, HUDCornerSize, HUDPattern); - } - - // Draw Playfield - - // Draw lights - for (r = 0; r < PuzzleSize; r++) - { - for (c = 0; c < PuzzleSize; c++) + switch (sceneId) { - GameWindow_SetLightRect(pGameWindow, &lightRect, c, r); - - if (GameEngine_GetLight(&(pGameWindow->Engine), c, r)) - { - // Draw ON light - FillRoundRect(&lightRect, LightCornerSize, LightCornerSize, white); - } - else - { - // Draw OFF light - FillRoundRect(&lightRect, LightCornerSize, LightCornerSize, black); - } + case Title: + TitleScene_Init(pGameWindow); + break; + case Play: + PlayScene_Init(pGameWindow); + break; + case LevelEnd: + LevelEndScene_Init(pGameWindow); + break; + case GameEnd: + GameEndScene_Init(pGameWindow); + break; } + pGameWindow->SceneIsInitialized[sceneId] = true; } - - // Draw HUD - - ForeColor(blackColor); - TextFace(bold + outline); - - // Draw Level - MoveTo(pGameWindow->HUDRect.left + 10, pGameWindow->HUDRect.top + 20); - DrawString("\pLevel: "); - NumToString(1L + pGameWindow->Engine.Level, &levelStr); - DrawString(levelStr); - DrawString("\p/50"); - - // Draw Par - MoveTo(pGameWindow->HUDRect.left + 10, pGameWindow->HUDRect.top + 40); - DrawString("\pPar: "); - NumToString((long)(pGameWindow->Engine.Par), &parStr); - DrawString(parStr); - - // Draw Moves - MoveTo(pGameWindow->HUDRect.left + 10, pGameWindow->HUDRect.top + 60); - DrawString("\pMoves: "); - NumToString((long)(pGameWindow->Engine.Moves), &movesStr); - DrawString(movesStr); - DrawString("\p/"); - DrawString(parStr); - - // Draw Stars - MoveTo(pGameWindow->HUDRect.left + 10, pGameWindow->HUDRect.top + 80); - DrawString("\pStars: "); - NumToString((long)GameEngine_GetHalfStars(&(pGameWindow->Engine)), &halfStarsStr); - DrawString(halfStarsStr); - DrawString("\p/6"); - - // Draw Score - MoveTo(pGameWindow->HUDRect.left + 10, pGameWindow->HUDRect.top + 100); - DrawString("\pScore: "); - NumToString((long)(pGameWindow->Engine.Score), &scoreStr); - DrawString(scoreStr); - DrawString("\p/300"); -} - -void GameWindow_DrawLevelCompleteMode(const GameWindow *pGameWindow, bool fullRefresh) -{ - Str255 halfStarsStr; - - SetPort(pGameWindow->Window); - - // TODO: Proper level complete - if (fullRefresh) - { - } - - MoveTo(50, 100); - DrawString("\pLevel complete! Click to continue."); - - MoveTo(50, 125); - DrawString("\pReceived "); - NumToString((long)GameEngine_GetHalfStars(&(pGameWindow->Engine)), &halfStarsStr); - DrawString(halfStarsStr); - DrawString("\p/6 half-stars."); - - MoveTo(25, 200); - DrawString("\pRetry level."); - - MoveTo(250, 200); - DrawString("\pNext level."); + pGameWindow->CurrentSceneId = sceneId; + GameWindow_Draw(pGameWindow, true); } void GameWindow_Show(const GameWindow *pGameWindow) { ShowWindow(pGameWindow->Window); } - -void GameWindow_Click(GameWindow *pGameWindow, const Point *pPosition) -{ - switch (pGameWindow->GameMode) - { - case Title: - GameWindow_ClickTitleMode(pGameWindow, pPosition); - break; - case Play: - GameWindow_ClickPlayMode(pGameWindow, pPosition); - break; - case LevelComplete: - GameWindow_ClickLevelCompleteMode(pGameWindow, pPosition); - break; - } -} - -void GameWindow_ClickTitleMode(GameWindow *pGameWindow, const Point *pPosition) -{ - bool setB; - - // TODO: Proper click handling - - if (pPosition->h < ((pGameWindow->Window->portRect.right - pGameWindow->Window->portRect.left) / 2)) - { - setB = false; - } - else - { - setB = true; - } - - GameEngine_NewGame(&(pGameWindow->Engine), setB); - pGameWindow->GameMode = Play; - GameWindow_Draw(pGameWindow, true); -} - -void GameWindow_ClickPlayMode(GameWindow *pGameWindow, const Point *pPosition) -{ - int8_t r, c; - Rect lightRect; - - if (PtInRect(*pPosition, &(pGameWindow->PlayfieldRect))) - { - // Click within Playfield - for (r = 0; r < PuzzleSize; r++) - { - for (c = 0; c < PuzzleSize; c++) - { - GameWindow_SetLightRect(pGameWindow, &lightRect, c, r); - - if (PtInRect(*pPosition, &lightRect)) - { - GameEngine_ToggleLights(&(pGameWindow->Engine), c, r); - GameWindow_Draw(pGameWindow, false); - break; - } - } - } - - if (GameEngine_IsCompleted(&(pGameWindow->Engine))) - { - // Level was completed in the last click - pGameWindow->GameMode = LevelComplete; - GameWindow_Draw(pGameWindow, true); - } - } - else if (PtInRect(*pPosition, &(pGameWindow->HUDRect))) - { - // Click within HUD - } -} - -void GameWindow_ClickLevelCompleteMode(GameWindow *pGameWindow, const Point *pPosition) -{ - // TODO: Proper click handling - - if (pPosition->h < ((pGameWindow->Window->portRect.right - pGameWindow->Window->portRect.left) / 2)) - { - GameEngine_ResetLevel(&(pGameWindow->Engine)); - } - else - { - GameEngine_NextLevel(&(pGameWindow->Engine)); - } - - pGameWindow->GameMode = Play; - GameWindow_Draw(pGameWindow, true); -} diff --git a/src/GameWindow.h b/src/GameWindow.h index f6298c8..e8af4f2 100644 --- a/src/GameWindow.h +++ b/src/GameWindow.h @@ -6,43 +6,25 @@ #include "MacCommon.h" #include "GameEngine.h" +#include "Scenes.h" -#define WindowPattern black - -#define PlayfieldMargin 4 -#define PlayfieldPadding 2 -#define PlayfieldCornerSize 12 -#define LightMargin 6 -#define LightSize 50 -#define LightCornerSize 8 -#define PlayfieldPattern ltGray - -#define HUDMargin PlayfieldMargin -#define HUDCornerSize PlayfieldCornerSize -#define HUDPattern PlayfieldPattern - -typedef enum GameMode -{ - Title, - Play, - LevelComplete, - GameComplete -} GameMode; +#define WindowPattern black typedef struct GameWindow { WindowPtr Window; GameEngine Engine; - GameMode GameMode; - Rect PlayfieldRect; - Rect HUDRect; + SceneId CurrentSceneId; + bool SceneIsInitialized[NumScenes]; + TitleScene TitleScene; + PlayScene PlayScene; } GameWindow; void GameWindow_Init(GameWindow *pGameWindow); - void GameWindow_Draw(const GameWindow *pGameWindow, bool fullRefresh); -void GameWindow_Show(const GameWindow *pGameWindow); - void GameWindow_Click(GameWindow *pGameWindow, const Point *pPosition); +void GameWindow_SetScene(GameWindow *pGameWindow, const SceneId sceneId); +void GameWindow_Show(const GameWindow *pGameWindow); + #endif diff --git a/src/LevelEndScene.c b/src/LevelEndScene.c new file mode 100644 index 0000000..adfdaf5 --- /dev/null +++ b/src/LevelEndScene.c @@ -0,0 +1,51 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#include "LevelEndScene.h" + +void LevelEndScene_Init(GameWindow *pGameWindow) +{ +} + +void LevelEndScene_Draw(const GameWindow *pGameWindow, bool fullRefresh) +{ + Str255 halfStarsStr; + + SetPort(pGameWindow->Window); + + // TODO: Proper level end + if (fullRefresh) + { + } + + MoveTo(100, 100); + DrawString("\pLevel complete! Click to continue."); + + MoveTo(100, 125); + DrawString("\pReceived "); + NumToString((long)GameEngine_GetHalfStars(&(pGameWindow->Engine)), &halfStarsStr); + DrawString(halfStarsStr); + DrawString("\p/6 half-stars."); + + MoveTo(100, 200); + DrawString("\pRetry level."); + + MoveTo(350, 200); + DrawString("\pNext level."); +} + +void LevelEndScene_Click(GameWindow *pGameWindow, const Point *pPosition) +{ + // TODO: Proper click handling + + if (pPosition->h < ((pGameWindow->Window->portRect.right - pGameWindow->Window->portRect.left) / 2)) + { + GameEngine_ResetLevel(&(pGameWindow->Engine)); + } + else + { + GameEngine_NextLevel(&(pGameWindow->Engine)); + } + + GameWindow_SetScene(pGameWindow, GameEngine_IsGameOver(&(pGameWindow->Engine)) ? GameEnd : Play); +} diff --git a/src/LevelEndScene.h b/src/LevelEndScene.h new file mode 100644 index 0000000..47becb5 --- /dev/null +++ b/src/LevelEndScene.h @@ -0,0 +1,13 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#ifndef LEVELENDSCENE_H +#define LEVELENDSCENE_H + +#include "GameWindow.h" + +void LevelEndScene_Init(GameWindow *pGameWindow); +void LevelEndScene_Draw(const GameWindow *pGameWindow, bool fullRefresh); +void LevelEndScene_Click(GameWindow *pGameWindow, const Point *pPosition); + +#endif diff --git a/src/Levels.c b/src/Levels.c index 1d8d68a..bbe790b 100644 --- a/src/Levels.c +++ b/src/Levels.c @@ -24,19 +24,22 @@ const uint32_t Levels_LightsB[] = { 0x1151151UL, 0x1F27C9FUL, 0x1F711DFUL, 0x04AFEA4UL, 0x1FFFFFFUL, }; -int8_t Levels_BoundLevel(const int8_t level) -{ - return max(level, 0) % LevelCount; -} - uint32_t Levels_GetLightsForLevel(const int8_t level, const bool setB) { - int8_t bLevel = Levels_BoundLevel(level); - return setB ? Levels_LightsB[bLevel] : Levels_LightsA[bLevel]; + if (level >= 0 && level < LevelCount) + { + return setB ? Levels_LightsB[level] : Levels_LightsA[level]; + } + + return 0; } uint16_t Levels_GetParForLevel(const int8_t level) { - return 6 + (Levels_BoundLevel(level) / 5); + if (level >= 0 && level < LevelCount) + { + return 6 + (level / 5); + } + + return 0; } - diff --git a/src/Levels.h b/src/Levels.h index 2c3498f..cd8a216 100644 --- a/src/Levels.h +++ b/src/Levels.h @@ -9,8 +9,6 @@ extern const int8_t LevelCount; -int8_t Levels_BoundLevel(const int8_t level); - uint32_t Levels_GetLightsForLevel(const int8_t level, const bool setB); uint16_t Levels_GetParForLevel(const int8_t level); diff --git a/src/MacCommon.c b/src/MacCommon.c index d919102..5d35cdf 100644 --- a/src/MacCommon.c +++ b/src/MacCommon.c @@ -13,3 +13,21 @@ void ShowError(Str255 message, Boolean isFatal) ExitToShell(); } } + +void CenterRect(const Rect *pOuterRect, Rect *pInnerRect) +{ + CenterRectH(pOuterRect, pInnerRect); + CenterRectV(pOuterRect, pInnerRect); +} + +void CenterRectH(const Rect *pOuterRect, Rect *pInnerRect) +{ + OffsetRect(pInnerRect, pOuterRect->left - pInnerRect->left, 0); + OffsetRect(pInnerRect, (pOuterRect->right - pInnerRect->right) / 2, 0); +} + +void CenterRectV(const Rect *pOuterRect, Rect *pInnerRect) +{ + OffsetRect(pInnerRect, 0, pOuterRect->top - pInnerRect->top); + OffsetRect(pInnerRect, 0, (pOuterRect->bottom - pInnerRect->bottom) / 2); +} \ No newline at end of file diff --git a/src/MacCommon.h b/src/MacCommon.h index 05a2bc3..40b6f4b 100644 --- a/src/MacCommon.h +++ b/src/MacCommon.h @@ -16,4 +16,8 @@ pascal OSErr SetDialogDefaultItem(DialogPtr theDialog, short newItem) = { 0x303C void ShowError(Str255 message, Boolean isFatal); +void CenterRect(const Rect *pOuterRect, Rect *pInnerRect); +void CenterRectH(const Rect *pOuterRect, Rect *pInnerRect); +void CenterRectV(const Rect *pOuterRect, Rect *pInnerRect); + #endif diff --git a/src/MacLO.c b/src/MacLO.c index 053bb62..31fb129 100644 --- a/src/MacLO.c +++ b/src/MacLO.c @@ -8,7 +8,8 @@ #define AboutMenuItemID 1 #define GameMenuResID BaseResID+1 -#define QuitMenuItemID 1 +#define NewMenuItemID 1 +#define QuitMenuItemID 3 #define AboutDialogResID BaseResID #define AboutDialogOKID 1 @@ -228,6 +229,9 @@ void MacLO_HandleGameMenuChoice(const short item) { switch (item) { + case NewMenuItemID: + GameWindow_SetScene(&gGameWindow, Title); + break; case QuitMenuItemID: gExitApp = true; break; diff --git a/src/MacLO.pi.bin b/src/MacLO.pi.bin index 743a81f17f08cd8b32079b663e1822f4c0ab491a..d2cafb78209544d922566c858722795d3c2ad17d 100644 GIT binary patch delta 3426 zcmdT{U2IcT9RHu5er;`c*LFg;ZnVv2hJzI_ppcOaG|Rw@fv`XzgD|%yUECU@Xfz?V zB!2LqhH`i?FcL9W#Do~W#E%-&2V+d+frJNNtTx8@X!_v8qFt}QbMC#2GKLF25KnUM z{^x&wzyEjJyWD}?=!yM}y`j>ZKkg{$hri4RmxqoW`(~Q381|}BqMp(GJ5M=WNAov3 zefo3l@`|W8bh-AjlLf>PSHg3yc9fs{TfaKvdYcJX!xVGogWcg}R3I1I&4%e~wu9|t z)l+ftK|?hAIxl>5jTg?Z=Y@}Fc;S=BvA^Plix+s|(+n?M+QcPK_)tqaw*<+zyqP}hpXx3jY|qN@?z>Eb)c8Ix zQr4&vRSgGGf6Z{#$Wx?VX4I+_sgPzEv&4-Gd4R#O4D>89h0faOHO!cuqgGb7;aMPS z#3~f4nD{w^*N994Jc3XG!BeJ~A#EFFxF+!XO+25+SINYeYt+V#;yfX%2=J7J1rQu? zFlRUwJ_`quVAuo=0tmcJ0NVs)WE0lJ0Fcoasoy{}5|66DHSkj5frBbB;86}F5HoTp zmw~5^XTW=kNDTPwLIOwQSj~v!;2y@ozfEAuBOIWxw;jlOd4NaNEIdcywIX@}e33MT zN8VOI60h0#tPCrs2=dA62`Cpb;7A|+#wV?2gcaU{*frp5s6&ooaG(n7M1wF9-dPn2 z+|&%8#G`F!aE@aZY&5E*&{^t5G613}NZKcvb?|;=T*6T)7>6g|WQFI^W$IVP5#~ZP zuNgt04FmCD*wq9{^cIC~b*KiwxK^a3JSaFf8pW8_>MZGp-aFacB5HxhG<2n;@BPr; z!rv0rlH@4q``@s)INa3X(}#LW))t2phL`l=4fYn7LapM5rWd=w+_%o&6d}~NJ+kNN zfnoCQ8Bb+WFD26?`n2n8Tx{05#Ioin*N1O_{)pJ#+`}@W96aNzH@sY|3#PgLYz~fF z#b?3q?h2+O0H<}KWVwFeU4$JG&xCt@^{KRpnJ|3rJBL(T#jSACSD$|DF8tl88s(&4QW5=+`%o zxkNJ5$y4MO-?u!9Qzg{ZEsg!_5R=L)R?-iK?V8-9reZG8)0dGYeDD@LyzHWA#poil zCNq1|9O(xc%ZJ#r1bWtO_v{{XJWj$0tn5qux53xaOPa|vEommVEo~+VYw*=A6ucpy z@{^7wpI+zm*kmRikBdJ7oBk(X`ibF2`NO@!lOuA7t)6a2(?mYl;%5$OL`od{a6T9o zXFXjFP8{S`iV_rV99*`d!|P9+$DwZV>%Y#xlov_~R?LH5KdZuKAc7m|z+>N>#ZATX zF6~O1N%8nu#=3xx8tjX+o{r|-sqrJQBs(BOw!-abj>iYbpqE&@9L($45c?T=>D7OS z-uuGj)Fku{aWT=!0#|P)x*D3z{}0gK>-^%apPEL5bJgkWnd9nxfZV(Jl{2eN+1UfR zY|8vk$fKsbVlTgP`jjcVK7jrNIq)t)ZYT7|32#l1{m`f7i$)72+MvH?;@vHf@rt7` z5y&@`oF#WV2ou&t9P%l0OOTTwZ-#_gJ0-?XIYl0Z{F^1OhkU^bq6_jDRuC&8Z?yEQ eA>Xw0Yay>SeYxI(JmhsvKR=e9Vo!)X%lre5T=Xjd literal 11520 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 delta 394 zcmZp$Z;+i3$;JEdZtF9zyA$RoPZSgvYium~!TO^^vECU1Y!^w<{O`97Sw{l9$GBiR285sTp0gHQLZYoP)X=VvS;AVa9aK?I6!v90{{OrFmP@Hvl|$6fC?`&*LJxuG=Rl_0u9iZd{fRyUJ4YRG7`Ry&dvR)*P diff --git a/src/PlayScene.c b/src/PlayScene.c new file mode 100644 index 0000000..b8ac8a9 --- /dev/null +++ b/src/PlayScene.c @@ -0,0 +1,151 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#include "PlayScene.h" + +#define PlayfieldMargin 4 +#define PlayfieldPadding 2 +#define PlayfieldCornerSize 12 +#define LightMargin 6 +#define LightSize 50 +#define LightCornerSize 8 +#define PlayfieldPattern ltGray + +#define HUDMargin PlayfieldMargin +#define HUDCornerSize PlayfieldCornerSize +#define HUDPattern PlayfieldPattern + +void PlayScene_Init(GameWindow *pGameWindow) +{ + // Setup rects + pGameWindow->PlayScene.PlayfieldRect.top = PlayfieldMargin; + pGameWindow->PlayScene.PlayfieldRect.bottom = pGameWindow->Window->portRect.bottom - PlayfieldMargin; + pGameWindow->PlayScene.PlayfieldRect.left = pGameWindow->PlayScene.PlayfieldRect.top; + pGameWindow->PlayScene.PlayfieldRect.right = pGameWindow->PlayScene.PlayfieldRect.bottom; + + pGameWindow->PlayScene.HUDRect.top = HUDMargin; + pGameWindow->PlayScene.HUDRect.bottom = pGameWindow->Window->portRect.bottom - HUDMargin; + pGameWindow->PlayScene.HUDRect.left = pGameWindow->PlayScene.PlayfieldRect.right + HUDMargin; + pGameWindow->PlayScene.HUDRect.right = pGameWindow->Window->portRect.right - HUDMargin; +} + +void PlayScene_SetLightRect(const GameWindow *pGameWindow, Rect *pRect, const int8_t c, const int8_t r) +{ + pRect->top = pGameWindow->PlayScene.PlayfieldRect.top + PlayfieldPadding + LightMargin + (r * (LightMargin + LightSize)); + pRect->bottom = pRect->top + LightSize; + pRect->left = pGameWindow->PlayScene.PlayfieldRect.left + PlayfieldPadding + LightMargin + (c * (LightMargin + LightSize)); + pRect->right = pRect->left + LightSize; +} + +void PlayScene_Draw(const GameWindow *pGameWindow, bool fullRefresh) +{ + int8_t r, c; + Rect lightRect; + Str255 levelStr, parStr, movesStr, halfStarsStr, scoreStr; + + SetPort(pGameWindow->Window); + + if (fullRefresh) + { + // Fill backgrounds + FillRoundRect(&(pGameWindow->PlayScene.PlayfieldRect), PlayfieldCornerSize, PlayfieldCornerSize, PlayfieldPattern); + FillRoundRect(&(pGameWindow->PlayScene.HUDRect), HUDCornerSize, HUDCornerSize, HUDPattern); + } + + // Draw Playfield + + // Draw lights + for (r = 0; r < PuzzleSize; r++) + { + for (c = 0; c < PuzzleSize; c++) + { + PlayScene_SetLightRect(pGameWindow, &lightRect, c, r); + + if (GameEngine_GetLight(&(pGameWindow->Engine), c, r)) + { + // Draw ON light + FillRoundRect(&lightRect, LightCornerSize, LightCornerSize, white); + } + else + { + // Draw OFF light + FillRoundRect(&lightRect, LightCornerSize, LightCornerSize, black); + } + } + } + + // Draw HUD + + ForeColor(blackColor); + TextFace(bold + outline); + + // Draw Level + MoveTo(pGameWindow->PlayScene.HUDRect.left + 10, pGameWindow->PlayScene.HUDRect.top + 20); + DrawString("\pLevel: "); + NumToString(1L + pGameWindow->Engine.Level, &levelStr); + DrawString(levelStr); + DrawString("\p/50"); + + // Draw Par + MoveTo(pGameWindow->PlayScene.HUDRect.left + 10, pGameWindow->PlayScene.HUDRect.top + 40); + DrawString("\pPar: "); + NumToString((long)(pGameWindow->Engine.Par), &parStr); + DrawString(parStr); + + // Draw Moves + MoveTo(pGameWindow->PlayScene.HUDRect.left + 10, pGameWindow->PlayScene.HUDRect.top + 60); + DrawString("\pMoves: "); + NumToString((long)(pGameWindow->Engine.Moves), &movesStr); + DrawString(movesStr); + DrawString("\p/"); + DrawString(parStr); + + // Draw Stars + MoveTo(pGameWindow->PlayScene.HUDRect.left + 10, pGameWindow->PlayScene.HUDRect.top + 80); + DrawString("\pStars: "); + NumToString((long)GameEngine_GetHalfStars(&(pGameWindow->Engine)), &halfStarsStr); + DrawString(halfStarsStr); + DrawString("\p/6"); + + // Draw Score + MoveTo(pGameWindow->PlayScene.HUDRect.left + 10, pGameWindow->PlayScene.HUDRect.top + 100); + DrawString("\pScore: "); + NumToString((long)(pGameWindow->Engine.Score), &scoreStr); + DrawString(scoreStr); + DrawString("\p/300"); +} + +void PlayScene_Click(GameWindow *pGameWindow, const Point *pPosition) +{ + int8_t r, c; + Rect lightRect; + + if (PtInRect(*pPosition, &(pGameWindow->PlayScene.PlayfieldRect))) + { + // Click within Playfield + for (r = 0; r < PuzzleSize; r++) + { + for (c = 0; c < PuzzleSize; c++) + { + PlayScene_SetLightRect(pGameWindow, &lightRect, c, r); + + if (PtInRect(*pPosition, &lightRect)) + { + GameEngine_ToggleLights(&(pGameWindow->Engine), c, r); + GameWindow_Draw(pGameWindow, false); + break; + } + } + } + + if (GameEngine_IsCompleted(&(pGameWindow->Engine))) + { + // Level was completed in the last click + GameWindow_SetScene(pGameWindow, LevelEnd); + } + } + else if (PtInRect(*pPosition, &(pGameWindow->PlayScene.HUDRect))) + { + // Click within HUD + } +} diff --git a/src/PlayScene.h b/src/PlayScene.h new file mode 100644 index 0000000..466d330 --- /dev/null +++ b/src/PlayScene.h @@ -0,0 +1,13 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#ifndef PLAYSCENE_H +#define PLAYSCENE_H + +#include "GameWindow.h" + +void PlayScene_Init(GameWindow *pGameWindow); +void PlayScene_Draw(const GameWindow *pGameWindow, bool fullRefresh); +void PlayScene_Click(GameWindow *pGameWindow, const Point *pPosition); + +#endif diff --git a/src/Scenes.h b/src/Scenes.h new file mode 100644 index 0000000..ef46def --- /dev/null +++ b/src/Scenes.h @@ -0,0 +1,29 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#ifndef SCENES_H +#define SCENES_H + +#define NumScenes 4 + +typedef enum SceneId +{ + Title, + Play, + LevelEnd, + GameEnd +} SceneId; + +typedef struct TitleScene +{ + PicHandle TitlePict; + Rect TitleRect; +} TitleScene; + +typedef struct PlayScene +{ + Rect PlayfieldRect; + Rect HUDRect; +} PlayScene; + +#endif diff --git a/src/TitleScene.c b/src/TitleScene.c new file mode 100644 index 0000000..cc2ef80 --- /dev/null +++ b/src/TitleScene.c @@ -0,0 +1,64 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#include "TitleScene.h" + +#define TitlePictResID BaseResID + +void TitleScene_Init(GameWindow *pGameWindow) +{ + const Rect *pContentRect = &(pGameWindow->Window->portRect); + + pGameWindow->TitleScene.TitlePict = GetPicture(TitlePictResID); + + if (pGameWindow->TitleScene.TitlePict == nil) + { + ShowError("\pTitle PICT resource missing!", true); + } + + // Setup rects + pGameWindow->TitleScene.TitleRect = (**(pGameWindow->TitleScene.TitlePict)).picFrame; + CenterRect(pContentRect, &(pGameWindow->TitleScene.TitleRect)); +} + +void TitleScene_Draw(const GameWindow *pGameWindow, bool fullRefresh) +{ + SetPort(pGameWindow->Window); + + // TODO: Proper title + if (fullRefresh) + { + } + + // Draw Title PICT + DrawPicture(pGameWindow->TitleScene.TitlePict, &(pGameWindow->TitleScene.TitleRect)); + + ForeColor(blackColor); + TextFace(bold + outline); + + MoveTo(100, pGameWindow->TitleScene.TitleRect.bottom + 30); + DrawString("\pSet A"); + + MoveTo(350, pGameWindow->TitleScene.TitleRect.bottom + 30); + DrawString("\pSet B"); +} + +void TitleScene_Click(GameWindow *pGameWindow, const Point *pPosition) +{ + bool setB; + + // TODO: Proper click handling + + if (pPosition->h < ((pGameWindow->Window->portRect.right - pGameWindow->Window->portRect.left) / 2)) + { + setB = false; + } + else + { + setB = true; + } + + GameEngine_NewGame(&(pGameWindow->Engine), setB); + + GameWindow_SetScene(pGameWindow, Play); +} diff --git a/src/TitleScene.h b/src/TitleScene.h new file mode 100644 index 0000000..1ace401 --- /dev/null +++ b/src/TitleScene.h @@ -0,0 +1,13 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#ifndef TITLESCENE_H +#define TITLESCENE_H + +#include "GameWindow.h" + +void TitleScene_Init(GameWindow *pGameWindow); +void TitleScene_Draw(const GameWindow *pGameWindow, bool fullRefresh); +void TitleScene_Click(GameWindow *pGameWindow, const Point *pPosition); + +#endif