mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 17:43:52 +00:00
feat: add out-of-range tint to action bar spell slots
Ranged spell icons dim to a red tint when the current target is farther than the spell's max range (read from SpellRange.dbc via spellbook data). Melee/self spells (max range ≤ 5 yd or unknown) are excluded. The spell tooltip also shows "Out of range" in red when applicable. Adds SpellbookScreen::getSpellMaxRange() as a public accessor so game_screen can query DBC range data without duplicating DBC loading.
This commit is contained in:
parent
bc5a7867a9
commit
8081a43d85
3 changed files with 39 additions and 0 deletions
|
|
@ -54,6 +54,10 @@ public:
|
||||||
uint32_t getDragSpellId() const { return dragSpellId_; }
|
uint32_t getDragSpellId() const { return dragSpellId_; }
|
||||||
void consumeDragSpell() { draggingSpell_ = false; dragSpellId_ = 0; dragSpellIconTex_ = VK_NULL_HANDLE; }
|
void consumeDragSpell() { draggingSpell_ = false; dragSpellId_ = 0; dragSpellIconTex_ = VK_NULL_HANDLE; }
|
||||||
|
|
||||||
|
/// Returns the max range in yards for a spell (0 if self-cast, unknown, or melee).
|
||||||
|
/// Triggers DBC load if needed. Used by the action bar for out-of-range tinting.
|
||||||
|
uint32_t getSpellMaxRange(uint32_t spellId, pipeline::AssetManager* assetManager);
|
||||||
|
|
||||||
/// Returns a WoW spell link string if the user shift-clicked a spell, then clears it.
|
/// Returns a WoW spell link string if the user shift-clicked a spell, then clears it.
|
||||||
std::string getAndClearPendingChatLink() {
|
std::string getAndClearPendingChatLink() {
|
||||||
std::string out = std::move(pendingChatSpellLink_);
|
std::string out = std::move(pendingChatSpellLink_);
|
||||||
|
|
|
||||||
|
|
@ -4969,6 +4969,27 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) {
|
||||||
bool onCooldown = !slot.isReady();
|
bool onCooldown = !slot.isReady();
|
||||||
const bool onGCD = gameHandler.isGCDActive() && !onCooldown && !slot.isEmpty();
|
const bool onGCD = gameHandler.isGCDActive() && !onCooldown && !slot.isEmpty();
|
||||||
|
|
||||||
|
// Out-of-range check: red tint when a targeted spell cannot reach the current target.
|
||||||
|
// Only applies to SPELL slots with a known max range (>5 yd) and an active target.
|
||||||
|
bool outOfRange = false;
|
||||||
|
if (!slot.isEmpty() && slot.type == game::ActionBarSlot::SPELL && slot.id != 0
|
||||||
|
&& !onCooldown && gameHandler.hasTarget()) {
|
||||||
|
uint32_t maxRange = spellbookScreen.getSpellMaxRange(slot.id, assetMgr);
|
||||||
|
if (maxRange > 5) { // >5 yd = not melee/self
|
||||||
|
auto& em = gameHandler.getEntityManager();
|
||||||
|
auto playerEnt = em.getEntity(gameHandler.getPlayerGuid());
|
||||||
|
auto targetEnt = em.getEntity(gameHandler.getTargetGuid());
|
||||||
|
if (playerEnt && targetEnt) {
|
||||||
|
float dx = playerEnt->getX() - targetEnt->getX();
|
||||||
|
float dy = playerEnt->getY() - targetEnt->getY();
|
||||||
|
float dz = playerEnt->getZ() - targetEnt->getZ();
|
||||||
|
float dist = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||||
|
if (dist > static_cast<float>(maxRange))
|
||||||
|
outOfRange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto getSpellName = [&](uint32_t spellId) -> std::string {
|
auto getSpellName = [&](uint32_t spellId) -> std::string {
|
||||||
std::string name = spellbookScreen.lookupSpellName(spellId, assetMgr);
|
std::string name = spellbookScreen.lookupSpellName(spellId, assetMgr);
|
||||||
if (!name.empty()) return name;
|
if (!name.empty()) return name;
|
||||||
|
|
@ -5021,6 +5042,7 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) {
|
||||||
ImVec4 bgColor(0.1f, 0.1f, 0.1f, 0.9f);
|
ImVec4 bgColor(0.1f, 0.1f, 0.1f, 0.9f);
|
||||||
if (onCooldown) { tintColor = ImVec4(0.4f, 0.4f, 0.4f, 0.8f); }
|
if (onCooldown) { tintColor = ImVec4(0.4f, 0.4f, 0.4f, 0.8f); }
|
||||||
else if (onGCD) { tintColor = ImVec4(0.6f, 0.6f, 0.6f, 0.85f); }
|
else if (onGCD) { tintColor = ImVec4(0.6f, 0.6f, 0.6f, 0.85f); }
|
||||||
|
else if (outOfRange) { tintColor = ImVec4(0.85f, 0.35f, 0.35f, 0.9f); }
|
||||||
clicked = ImGui::ImageButton("##icon",
|
clicked = ImGui::ImageButton("##icon",
|
||||||
(ImTextureID)(uintptr_t)iconTex,
|
(ImTextureID)(uintptr_t)iconTex,
|
||||||
ImVec2(slotSize, slotSize),
|
ImVec2(slotSize, slotSize),
|
||||||
|
|
@ -5028,6 +5050,7 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) {
|
||||||
bgColor, tintColor);
|
bgColor, tintColor);
|
||||||
} else {
|
} else {
|
||||||
if (onCooldown) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.2f, 0.2f, 0.8f));
|
if (onCooldown) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.2f, 0.2f, 0.8f));
|
||||||
|
else if (outOfRange) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.45f, 0.15f, 0.15f, 0.9f));
|
||||||
else if (slot.isEmpty())ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.15f, 0.15f, 0.8f));
|
else if (slot.isEmpty())ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15f, 0.15f, 0.15f, 0.8f));
|
||||||
else ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.3f, 0.3f, 0.5f, 0.9f));
|
else ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.3f, 0.3f, 0.5f, 0.9f));
|
||||||
|
|
||||||
|
|
@ -5137,6 +5160,9 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) {
|
||||||
ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f), "Home: %s", mapName);
|
ImGui::TextColored(ImVec4(0.8f, 0.9f, 1.0f, 1.0f), "Home: %s", mapName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (outOfRange) {
|
||||||
|
ImGui::TextColored(ImVec4(1.0f, 0.35f, 0.35f, 1.0f), "Out of range");
|
||||||
|
}
|
||||||
if (onCooldown) {
|
if (onCooldown) {
|
||||||
float cd = slot.cooldownRemaining;
|
float cd = slot.cooldownRemaining;
|
||||||
if (cd >= 60.0f)
|
if (cd >= 60.0f)
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,15 @@ std::string SpellbookScreen::lookupSpellName(uint32_t spellId, pipeline::AssetMa
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t SpellbookScreen::getSpellMaxRange(uint32_t spellId, pipeline::AssetManager* assetManager) {
|
||||||
|
if (!dbcLoadAttempted) {
|
||||||
|
loadSpellDBC(assetManager);
|
||||||
|
}
|
||||||
|
auto it = spellData.find(spellId);
|
||||||
|
if (it != spellData.end()) return it->second.rangeIndex;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void SpellbookScreen::loadSpellIconDBC(pipeline::AssetManager* assetManager) {
|
void SpellbookScreen::loadSpellIconDBC(pipeline::AssetManager* assetManager) {
|
||||||
if (iconDbLoaded) return;
|
if (iconDbLoaded) return;
|
||||||
iconDbLoaded = true;
|
iconDbLoaded = true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue