From 6c062df9bb1e915f175f40eea800b0aa3c3198b3 Mon Sep 17 00:00:00 2001
From: Dominic Masters <dominic@domsplace.com>
Date: Wed, 9 Oct 2024 09:47:05 -0500
Subject: [PATCH] Added main menu.

---
 src/dawn/display/draw/drawstatemainmenu.c  | 12 +++++++++
 src/dawn/display/draw/drawstateoverworld.c |  1 -
 src/dawn/display/draw/drawui.c             |  9 -------
 src/dawn/display/draw/drawui.h             |  7 +----
 src/dawn/display/frame.c                   |  2 ++
 src/dawn/game/game.c                       |  6 +++--
 src/dawn/rpg/world/map.c                   | 14 ++--------
 src/dawn/ui/mainmenu.c                     | 30 +++++++++++++++++-----
 src/dawn/ui/mainmenu.h                     |  6 +----
 src/dawn/ui/menu.c                         | 12 +++++++++
 src/dawn/ui/menu.h                         | 10 +++++++-
 11 files changed, 67 insertions(+), 42 deletions(-)

diff --git a/src/dawn/display/draw/drawstatemainmenu.c b/src/dawn/display/draw/drawstatemainmenu.c
index df8c9cb1..eb892bcd 100644
--- a/src/dawn/display/draw/drawstatemainmenu.c
+++ b/src/dawn/display/draw/drawstatemainmenu.c
@@ -7,8 +7,20 @@
 
 #include "drawstatemainmenu.h"
 #include "display/draw/drawtext.h"
+#include "display/draw/drawui.h"
+#include "ui/mainmenu.h"
 
 void drawStateMainMenu() {
   // Draw the logo
   drawText("Dawn", 4, 0, 0, COLOR_WHITE);
+
+  // Draw the menu
+  uint16_t width = menuGetLongestStringLength(&MAIN_MENU) + 3;
+  uint16_t height = MAIN_MENU.rows + 2;
+  drawUIMenuBox(
+    &MAIN_MENU,
+    (FRAME_WIDTH - width) / 2, FRAME_HEIGHT - height - 4,
+    width, height,
+    COLOR_WHITE, COLOR_WHITE, COLOR_WHITE
+  );
 }
\ No newline at end of file
diff --git a/src/dawn/display/draw/drawstateoverworld.c b/src/dawn/display/draw/drawstateoverworld.c
index 5b148fc1..82fb775a 100644
--- a/src/dawn/display/draw/drawstateoverworld.c
+++ b/src/dawn/display/draw/drawstateoverworld.c
@@ -36,5 +36,4 @@ void drawStateOverworld() {
 
   // Draw UI
   drawUITextbox();
-  // drawUITestMenu();
 }
\ No newline at end of file
diff --git a/src/dawn/display/draw/drawui.c b/src/dawn/display/draw/drawui.c
index 919b55f5..f43e9e18 100644
--- a/src/dawn/display/draw/drawui.c
+++ b/src/dawn/display/draw/drawui.c
@@ -225,13 +225,4 @@ void drawUITextbox() {
   int32_t blink = (int32_t)(TIME.time * DRAW_UI_TEXTBOX_BLINKS_PER_SECOND) % 2;
   FRAME_BUFFER[DRAW_UI_TEXTBOX_CURSOR_POS + 1] = blink ? '>' : ' ';
   FRAME_BUFFER[DRAW_UI_TEXTBOX_CURSOR_POS + 2] = blink ? ' ' : '>';
-}
-
-void drawUITestMenu() {
-  drawUIMenuBox(
-    &TEST_MENU.menu,
-    0, 0,
-    FRAME_WIDTH, 5,
-    COLOR_CYAN, COLOR_RED, COLOR_WHITE
-  );
 }
\ No newline at end of file
diff --git a/src/dawn/display/draw/drawui.h b/src/dawn/display/draw/drawui.h
index 23fcde02..5e9e2e2d 100644
--- a/src/dawn/display/draw/drawui.h
+++ b/src/dawn/display/draw/drawui.h
@@ -80,9 +80,4 @@ void drawUIMenuBox(
 /**
  * Draws the UI textbox to the frame buffer.
  */
-void drawUITextbox();
-
-/**
- * Draws the UI test menu to the frame buffer.
- */
-void drawUITestMenu();
\ No newline at end of file
+void drawUITextbox();
\ No newline at end of file
diff --git a/src/dawn/display/frame.c b/src/dawn/display/frame.c
index 2e7e88ca..36b78941 100644
--- a/src/dawn/display/frame.c
+++ b/src/dawn/display/frame.c
@@ -40,8 +40,10 @@ void frameUpdate() {
     
     case GAME_STATE_MAIN_MENU:
       drawStateMainMenu();
+      break;
     
     default:
+      printf("Rendering unknown game state: %d\n", GAME.state);
       break;
   }
 }
\ No newline at end of file
diff --git a/src/dawn/game/game.c b/src/dawn/game/game.c
index 38ee3a82..1edacf5c 100644
--- a/src/dawn/game/game.c
+++ b/src/dawn/game/game.c
@@ -10,7 +10,7 @@
 #include "input.h"
 #include "display/display.h"
 #include "asset/asset.h"
-#include "asset/assetmap.h"
+
 #include "ui/textbox.h"
 #include "ui/testmenu.h"
 #include "ui/mainmenu.h"
@@ -33,7 +33,6 @@ void gameInit() {
   testMenuInit();
   mainMenuInit();
 
-  GAME.mapNext = MAP_LIST_TEST;
   GAME.state = GAME_STATE_INITIAL;
 }
 
