mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-06 00:53:52 +00:00
feat: show discovered taxi nodes as markers on the world map
Add gold diamond markers for every flight master the player has already discovered (knownTaxiMask_), read from TaxiNodes.dbc and filtered to the current continent/map being displayed: - WorldMapTaxiNode struct carries canonical WoW coords + known flag - WorldMap::setTaxiNodes() accepts the per-frame list from game_screen - renderImGuiOverlay() projects each known node to UV, draws a gold diamond (AddQuadFilled) with a dark outline, and shows the node name as a tooltip on hover - GameHandler::isKnownTaxiNode(id) checks knownTaxiMask_[] efficiently - Markers update live — newly discovered nodes appear without reopening the map
This commit is contained in:
parent
488ec945b6
commit
d60d296b77
4 changed files with 75 additions and 0 deletions
|
|
@ -1919,6 +1919,11 @@ public:
|
||||||
float x = 0, y = 0, z = 0;
|
float x = 0, y = 0, z = 0;
|
||||||
};
|
};
|
||||||
const std::unordered_map<uint32_t, TaxiNode>& getTaxiNodes() const { return taxiNodes_; }
|
const std::unordered_map<uint32_t, TaxiNode>& getTaxiNodes() const { return taxiNodes_; }
|
||||||
|
bool isKnownTaxiNode(uint32_t nodeId) const {
|
||||||
|
if (nodeId == 0 || nodeId > 384) return false;
|
||||||
|
uint32_t idx = nodeId - 1;
|
||||||
|
return (knownTaxiMask_[idx / 32] & (1u << (idx % 32))) != 0;
|
||||||
|
}
|
||||||
uint32_t getTaxiCostTo(uint32_t destNodeId) const;
|
uint32_t getTaxiCostTo(uint32_t destNodeId) const;
|
||||||
bool taxiNpcHasRoutes(uint64_t guid) const {
|
bool taxiNpcHasRoutes(uint64_t guid) const {
|
||||||
auto it = taxiNpcHasRoutes_.find(guid);
|
auto it = taxiNpcHasRoutes_.find(guid);
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,15 @@ struct WorldMapPartyDot {
|
||||||
std::string name; ///< Member name (shown as tooltip on hover)
|
std::string name; ///< Member name (shown as tooltip on hover)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Taxi (flight master) node passed from the UI layer for world map overlay.
|
||||||
|
struct WorldMapTaxiNode {
|
||||||
|
uint32_t id = 0; ///< TaxiNodes.dbc ID
|
||||||
|
uint32_t mapId = 0; ///< WoW internal map ID (0=EK,1=Kal,530=Outland,571=Northrend)
|
||||||
|
float wowX = 0, wowY = 0, wowZ = 0; ///< Canonical WoW coordinates
|
||||||
|
std::string name; ///< Node name (shown as tooltip)
|
||||||
|
bool known = false; ///< Player has discovered this node
|
||||||
|
};
|
||||||
|
|
||||||
struct WorldMapZone {
|
struct WorldMapZone {
|
||||||
uint32_t wmaID = 0;
|
uint32_t wmaID = 0;
|
||||||
uint32_t areaID = 0; // 0 = continent level
|
uint32_t areaID = 0; // 0 = continent level
|
||||||
|
|
@ -57,6 +66,7 @@ public:
|
||||||
void setMapName(const std::string& name);
|
void setMapName(const std::string& name);
|
||||||
void setServerExplorationMask(const std::vector<uint32_t>& masks, bool hasData);
|
void setServerExplorationMask(const std::vector<uint32_t>& masks, bool hasData);
|
||||||
void setPartyDots(std::vector<WorldMapPartyDot> dots) { partyDots_ = std::move(dots); }
|
void setPartyDots(std::vector<WorldMapPartyDot> dots) { partyDots_ = std::move(dots); }
|
||||||
|
void setTaxiNodes(std::vector<WorldMapTaxiNode> nodes) { taxiNodes_ = std::move(nodes); }
|
||||||
bool isOpen() const { return open; }
|
bool isOpen() const { return open; }
|
||||||
void close() { open = false; }
|
void close() { open = false; }
|
||||||
|
|
||||||
|
|
@ -127,6 +137,10 @@ private:
|
||||||
// Party member dots (set each frame from the UI layer)
|
// Party member dots (set each frame from the UI layer)
|
||||||
std::vector<WorldMapPartyDot> partyDots_;
|
std::vector<WorldMapPartyDot> partyDots_;
|
||||||
|
|
||||||
|
// Taxi node markers (set each frame from the UI layer)
|
||||||
|
std::vector<WorldMapTaxiNode> taxiNodes_;
|
||||||
|
int currentMapId_ = -1; ///< WoW map ID currently loaded (set in loadZonesFromDBC)
|
||||||
|
|
||||||
// Exploration / fog of war
|
// Exploration / fog of war
|
||||||
std::vector<uint32_t> serverExplorationMask;
|
std::vector<uint32_t> serverExplorationMask;
|
||||||
bool hasServerExplorationMask = false;
|
bool hasServerExplorationMask = false;
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,7 @@ void WorldMap::loadZonesFromDBC() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentMapId_ = mapID;
|
||||||
LOG_INFO("WorldMap: loaded ", zones.size(), " zones for mapID=", mapID,
|
LOG_INFO("WorldMap: loaded ", zones.size(), " zones for mapID=", mapID,
|
||||||
", continentIdx=", continentIdx);
|
", continentIdx=", continentIdx);
|
||||||
}
|
}
|
||||||
|
|
@ -1059,6 +1060,42 @@ void WorldMap::renderImGuiOverlay(const glm::vec3& playerRenderPos, int screenWi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Taxi node markers — flight master icons on the map
|
||||||
|
if (currentIdx >= 0 && viewLevel != ViewLevel::WORLD && !taxiNodes_.empty()) {
|
||||||
|
ImVec2 mp = ImGui::GetMousePos();
|
||||||
|
for (const auto& node : taxiNodes_) {
|
||||||
|
if (!node.known) continue;
|
||||||
|
if (static_cast<int>(node.mapId) != currentMapId_) continue;
|
||||||
|
|
||||||
|
glm::vec3 rPos = core::coords::canonicalToRender(
|
||||||
|
glm::vec3(node.wowX, node.wowY, node.wowZ));
|
||||||
|
glm::vec2 uv = renderPosToMapUV(rPos, currentIdx);
|
||||||
|
if (uv.x < 0.0f || uv.x > 1.0f || uv.y < 0.0f || uv.y > 1.0f) continue;
|
||||||
|
|
||||||
|
float px = imgMin.x + uv.x * displayW;
|
||||||
|
float py = imgMin.y + uv.y * displayH;
|
||||||
|
|
||||||
|
// Flight-master icon: yellow diamond with dark border
|
||||||
|
constexpr float H = 5.0f; // half-size of diamond
|
||||||
|
ImVec2 top2(px, py - H);
|
||||||
|
ImVec2 right2(px + H, py );
|
||||||
|
ImVec2 bot2(px, py + H);
|
||||||
|
ImVec2 left2(px - H, py );
|
||||||
|
drawList->AddQuadFilled(top2, right2, bot2, left2,
|
||||||
|
IM_COL32(255, 215, 0, 230));
|
||||||
|
drawList->AddQuad(top2, right2, bot2, left2,
|
||||||
|
IM_COL32(80, 50, 0, 200), 1.2f);
|
||||||
|
|
||||||
|
// Tooltip on hover
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Hover coordinate display — show WoW coordinates under cursor
|
// Hover coordinate display — show WoW coordinates under cursor
|
||||||
if (currentIdx >= 0 && viewLevel != ViewLevel::WORLD) {
|
if (currentIdx >= 0 && viewLevel != ViewLevel::WORLD) {
|
||||||
auto& io = ImGui::GetIO();
|
auto& io = ImGui::GetIO();
|
||||||
|
|
|
||||||
|
|
@ -7033,6 +7033,25 @@ void GameScreen::renderWorldMap(game::GameHandler& gameHandler) {
|
||||||
wm->setPartyDots(std::move(dots));
|
wm->setPartyDots(std::move(dots));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Taxi node markers on world map
|
||||||
|
{
|
||||||
|
std::vector<rendering::WorldMapTaxiNode> taxiNodes;
|
||||||
|
const auto& nodes = gameHandler.getTaxiNodes();
|
||||||
|
taxiNodes.reserve(nodes.size());
|
||||||
|
for (const auto& [id, node] : nodes) {
|
||||||
|
rendering::WorldMapTaxiNode wtn;
|
||||||
|
wtn.id = node.id;
|
||||||
|
wtn.mapId = node.mapId;
|
||||||
|
wtn.wowX = node.x;
|
||||||
|
wtn.wowY = node.y;
|
||||||
|
wtn.wowZ = node.z;
|
||||||
|
wtn.name = node.name;
|
||||||
|
wtn.known = gameHandler.isKnownTaxiNode(id);
|
||||||
|
taxiNodes.push_back(std::move(wtn));
|
||||||
|
}
|
||||||
|
wm->setTaxiNodes(std::move(taxiNodes));
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec3 playerPos = renderer->getCharacterPosition();
|
glm::vec3 playerPos = renderer->getCharacterPosition();
|
||||||
float playerYaw = renderer->getCharacterYaw();
|
float playerYaw = renderer->getCharacterYaw();
|
||||||
auto* window = app.getWindow();
|
auto* window = app.getWindow();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue