mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-23 07:40:14 +00:00
feat: add aura icons to boss frame with DoT tracking and duration overlays
This commit is contained in:
parent
3665723622
commit
3d1b187986
1 changed files with 135 additions and 0 deletions
|
|
@ -9339,6 +9339,141 @@ void GameScreen::renderBossFrames(game::GameHandler& gameHandler) {
|
|||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
// Boss aura row: debuffs first (player DoTs), then boss buffs
|
||||
{
|
||||
const std::vector<game::AuraSlot>* bossAuras = nullptr;
|
||||
if (bs.guid == gameHandler.getTargetGuid())
|
||||
bossAuras = &gameHandler.getTargetAuras();
|
||||
else
|
||||
bossAuras = gameHandler.getUnitAuras(bs.guid);
|
||||
|
||||
if (bossAuras) {
|
||||
int bossActive = 0;
|
||||
for (const auto& a : *bossAuras) if (!a.isEmpty()) bossActive++;
|
||||
if (bossActive > 0) {
|
||||
constexpr float BA_ICON = 16.0f;
|
||||
constexpr int BA_PER_ROW = 10;
|
||||
|
||||
uint64_t baNowMs = static_cast<uint64_t>(
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch()).count());
|
||||
|
||||
// Sort: player-applied debuffs first (most relevant), then others
|
||||
const uint64_t pguid = gameHandler.getPlayerGuid();
|
||||
std::vector<size_t> baIdx;
|
||||
baIdx.reserve(bossAuras->size());
|
||||
for (size_t i = 0; i < bossAuras->size(); ++i)
|
||||
if (!(*bossAuras)[i].isEmpty()) baIdx.push_back(i);
|
||||
std::sort(baIdx.begin(), baIdx.end(), [&](size_t a, size_t b) {
|
||||
const auto& aa = (*bossAuras)[a];
|
||||
const auto& ab = (*bossAuras)[b];
|
||||
bool aPlayerDot = (aa.flags & 0x80) != 0 && aa.casterGuid == pguid;
|
||||
bool bPlayerDot = (ab.flags & 0x80) != 0 && ab.casterGuid == pguid;
|
||||
if (aPlayerDot != bPlayerDot) return aPlayerDot > bPlayerDot;
|
||||
bool aDebuff = (aa.flags & 0x80) != 0;
|
||||
bool bDebuff = (ab.flags & 0x80) != 0;
|
||||
if (aDebuff != bDebuff) return aDebuff > bDebuff;
|
||||
int32_t ra = aa.getRemainingMs(baNowMs);
|
||||
int32_t rb = ab.getRemainingMs(baNowMs);
|
||||
if (ra < 0 && rb < 0) return false;
|
||||
if (ra < 0) return false;
|
||||
if (rb < 0) return true;
|
||||
return ra < rb;
|
||||
});
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2.0f, 2.0f));
|
||||
int baShown = 0;
|
||||
for (size_t si = 0; si < baIdx.size() && baShown < 20; ++si) {
|
||||
const auto& aura = (*bossAuras)[baIdx[si]];
|
||||
bool isBuff = (aura.flags & 0x80) == 0;
|
||||
bool isPlayerCast = (aura.casterGuid == pguid);
|
||||
|
||||
if (baShown > 0 && baShown % BA_PER_ROW != 0) ImGui::SameLine();
|
||||
ImGui::PushID(static_cast<int>(baIdx[si]) + 7000);
|
||||
|
||||
ImVec4 borderCol;
|
||||
if (isBuff) {
|
||||
// Boss buffs: gold for important enrage/shield types
|
||||
borderCol = ImVec4(0.8f, 0.6f, 0.1f, 0.9f);
|
||||
} else {
|
||||
uint8_t dt = gameHandler.getSpellDispelType(aura.spellId);
|
||||
switch (dt) {
|
||||
case 1: borderCol = ImVec4(0.15f, 0.50f, 1.00f, 0.9f); break;
|
||||
case 2: borderCol = ImVec4(0.70f, 0.20f, 0.90f, 0.9f); break;
|
||||
case 3: borderCol = ImVec4(0.55f, 0.30f, 0.10f, 0.9f); break;
|
||||
case 4: borderCol = ImVec4(0.10f, 0.70f, 0.10f, 0.9f); break;
|
||||
default: borderCol = isPlayerCast
|
||||
? ImVec4(0.90f, 0.30f, 0.10f, 0.9f) // player DoT: orange-red
|
||||
: ImVec4(0.60f, 0.20f, 0.20f, 0.9f); // other debuff: dark red
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VkDescriptorSet baIcon = assetMgr
|
||||
? getSpellIcon(aura.spellId, assetMgr) : VK_NULL_HANDLE;
|
||||
if (baIcon) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, borderCol);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1, 1));
|
||||
ImGui::ImageButton("##baura",
|
||||
(ImTextureID)(uintptr_t)baIcon,
|
||||
ImVec2(BA_ICON - 2, BA_ICON - 2));
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor();
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, borderCol);
|
||||
char lab[8];
|
||||
snprintf(lab, sizeof(lab), "%u", aura.spellId % 10000);
|
||||
ImGui::Button(lab, ImVec2(BA_ICON, BA_ICON));
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
// Duration overlay
|
||||
int32_t baRemain = aura.getRemainingMs(baNowMs);
|
||||
if (baRemain > 0) {
|
||||
ImVec2 imin = ImGui::GetItemRectMin();
|
||||
ImVec2 imax = ImGui::GetItemRectMax();
|
||||
char ts[12];
|
||||
int s = (baRemain + 999) / 1000;
|
||||
if (s >= 3600) snprintf(ts, sizeof(ts), "%dh", s / 3600);
|
||||
else if (s >= 60) snprintf(ts, sizeof(ts), "%d:%02d", s / 60, s % 60);
|
||||
else snprintf(ts, sizeof(ts), "%d", s);
|
||||
ImVec2 tsz = ImGui::CalcTextSize(ts);
|
||||
float cx = imin.x + (imax.x - imin.x - tsz.x) * 0.5f;
|
||||
float cy = imax.y - tsz.y;
|
||||
ImGui::GetWindowDrawList()->AddText(ImVec2(cx + 1, cy + 1), IM_COL32(0, 0, 0, 180), ts);
|
||||
ImGui::GetWindowDrawList()->AddText(ImVec2(cx, cy), IM_COL32(255, 255, 255, 220), ts);
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
bool richOk = spellbookScreen.renderSpellInfoTooltip(
|
||||
aura.spellId, gameHandler, assetMgr);
|
||||
if (!richOk) {
|
||||
std::string nm = spellbookScreen.lookupSpellName(aura.spellId, assetMgr);
|
||||
if (nm.empty()) nm = "Spell #" + std::to_string(aura.spellId);
|
||||
ImGui::Text("%s", nm.c_str());
|
||||
}
|
||||
if (isPlayerCast && !isBuff)
|
||||
ImGui::TextColored(ImVec4(0.9f, 0.7f, 0.3f, 1.0f), "Your DoT");
|
||||
if (baRemain > 0) {
|
||||
int s = baRemain / 1000;
|
||||
char db[32];
|
||||
if (s < 60) snprintf(db, sizeof(db), "Remaining: %ds", s);
|
||||
else snprintf(db, sizeof(db), "Remaining: %dm %ds", s / 60, s % 60);
|
||||
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "%s", db);
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
baShown++;
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
ImGui::Spacing();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue