i think its better to bring more informations here..
that what i try is do deactivate the script if i can cast Manatite (restro) or Totemic Wrath (ele)
there is still an check / update if a player change his skilltree but i don't find the right lua to manage it
Code:
--
-- ShamWow_Enhance
ShamWow_Enhance = LibStub( "AceAddon-3.0" ):NewAddon( "ShamWow_Enhance", "AceConsole-3.0", "AceEvent-3.0" );
local media = LibStub:GetLibrary("LibSharedMedia-3.0");
local mainFrame, cooldownFrame, cooldownFrame1, cooldownFrame2, target, timeText;
local ENHANCE_MODE = 1;
local mode = 0;
local lastFlameShockCast = 0;
local TEXT = "Melee Addon nicht aktiv"
local TEXT = "Melee Addon aktiv"
local function swPrint(s)
DEFAULT_CHAT_FRAME:AddMessage("ShamWow_Enhance: ".. tostring(s));
end
-- spell info
local stormstrikeId = 17364;
local lavalashId = 60103;
local earthshockId = 8042;
local maelstromId = 51530;
local windfuryId = 8232;
local flametongueId = 8024;
local lightningBoltId = 403;
local clearcastId = 16246;
local lightningshieldId = 324;
local shamanisticRageId = 30823;
local sengendeflammenId = 77657;
local feralSpiritId = 51533;
local unleashelementsId = 73680;
local naturesSwiftnessId = 17116;
local flameshockId = 8050;
local totemOfWrathId = 77746;
local searingtotemId = 3599;
local totemOfWrathName = GetSpellInfo(totemOfWrathId);
local sengendeflammenName = GetSpellInfo(sengendeflammenId);
local flameshockName = GetSpellInfo(flameshockId);
local naturesSwiftnessName = GetSpellInfo(naturesSwiftnessId);
local clearcastName = GetSpellInfo(clearcastId);
local feralSpiritName = GetSpellInfo(feralSpiritId);
local autoattackName = "Attack"; -- fixme does this have an id?
local stormstrikeName = GetSpellInfo(stormstrikeId);
local lavalashName = GetSpellInfo(lavalashId);
local earthshockName = GetSpellInfo(earthshockId);
local maelstromName = GetSpellInfo(maelstromId);
local lightningBoltName = GetSpellInfo(lightningBoltId);
local windfuryName = GetSpellInfo(windfuryId);
local flametongueName = GetSpellInfo(flametongueId);
local lightningshieldName = GetSpellInfo(lightningshieldId);
local cooldownSpellName = lightningBoltName;
local shamanisticRageName = GetSpellInfo(shamanisticRageId);
local unleashelementsName = GetSpellInfo(unleashelementsId);
local searingtotemName = GetSpellInfo(searingtotemId);
local spellQueue = {};
local maxQueueSize = 4;
local groupCount = 0;
local hostile = false;
local timeLeft = 0;
local inCombat = false;
-- configs
local defaults = {
char = {
x = 0,
y = 0,
relativePoint = "CENTER",
mode = 1,
size = 50,
spacing = 15,
locked = false,
threatThreshold = 70,
updateFrequency = .2
}
};
-- random variables
local playerId;
local function canCastSpell(spellName, time)
local startTime, duration = GetSpellCooldown(spellName);
if duration then
local nextCastTime = startTime + duration;
return nextCastTime <= time;
end
end
function soonestCooldown(...)
local castInfo = {};
for i=1,select('#',...) do
local spellName = select(i, ...);
local startTime, duration = GetSpellCooldown(spellName);
if duration then
local nextCastTime = startTime + duration;
if castInfo.castTime == nil or castInfo.castTime > nextCastTime then
castInfo.castTime = nextCastTime;
castInfo.spell = spellName;
end
end
end
return castInfo;
end
function ShamWow_Enhance:SaveLocation()
point, relativeTo, relativePoint, xOfs, yOfs = mainFrame:GetPoint();
self.db.char.x = xOfs;
self.db.char.y = yOfs;
self.db.char.relativePoint = relativePoint;
end
local function RepositionFrames()
for i=maxQueueSize,1,-1 do
local spacing = ShamWow_Enhance.db.char.spacing;
local f = spellQueueFrames[i];
f:SetWidth(ShamWow_Enhance.db.char.size)
f:SetHeight(ShamWow_Enhance.db.char.size)
if i == maxQueueSize then
f:SetPoint("CENTER", spacing * (maxQueueSize-1), 0);
else
f:SetPoint("CENTER", -spacing, 0);
end
end
end
function ShamWow_Enhance:OnInitialize()
local AceConfigReg = LibStub("AceConfigRegistry-3.0")
local AceConfigDialog = LibStub("AceConfigDialog-3.0")
self.db = LibStub("AceDB-3.0"):New("ShamWow_EnhanceDB", defaults, "char")
LibStub("AceConfig-3.0"):RegisterOptionsTable("ShamWow_Enhance", self:GetOptions(), {"ShamWow_Enhance", "swe"} )
self.optionsFrame = AceConfigDialog:AddToBlizOptions("ShamWow_Enhance","ShamWow_Enhance")
self.db:RegisterDefaults(defaults);
mainFrame = CreateFrame("Frame","ShamWow_EnhanceDisplayFrame",UIParent)
mainFrame:SetFrameStrata("BACKGROUND")
mainFrame:SetWidth(self.db.char.size)
mainFrame:SetHeight(self.db.char.size)
mainFrame:EnableMouse(true)
mainFrame:SetMovable(true)
mainFrame:SetClampedToScreen(true)
mainFrame:SetScript("OnMouseDown",
function(self)
if not ShamWow_Enhance.db.char.locked then
self:StartMoving();
end
end);
mainFrame:SetScript("OnMouseUp", function(self) self:StopMovingOrSizing(); ShamWow_Enhance:SaveLocation(); end);
mainFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing(); ShamWow_Enhance:SaveLocation(); end)
mainFrame:ClearAllPoints();
mainFrame:SetPoint(self.db.char.relativePoint, self.db.char.x, self.db.char.y);
spellQueueFrames = {};
for i=maxQueueSize,1,-1 do
local parentFrame;
if i == maxQueueSize then
parentFrame = mainFrame;
else
parentFrame = spellQueueFrames[i+1];
end
local f = CreateFrame("Frame","ShamWow_EnhanceDisplayFrame" .. i, parentFrame)
f:SetFrameStrata("BACKGROUND")
f:SetWidth(self.db.char.size)
f:SetHeight(self.db.char.size)
f:EnableMouse(false)
f:SetMovable(false)
f:SetClampedToScreen(true)
f:ClearAllPoints();
local spacing = ShamWow_Enhance.db.char.spacing;
f.spellTexture = f:CreateTexture(nil,"BACKGROUND");
f.spellTexture:SetAllPoints(f);
f.overlayTexture = f:CreateTexture(nil,"OVERLAY");
f.overlayTexture:SetAllPoints(f);
spellQueueFrames[i] = f;
end
cooldownFrame1 = CreateFrame("Frame","ShamWow_ClearCastFrame", spellQueueFrames[1])
cooldownFrame1:SetFrameStrata("BACKGROUND")
local ccSize = self.db.char.size / 2;
cooldownFrame1:SetWidth(ccSize);
cooldownFrame1:SetHeight(ccSize);
cooldownFrame1:SetPoint("TOPLEFT", -ccSize, 0);
cooldownFrame1:EnableMouse(false)
cooldownFrame1:SetMovable(false)
cooldownFrame1:SetClampedToScreen(true)
cooldownFrame1.texture = cooldownFrame1:CreateTexture(nil,"OVERLAY");
cooldownFrame1.texture:SetAllPoints(cooldownFrame1);
cooldownFrame2 = CreateFrame("Frame","ShamWow_FeralSpiritFrame", spellQueueFrames[1])
cooldownFrame2:SetFrameStrata("BACKGROUND")
cooldownFrame2:SetWidth(ccSize);
cooldownFrame2:SetHeight(ccSize);
cooldownFrame2:SetPoint("TOPLEFT", -ccSize, -ccSize);
cooldownFrame2:EnableMouse(false)
cooldownFrame2:SetMovable(false)
cooldownFrame2:SetClampedToScreen(true)
cooldownFrame2.texture = cooldownFrame2:CreateTexture(nil,"OVERLAY");
cooldownFrame2.texture:SetAllPoints(cooldownFrame2);
cooldownFrame = CreateFrame("Cooldown","$parent_cooldown", spellQueueFrames[1]);
cooldownFrame:SetAllPoints(mainFrame);
local testfont = media:Fetch("font", 'Arial');
if not mainFrame.text then
mainFrame.text = mainFrame:CreateFontString(nil,"OVERLAY")
end
mainFrame.text:SetFont(testfont, 12, "THICKOUTLINE");
mainFrame.text:ClearAllPoints()
mainFrame.text:SetTextColor(.8, 0, 0, 1)
mainFrame.text:SetPoint("BOTTOM", mainFrame, "BOTTOM", 0, -13);
mainFrame.text:SetText("")
if not mainFrame.alertText then
mainFrame.alertText = mainFrame:CreateFontString(nil,"OVERLAY")
end
mainFrame.alertText:SetFont(testfont, 12, "THICKOUTLINE");
mainFrame.alertText:ClearAllPoints()
mainFrame.alertText:SetTextColor(1, 1, 0, 1)
mainFrame.alertText:SetPoint("BOTTOM", mainFrame, "TOP", 5, 2);
mainFrame.alertText:SetText("")
timeText = spellQueueFrames[1]:CreateFontString(nil,"OVERLAY")
timeText:SetFont(testfont, 12, "THICKOUTLINE");
timeText:ClearAllPoints()
timeText:SetTextColor(0, 1, 0, 1)
timeText:SetPoint("CENTER", mainFrame, "CENTER", 0, 0);
timeText:SetText("")
RepositionFrames();
swPrint('Initialized');
end
local function AlertCheck()
if (not hostile) or groupCount == 0 or ShamWow_Enhance.db.char.threatThreshold > 100 then
mainFrame.text:SetText("");
else
local _,_,threatpct,_,_ = UnitDetailedThreatSituation("player", "target");
if not threatpct or threatpct < ShamWow_Enhance.db.char.threatThreshold then
mainFrame.text:SetText("");
else
mainFrame.text:SetText(string.format("%.0f", threatpct) .. '%');
end
end
local nastySpellName = ""; -- for tracking nasty spell reflect debuffs
if (hostile) then
-- check target buffs
for i=1,40 do
local name = UnitBuff("target", i);
if not name then
break; -- end of buffs
end
if name:lower():find('reflect') then
nastySpellName = name;
break;
end
end
end
mainFrame.alertText:SetText(nastySpellName);
end
-- this colors the overlay frame based on range, mana
local function FrameStatusCheck(f, spell)
if spell == autoattackName or IsSpellInRange(spell, 'target') == 0 then
f.overlayTexture:SetTexture(1, 0, 0, .5);
else
name, _, _, cost = GetSpellInfo(spell);
if cost and UnitPower('player') < cost then
f.overlayTexture:SetTexture(0, 0, 1, .5);
else
f.overlayTexture:SetTexture(nil);
end
end
end
function ShamWow_Enhance:PARTY_MEMBERS_CHANGED(...)
groupCount = GetNumRaidMembers();
if groupCount == 0 then
groupType = "party";
groupCount = GetNumPartyMembers();
else
groupType = "raid";
groupCount = groupCount - 1; -- don't include yourself
end
end
local function addSpell(spellName)
spellQueue[#spellQueue+1] = spellName;
end
local function RecalcEnhanceQueue(nextCastTime)
local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo();
if not hasMainHandEnchant then
addSpell(windfuryName);
end
if (not hasOffHandEnchant) and OffhandHasWeapon() then
addSpell(flametongueName);
end
-- check target debuffs
local hasSSDebuff = false;
local hasFSDebuff = false;
for i=1,40 do
local name, _, _, _, _, _, _, isMine = UnitDebuff("target", i);
if not name then
break; -- end of debuffs
end
if isMine == "player" and name == flameshockName then
hasFSDebuff = true;
end
if isMine == "player" and name == stormstrikeName then
hasSSDebuff = true;
end
end
-- check buffs
local ccTexture = nil;
local hasShield = false;
local maelstrom = false;
for i=1,40 do
local name, _, texture, count = UnitBuff("player", i);
if not name then
break; -- end of buffs
end
if name == maelstromName then
if hostile and count == 5 then
maelstrom = true;
end
elseif name == lightningshieldName then
hasShield = true;
elseif name == clearcastName then
ccTexture = texture;
end
end
if true or ccTexture then
cooldownFrame1.texture:SetTexture(ccTexture);
else
cooldownFrame1.texture:SetTexture(0, 1, 0, .5);
end
if inCombat and canCastSpell(feralSpiritName, nextCastTime) then
cooldownFrame2.texture:SetTexture(GetSpellTexture(feralSpiritName));
else
cooldownFrame2.texture:SetTexture(nil);
end
-- Searing Totem
local hasSFDebuff = false;
for i=1,40 do
local name, _, _, _, _, _, _, isMine = UnitDebuff("target", i);
if not name then
break; -- end of debuffs
end
if isMine == "player" and name == sengendeflammenName then
hasSFDebuff = true;
end
end
if hasSFDebuff == false then
if inCombat and canCastSpell(searingtotemName, nextCastTime) then
cooldownFrame1.texture:SetTexture(GetSpellTexture(searingtotemName));
end
else
cooldownFrame1.texture:SetTexture(nil);
end
-- End of Searing Totem
if (not inCombat) and (not hasShield) then
addSpell(lightningshieldName);
end
--local haveTotem, nameTotem, startTimeTotem, durationTotem, iconTotem = GetTotemInfo(1);
--local magmaTotemCastable = false;
-- if inCombat and (not haveTotem) then
-- addSpell(lightningshieldName);
-- end
local mana = UnitPower('player');
local maxMana = UnitPowerMax('player');
if hostile then
local ranged = IsSpellInRange(stormstrikeName, 'target') == 0;
local earthshockCastable = canCastSpell(earthshockName, nextCastTime);
local stormstrikeCastable = canCastSpell(stormstrikeName, nextCastTime);
local lavalashCastable = canCastSpell(lavalashName, nextCastTime);
local maelstromFirst = maelstrom and (hasSSDebuff or ranged);
if lavalashCastable then
addSpell(lavalashName);
end
local maelstromSpell = lightningBoltName;
if maelstrom then
if canCastSpell(lightningBoltName, nextCastTime) then
maelstromSpell = lightningBoltName;
end
end
if maelstromFirst then
addSpell(maelstromSpell);
end
if ranged then
if earthshockCastable then
if hasFSDebuff == false then
addSpell(flameshockName);
else
addSpell(earthshockName);
end
elseif (not stormstrikeCastable) and (not lavalashCastable) then
addSpell(autoattackName);
end
end
if maelstrom and (not maelstromFirst) then
addSpell(maelstromSpell);
end
-- if ranged == false and earthshockCastable then
-- if hasFSDebuff == false then
-- addSpell(flameshockName);
-- else
-- addSpell(earthshockName);
-- end
-- end
if ranged == false and earthshockCastable then
if hasFSDebuff == false then
addSpell(flameshockName);
end
end
if stormstrikeCastable then
addSpell(stormstrikeName);
end
if ranged == false and earthshockCastable then
if hasFSDebuff == true then
addSpell(earthshockName);
end
end
if canCastSpell(unleashelementsName, nextCastTime) then
addSpell(unleashelementsName);
end
else
local health = UnitHealth('player');
local maxHealth = UnitHealthMax('player');
if health < (.6 * maxHealth) then
addSpell(healingWaveName);
elseif (not inCombat) and (mana >= (.90 * maxMana) or ccTexture) and health < (.75 * maxHealth) then
addSpell(healingWaveName); -- heal yoself foo!
end
end
if inCombat and not hasShield then
addSpell(lightningshieldName);
end
end
local function RecalcSpell()
if (not inCombat) then
ShamWow_Enhance:RecalcMode(); -- check if you switched spec
end
AlertCheck();
spellQueue = {};
local startTime, duration = GetSpellCooldown(cooldownSpellName);
local curTime = GetTime();
local nextCastTime = curTime;
if duration > 0 then
local gcdEndTime = startTime + duration;
if gcdEndTime > curTime then
nextCastTime = gcdEndTime;
end
cooldownFrame:SetCooldown(startTime, duration);
cooldownFrame:SetAlpha(1);
if mode == ELEM_MODE then
-- we don't want to recalc too close to the last cast
if curTime - startTime < .5 then
return;
end
end
else
cooldownFrame:SetAlpha(0);
end
local _, _, _, _, _, spellEndTime = UnitCastingInfo('player');
if spellEndTime then
nextCastTime = math.min(nextCastTime, spellEndTime / 1000);
end
--local possessed = GetActionTexture(121);
--if possessed ~= nil then
-- do nothing
if mode == RESTO_MODE then
RecalcRestoQueue(nextCastTime);
elseif mode == ELEM_MODE then
RecalcElemQueue(nextCastTime);
else
RecalcEnhanceQueue(nextCastTime);
end
for i=maxQueueSize,1,-1 do
local spell = spellQueue[i];
local f = spellQueueFrames[i];
if spell then
f.spellTexture:SetTexture(GetSpellTexture(spellQueue[i]));
FrameStatusCheck(f,spell);
else
f.spellTexture:SetTexture(nil);
f.overlayTexture:SetTexture(nil);
end
end
local timeTextStr = '';
if inCombat or hostile then
timeLeft = ShamWow_Enhance.db.char.updateFrequency;
else
timeLeft = .5;
end
if #spellQueue == 0 then
if (not possessed) and hostile and mode == ENHANCE_MODE then
local castInfo = soonestCooldown(stormstrikeName, earthshockName, lavalashName);
local timeUntilCast = castInfo.castTime - GetTime();
if timeUntilCast < timeLeft then
timeLeft = timeUntilCast;
end
if timeUntilCast < 1 then
local f = spellQueueFrames[1];
f.overlayTexture:SetTexture(.5, .5, .5, .5);
f.spellTexture:SetTexture(GetSpellTexture(castInfo.spell));
timeTextStr = string.format("%0.1f", timeUntilCast);
else
cooldownFrame:SetAlpha(0);
end
else
cooldownFrame:SetAlpha(0);
end
end
timeText:SetText(timeTextStr);
end
function ShamWow_Enhance:RecalcMode(...)
end
function ShamWow_Enhance:PLAYER_REGEN_ENABLED(...)
inCombat = false;
end
function ShamWow_Enhance:PLAYER_REGEN_DISABLED(...)
inCombat = true;
ShamWow_Enhance:PLAYER_TARGET_CHANGED(); -- recompute if target is friend when combat starts
end
function ShamWow_Enhance:PLAYER_TARGET_CHANGED(...)
hostile = UnitName("target") and UnitCanAttack("player","target") and UnitHealth("target") > 0;
timeLeft = 0;
end
function ShamWow_Enhance:OnEnable()
local playerClass, englishClass = UnitClass("player");
if englishClass ~= 'SHAMAN' then
swPrint('You are not a shaman. Please disable ShamWow_Enhance as an Addon for this character');
DisableAddon("ShamWow_Enhance");
else
playerId = UnitGUID("player");
self:PARTY_MEMBERS_CHANGED(); -- recheck party members
self:PLAYER_TARGET_CHANGED(); -- check target
self:RecalcMode();
-- Register for Function Events
self:UnregisterAllEvents();
self:RegisterEvent("PLAYER_TARGET_CHANGED");
self:RegisterEvent("PLAYER_REGEN_ENABLED");
self:RegisterEvent("PLAYER_REGEN_DISABLED");
self:RegisterEvent("PARTY_MEMBERS_CHANGED");
mainFrame:SetScript('OnUpdate', function(self, timeSinceLast)
timeLeft = timeLeft - timeSinceLast;
if timeLeft <= 0 then
RecalcSpell();
end
end);
swPrint('Enabled');
end
end
function ShamWow_Enhance:OnDisable()
mainFrame:SetScript('OnUpdate', nil);
swPrint(' disabled');
end
function ShamWow_Enhance:GetProperty(info)
local propName = info[#info];
local value = self.db.char[propName];
return value;
end
function ShamWow_Enhance:SetProperty(info, newValue)
local propName = info[#info];
self.db.char[propName] = newValue;
if propName == 'spacing' or propName == 'size' then
RepositionFrames();
end
if mainFrame and propName == 'size' then
mainFrame:SetWidth(self.db.char.size);
mainFrame:SetHeight(self.db.char.size);
end
end
function ShamWow_Enhance:GetOptions()
local options = {
name = "ShamWow_Enhance",
handler = ShamWow_Enhance,
type = 'group',
childGroups ='tree',
args = {
locked = {
type = "toggle",
name = "Locked",
get = "GetProperty",
set = "SetProperty",
order = 0,
},
mode = {
type = 'select',
name = "Mode",
values = { 'Enhancement', 'Heal', 'Elemental', 'Auto' },
get = "GetProperty",
set = "SetProperty",
order = 1,
},
size = {
type = "range",
name = "Size",
desc = "Size of the Frame",
min = 1,
max = 200,
step = 1,
get = "GetProperty",
set = "SetProperty",
order = 2,
},
updateFrequency = {
type = 'range',
name = "Update Frequency",
desc = "The delay in seconds to wait before rechecking the next spell.",
min = .05,
max = .5,
step = .05,
get = "GetProperty",
set = "SetProperty",
order = 3,
},
spacing = {
type = 'range',
name = "Button Spacing",
min = 1,
max = 200,
step = 1,
get = "GetProperty",
set = "SetProperty",
order = 4,
},
threatThreshold = {
type = 'range',
name = "Threat",
desc = "Show threat if your threat percentage is atleast this amount. 100% means you have aggro! Set to 101 if you don't want to see the threat indicator at all.",
min = 0,
max = 101,
step = 1,
get = "GetProperty",
set = "SetProperty",
order = 5,
}
},
}
return options
end