mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 00:03:50 +00:00
Add Channels tab to social frame and reputation change toast
Social frame now has three tabs: Friends, Ignore, and Channels. The Channels tab lists joined channels with right-click Leave and an input to join new channels. Also adds a slide-in reputation change toast in the lower-right corner: shows faction name, delta (+/-), and current standing tier (Honored, Revered, etc.) whenever SMSG_SET_FACTION_STANDING fires a rep change.
This commit is contained in:
parent
fb6630a7ae
commit
1bc3e6b677
4 changed files with 146 additions and 0 deletions
|
|
@ -1275,6 +1275,10 @@ public:
|
||||||
void setUIErrorCallback(UIErrorCallback cb) { uiErrorCallback_ = std::move(cb); }
|
void setUIErrorCallback(UIErrorCallback cb) { uiErrorCallback_ = std::move(cb); }
|
||||||
void addUIError(const std::string& msg) { if (uiErrorCallback_) uiErrorCallback_(msg); }
|
void addUIError(const std::string& msg) { if (uiErrorCallback_) uiErrorCallback_(msg); }
|
||||||
|
|
||||||
|
// Reputation change toast: factionName, delta, new standing
|
||||||
|
using RepChangeCallback = std::function<void(const std::string& factionName, int32_t delta, int32_t standing)>;
|
||||||
|
void setRepChangeCallback(RepChangeCallback cb) { repChangeCallback_ = std::move(cb); }
|
||||||
|
|
||||||
// Mount state
|
// Mount state
|
||||||
using MountCallback = std::function<void(uint32_t mountDisplayId)>; // 0 = dismount
|
using MountCallback = std::function<void(uint32_t mountDisplayId)>; // 0 = dismount
|
||||||
void setMountCallback(MountCallback cb) { mountCallback_ = std::move(cb); }
|
void setMountCallback(MountCallback cb) { mountCallback_ = std::move(cb); }
|
||||||
|
|
@ -2557,6 +2561,9 @@ private:
|
||||||
|
|
||||||
// ---- UI error frame callback ----
|
// ---- UI error frame callback ----
|
||||||
UIErrorCallback uiErrorCallback_;
|
UIErrorCallback uiErrorCallback_;
|
||||||
|
|
||||||
|
// ---- Reputation change callback ----
|
||||||
|
RepChangeCallback repChangeCallback_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace game
|
} // namespace game
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,12 @@ private:
|
||||||
std::vector<UIErrorEntry> uiErrors_;
|
std::vector<UIErrorEntry> uiErrors_;
|
||||||
bool uiErrorCallbackSet_ = false;
|
bool uiErrorCallbackSet_ = false;
|
||||||
static constexpr float kUIErrorLifetime = 2.5f;
|
static constexpr float kUIErrorLifetime = 2.5f;
|
||||||
|
|
||||||
|
// Reputation change toast: brief colored slide-in below minimap
|
||||||
|
struct RepToastEntry { std::string factionName; int32_t delta = 0; int32_t standing = 0; float age = 0.0f; };
|
||||||
|
std::vector<RepToastEntry> repToasts_;
|
||||||
|
bool repChangeCallbackSet_ = false;
|
||||||
|
static constexpr float kRepToastLifetime = 3.5f;
|
||||||
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;
|
||||||
|
|
@ -263,6 +269,7 @@ private:
|
||||||
void renderPartyFrames(game::GameHandler& gameHandler);
|
void renderPartyFrames(game::GameHandler& gameHandler);
|
||||||
void renderBossFrames(game::GameHandler& gameHandler);
|
void renderBossFrames(game::GameHandler& gameHandler);
|
||||||
void renderUIErrors(game::GameHandler& gameHandler, float deltaTime);
|
void renderUIErrors(game::GameHandler& gameHandler, float deltaTime);
|
||||||
|
void renderRepToasts(float deltaTime);
|
||||||
void renderGroupInvitePopup(game::GameHandler& gameHandler);
|
void renderGroupInvitePopup(game::GameHandler& gameHandler);
|
||||||
void renderDuelRequestPopup(game::GameHandler& gameHandler);
|
void renderDuelRequestPopup(game::GameHandler& gameHandler);
|
||||||
void renderLootRollPopup(game::GameHandler& gameHandler);
|
void renderLootRollPopup(game::GameHandler& gameHandler);
|
||||||
|
|
|
||||||
|
|
@ -3517,6 +3517,7 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
||||||
delta > 0 ? "increased" : "decreased",
|
delta > 0 ? "increased" : "decreased",
|
||||||
std::abs(delta));
|
std::abs(delta));
|
||||||
addSystemChatMessage(buf);
|
addSystemChatMessage(buf);
|
||||||
|
if (repChangeCallback_) repChangeCallback_(name, delta, standing);
|
||||||
}
|
}
|
||||||
LOG_DEBUG("SMSG_SET_FACTION_STANDING: faction=", factionId, " standing=", standing);
|
LOG_DEBUG("SMSG_SET_FACTION_STANDING: faction=", factionId, " standing=", standing);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,15 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
||||||
uiErrorCallbackSet_ = true;
|
uiErrorCallbackSet_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up reputation change toast callback (once)
|
||||||
|
if (!repChangeCallbackSet_) {
|
||||||
|
gameHandler.setRepChangeCallback([this](const std::string& name, int32_t delta, int32_t standing) {
|
||||||
|
repToasts_.push_back({name, delta, standing, 0.0f});
|
||||||
|
if (repToasts_.size() > 4) repToasts_.erase(repToasts_.begin());
|
||||||
|
});
|
||||||
|
repChangeCallbackSet_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Apply UI transparency setting
|
// Apply UI transparency setting
|
||||||
float prevAlpha = ImGui::GetStyle().Alpha;
|
float prevAlpha = ImGui::GetStyle().Alpha;
|
||||||
ImGui::GetStyle().Alpha = uiOpacity_;
|
ImGui::GetStyle().Alpha = uiOpacity_;
|
||||||
|
|
@ -453,6 +462,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
||||||
renderBattlegroundScore(gameHandler);
|
renderBattlegroundScore(gameHandler);
|
||||||
renderCombatText(gameHandler);
|
renderCombatText(gameHandler);
|
||||||
renderUIErrors(gameHandler, ImGui::GetIO().DeltaTime);
|
renderUIErrors(gameHandler, ImGui::GetIO().DeltaTime);
|
||||||
|
renderRepToasts(ImGui::GetIO().DeltaTime);
|
||||||
if (showRaidFrames_) {
|
if (showRaidFrames_) {
|
||||||
renderPartyFrames(gameHandler);
|
renderPartyFrames(gameHandler);
|
||||||
}
|
}
|
||||||
|
|
@ -6585,6 +6595,89 @@ void GameScreen::renderUIErrors(game::GameHandler& /*gameHandler*/, float deltaT
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Reputation change toasts
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
void GameScreen::renderRepToasts(float deltaTime) {
|
||||||
|
for (auto& e : repToasts_) e.age += deltaTime;
|
||||||
|
repToasts_.erase(
|
||||||
|
std::remove_if(repToasts_.begin(), repToasts_.end(),
|
||||||
|
[](const RepToastEntry& e) { return e.age >= kRepToastLifetime; }),
|
||||||
|
repToasts_.end());
|
||||||
|
|
||||||
|
if (repToasts_.empty()) return;
|
||||||
|
|
||||||
|
auto* window = core::Application::getInstance().getWindow();
|
||||||
|
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
|
||||||
|
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
|
||||||
|
|
||||||
|
// Stack toasts in the lower-right corner (above the action bar), newest on top
|
||||||
|
const float toastW = 220.0f;
|
||||||
|
const float toastH = 26.0f;
|
||||||
|
const float padY = 4.0f;
|
||||||
|
const float rightEdge = screenW - 14.0f;
|
||||||
|
const float baseY = screenH - 180.0f;
|
||||||
|
|
||||||
|
const int count = static_cast<int>(repToasts_.size());
|
||||||
|
|
||||||
|
ImDrawList* draw = ImGui::GetForegroundDrawList();
|
||||||
|
ImFont* font = ImGui::GetFont();
|
||||||
|
float fontSize = ImGui::GetFontSize();
|
||||||
|
|
||||||
|
// Compute standing tier label (Exalted, Revered, Honored, Friendly, Neutral, Unfriendly, Hostile, Hated)
|
||||||
|
auto standingLabel = [](int32_t s) -> const char* {
|
||||||
|
if (s >= 42000) return "Exalted";
|
||||||
|
if (s >= 21000) return "Revered";
|
||||||
|
if (s >= 9000) return "Honored";
|
||||||
|
if (s >= 3000) return "Friendly";
|
||||||
|
if (s >= 0) return "Neutral";
|
||||||
|
if (s >= -3000) return "Unfriendly";
|
||||||
|
if (s >= -6000) return "Hostile";
|
||||||
|
return "Hated";
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
const auto& e = repToasts_[i];
|
||||||
|
// Slide in from right on appear, slide out at end
|
||||||
|
constexpr float kSlideDur = 0.3f;
|
||||||
|
float slideIn = std::min(e.age, kSlideDur) / kSlideDur;
|
||||||
|
float slideOut = std::min(std::max(0.0f, kRepToastLifetime - e.age), kSlideDur) / kSlideDur;
|
||||||
|
float slide = std::min(slideIn, slideOut);
|
||||||
|
|
||||||
|
float alpha = std::clamp(slide, 0.0f, 1.0f);
|
||||||
|
float xFull = rightEdge - toastW;
|
||||||
|
float xStart = screenW + 10.0f;
|
||||||
|
float toastX = xStart + (xFull - xStart) * slide;
|
||||||
|
float toastY = baseY - i * (toastH + padY);
|
||||||
|
|
||||||
|
ImVec2 tl(toastX, toastY);
|
||||||
|
ImVec2 br(toastX + toastW, toastY + toastH);
|
||||||
|
|
||||||
|
// Background
|
||||||
|
draw->AddRectFilled(tl, br, IM_COL32(15, 15, 20, (int)(alpha * 200)), 4.0f);
|
||||||
|
// Border: green for gain, red for loss
|
||||||
|
ImU32 borderCol = (e.delta > 0)
|
||||||
|
? IM_COL32(80, 200, 80, (int)(alpha * 220))
|
||||||
|
: IM_COL32(200, 60, 60, (int)(alpha * 220));
|
||||||
|
draw->AddRect(tl, br, borderCol, 4.0f, 0, 1.5f);
|
||||||
|
|
||||||
|
// Delta text: "+250" or "-250"
|
||||||
|
char deltaBuf[16];
|
||||||
|
snprintf(deltaBuf, sizeof(deltaBuf), "%+d", e.delta);
|
||||||
|
ImU32 deltaCol = (e.delta > 0) ? IM_COL32(80, 220, 80, (int)(alpha * 255))
|
||||||
|
: IM_COL32(220, 70, 70, (int)(alpha * 255));
|
||||||
|
draw->AddText(font, fontSize, ImVec2(tl.x + 6.0f, tl.y + (toastH - fontSize) * 0.5f),
|
||||||
|
deltaCol, deltaBuf);
|
||||||
|
|
||||||
|
// Faction name + standing
|
||||||
|
char nameBuf[64];
|
||||||
|
snprintf(nameBuf, sizeof(nameBuf), "%s (%s)", e.factionName.c_str(), standingLabel(e.standing));
|
||||||
|
draw->AddText(font, fontSize * 0.85f, ImVec2(tl.x + 44.0f, tl.y + (toastH - fontSize * 0.85f) * 0.5f),
|
||||||
|
IM_COL32(210, 210, 210, (int)(alpha * 220)), nameBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Boss Encounter Frames
|
// Boss Encounter Frames
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
@ -8018,6 +8111,44 @@ void GameScreen::renderSocialFrame(game::GameHandler& gameHandler) {
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- Channels tab ----
|
||||||
|
if (ImGui::BeginTabItem("Channels")) {
|
||||||
|
const auto& channels = gameHandler.getJoinedChannels();
|
||||||
|
ImGui::BeginChild("##ChannelList", ImVec2(200, 200), false);
|
||||||
|
|
||||||
|
if (channels.empty()) {
|
||||||
|
ImGui::TextDisabled("Not in any channels.");
|
||||||
|
} else {
|
||||||
|
for (size_t ci = 0; ci < channels.size(); ++ci) {
|
||||||
|
ImGui::PushID(static_cast<int>(ci));
|
||||||
|
ImGui::TextUnformatted(channels[ci].c_str());
|
||||||
|
if (ImGui::BeginPopupContextItem("ChanCtx")) {
|
||||||
|
ImGui::TextDisabled("%s", channels[ci].c_str());
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::MenuItem("Leave Channel"))
|
||||||
|
gameHandler.leaveChannel(channels[ci]);
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndChild();
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
// Join a channel
|
||||||
|
static char joinChanBuf[64] = {};
|
||||||
|
ImGui::SetNextItemWidth(140.0f);
|
||||||
|
ImGui::InputText("##sf_joinchan", joinChanBuf, sizeof(joinChanBuf));
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("+##joinchan") && joinChanBuf[0] != '\0') {
|
||||||
|
gameHandler.joinChannel(joinChanBuf);
|
||||||
|
joinChanBuf[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::EndTabBar();
|
ImGui::EndTabBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue