mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
feat: add melee swing timer bar to player frame during auto-attack
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
Shows a thin progress bar below the player health/power bars whenever the player is auto-attacking. The bar fills from the last swing timestamp to the next expected swing based on the main-hand weapon's delay (from ItemQueryResponseData::delayMs). Falls back to 2.0s for unarmed. Turns gold and shows "Swing!" when the timer is complete to signal readiness. Hides when not auto-attacking.
This commit is contained in:
parent
a7261a0d15
commit
a87d62abf8
3 changed files with 50 additions and 2 deletions
|
|
@ -573,6 +573,9 @@ public:
|
|||
}
|
||||
uint64_t getAutoAttackTargetGuid() const { return autoAttackTarget; }
|
||||
bool isAggressiveTowardPlayer(uint64_t guid) const { return hostileAttackers_.count(guid) > 0; }
|
||||
// Timestamp (ms since epoch) of the most recent player melee auto-attack.
|
||||
// Zero if no swing has occurred this session.
|
||||
uint64_t getLastMeleeSwingMs() const { return lastMeleeSwingMs_; }
|
||||
const std::vector<CombatTextEntry>& getCombatText() const { return combatText; }
|
||||
void updateCombatText(float deltaTime);
|
||||
|
||||
|
|
@ -2854,6 +2857,7 @@ private:
|
|||
StandStateCallback standStateCallback_;
|
||||
GhostStateCallback ghostStateCallback_;
|
||||
MeleeSwingCallback meleeSwingCallback_;
|
||||
uint64_t lastMeleeSwingMs_ = 0; // system_clock ms at last player auto-attack swing
|
||||
SpellCastAnimCallback spellCastAnimCallback_;
|
||||
UnitAnimHintCallback unitAnimHintCallback_;
|
||||
UnitMoveFlagsCallback unitMoveFlagsCallback_;
|
||||
|
|
|
|||
|
|
@ -14328,8 +14328,11 @@ void GameHandler::handleAttackerStateUpdate(network::Packet& packet) {
|
|||
bool isPlayerTarget = (data.targetGuid == playerGuid);
|
||||
if (!isPlayerAttacker && !isPlayerTarget) return; // Not our combat
|
||||
|
||||
if (isPlayerAttacker && meleeSwingCallback_) {
|
||||
meleeSwingCallback_();
|
||||
if (isPlayerAttacker) {
|
||||
lastMeleeSwingMs_ = static_cast<uint64_t>(
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count());
|
||||
if (meleeSwingCallback_) meleeSwingCallback_();
|
||||
}
|
||||
if (!isPlayerAttacker && npcSwingCallback_) {
|
||||
npcSwingCallback_(data.attackerGuid);
|
||||
|
|
|
|||
|
|
@ -2977,6 +2977,47 @@ void GameScreen::renderPlayerFrame(game::GameHandler& gameHandler) {
|
|||
ImGui::SetCursorScreenPos(ImVec2(cursor.x, cursor.y + slotH + 2.0f));
|
||||
}
|
||||
}
|
||||
|
||||
// Melee swing timer — shown when player is auto-attacking
|
||||
if (gameHandler.isAutoAttacking()) {
|
||||
const uint64_t lastSwingMs = gameHandler.getLastMeleeSwingMs();
|
||||
if (lastSwingMs > 0) {
|
||||
// Determine weapon speed from the equipped main-hand weapon
|
||||
uint32_t weaponDelayMs = 2000; // Default: 2.0s unarmed
|
||||
const auto& mainSlot = gameHandler.getInventory().getEquipSlot(game::EquipSlot::MAIN_HAND);
|
||||
if (!mainSlot.empty() && mainSlot.item.itemId != 0) {
|
||||
const auto* info = gameHandler.getItemInfo(mainSlot.item.itemId);
|
||||
if (info && info->delayMs > 0) {
|
||||
weaponDelayMs = info->delayMs;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute elapsed since last swing
|
||||
uint64_t nowMs = static_cast<uint64_t>(
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count());
|
||||
uint64_t elapsedMs = (nowMs >= lastSwingMs) ? (nowMs - lastSwingMs) : 0;
|
||||
|
||||
// Clamp to weapon delay (cap at 1.0 so the bar fills but doesn't exceed)
|
||||
float pct = std::min(static_cast<float>(elapsedMs) / static_cast<float>(weaponDelayMs), 1.0f);
|
||||
|
||||
// Light silver-orange color indicating auto-attack readiness
|
||||
ImVec4 swingColor = (pct >= 0.95f)
|
||||
? ImVec4(1.0f, 0.75f, 0.15f, 1.0f) // gold when ready to swing
|
||||
: ImVec4(0.65f, 0.55f, 0.40f, 1.0f); // muted brown-orange while filling
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, swingColor);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.15f, 0.12f, 0.08f, 0.8f));
|
||||
char swingLabel[24];
|
||||
float remainSec = std::max(0.0f, (weaponDelayMs - static_cast<float>(elapsedMs)) / 1000.0f);
|
||||
if (pct >= 0.98f)
|
||||
snprintf(swingLabel, sizeof(swingLabel), "Swing!");
|
||||
else
|
||||
snprintf(swingLabel, sizeof(swingLabel), "%.1fs", remainSec);
|
||||
ImGui::ProgressBar(pct, ImVec2(-1.0f, 8.0f), swingLabel);
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue