diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index c2320681..d01b3638 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -368,6 +368,7 @@ private: void renderNameplates(game::GameHandler& gameHandler); void renderBattlegroundScore(game::GameHandler& gameHandler); void renderDPSMeter(game::GameHandler& gameHandler); + void renderDurabilityWarning(game::GameHandler& gameHandler); /** * Inventory screen diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index c724ceb7..abf95f72 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -565,6 +565,7 @@ void GameScreen::render(game::GameHandler& gameHandler) { renderRaidWarningOverlay(gameHandler); renderCombatText(gameHandler); renderDPSMeter(gameHandler); + renderDurabilityWarning(gameHandler); renderUIErrors(gameHandler, ImGui::GetIO().DeltaTime); renderRepToasts(ImGui::GetIO().DeltaTime); renderQuestCompleteToasts(ImGui::GetIO().DeltaTime); @@ -9088,6 +9089,72 @@ void GameScreen::renderPartyFrames(game::GameHandler& gameHandler) { ImGui::PopStyleVar(); } +// ============================================================ +// Durability Warning (equipment damage indicator) +// ============================================================ + +void GameScreen::renderDurabilityWarning(game::GameHandler& gameHandler) { + if (gameHandler.getPlayerGuid() == 0) return; + + const auto& inv = gameHandler.getInventory(); + + // Scan all equipment slots (skip bag slots which have no durability) + float minDurPct = 1.0f; + bool hasBroken = false; + + for (int i = static_cast(game::EquipSlot::HEAD); + i < static_cast(game::EquipSlot::BAG1); ++i) { + const auto& slot = inv.getEquipSlot(static_cast(i)); + if (slot.empty() || slot.item.maxDurability == 0) continue; + if (slot.item.curDurability == 0) { + hasBroken = true; + } + float pct = static_cast(slot.item.curDurability) / + static_cast(slot.item.maxDurability); + if (pct < minDurPct) minDurPct = pct; + } + + // Only show warning below 20% + if (minDurPct >= 0.2f && !hasBroken) return; + + ImGuiIO& io = ImGui::GetIO(); + const float screenW = io.DisplaySize.x; + const float screenH = io.DisplaySize.y; + + // Position: just above the XP bar / action bar area (bottom-center) + const float warningW = 220.0f; + const float warningH = 26.0f; + const float posX = (screenW - warningW) * 0.5f; + const float posY = screenH - 140.0f; // above action bar + + ImGui::SetNextWindowPos(ImVec2(posX, posY), ImGuiCond_Always); + ImGui::SetNextWindowSize(ImVec2(warningW, warningH), ImGuiCond_Always); + ImGui::SetNextWindowBgAlpha(0.75f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(6, 4)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); + + ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | + ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoBringToFrontOnFocus; + + if (ImGui::Begin("##durability_warn", nullptr, flags)) { + if (hasBroken) { + ImGui::TextColored(ImVec4(1.0f, 0.15f, 0.15f, 1.0f), + "\xef\x94\x9b Gear broken! Visit a repair NPC"); + } else { + int pctInt = static_cast(minDurPct * 100.0f); + ImGui::TextColored(ImVec4(1.0f, 0.85f, 0.1f, 1.0f), + "\xef\x94\x9b Low durability: %d%%", pctInt); + } + if (ImGui::IsWindowHovered()) + ImGui::SetTooltip("Your equipment is damaged. Visit any blacksmith or repair NPC."); + } + ImGui::End(); + ImGui::PopStyleVar(3); +} + // ============================================================ // UI Error Frame (WoW-style center-bottom error overlay) // ============================================================