diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index f39d5061..7c17820d 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -354,6 +354,11 @@ private: // Dungeon Finder state bool showDungeonFinder_ = false; + + // Achievements window + bool showAchievementWindow_ = false; + char achievementSearchBuf_[128] = {}; + void renderAchievementWindow(game::GameHandler& gameHandler); uint8_t lfgRoles_ = 0x08; // default: DPS (0x02=tank, 0x04=healer, 0x08=dps) uint32_t lfgSelectedDungeon_ = 861; // default: random dungeon (entry 861 = Random Dungeon WotLK) diff --git a/include/ui/keybinding_manager.hpp b/include/ui/keybinding_manager.hpp index 09c9ac05..385340ab 100644 --- a/include/ui/keybinding_manager.hpp +++ b/include/ui/keybinding_manager.hpp @@ -30,6 +30,7 @@ public: TOGGLE_NAMEPLATES, TOGGLE_RAID_FRAMES, TOGGLE_QUEST_LOG, + TOGGLE_ACHIEVEMENTS, ACTION_COUNT }; diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 9a020d6a..f8f95801 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -497,6 +497,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { renderAuctionHouseWindow(gameHandler); renderDungeonFinderWindow(gameHandler); renderInstanceLockouts(gameHandler); + renderAchievementWindow(gameHandler); // renderQuestMarkers(gameHandler); // Disabled - using 3D billboard markers now if (showMinimap_) { renderMinimapMarkers(gameHandler); @@ -1762,6 +1763,10 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) { questLogScreen.toggle(); } + if (KeybindingManager::getInstance().isActionPressed(KeybindingManager::Action::TOGGLE_ACHIEVEMENTS)) { + showAchievementWindow_ = !showAchievementWindow_; + } + // Action bar keys (1-9, 0, -, =) static const SDL_Scancode actionBarKeys[] = { SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, @@ -14326,4 +14331,68 @@ void GameScreen::renderBattlegroundScore(game::GameHandler& gameHandler) { ImGui::PopStyleVar(2); } +// ─── Achievement Window ─────────────────────────────────────────────────────── +void GameScreen::renderAchievementWindow(game::GameHandler& gameHandler) { + if (!showAchievementWindow_) return; + + ImGui::SetNextWindowSize(ImVec2(420, 480), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowPos(ImVec2(200, 150), ImGuiCond_FirstUseEver); + + if (!ImGui::Begin("Achievements", &showAchievementWindow_)) { + ImGui::End(); + return; + } + + const auto& earned = gameHandler.getEarnedAchievements(); + ImGui::Text("Earned: %u", static_cast(earned.size())); + ImGui::SameLine(); + ImGui::SetNextItemWidth(180.0f); + ImGui::InputText("##achsearch", achievementSearchBuf_, sizeof(achievementSearchBuf_)); + ImGui::SameLine(); + if (ImGui::Button("Clear")) achievementSearchBuf_[0] = '\0'; + ImGui::Separator(); + + if (earned.empty()) { + ImGui::TextDisabled("No achievements earned yet."); + ImGui::End(); + return; + } + + ImGui::BeginChild("##achlist", ImVec2(0, 0), false); + + std::string filter(achievementSearchBuf_); + // lower-case filter for case-insensitive matching + for (char& c : filter) c = static_cast(tolower(static_cast(c))); + + // Collect and sort ids for stable display + std::vector ids(earned.begin(), earned.end()); + std::sort(ids.begin(), ids.end()); + + for (uint32_t id : ids) { + const std::string& name = gameHandler.getAchievementName(id); + const std::string& display = name.empty() ? std::to_string(id) : name; + + if (!filter.empty()) { + std::string lower = display; + for (char& c : lower) c = static_cast(tolower(static_cast(c))); + if (lower.find(filter) == std::string::npos) continue; + } + + ImGui::PushID(static_cast(id)); + ImGui::TextColored(ImVec4(1.0f, 0.85f, 0.0f, 1.0f), "[Achievement]"); + ImGui::SameLine(); + ImGui::TextUnformatted(display.c_str()); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("ID: %u", id); + if (!name.empty()) ImGui::TextDisabled("%s", name.c_str()); + ImGui::EndTooltip(); + } + ImGui::PopID(); + } + + ImGui::EndChild(); + ImGui::End(); +} + }} // namespace wowee::ui diff --git a/src/ui/keybinding_manager.cpp b/src/ui/keybinding_manager.cpp index 212d2af0..5ac79927 100644 --- a/src/ui/keybinding_manager.cpp +++ b/src/ui/keybinding_manager.cpp @@ -31,6 +31,7 @@ void KeybindingManager::initializeDefaults() { bindings_[static_cast(Action::TOGGLE_NAMEPLATES)] = ImGuiKey_V; bindings_[static_cast(Action::TOGGLE_RAID_FRAMES)] = ImGuiKey_F; // Reassigned from R (now camera reset) bindings_[static_cast(Action::TOGGLE_QUEST_LOG)] = ImGuiKey_Q; + bindings_[static_cast(Action::TOGGLE_ACHIEVEMENTS)] = ImGuiKey_Y; // WoW standard key (Shift+Y in retail) } bool KeybindingManager::isActionPressed(Action action, bool repeat) { @@ -71,6 +72,7 @@ const char* KeybindingManager::getActionName(Action action) { case Action::TOGGLE_NAMEPLATES: return "Nameplates"; case Action::TOGGLE_RAID_FRAMES: return "Raid Frames"; case Action::TOGGLE_QUEST_LOG: return "Quest Log"; + case Action::TOGGLE_ACHIEVEMENTS: return "Achievements"; case Action::ACTION_COUNT: break; } return "Unknown"; @@ -135,6 +137,7 @@ void KeybindingManager::loadFromConfigFile(const std::string& filePath) { else if (action == "toggle_nameplates") actionIdx = static_cast(Action::TOGGLE_NAMEPLATES); else if (action == "toggle_raid_frames") actionIdx = static_cast(Action::TOGGLE_RAID_FRAMES); else if (action == "toggle_quest_log") actionIdx = static_cast(Action::TOGGLE_QUEST_LOG); + else if (action == "toggle_achievements") actionIdx = static_cast(Action::TOGGLE_ACHIEVEMENTS); if (actionIdx < 0) continue; @@ -226,6 +229,7 @@ void KeybindingManager::saveToConfigFile(const std::string& filePath) const { {Action::TOGGLE_NAMEPLATES, "toggle_nameplates"}, {Action::TOGGLE_RAID_FRAMES, "toggle_raid_frames"}, {Action::TOGGLE_QUEST_LOG, "toggle_quest_log"}, + {Action::TOGGLE_ACHIEVEMENTS, "toggle_achievements"}, }; for (const auto& [action, nameStr] : actionMap) {