diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index ef1410bb..639fd577 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -237,6 +237,7 @@ private: void renderGuildBankWindow(game::GameHandler& gameHandler); void renderAuctionHouseWindow(game::GameHandler& gameHandler); void renderDungeonFinderWindow(game::GameHandler& gameHandler); + void renderInstanceLockouts(game::GameHandler& gameHandler); /** * Inventory screen @@ -269,6 +270,9 @@ private: int bagBarPickedSlot_ = -1; // Visual drag in progress (-1 = none) int bagBarDragSource_ = -1; // Mouse pressed on this slot, waiting for drag or click (-1 = none) + // Instance Lockouts window + bool showInstanceLockouts_ = false; + // Dungeon Finder state bool showDungeonFinder_ = false; uint8_t lfgRoles_ = 0x08; // default: DPS (0x02=tank, 0x04=healer, 0x08=dps) diff --git a/src/core/application.cpp b/src/core/application.cpp index 4ff9a73b..5741b877 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -4841,11 +4841,9 @@ void Application::spawnOnlineCreature(uint64_t guid, uint32_t displayId, float x // Check model cache - reuse if same displayId was already loaded uint32_t modelId = 0; - bool modelCached = false; auto cacheIt = displayIdModelCache_.find(displayId); if (cacheIt != displayIdModelCache_.end()) { modelId = cacheIt->second; - modelCached = true; } else { // Load model from disk (only once per displayId) modelId = nextCreatureModelId_++; diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index e94fc381..25a4400f 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -11525,7 +11525,6 @@ void GameHandler::handleMonsterMoveTransport(network::Packet& packet) { if (hasDest && duration > 0) { glm::vec3 destLocalCanonical = core::coords::serverToCanonical(glm::vec3(destLocalX, destLocalY, destLocalZ)); - glm::vec3 startWorld = transportManager_->getPlayerWorldPosition(transportGuid, startLocalCanonical); glm::vec3 destWorld = transportManager_->getPlayerWorldPosition(transportGuid, destLocalCanonical); // Face toward destination unless an explicit facing was given diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index eae66ab5..0d7c42c2 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -422,6 +422,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { renderGuildBankWindow(gameHandler); renderAuctionHouseWindow(gameHandler); renderDungeonFinderWindow(gameHandler); + renderInstanceLockouts(gameHandler); // renderQuestMarkers(gameHandler); // Disabled - using 3D billboard markers now renderMinimapMarkers(gameHandler); renderDeathScreen(gameHandler); @@ -2015,7 +2016,7 @@ void GameScreen::renderTargetFrame(game::GameHandler& gameHandler) { void GameScreen::sendChatMessage(game::GameHandler& gameHandler) { if (strlen(chatInputBuffer) > 0) { std::string input(chatInputBuffer); - game::ChatType type; + game::ChatType type = game::ChatType::SAY; std::string message = input; std::string target; @@ -6320,6 +6321,10 @@ void GameScreen::renderEscapeMenu() { settingsInit = false; showEscapeMenu = false; } + if (ImGui::Button("Instance Lockouts", ImVec2(-1, 0))) { + showInstanceLockouts_ = true; + showEscapeMenu = false; + } ImGui::Spacing(); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 10.0f)); @@ -9539,4 +9544,120 @@ void GameScreen::renderDungeonFinderWindow(game::GameHandler& gameHandler) { ImGui::End(); } +// ============================================================ +// Instance Lockouts +// ============================================================ + +void GameScreen::renderInstanceLockouts(game::GameHandler& gameHandler) { + if (!showInstanceLockouts_) return; + + ImGui::SetNextWindowSize(ImVec2(480, 0), ImGuiCond_Appearing); + ImGui::SetNextWindowPos( + ImVec2(ImGui::GetIO().DisplaySize.x / 2 - 240, 140), ImGuiCond_Appearing); + + if (!ImGui::Begin("Instance Lockouts", &showInstanceLockouts_, + ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::End(); + return; + } + + const auto& lockouts = gameHandler.getInstanceLockouts(); + + if (lockouts.empty()) { + ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "No active instance lockouts."); + } else { + // Build map name lookup from Map.dbc (cached after first call) + static std::unordered_map sMapNames; + static bool sMapNamesLoaded = false; + if (!sMapNamesLoaded) { + sMapNamesLoaded = true; + if (auto* am = core::Application::getInstance().getAssetManager()) { + if (auto dbc = am->loadDBC("Map.dbc"); dbc && dbc->isLoaded()) { + for (uint32_t i = 0; i < dbc->getRecordCount(); ++i) { + uint32_t id = dbc->getUInt32(i, 0); + // Field 2 = MapName_enUS (first localized), field 1 = InternalName + std::string name = dbc->getString(i, 2); + if (name.empty()) name = dbc->getString(i, 1); + if (!name.empty()) sMapNames[id] = std::move(name); + } + } + } + } + + auto difficultyLabel = [](uint32_t diff) -> const char* { + switch (diff) { + case 0: return "Normal"; + case 1: return "Heroic"; + case 2: return "25-Man"; + case 3: return "25-Man Heroic"; + default: return "Unknown"; + } + }; + + // Current UTC time for reset countdown + auto nowSec = static_cast(std::time(nullptr)); + + if (ImGui::BeginTable("lockouts", 4, + ImGuiTableFlags_SizingStretchProp | + ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter)) { + ImGui::TableSetupColumn("Instance", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("Difficulty", ImGuiTableColumnFlags_WidthFixed, 110.0f); + ImGui::TableSetupColumn("Resets In", ImGuiTableColumnFlags_WidthFixed, 100.0f); + ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 60.0f); + ImGui::TableHeadersRow(); + + for (const auto& lo : lockouts) { + ImGui::TableNextRow(); + + // Instance name + ImGui::TableSetColumnIndex(0); + auto it = sMapNames.find(lo.mapId); + if (it != sMapNames.end()) { + ImGui::TextUnformatted(it->second.c_str()); + } else { + ImGui::Text("Map %u", lo.mapId); + } + + // Difficulty + ImGui::TableSetColumnIndex(1); + ImGui::TextUnformatted(difficultyLabel(lo.difficulty)); + + // Reset countdown + ImGui::TableSetColumnIndex(2); + if (lo.resetTime > nowSec) { + uint64_t remaining = lo.resetTime - nowSec; + uint64_t days = remaining / 86400; + uint64_t hours = (remaining % 86400) / 3600; + if (days > 0) { + ImGui::Text("%llud %lluh", + static_cast(days), + static_cast(hours)); + } else { + uint64_t mins = (remaining % 3600) / 60; + ImGui::Text("%lluh %llum", + static_cast(hours), + static_cast(mins)); + } + } else { + ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "Expired"); + } + + // Locked / Extended status + ImGui::TableSetColumnIndex(3); + if (lo.extended) { + ImGui::TextColored(ImVec4(0.3f, 0.7f, 1.0f, 1.0f), "Ext"); + } else if (lo.locked) { + ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "Locked"); + } else { + ImGui::TextColored(ImVec4(0.5f, 0.9f, 0.5f, 1.0f), "Open"); + } + } + + ImGui::EndTable(); + } + } + + ImGui::End(); +} + }} // namespace wowee::ui