mirror of
https://github.com/Bluewhale1337/HealBotBlue.git
synced 2026-09-10 09:20:21 +00:00
refactor: implement reliable shapeshift unshifting with a queued cast system and Nampower integration settings
This commit is contained in:
@@ -78,33 +78,75 @@ function HealBot_OnUpdate(this, arg1)
|
||||
end
|
||||
|
||||
if HealBot_PendingShapeshiftCast then
|
||||
if GetTime() > HealBot_PendingShapeshiftCast.expires then
|
||||
HealBot_PendingShapeshiftCast = nil
|
||||
else
|
||||
-- Only cast once the form has successfully been removed
|
||||
local currentForm = HealBot_GetShapeshiftForm()
|
||||
if not currentForm then
|
||||
local pendingCast = HealBot_PendingShapeshiftCast
|
||||
HealBot_PendingShapeshiftCast = nil
|
||||
|
||||
local pendingCast = HealBot_PendingShapeshiftCast
|
||||
|
||||
-- Wait for server to process the unshift before attempting the cast
|
||||
if GetTime() >= pendingCast.fireTime then
|
||||
if not HealBot_GetShapeshiftForm() then
|
||||
-- Target the unit if necessary before casting
|
||||
-- Target the unit if necessary before casting
|
||||
if pendingCast.oldTarget ~= UnitName(pendingCast.target) then
|
||||
TargetUnit(pendingCast.target)
|
||||
end
|
||||
|
||||
-- Attempt the cast now that form is cleared
|
||||
HealBot_StartCasting(pendingCast.spell, pendingCast.target, "direct")
|
||||
|
||||
if pendingCast.targetEnemy then
|
||||
HealBot_TargetRestorePending = { type = "enemy" }
|
||||
elseif pendingCast.oldTarget and pendingCast.oldTarget ~= UnitName(pendingCast.target) then
|
||||
HealBot_TargetRestorePending = { type = "friend" }
|
||||
elseif not pendingCast.oldTarget then
|
||||
HealBot_TargetRestorePending = { type = "clear" }
|
||||
-- 1. Initialize the MVC side effects (AnnounceCast, Incoming Heals) only ONCE
|
||||
if not pendingCast.started then
|
||||
pendingCast.started = true
|
||||
|
||||
-- Extract base spell
|
||||
local baseSpell = pendingCast.spell
|
||||
local parenIndex = string.find(pendingCast.spell, "%(")
|
||||
if parenIndex then
|
||||
baseSpell = string.sub(pendingCast.spell, 1, parenIndex - 1)
|
||||
end
|
||||
baseSpell = string.gsub(baseSpell, "%s+$", "")
|
||||
|
||||
-- Force MVC updates since we guarantee the cast will eventually pierce the server
|
||||
HealBot_CastFailed = false
|
||||
HealBot_CastingSpell = baseSpell
|
||||
HealBot_CastingTarget = pendingCast.target
|
||||
HealBot_Process_HealValue(baseSpell, pendingCast.target)
|
||||
HealBot_AnnounceCast(pendingCast.spell, pendingCast.target)
|
||||
|
||||
-- Restore target logic
|
||||
if pendingCast.targetEnemy then
|
||||
HealBot_TargetRestorePending = { type = "enemy" }
|
||||
elseif pendingCast.oldTarget and pendingCast.oldTarget ~= UnitName(pendingCast.target) then
|
||||
HealBot_TargetRestorePending = { type = "friend" }
|
||||
elseif not pendingCast.oldTarget then
|
||||
HealBot_TargetRestorePending = { type = "clear" }
|
||||
end
|
||||
HealBot_TargetRestoreTimer = 0
|
||||
end
|
||||
|
||||
-- 2. Spam the raw cast silently to guarantee it pierces the server delay
|
||||
if pendingCast.started then
|
||||
if not pendingCast.nextSpam or GetTime() >= pendingCast.nextSpam then
|
||||
pendingCast.nextSpam = GetTime() + 0.15
|
||||
|
||||
-- Safely suppress UI errors
|
||||
UIErrorsFrame:UnregisterEvent("UI_ERROR_MESSAGE")
|
||||
|
||||
-- Only use HealBot's native cast wrapper
|
||||
HealBot_CastSpellByName(pendingCast.spell)
|
||||
|
||||
if SpellCanTargetUnit(pendingCast.target) then
|
||||
SpellTargetUnit(pendingCast.target)
|
||||
elseif SpellIsTargeting() then
|
||||
SpellTargetUnit(pendingCast.target)
|
||||
SpellStopTargeting()
|
||||
end
|
||||
|
||||
UIErrorsFrame:RegisterEvent("UI_ERROR_MESSAGE")
|
||||
end
|
||||
end
|
||||
HealBot_TargetRestoreTimer = 0
|
||||
end
|
||||
end
|
||||
|
||||
-- Failsafe timeout
|
||||
if HealBot_PendingShapeshiftCast and GetTime() > pendingCast.expires then
|
||||
HealBot_PendingShapeshiftCast = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Process Dirty Queue for MVC View
|
||||
@@ -524,6 +566,7 @@ end
|
||||
-- HealBot_OnEvent_SpellcastStart: Internal utility: HealBot_OnEvent_SpellcastStart
|
||||
function HealBot_OnEvent_SpellcastStart(this, spell, duration)
|
||||
HealBot_IsCasting = true;
|
||||
HealBot_PendingShapeshiftCast = nil;
|
||||
HealBot_RecalcHeals();
|
||||
HealBot_CheckCasting();
|
||||
if spell == HEALBOT_RESURRECTION or spell == HEALBOT_ANCESTRALSPIRIT or spell == HEALBOT_REBIRTH or spell == HEALBOT_REDEMPTION then
|
||||
@@ -537,6 +580,7 @@ end
|
||||
-- HealBot_OnEvent_SpellcastStop: Internal utility: HealBot_OnEvent_SpellcastStop
|
||||
function HealBot_OnEvent_SpellcastStop(this, eventName)
|
||||
HealBot_IsCasting = false;
|
||||
HealBot_PendingShapeshiftCast = nil;
|
||||
if eventName == "SPELLCAST_FAILED" then
|
||||
HealBot_CastFailed = true;
|
||||
end
|
||||
|
||||
@@ -171,6 +171,19 @@ end
|
||||
-- HealBot_StartCasting: Initiates spell cast and broadcasts incoming heal.
|
||||
function HealBot_StartCasting(spell, target, ttype)
|
||||
HealBot_CastFailed = false;
|
||||
|
||||
-- Extract base spell for internal tracking
|
||||
local baseSpell = spell
|
||||
local parenIndex = string.find(spell, " %(")
|
||||
if parenIndex then
|
||||
baseSpell = string.sub(spell, 1, parenIndex - 1)
|
||||
else
|
||||
parenIndex = string.find(spell, "%(")
|
||||
if parenIndex then
|
||||
baseSpell = string.sub(spell, 1, parenIndex - 1)
|
||||
end
|
||||
end
|
||||
|
||||
HealBot_CastSpellByName(spell);
|
||||
if ( SpellCanTargetUnit(target) ) then
|
||||
SpellTargetUnit(target);
|
||||
@@ -184,14 +197,16 @@ function HealBot_StartCasting(spell, target, ttype)
|
||||
end
|
||||
end
|
||||
|
||||
if ttype == "fired" and HealBot_Spells[spell] then
|
||||
if ttype == "fired" and HealBot_Spells[baseSpell] then
|
||||
if not HealBot_CastFailed then
|
||||
HealBot_CastingSpell = spell;
|
||||
HealBot_CastingSpell = baseSpell;
|
||||
HealBot_CastingTarget = target;
|
||||
HealBot_Process_HealValue(spell, target);
|
||||
HealBot_Process_HealValue(baseSpell, target);
|
||||
HealBot_AnnounceCast(spell, target);
|
||||
end
|
||||
end
|
||||
|
||||
return ttype == "fired"
|
||||
end
|
||||
|
||||
-- HealBot_StopCasting: Internal utility: HealBot_StopCasting
|
||||
@@ -308,7 +323,9 @@ function HealBot_CastSpellOnFriend(spell, target)
|
||||
end
|
||||
|
||||
if formCancelled then
|
||||
HealBot_PendingShapeshiftCast = { spell = spell, target = target, targetEnemy = targetEnemy, oldTarget = oldTarget, expires = GetTime() + 1.0 }
|
||||
-- ALWAYS put the cast into the Pending queue so the OnUpdate loop can wait for the server
|
||||
-- to process the unshift before attempting the cast, otherwise we get "You are in shapeshift form".
|
||||
HealBot_PendingShapeshiftCast = { spell = spell, target = target, targetEnemy = targetEnemy, oldTarget = oldTarget, fireTime = GetTime() + 0.05, expires = GetTime() + 1.0 }
|
||||
return;
|
||||
end
|
||||
|
||||
@@ -839,9 +856,9 @@ function HealBot_Generic_Patten(matchStr, matchPattern)
|
||||
return tmpTest, _HealsMin, _HealsMax;
|
||||
end
|
||||
|
||||
-- HealBot_UpdateShapeshiftForm: Internal utility: HealBot_UpdateShapeshiftForm
|
||||
-- HealBot_UpdateShapeshiftForm: Called on UPDATE_SHAPESHIFT_FORM
|
||||
function HealBot_UpdateShapeshiftForm()
|
||||
-- Deprecated, state is pulled in real-time on cast
|
||||
-- Deprecated
|
||||
end
|
||||
|
||||
-- HealBot_GetShapeshiftForm: Detects active druid form to prevent invalid casts.
|
||||
@@ -852,10 +869,7 @@ function HealBot_GetShapeshiftForm()
|
||||
for i=1,forms do
|
||||
local icon,name,active = GetShapeshiftFormInfo(i);
|
||||
if active then
|
||||
local icon_lower = string.lower(icon);
|
||||
if not string.find(icon_lower, "humanoidform") and not string.find(icon_lower, "treeoflife") and not string.find(icon_lower, "stoneclawtotem") then
|
||||
return i;
|
||||
end
|
||||
return i;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+2
-1
@@ -27,8 +27,9 @@ HealBot_ConfigDefaults = {
|
||||
ActionVisible = 1,
|
||||
HideSolo = 0,
|
||||
OverHeal = 0.25,
|
||||
CastNotify = 1,
|
||||
UpdateFreq = 0.5,
|
||||
AutoUnshift = 1,
|
||||
Integrations_Nampower_Active = true,
|
||||
ChatMessages = {
|
||||
[1] = { Spell = "None", Message = "Casting #Spell# on #Target#", Channel = "None" },
|
||||
[2] = { Spell = "None", Message = "Casting #Spell# on #Target#", Channel = "None" },
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
getglobal(this:GetName().."Text"):SetText("Enable nampower Integration (Buffs/Heals)");
|
||||
getglobal(this:GetName().."Text"):SetText("Enable nampower Integration (Buffs/Heals/Queueing)");
|
||||
</OnLoad>
|
||||
<OnClick>
|
||||
HealBot_Config.HealBot_Integrations_Nampower = this:GetChecked() and 1 or 0;
|
||||
@@ -44,9 +44,9 @@
|
||||
|
||||
<CheckButton name="HealBot_Options_Integrations_SuperWoW" inherits="OptionsCheckButtonTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativeTo="HealBot_Options_Integrations_Nampower" relativePoint="BOTTOMLEFT">
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="5"/>
|
||||
<AbsDimension x="31" y="-145"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
@@ -81,6 +81,21 @@
|
||||
</CheckButton>
|
||||
|
||||
</Frames>
|
||||
<Layers>
|
||||
<Layer level="ARTWORK">
|
||||
<FontString name="HealBot_Options_Integrations_NampowerInfo" inherits="GameFontHighlightSmall" justifyH="LEFT" justifyV="TOP" text="Note: For the 1-click Shapeshift auto-unshift to work smoothly, you must DISABLE 'Retry server rejected spells' in Nampower ENABLE Queue Instant Cast Spells and Queue Cast Time Spells.">
|
||||
<Size x="330" y="30"/>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="65" y="-95"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Color r="0.7" g="0.7" b="0.7"/>
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Scripts>
|
||||
<OnShow>
|
||||
HealBot_Options_Integrations_OnShow(this);
|
||||
|
||||
@@ -59,6 +59,8 @@ Default installation path: `C:\Program Files\World of Warcraft\Interface\AddOns\
|
||||
* **Bug Fix - Slow Client Init** - Fixed missing class colors after `/reload` by adding lazy-load identity fetches directly into the render pipeline for when `UnitClass` data is delayed by the server.
|
||||
* **Bug Fix - Debuff Tracking** - HealBot now automatically tracks all curable debuffs for the player's class out of the box. Previously, users had to manually assign a cure spell to a click binding to enable CDC debuff tracking.
|
||||
* **Bug Fix - CDC Filter** - Fixed an issue where the CDC module displayed all debuffs instead of filtering for dispellable ones, restoring proper health bar coloring.
|
||||
* **Bug Fix - UnitClass Localization** - Added a fallback mapping for the Vanilla `UnitClass` API to always return the uppercase English class string. This fixes a bug where default options (like Debuff tracking) failed to initialize.
|
||||
* **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.
|
||||
|
||||
**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.
|
||||
|
||||
Reference in New Issue
Block a user