mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-26 00:40:15 +00:00
feat: add duel countdown overlay (3-2-1-Fight!)
Parse SMSG_DUEL_COUNTDOWN to get the countdown duration, track the start time, and render a large centered countdown overlay. Numbers display in pulsing gold; transitions to pulsing red 'Fight!' for the last 0.5 seconds. Countdown clears on SMSG_DUEL_COMPLETE.
This commit is contained in:
parent
29a989e1f4
commit
c35bf8d953
4 changed files with 63 additions and 2 deletions
|
|
@ -3214,9 +3214,16 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
|||
case Opcode::SMSG_DUEL_INBOUNDS:
|
||||
// Re-entered the duel area; no special action needed.
|
||||
break;
|
||||
case Opcode::SMSG_DUEL_COUNTDOWN:
|
||||
// Countdown timer — no action needed; server also sends UNIT_FIELD_FLAGS update.
|
||||
case Opcode::SMSG_DUEL_COUNTDOWN: {
|
||||
// uint32 countdown in milliseconds (typically 3000 ms)
|
||||
if (packet.getSize() - packet.getReadPos() >= 4) {
|
||||
uint32_t ms = packet.readUInt32();
|
||||
duelCountdownMs_ = (ms > 0 && ms <= 30000) ? ms : 3000;
|
||||
duelCountdownStartedAt_ = std::chrono::steady_clock::now();
|
||||
LOG_INFO("SMSG_DUEL_COUNTDOWN: ", duelCountdownMs_, " ms");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Opcode::SMSG_PARTYKILLLOG: {
|
||||
// uint64 killerGuid + uint64 victimGuid
|
||||
if (packet.getSize() - packet.getReadPos() < 16) break;
|
||||
|
|
@ -10472,6 +10479,7 @@ void GameHandler::handleDuelComplete(network::Packet& packet) {
|
|||
uint8_t started = packet.readUInt8();
|
||||
// started=1: duel began, started=0: duel was cancelled before starting
|
||||
pendingDuelRequest_ = false;
|
||||
duelCountdownMs_ = 0; // clear countdown once duel is resolved
|
||||
if (!started) {
|
||||
addSystemChatMessage("The duel was cancelled.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -482,6 +482,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
|||
renderBossFrames(gameHandler);
|
||||
renderGroupInvitePopup(gameHandler);
|
||||
renderDuelRequestPopup(gameHandler);
|
||||
renderDuelCountdown(gameHandler);
|
||||
renderLootRollPopup(gameHandler);
|
||||
renderTradeRequestPopup(gameHandler);
|
||||
renderTradeWindow(gameHandler);
|
||||
|
|
@ -7488,6 +7489,47 @@ void GameScreen::renderDuelRequestPopup(game::GameHandler& gameHandler) {
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
void GameScreen::renderDuelCountdown(game::GameHandler& gameHandler) {
|
||||
float remaining = gameHandler.getDuelCountdownRemaining();
|
||||
if (remaining <= 0.0f) return;
|
||||
|
||||
ImVec2 displaySize = ImGui::GetIO().DisplaySize;
|
||||
float screenW = displaySize.x > 0.0f ? displaySize.x : 1280.0f;
|
||||
float screenH = displaySize.y > 0.0f ? displaySize.y : 720.0f;
|
||||
|
||||
auto* dl = ImGui::GetForegroundDrawList();
|
||||
ImFont* font = ImGui::GetFont();
|
||||
float fontSize = ImGui::GetFontSize();
|
||||
|
||||
// Show integer countdown or "Fight!" when under 0.5s
|
||||
char buf[32];
|
||||
if (remaining > 0.5f) {
|
||||
snprintf(buf, sizeof(buf), "%d", static_cast<int>(std::ceil(remaining)));
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Fight!");
|
||||
}
|
||||
|
||||
// Large font by scaling — use 4x font size for dramatic effect
|
||||
float scale = 4.0f;
|
||||
float scaledSize = fontSize * scale;
|
||||
ImVec2 textSz = font->CalcTextSizeA(scaledSize, FLT_MAX, 0.0f, buf);
|
||||
float tx = (screenW - textSz.x) * 0.5f;
|
||||
float ty = screenH * 0.35f - textSz.y * 0.5f;
|
||||
|
||||
// Pulsing alpha: fades in and out per second
|
||||
float pulse = 0.75f + 0.25f * std::sin(static_cast<float>(ImGui::GetTime()) * 6.28f);
|
||||
uint8_t alpha = static_cast<uint8_t>(255 * pulse);
|
||||
|
||||
// Color: golden countdown, red "Fight!"
|
||||
ImU32 color = (remaining > 0.5f)
|
||||
? IM_COL32(255, 200, 50, alpha)
|
||||
: IM_COL32(255, 60, 60, alpha);
|
||||
|
||||
// Drop shadow
|
||||
dl->AddText(font, scaledSize, ImVec2(tx + 2.0f, ty + 2.0f), IM_COL32(0, 0, 0, alpha / 2), buf);
|
||||
dl->AddText(font, scaledSize, ImVec2(tx, ty), color, buf);
|
||||
}
|
||||
|
||||
void GameScreen::renderItemTextWindow(game::GameHandler& gameHandler) {
|
||||
if (!gameHandler.isItemTextOpen()) return;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue