--[[ BestBuff 1.7 Casts the best rank possible of various buffs on caster's target, irregardless of caster or target level. Configuration: /bestbuff It will bring up a window to set options and define buffs. Generally you will only need to do this once or very seldom. There are now two ways to use BestBuff: Old way: /script BestBuff(buff_name) ie: /script BestBuff("Power Word: Fortitude") New way: Go into /bestbuff config panel and check Enabled. Any buff defined there on your action bars will automatically BestBuff. This means if you have macros dedicated to casting BestBuff you can get rid of them. Drag the spell from your spellbook to a hotkey and use it there. Self cast and spam which were previously turned on/off in the BestBuff() function are now defined in the BestBuff settings. By default, buffs have no notification and do not self cast. To add/change/remove buffs, use the /bestbuff config panel. For more permanent changes (in case you frequently lose SavedVariables.lua), instructions are in the BestBuff_Defaults.lua. To restore settings to default, use /bestbuff reset. -- Gello 3/29/06 - 1.10 tooltip changes 7/24/05 - changed highest rank to highest rank user knows 4/11/05 - removed BestBuff from UISpecialFrames 4/1/05 - added UI config window, ability to auto-BestBuff from action bar, saved buffs to SavedVariables.lua so users don't have to re-edit for every update. 3/22/05 - updated toc to 1300 3/18/05 - fixed a small bug causing excess spam 3/17/05 - added switch to kill self cast, some cleanup and comments 2/8/05 - initial release ]] BestBuff_Original_UseAction = nil; -- for hooking UseAction --[[ Variables saved to SavedVariables.lua ]] BB = {}; BB.Buffs = {}; BB.Enabled = 1; BB.Population = 0; BB.Selected = 0; --[[ Original BestBuff() left mostly unchanged ]] --[[ no squelch or self cast disable flags, they're in config options now ]] function BestBuff(intended_buff) local best_rank = 1; local target_rank = 1; local cast_rank = 1; local which_buff = 0; local x = 1; local text = nil; which_buff = nil; -- intended_buff is the string passed to us by user, see if this is in the buffnames list for x=1, table.getn(BB.Buffs), 1 do if (BB.Buffs[x].Name == intended_buff) then which_buff = x; end end -- if it is in the list... if which_buff then -- see which is the player's best castable rank due to player's level for x=1, table.getn(BB.Buffs[which_buff].Levels), 1 do if (UnitLevel("player")>=tonumber(BB.Buffs[which_buff].Levels[x])) then best_rank = x; end end -- see which is the target's best rank due to target's level if (UnitLevel("target")>0) then for x=1, table.getn(BB.Buffs[which_buff].Levels), 1 do if (UnitLevel("target")>=(tonumber(BB.Buffs[which_buff].Levels[x])-10)) then target_rank = x; end end else target_rank = best_rank end -- if the target's best rank is greater than the caster's best rank, -- (ie, target is much higher level) then the actual rank will be -- the caster's best rank. if best_rank < target_rank then cast_rank = best_rank; else -- otherwise, choose the best rank for the target. cast_rank = target_rank; end -- attempt the spell BestBuff_CastSpellByName(intended_buff,"Rank "..cast_rank); -- if spam is on and we have a friendly target, spam away if BB.Buffs[which_buff].Notify==1 and UnitExists("target") then text = "Casting "..intended_buff.."(Rank "..cast_rank..") on "..UnitName("target").."."; end -- If the spell didn't actually cast, and selfcasting not disabled, self cast it if BB.Buffs[which_buff].SelfCast==1 and SpellIsTargeting() then cast_rank = best_rank; SpellTargetUnit("player"); if BB.Buffs[which_buff].Notify==1 then text = "Casting "..intended_buff.."(Rank "..cast_rank..") on yourself."; end end else -- if we're here it means the user asked for a buff not in the buffnames list text = "Unable to cast "..intended_buff.."."; end -- if we gained a message to spam at some point, spam it if text and DEFAULT_CHAT_FRAME then DEFAULT_CHAT_FRAME:AddMessage(text); end end --[[ BestBuff callback functions ]] function BestBuff_OnLoad() BestBuff_Original_UseAction = UseAction; UseAction = BestBuff_New_UseAction; this:RegisterEvent("VARIABLES_LOADED"); end function BestBuff_OnEvent() if event=="VARIABLES_LOADED" then BestBuffFrame:Hide(); if BB.Population<1 then BestBuff_PopulateBuffs() end if BB.Enabled then BestBuffEnableCheckButton:SetChecked(1); else BestBuffEnableCheckButton:SetChecked(0); end SlashCmdList["BestBuffCOMMAND"] = BestBuff_SlashHandler; SLASH_BestBuffCOMMAND1 = "/bestbuff"; end end function BestBuff_SlashHandler(arg1) if string.find(arg1,"reset") then BestBuff_PopulateBuffs(); end BestBuff_Startup(); BestBuff_ClearEntry(); end function BestBuff_New_UseAction(slot,arg2,onself) local intended_buff; local which_buff = nil; local i; if not BB.Enabled then BestBuff_Original_UseAction(slot,arg2,onself); else BestBuffTooltip:SetOwner(UIParent,"ANCHOR_NONE") BestBuffTooltip:SetAction(slot); intended_buff = getglobal("BestBuffTooltipTextLeft1"):GetText(); for i=1,table.getn(BB.Buffs) do if BB.Buffs[i].Name == intended_buff then which_buff = intended_buff; end end if which_buff then BestBuff(intended_buff); else BestBuff_Original_UseAction(slot,arg2,onself); end end end --[[ Helper functions ]] -- CastSpellByName() won't work from within UseAction, use CastSpell instead function BestBuff_CastSpellByName(spell_name,spell_rank) --intended_buff,"Rank "..cast_rank); local id; local i = 1; local done = nil; local name; local rank; local id = nil; local intended_rank; _,_,intended_rank = string.find(spell_rank,"(%d+)") while not done do name,rank = GetSpellName(i,BOOKTYPE_SPELL); if not name then done = true; else if name==spell_name then _,_,rank = string.find(rank,"(%d+)") if tonumber(rank)<=tonumber(intended_rank) then id = i; end end end i = i+1; end if id then CastSpell(id,BOOKTYPE_SPELL); end end -- restore or initialize Buff to defaults function BestBuff_PopulateBuffs() BestBuffEnableCheckButton:SetChecked(0); BB = {}; BB.Buffs = {}; BB.Enabled = false; BB.Selected = 0; BB.Population = 1; foreach(BBDefaultBuffs,BestBuff_AddDefaultBuffs); BestBuff_SortBuffs(); end function BestBuff_AddDefaultBuffs(arg1) local i; if arg1 then BB.Buffs[BB.Population] = {}; BB.Buffs[BB.Population].Name = arg1; BB.Buffs[BB.Population].Notify = BBDefault_Notify; BB.Buffs[BB.Population].SelfCast = BBDefault_SelfCast; BB.Buffs[BB.Population].Levels = {}; for i=1,table.getn(BBDefaultBuffs[arg1]) do BB.Buffs[BB.Population].Levels[i] = BBDefaultBuffs[arg1][i]; end end BB.Population = BB.Population + 1; end -- always sort buffs alphabetically by .Name function BestBuff_SortBuffs() local temp_buff = {}; local changed = true; if BB.Population>2 then while changed do changed = false; for i=1,BB.Population-2 do if BB.Buffs[i].Name > BB.Buffs[i+1].Name then temp_buff = BB.Buffs[i]; BB.Buffs[i] = BB.Buffs[i+1]; BB.Buffs[i+1] = temp_buff; changed = true; end end end end end function BestBuff_Debug() local i; local j; local text; DEFAULT_CHAT_FRAME:AddMessage("Population: "..BB.Population); for i=1,table.getn(BB.Buffs) do text = "Buff #"..i..": "..BB.Buffs[i].Name..": "; for j=1,table.getn(BB.Buffs[i].Levels) do text = text .. BB.Buffs[i].Levels[j] .. " "; end DEFAULT_CHAT_FRAME:AddMessage(text); end end -- reset the lower "edit" area of the window function BestBuff_ClearEntry() BestBuffEditBox_OnEscapePressed(); BestBuff_SortBuffs() BB.Selected = 0; BestBuffEditNameBox:SetText(""); BestBuffEditLevelsBox:SetText(""); BestBuffNotifyCheckButton:SetChecked(0); BestBuffSelfCastCheckButton:SetChecked(0); BestBuffList_Update(); end -- returns a string as levels separated by spaces function BestBuff_LevelString(arg1) local text = ""; if BB.Buffs[arg1].Levels then for i=1,table.getn(BB.Buffs[arg1].Levels) do if i>1 then text = text .. " "; end text = text .. BB.Buffs[arg1].Levels[i]; end end return text; end function BestBuff_Startup() BestBuffFrame:StopMovingOrSizing(); BestBuffFrame:Show(); end --[[ Dialog control functions ]] function BestBuff_OnMouseDown(arg1) if arg1=="LeftButton" then BestBuffFrame:StartMoving(); end end function BestBuff_OnMouseUp(arg1) if arg1=="LeftButton" then BestBuffFrame:StopMovingOrSizing(); end end function BestBuffCloseButton_OnClick() BestBuff_ClearEntry(); BestBuffFrame:Hide(); end function BestBuffNameButton_OnClick(arg1) local index; local item; BestBuffEditBox_OnEscapePressed(); index = arg1 + FauxScrollFrame_GetOffset(BestBuffScrollFrame) if index==BB.Selected then index = BB.Population; BB.Selected = 0; end if index < BB.Population then BB.Selected = index; BestBuffEditNameBox:SetText(BB.Buffs[index].Name); BestBuffEditLevelsBox:SetText(BestBuff_LevelString(index)); BestBuffNotifyCheckButton:SetChecked(BB.Buffs[index].Notify); BestBuffSelfCastCheckButton:SetChecked(BB.Buffs[index].SelfCast); BestBuffList_Update(); else BestBuff_ClearEntry(); end end function BestBuffEnableCheckButton_OnClick() if BestBuffEnableCheckButton:GetChecked()==1 then BB.Enabled = true; else BB.Enabled = false; end end function BestBuffSelfCastCheckButton_OnClick() if BB.Selected>0 then BB.Buffs[BB.Selected].SelfCast = BestBuffSelfCastCheckButton:GetChecked(); end end function BestBuffNotifyCheckButton_OnClick() if BB.Selected>0 then BB.Buffs[BB.Selected].Notify = BestBuffNotifyCheckButton:GetChecked(); end end function BestBuffAddButton_OnClick() local i; local j; local text; local err_msg = ""; text = BestBuffEditNameBox:GetText(); for i=1,BB.Population-1 do if text=="" or BB.Buffs[i].Name==text then err_msg = "Can't add this buff.\nNew buffs must have a unique name."; end end if err_msg~="" then message(err_msg); else BB.Buffs[BB.Population] = {}; BB.Buffs[BB.Population].Name = BestBuffEditNameBox:GetText(); text = BestBuffEditLevelsBox:GetText(); -- populate .Levels with numbers in text BB.Buffs[BB.Population].Levels = {}; j = 1; for i in string.gfind(text,"(%d+)") do BB.Buffs[BB.Population].Levels[j] = i; j = j+1; end if j==1 then BB.Buffs[BB.Population].Levels[1] = 1; end BB.Buffs[BB.Population].Notify = BestBuffNotifyCheckButton:GetChecked(); BB.Buffs[BB.Population].SelfCast = BestBuffSelfCastCheckButton:GetChecked(); table.setn(BB.Buffs,BB.Population); BB.Population = BB.Population + 1; BestBuff_ClearEntry(); end end function BestBuffChangeButton_OnClick() local item; local i; local j; local text; if BB.Selected>0 then BB.Buffs[BB.Selected].Name = BestBuffEditNameBox:GetText(); text = BestBuffEditLevelsBox:GetText(); -- populate .Levels with numbers in text BB.Buffs[BB.Selected].Levels = {}; j = 1; for i in string.gfind(text,"(%d+)") do BB.Buffs[BB.Selected].Levels[j] = i; j = j+1; end if j==1 then BB.Buffs[BB.Selected].Levels[1] = 1; end BB.Buffs[BB.Selected].Notify = BestBuffNotifyCheckButton:GetChecked(); BB.Buffs[BB.Selected].SelfCast = BestBuffSelfCastCheckButton:GetChecked(); BestBuff_ClearEntry(); end end function BestBuffDeleteButton_OnClick() if BB.Selected>0 then table.remove(BB.Buffs,BB.Selected); BB.Population = BB.Population - 1; BB.Selected = 0; BestBuff_ClearEntry(); end end function BestBuffEditBox_OnEscapePressed() BestBuffEditNameBox:ClearFocus(); BestBuffEditLevelsBox:ClearFocus(); if BB.Selected>0 then BestBuffEditNameBox:SetText(BB.Buffs[BB.Selected].Name); BestBuffEditLevelsBox:SetText(BestBuff_LevelString(BB.Selected)); end end function BestBuffList_Update() local index; local i; local itemText; local itemButton; FauxScrollFrame_Update(BestBuffScrollFrame, BB.Population-1, 8, 8); for i=1,8 do index = i + FauxScrollFrame_GetOffset(BestBuffScrollFrame); itemButton = getglobal("BestBuffName"..i); itemText = getglobal("BestBuffName"..i.."_Text"); if (indexrank then rank = foundrank; end end return rank; end