From f4945731a958371d206ccfa4a34486b263be5b21 Mon Sep 17 00:00:00 2001
From: Star Rauchenberger <fefferburbia@gmail.com>
Date: Tue, 11 Mar 2025 23:18:33 -0400
Subject: Added color indicators to subway map

---
 src/ap_state.cpp   |  9 +++++++++
 src/ap_state.h     |  2 ++
 src/game_data.cpp  | 58 +++++++++++++++++++++++++++---------------------------
 src/game_data.h    |  2 ++
 src/subway_map.cpp | 12 +++++++++++
 5 files changed, 54 insertions(+), 29 deletions(-)

(limited to 'src')

diff --git a/src/ap_state.cpp b/src/ap_state.cpp
index 1e5621d..023bf7f 100644
--- a/src/ap_state.cpp
+++ b/src/ap_state.cpp
@@ -228,6 +228,11 @@ struct APState {
     return inventory.count(item_id) && inventory.at(item_id) >= quantity;
   }
 
+  bool HasItemSafe(int item_id, int quantity) {
+    std::lock_guard state_guard(state_mutex);
+    return HasItem(item_id, quantity);
+  }
+
   bool HasAchievement(const std::string& name) {
     std::lock_guard state_guard(state_mutex);
 
@@ -723,6 +728,10 @@ bool AP_HasItem(int item_id, int quantity) {
   return GetState().HasItem(item_id, quantity);
 }
 
+bool AP_HasItemSafe(int item_id, int quantity) {
+  return GetState().HasItemSafe(item_id, quantity);
+}
+
 std::string AP_GetItemName(int item_id) {
   return GetState().GetItemName(item_id);
 }
diff --git a/src/ap_state.h b/src/ap_state.h
index 298df8c..482c155 100644
--- a/src/ap_state.h
+++ b/src/ap_state.h
@@ -63,6 +63,8 @@ bool AP_HasCheckedHuntPanel(int location_id);
 // RecalculateReachability, which is only called from the APState thread anyway.
 bool AP_HasItem(int item_id, int quantity = 1);
 
+bool AP_HasItemSafe(int item_id, int quantity = 1);
+
 // This doesn't lock the client mutex because it is ONLY to be called from
 // RecalculateReachability, which is only called from within a client callback
 // anyway.
diff --git a/src/game_data.cpp b/src/game_data.cpp
index a4a441d..7c221e9 100644
--- a/src/game_data.cpp
+++ b/src/game_data.cpp
@@ -12,32 +12,6 @@
 
 namespace {
 
-LingoColor GetColorForString(const std::string &str) {
-  if (str == "black") {
-    return LingoColor::kBlack;
-  } else if (str == "red") {
-    return LingoColor::kRed;
-  } else if (str == "blue") {
-    return LingoColor::kBlue;
-  } else if (str == "yellow") {
-    return LingoColor::kYellow;
-  } else if (str == "orange") {
-    return LingoColor::kOrange;
-  } else if (str == "green") {
-    return LingoColor::kGreen;
-  } else if (str == "gray") {
-    return LingoColor::kGray;
-  } else if (str == "brown") {
-    return LingoColor::kBrown;
-  } else if (str == "purple") {
-    return LingoColor::kPurple;
-  } else {
-    TrackerLog(fmt::format("Invalid color: {}", str));
-
-    return LingoColor::kNone;
-  }
-}
-
 struct GameData {
   std::vector<Room> rooms_;
   std::vector<Door> doors_;
@@ -84,7 +58,7 @@ struct GameData {
           ids_config["special_items"][color_name]) {
         std::string input_name = color_name;
         input_name[0] = std::tolower(input_name[0]);
-        ap_id_by_color_[GetColorForString(input_name)] =
+        ap_id_by_color_[GetLingoColorForString(input_name)] =
             ids_config["special_items"][color_name].as<int>();
       } else {
         TrackerLog(fmt::format("Missing AP item ID for color {}", color_name));
@@ -181,12 +155,12 @@ struct GameData {
 
           if (panel_it.second["colors"]) {
             if (panel_it.second["colors"].IsScalar()) {
-              panels_[panel_id].colors.push_back(GetColorForString(
+              panels_[panel_id].colors.push_back(GetLingoColorForString(
                   panel_it.second["colors"].as<std::string>()));
             } else {
               for (const auto &color_node : panel_it.second["colors"]) {
                 panels_[panel_id].colors.push_back(
-                    GetColorForString(color_node.as<std::string>()));
+                    GetLingoColorForString(color_node.as<std::string>()));
               }
             }
           }
@@ -1010,3 +984,29 @@ std::optional<int> GD_GetSubwayItemForPainting(const std::string &painting_id) {
 int GD_GetSubwayItemForSunwarp(const SubwaySunwarp &sunwarp) {
   return GetState().subway_item_by_sunwarp_.at(sunwarp);
 }
+
+LingoColor GetLingoColorForString(const std::string &str) {
+  if (str == "black") {
+    return LingoColor::kBlack;
+  } else if (str == "red") {
+    return LingoColor::kRed;
+  } else if (str == "blue") {
+    return LingoColor::kBlue;
+  } else if (str == "yellow") {
+    return LingoColor::kYellow;
+  } else if (str == "orange") {
+    return LingoColor::kOrange;
+  } else if (str == "green") {
+    return LingoColor::kGreen;
+  } else if (str == "gray") {
+    return LingoColor::kGray;
+  } else if (str == "brown") {
+    return LingoColor::kBrown;
+  } else if (str == "purple") {
+    return LingoColor::kPurple;
+  } else {
+    TrackerLog(fmt::format("Invalid color: {}", str));
+
+    return LingoColor::kNone;
+  }
+}
diff --git a/src/game_data.h b/src/game_data.h
index 24760de..0facd12 100644
--- a/src/game_data.h
+++ b/src/game_data.h
@@ -189,4 +189,6 @@ const SubwayItem& GD_GetSubwayItem(int id);
 std::optional<int> GD_GetSubwayItemForPainting(const std::string& painting_id);
 int GD_GetSubwayItemForSunwarp(const SubwaySunwarp& sunwarp);
 
+LingoColor GetLingoColorForString(const std::string& str);
+
 #endif /* end of include guard: GAME_DATA_H_9C42AC51 */
diff --git a/src/subway_map.cpp b/src/subway_map.cpp
index 94292fd..55ac411 100644
--- a/src/subway_map.cpp
+++ b/src/subway_map.cpp
@@ -551,6 +551,18 @@ void SubwayMap::Redraw() {
       brush_color = wxGREEN_BRUSH;
     } else if (subway_item.special == "starting_room_overhead") {
       // Do not draw.
+    } else if (AP_IsColorShuffle() && subway_item.special &&
+               subway_item.special->starts_with("color_")) {
+      std::string color_name = subway_item.special->substr(6);
+      LingoColor lingo_color = GetLingoColorForString(color_name);
+      int color_item_id = GD_GetItemIdForColor(lingo_color);
+
+      draw_type = ItemDrawType::kBox;
+      if (AP_HasItemSafe(color_item_id)) {
+        brush_color = wxGREEN_BRUSH;
+      } else {
+        brush_color = wxRED_BRUSH;
+      }
     } else if (subway_item.special == "sun_painting") {
       if (!AP_IsPilgrimageEnabled()) {
         draw_type = ItemDrawType::kOwl;
-- 
cgit 1.4.1