SH_SMARTHEAL_VERSION= SH_SMARTHEAL.." "..SMARTHEAL_CURRENT_VERSION function SmartHeal:Init() -- Hook the UseAction function and backup original UseAction SMARTHEAL_ORIG_USEACTION=UseAction; UseAction = function(slot,arg1,onself) SmartHeal:UseAction(slot,arg1,onself); end; -- set slash command SlashCmdList["SMARTHEAL"] = function(arg1) SmartHeal:SlashCmd(arg1); end; SLASH_SMARTHEAL1 = "/smartheal"; SLASH_SMARTHEAL2 = "/smh"; -- get realm and player name SmartHeal.realmName=GetRealmName(); SmartHeal.playerName=UnitName("player"); --local _,_,large_version,small_version,release_version=string.find(SmartHeal_Version,"^(%d+)%.(%d+)%.?(%d*)"); --if(not SmartHeal_Config['version'] or tonumber(SmartHeal_Config['version'])hpDeficit*SmartHeal:getConfig('overheal')/100) then SmartHeal.HealedValue=TotalHeal break end end return min(rank,rank2) end function SmartHeal:isSelfCast(spell) if (not UnitExists("target") or not UnitIsFriend("target","player")) then return 1 else return 0 end end function SmartHeal:targetRank(target,spell) local targetRank=1; local SpellStats if (SmartHeal.isBuff) then SpellStats=SmartHeal.buffList[spell]; elseif (SmartHeal.isHeal) then SpellStats=SmartHeal.spellList[spell]; end -- find target acceptable rank for i=table.getn(SpellStats.level),1,-1 do if (UnitLevel(target)>=SpellStats.level[i]-10) then targetRank=i; break; end end return targetRank end function SmartHeal:AdjustHealValue(spell,rank) -- calculate bonus offsets local EquipmentBonus=0 if (BonusScanner) then EquipmentBonus=tonumber(BonusScanner:GetBonus("HEAL")) end -- Adjust Talent local talent_multiplier,talent_adder=SmartHeal:TalentAdjust(spell) local healvalue=(SmartHeal.spellList[spell].value[rank]*talent_multiplier)+talent_adder+(EquipmentBonus*SmartHeal:bonusAdjust(spell,rank)); return healvalue or 0 end function SmartHeal:UseAction(slot, arg2, onself) -- Hack to get the spell name SmartHealSpellTooltip:SetAction(slot) local spell = getglobal("SmartHealSpellTooltipTextLeft1"):GetText() local rankTemp = getglobal("SmartHealSpellTooltipTextRight1"):GetText() local _,rankCap if(rankTemp) then _,_,rankCap=string.find(rankTemp,"^"..SH_RANK.." (%d+)") end SmartHeal.HotkeyMouseButton=arg1 if ( (SmartHeal.spellList[spell]~=nil or SmartHeal.buffList[spell]~=nil) and SmartHeal:getConfig("override") and SmartHeal:getConfig("enable")) then if (rankCap) then SmartHeal:Cast(spell.."("..SH_RANK.." "..rankCap..")") else SmartHeal:Cast(spell) end else SmartHeal.selfCast=onself -- Check for alt self cast if (IsAltKeyDown() and SmartHeal:getConfig("altselfcast")) then SmartHeal.selfCast=1 elseif(SmartHeal.HotkeyMouseButton=="RightButton" and SmartHeal:getConfig("RClickHotKeySelfCast")) then SmartHeal.selfCast=1 elseif( SmartHeal:isSelfCast(spell)==1 and SmartHeal:getConfig("autoselfcast") and (SmartHeal.spellList[spell]~=nil or SmartHeal.buffList[spell]~=nil) ) then SmartHeal.selfCast=1 end SmartHeal.CacheUnitId=SmartHeal:TargetUnitId() if (rankCap and SmartHeal.spellList[spell]~=nil and SmartHeal.spellList[spell].HoT~=1) then SmartHeal.HealedValue=SmartHeal:AdjustHealValue(spell,tonumber(rankCap)) end -- do default button action if the spell is not listed in the healing spells list SMARTHEAL_ORIG_USEACTION(slot, arg2, SmartHeal.selfCast) SmartHeal.selfCast=nil end end function SmartHeal:SpellMaxRank(spellname,ignoreMana) local maxRank=1; local manatooltip; local spells={[1]=spellname} if(spellname==SH_LESSER_GREATER_HEALS) then spells={[1]=SH_LESSER_HEAL, [4]=SH_HEAL, [8]=SH_GREATER_HEAL,} end for r,spell in spells do local i = 1 while true do local sName , sRank = GetSpellName(i, BOOKTYPE_SPELL) if not sName then do break end elseif (sName==spells[r]) then local _,_,rankNumber=string.find(sRank,"^"..SH_RANK.." (%d+)") if (rankNumber and rankNumber~="") then rankNumber=tonumber(rankNumber) SmartHealSpellTooltip:SetSpell(i,BOOKTYPE_SPELL) manatooltip = getglobal("SmartHealSpellTooltipTextLeft2"):GetText() local _,_,mana=string.find(manatooltip,"^(%d+) "..SH_MANA); if ((mana and UnitMana('player')>tonumber(mana)) or not mana or ignoreMana) then maxRank=max(maxRank,rankNumber+(r-1)) end else return end end i = i + 1 end -- end of while loop end -- end of for loop return maxRank end function SmartHeal:TalentAdjust(spell) local _, playerClass = UnitClass("player"); local rank local multiplier_factor=1 local additional_factor=0; if (playerClass=="PRIEST") then -- Improved Renew (renew only) 5% per point _, _, _, _, rank,_= GetTalentInfo(2,2); if (spell==SH_RENEW) then multiplier_factor=multiplier_factor*(1+(rank*0.05)); end; -- Spiritual Healing (all healing) 2% per point _, _, _, _, rank,_= GetTalentInfo(2,15); multiplier_factor=multiplier_factor*(1+(rank*0.02)); -- Spiritual Guidance (all healing) 5% per point, based on total spirit _, _, _, _, rank,_= GetTalentInfo(2,14); local spirit=0; if (BonusScanner) then spirit=tonumber(BonusScanner:GetBonus("SPI")); end additional_factor=additional_factor+spirit*(rank*0.05) elseif (playerClass=="PALADIN") then -- Healing Light (healing light and flash light) 4% per point _, _, _, _, rank,_= GetTalentInfo(1,5); if (spell==SH_HEALING_LIGHT or spell==SH_FLASH_OF_LIGHT) then multiplier_factor=multiplier_factor*(1+(rank*0.04)); end; elseif (playerClass=="DRUID") then -- Improved Rejuvenation (rejuvenation only) 5% per point _, _, _, _, rank,_= GetTalentInfo(3,10); if (spell==SH_REJUVENATION) then multiplier_factor=multiplier_factor*(1+(rank*0.05)); end; -- Gift of Nature (all healing spells) 2% per point _, _, _, _, rank,_= GetTalentInfo(3,12); multiplier_factor=multiplier_factor*(1+(rank*0.02)); elseif (playerClass=="SHAMAN") then -- Purification 2% per point _, _, _, _, rank,_= GetTalentInfo(3,10); multiplier_factor=multiplier_factor*(1+(rank*0.02)); end return multiplier_factor,additional_factor end function SmartHeal:bonusAdjust(spell,rank) local SpellStats=SmartHeal.spellList[spell]; local bonus=1; local castTimeBonus=1; local lowlevelBonus=1; local HoTBonus=1; -- cast time discount, ActualBenefit = AdvertisedBenefit * (CastingTime / 3.5) if (SpellStats.castTime[rank]<3.5 and SpellStats.value[rank]>0) then castTimeBonus=SpellStats.castTime[rank]/3.5; end -- Low level discount , EffectiveBonus = (1-((20-LevelLearnt)*0.0375))*AdvertisedBonus if (SpellStats.level[rank]<20) then lowlevelBonus=(1-((20-SpellStats.level[rank])*0.0375)) end -- Heal+HoT discount if (SpellStats.HoTvalue~=nil) then if (SpellStats.value[rank]>0 and SpellStats.HoTvalue[rank]>0) then HoTBonus=SpellStats.value[rank]/(SpellStats.value[rank]+SpellStats.HoTvalue[rank]) end end bonus=bonus*castTimeBonus*lowlevelBonus*HoTBonus; return bonus; end function SmartHeal:buffRank(spell) local BuffStats=SmartHeal.buffList[spell]; local targetRank=1; local target="target"; if(SmartHeal.selfCast==1) then target="player"; end local maxrank=SmartHeal:SpellMaxRank(spell) if(not maxrank) then return end if (BuffStats.group==0) then -- target buff targetRank=SmartHeal:targetRank(target,spell); elseif (BuffStats.group==1) then -- group member buff for i=1,4 do targetRank=max(targetRank,SmartHeal:targetRank("party"..i,spell)); end targetRank=max(targetRank,SmartHeal:targetRank("player",spell)); elseif (BuffStats.group==2) then -- paladin unit class blessings local _, targetClass = UnitClass(target); local thisUnitClass; if SmartHeal:inRaid() then for i=1,40 do _, thisUnitClass = UnitClass("raid"..i); if (thisUnitClass==targetClass) then targetRank=max(targetRank,SmartHeal:targetRank("raid"..i,spell)); end end elseif SmartHeal:inParty() then for i=1,4 do _, thisUnitClass = UnitClass("party"..i); if (thisUnitClass==targetClass) then targetRank=max(targetRank,SmartHeal:targetRank("party"..i,spell)); end end targetRank=max(targetRank,SmartHeal:targetRank("player",spell)); end else targetRank=SmartHeal:targetRank(target,spell); -- treat as target only buff end -- target max acceptable rank or player max rank whichever is lower return min(targetRank,maxrank); end function SmartHeal:inRaid() if GetNumRaidMembers()>0 then return true else return false end end function SmartHeal:inParty() if GetNumPartyMembers()>0 then return true else return false end end function SmartHeal:ErrorMsg(msg,r,g,b) if (not r and not g and not b) then r=1;g=0;b=0; end DEFAULT_CHAT_FRAME:AddMessage(msg,r,g,b); end function SmartHeal:doDebug() SmartHeal:ErrorMsg("SmartHeal Casted: "..SmartHeal.CastedSpell.."(Rank "..SmartHeal.CastedRank..")") if (SMARTHEAL_HEALTABLE[SmartHeal.playerClass] ~= nil) then SmartHeal_DebugMsg['talent']=SmartHeal:getAllTalent() end end function SmartHeal:AlertHealer(arg1) if (not UnitExists("target") or not UnitIsFriend("player","target")) then return end local current_targetName=UnitName("target") local _,_,casterName,spell=string.find(arg1,"(.+) "..SH_BEGINS_TO_CAST.." (.+).") if(not casterName or not spell) then return end TargetByName(casterName) if (UnitName("target")==casterName and UnitName("targettarget")==current_targetName) then local _, casterClass = UnitClass("target"); if (UnitName("target")~= current_targetName) then TargetLastTarget() end local alert_msg=string.format(SH_ALERT_HEALER_MSG, casterName, spell, current_targetName); local holdtime=UIERRORS_HOLD_TIME; local casterspellList=SMARTHEAL_HEALTABLE[casterClass]; if (casterspellList) then local spellStats=casterspellList[spell]; if (spellStats) then if (spellStats.castTime[1]) then holdtime=spellStats.castTime[1]; -- take the rank 1 cast time as holdtime end UIErrorsFrame:AddMessage(alert_msg, 0, 1.0, 0, 1.0, holdtime); end end else if (UnitName("target")~= current_targetName) then TargetLastTarget() end end end -- cannot stop cast onupdate after 1.10 , using warning alert instead function SmartHeal:StopCasting_OnUpdate(arg1) --if (not SmartHeal.SpellIsCasting and not SmartHeal.SpellIsChanneling) then return end if (not SmartHeal.HealUnitId or not SmartHeal.DoExcessHealAlert or not SmartHeal:getConfig("excesshealalert")) then return end if (SmartHeal.SpellIsCasting) then SmartHeal.timer=SmartHeal.timer-(arg1*1000) end if(SmartHeal.timer<1000) then local hp_ratio=UnitHealth(SmartHeal.HealUnitId)/UnitHealthMax(SmartHeal.HealUnitId)*100 if (hp_ratio>=SmartHeal:getConfig("excesshealalerttrigger")) then UIErrorsFrame:AddMessage(SH_EXCESSIVE_HEALING_ALERT_MSG.." "..UnitName(SmartHeal.HealUnitId).."!!!", 1, 0, 1, 1.0,3); end SmartHeal.DoExcessHealAlert=nil end end -- for debug purposes, use when talent tree is changed by Blizzard function SmartHeal:getAllTalent() local _, playerClass = UnitClass("player"); local numTabs = GetNumTalentTabs(); local talent={} talent[playerClass]={} for t=1, numTabs do local numTalents = GetNumTalents(t); talent[playerClass][t]={} for i=1, numTalents do local nameTalent, _, _, _, currRank, maxRank= GetTalentInfo(t,i); talent[playerClass][t][i]={name=nameTalent, rank=currRank,max=maxRank} end end return talent end