mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 17:43:52 +00:00
feat: zone entry toast and unspent talent points indicator
- Zone entry toast: centered slide-down banner when entering a new zone (tracks renderer's zone name, fires on change) - Talent indicator: pulsing green '! N Talent Points Available' below minimap alongside existing New Mail / BG queue indicators
This commit is contained in:
parent
b6a43d6ce7
commit
bc5a7867a9
2 changed files with 98 additions and 0 deletions
|
|
@ -106,6 +106,13 @@ private:
|
||||||
std::vector<QuestCompleteToastEntry> questCompleteToasts_;
|
std::vector<QuestCompleteToastEntry> questCompleteToasts_;
|
||||||
bool questCompleteCallbackSet_ = false;
|
bool questCompleteCallbackSet_ = false;
|
||||||
static constexpr float kQuestCompleteToastLifetime = 4.0f;
|
static constexpr float kQuestCompleteToastLifetime = 4.0f;
|
||||||
|
|
||||||
|
// Zone entry toast: brief banner when entering a new zone
|
||||||
|
struct ZoneToastEntry { std::string zoneName; float age = 0.0f; };
|
||||||
|
std::vector<ZoneToastEntry> zoneToasts_;
|
||||||
|
std::string lastKnownZone_;
|
||||||
|
static constexpr float kZoneToastLifetime = 3.0f;
|
||||||
|
void renderZoneToasts(float deltaTime);
|
||||||
bool showPlayerInfo = false;
|
bool showPlayerInfo = false;
|
||||||
bool showSocialFrame_ = false; // O key toggles social/friends list
|
bool showSocialFrame_ = false; // O key toggles social/friends list
|
||||||
bool showGuildRoster_ = false;
|
bool showGuildRoster_ = false;
|
||||||
|
|
|
||||||
|
|
@ -419,6 +419,20 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
||||||
// Apply auto-loot setting to GameHandler every frame (cheap bool sync)
|
// Apply auto-loot setting to GameHandler every frame (cheap bool sync)
|
||||||
gameHandler.setAutoLoot(pendingAutoLoot);
|
gameHandler.setAutoLoot(pendingAutoLoot);
|
||||||
|
|
||||||
|
// Zone entry detection — fire a toast when the renderer's zone name changes
|
||||||
|
if (auto* rend = core::Application::getInstance().getRenderer()) {
|
||||||
|
const std::string& curZone = rend->getCurrentZoneName();
|
||||||
|
if (!curZone.empty() && curZone != lastKnownZone_) {
|
||||||
|
if (!lastKnownZone_.empty()) {
|
||||||
|
// Genuine zone change (not first entry)
|
||||||
|
zoneToasts_.push_back({curZone, 0.0f});
|
||||||
|
if (zoneToasts_.size() > 3)
|
||||||
|
zoneToasts_.erase(zoneToasts_.begin());
|
||||||
|
}
|
||||||
|
lastKnownZone_ = curZone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sync chat auto-join settings to GameHandler
|
// Sync chat auto-join settings to GameHandler
|
||||||
gameHandler.chatAutoJoin.general = chatAutoJoinGeneral_;
|
gameHandler.chatAutoJoin.general = chatAutoJoinGeneral_;
|
||||||
gameHandler.chatAutoJoin.trade = chatAutoJoinTrade_;
|
gameHandler.chatAutoJoin.trade = chatAutoJoinTrade_;
|
||||||
|
|
@ -476,6 +490,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
||||||
renderUIErrors(gameHandler, ImGui::GetIO().DeltaTime);
|
renderUIErrors(gameHandler, ImGui::GetIO().DeltaTime);
|
||||||
renderRepToasts(ImGui::GetIO().DeltaTime);
|
renderRepToasts(ImGui::GetIO().DeltaTime);
|
||||||
renderQuestCompleteToasts(ImGui::GetIO().DeltaTime);
|
renderQuestCompleteToasts(ImGui::GetIO().DeltaTime);
|
||||||
|
renderZoneToasts(ImGui::GetIO().DeltaTime);
|
||||||
if (showRaidFrames_) {
|
if (showRaidFrames_) {
|
||||||
renderPartyFrames(gameHandler);
|
renderPartyFrames(gameHandler);
|
||||||
}
|
}
|
||||||
|
|
@ -7494,6 +7509,64 @@ void GameScreen::renderQuestCompleteToasts(float deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Zone Entry Toast
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
void GameScreen::renderZoneToasts(float deltaTime) {
|
||||||
|
for (auto& e : zoneToasts_) e.age += deltaTime;
|
||||||
|
zoneToasts_.erase(
|
||||||
|
std::remove_if(zoneToasts_.begin(), zoneToasts_.end(),
|
||||||
|
[](const ZoneToastEntry& e) { return e.age >= kZoneToastLifetime; }),
|
||||||
|
zoneToasts_.end());
|
||||||
|
|
||||||
|
if (zoneToasts_.empty()) return;
|
||||||
|
|
||||||
|
auto* window = core::Application::getInstance().getWindow();
|
||||||
|
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
|
||||||
|
|
||||||
|
ImDrawList* draw = ImGui::GetForegroundDrawList();
|
||||||
|
ImFont* font = ImGui::GetFont();
|
||||||
|
|
||||||
|
for (int i = 0; i < static_cast<int>(zoneToasts_.size()); ++i) {
|
||||||
|
const auto& e = zoneToasts_[i];
|
||||||
|
constexpr float kSlideDur = 0.35f;
|
||||||
|
float slideIn = std::min(e.age, kSlideDur) / kSlideDur;
|
||||||
|
float slideOut = std::min(std::max(0.0f, kZoneToastLifetime - e.age), kSlideDur) / kSlideDur;
|
||||||
|
float slide = std::min(slideIn, slideOut);
|
||||||
|
float alpha = std::clamp(slide, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
// Measure text to size the toast
|
||||||
|
ImVec2 nameSz = font->CalcTextSizeA(14.0f, FLT_MAX, 0.0f, e.zoneName.c_str());
|
||||||
|
const char* header = "Entering:";
|
||||||
|
ImVec2 hdrSz = font->CalcTextSizeA(11.0f, FLT_MAX, 0.0f, header);
|
||||||
|
|
||||||
|
float toastW = std::max(nameSz.x, hdrSz.x) + 28.0f;
|
||||||
|
float toastH = 42.0f;
|
||||||
|
|
||||||
|
// Center the toast horizontally, appear just below the zone name area (top-center)
|
||||||
|
float toastX = (screenW - toastW) * 0.5f;
|
||||||
|
float toastY = 56.0f + i * (toastH + 4.0f);
|
||||||
|
// Slide down from above
|
||||||
|
float offY = (1.0f - slide) * (-toastH - 10.0f);
|
||||||
|
toastY += offY;
|
||||||
|
|
||||||
|
ImVec2 tl(toastX, toastY);
|
||||||
|
ImVec2 br(toastX + toastW, toastY + toastH);
|
||||||
|
|
||||||
|
draw->AddRectFilled(tl, br, IM_COL32(10, 10, 16, (int)(alpha * 200)), 6.0f);
|
||||||
|
draw->AddRect(tl, br, IM_COL32(160, 140, 80, (int)(alpha * 220)), 6.0f, 0, 1.2f);
|
||||||
|
|
||||||
|
float cx = tl.x + toastW * 0.5f;
|
||||||
|
draw->AddText(font, 11.0f,
|
||||||
|
ImVec2(cx - hdrSz.x * 0.5f, tl.y + 5.0f),
|
||||||
|
IM_COL32(180, 170, 120, (int)(alpha * 200)), header);
|
||||||
|
draw->AddText(font, 14.0f,
|
||||||
|
ImVec2(cx - nameSz.x * 0.5f, tl.y + toastH * 0.5f + 1.0f),
|
||||||
|
IM_COL32(255, 230, 140, (int)(alpha * 240)), e.zoneName.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Boss Encounter Frames
|
// Boss Encounter Frames
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
@ -12887,6 +12960,24 @@ void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) {
|
||||||
nextIndicatorY += kIndicatorH;
|
nextIndicatorY += kIndicatorH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unspent talent points indicator
|
||||||
|
{
|
||||||
|
uint8_t unspent = gameHandler.getUnspentTalentPoints();
|
||||||
|
if (unspent > 0) {
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(indicatorX, nextIndicatorY), ImGuiCond_Always);
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(indicatorW, kIndicatorH), ImGuiCond_Always);
|
||||||
|
if (ImGui::Begin("##TalentIndicator", nullptr, indicatorFlags)) {
|
||||||
|
float pulse = 0.7f + 0.3f * std::sin(static_cast<float>(ImGui::GetTime()) * 2.5f);
|
||||||
|
char talentBuf[40];
|
||||||
|
snprintf(talentBuf, sizeof(talentBuf), "! %u Talent Point%s Available",
|
||||||
|
static_cast<unsigned>(unspent), unspent == 1 ? "" : "s");
|
||||||
|
ImGui::TextColored(ImVec4(0.3f, 1.0f, 0.3f * pulse, pulse), "%s", talentBuf);
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
nextIndicatorY += kIndicatorH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BG queue status indicator (when in queue but not yet invited)
|
// BG queue status indicator (when in queue but not yet invited)
|
||||||
for (const auto& slot : gameHandler.getBgQueues()) {
|
for (const auto& slot : gameHandler.getBgQueues()) {
|
||||||
if (slot.statusId != 1) continue; // STATUS_WAIT_QUEUE only
|
if (slot.statusId != 1) continue; // STATUS_WAIT_QUEUE only
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue