13 Commits
Author SHA1 Message Date
Bluewhale1337 fca88016f2 refactor: remove Spirit of Zanza from Divine Spirit aura tracking and bump version to 1.7.7 2026-11-05 22:33:46 +01:00
Bluewhale1337 cc2d6830e5 feat: add Spirit of Zanza aura tracking and fix bar text font height handling 2026-11-05 18:46:44 +01:00
Bluewhale1337 7fdf76eff8 fix: HoT timer tracking premature deletion of auta_Cast_ON even
fixed guid cache
fixed .show() call on overlay visible
2026-11-05 17:37:46 +01:00
Bluewhale1337 5ec9bde8dd Merge pull request #25 from Bluewhale1337/main
Merging patch 1.7.6 into dev branch
2026-11-05 10:52:11 +01:00
Bluewhale1337 18eff88f7b Update README.md
fixing accidental leak of dev readme into main branch

Signed-off-by: Bluewhale1337 <295648290+Bluewhale1337@users.noreply.github.com>
2026-11-05 10:47:04 +01:00
Bluewhale1337 31f7c6fe2b Merge branch 'dev' into main
Signed-off-by: Bluewhale1337 <295648290+Bluewhale1337@users.noreply.github.com>
2026-11-05 10:44:58 +01:00
Bluewhale1337 de9454e85f docs: update version to v1.7.7 in readme changelog 2026-11-05 10:13:55 +01:00
Bluewhale1337 c3f8cdb4ed Feature set: expand class support and improve buff tracking logic 2026-11-04 17:41:52 +01:00
Bluewhale1337 5a77b2298d refactor: improve Nampower aura tracking and GUID management integration 2026-11-02 17:13:37 +01:00
Bluewhale1337 7b8c0251fc fix: dropdown syntax + converted to named click handlers 2026-10-21 22:33:01 +02:00
Bluewhale1337 71b92fe1a6 refactor: unify aura and hoT tracking into a single master dictionary with localized support 2026-10-15 14:19:10 +02:00
Bluewhale1337 3ed13b97f4 fix: bump addon version to 1.7.6 in TOC file 2026-10-14 17:57:39 +02:00
Bluewhale1337 aea1f734ca fix: resolve raid class coloring, identity cache, and player range detection issues 2026-10-14 17:55:30 +02:00
21 changed files with 1482 additions and 326 deletions
+49 -12
View File
@@ -203,23 +203,60 @@ end
-- Spell parsing and casting functions moved to HealBot_Controller_Spells.lua
HealBot_ClassMap = nil
function HealBot_InitClassMap()
HealBot_ClassMap = {
["DRUID"] = "DRUID", ["Druid"] = "DRUID",
["HUNTER"] = "HUNTER", ["Hunter"] = "HUNTER",
["MAGE"] = "MAGE", ["Mage"] = "MAGE",
["PALADIN"] = "PALADIN", ["Paladin"] = "PALADIN",
["PRIEST"] = "PRIEST", ["Priest"] = "PRIEST",
["ROGUE"] = "ROGUE", ["Rogue"] = "ROGUE",
["SHAMAN"] = "SHAMAN", ["Shaman"] = "SHAMAN",
["WARLOCK"] = "WARLOCK", ["Warlock"] = "WARLOCK",
["WARRIOR"] = "WARRIOR", ["Warrior"] = "WARRIOR",
}
if HEALBOT_DRUID then HealBot_ClassMap[HEALBOT_DRUID] = "DRUID" end
if HEALBOT_HUNTER then HealBot_ClassMap[HEALBOT_HUNTER] = "HUNTER" end
if HEALBOT_MAGE then HealBot_ClassMap[HEALBOT_MAGE] = "MAGE" end
if HEALBOT_PALADIN then HealBot_ClassMap[HEALBOT_PALADIN] = "PALADIN" end
if HEALBOT_PRIEST then HealBot_ClassMap[HEALBOT_PRIEST] = "PRIEST" end
if HEALBOT_ROGUE then HealBot_ClassMap[HEALBOT_ROGUE] = "ROGUE" end
if HEALBOT_SHAMAN then HealBot_ClassMap[HEALBOT_SHAMAN] = "SHAMAN" end
if HEALBOT_WARLOCK then HealBot_ClassMap[HEALBOT_WARLOCK] = "WARLOCK" end
if HEALBOT_WARRIOR then HealBot_ClassMap[HEALBOT_WARRIOR] = "WARRIOR" end
end
-- HealBot_UnitClass: Returns English class string for a unit.
function HealBot_UnitClass(unit)
local locClass, enClass = UnitClass(unit)
if enClass then return string.upper(enClass) end
if not unit then return nil end
if not HealBot_ClassMap then HealBot_InitClassMap() end
-- Fallback for Vanilla 1.12 where enClass is nil
if locClass == HEALBOT_DRUID then return "DRUID"
elseif locClass == HEALBOT_HUNTER then return "HUNTER"
elseif locClass == HEALBOT_MAGE then return "MAGE"
elseif locClass == HEALBOT_PALADIN then return "PALADIN"
elseif locClass == HEALBOT_PRIEST then return "PRIEST"
elseif locClass == HEALBOT_ROGUE then return "ROGUE"
elseif locClass == HEALBOT_SHAMAN then return "SHAMAN"
elseif locClass == HEALBOT_WARLOCK then return "WARLOCK"
elseif locClass == HEALBOT_WARRIOR then return "WARRIOR"
-- 1. If player self, query "player" directly
if unit == "player" or UnitIsUnit(unit, "player") then
local locClass, enClass = UnitClass("player")
if enClass and enClass ~= "" then return string.upper(enClass) end
if locClass and HealBot_ClassMap[locClass] then return HealBot_ClassMap[locClass] end
if locClass then return string.upper(locClass) end
end
-- 2. If raid member, query GetRaidRosterInfo (server authoritative English class token)
local _, _, raidIdx = string.find(unit, "^raid(%d+)$")
if raidIdx and GetNumRaidMembers() > 0 then
local _, _, _, _, class, fileName = GetRaidRosterInfo(tonumber(raidIdx))
if fileName and fileName ~= "" then
return string.upper(fileName)
elseif class and HealBot_ClassMap[class] then
return HealBot_ClassMap[class]
end
end
-- 3. General fallback via UnitClass API
local locClass, enClass = UnitClass(unit)
if enClass and enClass ~= "" then return string.upper(enClass) end
if locClass and HealBot_ClassMap[locClass] then return HealBot_ClassMap[locClass] end
return locClass
end
+1 -1
View File
@@ -1,6 +1,6 @@
## Interface: 11200
## Title: HealBotBlue
## Version: 1.7.5
## Version: 1.7.7
## Author: Bluewhale
## Notes: Raidframe replacement for healing, decursing, resource tracking and buffing with optional support for SuperWow, ClassicAPI, UnitXP_SP3 and Nampower.
## SavedVariablesPerCharacter: HealBot_Config
+12
View File
@@ -2,6 +2,10 @@
-- HealBot_AlwaysHeal: Returns true if healthy units should be shown.
function HealBot_AlwaysHeal()
local class = HealBot_UnitClass("player")
if class ~= "PRIEST" and class ~= "DRUID" and class ~= "PALADIN" and class ~= "SHAMAN" then
return true
end
return HealBot_Config.EnableHealthy==1
end
@@ -60,6 +64,14 @@ end
-- HealBot_CanHeal: Internal utility: HealBot_CanHeal
function HealBot_CanHeal(unit)
if string.find(unit, "^Test") then return true end
local class = HealBot_UnitClass("player")
if class ~= "PRIEST" and class ~= "DRUID" and class ~= "PALADIN" and class ~= "SHAMAN" then
if UnitExists(unit) and not UnitIsDeadOrGhost(unit) then
return true
end
return false
end
if UnitIsDeadOrGhost(unit) then
local rezSpell = HealBot_GetRezSpellForClass();
if rezSpell and HealBot_GetHealSpell(unit, rezSpell) then
+80 -48
View File
@@ -1,3 +1,4 @@
local HealBot_Buff_Equivalents = nil
-- HealBot_Controller_Aura.lua
-- Handles tracking buffs/debuffs (auras) on group/raid units
@@ -94,14 +95,52 @@ function HealBot_CheckBuffs(unit)
return
end
-- Group Buff Equivalents
local HealBot_Buff_Equivalents = {
[HEALBOT_POWER_WORD_FORTITUDE] = HEALBOT_PRAYER_OF_FORTITUDE,
[HEALBOT_DIVINE_SPIRIT] = HEALBOT_PRAYER_OF_SPIRIT,
[HEALBOT_SHADOW_PROTECTION] = HEALBOT_PRAYER_OF_SHADOW_PROTECTION,
[HEALBOT_ARCANE_INTELLECT] = HEALBOT_ARCANE_BRILLIANCE,
[HEALBOT_MARK_OF_THE_WILD] = HEALBOT_GIFT_OF_THE_WILD,
if not HealBot_Buff_Equivalents then
HealBot_Buff_Equivalents = {
-- Priest Fortitude
[HEALBOT_POWER_WORD_FORTITUDE] = { HEALBOT_PRAYER_OF_FORTITUDE },
[HEALBOT_PRAYER_OF_FORTITUDE] = { HEALBOT_POWER_WORD_FORTITUDE },
-- Priest Spirit
[HEALBOT_DIVINE_SPIRIT] = { HEALBOT_PRAYER_OF_SPIRIT },
[HEALBOT_PRAYER_OF_SPIRIT] = { HEALBOT_DIVINE_SPIRIT },
-- Priest Shadow Protection
[HEALBOT_SHADOW_PROTECTION] = { HEALBOT_PRAYER_OF_SHADOW_PROTECTION },
[HEALBOT_PRAYER_OF_SHADOW_PROTECTION] = { HEALBOT_SHADOW_PROTECTION },
-- Mage Intellect
[HEALBOT_ARCANE_INTELLECT] = { HEALBOT_ARCANE_BRILLIANCE },
[HEALBOT_ARCANE_BRILLIANCE] = { HEALBOT_ARCANE_INTELLECT },
-- Mage Armors
[HEALBOT_FROST_ARMOR] = { HEALBOT_ICE_ARMOR },
[HEALBOT_ICE_ARMOR] = { HEALBOT_FROST_ARMOR },
-- Druid MotW
[HEALBOT_MARK_OF_THE_WILD] = { HEALBOT_GIFT_OF_THE_WILD },
[HEALBOT_GIFT_OF_THE_WILD] = { HEALBOT_MARK_OF_THE_WILD },
-- Paladin Kings
[HEALBOT_BLESSING_OF_KINGS] = { HEALBOT_GREATER_BLESSING_OF_KINGS },
[HEALBOT_GREATER_BLESSING_OF_KINGS] = { HEALBOT_BLESSING_OF_KINGS },
-- Paladin Might
[HEALBOT_BLESSING_OF_MIGHT] = { HEALBOT_GREATER_BLESSING_OF_MIGHT },
[HEALBOT_GREATER_BLESSING_OF_MIGHT] = { HEALBOT_BLESSING_OF_MIGHT },
-- Paladin Wisdom
[HEALBOT_BLESSING_OF_WISDOM] = { HEALBOT_GREATER_BLESSING_OF_WISDOM },
[HEALBOT_GREATER_BLESSING_OF_WISDOM] = { HEALBOT_BLESSING_OF_WISDOM },
-- Paladin Salvation
[HEALBOT_BLESSING_OF_SALVATION] = { HEALBOT_GREATER_BLESSING_OF_SALVATION },
[HEALBOT_GREATER_BLESSING_OF_SALVATION] = { HEALBOT_BLESSING_OF_SALVATION },
-- Paladin Light
[HEALBOT_BLESSING_OF_LIGHT] = { HEALBOT_GREATER_BLESSING_OF_LIGHT },
[HEALBOT_GREATER_BLESSING_OF_LIGHT] = { HEALBOT_BLESSING_OF_LIGHT },
-- Paladin Sanctuary
[HEALBOT_BLESSING_OF_SANCTUARY] = { HEALBOT_GREATER_BLESSING_OF_SANCTUARY },
[HEALBOT_GREATER_BLESSING_OF_SANCTUARY] = { HEALBOT_BLESSING_OF_SANCTUARY },
-- Warlock Armors
[HEALBOT_DEMON_SKIN] = { HEALBOT_DEMON_ARMOR },
[HEALBOT_DEMON_ARMOR] = { HEALBOT_DEMON_SKIN },
-- Warlock Invisibility
[HEALBOT_DETECT_LESSER_INVISIBILITY] = { HEALBOT_DETECT_INVISIBILITY },
[HEALBOT_DETECT_INVISIBILITY] = { HEALBOT_DETECT_LESSER_INVISIBILITY },
}
end
-- Gather buffs on unit
local hasBuff = StaticHasBuff
@@ -141,13 +180,17 @@ function HealBot_CheckBuffs(unit)
for j = 1, 8 do
local val = HealBot_Config.BuffDropDowns[myClass][j]
if val and val > 0 then
local isSelfOnly = (HealBot_Config.BuffWatchSelf and HealBot_Config.BuffWatchSelf[j] == 1)
if not (isSelfOnly and not UnitIsUnit(unit, "player")) then
local spellName = HealBot_Buff_Spells[myClass][val]
local isSelfOnly = (HealBot_Config.BuffWatchSelf and HealBot_Config.BuffWatchSelf[j] == 1) or (HealBot_SelfOnly_Buffs and HealBot_SelfOnly_Buffs[spellName])
if not (isSelfOnly and not UnitIsUnit(unit, "player")) then
local hasIt = hasBuff[spellName]
if not hasIt and HealBot_Buff_Equivalents[spellName] then
hasIt = hasBuff[HealBot_Buff_Equivalents[spellName]]
for _, equiv in ipairs(HealBot_Buff_Equivalents[spellName]) do
if hasBuff[equiv] then
hasIt = true
break
end
end
end
if not hasIt then
@@ -166,17 +209,6 @@ function HealBot_CheckBuffs(unit)
end
end
local HealBot_TrackedHoTs = {
["Interface\\Icons\\Spell_Holy_Renew"] = true,
["Interface\\Icons\\Spell_Nature_Rejuvenation"] = true,
["Interface\\Icons\\Spell_Nature_ResistNature"] = true,
["Interface\\Icons\\Spell_Holy_PowerWordShield"] = true,
["Interface\\Icons\\Spell_Holy_SealOfProtection"] = true,
["Interface\\Icons\\Spell_Holy_Excorcism"] = true,
["Interface\\Icons\\btnholyscriptures"] = true,
["Interface\\Icons\\Spell_Holy_AshesToAshes"] = true,
}
local HealBot_DebuffTypeMap = nil
local HealBot_AuraWarningPlayed = {}
@@ -190,6 +222,9 @@ function HealBot_OnEvent_UnitAura(this, unit)
[HEALBOT_POISON] = HEALBOT_POISON_en,
[HEALBOT_CURSE] = HEALBOT_CURSE_en
}
if HealBot_Init_TrackedAuras then
HealBot_Init_TrackedAuras()
end
end
local DebuffType;
@@ -280,48 +315,45 @@ function HealBot_OnEvent_UnitAura(this, unit)
local buff = UnitBuff(unit, b)
if not buff then break end
activeBuffs[buff] = true
if HealBot_TrackedHoTs[buff] and iconCount < 10 then
if HealBot_TrackedAura_Textures and HealBot_TrackedAura_Textures[buff] and iconCount < 10 then
iconCount = iconCount + 1
HealBot_UnitIcons[unit][iconCount] = buff
end
b = b + 1
end
if HealBot_Integrations_Nampower_Active and HealBot_Nampower_Auras then
local guid = HealBot_GetUnitGUID and HealBot_GetUnitGUID(unit)
if guid then
if not HealBot_Nampower_NameCache then HealBot_Nampower_NameCache = HealBot_GetTable() end
HealBot_Nampower_NameCache[guid] = UnitName(unit)
if HealBot_Nampower_Auras[guid] then
local validHoTs = {
["Renew"] = "Interface\\Icons\\Spell_Holy_Renew",
["Rejuvenation"] = "Interface\\Icons\\Spell_Nature_Rejuvenation",
["Regrowth"] = "Interface\\Icons\\Spell_Nature_ResistNature",
["Power Word: Shield"] = "Interface\\Icons\\Spell_Holy_PowerWordShield",
}
for spellName, _ in pairs(HealBot_Nampower_Auras[guid]) do
local tex = validHoTs[spellName]
if tex and not activeBuffs[tex] then
HealBot_Nampower_Auras[guid][spellName] = nil
end
end
end
end
end
HealBot_ReleaseTable(activeBuffs)
local d = 1
local activeDebuffs = HealBot_GetTable()
while true do
local debuff = UnitDebuff(unit, d)
if not debuff then break end
if HealBot_TrackedHoTs[debuff] and iconCount < 10 then
activeDebuffs[debuff] = true
if HealBot_TrackedAura_Textures and HealBot_TrackedAura_Textures[debuff] and iconCount < 10 then
iconCount = iconCount + 1
HealBot_UnitIcons[unit][iconCount] = debuff
end
d = d + 1
end
if HealBot_Integrations_Nampower_Active and HealBot_Nampower_Auras then
local guid = HealBot_GetUnitGUID and HealBot_GetUnitGUID(unit)
if guid then
if not HealBot_Nampower_NameCache then HealBot_Nampower_NameCache = HealBot_GetTable() end
local uName = UnitName(unit)
if uName then
HealBot_Nampower_NameCache[guid] = uName
HealBot_Nampower_NameCache[string.lower(guid)] = uName
end
if HealBot_Model and HealBot_Model.guidUnits then
HealBot_Model.guidUnits[guid] = unit
HealBot_Model.guidUnits[string.lower(guid)] = unit
HealBot_Model.unitGUIDs[unit] = guid
end
end
end
HealBot_ReleaseTable(activeBuffs)
HealBot_ReleaseTable(activeDebuffs)
if HealBot_UnitDebuff[unit] then
if DebuffType and HealBot_Range_Check(unit, 40) == 1 then
if HealBot_AuraWarningPlayed[unit] ~= DebuffType then
+40 -6
View File
@@ -172,6 +172,18 @@ function HealBot_OnUpdate(this, arg1)
for unitID in pairs(powerToRefresh) do
HealBot_Action_RefreshPower(unitID)
end
-- Periodic resolution of units with missing class identity
if HealBot_Model and HealBot_Model.unresolvedUnits and next(HealBot_Model.unresolvedUnits) then
HealBot_UnresolvedTimer = (HealBot_UnresolvedTimer or 0) + arg1
if HealBot_UnresolvedTimer >= 0.5 then
HealBot_UnresolvedTimer = 0
for u in pairs(HealBot_Model.unresolvedUnits) do
if HealBot_Model:UpdateUnitIdentity(u) then
HealBot_View_DirtyUnits[u] = true
end
end
end
end
if HealBot_EquipChangeTimer > 0 then
HealBot_EquipChangeTimer = HealBot_EquipChangeTimer - arg1
@@ -185,13 +197,23 @@ function HealBot_OnUpdate(this, arg1)
if HealBot_Config.HealBot_Integrations_ShowHoTTimers == 1 then
if not HealBot_HoT_Update_Timer or GetTime() >= HealBot_HoT_Update_Timer then
HealBot_HoT_Update_Timer = GetTime() + 0.25
if HealBot_Action_UpdatePlayerHoTs then
if HealBot_UpdateActiveHoTTimers then
HealBot_UpdateActiveHoTTimers()
elseif HealBot_Action_UpdatePlayerHoTs then
HealBot_Action_UpdatePlayerHoTs()
end
end
elseif HealBot_PlayerHoTsListFrame and HealBot_PlayerHoTsListFrame:IsVisible() then
else
if (HealBot_PlayerHoTsListFrame and HealBot_PlayerHoTsListFrame:IsVisible()) or HealBot_Overlays_Active then
if HealBot_PlayerHoTsListFrame and HealBot_PlayerHoTsListFrame:IsVisible() then
HealBot_PlayerHoTsListFrame:Hide()
end
if HealBot_ClearHoTOverlays then
HealBot_ClearHoTOverlays()
end
HealBot_Overlays_Active = false
end
end
HealBot_Timer1 = HealBot_Timer1 + arg1;
if HealBot_Timer1 >= 2.5 then
@@ -274,22 +296,30 @@ local HealBot_EventHandlers = {
HealBot_OnEvent_PlayerTargetChanged(this)
end,
["PARTY_MEMBERS_CHANGED"] = function(this)
HealBot_Model:RefreshUnit("player")
for _, unit in ipairs(HealBot_Model.partyMembers) do
HealBot_Model:RefreshUnit(unit)
end
for _, unit in ipairs(HealBot_Model.raidMembers) do
HealBot_Model:RefreshUnit(unit)
end
if HealBot_Model and HealBot_Model.PopulateAllGUIDs then
HealBot_Model:PopulateAllGUIDs()
end
HealBot_Model:NotifyObservers("ROSTER_CHANGED")
HealBot_OnEvent_PartyMembersChanged(this)
end,
["RAID_ROSTER_UPDATE"] = function(this)
HealBot_Model:RefreshUnit("player")
for _, unit in ipairs(HealBot_Model.partyMembers) do
HealBot_Model:RefreshUnit(unit)
end
for _, unit in ipairs(HealBot_Model.raidMembers) do
HealBot_Model:RefreshUnit(unit)
end
if HealBot_Model and HealBot_Model.PopulateAllGUIDs then
HealBot_Model:PopulateAllGUIDs()
end
HealBot_Model:NotifyObservers("ROSTER_CHANGED")
HealBot_OnEvent_PartyMembersChanged(this)
end,
@@ -303,6 +333,9 @@ local HealBot_EventHandlers = {
["PLAYER_ENTERING_WORLD"] = function(this)
HealBot_Model:RefreshUnit("player")
HealBot_Model:RefreshUnit("pet")
if HealBot_Model and HealBot_Model.PopulateAllGUIDs then
HealBot_Model:PopulateAllGUIDs()
end
HealBot_OnEvent_PlayerEnteringWorld(this)
end,
["VARIABLES_LOADED"] = function(this)
@@ -346,8 +379,6 @@ end
-- HealBot_OnEvent_VariablesLoaded: Applies config defaults and initializes state.
function HealBot_OnEvent_VariablesLoaded(this)
local class = HealBot_UnitClass("player")
local function DeepCopyMissing(src, dest)
for k, v in pairs(src) do
if type(v) == "table" then
@@ -362,6 +393,11 @@ function HealBot_OnEvent_VariablesLoaded(this)
end
DeepCopyMissing(HealBot_ConfigDefaults, HealBot_Config)
local locClass = UnitClass("player")
if locClass and (not HealBot_Config.KeyCombo[locClass] or not next(HealBot_Config.KeyCombo[locClass])) then
HealBot_Config.KeyCombo[locClass] = { ["Left"] = "Target" }
end
local foundModern = false
if HealBot_Config.Skins then
for _, skin in ipairs(HealBot_Config.Skins) do
@@ -390,7 +426,6 @@ function HealBot_OnEvent_VariablesLoaded(this)
HidePartyFrame();
end
if class == "PRIEST" or class == "DRUID" or class == "PALADIN" or class == "SHAMAN" then
HealBot_BonusScanner:ScanEquipment();
HealBot_Action_ShowFrame();
@@ -423,7 +458,6 @@ function HealBot_OnEvent_VariablesLoaded(this)
this:RegisterEvent("PLAYER_ENTERING_WORLD");
HealBot_SpellsInitFlag = 2;
end
end
-- HealBot_OnEvent_UnitHealth: Internal utility: HealBot_OnEvent_UnitHealth
function HealBot_OnEvent_UnitHealth(this, unit)
+1 -1
View File
@@ -33,7 +33,7 @@ function HealBot_Range_Check(unit, range)
return _rangeCache[range][unit]
end
if ( unit == "player" or string.find(unit, "^Test") ) then
if ( unit and (unit == "player" or UnitIsUnit(unit, "player") or string.find(unit, "^Test")) ) then
return_val = 1;
elseif HealBot_Integrations_ClassicAPI_Active and UnitDistanceSquared and UnitInLineOfSight then
local inSight = UnitInLineOfSight("player", unit)
+8 -6
View File
@@ -491,6 +491,7 @@ function HealBot_FindHealSpells()
if HealBot_SpellsInitFlag > 0 then NeedEquipUpdate = 1; return; end
HealBot_Heals = { player = {}, pet = {}, party = {} };
RealHealing = 0;
table.foreach(HealBot_CurrentSpells, function (index, spell)
if (HealBot_Spells[spell]) then
@@ -534,12 +535,8 @@ function HealBot_FindHealSpells()
end
end
end
table.foreach(HealBot_Heals, function (key, val)
if (table.getn(val) == 0) then
HealBot_Heals[key] = nil;
end
end);
HealBot_Heals.target = HealBot_Heals.party;
HealBot_Heals.focus = HealBot_Heals.party;
for i = 1, 4 do
HealBot_Heals["party" .. i] = HealBot_Heals.party;
HealBot_Heals["partypet" .. i] = HealBot_Heals.party;
@@ -551,7 +548,7 @@ function HealBot_FindHealSpells()
HealBot_ReleaseTable(items);
if HealBot_CalcEquipBonus then
HealBot_AddDebug("...Done Equip Bonus:" .. RealHealing);
HealBot_AddDebug("...Done Equip Bonus:" .. tostring(RealHealing or 0));
end
HealBot_CalcEquipBonus = false;
end
@@ -590,6 +587,11 @@ function HealBot_GetHealSpell(unit, pattern)
return pattern;
end
-- Handle Special Targeting Pattern
if string.lower(pattern) == "target" then
return pattern;
end
-- Handle Spells
if HealBot_Spells[pattern] or HealBot_GetSpellId(pattern) then
local spell = HealBot_GetSpellName(HealBot_GetSpellId(pattern)) or pattern
+124 -2
View File
@@ -66,12 +66,22 @@ HealBot_ConfigDefaults = {
[HEALBOT_PALADIN] = 1,
[HEALBOT_PRIEST] = 1,
[HEALBOT_SHAMAN] = 1,
[HEALBOT_MAGE] = 1,
[HEALBOT_WARRIOR] = 1,
[HEALBOT_ROGUE] = 1,
[HEALBOT_HUNTER] = 1,
[HEALBOT_WARLOCK] = 1,
},
Debuff_Right = {
[HEALBOT_DRUID] = 1,
[HEALBOT_PALADIN] = 1,
[HEALBOT_PRIEST] = 1,
[HEALBOT_SHAMAN] = 1,
[HEALBOT_MAGE] = 1,
[HEALBOT_WARRIOR] = 1,
[HEALBOT_ROGUE] = 1,
[HEALBOT_HUNTER] = 1,
[HEALBOT_WARLOCK] = 1,
},
BuffWatch = 1,
BuffWatchInCombat = 0,
@@ -187,13 +197,28 @@ HealBot_ConfigDefaults = {
["ShiftCtrlRight"] = HEALBOT_HEALING_WAVE .. HEALBOT_RANK_4,
["Middle"] = HEALBOT_CHAIN_HEAL,
},
[HEALBOT_WARRIOR] = {
["Left"] = "Target",
},
[HEALBOT_MAGE] = {
["Left"] = "Target",
},
[HEALBOT_ROGUE] = {
["Left"] = "Target",
},
[HEALBOT_HUNTER] = {
["Left"] = "Target",
},
[HEALBOT_WARLOCK] = {
["Left"] = "Target",
},
},
EnableHealthy = 0,
ShowNonManaBars = 0,
ActionVisible = 0,
ActionMouseover = 1,
CDCLeftText = {[HEALBOT_PRIEST]="None", [HEALBOT_SHAMAN]="None", [HEALBOT_DRUID]="None", [HEALBOT_PALADIN]="None",},
CDCRightText = {[HEALBOT_PRIEST]="None", [HEALBOT_SHAMAN]="None", [HEALBOT_DRUID]="None", [HEALBOT_PALADIN]="None",},
CDCLeftText = {[HEALBOT_PRIEST]="None", [HEALBOT_SHAMAN]="None", [HEALBOT_DRUID]="None", [HEALBOT_PALADIN]="None", [HEALBOT_MAGE]="None", [HEALBOT_WARRIOR]="None", [HEALBOT_ROGUE]="None", [HEALBOT_HUNTER]="None", [HEALBOT_WARLOCK]="None",},
CDCRightText = {[HEALBOT_PRIEST]="None", [HEALBOT_SHAMAN]="None", [HEALBOT_DRUID]="None", [HEALBOT_PALADIN]="None", [HEALBOT_MAGE]="None", [HEALBOT_WARRIOR]="None", [HEALBOT_ROGUE]="None", [HEALBOT_HUNTER]="None", [HEALBOT_WARLOCK]="None",},
Current_Skin = "Modern Flat",
Skin_ID = 1,
Skins = {"Modern Flat", HEALBOT_SKINS_STD, "HealBot Party", "HealBot Raid", "Alteric Valley"},
@@ -269,6 +294,8 @@ HealBot_ConfigDefaults = {
HealBot_Integrations_SuperWoW = 0,
HealBot_Integrations_ClassicAPI = 0,
HealBot_Integrations_ShowHoTTimers = 0,
HealBot_Integrations_HoTTimerPosition = "BELOW",
HealBot_Integrations_HoTTimerDisplayMode = 0,
};
HealBot_Config = {};
@@ -510,6 +537,9 @@ HealBot_Debuff_Spells = {
HEALBOT_CURE_POISON,
HEALBOT_CURE_DISEASE,
},
[HEALBOT_MAGE] = {
HEALBOT_REMOVE_LESSER_CURSE,
},
}
HealBot_Buff_Spells = {
@@ -520,6 +550,13 @@ HealBot_Buff_Spells = {
HEALBOT_BLESSING_OF_SALVATION,
HEALBOT_BLESSING_OF_LIGHT,
HEALBOT_BLESSING_OF_SANCTUARY,
HEALBOT_GREATER_BLESSING_OF_KINGS,
HEALBOT_GREATER_BLESSING_OF_MIGHT,
HEALBOT_GREATER_BLESSING_OF_WISDOM,
HEALBOT_GREATER_BLESSING_OF_SALVATION,
HEALBOT_GREATER_BLESSING_OF_LIGHT,
HEALBOT_GREATER_BLESSING_OF_SANCTUARY,
HEALBOT_RIGHTEOUS_FURY,
},
[HEALBOT_DRUID] = {
HEALBOT_MARK_OF_THE_WILD,
@@ -536,6 +573,7 @@ HealBot_Buff_Spells = {
HEALBOT_PRAYER_OF_SHADOW_PROTECTION,
HEALBOT_INNER_FIRE,
HEALBOT_FEAR_WARD,
HEALBOT_SHADOWFORM,
HEALBOT_ENLIGHTEN,
},
[HEALBOT_MAGE] = {
@@ -543,13 +581,63 @@ HealBot_Buff_Spells = {
HEALBOT_ARCANE_BRILLIANCE,
HEALBOT_DAMPEN_MAGIC,
HEALBOT_AMPLIFY_MAGIC,
HEALBOT_FROST_ARMOR,
HEALBOT_ICE_ARMOR,
HEALBOT_MAGE_ARMOR,
HEALBOT_ICE_BARRIER,
},
[HEALBOT_SHAMAN] = {
HEALBOT_ROCKBITER_WEAPON,
HEALBOT_FLAMETONGUE_WEAPON,
HEALBOT_FROSTBRAND_WEAPON,
HEALBOT_WINDFURY_WEAPON,
HEALBOT_LIGHTNING_SHIELD,
HEALBOT_WATER_SHIELD,
HEALBOT_WATER_WALKING,
HEALBOT_WATER_BREATHING,
},
[HEALBOT_WARRIOR] = {
HEALBOT_BATTLE_SHOUT,
},
[HEALBOT_WARLOCK] = {
HEALBOT_DEMON_SKIN,
HEALBOT_DEMON_ARMOR,
HEALBOT_UNENDING_BREATH,
HEALBOT_DETECT_LESSER_INVISIBILITY,
HEALBOT_DETECT_INVISIBILITY,
},
[HEALBOT_HUNTER] = {
HEALBOT_TRUESHOT_AURA,
HEALBOT_ASPECT_OF_THE_HAWK,
HEALBOT_ASPECT_OF_THE_MONKEY,
HEALBOT_ASPECT_OF_THE_CHEETAH,
HEALBOT_ASPECT_OF_THE_PACK,
HEALBOT_ASPECT_OF_THE_WILD,
HEALBOT_ASPECT_OF_THE_BEAST,
},
[HEALBOT_ROGUE] = {},
}
HealBot_SelfOnly_Buffs = {
[HEALBOT_DEMON_SKIN] = true,
[HEALBOT_DEMON_ARMOR] = true,
[HEALBOT_ASPECT_OF_THE_HAWK] = true,
[HEALBOT_ASPECT_OF_THE_MONKEY] = true,
[HEALBOT_ASPECT_OF_THE_CHEETAH] = true,
[HEALBOT_ASPECT_OF_THE_BEAST] = true,
[HEALBOT_FROST_ARMOR] = true,
[HEALBOT_ICE_ARMOR] = true,
[HEALBOT_MAGE_ARMOR] = true,
[HEALBOT_ICE_BARRIER] = true,
[HEALBOT_RIGHTEOUS_FURY] = true,
[HEALBOT_INNER_FIRE] = true,
[HEALBOT_SHADOWFORM] = true,
[HEALBOT_LIGHTNING_SHIELD] = true,
[HEALBOT_WATER_SHIELD] = true,
[HEALBOT_ROCKBITER_WEAPON] = true,
[HEALBOT_FLAMETONGUE_WEAPON] = true,
[HEALBOT_FROSTBRAND_WEAPON] = true,
[HEALBOT_WINDFURY_WEAPON] = true,
}
HealBot_Debuff_Types = {
@@ -562,6 +650,7 @@ HealBot_Debuff_Types = {
[HEALBOT_ABOLISH_DISEASE] = {HEALBOT_DISEASE_en},
[HEALBOT_DISPEL_MAGIC..HEALBOT_RANK_1] = {HEALBOT_MAGIC_en},
[HEALBOT_DISPEL_MAGIC..HEALBOT_RANK_2] = {HEALBOT_MAGIC_en},
[HEALBOT_REMOVE_LESSER_CURSE] = {HEALBOT_CURSE_en},
}
HealBot_IsFighting = false;
@@ -603,3 +692,36 @@ function HealBot_ReleaseTable(t)
end
end
HealBot_TrackedAuras = {
["Renew"] = { texture = "Interface\\Icons\\Spell_Holy_Renew", isDebuff = false, showTimer = true, locKey = "HEALBOT_RENEW" },
["Rejuvenation"] = { texture = "Interface\\Icons\\Spell_Nature_Rejuvenation", isDebuff = false, showTimer = true, locKey = "HEALBOT_REJUVENATION" },
["Regrowth"] = { texture = "Interface\\Icons\\Spell_Nature_ResistNature", isDebuff = false, showTimer = true, locKey = "HEALBOT_REGROWTH" },
["Power Word: Shield"] = { texture = "Interface\\Icons\\Spell_Holy_PowerWordShield", isDebuff = false, showTimer = true, locKey = "HEALBOT_POWER_WORD_SHIELD" },
["Fear Ward"] = { texture = "Interface\\Icons\\Spell_Holy_Excorcism", isDebuff = false, showTimer = true, locKey = "HEALBOT_FEAR_WARD" },
["Abolish Disease"] = { texture = "Interface\\Icons\\Spell_Nature_NullifyDisease",isDebuff = false, showTimer = true, locKey = "HEALBOT_ABOLISH_DISEASE" },
["Abolish Poison"] = { texture = "Interface\\Icons\\Spell_Nature_NullifyPoison", isDebuff = false, showTimer = true, locKey = "HEALBOT_ABOLISH_POISON" },
["Weakened Soul"] = { texture = "Interface\\Icons\\Spell_Holy_AshesToAshes", isDebuff = true, showTimer = true, locKey = "HEALBOT_WEAKENED_SOUL" },
["Blessing of Protection"] = { texture = "Interface\\Icons\\Spell_Holy_SealOfProtection", isDebuff = false, showTimer = false },
["Holy Scriptures"] = { texture = "Interface\\Icons\\btnholyscriptures", isDebuff = false, showTimer = false },
};
HealBot_TrackedAura_Textures = {};
HealBot_TrackedAura_Spells = {};
function HealBot_Init_TrackedAuras()
for spell, info in pairs(HealBot_TrackedAuras) do
info.spell = spell
HealBot_TrackedAura_Textures[info.texture] = info
HealBot_TrackedAura_Spells[spell] = info
if info.locKey then
local locName = getglobal(info.locKey)
if locName and locName ~= "" then
info.locName = locName
HealBot_TrackedAura_Spells[locName] = info
end
end
end
end
HealBot_Init_TrackedAuras();
+103 -33
View File
@@ -40,11 +40,15 @@ function HealBot_Integrations_Toggle()
if not HealBot_Integrations_Nampower_Active then return end
if event == "AURA_CAST_ON_SELF" or event == "AURA_CAST_ON_OTHER" then
local spellID, caster, target, _, _, _, _, duration = arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
if not caster or not target or duration <= 0 then return end
if not caster or not target or not duration or duration <= 0 then return end
-- The player is ALWAYS the caster in these events for Nampower
if not HealBot_PlayerGUID then
HealBot_PlayerGUID = caster
if HealBot_Model and HealBot_Model.unitGUIDs then
HealBot_Model.unitGUIDs["player"] = caster
HealBot_Model.guidUnits[caster] = "player"
end
end
local spellName = GetSpellRecField(spellID, "name")
@@ -57,9 +61,62 @@ function HealBot_Integrations_Toggle()
local expirationTime = GetTime() + (duration / 1000)
HealBot_Nampower_Auras[target][spellName] = expirationTime
local unitID = HealBot_Model:GetUnitIDByName(target)
if unitID then
HealBot_OnEvent_UnitAura(nil, unitID)
if not HealBot_Nampower_NameCache then HealBot_Nampower_NameCache = HealBot_GetTable() end
local unitID = nil
local tName = nil
if event == "AURA_CAST_ON_SELF" or (HealBot_PlayerGUID and (target == HealBot_PlayerGUID or string.lower(target) == string.lower(HealBot_PlayerGUID))) then
unitID = "player"
tName = UnitName("player")
if not HealBot_PlayerGUID then
HealBot_PlayerGUID = target
end
else
unitID = HealBot_Model and (HealBot_Model:GetUnitByGUID(target) or HealBot_Model:GetUnitByGUID(string.lower(target)))
if not unitID and HealBot_PlayerGUID and (target == HealBot_PlayerGUID or string.lower(target) == string.lower(HealBot_PlayerGUID)) then
unitID = "player"
end
if UnitExists("target") then
local curTargetGuid = HealBot_GetUnitGUID and HealBot_GetUnitGUID("target")
if curTargetGuid and (curTargetGuid == target or string.lower(curTargetGuid) == string.lower(target)) then
tName = UnitName("target")
if not unitID and UnitIsUnit("target", "player") then unitID = "player" end
end
end
if not tName and UnitExists("mouseover") then
local curMOGuid = HealBot_GetUnitGUID and HealBot_GetUnitGUID("mouseover")
if curMOGuid and (curMOGuid == target or string.lower(curMOGuid) == string.lower(target)) then
tName = UnitName("mouseover")
if not unitID and UnitIsUnit("mouseover", "player") then unitID = "player" end
end
end
if not tName and unitID then
tName = UnitName(unitID) or (HealBot_Model and HealBot_Model.units[unitID] and HealBot_Model.units[unitID].name)
end
end
if tName then
HealBot_Nampower_NameCache[target] = tName
HealBot_Nampower_NameCache[string.lower(target)] = tName
end
if unitID and HealBot_Model then
if HealBot_Model.guidUnits then
HealBot_Model.guidUnits[target] = unitID
HealBot_Model.guidUnits[string.lower(target)] = unitID
end
if HealBot_Model.unitGUIDs then
HealBot_Model.unitGUIDs[unitID] = target
end
end
if unitID and HealBot_View_DirtyUnits then
HealBot_View_DirtyUnits[unitID] = true
end
if HealBot_UpdateActiveHoTTimers then
HealBot_UpdateActiveHoTTimers()
elseif HealBot_Action_UpdatePlayerHoTs then
HealBot_Action_UpdatePlayerHoTs()
end
end
end)
@@ -75,35 +132,6 @@ function HealBot_Integrations_Toggle()
end
end
function HealBot_Integrations_PruneNampower()
if not HealBot_Integrations_Nampower_Active or not HealBot_Nampower_Auras then return end
local currentTime = GetTime()
for targetName, auras in pairs(HealBot_Nampower_Auras) do
-- Check if target is still in the raid/party
if not HealBot_Model:GetUnitByGUID(targetName) and not HealBot_Model:GetUnitIDByName(targetName) then
HealBot_ReleaseTable(auras)
HealBot_Nampower_Auras[targetName] = nil
else
-- Prune expired auras
local hasAuras = false
for spellName, expiration in pairs(auras) do
if currentTime > expiration then
auras[spellName] = nil
else
hasAuras = true
end
end
if not hasAuras then
HealBot_ReleaseTable(auras)
HealBot_Nampower_Auras[targetName] = nil
end
end
end
end
-- SuperWoW
if HealBot_Config.HealBot_Integrations_SuperWoW == 1 and UnitExists ~= nil then
-- We can check if GetUnitGUID exists as a quick SuperWoW test, or UnitExists returns 2 args
@@ -135,6 +163,10 @@ end
HealBot_AddDebug("ClassicAPI Integration: DISABLED");
end
if HealBot_Model and HealBot_Model.PopulateAllGUIDs then
HealBot_Model:PopulateAllGUIDs()
end
if HealBot_Options_Integrations_ShowHoTTimers then
if HealBot_Integrations_Nampower_Active or HealBot_Integrations_SuperWoW_Active or HealBot_Integrations_ClassicAPI_Active then
HealBot_Options_Integrations_ShowHoTTimers:Enable()
@@ -145,5 +177,43 @@ end
HealBot_Options_Integrations_ShowHoTTimers:SetChecked(0)
HealBot_Config.HealBot_Integrations_ShowHoTTimers = 0
end
if HealBot_Options_Integrations_UpdateDropdownStates then
HealBot_Options_Integrations_UpdateDropdownStates()
end
end
end
function HealBot_Integrations_PruneNampower()
if not HealBot_Integrations_Nampower_Active or not HealBot_Nampower_Auras then return end
local currentTime = GetTime()
for targetName, auras in pairs(HealBot_Nampower_Auras) do
local lowerName = string.lower(targetName)
local isPlayer = (HealBot_PlayerGUID and lowerName == string.lower(HealBot_PlayerGUID))
or (UnitName("player") and lowerName == string.lower(UnitName("player")))
or (HealBot_GetUnitGUID and (targetName == HealBot_GetUnitGUID("player") or lowerName == string.lower(HealBot_GetUnitGUID("player") or "")))
-- Prune expired auras
local hasAuras = false
for spellName, expiration in pairs(auras) do
if currentTime > expiration then
auras[spellName] = nil
else
hasAuras = true
end
end
if not hasAuras then
HealBot_ReleaseTable(auras)
HealBot_Nampower_Auras[targetName] = nil
elseif not isPlayer and not (HealBot_Model and (HealBot_Model:GetUnitByGUID(targetName) or HealBot_Model:GetUnitByGUID(lowerName))) and not (HealBot_Model and HealBot_Model:GetUnitIDByName(targetName)) then
-- Target left group or disconnected and is not player
if GetNumPartyMembers() == 0 and GetNumRaidMembers() == 0 then
-- Solo: keep non-player auras until expired
else
HealBot_ReleaseTable(auras)
HealBot_Nampower_Auras[targetName] = nil
end
end
end
end
+55
View File
@@ -83,6 +83,59 @@ HEALBOT_POWER_WORD_FORTITUDE = "Machtwort: Seelenst\195\164rke";
HEALBOT_MARK_OF_THE_WILD = "Mal der Wildnis";
HEALBOT_BLESSING_OF_SALVATION = "Segen der Rettung";
HEALBOT_BATTLE_SHOUT = "Schlachtruf";
HEALBOT_BLOODRAGE = "Blutrausch";
HEALBOT_BERSERKER_RAGE = "Berserkerwut";
HEALBOT_DEMON_SKIN = "D\195\164monenhaut";
HEALBOT_DEMON_ARMOR = "D\195\164monenr\195\188stung";
HEALBOT_UNENDING_BREATH = "Unendlicher Atem";
HEALBOT_DETECT_LESSER_INVISIBILITY = "Geringe Unsichtbarkeit entdecken";
HEALBOT_DETECT_INVISIBILITY = "Unsichtbarkeit entdecken";
HEALBOT_SHADOW_WARD = "Schattenzauberschutz";
HEALBOT_SOULSTONE_RESURRECTION = "Seelenstein-Auferstehung";
HEALBOT_FIRE_SHIELD = "Feuerschild";
HEALBOT_TRUESHOT_AURA = "Aura des Volltreffers";
HEALBOT_ASPECT_OF_THE_HAWK = "Aspekt des Falken";
HEALBOT_ASPECT_OF_THE_MONKEY = "Aspekt des Affen";
HEALBOT_ASPECT_OF_THE_CHEETAH = "Aspekt des Geparden";
HEALBOT_ASPECT_OF_THE_PACK = "Aspekt des Rudels";
HEALBOT_ASPECT_OF_THE_WILD = "Aspekt der Wildnis";
HEALBOT_ASPECT_OF_THE_BEAST = "Aspekt des Wildtiers";
HEALBOT_STEALTH = "Verstohlenheit";
HEALBOT_BLADE_FLURRY = "Klingenwirbel";
HEALBOT_EVASION = "Entrinnen";
HEALBOT_SPRINT = "Sprinten";
HEALBOT_SLICE_AND_DICE = "Zerh\195\164ckseln";
HEALBOT_FROST_ARMOR = "Frostr\195\188stung";
HEALBOT_ICE_ARMOR = "Eisr\195\188stung";
HEALBOT_MAGE_ARMOR = "Magische R\195\188stung";
HEALBOT_MANA_SHIELD = "Manaschild";
HEALBOT_ICE_BARRIER = "Eisbarriere";
HEALBOT_FIRE_WARD = "Feuerzauberschutz";
HEALBOT_FROST_WARD = "Frostzauberschutz";
HEALBOT_GREATER_BLESSING_OF_SALVATION = "Gro\195\159er Segen der Rettung";
HEALBOT_GREATER_BLESSING_OF_MIGHT = "Gro\195\159er Segen der Macht";
HEALBOT_GREATER_BLESSING_OF_WISDOM = "Gro\195\159er Segen der Weisheit";
HEALBOT_GREATER_BLESSING_OF_KINGS = "Gro\195\159er Segen der K\195\182nige";
HEALBOT_GREATER_BLESSING_OF_LIGHT = "Gro\195\159er Segen des Lichts";
HEALBOT_GREATER_BLESSING_OF_SANCTUARY = "Gro\195\159er Segen des Unterschlupfs";
HEALBOT_RIGHTEOUS_FURY = "Zorn der Gerechtigkeit";
HEALBOT_SHADOWFORM = "Schattengestalt";
HEALBOT_BARKSKIN = "Baumrinde";
HEALBOT_NATURES_GRASP = "Griff der Natur";
HEALBOT_LIGHTNING_SHIELD = "Blitzschlagschild";
HEALBOT_WATER_SHIELD = "Wasserschild";
HEALBOT_WATER_WALKING = "Wasserwandeln";
HEALBOT_WATER_BREATHING = "Wasseratmung";
HEALBOT_RESURRECTION = "Auferstehung";
HEALBOT_REDEMPTION = "Erl\195\182sung";
HEALBOT_REBIRTH = "Wiedergeburt";
@@ -96,6 +149,7 @@ HEALBOT_DISPEL_MAGIC = "Magiebannung";
HEALBOT_CURE_POISON = "Vergiftung heilen";
HEALBOT_ABOLISH_POISON = "Vergiftung aufheben";
HEALBOT_REMOVE_CURSE = "Fluch aufheben";
HEALBOT_REMOVE_LESSER_CURSE= "Geringeren Fluch aufheben";
HEALBOT_DISEASE = "Krankheit";
HEALBOT_MAGIC = "Magie";
HEALBOT_CURSE = "Fluch";
@@ -154,6 +208,7 @@ HEALBOT_BUFF_REGROWTH = "Interface\\Icons\\Spell_Nature_ResistNature"
HEALBOT_BUFF_RENEW = "Interface\\Icons\\Spell_Holy_Renew";
HEALBOT_BUFF_FEAR_WARD = "Interface\\Icons\\Spell_Holy_Excorcism";
HEALBOT_DEBUFF_WEAKENED_SOUL = "Interface\\Icons\\Spell_Holy_AshesToAshes";
HEALBOT_WEAKENED_SOUL = "Geschw\195\164chte Seele";
HEALBOT_DEBUFF_RECENTLY_BANDAGED = "Interface\\Icons\\INV_Misc_Bandage_08";
+55
View File
@@ -95,6 +95,59 @@ HEALBOT_INNER_FIRE = "Inner Fire";
HEALBOT_FEAR_WARD = "Fear Ward";
HEALBOT_ENLIGHTEN = "Enlighten";
HEALBOT_BATTLE_SHOUT = "Battle Shout";
HEALBOT_BLOODRAGE = "Bloodrage";
HEALBOT_BERSERKER_RAGE = "Berserker Rage";
HEALBOT_DEMON_SKIN = "Demon Skin";
HEALBOT_DEMON_ARMOR = "Demon Armor";
HEALBOT_UNENDING_BREATH = "Unending Breath";
HEALBOT_DETECT_LESSER_INVISIBILITY = "Detect Lesser Invisibility";
HEALBOT_DETECT_INVISIBILITY = "Detect Invisibility";
HEALBOT_SHADOW_WARD = "Shadow Ward";
HEALBOT_SOULSTONE_RESURRECTION = "Soulstone Resurrection";
HEALBOT_FIRE_SHIELD = "Fire Shield";
HEALBOT_TRUESHOT_AURA = "Trueshot Aura";
HEALBOT_ASPECT_OF_THE_HAWK = "Aspect of the Hawk";
HEALBOT_ASPECT_OF_THE_MONKEY = "Aspect of the Monkey";
HEALBOT_ASPECT_OF_THE_CHEETAH = "Aspect of the Cheetah";
HEALBOT_ASPECT_OF_THE_PACK = "Aspect of the Pack";
HEALBOT_ASPECT_OF_THE_WILD = "Aspect of the Wild";
HEALBOT_ASPECT_OF_THE_BEAST = "Aspect of the Beast";
HEALBOT_STEALTH = "Stealth";
HEALBOT_BLADE_FLURRY = "Blade Flurry";
HEALBOT_EVASION = "Evasion";
HEALBOT_SPRINT = "Sprint";
HEALBOT_SLICE_AND_DICE = "Slice and Dice";
HEALBOT_FROST_ARMOR = "Frost Armor";
HEALBOT_ICE_ARMOR = "Ice Armor";
HEALBOT_MAGE_ARMOR = "Mage Armor";
HEALBOT_MANA_SHIELD = "Mana Shield";
HEALBOT_ICE_BARRIER = "Ice Barrier";
HEALBOT_FIRE_WARD = "Fire Ward";
HEALBOT_FROST_WARD = "Frost Ward";
HEALBOT_GREATER_BLESSING_OF_SALVATION = "Greater Blessing of Salvation";
HEALBOT_GREATER_BLESSING_OF_MIGHT = "Greater Blessing of Might";
HEALBOT_GREATER_BLESSING_OF_WISDOM = "Greater Blessing of Wisdom";
HEALBOT_GREATER_BLESSING_OF_KINGS = "Greater Blessing of Kings";
HEALBOT_GREATER_BLESSING_OF_LIGHT = "Greater Blessing of Light";
HEALBOT_GREATER_BLESSING_OF_SANCTUARY = "Greater Blessing of Sanctuary";
HEALBOT_RIGHTEOUS_FURY = "Righteous Fury";
HEALBOT_SHADOWFORM = "Shadowform";
HEALBOT_BARKSKIN = "Barkskin";
HEALBOT_NATURES_GRASP = "Nature's Grasp";
HEALBOT_LIGHTNING_SHIELD = "Lightning Shield";
HEALBOT_WATER_SHIELD = "Water Shield";
HEALBOT_WATER_WALKING = "Water Walking";
HEALBOT_WATER_BREATHING = "Water Breathing";
HEALBOT_RESURRECTION = "Resurrection";
HEALBOT_REDEMPTION = "Redemption";
HEALBOT_REBIRTH = "Rebirth";
@@ -104,6 +157,7 @@ HEALBOT_PURIFY = "Purify";
HEALBOT_CLEANSE = "Cleanse";
HEALBOT_CURE_POISON = "Cure Poison";
HEALBOT_REMOVE_CURSE = "Remove Curse";
HEALBOT_REMOVE_LESSER_CURSE= "Remove Lesser Curse";
HEALBOT_ABOLISH_POISON = "Abolish Poison";
HEALBOT_CURE_DISEASE = "Cure Disease";
HEALBOT_ABOLISH_DISEASE = "Abolish Disease";
@@ -171,6 +225,7 @@ HEALBOT_BUFF_REGROWTH = "Interface\\Icons\\Spell_Nature_ResistNature"
HEALBOT_BUFF_RENEW = "Interface\\Icons\\Spell_Holy_Renew";
HEALBOT_BUFF_FEAR_WARD = "Interface\\Icons\\Spell_Holy_Excorcism";
HEALBOT_DEBUFF_WEAKENED_SOUL = "Interface\\Icons\\Spell_Holy_AshesToAshes";
HEALBOT_WEAKENED_SOUL = "Weakened Soul";
HEALBOT_DEBUFF_RECENTLY_BANDAGED = "Interface\\Icons\\INV_Misc_Bandage_08";
+55
View File
@@ -72,6 +72,7 @@ HEALBOT_LESSER_HEAL = "Soins inf\195\169rieurs";
HEALBOT_LESSER_HEALING_WAVE = "Vague de soins mineurs";
HEALBOT_MEND_PET = "Soigner un Familier";
HEALBOT_POWER_WORD_SHIELD = "Mot de pouvoir : Bouclier";
HEALBOT_WEAKENED_SOUL = "\195\130me affaiblie";
HEALBOT_REGROWTH = "R\195\169tablissement";
HEALBOT_RENEW = "R\195\169novation";
HEALBOT_REJUVENATION = "R\195\169cup\195\169ration";
@@ -82,6 +83,59 @@ HEALBOT_POWER_WORD_FORTITUDE = "Mot de pouvoir : Robustesse";
HEALBOT_MARK_OF_THE_WILD = "Marque du fauve";
HEALBOT_BLESSING_OF_SALVATION = "B\195\169n\195\169diction de salut";
HEALBOT_BATTLE_SHOUT = "Cri de guerre";
HEALBOT_BLOODRAGE = "Rage sanguinaire";
HEALBOT_BERSERKER_RAGE = "Rage berserker";
HEALBOT_DEMON_SKIN = "Peau de d\195\169mon";
HEALBOT_DEMON_ARMOR = "Armure d\195\169moniaque";
HEALBOT_UNENDING_BREATH = "Respiration interminable";
HEALBOT_DETECT_LESSER_INVISIBILITY = "D\195\169tection de l'invisibilit\195\169 inf\195\169rieure";
HEALBOT_DETECT_INVISIBILITY = "D\195\169tection de l'invisibilit\195\169";
HEALBOT_SHADOW_WARD = "Gardien de l'ombre";
HEALBOT_SOULSTONE_RESURRECTION = "R\195\169surrection de pierre d'\195\162me";
HEALBOT_FIRE_SHIELD = "Bouclier de feu";
HEALBOT_TRUESHOT_AURA = "Aura de pr\195\169cision";
HEALBOT_ASPECT_OF_THE_HAWK = "Aspect du faucon";
HEALBOT_ASPECT_OF_THE_MONKEY = "Aspect du singe";
HEALBOT_ASPECT_OF_THE_CHEETAH = "Aspect du gu\195\169pard";
HEALBOT_ASPECT_OF_THE_PACK = "Aspect de la meute";
HEALBOT_ASPECT_OF_THE_WILD = "Aspect de la nature";
HEALBOT_ASPECT_OF_THE_BEAST = "Aspect de la b\195\170te";
HEALBOT_STEALTH = "Camouflage";
HEALBOT_BLADE_FLURRY = "D\195\169luge de lames";
HEALBOT_EVASION = "Evasion";
HEALBOT_SPRINT = "Sprint";
HEALBOT_SLICE_AND_DICE = "D\195\169biter";
HEALBOT_FROST_ARMOR = "Armure de givre";
HEALBOT_ICE_ARMOR = "Armure de glace";
HEALBOT_MAGE_ARMOR = "Armure du mage";
HEALBOT_MANA_SHIELD = "Bouclier de mana";
HEALBOT_ICE_BARRIER = "Barri\195\168re de glace";
HEALBOT_FIRE_WARD = "Gardien de feu";
HEALBOT_FROST_WARD = "Gardien de givre";
HEALBOT_GREATER_BLESSING_OF_SALVATION = "B\195\169n\195\169diction de salut sup\195\169rieure";
HEALBOT_GREATER_BLESSING_OF_MIGHT = "B\195\169n\195\169diction de puissance sup\195\169rieure";
HEALBOT_GREATER_BLESSING_OF_WISDOM = "B\195\169n\195\169diction de sagesse sup\195\169rieure";
HEALBOT_GREATER_BLESSING_OF_KINGS = "B\195\169n\195\169diction des rois sup\195\169rieure";
HEALBOT_GREATER_BLESSING_OF_LIGHT = "B\195\169n\195\169diction de lumi\195\168re sup\195\169rieure";
HEALBOT_GREATER_BLESSING_OF_SANCTUARY = "B\195\169n\195\169diction du sanctuaire sup\195\169rieure";
HEALBOT_RIGHTEOUS_FURY = "Fureur vertueuse";
HEALBOT_SHADOWFORM = "Forme d'Ombre";
HEALBOT_BARKSKIN = "Peau d'\195\169corce";
HEALBOT_NATURES_GRASP = "Emprise de la nature";
HEALBOT_LIGHTNING_SHIELD = "Bouclier de foudre";
HEALBOT_WATER_SHIELD = "Bouclier d'eau";
HEALBOT_WATER_WALKING = "Marche sur l'eau";
HEALBOT_WATER_BREATHING = "Respiration aquatique";
HEALBOT_RESURRECTION = "R\195\169surrection";
HEALBOT_REDEMPTION = "R\195\169demption";
HEALBOT_REBIRTH = "Renaissance";
@@ -91,6 +145,7 @@ HEALBOT_PURIFY = "Purification";
HEALBOT_CLEANSE = "Epuration";
HEALBOT_CURE_POISON = "Gu\195\169rison du poison";
HEALBOT_REMOVE_CURSE = "D\195\169livrance de la mal\195\169diction";
HEALBOT_REMOVE_LESSER_CURSE= "D\195\169livrance de la mal\195\169diction mineure";
HEALBOT_ABOLISH_POISON = "Abolir le poison";
HEALBOT_CURE_DISEASE = "Gu\195\169rison des maladies";
HEALBOT_ABOLISH_DISEASE = "Abolir maladie";
+54
View File
@@ -54,6 +54,7 @@ if (GetLocale() == "koKR") then
HEALBOT_LESSER_HEALING_WAVE = "하급 치유의 물결";
HEALBOT_MEND_PET = "동물 치료";
HEALBOT_POWER_WORD_SHIELD = "신의 권능: 보호막";
HEALBOT_WEAKENED_SOUL = "신체 취약";
HEALBOT_REGROWTH = "재생";
HEALBOT_RENEW = "소생";
HEALBOT_REJUVENATION = "회복";
@@ -67,6 +68,58 @@ HEALBOT_ENLIGHTEN = "Enlighten";
HEALBOT_MARK_OF_THE_WILD = "야생의 징표";
HEALBOT_GREATER_BLESSING_OF_SALVATION = "상급 구원의 축복";
HEALBOT_BATTLE_SHOUT = "전투의 외침";
HEALBOT_BLOODRAGE = "피의 분노";
HEALBOT_BERSERKER_RAGE = "광전사의 격노";
HEALBOT_DEMON_SKIN = "악마의 피부";
HEALBOT_DEMON_ARMOR = "악마의 갑옷";
HEALBOT_UNENDING_BREATH = "영원의 숨결";
HEALBOT_DETECT_LESSER_INVISIBILITY = "하급 투명체 감지";
HEALBOT_DETECT_INVISIBILITY = "투명체 감지";
HEALBOT_SHADOW_WARD = "암흑계 수호";
HEALBOT_SOULSTONE_RESURRECTION = "영혼석 부활";
HEALBOT_FIRE_SHIELD = "불의 방패";
HEALBOT_TRUESHOT_AURA = "정밀함의 오라";
HEALBOT_ASPECT_OF_THE_HAWK = "매의 상";
HEALBOT_ASPECT_OF_THE_MONKEY = "원숭이의 상";
HEALBOT_ASPECT_OF_THE_CHEETAH = "치타의 상";
HEALBOT_ASPECT_OF_THE_PACK = "치타 무리의 상";
HEALBOT_ASPECT_OF_THE_WILD = "야생의 상";
HEALBOT_ASPECT_OF_THE_BEAST = "야수의 상";
HEALBOT_STEALTH = "은신";
HEALBOT_BLADE_FLURRY = "폭풍의 칼날";
HEALBOT_EVASION = "회피";
HEALBOT_SPRINT = "전력 질주";
HEALBOT_SLICE_AND_DICE = "난도질";
HEALBOT_FROST_ARMOR = "서리 갑옷";
HEALBOT_ICE_ARMOR = "얼음 갑옷";
HEALBOT_MAGE_ARMOR = "마법사 갑옷";
HEALBOT_MANA_SHIELD = "마나 보호막";
HEALBOT_ICE_BARRIER = "얼음 보호막";
HEALBOT_FIRE_WARD = "화염계 수호";
HEALBOT_FROST_WARD = "냉기계 수호";
HEALBOT_GREATER_BLESSING_OF_MIGHT = "상급 힘의 축복";
HEALBOT_GREATER_BLESSING_OF_WISDOM = "상급 지혜의 축복";
HEALBOT_GREATER_BLESSING_OF_KINGS = "상급 왕의 축복";
HEALBOT_GREATER_BLESSING_OF_LIGHT = "상급 빛의 축복";
HEALBOT_GREATER_BLESSING_OF_SANCTUARY = "상급 성역의 축복";
HEALBOT_RIGHTEOUS_FURY = "정의의 격노";
HEALBOT_SHADOWFORM = "어둠의 형상";
HEALBOT_BARKSKIN = "나무 껍질";
HEALBOT_NATURES_GRASP = "자연의 파악";
HEALBOT_LIGHTNING_SHIELD = "번개 보호막";
HEALBOT_WATER_SHIELD = "물의 보호막";
HEALBOT_WATER_WALKING = "수면 보행";
HEALBOT_WATER_BREATHING = "수중 호흡";
HEALBOT_RESURRECTION = "부활";
HEALBOT_REDEMPTION = "구원";
HEALBOT_REBIRTH = "환생";
@@ -76,6 +129,7 @@ HEALBOT_GREATER_BLESSING_OF_SALVATION = "상급 구원의 축복";
HEALBOT_CLEANSE = "정화";
HEALBOT_CURE_POISON = "해독";
HEALBOT_REMOVE_CURSE = "저주 해제";
HEALBOT_REMOVE_LESSER_CURSE = "하급 저주 해제";
HEALBOT_ABOLISH_POISON = "독 해제";
HEALBOT_CURE_DISEASE = "질병 치료";
HEALBOT_ABOLISH_DISEASE = "질병 해제";
+144 -2
View File
@@ -47,7 +47,10 @@ HealBot_Model = {
-- Integration maps
unitGUIDs = {}, -- unit -> GUID
guidUnits = {} -- GUID -> unit
guidUnits = {}, -- GUID -> unit
-- Delayed resolution queue
unresolvedUnits = {}
}
--------------------------------------------------------------------------------
@@ -87,6 +90,7 @@ end
-- HealBot_Model:Initialize: Pre-allocates the unit state dictionary.
function HealBot_Model:Initialize()
for k in pairs(self.unresolvedUnits) do self.unresolvedUnits[k] = nil end
self:InitUnitState("player")
self:InitUnitState("target")
self:InitUnitState("pet")
@@ -149,8 +153,37 @@ function HealBot_Model:UpdateUnitIdentity(unit)
local oldName = self.units[unit].name
local oldEnglishClass = self.units[unit].englishClass
local name = UnitName(unit)
-- If UnitName is not ready, attempt raid roster fallback for raid units
if not name or name == "Unknown" then
local _, _, raidIdx = string.find(unit, "^raid(%d+)$")
if raidIdx and GetNumRaidMembers() > 0 then
local rName = GetRaidRosterInfo(tonumber(raidIdx))
if rName and rName ~= "" and rName ~= "Unknown" then
name = rName
end
end
end
-- If name is still nil, retain oldName if unit exists
if not name and oldName and UnitExists(unit) then
name = oldName
end
local englishClass = HealBot_UnitClass(unit)
-- If name is identical, do NOT overwrite an existing valid englishClass with nil
if oldName and name == oldName and not englishClass and oldEnglishClass then
englishClass = oldEnglishClass
end
-- Track unresolved units (unit exists with a name, but missing englishClass)
if name and not englishClass then
self.unresolvedUnits[unit] = true
else
self.unresolvedUnits[unit] = nil
end
if oldName ~= name or oldEnglishClass ~= englishClass then
self.units[unit].name = name
self.units[unit].englishClass = englishClass
@@ -160,18 +193,127 @@ function HealBot_Model:UpdateUnitIdentity(unit)
local guid = HealBot_GetUnitGUID(unit)
if guid and guid ~= "0" and guid ~= "0x0000000000000000" then
self.unitGUIDs[unit] = guid
if unit ~= "target" then
self.guidUnits[guid] = unit
end
end
end
return true -- Identity changed
end
return false
end
-- HealBot_Model:PopulateAllGUIDs: Refreshes unit-to-GUID and GUID-to-unit mappings for all current roster units.
function HealBot_Model:PopulateAllGUIDs()
if not (HealBot_Integrations_SuperWoW_Active or HealBot_Integrations_ClassicAPI_Active or HealBot_Integrations_Nampower_Active) or not HealBot_GetUnitGUID then return end
if not HealBot_Nampower_NameCache then HealBot_Nampower_NameCache = HealBot_GetTable() end
local playerGuid = HealBot_GetUnitGUID("player")
if playerGuid and playerGuid ~= "0" and playerGuid ~= "0x0000000000000000" then
local lowerPGuid = string.lower(playerGuid)
self.unitGUIDs["player"] = playerGuid
self.guidUnits[playerGuid] = "player"
self.guidUnits[lowerPGuid] = "player"
HealBot_PlayerGUID = playerGuid
local pName = UnitName("player")
if pName then
HealBot_Nampower_NameCache[playerGuid] = pName
HealBot_Nampower_NameCache[lowerPGuid] = pName
end
end
for _, unit in ipairs(self.partyMembers) do
local guid = HealBot_GetUnitGUID(unit)
if guid and guid ~= "0" and guid ~= "0x0000000000000000" then
local lowerGuid = string.lower(guid)
self.unitGUIDs[unit] = guid
self.guidUnits[guid] = unit
self.guidUnits[lowerGuid] = unit
local uName = UnitName(unit)
if uName then
HealBot_Nampower_NameCache[guid] = uName
HealBot_Nampower_NameCache[lowerGuid] = uName
end
end
end
for _, unit in ipairs(self.raidMembers) do
local guid = HealBot_GetUnitGUID(unit)
if guid and guid ~= "0" and guid ~= "0x0000000000000000" then
local lowerGuid = string.lower(guid)
self.unitGUIDs[unit] = guid
self.guidUnits[guid] = unit
self.guidUnits[lowerGuid] = unit
local uName = UnitName(unit)
if uName then
HealBot_Nampower_NameCache[guid] = uName
HealBot_Nampower_NameCache[lowerGuid] = uName
end
end
end
end
-- HealBot_Model:GetUnitByGUID: Internal utility: HealBot_Model:GetUnitByGUID
function HealBot_Model:GetUnitByGUID(guid)
if not guid then return nil end
return self.guidUnits[guid]
local unit = self.guidUnits[guid]
if unit and UnitExists(unit) then return unit end
local lowerGuid = string.lower(guid)
unit = self.guidUnits[lowerGuid]
if unit and UnitExists(unit) then return unit end
if HealBot_PlayerGUID and string.lower(HealBot_PlayerGUID) == lowerGuid then
self.guidUnits[guid] = "player"
self.guidUnits[lowerGuid] = "player"
return "player"
end
if HealBot_GetUnitGUID then
local pGuid = HealBot_GetUnitGUID("player")
if pGuid and string.lower(pGuid) == lowerGuid then
self.guidUnits[guid] = "player"
self.guidUnits[lowerGuid] = "player"
HealBot_PlayerGUID = pGuid
return "player"
end
for i = 1, 40 do
local u = "raid" .. i
if UnitExists(u) then
local uGuid = HealBot_GetUnitGUID(u)
if uGuid and string.lower(uGuid) == lowerGuid then
self.guidUnits[guid] = u
self.guidUnits[lowerGuid] = u
self.unitGUIDs[u] = guid
return u
end
end
end
for i = 1, 4 do
local u = "party" .. i
if UnitExists(u) then
local uGuid = HealBot_GetUnitGUID(u)
if uGuid and string.lower(uGuid) == lowerGuid then
self.guidUnits[guid] = u
self.guidUnits[lowerGuid] = u
self.unitGUIDs[u] = guid
return u
end
end
end
if UnitExists("target") then
local tGuid = HealBot_GetUnitGUID("target")
if tGuid and string.lower(tGuid) == lowerGuid then
return "target"
end
end
if UnitExists("mouseover") then
local moGuid = HealBot_GetUnitGUID("mouseover")
if moGuid and string.lower(moGuid) == lowerGuid then
return "mouseover"
end
end
end
return nil
end
-- HealBot_Model:GetUnitIDByName: Looks up a group unit token by player name.
+5
View File
@@ -111,6 +111,11 @@ function HealBot_Options_SetBuffs()
local val = HealBot_Config.BuffDropDowns[myClass][i] or 0
UIDropDownMenu_Initialize(dropDown, HealBot_Options_Buff_Initialize)
HealBot_UIDropDownMenu_SetSelectedID(dropDown, val + 1)
local text = "None"
if val > 0 and HealBot_Buff_Spells[myClass] and HealBot_Buff_Spells[myClass][val] then
text = HealBot_Buff_Spells[myClass][val]
end
UIDropDownMenu_SetText(text, dropDown)
end
local selfCheck = getglobal("HealBot_Options_Buff" .. i .. "Self")
+44 -14
View File
@@ -168,14 +168,13 @@ end
-- HealBot_Options_CDCButLeft_DropDown: UI handler for DropDown options panel.
function HealBot_Options_CDCButLeft_DropDown()
local classEN=HealBot_UnitClass("player")
if classEN=="PRIEST" or classEN=="DRUID" or classEN=="PALADIN" or classEN=="SHAMAN" then
local class=UnitClass("Player");
local DebuffSpells_List = HealBot_Options_GetDebuffSpells_List(class)
local info = {};
info.text = "None";
info.func = HealBot_Options_CDCButLeft_OnSelect;
UIDropDownMenu_AddButton(info);
local class = UnitClass("Player");
local DebuffSpells_List = HealBot_Options_GetDebuffSpells_List(class);
if DebuffSpells_List then
for i=1, getn(DebuffSpells_List), 1 do
local spell=HealBot_GetSpellName(HealBot_GetSpellId(DebuffSpells_List[i]));
if spell then
@@ -189,14 +188,13 @@ function HealBot_Options_CDCButLeft_DropDown()
end
-- HealBot_Options_CDCButRight_DropDown: UI handler for DropDown options panel.
function HealBot_Options_CDCButRight_DropDown()
local classEN=HealBot_UnitClass("player")
if classEN=="PRIEST" or classEN=="DRUID" or classEN=="PALADIN" or classEN=="SHAMAN" then
local class=UnitClass("Player");
local DebuffSpells_List = HealBot_Options_GetDebuffSpells_List(class)
local info = {};
info.text = "None";
info.func = HealBot_Options_CDCButRight_OnSelect;
UIDropDownMenu_AddButton(info);
local class = UnitClass("Player");
local DebuffSpells_List = HealBot_Options_GetDebuffSpells_List(class);
if DebuffSpells_List then
for i=1, getn(DebuffSpells_List), 1 do
local spell=HealBot_GetSpellName(HealBot_GetSpellId(DebuffSpells_List[i]));
if spell then
@@ -220,17 +218,47 @@ end
function HealBot_Options_CDCButLeft_Refresh(onselect)
local set_id = 1;
local class = UnitClass("Player");
local DebuffSpells_List = HealBot_Options_GetDebuffSpells_List(class);
if not onselect then HealBot_Options_CDCButLeft_Initialize() end
set_id = HealBot_Config.Debuff_Left[class];
HealBot_UIDropDownMenu_SetSelectedID(HealBot_Options_CDCButLeft,set_id)
if DebuffSpells_List and getn(DebuffSpells_List) > 0 then
set_id = HealBot_Config.Debuff_Left[class] or 1;
getglobal("HealBot_Options_CDCButLeftButton"):Enable();
getglobal("HealBot_Options_CDCButLeftText"):SetTextColor(1.0, 1.0, 1.0);
HealBot_UIDropDownMenu_SetSelectedID(HealBot_Options_CDCButLeft, set_id);
if set_id == 1 then
UIDropDownMenu_SetText("None", HealBot_Options_CDCButLeft);
end
else
set_id = 1;
HealBot_Config.Debuff_Left[class] = 1;
HealBot_Config.CDCLeftText[class] = "None";
getglobal("HealBot_Options_CDCButLeftButton"):Disable();
getglobal("HealBot_Options_CDCButLeftText"):SetTextColor(0.5, 0.5, 0.5);
UIDropDownMenu_SetText("None", HealBot_Options_CDCButLeft);
end
end
-- HealBot_Options_CDCButRight_Refresh: UI handler for Refresh options panel.
function HealBot_Options_CDCButRight_Refresh(onselect)
local set_id;
local set_id = 1;
local class = UnitClass("Player");
local DebuffSpells_List = HealBot_Options_GetDebuffSpells_List(class);
if not onselect then HealBot_Options_CDCButRight_Initialize() end
set_id = HealBot_Config.Debuff_Right[class];
HealBot_UIDropDownMenu_SetSelectedID(HealBot_Options_CDCButRight,set_id)
if DebuffSpells_List and getn(DebuffSpells_List) > 0 then
set_id = HealBot_Config.Debuff_Right[class] or 1;
getglobal("HealBot_Options_CDCButRightButton"):Enable();
getglobal("HealBot_Options_CDCButRightText"):SetTextColor(1.0, 1.0, 1.0);
HealBot_UIDropDownMenu_SetSelectedID(HealBot_Options_CDCButRight, set_id);
if set_id == 1 then
UIDropDownMenu_SetText("None", HealBot_Options_CDCButRight);
end
else
set_id = 1;
HealBot_Config.Debuff_Right[class] = 1;
HealBot_Config.CDCRightText[class] = "None";
getglobal("HealBot_Options_CDCButRightButton"):Disable();
getglobal("HealBot_Options_CDCButRightText"):SetTextColor(0.5, 0.5, 0.5);
UIDropDownMenu_SetText("None", HealBot_Options_CDCButRight);
end
end
-- HealBot_Options_CDCButLeft_OnLoad: UI handler for OnLoad options panel.
function HealBot_Options_CDCButLeft_OnLoad()
@@ -275,7 +303,7 @@ end
-- HealBot_Options_Debuff_Reset: Restores default debuff tracking options.
function HealBot_Options_Debuff_Reset()
local classEN=HealBot_UnitClass("player")
if classEN=="PRIEST" or classEN=="DRUID" or classEN=="PALADIN" or classEN=="SHAMAN" then
if classEN=="PRIEST" or classEN=="DRUID" or classEN=="PALADIN" or classEN=="SHAMAN" or classEN=="MAGE" then
HealBot_DebuffWatch = {[HEALBOT_DISEASE_en]=false, [HEALBOT_MAGIC_en]=false, [HEALBOT_POISON_en]=false, [HEALBOT_CURSE_en]=false }
-- Automatically track all curable debuffs out of the box
@@ -292,6 +320,8 @@ function HealBot_Options_Debuff_Reset()
elseif classEN == "SHAMAN" then
HealBot_DebuffWatch[HEALBOT_POISON_en] = true
HealBot_DebuffWatch[HEALBOT_DISEASE_en] = true
elseif classEN == "MAGE" then
HealBot_DebuffWatch[HEALBOT_CURSE_en] = true
end
local spell = HealBot_Config.CDCLeftText[UnitClass("player")];
+130
View File
@@ -1,3 +1,34 @@
-- HealBot_Options_Integrations.lua
local function HealBot_Options_SetDropDownState(frame, enabled)
if not frame then return end
local button = getglobal(frame:GetName() .. "Button")
local text = getglobal(frame:GetName() .. "Text")
if button then
if enabled then
button:Enable()
else
button:Disable()
end
end
if text then
if enabled then
text:SetTextColor(1, 1, 1)
else
text:SetTextColor(0.5, 0.5, 0.5)
end
end
end
-- Update enabled/disabled state of dropdowns based on current config
function HealBot_Options_Integrations_UpdateDropdownStates()
local timersEnabled = HealBot_Config.HealBot_Integrations_ShowHoTTimers == 1
local displayMode = HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0
HealBot_Options_SetDropDownState(HealBot_Options_Integrations_DisplayModeDropdown, timersEnabled)
HealBot_Options_SetDropDownState(HealBot_Options_Integrations_PositionDropdown, timersEnabled and (displayMode == 0 or displayMode == 2))
end
-- HealBot_Options_Integrations_OnShow: UI handler for OnShow options panel.
function HealBot_Options_Integrations_OnShow(this)
HealBot_Options_Integrations_UnitXP:SetChecked(HealBot_Config.HealBot_Integrations_UnitXP);
@@ -5,4 +36,103 @@ function HealBot_Options_Integrations_OnShow(this)
HealBot_Options_Integrations_SuperWoW:SetChecked(HealBot_Config.HealBot_Integrations_SuperWoW);
HealBot_Options_Integrations_ClassicAPI:SetChecked(HealBot_Config.HealBot_Integrations_ClassicAPI);
HealBot_Options_Integrations_ShowHoTTimers:SetChecked(HealBot_Config.HealBot_Integrations_ShowHoTTimers);
-- Set display mode dropdown text
local displayMode = HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0
if displayMode == 1 then
UIDropDownMenu_SetText("Icon Overlay", HealBot_Options_Integrations_DisplayModeDropdown)
elseif displayMode == 2 then
UIDropDownMenu_SetText("Both", HealBot_Options_Integrations_DisplayModeDropdown)
else
UIDropDownMenu_SetText("List", HealBot_Options_Integrations_DisplayModeDropdown)
end
-- Set position dropdown text
local pos = HealBot_Config.HealBot_Integrations_HoTTimerPosition or "BELOW"
local posLabels = { BELOW = "Below", ABOVE = "Above", LEFT = "Left", RIGHT = "Right" }
UIDropDownMenu_SetText(posLabels[pos] or "Below", HealBot_Options_Integrations_PositionDropdown)
-- Update enabled/disabled state
HealBot_Options_Integrations_UpdateDropdownStates()
end
-- Display Mode dropdown click handler (relying on global this)
function HealBot_Options_Integrations_DisplayModeDropdown_OnClick()
UIDropDownMenu_SetSelectedID(HealBot_Options_Integrations_DisplayModeDropdown, this:GetID())
HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode = this.value
UIDropDownMenu_SetText(this:GetText(), HealBot_Options_Integrations_DisplayModeDropdown)
HealBot_Options_Integrations_UpdateDropdownStates()
if HealBot_Action_UnitButtons then
for u in pairs(HealBot_Action_UnitButtons) do
HealBot_View_DirtyUnits[u] = true
end
end
if HealBot_Action_UpdatePlayerHoTs then
HealBot_Action_UpdatePlayerHoTs()
end
end
-- Display Mode dropdown init
function HealBot_Options_Integrations_DisplayModeDropdown_Init()
local mode = HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0
local info
info = {}
info.text = "List"
info.value = 0
info.func = HealBot_Options_Integrations_DisplayModeDropdown_OnClick
if mode == 0 then
info.checked = 1
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Icon Overlay"
info.value = 1
info.func = HealBot_Options_Integrations_DisplayModeDropdown_OnClick
if mode == 1 then
info.checked = 1
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "Both"
info.value = 2
info.func = HealBot_Options_Integrations_DisplayModeDropdown_OnClick
if mode == 2 then
info.checked = 1
end
UIDropDownMenu_AddButton(info)
end
-- Position dropdown click handler (relying on global this)
function HealBot_Options_Integrations_PositionDropdown_OnClick()
UIDropDownMenu_SetSelectedID(HealBot_Options_Integrations_PositionDropdown, this:GetID())
HealBot_Config.HealBot_Integrations_HoTTimerPosition = this.value
UIDropDownMenu_SetText(this:GetText(), HealBot_Options_Integrations_PositionDropdown)
if HealBot_Action_UpdatePlayerHoTs then
HealBot_Action_UpdatePlayerHoTs()
end
end
-- Position dropdown init
function HealBot_Options_Integrations_PositionDropdown_Init()
local positions = {
{ value = "BELOW", label = "Below" },
{ value = "ABOVE", label = "Above" },
{ value = "LEFT", label = "Left" },
{ value = "RIGHT", label = "Right" },
}
local currentPos = HealBot_Config.HealBot_Integrations_HoTTimerPosition or "BELOW"
for _, p in ipairs(positions) do
local info = {}
info.text = p.label
info.value = p.value
info.func = HealBot_Options_Integrations_PositionDropdown_OnClick
if currentPos == p.value then
info.checked = 1
end
UIDropDownMenu_AddButton(info)
end
end
+74 -2
View File
@@ -94,9 +94,81 @@
</OnLoad>
<OnClick>
HealBot_Config.HealBot_Integrations_ShowHoTTimers = this:GetChecked() and 1 or 0;
HealBot_Options_Integrations_UpdateDropdownStates();
if HealBot_Action_UnitButtons then
for u in pairs(HealBot_Action_UnitButtons) do
HealBot_View_DirtyUnits[u] = true;
end
end
if HealBot_Action_UpdatePlayerHoTs then
HealBot_Action_UpdatePlayerHoTs();
end
</OnClick>
</Scripts>
</CheckButton>
<!-- HoT Timer Display Mode Dropdown -->
<Frame name="HealBot_Options_Integrations_DisplayModeDropdown" inherits="UIDropDownMenuTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="HealBot_Options_Integrations_ShowHoTTimers" relativePoint="BOTTOMLEFT">
<Offset>
<AbsDimension x="-15" y="-22"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<FontString name="HealBot_Options_Integrations_DisplayModeLabel" inherits="GameFontHighlightSmall" justifyH="LEFT" text="Timer Display Mode:">
<Anchors>
<Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT">
<Offset>
<AbsDimension x="20" y="2"/>
</Offset>
</Anchor>
</Anchors>
<Color r="1" g="0.82" b="0"/>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>
UIDropDownMenu_SetWidth(120, this);
UIDropDownMenu_Initialize(this, HealBot_Options_Integrations_DisplayModeDropdown_Init);
</OnLoad>
</Scripts>
</Frame>
<!-- HoT Timer Position Dropdown -->
<Frame name="HealBot_Options_Integrations_PositionDropdown" inherits="UIDropDownMenuTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="HealBot_Options_Integrations_DisplayModeDropdown" relativePoint="BOTTOMLEFT">
<Offset>
<AbsDimension x="0" y="-22"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<FontString name="HealBot_Options_Integrations_PositionLabel" inherits="GameFontHighlightSmall" justifyH="LEFT" text="Timer List Position:">
<Anchors>
<Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT">
<Offset>
<AbsDimension x="20" y="2"/>
</Offset>
</Anchor>
</Anchors>
<Color r="1" g="0.82" b="0"/>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>
UIDropDownMenu_SetWidth(120, this);
UIDropDownMenu_Initialize(this, HealBot_Options_Integrations_PositionDropdown_Init);
</OnLoad>
</Scripts>
</Frame>
<Frame setAllPoints="true">
<Layers>
<Layer level="ARTWORK">
@@ -114,9 +186,9 @@
<FontString name="HealBot_Options_Integrations_HoTInfo" inherits="GameFontHighlightSmall" justifyH="LEFT" justifyV="TOP" text="Note: HoT Timers require Nampower to be enabled and active to provide accurate aura times.">
<Size x="340" y="30"/>
<Anchors>
<Anchor point="TOPLEFT" relativeTo="HealBot_Options_Integrations_ShowHoTTimers" relativePoint="BOTTOMLEFT">
<Anchor point="TOPLEFT" relativeTo="HealBot_Options_Integrations_PositionDropdown" relativePoint="BOTTOMLEFT">
<Offset>
<AbsDimension x="20" y="-4"/>
<AbsDimension x="20" y="-6"/>
</Offset>
</Anchor>
</Anchors>
+5
View File
@@ -116,6 +116,11 @@ function HealBot_Options_ComboClass_Text()
HealBot_Options_Shift:SetText(combo["Shift"..button] or "")
HealBot_Options_Ctrl:SetText(combo["Ctrl"..button] or "")
HealBot_Options_ShiftCtrl:SetText(combo["ShiftCtrl"..button] or "")
else
HealBot_Options_Click:SetText("")
HealBot_Options_Shift:SetText("")
HealBot_Options_Ctrl:SetText("")
HealBot_Options_ShiftCtrl:SetText("")
end
end
+338 -109
View File
@@ -69,10 +69,20 @@ function HealBot_HealthColor(unit, hlth, maxhlth)
end
local colorMode = HealBot_Config.bcolormode[HealBot_Config.Current_Skin] or 1
local engClass = nil
if colorMode == 2 and not string.find(unit, "pet") then
engClass = HealBot_Model and HealBot_Model.units[unit] and HealBot_Model.units[unit].englishClass
if not engClass then
engClass = HealBot_UnitClass(unit)
if engClass and HealBot_Model and HealBot_Model.units[unit] then
HealBot_Model.units[unit].englishClass = engClass
end
end
end
if colorMode == 2 and string.find(unit, "pet") then
r, g, b = 0.4, 0.9, 0.6 -- Mint color
elseif colorMode == 2 and HealBot_Model and HealBot_Model.units[unit] and HealBot_Model.units[unit].englishClass and RAID_CLASS_COLORS and RAID_CLASS_COLORS[HealBot_Model.units[unit].englishClass] then
local engClass = HealBot_Model.units[unit].englishClass
elseif colorMode == 2 and engClass and RAID_CLASS_COLORS and RAID_CLASS_COLORS[engClass] then
r = RAID_CLASS_COLORS[engClass].r
g = RAID_CLASS_COLORS[engClass].g
b = RAID_CLASS_COLORS[engClass].b
@@ -265,14 +275,20 @@ function HealBot_Action_EnableButton(button)
bar.txt:SetText(displayText);
bar.txt:SetTextColor(sr, sg, sb, sa);
local fontName, fontHeight, fontFlags = bar.txt:GetFont()
local btextheight = (HealBot_Config.btextheight and HealBot_Config.btextheight[HealBot_Config.Current_Skin]) or 10
local fontHeightToUse = (fontHeight and fontHeight >= 6) and fontHeight or btextheight
local fontOutline = HealBot_Config.bfontoutline[HealBot_Config.Current_Skin] or 0
local expectedFlags = fontOutline == 1 and "OUTLINE" or ""
local expectedFont = (HealBot_Config.bfont and HealBot_Config.bfont[HealBot_Config.Current_Skin]) or fontName
if fontFlags ~= expectedFlags or fontName ~= expectedFont then
bar.txt:SetFont(expectedFont, fontHeight, expectedFlags)
if fontFlags ~= expectedFlags or fontName ~= expectedFont or (fontHeight and fontHeight < 6) then
bar.txt:SetFont(expectedFont, fontHeightToUse, expectedFlags)
end
local iconSize = HealBot_Config.biconsize[HealBot_Config.Current_Skin] or 12
local dMode = HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0
local overlayMode = (HealBot_Config.HealBot_Integrations_ShowHoTTimers == 1) and (dMode == 1 or dMode == 2)
local unitMap = overlayMode and HealBot_ActiveHoTUnitMap and HealBot_ActiveHoTUnitMap[unit]
for i = 1, 10 do
local icon = button["icon"..i]
if not icon then
@@ -280,6 +296,13 @@ function HealBot_Action_EnableButton(button)
button["icon"..i] = icon
end
if icon then
if button["iconText"..i] then
button["iconText"..i]:Hide()
button["iconText"..i] = nil
end
local iconText = bar["iconText"..i]
if HealBot_UnitIcons and HealBot_UnitIcons[unit] and HealBot_UnitIcons[unit][i] then
local currentTexture = icon:GetTexture()
local newTexture = HealBot_UnitIcons[unit][i]
@@ -290,15 +313,54 @@ function HealBot_Action_EnableButton(button)
if icon:GetWidth() ~= iconSize then
icon:SetWidth(iconSize)
icon:SetHeight(iconSize)
if iconText then
iconText:SetFont("Fonts\\ARIALN.TTF", math.min(11, math.max(8, iconSize - 2)), "OUTLINE")
end
end
if not icon:IsVisible() then
icon:Show()
end
if overlayMode then
if not iconText then
local overlayFrame = bar.overlayFrame
if not overlayFrame then
overlayFrame = CreateFrame("Frame", nil, bar)
overlayFrame:SetAllPoints(bar)
overlayFrame:SetFrameLevel(bar:GetFrameLevel() + 5)
bar.overlayFrame = overlayFrame
end
iconText = overlayFrame:CreateFontString(nil, "OVERLAY")
iconText:SetFont("Fonts\\ARIALN.TTF", math.min(11, math.max(8, iconSize - 2)), "OUTLINE")
iconText:SetPoint("CENTER", icon, "CENTER", 0, 0)
iconText:SetTextColor(1, 1, 1, 1)
bar["iconText"..i] = iconText
end
local cleanTex = newTexture and string.lower(string.gsub(newTexture, "/", "\\"))
local shortTex = cleanTex and string.match(cleanTex, "([^\\]+)$")
local timeLeft = unitMap and (unitMap[newTexture] or (cleanTex and unitMap[cleanTex]) or (shortTex and unitMap[shortTex]))
if timeLeft then
if bar.overlayFrame then bar.overlayFrame:Show() end
iconText:SetText(timeLeft)
iconText:Show()
else
if iconText and iconText:IsVisible() then
iconText:SetText("")
iconText:Hide()
end
end
elseif iconText and iconText:IsVisible() then
iconText:SetText("")
iconText:Hide()
end
else
if icon:IsVisible() then
icon:Hide()
end
if iconText and iconText:IsVisible() then
iconText:Hide()
end
end
end
end
@@ -845,14 +907,15 @@ function HealBot_Action_PartyChanged()
if GetNumRaidMembers() > 0 then
for j = 1, 40 do
local unit = "raid" .. j;
local Class = UnitClass(unit);
local ProcessUnit = 0;
local PossibleEmerg = 1;
local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(j);
if not name then name = "not known" end
if not class then class = "not known" end
if not subgroup then subgroup = "not known" end
local Class = UnitClass(unit) or class;
local ProcessUnit = 0;
local PossibleEmerg = 1;
if HealBot_EmergInc[Class] == 1 then
ProcessUnit = 1;
end
@@ -1360,65 +1423,133 @@ end
local HealBot_PlayerHoTsListFrame = nil
local HealBot_PlayerHoTFrames = {}
local HealBot_PlayerHoTs_ValidHoTs = {
["Renew"] = "Interface\\Icons\\Spell_Holy_Renew",
["Rejuvenation"] = "Interface\\Icons\\Spell_Nature_Rejuvenation",
["Regrowth"] = "Interface\\Icons\\Spell_Nature_ResistNature",
["Power Word: Shield"] = "Interface\\Icons\\Spell_Holy_PowerWordShield",
}
local HealBot_PlayerHoTs_ListCache = {}
HealBot_ActiveHoTUnitMap = {} -- unitID -> { [texture] = timeLeft }
local function HealBot_PlayerHoTs_SortComparator(a, b)
return (a.expires or 0) < (b.expires or 0)
end
function HealBot_Action_UpdatePlayerHoTs()
-- Reposition the HoT timer list frame based on config
local function HealBot_HoTTimerList_Reanchor()
if not HealBot_PlayerHoTsListFrame then return end
local pos = HealBot_Config.HealBot_Integrations_HoTTimerPosition or "BELOW"
HealBot_PlayerHoTsListFrame:ClearAllPoints()
if pos == "ABOVE" then
HealBot_PlayerHoTsListFrame:SetPoint("BOTTOMLEFT", HealBot_Action, "TOPLEFT", 0, 2)
elseif pos == "RIGHT" then
HealBot_PlayerHoTsListFrame:SetPoint("TOPLEFT", HealBot_Action, "TOPRIGHT", 2, 0)
elseif pos == "LEFT" then
HealBot_PlayerHoTsListFrame:SetPoint("TOPRIGHT", HealBot_Action, "TOPLEFT", -2, 0)
else -- BELOW (default)
HealBot_PlayerHoTsListFrame:SetPoint("TOPLEFT", HealBot_Action, "BOTTOMLEFT", 0, -2)
end
end
-- Reposition child HoT frames for stacking direction
local function HealBot_HoTTimerList_StackChild(frame, index)
local pos = HealBot_Config.HealBot_Integrations_HoTTimerPosition or "BELOW"
frame:ClearAllPoints()
if pos == "ABOVE" then
if index == 1 then
frame:SetPoint("BOTTOMLEFT", HealBot_PlayerHoTsListFrame, "BOTTOMLEFT", 0, 0)
else
frame:SetPoint("BOTTOMLEFT", HealBot_PlayerHoTFrames[index-1], "TOPLEFT", 0, 2)
end
else
if index == 1 then
frame:SetPoint("TOPLEFT", HealBot_PlayerHoTsListFrame, "TOPLEFT", 0, 0)
else
frame:SetPoint("TOPLEFT", HealBot_PlayerHoTFrames[index-1], "BOTTOMLEFT", 0, -2)
end
end
end
-- Clear all icon overlay timer texts
function HealBot_ClearHoTOverlays()
if not HealBot_Action_UnitButtons then return end
for unit, btnList in pairs(HealBot_Action_UnitButtons) do
for _, button in pairs(btnList) do
local bar = button.bar or getglobal(button:GetName() .. "Bar")
if bar then
for i = 1, 10 do
local iconText = bar["iconText"..i]
if iconText and iconText:IsVisible() then
iconText:SetText("")
iconText:Hide()
end
end
end
end
end
end
-- Render countdown numbers directly on unit bar icons
function HealBot_RenderHoTOverlays()
if not HealBot_Action_UnitButtons then return end
local iconSize = HealBot_Config.biconsize[HealBot_Config.Current_Skin] or 12
local fontSize = math.min(11, math.max(8, iconSize - 2))
for unit, btnList in pairs(HealBot_Action_UnitButtons) do
local unitMap = HealBot_ActiveHoTUnitMap[unit]
for _, button in pairs(btnList) do
local bar = HealBot_Action_HealthBar(button)
if bar and bar:IsVisible() then
for i = 1, 10 do
local icon = button["icon"..i] or getglobal(button:GetName() .. "BarIcon" .. i)
local iconText = bar["iconText"..i]
if icon and icon:IsVisible() then
local tex = icon:GetTexture()
local cleanTex = tex and string.lower(string.gsub(tex, "/", "\\"))
local shortTex = cleanTex and string.match(cleanTex, "([^\\]+)$")
local timeLeft = unitMap and (unitMap[tex] or (cleanTex and unitMap[cleanTex]) or (shortTex and unitMap[shortTex]))
if timeLeft then
if not iconText then
local overlayFrame = bar.overlayFrame
if not overlayFrame then
overlayFrame = CreateFrame("Frame", nil, bar)
overlayFrame:SetAllPoints(bar)
overlayFrame:SetFrameLevel(bar:GetFrameLevel() + 5)
bar.overlayFrame = overlayFrame
end
iconText = overlayFrame:CreateFontString(nil, "OVERLAY")
iconText:SetFont("Fonts\\ARIALN.TTF", fontSize, "OUTLINE")
iconText:SetPoint("CENTER", icon, "CENTER", 0, 0)
iconText:SetTextColor(1, 1, 1, 1)
bar["iconText"..i] = iconText
end
if bar.overlayFrame then bar.overlayFrame:Show() end
iconText:SetText(timeLeft)
iconText:Show()
else
if iconText and iconText:IsVisible() then
iconText:SetText("")
iconText:Hide()
end
end
else
if iconText and iconText:IsVisible() then
iconText:Hide()
end
end
end
end
end
end
end
-- Render HoT timer list
local function HealBot_RenderHoTList(numHoTs, currentTime)
if not HealBot_PlayerHoTsListFrame then
HealBot_PlayerHoTsListFrame = CreateFrame("Frame", "HealBot_PlayerHoTsListFrame", HealBot_Action)
HealBot_PlayerHoTsListFrame:SetWidth(128)
HealBot_PlayerHoTsListFrame:SetHeight(1)
HealBot_PlayerHoTsListFrame:SetPoint("TOPLEFT", HealBot_Action, "BOTTOMLEFT", 0, -2)
end
HealBot_HoTTimerList_Reanchor()
HealBot_PlayerHoTsListFrame:Show()
end
if HealBot_Config.HealBot_Integrations_ShowHoTTimers ~= 1 then
HealBot_PlayerHoTsListFrame:Hide()
return
else
HealBot_PlayerHoTsListFrame:Show()
end
local currentTime = GetTime()
-- Clear cache instead of reallocating
local numHoTs = 0
if HealBot_Integrations_Nampower_Active and HealBot_Nampower_Auras then
for targetName, auras in pairs(HealBot_Nampower_Auras) do
for spellName, expiration in pairs(auras) do
if HealBot_PlayerHoTs_ValidHoTs[spellName] then
if expiration > currentTime then
numHoTs = numHoTs + 1
if not HealBot_PlayerHoTs_ListCache[numHoTs] then
HealBot_PlayerHoTs_ListCache[numHoTs] = {}
end
HealBot_PlayerHoTs_ListCache[numHoTs].name = targetName
HealBot_PlayerHoTs_ListCache[numHoTs].spell = spellName
HealBot_PlayerHoTs_ListCache[numHoTs].expires = expiration
end
end
end
end
end
-- Blank out remaining cache entries so sort doesn't read them
for i = numHoTs + 1, table.getn(HealBot_PlayerHoTs_ListCache) do
HealBot_PlayerHoTs_ListCache[i].expires = 9999999999
end
-- Sort only the active portion by shifting expired ones to the end
-- Sort active HoTs by expiration
table.sort(HealBot_PlayerHoTs_ListCache, HealBot_PlayerHoTs_SortComparator)
for i = 1, math.max(numHoTs, table.getn(HealBot_PlayerHoTFrames)) do
@@ -1428,11 +1559,6 @@ function HealBot_Action_UpdatePlayerHoTs()
frame = CreateFrame("Frame", "HealBot_PlayerHoT" .. i, HealBot_PlayerHoTsListFrame)
frame:SetWidth(128)
frame:SetHeight(16)
if i == 1 then
frame:SetPoint("TOPLEFT", HealBot_PlayerHoTsListFrame, "TOPLEFT", 0, 0)
else
frame:SetPoint("TOPLEFT", HealBot_PlayerHoTFrames[i-1], "BOTTOMLEFT", 0, -2)
end
local icon = frame:CreateTexture(nil, "ARTWORK")
icon:SetWidth(14)
@@ -1448,58 +1574,13 @@ function HealBot_Action_UpdatePlayerHoTs()
HealBot_PlayerHoTFrames[i] = frame
end
HealBot_HoTTimerList_StackChild(frame, i)
local hot = HealBot_PlayerHoTs_ListCache[i]
local timeLeft = math.floor(hot.expires - currentTime)
local timeLeft = hot.timeLeft or math.floor(hot.expires - currentTime)
-- Resolve GUID to Name
if not HealBot_Nampower_NameCache then HealBot_Nampower_NameCache = HealBot_GetTable() end
local dispName = HealBot_Nampower_NameCache[hot.name]
if not dispName then
dispName = hot.name
local resolved = false
local unitID = HealBot_Model:GetUnitByGUID(hot.name) or HealBot_Model:GetUnitIDByName(hot.name)
if unitID then
local n = UnitName(unitID)
if n then
dispName = n
resolved = true
end
elseif string.sub(hot.name, 1, 2) == "0x" or string.sub(hot.name, 1, 2) == "0X" then
if HealBot_PlayerGUID and string.lower(HealBot_PlayerGUID) == string.lower(hot.name) then
dispName = UnitName("player") or "Player"
resolved = true
elseif HealBot_GetUnitGUID then
if string.lower(HealBot_GetUnitGUID("player") or "") == string.lower(hot.name) then
dispName = UnitName("player") or "Player"
resolved = true
elseif string.lower(HealBot_GetUnitGUID("target") or "") == string.lower(hot.name) then
dispName = UnitName("target") or "Target"
resolved = true
elseif string.lower(HealBot_GetUnitGUID("mouseover") or "") == string.lower(hot.name) then
dispName = UnitName("mouseover") or "Mouseover"
resolved = true
end
end
end
if resolved then
HealBot_Nampower_NameCache[hot.name] = dispName
elseif string.sub(hot.name, 1, 2) == "0x" then
dispName = "Unknown"
end
end
local spellId = HealBot_GetSpellId and HealBot_GetSpellId(hot.spell) or nil
local tex = HealBot_PlayerHoTs_ValidHoTs[hot.spell] or "Interface\\Icons\\INV_Misc_QuestionMark"
if spellId then
tex = GetSpellTexture(spellId, "BOOKTYPE_SPELL") or tex
end
frame.icon:SetTexture(tex)
frame.text:SetText(dispName .. ": " .. timeLeft .. "s")
frame.icon:SetTexture(hot.texture)
frame.text:SetText(hot.name .. ": " .. timeLeft .. "s")
frame.text:SetTextColor(0.8, 1, 0.8)
frame:Show()
else
@@ -1511,3 +1592,151 @@ function HealBot_Action_UpdatePlayerHoTs()
HealBot_PlayerHoTsListFrame:SetHeight(math.max(1, numHoTs * 18))
end
-- Unified HoT Timer Pipeline
function HealBot_UpdateActiveHoTTimers()
if HealBot_Config.HealBot_Integrations_ShowHoTTimers ~= 1 then
if HealBot_PlayerHoTsListFrame and HealBot_PlayerHoTsListFrame:IsVisible() then
HealBot_PlayerHoTsListFrame:Hide()
end
HealBot_ClearHoTOverlays()
return
end
local currentTime = GetTime()
local numHoTs = 0
-- Clear unit map (recycle)
for _, sub in pairs(HealBot_ActiveHoTUnitMap) do
for k in pairs(sub) do sub[k] = nil end
end
if HealBot_Integrations_Nampower_Active and HealBot_Nampower_Auras then
for targetKey, auras in pairs(HealBot_Nampower_Auras) do
local lowerKey = string.lower(targetKey)
local unitID = HealBot_Model and (HealBot_Model:GetUnitByGUID(targetKey) or HealBot_Model:GetUnitByGUID(lowerKey))
if not unitID then
local isPlayer = (HealBot_PlayerGUID and (targetKey == HealBot_PlayerGUID or lowerKey == string.lower(HealBot_PlayerGUID)))
or (UnitName("player") and (targetKey == UnitName("player") or lowerKey == string.lower(UnitName("player"))))
or (HealBot_GetUnitGUID and (targetKey == HealBot_GetUnitGUID("player") or lowerKey == string.lower(HealBot_GetUnitGUID("player") or "")))
if isPlayer then
unitID = "player"
end
end
if not unitID and HealBot_Model and HealBot_Model.GetUnitIDByName then
unitID = HealBot_Model:GetUnitIDByName(targetKey)
end
-- Multi-tier player name resolution
local displayName = nil
if unitID and unitID ~= "target" then
if HealBot_Model and HealBot_Model.units[unitID] and HealBot_Model.units[unitID].name then
displayName = HealBot_Model.units[unitID].name
end
if not displayName then
displayName = UnitName(unitID)
end
end
if not displayName and HealBot_Nampower_NameCache then
displayName = HealBot_Nampower_NameCache[targetKey] or HealBot_Nampower_NameCache[lowerKey]
end
if not displayName and UnitExists("target") and HealBot_GetUnitGUID and (targetKey == HealBot_GetUnitGUID("target") or lowerKey == string.lower(HealBot_GetUnitGUID("target") or "")) then
displayName = UnitName("target")
end
if not displayName and UnitExists("mouseover") and HealBot_GetUnitGUID and (targetKey == HealBot_GetUnitGUID("mouseover") or lowerKey == string.lower(HealBot_GetUnitGUID("mouseover") or "")) then
displayName = UnitName("mouseover")
end
if not displayName then
local uName = UnitName(targetKey)
if uName and uName ~= targetKey and uName ~= "Unknown" then
displayName = uName
end
end
if displayName and HealBot_Nampower_NameCache then
HealBot_Nampower_NameCache[targetKey] = displayName
HealBot_Nampower_NameCache[lowerKey] = displayName
end
-- Exclude pets
if not (unitID and string.find(unitID, "pet")) then
for spellName, expiration in pairs(auras) do
local auraInfo = HealBot_TrackedAura_Spells and HealBot_TrackedAura_Spells[spellName]
if not auraInfo and HealBot_TrackedAuras and HealBot_TrackedAuras[spellName] then
auraInfo = HealBot_TrackedAuras[spellName]
end
if auraInfo and auraInfo.showTimer and expiration > currentTime then
local timeLeft = math.floor(expiration - currentTime)
local tex = auraInfo.texture or "Interface\\Icons\\INV_Misc_QuestionMark"
numHoTs = numHoTs + 1
if not HealBot_PlayerHoTs_ListCache[numHoTs] then
HealBot_PlayerHoTs_ListCache[numHoTs] = {}
end
local hot = HealBot_PlayerHoTs_ListCache[numHoTs]
hot.unit = unitID
hot.name = displayName or "Unknown"
hot.spell = spellName
hot.texture = tex
hot.expires = expiration
hot.timeLeft = timeLeft
if unitID then
if not HealBot_ActiveHoTUnitMap[unitID] then
HealBot_ActiveHoTUnitMap[unitID] = {}
end
local cleanTex = string.lower(string.gsub(tex, "/", "\\"))
local shortTex = string.match(cleanTex, "([^\\]+)$")
HealBot_ActiveHoTUnitMap[unitID][tex] = timeLeft
HealBot_ActiveHoTUnitMap[unitID][cleanTex] = timeLeft
if shortTex then
HealBot_ActiveHoTUnitMap[unitID][shortTex] = timeLeft
end
-- If player in raid, map under raid token button as well
if unitID == "player" and HealBot_Action_UnitButtons then
for btnUnit in pairs(HealBot_Action_UnitButtons) do
if btnUnit ~= "player" and UnitIsUnit(btnUnit, "player") then
if not HealBot_ActiveHoTUnitMap[btnUnit] then
HealBot_ActiveHoTUnitMap[btnUnit] = {}
end
HealBot_ActiveHoTUnitMap[btnUnit][tex] = timeLeft
HealBot_ActiveHoTUnitMap[btnUnit][cleanTex] = timeLeft
if shortTex then
HealBot_ActiveHoTUnitMap[btnUnit][shortTex] = timeLeft
end
end
end
end
end
end
end
end
end
end
-- Blank out remaining cache entries so sort doesn't read them
for i = numHoTs + 1, table.getn(HealBot_PlayerHoTs_ListCache) do
HealBot_PlayerHoTs_ListCache[i].expires = 9999999999
end
local displayMode = HealBot_Config.HealBot_Integrations_HoTTimerDisplayMode or 0
if displayMode == 0 then
-- List Mode
HealBot_ClearHoTOverlays()
HealBot_RenderHoTList(numHoTs, currentTime)
elseif displayMode == 1 then
-- Overlay Mode
if HealBot_PlayerHoTsListFrame and HealBot_PlayerHoTsListFrame:IsVisible() then
HealBot_PlayerHoTsListFrame:Hide()
end
HealBot_RenderHoTOverlays()
else
-- Both Mode (2)
HealBot_RenderHoTList(numHoTs, currentTime)
HealBot_RenderHoTOverlays()
end
end
HealBot_Action_UpdatePlayerHoTs = HealBot_UpdateActiveHoTTimers
+15
View File
@@ -50,6 +50,19 @@ Default installation path: `C:\Program Files\World of Warcraft\Interface\AddOns\
### Change Log
**v1.7.7**
* **Feature - HoT Timer Display Modes & Positioning:** Added configurable HoT timer list position dropdown (`Below`, `Above`, `Left`, `Right`) relative to raid frames. Added `Icon Overlay` mode rendering countdown timers directly on health bar HoT icons, and a `Both` mode allowing simultaneous timer list and on-bar icon countdown numbers. Excluded pets from HoT timer lists and overlays. Optimized expiration lookups with O(1) texture-to-spell mappings.
* **Refactor & Feature - Unified Aura & HoT Tracking:** Unified bar icons and HoT timers into a master dictionary (`HealBot_TrackedAuras`) in `HealBot_Data.lua`. Added Weakened Soul, Fear Ward, Abolish Disease, and Abolish Poison to active timer bars with localized client support and debuff-aware pruning.
* **Bug Fix - HoT Tracking Premature Deletion & GUID Resolution:** Resolved issue where synchronous aura scans on spell cast prematurely purged active HoTs before server buff packets arrived. Fixed HoT timer list showing raw GUID strings instead of names by ensuring GUID caches populate immediately on `PLAYER_ENTERING_WORLD` (even when solo) and adding multi-tier name resolution fallbacks. Fixed unit bar icon countdown numbers not rendering by adding explicit overlay frame show triggers and normalized texture lookup fallbacks.
**v1.7.6**
* **Feature - All-Class Support & Raid Frame Replacement:** Removed legacy restriction that disabled HealBot event listeners and UI frames for classes without native healing spells. HealBot now initializes and functions as a full party/raid frame replacement for all classes (Warrior, Mage, Rogue, Hunter, Warlock).
* **Targeting & Binding Defaults:** Added default `Left` click `"Target"` binding for non-healer classes, recognized `"target"` in spell resolution, and prevented non-healer buttons from disabling on full-health allies.
* **Mage Decurse Support:** Integrated `Remove Lesser Curse` into Mage debuff tables and Cure/Dispel (CDC) options.
* **Bug Fix - Spellbook Scan Lua Error:** Initialized `RealHealing` in spell scanner, resolving `attempt to concatenate global 'RealHealing' (a nil value)` when opening the spellbook on non-healer classes.
* **UI Fix - Cure Dropdown Stale Text:** Unconditionally added "None" entry and disabled curing button dropdowns for classes without decurse/cleanse abilities, fixing stale dropdown text ("Melee") displaying on Warrior and other non-dispelling classes.
* **Feature - Class Buff Tracking:** Added buff tracking lists, bidirectional group/rank equivalents (Greater Blessings, armors, etc.), and self-only auto-filtering for all classes. Added Water Shield for Shaman and refreshed buff dropdown labels to eliminate stale UI cache text.
**v1.7.5**
* **Feature - Test Bars** - Implemented a "Test Bars" button and slider in the Skins options tab, allowing you to spawn and adjust a dummy raid group of up to 40 members without being in a real raid. This allows for easy layout and appearance customization out of combat.
* **UI - Skins Options & Custom Health Gradients** - Added configurable Max HP and Min HP colour pickers with descriptive labels for custom gradient support. Fixed colour picker button click interceptors and hooked ColorPickerFrame callbacks. Integrated global font selector across raid frame text, headers, Options button, and preview bars. Reorganized Skins tab layout to anchor Test Bars cleanly in Column 2.
@@ -102,6 +115,8 @@ Default installation path: `C:\Program Files\World of Warcraft\Interface\AddOns\
* **Feature - Shapeshift Spell Queue** - Built a native spell queue system for Druid auto-unshifting. Bypasses the "Cannot cast while shapeshifted" error and server lag when AutoUnshift is enabled, firing the heal seamlessly the exact millisecond the form is dropped. Now completely unified to use the standard casting API for maximum reliability across all client setups.
* **Bug Fix - CDC Config List** - Fixed an uninitialized dropdown list array that prevented the CDC class monitor configuration from saving correctly.
* **Bug Fix - Color Picker Accuracy** - Removed an undocumented multiplier hack on default textures that was artificially brightening debuff bar colors and overriding the user's selected colors from the color picker.
* **Bug Fix - Raid Self-Range & Transparency** - Fixed player health bar appearing transparent in raid instances by checking `UnitIsUnit(unit, "player")` in range detection, preventing false out-of-range failures when player is represented by a `raidX` token.
* **Bug Fix - Raid Class Coloring & Identity Cache** - Fixed missing and delayed raid class colors by querying authoritative server data (`GetRaidRosterInfo`) for raid members, preventing model identity cache wipes, adding a throttled resolution retry in `OnUpdate`, and providing on-demand class color fallbacks in `HealBot_HealthColor`.
**v1.6.5**
* **Performance Update - Mana Tracking** - Added a fast-path redraw pipeline for unit power changes. This optimization prevents full frame redraws when players naturally regenerate or consume mana, resolving severe FPS drops in 40-man raids while tracking mana.