diff --git a/assets/prev.gif b/assets/prev.gif new file mode 100644 index 0000000..42cb4ed Binary files /dev/null and b/assets/prev.gif differ diff --git a/src/Bitmaps.c b/src/Bitmaps.c index 7a52cc1..4930d47 100644 --- a/src/Bitmaps.c +++ b/src/Bitmaps.c @@ -13,7 +13,8 @@ #define BCharPictResID (ACharPictResID + 1) #define SlashCharPictResID (BCharPictResID + 1) #define StarPictBaseResID (SlashCharPictResID + 1) -#define NextButtonPictResID (StarPictBaseResID + StarPictCount) +#define PrevButtonPictResID (StarPictBaseResID + StarPictCount) +#define NextButtonPictResID (PrevButtonPictResID + 1) #define RetryButtonPictResID (NextButtonPictResID + 1) #define SoundOffPictResID (RetryButtonPictResID + 1) #define SoundOnPictResID (SoundOffPictResID + 1) @@ -89,6 +90,13 @@ void Bitmaps_Init(Bitmaps *pBitmaps) ShowError("\pSlash char PICT resource missing!", true); } + // Load prev button + pBitmaps->PrevButtonPict = Bitmaps_GetPict(baseResID, PrevButtonPictResID); + if (pBitmaps->PrevButtonPict == nil) + { + ShowError("\pPrev button PICT resource missing!", true); + } + // Load next button pBitmaps->NextButtonPict = Bitmaps_GetPict(baseResID, NextButtonPictResID); if (pBitmaps->NextButtonPict == nil) diff --git a/src/Bitmaps.h b/src/Bitmaps.h index 8eb89ae..15dcdbd 100644 --- a/src/Bitmaps.h +++ b/src/Bitmaps.h @@ -17,6 +17,7 @@ typedef struct sBitmaps PicHandle BCharPict; PicHandle SlashCharPict; PicHandle StarPicts[StarPictCount]; + PicHandle PrevButtonPict; PicHandle NextButtonPict; PicHandle RetryButtonPict; PicHandle SoundOffPict; diff --git a/src/GameEndScene.c b/src/GameEndScene.c index 02ca7d6..a9758e7 100644 --- a/src/GameEndScene.c +++ b/src/GameEndScene.c @@ -23,7 +23,7 @@ void GameEndScene_Init(GameWindow *pGameWindow) CenterRect(&r, &(pGameWindow->GameEndScene.SetRect)); // Setup score - Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), pGameWindow->Engine.Score, ScoreTextScale, &(pGameWindow->GameEndScene.ScoreRect)); + Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), GameEngine_GetTotalScore(&(pGameWindow->Engine)), ScoreTextScale, &(pGameWindow->GameEndScene.ScoreRect)); GetScaledPicFrame(pGameWindow->Bitmaps.SlashCharPict, ScoreTextScale, &r); ConcatenateRect(&(pGameWindow->GameEndScene.ScoreRect), &r, &(pGameWindow->GameEndScene.ScoreRect)); Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), PerfectScore, ScoreTextScale, &r); @@ -51,7 +51,7 @@ void GameEndScene_Draw(const GameWindow *pGameWindow, bool fullRefresh) // Draw score MoveTo(pGameWindow->GameEndScene.ScoreRect.left, pGameWindow->GameEndScene.ScoreRect.top); - Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), pGameWindow->Engine.Score, ScoreTextScale); + Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), GameEngine_GetTotalScore(&(pGameWindow->Engine)), ScoreTextScale); Bitmaps_DrawSlashChar(&(pGameWindow->Bitmaps), ScoreTextScale); Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), PerfectScore, ScoreTextScale); } diff --git a/src/GameEngine.c b/src/GameEngine.c index 7357377..100540d 100644 --- a/src/GameEngine.c +++ b/src/GameEngine.c @@ -16,24 +16,73 @@ void GameEngine_LoadLevel(GameEngine *pGameEngine, const int8_t level, const boo uint8_t GameEngine_CalculateHalfStars(const uint16_t par, const uint16_t moves); void GameEngine_ToggleSingleLight(GameEngine *pGameEngine, const int8_t x, const int8_t y); +void GameEngine_Init(GameEngine *pGameEngine) +{ + int8_t level; + + for (level = 0; level < LevelCount; level++) + { + // TODO: Load actual scores + pGameEngine->ScoresA[level] = 1; + pGameEngine->ScoresB[level] = 0; + } + + pGameEngine->Level = -1; + pGameEngine->SetB = false; + pGameEngine->PreviousLights = 0; + pGameEngine->Lights = 0; + pGameEngine->Par = 0; + pGameEngine->Moves = 0; +} + void GameEngine_NewGame(GameEngine *pGameEngine, const bool setB) { - pGameEngine->Score = 0; - GameEngine_LoadLevel(pGameEngine, 0, setB); + pGameEngine->SetB = setB; + GameEngine_StartLevel(pGameEngine, 0); +} + +void GameEngine_ResetGame(GameEngine *pGameEngine) +{ + int8_t level; + + for (level = 0; level < LevelCount; level++) + { + pGameEngine->ScoresA[level] = 0; + pGameEngine->ScoresB[level] = 0; + } +} + +void GameEngine_StartLevel(GameEngine *pGameEngine, const uint8_t level) +{ + GameEngine_LoadLevel(pGameEngine, level, pGameEngine->SetB); +} + +void GameEngine_CompleteLevel(GameEngine *pGameEngine) +{ + if (GameEngine_IsCompleted(pGameEngine)) + { + if (pGameEngine->SetB) + { + pGameEngine->ScoresB[pGameEngine->Level] = max(GameEngine_GetHalfStars(pGameEngine), pGameEngine->ScoresB[pGameEngine->Level]); + } + else + { + pGameEngine->ScoresA[pGameEngine->Level] = max(GameEngine_GetHalfStars(pGameEngine), pGameEngine->ScoresA[pGameEngine->Level]); + } + } } void GameEngine_NextLevel(GameEngine *pGameEngine) { if (GameEngine_IsCompleted(pGameEngine)) { - pGameEngine->Score += GameEngine_GetHalfStars(pGameEngine); - GameEngine_LoadLevel(pGameEngine, pGameEngine->Level + 1, pGameEngine->SetB); + GameEngine_StartLevel(pGameEngine, pGameEngine->Level + 1); } } void GameEngine_ResetLevel(GameEngine *pGameEngine) { - GameEngine_LoadLevel(pGameEngine, pGameEngine->Level, pGameEngine->SetB); + GameEngine_StartLevel(pGameEngine, pGameEngine->Level); } void GameEngine_LoadLevel(GameEngine *pGameEngine, const int8_t level, const bool setB) @@ -56,6 +105,11 @@ bool GameEngine_GetLight(const GameEngine *pGameEngine, const int8_t x, const in return false; } +bool GameEngine_IsEnabled(const GameEngine *pGameEngine, const int8_t level) +{ + return level == 0 || (level < LevelCount && GameEngine_GetScore(pGameEngine, level - 1) > 0); +} + bool GameEngine_IsCompleted(const GameEngine *pGameEngine) { return pGameEngine->Lights == 0; @@ -71,6 +125,25 @@ uint8_t GameEngine_GetHalfStars(const GameEngine *pGameEngine) return GameEngine_CalculateHalfStars(pGameEngine->Par, pGameEngine->Moves); } +uint8_t GameEngine_GetScore(const GameEngine *pGameEngine, const int8_t level) +{ + return pGameEngine->SetB ? pGameEngine->ScoresB[level] : pGameEngine->ScoresA[level]; +} + +uint16_t GameEngine_GetTotalScore(const GameEngine *pGameEngine) +{ + uint8_t level; + uint16_t score; + + score = 0; + for (level = 0; level < LevelCount; level++) + { + score += GameEngine_GetScore(pGameEngine, level); + } + + return score; +} + uint8_t GameEngine_CalculateHalfStars(const uint16_t par, const uint16_t moves) { uint8_t halfStarsLost = moves <= par ? 0 : max(0, (1 + moves - par) / 2); diff --git a/src/GameEngine.h b/src/GameEngine.h index 2a2e3d4..de76126 100644 --- a/src/GameEngine.h +++ b/src/GameEngine.h @@ -16,7 +16,8 @@ extern const uint16_t PerfectScore; typedef struct GameEngine { - uint16_t Score; + uint8_t ScoresA[LevelCount]; + uint8_t ScoresB[LevelCount]; int8_t Level; bool SetB; uint32_t Lights; @@ -25,8 +26,16 @@ typedef struct GameEngine uint16_t Moves; } GameEngine; +void GameEngine_Init(GameEngine *pGameEngine); + void GameEngine_NewGame(GameEngine *pGameEngine, const bool setB); +void GameEngine_ResetGame(GameEngine *pGameEngine); + +void GameEngine_StartLevel(GameEngine *pGameEngine, const uint8_t level); + +void GameEngine_CompleteLevel(GameEngine *pGameEngine); + void GameEngine_NextLevel(GameEngine *pGameEngine); void GameEngine_ResetLevel(GameEngine *pGameEngine); @@ -35,10 +44,16 @@ bool GameEngine_GetLight(const GameEngine *pGameEngine, const int8_t x, const in bool GameEngine_IsCompleted(const GameEngine *pGameEngine); +bool GameEngine_IsEnabled(const GameEngine *pGameEngine, const int8_t level); + bool GameEngine_IsGameOver(const GameEngine *pGameEngine); uint8_t GameEngine_GetHalfStars(const GameEngine *pGameEngine); +uint8_t GameEngine_GetScore(const GameEngine *pGameEngine, const int8_t level); + +uint16_t GameEngine_GetTotalScore(const GameEngine *pGameEngine); + void GameEngine_ToggleLights(GameEngine *pGameEngine, const int8_t x, const int8_t y); bool GameEngine_LightChanged(const GameEngine *pGameEngine, const int8_t x, const int8_t y); diff --git a/src/GameWindow.c b/src/GameWindow.c index e891366..ff56839 100644 --- a/src/GameWindow.c +++ b/src/GameWindow.c @@ -3,6 +3,7 @@ #include "GameWindow.h" #include "TitleScene.h" +#include "LevelSelectScene.h" #include "PlayScene.h" #include "LevelEndScene.h" #include "GameEndScene.h" @@ -21,15 +22,18 @@ void GameWindow_Init(GameWindow *pGameWindow) ShowError("\pGameWindow WIND resource missing!", true); } + // Initialize window buffer + WindowBuffer_Init(&(pGameWindow->WindowBuffer), pGameWindow->Window); + + // Initialize game engine + GameEngine_Init(&(pGameWindow->Engine)); + // Load PICT resources Bitmaps_Init(&(pGameWindow->Bitmaps)); // Load snd resources Sounds_Init(&(pGameWindow->Sounds)); - // Initialize window buffer - WindowBuffer_Init(&(pGameWindow->WindowBuffer), pGameWindow->Window); - // Setup graphics before first draw SetPort(pGameWindow->Window); FillRect(&(pGameWindow->Window->portRect), WindowPattern); @@ -58,6 +62,9 @@ void GameWindow_Draw(const GameWindow *pGameWindow, bool fullRefresh) case Title: TitleScene_Draw(pGameWindow, fullRefresh); break; + case LevelSelect: + LevelSelectScene_Draw(pGameWindow, fullRefresh); + break; case Play: PlayScene_Draw(pGameWindow, fullRefresh); break; @@ -81,6 +88,9 @@ void GameWindow_Click(GameWindow *pGameWindow, const Point *pPosition) case Title: TitleScene_Click(pGameWindow, pPosition); break; + case LevelSelect: + LevelSelectScene_Click(pGameWindow, pPosition); + break; case Play: PlayScene_Click(pGameWindow, pPosition); break; @@ -100,6 +110,9 @@ void GameWindow_SetScene(GameWindow *pGameWindow, const SceneId sceneId) case Title: TitleScene_Init(pGameWindow); break; + case LevelSelect: + LevelSelectScene_Init(pGameWindow); + break; case Play: PlayScene_Init(pGameWindow); break; @@ -119,3 +132,12 @@ void GameWindow_Show(const GameWindow *pGameWindow) { ShowWindow(pGameWindow->Window); } + +void GameWindow_ClearScores(GameWindow *pGameWindow) +{ + if (ShowConfirm("\pClear all scores?")) + { + GameEngine_ResetGame(&(pGameWindow->Engine)); + GameWindow_SetScene(pGameWindow, Title); + } +} diff --git a/src/GameWindow.h b/src/GameWindow.h index 8248fcd..8ef5ce8 100644 --- a/src/GameWindow.h +++ b/src/GameWindow.h @@ -15,16 +15,17 @@ typedef struct sGameWindow { - WindowPtr Window; - WindowBuffer WindowBuffer; - GameEngine Engine; - Bitmaps Bitmaps; - Sounds Sounds; - SceneId CurrentSceneId; - TitleScene TitleScene; - PlayScene PlayScene; - LevelEndScene LevelEndScene; - GameEndScene GameEndScene; + WindowPtr Window; + WindowBuffer WindowBuffer; + GameEngine Engine; + Bitmaps Bitmaps; + Sounds Sounds; + SceneId CurrentSceneId; + TitleScene TitleScene; + LevelSelectScene LevelSelectScene; + PlayScene PlayScene; + LevelEndScene LevelEndScene; + GameEndScene GameEndScene; } GameWindow; void GameWindow_Init(GameWindow *pGameWindow); @@ -34,4 +35,6 @@ void GameWindow_Click(GameWindow *pGameWindow, const Point *pPosition); void GameWindow_SetScene(GameWindow *pGameWindow, const SceneId sceneId); void GameWindow_Show(const GameWindow *pGameWindow); +void GameWindow_ClearScores(GameWindow *pGameWindow); + #endif diff --git a/src/LevelEndScene.c b/src/LevelEndScene.c index 48b40f2..4a2f364 100644 --- a/src/LevelEndScene.c +++ b/src/LevelEndScene.c @@ -28,7 +28,7 @@ void LevelEndScene_Init(GameWindow *pGameWindow) CenterRect(&r, &(pGameWindow->LevelEndScene.HalfStarsRect)); // Setup score - Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), pGameWindow->Engine.Score, ScoreTextScale, &(pGameWindow->LevelEndScene.ScoreRect)); + Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), GameEngine_GetTotalScore(&(pGameWindow->Engine)), ScoreTextScale, &(pGameWindow->LevelEndScene.ScoreRect)); GetScaledPicFrame(pGameWindow->Bitmaps.SlashCharPict, ScoreTextScale, &r); ConcatenateRect(&(pGameWindow->LevelEndScene.ScoreRect), &r, &(pGameWindow->LevelEndScene.ScoreRect)); Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), PerfectScore, ScoreTextScale, &r); @@ -70,7 +70,7 @@ void LevelEndScene_Draw(const GameWindow *pGameWindow, bool fullRefresh) // Draw score MoveTo(pGameWindow->LevelEndScene.ScoreRect.left, pGameWindow->LevelEndScene.ScoreRect.top); - Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), pGameWindow->Engine.Score, ScoreTextScale); + Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), GameEngine_GetTotalScore(&(pGameWindow->Engine)), ScoreTextScale); Bitmaps_DrawSlashChar(&(pGameWindow->Bitmaps), ScoreTextScale); Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), PerfectScore, ScoreTextScale); diff --git a/src/LevelSelectScene.c b/src/LevelSelectScene.c new file mode 100644 index 0000000..aae1e9c --- /dev/null +++ b/src/LevelSelectScene.c @@ -0,0 +1,206 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#include "LevelSelectScene.h" + +#define SetTextScale 3 +#define ScoreTextScale 1 + +#define LevelMargin 10 +#define LevelWidth 80 +#define LevelHeight 60 +#define LevelRowCount 2 +#define LevelColumnCount 5 +#define LevelsPerPage (LevelRowCount * LevelColumnCount) +#define LevelTextScale 1 + +void LevelSelectScene_Init(GameWindow *pGameWindow) +{ + Rect r; + + const Rect *pContentRect = &(pGameWindow->Window->portRect); + + pGameWindow->LevelSelectScene.PageNumber = pGameWindow->Engine.Level / LevelsPerPage; + + // Setup set + GetScaledPicFrame(pGameWindow->Engine.SetB ? pGameWindow->Bitmaps.BCharPict : pGameWindow->Bitmaps.ACharPict, SetTextScale, &(pGameWindow->LevelSelectScene.SetRect)); + + GetBoxRect(pContentRect, Top, &r); + //GetBoxRect(&r, Top, &r); + CenterRect(&r, &(pGameWindow->LevelSelectScene.SetRect)); + + // Setup score + Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), GameEngine_GetTotalScore(&(pGameWindow->Engine)), ScoreTextScale, &(pGameWindow->LevelSelectScene.ScoreRect)); + GetScaledPicFrame(pGameWindow->Bitmaps.SlashCharPict, ScoreTextScale, &r); + ConcatenateRect(&(pGameWindow->LevelSelectScene.ScoreRect), &r, &(pGameWindow->LevelSelectScene.ScoreRect)); + Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), PerfectScore, ScoreTextScale, &r); + ConcatenateRect(&(pGameWindow->LevelSelectScene.ScoreRect), &r, &(pGameWindow->LevelSelectScene.ScoreRect)); + + GetBoxRect(pContentRect, Bottom, &r); + //GetBoxRect(&r, Bottom, &r); + CenterRect(&r, &(pGameWindow->LevelSelectScene.ScoreRect)); + + // Setup previous button + GetPictureRect(pGameWindow->Bitmaps.NextButtonPict, &(pGameWindow->LevelSelectScene.PrevButtonRect)); + + GetBoxRect(pContentRect, BottomLeft, &r); + //GetBoxRect(&r, Bottom, &r); + CenterRect(&r, &(pGameWindow->LevelSelectScene.PrevButtonRect)); + + // Setup next button + GetPictureRect(pGameWindow->Bitmaps.NextButtonPict, &(pGameWindow->LevelSelectScene.NextButtonRect)); + + GetBoxRect(pContentRect, BottomRight, &r); + //GetBoxRect(&r, Bottom, &r); + CenterRect(&r, &(pGameWindow->LevelSelectScene.NextButtonRect)); + + // Setup LevelGrid + pGameWindow->LevelSelectScene.LevelGridRect.top = 0; + pGameWindow->LevelSelectScene.LevelGridRect.bottom = (LevelRowCount * (LevelHeight + LevelMargin)) - LevelMargin; + pGameWindow->LevelSelectScene.LevelGridRect.left = 0; + pGameWindow->LevelSelectScene.LevelGridRect.right = (LevelColumnCount * (LevelWidth + LevelMargin)) - LevelMargin; + CenterRect(pContentRect, &(pGameWindow->LevelSelectScene.LevelGridRect)); +} + +void LevelSelectScene_SetLevelRect(const GameWindow *pGameWindow, Rect *pRect, const int8_t i) +{ + int8_t c, r; + c = i % LevelColumnCount; + r = i / LevelColumnCount; + + pRect->top = pGameWindow->LevelSelectScene.LevelGridRect.top + (r * (LevelHeight + LevelMargin)); + pRect->bottom = pRect->top + LevelHeight; + pRect->left = pGameWindow->LevelSelectScene.LevelGridRect.left + (c * (LevelWidth + LevelMargin)); + pRect->right = pRect->left + LevelWidth; +} + +void LevelSelectScene_Draw(const GameWindow *pGameWindow, bool fullRefresh) +{ + int8_t i, level; + Rect levelRect, levelTextRect, levelHalfStarsRect, r; + + // Draw set + if (fullRefresh) + { + MoveTo(pGameWindow->LevelSelectScene.SetRect.left, pGameWindow->LevelSelectScene.SetRect.top); + if (pGameWindow->Engine.SetB) + { + Bitmaps_DrawBChar(&(pGameWindow->Bitmaps), SetTextScale); + } + else + { + Bitmaps_DrawAChar(&(pGameWindow->Bitmaps), SetTextScale); + } + } + + // Draw score + if (fullRefresh) + { + MoveTo(pGameWindow->LevelSelectScene.ScoreRect.left, pGameWindow->LevelSelectScene.ScoreRect.top); + Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), GameEngine_GetTotalScore(&(pGameWindow->Engine)), ScoreTextScale); + Bitmaps_DrawSlashChar(&(pGameWindow->Bitmaps), ScoreTextScale); + Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), PerfectScore, ScoreTextScale); + } + + // Draw prev button + if (fullRefresh) + { + DrawPicture(pGameWindow->Bitmaps.PrevButtonPict, &(pGameWindow->LevelSelectScene.PrevButtonRect)); + } + + // Draw next button + if ((pGameWindow->LevelSelectScene.PageNumber + 1) * LevelsPerPage < LevelCount) + { + DrawPicture(pGameWindow->Bitmaps.NextButtonPict, &(pGameWindow->LevelSelectScene.NextButtonRect)); + } + else + { + FillRect(&(pGameWindow->LevelSelectScene.NextButtonRect), WindowPattern); + } + + // Draw levels + for (i = 0; i < LevelsPerPage; i++) + { + level = i + (LevelsPerPage * pGameWindow->LevelSelectScene.PageNumber); + + LevelSelectScene_SetLevelRect(pGameWindow, &levelRect, i); + + if (!fullRefresh) + { + FillRect(&levelRect, WindowPattern); + } + + if (level < LevelCount) + { + // Draw level number + Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), 1 + level, LevelTextScale, &levelTextRect); + + GetBoxRect(&levelRect, Top, &r); + GetBoxRect(&r, Bottom, &r); + CenterRect(&r, &levelTextRect); + + MoveTo(levelTextRect.left, levelTextRect.top); + Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), 1 + level, LevelTextScale); + + if (GameEngine_IsEnabled(&(pGameWindow->Engine), level)) + { + // Draw half-stars + Bitmaps_GetHalfStarsRect(&(pGameWindow->Bitmaps), GameEngine_GetScore(&(pGameWindow->Engine), level), MaxStars, LevelTextScale, &levelHalfStarsRect); + + GetBoxRect(&levelRect, Bottom, &r); + GetBoxRect(&r, Top, &r); + CenterRect(&r, &levelHalfStarsRect); + + MoveTo(levelHalfStarsRect.left, levelHalfStarsRect.top); + Bitmaps_DrawHalfStars(&(pGameWindow->Bitmaps), GameEngine_GetScore(&(pGameWindow->Engine), level), MaxStars, LevelTextScale); + } + } + } +} + +void LevelSelectScene_Click(GameWindow *pGameWindow, const Point *pPosition) +{ + int8_t i, level; + Rect levelRect; + + if (PtInRect(*pPosition, &(pGameWindow->LevelSelectScene.LevelGridRect))) + { + // Click within LevelGrid + for (i = 0; i < LevelsPerPage; i++) + { + level = i + (LevelsPerPage * pGameWindow->LevelSelectScene.PageNumber); + + if (GameEngine_IsEnabled(&(pGameWindow->Engine), level)) + { + LevelSelectScene_SetLevelRect(pGameWindow, &levelRect, i); + + if (PtInRect(*pPosition, &levelRect)) + { + GameEngine_StartLevel(&(pGameWindow->Engine), level); + GameWindow_SetScene(pGameWindow, Play); + break; + } + } + } + } + else if (PtInRect(*pPosition, &(pGameWindow->LevelSelectScene.PrevButtonRect))) + { + if (pGameWindow->LevelSelectScene.PageNumber > 0) + { + pGameWindow->LevelSelectScene.PageNumber--; + GameWindow_Draw(pGameWindow, false); + } + else + { + GameWindow_SetScene(pGameWindow, Title); + } + } + else if (PtInRect(*pPosition, &(pGameWindow->LevelSelectScene.NextButtonRect))) + { + if ((pGameWindow->LevelSelectScene.PageNumber + 1) * LevelsPerPage < LevelCount) + { + pGameWindow->LevelSelectScene.PageNumber++; + GameWindow_Draw(pGameWindow, false); + } + } +} diff --git a/src/LevelSelectScene.h b/src/LevelSelectScene.h new file mode 100644 index 0000000..b552297 --- /dev/null +++ b/src/LevelSelectScene.h @@ -0,0 +1,13 @@ +// Copyright (c) Jon Thysell +// Licensed under the MIT License. + +#ifndef LEVELSELECTSCENE_H +#define LEVELSELECTSCENE_H + +#include "GameWindow.h" + +void LevelSelectScene_Init(GameWindow *pGameWindow); +void LevelSelectScene_Draw(const GameWindow *pGameWindow, bool fullRefresh); +void LevelSelectScene_Click(GameWindow *pGameWindow, const Point *pPosition); + +#endif diff --git a/src/Levels.c b/src/Levels.c index bbe790b..182cbce 100644 --- a/src/Levels.c +++ b/src/Levels.c @@ -4,8 +4,6 @@ #include "Common.h" #include "Levels.h" -const int8_t LevelCount = 50; - const uint32_t Levels_LightsA[] = { 0x0005400UL, 0x15A82B5UL, 0x0ADEF6AUL, 0x1B88360UL, 0x1BC5EEFUL, 0x0EAD400UL, 0x0F8C62FUL, 0x0AAA880UL, 0x07D3BEAUL, 0x00039CEUL, 0x0EAD6B5UL, 0x0A76D5FUL, 0x022AA88UL, 0x0210800UL, 0x0010040UL, 0x1F08421UL, 0x1F71000UL, 0x0455544UL, diff --git a/src/Levels.h b/src/Levels.h index cd8a216..0e42a3c 100644 --- a/src/Levels.h +++ b/src/Levels.h @@ -7,7 +7,7 @@ #include "stdint.h" #include "stdbool.h" -extern const int8_t LevelCount; +#define LevelCount 50 uint32_t Levels_GetLightsForLevel(const int8_t level, const bool setB); diff --git a/src/MacCommon.c b/src/MacCommon.c index c24bc29..ce23085 100644 --- a/src/MacCommon.c +++ b/src/MacCommon.c @@ -3,6 +3,11 @@ #include "MacCommon.h" +#define ErrorAlertResID BaseResID +#define ConfirmAlertResID (ErrorAlertResID + 1) + +#define YesResult 2 + const int16_t MonthOffset[] = { 0, // Jan 31, // Feb @@ -29,6 +34,16 @@ void ShowError(Str255 message, bool isFatal) } } +bool ShowConfirm(Str255 message) +{ + uint16_t result; + + ParamText(message, EmptyString, EmptyString, EmptyString); + result = CautionAlert(ConfirmAlertResID, NilFilterProc); + + return result == YesResult; +} + void CenterRect(const Rect *pOuterRect, Rect *pInnerRect) { CenterRectH(pOuterRect, pInnerRect); diff --git a/src/MacCommon.h b/src/MacCommon.h index da8cb26..c344fd8 100644 --- a/src/MacCommon.h +++ b/src/MacCommon.h @@ -12,8 +12,6 @@ #define EmptyString "\p" #define NilFilterProc nil -#define ErrorAlertResID BaseResID - extern const int16_t MonthOffset[]; typedef enum eBoxAlignment @@ -33,6 +31,8 @@ pascal OSErr SetDialogDefaultItem(DialogPtr theDialog, int16_t newItem) = { 0x30 void ShowError(Str255 message, bool isFatal); +bool ShowConfirm(Str255 message); + void CenterRect(const Rect *pOuterRect, Rect *pInnerRect); void CenterRectH(const Rect *pOuterRect, Rect *pInnerRect); void CenterRectV(const Rect *pOuterRect, Rect *pInnerRect); diff --git a/src/MacLO.c b/src/MacLO.c index 1efcdb9..2a09934 100644 --- a/src/MacLO.c +++ b/src/MacLO.c @@ -8,8 +8,9 @@ #define AboutMenuItemID 1 #define GameMenuResID BaseResID+1 -#define NewMenuItemID 1 -#define QuitMenuItemID 3 +#define TitleMenuItemID 1 +#define ClearMenuItemID 2 +#define QuitMenuItemID 4 #define AboutDialogResID BaseResID #define AboutDialogOKID 1 @@ -29,6 +30,8 @@ void MacLO_LaunchAppleMenuItem(const int16_t item); void MacLO_HandleGameMenuChoice(const int16_t item); +void MacLO_Quit(); + void MacLO_ToolBoxInit() { MaxApplZone(); @@ -233,11 +236,22 @@ void MacLO_HandleGameMenuChoice(const int16_t item) { switch (item) { - case NewMenuItemID: + case TitleMenuItemID: GameWindow_SetScene(&gGameWindow, Title); break; + case ClearMenuItemID: + GameWindow_ClearScores(&gGameWindow); + break; case QuitMenuItemID: - gExitApp = true; + MacLO_Quit(); break; } } + +void MacLO_Quit() +{ + if (ShowConfirm("\pQuit MacLO?")) + { + gExitApp = true; + } +} diff --git a/src/MacLO.pi.bin b/src/MacLO.pi.bin index c2bc12a..cde80a9 100644 Binary files a/src/MacLO.pi.bin and b/src/MacLO.pi.bin differ diff --git a/src/MacLO.pi.rsrc.bin b/src/MacLO.pi.rsrc.bin index 8445c74..2255171 100644 Binary files a/src/MacLO.pi.rsrc.bin and b/src/MacLO.pi.rsrc.bin differ diff --git a/src/PlayScene.c b/src/PlayScene.c index c192029..cc888ce 100644 --- a/src/PlayScene.c +++ b/src/PlayScene.c @@ -16,6 +16,8 @@ #define HalfStarScale 2 #define ScoreTextScale 1 +void PlayScene_SetLightRect(const GameWindow *pGameWindow, Rect *pRect, const int8_t c, const int8_t r); + void PlayScene_Init(GameWindow *pGameWindow) { Rect r; @@ -49,7 +51,7 @@ void PlayScene_Init(GameWindow *pGameWindow) CenterRect(&r, &(pGameWindow->PlayScene.HalfStarsRect)); // Setup score - Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), pGameWindow->Engine.Score, ScoreTextScale, &(pGameWindow->PlayScene.ScoreRect)); + Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), GameEngine_GetTotalScore(&(pGameWindow->Engine)), ScoreTextScale, &(pGameWindow->PlayScene.ScoreRect)); GetScaledPicFrame(pGameWindow->Bitmaps.SlashCharPict, ScoreTextScale, &r); ConcatenateRect(&(pGameWindow->PlayScene.ScoreRect), &r, &(pGameWindow->PlayScene.ScoreRect)); Bitmaps_GetNumberRect(&(pGameWindow->Bitmaps), PerfectScore, ScoreTextScale, &r); @@ -144,7 +146,7 @@ void PlayScene_Draw(const GameWindow *pGameWindow, bool fullRefresh) if (fullRefresh) { MoveTo(pGameWindow->PlayScene.ScoreRect.left, pGameWindow->PlayScene.ScoreRect.top); - Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), pGameWindow->Engine.Score, ScoreTextScale); + Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), GameEngine_GetTotalScore(&(pGameWindow->Engine)), ScoreTextScale); Bitmaps_DrawSlashChar(&(pGameWindow->Bitmaps), ScoreTextScale); Bitmaps_DrawNumber(&(pGameWindow->Bitmaps), PerfectScore, ScoreTextScale); } @@ -187,6 +189,7 @@ void PlayScene_Click(GameWindow *pGameWindow, const Point *pPosition) if (GameEngine_IsCompleted(&(pGameWindow->Engine))) { // Level was completed in the last click + GameEngine_CompleteLevel(&(pGameWindow->Engine)); GameWindow_Draw(pGameWindow, false); GameWindow_SetScene(pGameWindow, LevelEnd); Sounds_PlayDoneSnd(&(pGameWindow->Sounds)); diff --git a/src/Scenes.h b/src/Scenes.h index 597de22..be21742 100644 --- a/src/Scenes.h +++ b/src/Scenes.h @@ -9,6 +9,7 @@ typedef enum eSceneId { Title, + LevelSelect, Play, LevelEnd, GameEnd @@ -22,6 +23,16 @@ typedef struct sTitleScene Rect SoundButtonRect; } TitleScene; +typedef struct sLevelSelectScene +{ + int8_t PageNumber; + Rect SetRect; + Rect ScoreRect; + Rect PrevButtonRect; + Rect NextButtonRect; + Rect LevelGridRect; +} LevelSelectScene; + typedef struct sPlayScene { Rect PlayfieldRect; diff --git a/src/TitleScene.c b/src/TitleScene.c index ecc2e22..92e9995 100644 --- a/src/TitleScene.c +++ b/src/TitleScene.c @@ -14,7 +14,9 @@ void TitleScene_Init(GameWindow *pGameWindow) // Setup Title GetPictureRect(pGameWindow->Bitmaps.TitlePict, &(pGameWindow->TitleScene.TitleRect)); - CenterRect(pContentRect, &(pGameWindow->TitleScene.TitleRect)); + GetBoxRect(pContentRect, Center, &r); + GetBoxRect(&r, Top, &r); + CenterRect(&r, &(pGameWindow->TitleScene.TitleRect)); // Setup Set A GetScaledPicFrame(pGameWindow->Bitmaps.ACharPict, TitleTextScale, &(pGameWindow->TitleScene.SetARect)); @@ -55,12 +57,12 @@ void TitleScene_Click(GameWindow *pGameWindow, const Point *pPosition) if (PtInRect(*pPosition, &(pGameWindow->TitleScene.SetARect))) { GameEngine_NewGame(&(pGameWindow->Engine), false); - GameWindow_SetScene(pGameWindow, Play); + GameWindow_SetScene(pGameWindow, LevelSelect); } else if (PtInRect(*pPosition, &(pGameWindow->TitleScene.SetBRect))) { GameEngine_NewGame(&(pGameWindow->Engine), true); - GameWindow_SetScene(pGameWindow, Play); + GameWindow_SetScene(pGameWindow, LevelSelect); } else if (PtInRect(*pPosition, &(pGameWindow->TitleScene.SoundButtonRect))) {