@@ -61,6 +60,9 @@ gameupdateresult_t gameUpdate(const float_t delta) {
     case GAME_STATE_MAIN_MENU:
       gameStateMainMenuUpdate();
       break;
+    
+    default:
+      printf("Updating unknown state %d\n", GAME.state);
   }
 
   // Perform render.
diff --git a/src/dawn/rpg/world/map.c b/src/dawn/rpg/world/map.c
index 414adbc7..9bcbe8c2 100644
--- a/src/dawn/rpg/world/map.c
+++ b/src/dawn/rpg/world/map.c
@@ -104,18 +104,8 @@ tile_t mapTileGetByPosition(
   const uint16_t y,
   const uint8_t layer
 ) {
-  assertTrue(
-    x < map->width,
-    "X position must be less than map width."
-  );
-  assertTrue(
-    y < map->height,
-    "Y position must be less than map height."
-  );
-  assertTrue(
-    layer < map->layers,
-    "Layer must be less than map layers."
-  );
+  if(x >= map->width || y >= map->height) return TILE_NULL;
+  if(layer >= map->layers) return TILE_NULL;
 
   return map->tiles[
     (layer * map->width * map->height) +
diff --git a/src/dawn/ui/mainmenu.c b/src/dawn/ui/mainmenu.c
index f4fe9a28..2bf4e775 100644
--- a/src/dawn/ui/mainmenu.c
+++ b/src/dawn/ui/mainmenu.c
@@ -6,8 +6,9 @@
  */
 
 #include "mainmenu.h"
+#include "game/game.h"
 
-mainmenu_t MAIN_MENU;
+menu_t MAIN_MENU;
 
 void mainMenuInit() {
   const char_t* strings[] = {
@@ -19,13 +20,13 @@ void mainMenuInit() {
 
   uint16_t columns = 1;
   uint16_t rows = 4;
-  menuInit(&MAIN_MENU.menu, columns, rows);
-  memcpy(MAIN_MENU.menu.strings, strings, sizeof(strings));
-  MAIN_MENU.menu.selectCallback = mainMenuSelectCallback;
+  menuInit(&MAIN_MENU, columns, rows);
+  memcpy(MAIN_MENU.strings, strings, sizeof(strings));
+  MAIN_MENU.selectCallback = mainMenuSelectCallback;
 }
 
 void mainMenuUpdate() {
-  menuUpdate(&MAIN_MENU.menu);
+  menuUpdate(&MAIN_MENU);
 }
 
 void mainMenuSelectCallback(
@@ -34,5 +35,22 @@ void mainMenuSelectCallback(
   const uint16_t y,
   const char_t *str
 ) {
-  printf("Selected: %s\n", str);
+  if(strcmp(str, "New Game") == 0) {
+    GAME.mapNext = MAP_LIST_TEST;
+    GAME.state = GAME_STATE_MAP_CHANGE;
+    return;
+  }
+
+  if(strcmp(str, "Load Game") == 0) {
+    return;
+  }
+
+  if(strcmp(str, "Options") == 0) {
+    return;
+  }
+
+  if(strcmp(str, "Exit") == 0) {
+    GAME.shouldExit = true;
+    return;
+  }
 }
\ No newline at end of file
diff --git a/src/dawn/ui/mainmenu.h b/src/dawn/ui/mainmenu.h
index b66b3a63..cb5becbf 100644
--- a/src/dawn/ui/mainmenu.h
+++ b/src/dawn/ui/mainmenu.h
@@ -8,11 +8,7 @@
 #pragma once
 #include "ui/menu.h"
 
-typedef struct {
-  menu_t menu;
-} mainmenu_t;
-
-extern mainmenu_t MAIN_MENU;
+extern menu_t MAIN_MENU;
 
 /**
  * Initializes the main menu.
diff --git a/src/dawn/ui/menu.c b/src/dawn/ui/menu.c
index d57f69d4..91bfa817 100644
--- a/src/dawn/ui/menu.c
+++ b/src/dawn/ui/menu.c
@@ -131,4 +131,16 @@ void menuPositionSet(menu_t *menu, const uint16_t x, const uint16_t y) {
       menu->y--;
     }
   }
+}
+
+size_t menuGetLongestStringLength(const menu_t *menu) {
+  assertNotNull(menu, "Menu cannot be NULL.");
+  size_t longest = 0;
+  for(uint16_t i = 0; i < MENU_ITEM_COUNT_MAX; i++) {
+    if(menu->strings[i] == NULL) continue;
+
+    size_t len = strlen(menu->strings[i]);
+    if(len > longest) longest = len;
+  }
+  return longest;
 }
\ No newline at end of file
diff --git a/src/dawn/ui/menu.h b/src/dawn/ui/menu.h
index 11c922a0..ed19e926 100644
--- a/src/dawn/ui/menu.h
+++ b/src/dawn/ui/menu.h
@@ -70,4 +70,12 @@ void menuPositionMove(menu_t *menu, const menudirection_t direction);
  * @param x X position.
  * @param y Y position.
  */
-void menuPositionSet(menu_t *menu, const uint16_t x, const uint16_t y);
\ No newline at end of file
+void menuPositionSet(menu_t *menu, const uint16_t x, const uint16_t y);
+
+/**
+ * Gets the length of the longest string in the menu.
+ * 
+ * @param menu Menu to get the longest string from.
+ * @return The length of the longest string.
+ */
+size_t menuGetLongestStringLength(const menu_t *menu);
\ No newline at end of file