From 2300ca3653ff249f962ca216d47eafd6e7779a8d Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 21 Jul 2026 04:58:24 -0700 Subject: [PATCH] feat: show undiscovered flight points on the world map Draw undiscovered flight masters as green diamonds so players can see where flight paths exist before visiting them, keeping discovered nodes gold. Filter to the player's own faction (own-faction or neutral both- faction nodes only) so the opposite faction's flight masters and non-flight boat/zeppelin nodes are not shown. Adds GameHandler:: isPlayerAlliance() helper. --- include/game/game_handler.hpp | 11 ++++++++++ .../world_map/layers/taxi_node_layer.cpp | 20 +++++++++++++++---- src/ui/game_screen_hud.cpp | 17 +++++++++++++++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 051f9825..48bf9d9c 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -1298,6 +1298,17 @@ public: const Character* ch = getActiveCharacter(); return ch ? static_cast(ch->race) : 0; } + // Horde races: Orc, Undead, Tauren, Troll, Goblin, Blood Elf. Everything + // else (including an unknown/zero race) defaults to Alliance. + bool isPlayerAlliance() const { + switch (static_cast(getPlayerRace())) { + case Race::ORC: case Race::UNDEAD: case Race::TAUREN: + case Race::TROLL: case Race::GOBLIN: case Race::BLOOD_ELF: + return false; + default: + return true; + } + } void setPlayerGuid(uint64_t guid) { playerGuid = guid; } // Player death state diff --git a/src/rendering/world_map/layers/taxi_node_layer.cpp b/src/rendering/world_map/layers/taxi_node_layer.cpp index 0c7caff8..4fc985a4 100644 --- a/src/rendering/world_map/layers/taxi_node_layer.cpp +++ b/src/rendering/world_map/layers/taxi_node_layer.cpp @@ -119,7 +119,6 @@ void TaxiNodeLayer::renderWorldMapMarkers(const LayerContext& ctx, bool isContinent) { ImVec2 mp = ImGui::GetMousePos(); for (const auto& node : *nodes_) { - if (!node.known) continue; glm::vec3 rPos(0.0f); if (!projectNodeToDisplayedMap(node, ctx, rPos)) continue; glm::vec2 uv = renderPosToMapUV(rPos, bounds, isContinent); @@ -128,13 +127,26 @@ void TaxiNodeLayer::renderWorldMapMarkers(const LayerContext& ctx, float px = ctx.imgMin.x + uv.x * ctx.displayW; float py = ctx.imgMin.y + uv.y * ctx.displayH; - drawDiamond(ctx.drawList, px, py, 5.0f, - IM_COL32(255, 215, 0, 230), IM_COL32(80, 50, 0, 200), 1.2f); + // Discovered nodes are gold; undiscovered flight masters are drawn in + // green so the player can see where flight paths exist before visiting + // them (matches the green flight-point icon from the game). + if (node.known) { + drawDiamond(ctx.drawList, px, py, 5.0f, + IM_COL32(255, 215, 0, 230), IM_COL32(80, 50, 0, 200), 1.2f); + } else { + drawDiamond(ctx.drawList, px, py, 4.5f, + IM_COL32(70, 200, 90, 210), IM_COL32(15, 60, 25, 200), 1.2f); + } if (!node.name.empty()) { float mdx = mp.x - px, mdy = mp.y - py; if (mdx * mdx + mdy * mdy < 49.0f) { - ImGui::SetTooltip("%s\n(Flight Master)", node.name.c_str()); + if (node.known) { + ImGui::SetTooltip("%s\n(Flight Master)", node.name.c_str()); + } else { + ImGui::SetTooltip("%s\n(Flight Master — not yet discovered)", + node.name.c_str()); + } } } } diff --git a/src/ui/game_screen_hud.cpp b/src/ui/game_screen_hud.cpp index 565928d6..86bac24c 100644 --- a/src/ui/game_screen_hud.cpp +++ b/src/ui/game_screen_hud.cpp @@ -461,8 +461,23 @@ void GameScreen::renderWorldMap(game::GameHandler& gameHandler) { std::vector taxiNodes; const auto& nodes = gameHandler.getTaxiNodes(); uint32_t currentTaxiNode = gameHandler.getTaxiCurrentNode(); + const bool playerAlliance = gameHandler.isPlayerAlliance(); taxiNodes.reserve(nodes.size()); for (const auto& [id, node] : nodes) { + const bool known = gameHandler.isKnownTaxiNode(id); + // Undiscovered nodes are shown so the player can see where flight + // paths exist, but only ones their faction can actually use. A node's + // faction is inferred from which taxi mount TaxiNodes.dbc lists: + // own-faction mount → show; both mounts → neutral flight point, show; + // opposite-faction-only OR no mount at all (boat/zeppelin/script + // nodes) → hide. Known nodes are always shown. + if (!known) { + const bool hasAlliance = node.mountDisplayIdAlliance != 0; + const bool hasHorde = node.mountDisplayIdHorde != 0; + const bool bothFactions = hasAlliance && hasHorde; // neutral hub + const bool ownFaction = playerAlliance ? hasAlliance : hasHorde; + if (!bothFactions && !ownFaction) continue; + } rendering::WorldMapTaxiNode wtn; wtn.id = node.id; wtn.mapId = node.mapId; @@ -475,7 +490,7 @@ void GameScreen::renderWorldMap(game::GameHandler& gameHandler) { wtn.wowY = canonical.y; wtn.wowZ = canonical.z; wtn.name = node.name; - wtn.known = gameHandler.isKnownTaxiNode(id); + wtn.known = known; wtn.costCopper = gameHandler.getTaxiCostTo(id); wtn.current = (id == currentTaxiNode); wtn.reachable = gameHandler.hasTaxiRouteTo(id);