mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 17:43:52 +00:00
feat: add Skills/Professions window (K key) with per-category progress bars
Implements renderSkillsWindow() showing all player skills grouped by DBC category (Professions, Secondary Skills, Class Skills, Weapon Skills, Armor, Languages) with value/max progress bars and a bonus breakdown tooltip. Hooked up to the TOGGLE_SKILLS keybinding (K by default).
This commit is contained in:
parent
d44d462686
commit
48cb7df4b4
2 changed files with 118 additions and 0 deletions
|
|
@ -438,6 +438,10 @@ private:
|
||||||
char achievementSearchBuf_[128] = {};
|
char achievementSearchBuf_[128] = {};
|
||||||
void renderAchievementWindow(game::GameHandler& gameHandler);
|
void renderAchievementWindow(game::GameHandler& gameHandler);
|
||||||
|
|
||||||
|
// Skills / Professions window (K key)
|
||||||
|
bool showSkillsWindow_ = false;
|
||||||
|
void renderSkillsWindow(game::GameHandler& gameHandler);
|
||||||
|
|
||||||
// Titles window
|
// Titles window
|
||||||
bool showTitlesWindow_ = false;
|
bool showTitlesWindow_ = false;
|
||||||
void renderTitlesWindow(game::GameHandler& gameHandler);
|
void renderTitlesWindow(game::GameHandler& gameHandler);
|
||||||
|
|
|
||||||
|
|
@ -718,6 +718,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
||||||
renderWhoWindow(gameHandler);
|
renderWhoWindow(gameHandler);
|
||||||
renderCombatLog(gameHandler);
|
renderCombatLog(gameHandler);
|
||||||
renderAchievementWindow(gameHandler);
|
renderAchievementWindow(gameHandler);
|
||||||
|
renderSkillsWindow(gameHandler);
|
||||||
renderTitlesWindow(gameHandler);
|
renderTitlesWindow(gameHandler);
|
||||||
renderEquipSetWindow(gameHandler);
|
renderEquipSetWindow(gameHandler);
|
||||||
renderGmTicketWindow(gameHandler);
|
renderGmTicketWindow(gameHandler);
|
||||||
|
|
@ -2766,6 +2767,9 @@ void GameScreen::processTargetInput(game::GameHandler& gameHandler) {
|
||||||
if (KeybindingManager::getInstance().isActionPressed(KeybindingManager::Action::TOGGLE_ACHIEVEMENTS)) {
|
if (KeybindingManager::getInstance().isActionPressed(KeybindingManager::Action::TOGGLE_ACHIEVEMENTS)) {
|
||||||
showAchievementWindow_ = !showAchievementWindow_;
|
showAchievementWindow_ = !showAchievementWindow_;
|
||||||
}
|
}
|
||||||
|
if (KeybindingManager::getInstance().isActionPressed(KeybindingManager::Action::TOGGLE_SKILLS)) {
|
||||||
|
showSkillsWindow_ = !showSkillsWindow_;
|
||||||
|
}
|
||||||
|
|
||||||
// Toggle Titles window with H (hero/title screen — no conflicting keybinding)
|
// Toggle Titles window with H (hero/title screen — no conflicting keybinding)
|
||||||
if (input.isKeyJustPressed(SDL_SCANCODE_H) && !ImGui::GetIO().WantCaptureKeyboard) {
|
if (input.isKeyJustPressed(SDL_SCANCODE_H) && !ImGui::GetIO().WantCaptureKeyboard) {
|
||||||
|
|
@ -22702,4 +22706,114 @@ void GameScreen::renderEquipSetWindow(game::GameHandler& gameHandler) {
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameScreen::renderSkillsWindow(game::GameHandler& gameHandler) {
|
||||||
|
if (!showSkillsWindow_) return;
|
||||||
|
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(380, 480), ImGuiCond_FirstUseEver);
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(220, 130), ImGuiCond_FirstUseEver);
|
||||||
|
|
||||||
|
if (!ImGui::Begin("Skills & Professions", &showSkillsWindow_)) {
|
||||||
|
ImGui::End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& skills = gameHandler.getPlayerSkills();
|
||||||
|
if (skills.empty()) {
|
||||||
|
ImGui::TextDisabled("No skill data received yet.");
|
||||||
|
ImGui::End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Organise skills by category
|
||||||
|
// WoW SkillLine.dbc categories: 6=Weapon, 7=Class, 8=Armor, 9=Secondary, 11=Professions, others=Misc
|
||||||
|
struct SkillEntry {
|
||||||
|
uint32_t skillId;
|
||||||
|
const game::PlayerSkill* skill;
|
||||||
|
};
|
||||||
|
std::map<uint32_t, std::vector<SkillEntry>> byCategory;
|
||||||
|
for (const auto& [id, sk] : skills) {
|
||||||
|
uint32_t cat = gameHandler.getSkillCategory(id);
|
||||||
|
byCategory[cat].push_back({id, &sk});
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct { uint32_t cat; const char* label; } kCatOrder[] = {
|
||||||
|
{11, "Professions"},
|
||||||
|
{ 9, "Secondary Skills"},
|
||||||
|
{ 7, "Class Skills"},
|
||||||
|
{ 6, "Weapon Skills"},
|
||||||
|
{ 8, "Armor"},
|
||||||
|
{ 5, "Languages"},
|
||||||
|
{ 0, "Other"},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Collect handled categories to fall back to "Other" for unknowns
|
||||||
|
static const uint32_t kKnownCats[] = {11, 9, 7, 6, 8, 5};
|
||||||
|
|
||||||
|
// Redirect unknown categories into bucket 0
|
||||||
|
for (auto& [cat, vec] : byCategory) {
|
||||||
|
bool known = false;
|
||||||
|
for (uint32_t kc : kKnownCats) if (cat == kc) { known = true; break; }
|
||||||
|
if (!known && cat != 0) {
|
||||||
|
auto& other = byCategory[0];
|
||||||
|
other.insert(other.end(), vec.begin(), vec.end());
|
||||||
|
vec.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::BeginChild("##skillscroll", ImVec2(0, 0), false);
|
||||||
|
|
||||||
|
for (const auto& [cat, label] : kCatOrder) {
|
||||||
|
auto it = byCategory.find(cat);
|
||||||
|
if (it == byCategory.end() || it->second.empty()) continue;
|
||||||
|
|
||||||
|
auto& entries = it->second;
|
||||||
|
// Sort alphabetically within each category
|
||||||
|
std::sort(entries.begin(), entries.end(), [&](const SkillEntry& a, const SkillEntry& b) {
|
||||||
|
return gameHandler.getSkillName(a.skillId) < gameHandler.getSkillName(b.skillId);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ImGui::CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
for (const auto& e : entries) {
|
||||||
|
const std::string& name = gameHandler.getSkillName(e.skillId);
|
||||||
|
const char* displayName = name.empty() ? "Unknown" : name.c_str();
|
||||||
|
uint16_t val = e.skill->effectiveValue();
|
||||||
|
uint16_t maxVal = e.skill->maxValue;
|
||||||
|
|
||||||
|
ImGui::PushID(static_cast<int>(e.skillId));
|
||||||
|
|
||||||
|
// Name column
|
||||||
|
ImGui::TextUnformatted(displayName);
|
||||||
|
ImGui::SameLine(170.0f);
|
||||||
|
|
||||||
|
// Progress bar
|
||||||
|
float fraction = (maxVal > 0) ? static_cast<float>(val) / static_cast<float>(maxVal) : 0.0f;
|
||||||
|
char overlay[32];
|
||||||
|
snprintf(overlay, sizeof(overlay), "%u / %u", val, maxVal);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.20f, 0.55f, 0.20f, 1.0f));
|
||||||
|
ImGui::ProgressBar(fraction, ImVec2(160.0f, 14.0f), overlay);
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::Text("%s", displayName);
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Base: %u", e.skill->value);
|
||||||
|
if (e.skill->bonusPerm > 0)
|
||||||
|
ImGui::Text("Permanent bonus: +%u", e.skill->bonusPerm);
|
||||||
|
if (e.skill->bonusTemp > 0)
|
||||||
|
ImGui::Text("Temporary bonus: +%u", e.skill->bonusTemp);
|
||||||
|
ImGui::Text("Max: %u", maxVal);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
ImGui::Spacing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndChild();
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace wowee::ui
|
}} // namespace wowee::ui
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue