feat: parse Classic SMSG_INSPECT gear + implement temp weapon enchant timers

Classic 1.12 SMSG_INSPECT (wire 0x115): parse PackedGUID + 19×uint32
itemEntries to populate InspectResult and inspectedPlayerItemEntries_ cache,
enabling gear inspection of other players on Classic servers. Triggers item
queries for all filled slots so the inspect window shows names/ilevels.

SMSG_ITEM_ENCHANT_TIME_UPDATE: parse itemGuid/slot/durationSec/playerGuid and
store per-slot expire timestamps in tempEnchantTimers_. Fires 5min/1min
chat warnings before expiry. getTempEnchantRemainingMs() helper queries live
remaining time. Buff bar renders timed slot buttons (gold/teal/purple per
slot) that pulse red below 60s — useful for Shaman imbues, Rogue poisons,
whetstones and oils across all three expansions.
This commit is contained in:
Kelsi 2026-03-12 18:15:51 -07:00
parent 2f479c6230
commit 218d68e275
3 changed files with 178 additions and 4 deletions

View file

@ -12036,6 +12036,60 @@ void GameScreen::renderBuffBar(game::GameHandler& gameHandler) {
}
ImGui::PopStyleColor(2);
}
// Temporary weapon enchant timers (Shaman imbues, Rogue poisons, whetstones, etc.)
{
const auto& timers = gameHandler.getTempEnchantTimers();
if (!timers.empty()) {
ImGui::Spacing();
ImGui::Separator();
static const ImVec4 kEnchantSlotColors[] = {
ImVec4(0.9f, 0.6f, 0.1f, 1.0f), // main-hand: gold
ImVec4(0.5f, 0.8f, 0.9f, 1.0f), // off-hand: teal
ImVec4(0.7f, 0.5f, 0.9f, 1.0f), // ranged: purple
};
uint64_t enchNowMs = static_cast<uint64_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch()).count());
for (const auto& t : timers) {
if (t.slot > 2) continue;
uint64_t remMs = (t.expireMs > enchNowMs) ? (t.expireMs - enchNowMs) : 0;
if (remMs == 0) continue;
ImVec4 col = kEnchantSlotColors[t.slot];
// Flash red when < 60s remaining
if (remMs < 60000) {
float pulse = 0.6f + 0.4f * std::sin(
static_cast<float>(ImGui::GetTime()) * 4.0f);
col = ImVec4(pulse, 0.2f, 0.1f, 1.0f);
}
// Format remaining time
uint32_t secs = static_cast<uint32_t>((remMs + 999) / 1000);
char timeStr[16];
if (secs >= 3600)
snprintf(timeStr, sizeof(timeStr), "%dh%02dm", secs / 3600, (secs % 3600) / 60);
else if (secs >= 60)
snprintf(timeStr, sizeof(timeStr), "%d:%02d", secs / 60, secs % 60);
else
snprintf(timeStr, sizeof(timeStr), "%ds", secs);
ImGui::PushID(static_cast<int>(t.slot) + 5000);
ImGui::PushStyleColor(ImGuiCol_Button, col);
char label[40];
snprintf(label, sizeof(label), "~%s %s",
game::GameHandler::kTempEnchantSlotNames[t.slot], timeStr);
ImGui::Button(label, ImVec2(-1, 16));
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Temporary weapon enchant: %s\nRemaining: %s",
game::GameHandler::kTempEnchantSlotNames[t.slot],
timeStr);
ImGui::PopStyleColor();
ImGui::PopID();
}
}
}
}
ImGui::End();