PuppeteerSettings = {} PTUtil.SetEnvironment(PuppeteerSettings) local _G = getfenv(0) local util = PTUtil local _, playerClass = UnitClass("player") function UpdateTrackedDebuffTypes() local debuffTypeCureSpells = { ["PALADIN"] = { ["Purify"] = {"Poison", "Disease"}, ["Cleanse"] = {"Poison", "Disease", "Magic"} }, ["PRIEST"] = { ["Cure Disease"] = {"Disease"}, ["Abolish Disease"] = {"Disease"}, ["Dispel Magic"] = {"Magic"} }, ["DRUID"] = { ["Cure Poison"] = {"Poison"}, ["Abolish Poison"] = {"Poison"}, ["Remove Curse"] = {"Curse"} }, ["SHAMAN"] = { ["Cure Poison"] = {"Poison"}, ["Cure Disease"] = {"Disease"} }, ["MAGE"] = { ["Remove Lesser Curse"] = {"Curse"} } } for _, class in ipairs(util.GetClasses()) do if not debuffTypeCureSpells[class] then debuffTypeCureSpells[class] = {} end end local trackedDebuffTypes = {} do local id = 1; for i = 1, GetNumSpellTabs() do local _, _, _, numSpells = GetSpellTabInfo(i); for j = 1, numSpells do local spellName = GetSpellName(id, "spell"); local types = debuffTypeCureSpells[playerClass][spellName] if types then for _, type in ipairs(types) do trackedDebuffTypes[type] = 1 end end id = id + 1 end end end TrackedDebuffTypesSet = trackedDebuffTypes trackedDebuffTypes = util.ToArray(trackedDebuffTypes) TrackedDebuffTypes = trackedDebuffTypes end function LetsCrashOut() local dialog dialog = PTGuiLib.Get("simple_dialog", UIParent) :SetPoint("CENTER") :SetTitle("Puppeteer") :SetText("You are using a newer settings version with an older version of Puppeteer! Either update the addon or ".. "manually delete its data.") :AddButton("Okay", function() dialog:Dispose() end) Puppeteer.UnregisterEventHandlers() SeeYaImCrashingOut() -- im crashing out end function SetDefaults() if not PTOptions then _G.PTOptions = {} end if not PTGlobalOptions then _G.PTGlobalOptions = {} end local OPTIONS_VERSION = 3 if PTOptions.OptionsVersion and (PTOptions.OptionsVersion > OPTIONS_VERSION) then LetsCrashOut() end if PTGlobalOptions.OptionsVersion and (PTGlobalOptions.OptionsVersion > OPTIONS_VERSION) then LetsCrashOut() end local isHealer = util.IsHealerClass("player") local isManaUser = util.ClassPowerTypes[util.GetClass("player")] == "mana" do local defaults = { ["ShowTargets"] = { ["Friendly"] = isHealer, ["Hostile"] = false }, ["AlwaysShowTargetFrame"] = false, ["TargetWhileCasting"] = false, ["TargetAfterCasting"] = false, ["FrameDrag"] = { ["MoveAll"] = false, ["AltMoveKey"] = "Shift" }, ["DisablePartyFrames"] = { ["InParty"] = false, ["InRaid"] = false }, ["SpellsTooltip"] = { ["Enabled"] = isHealer, ["AttachTo"] = "Button", -- "Button", "Frame", "Group", "Screen" ["OffsetX"] = 0, ["OffsetY"] = 0, ["Anchor"] = "Top Right", -- "Top Left", "Top Right", "Bottom Left", "Bottom Right" ["ShowManaCost"] = false, ["ShowManaPercentCost"] = true, ["HideCastsAbove"] = 3, ["CriticalCastsLevel"] = 3, ["AbbreviatedKeys"] = false, ["ColoredKeys"] = true, ["ShowPowerBar"] = true, ["ShowPowerAs"] = isManaUser and "Power %" or "Power", -- "Power", "Power/Max Power", "Power %" ["ShowItemCount"] = false }, ["ShowAuraTimesAt"] = { ["Short"] = 5, -- <1 min ["Medium"] = 10, -- <=2 min ["Long"] = 60 * 2 -- >2 min }, ["Tracking"] = { ["EvaluateInterval"] = 1.25, -- How often everyone is fully scanned to determine if they should be closely tracked ["DistanceUpdateInterval"] = 0.1, -- How often distance tracked units are updated ["SightUpdateInterval"] = 0.1, -- How often sight tracked units are updated ["MinDistanceTracking"] = 20, -- The minimum distance to start closely tracking distance ["MaxDistanceTracking"] = 60, -- The maxmimum distance to start closely tracking distance ["MaxSightTracking"] = 80 -- The maximum distance to closely track sight }, ["CastWhen"] = "Mouse Up", -- Mouse Up, Mouse Down ["CastWhenKey"] = "Key Up", -- Key Up, Key Down ["AutoResurrect"] = Puppeteer.ResurrectionSpells[util.GetClass("player")] ~= nil, ["UseHealPredictions"] = true, ["PVPFlagProtection"] = true, ["SetMouseover"] = true, ["LFTAutoRole"] = true, -- Turtle WoW ["TestUI"] = false, ["Hidden"] = false, ["HideWhileSolo"] = false, ["ChosenProfiles"] = { ["Party"] = "Default", ["Pets"] = "Default", ["Raid"] = "Small", ["Raid Pets"] = "Small", ["Target"] = "Long", ["Focus"] = "Default" }, ["StyleOverrides"] = {}, ["FrameOptions"] = {}, ["Scripts"] = { ["OnLoad"] = "", ["OnPostLoad"] = "" }, ["OptionsVersion"] = OPTIONS_VERSION } local specialDefaults = { ["Buttons"] = { "LeftButton", "MiddleButton", "RightButton", "Button5", "Button4", "MOUSEWHEELUP", "MOUSEWHEELDOWN" }, ["ButtonInfo"] = { ["LeftButton"] = { ["Name"] = "Left", ["ShowUnbound"] = true }, ["MiddleButton"] = { ["Name"] = "Middle", ["ShowUnbound"] = true }, ["RightButton"] = { ["Name"] = "Right", ["ShowUnbound"] = true }, ["Button5"] = { ["Name"] = "Forward", ["ShowUnbound"] = true }, ["Button4"] = { ["Name"] = "Back", ["ShowUnbound"] = true }, ["MOUSEWHEELUP"] = { ["Name"] = "Wheel Up", ["ShowUnbound"] = false }, ["MOUSEWHEELDOWN"] = { ["Name"] = "Wheel Down", ["ShowUnbound"] = false }, } } local optionsUpgrades = { { version = 2, upgrade = function(self, options) local upgraded = util.CloneTable(options, true) if options["ShowSpellsTooltip"] ~= nil then if not options["SpellsTooltip"] then upgraded["SpellsTooltip"] = {} end upgraded["SpellsTooltip"]["Enabled"] = options["ShowSpellsTooltip"] upgraded["ShowSpellsTooltip"] = nil end if options["ChosenProfiles"] ~= nil then local groupNames = {"Party", "Pets", "Raid", "Raid Pets", "Target"} local changedProfileNames = { ["Compact"] = "Default", ["Compact (Small)"] = "Small", ["Compact (Short Bar)"] = "Default (Short Bar)" } for _, name in ipairs(groupNames) do local currentlySelected = options["ChosenProfiles"][name] if changedProfileNames[currentlySelected] then upgraded["ChosenProfiles"][name] = changedProfileNames[currentlySelected] end end end upgraded["OptionsVersion"] = self.version return upgraded end, shouldUpgrade = function(self, options) return options.OptionsVersion < self.version end }, { version = 3, upgrade = function(self, options) local upgraded = util.CloneTable(options, true) if options["AutoTarget"] then upgraded["TargetWhileCasting"] = true upgraded["TargetAfterCasting"] = true end if options["Scripts"] then local guard = "-- Auto-generated guard to prevent errors in new addon version, remove if you're sure ".. "your script won't produce errors\nif true then return end\n\n" if options["Scripts"]["OnLoad"] ~= nil and options["Scripts"]["OnLoad"] ~= "" then upgraded["Scripts"]["OnLoad"] = guard..options["Scripts"]["OnLoad"] end if options["Scripts"]["OnPostLoad"] ~= nil and options["Scripts"]["OnPostLoad"] ~= "" then upgraded["Scripts"]["OnPostLoad"] = guard..options["Scripts"]["OnPostLoad"] end end upgraded["OptionsVersion"] = self.version return upgraded end, shouldUpgrade = function(self, options) return options.OptionsVersion < self.version end } } if PTOptions.OptionsVersion and PTOptions.OptionsVersion < OPTIONS_VERSION then for _, upgrade in ipairs(optionsUpgrades) do if upgrade:shouldUpgrade(PTOptions) then local prevVersion = PTOptions.OptionsVersion _G.PTOptions = upgrade:upgrade(PTOptions) DEFAULT_CHAT_FRAME:AddMessage("[Puppeteer] Upgraded options from version ".. prevVersion.." to "..upgrade.version) end end end ApplyDefaults(PTOptions, defaults) -- Special defaults if not PTOptions["Buttons"] then PTOptions["Buttons"] = util.CloneTable(specialDefaults["Buttons"]) end if not PTOptions["ButtonInfo"] then PTOptions["ButtonInfo"] = util.CloneTable(specialDefaults["ButtonInfo"]) end end do local defaults = { ["ShowLoadMessage"] = true, ["Experiments"] = { ["AutoRole"] = false }, ["OptionsVersion"] = OPTIONS_VERSION } ApplyDefaults(PTGlobalOptions, defaults) end end function ApplyDefaults(t, defaults) for field, value in pairs(defaults) do if type(value) == "table" then t[field] = t[field] or {} ApplyDefaults(t[field], value) elseif t[field] == nil then t[field] = value end end end function TraverseOptions(location) local path = util.SplitString(location, ".") local currentTable = PTOptions if path[1] == "Global" then currentTable = PTGlobalOptions table.remove(path, 1) end for i = 1, table.getn(path) - 1 do currentTable = currentTable[path[i]] end return currentTable, path[table.getn(path)] end function GetOption(location) local optionTable, location = TraverseOptions(location) return optionTable[location] end function SetOption(location, value) local optionTable, location = TraverseOptions(location) optionTable[location] = value end -- Buffs/debuffs that significantly modify healing DefaultTrackedHealingBuffs = {"Amplify Magic", "Dampen Magic"} DefaultTrackedHealingDebuffs = {"Mortal Strike", "Wound Poison", "Curse of the Deadwood", "Veil of Shadow", "Gehennas' Curse", "Necrotic Poison", "Blood Fury", "Necrotic Aura", "Shadowbane Curse" -- Turtle WoW } -- Tracked buffs for all classes DefaultTrackedBuffs = { "Blessing of Protection", "Hand of Protection", "Divine Protection", "Divine Shield", "Divine Intervention", -- Paladin "Bulwark of the Righteous", "Blessing of Sacrifice", "Hand of Sacrifice", "Power Infusion", "Spirit of Redemption", "Inner Focus", "Abolish Disease", "Power Word: Shield", -- Priest "Shield Wall", "Recklessness", "Last Stand", -- Warrior "Evasion", "Vanish", -- Rogue "Deterrence", "Feign Death", "Mend Pet", -- Hunter "Frenzied Regeneration", "Innervate", "Abolish Poison", -- Druid "Soulstone Resurrection", "Hellfire", "Health Funnel", -- Warlock "Ice Block", "Evocation", "Ice Barrier", "Mana Shield", -- Mage "Quel'dorei Meditation", "Grace of the Sunwell", -- Racial "First Aid", "Food", "Drink" -- Generic } -- Tracked buffs for specific classes DefaultClassTrackedBuffs = { ["PALADIN"] = {"Blessing of Wisdom", "Blessing of Might", "Blessing of Salvation", "Blessing of Sanctuary", "Blessing of Kings", "Blessing of Light", "Greater Blessing of Wisdom", "Greater Blessing of Might", "Greater Blessing of Salvation", "Greater Blessing of Sanctuary", "Greater Blessing of Kings", "Greater Blessing of Light", "Daybreak", "Blessing of Freedom", "Hand of Freedom", "Redoubt", "Holy Shield"}, ["PRIEST"] = {"Prayer of Fortitude", "Power Word: Fortitude", "Prayer of Spirit", "Divine Spirit", "Prayer of Shadow Protection", "Shadow Protection", "Holy Champion", "Champion's Grace", "Empower Champion", "Champion's Bond", "Fear Ward", "Inner Fire", "Renew", "Greater Heal", "Lightwell Renew", "Inspiration", "Fade", "Spirit Tap", "Enlighten", "Enlightened"}, ["WARRIOR"] = {"Battle Shout"}, ["DRUID"] = {"Gift of the Wild", "Mark of the Wild", "Thorns", "Rejuvenation", "Regrowth"}, ["SHAMAN"] = {"Water Walking", "Healing Way", "Ancestral Fortitude"}, ["MAGE"] = {"Arcane Brilliance", "Arcane Intellect", "Frost Armor", "Ice Armor", "Mage Armor"}, ["WARLOCK"] = {"Demon Armor", "Demon Skin", "Unending Breath", "Shadow Ward", "Fire Shield"}, ["HUNTER"] = {"Rapid Fire", "Quick Shots", "Quick Strikes", "Aspect of the Pack", "Aspect of the Wild", "Bestial Wrath", "Feed Pet Effect"} } -- Tracked debuffs for all classes DefaultTrackedDebuffs = { "Forbearance", -- Paladin "Death Wish", -- Warrior "Enrage", -- Druid "Recently Bandaged", "Resurrection Sickness", "Ghost", -- Generic "Deafening Screech" -- Applied by mobs } -- Tracked debuffs for specific classes DefaultClassTrackedDebuffs = { ["PRIEST"] = {"Weakened Soul"} } -- The baked aura sets TrackedBuffs = {} TrackedDebuffs = {} TrackedDebuffTypes = {} TrackedHealingBuffs = {} TrackedHealingDebuffs = {} function BakeTrackedAuras() util.ClearTable(TrackedBuffs) util.ClearTable(TrackedDebuffs) util.ClearTable(TrackedHealingBuffs) util.ClearTable(TrackedHealingDebuffs) local trackedBuffsArray = {} if DefaultClassTrackedBuffs[playerClass] then util.AppendArrayElements(trackedBuffsArray, DefaultClassTrackedBuffs[playerClass]) end util.AppendArrayElements(trackedBuffsArray, TrackedHealingBuffs) util.AppendArrayElements(trackedBuffsArray, DefaultTrackedBuffs) util.ToSet(trackedBuffsArray, true, TrackedBuffs) local trackedDebuffsArray = {} if DefaultClassTrackedDebuffs[playerClass] then util.AppendArrayElements(trackedDebuffsArray, DefaultClassTrackedDebuffs[playerClass]) end util.AppendArrayElements(trackedDebuffsArray, TrackedHealingDebuffs) util.AppendArrayElements(trackedDebuffsArray, DefaultTrackedDebuffs) util.ToSet(trackedDebuffsArray, true, TrackedDebuffs) util.ToSet(DefaultTrackedHealingBuffs, false, TrackedHealingBuffs) util.ToSet(DefaultTrackedHealingDebuffs, false, TrackedHealingDebuffs) end BakeTrackedAuras() function AddTrackedBuffs(...) for _, buff in ipairs(arg) do table.insert(DefaultTrackedBuffs, buff) end BakeTrackedAuras() end function RemoveTrackedBuffs(...) for _, buff in ipairs(arg) do util.RemoveElement(DefaultTrackedBuffs, buff) util.RemoveElement(DefaultClassTrackedBuffs[playerClass], buff) end BakeTrackedAuras() end function AddTrackedDebuffs(...) for _, debuff in ipairs(arg) do table.insert(DefaultTrackedDebuffs, debuff) end BakeTrackedAuras() end function RemoveTrackedDebuffs(...) for _, debuff in ipairs(arg) do util.RemoveElement(DefaultTrackedDebuffs, debuff) util.RemoveElement(DefaultClassTrackedDebuffs[playerClass], debuff) end BakeTrackedAuras() end DebuffTypeColors = { ["Magic"] = {0.35, 0.35, 1}, ["Curse"] = {0.5, 0, 1}, ["Disease"] = {0.45, 0.35, 0.16}, ["Poison"] = {0.6, 0.7, 0} } function GetSelectedProfileName(frame) local selected = PTOptions.ChosenProfiles[frame] if not PTProfileManager.GetProfile(selected) then selected = "Default" end return selected end function GetSelectedProfile(frame) return PTProfileManager.GetProfile(GetSelectedProfileName(frame)) end local function validateFrameOptionsExistence(frameName) if not PTOptions.FrameOptions[frameName] then PTOptions.FrameOptions[frameName] = {} end end function IsFrameHidden(frameName) return PTOptions.FrameOptions[frameName] and PTOptions.FrameOptions[frameName].Hidden end function SetFrameHidden(frameName, hidden) validateFrameOptionsExistence(frameName) PTOptions.FrameOptions[frameName].Hidden = hidden PTSettingsGui.UpdateFrameOptions() end function IsFrameLocked(frameName) return PTOptions.FrameOptions[frameName] and PTOptions.FrameOptions[frameName].Locked end function SetFrameLocked(frameName, locked) validateFrameOptionsExistence(frameName) PTOptions.FrameOptions[frameName].Locked = locked local group = Puppeteer.UnitFrameGroups[frameName] if group then group:UpdateHeaderColor() end PTSettingsGui.UpdateFrameOptions() end function IsTitleHidden(frameName) return PTOptions.FrameOptions[frameName] and PTOptions.FrameOptions[frameName].TitleHidden end function SetTitleHidden(frameName, hidden) validateFrameOptionsExistence(frameName) PTOptions.FrameOptions[frameName].TitleHidden = hidden local group = Puppeteer.UnitFrameGroups[frameName] if group then group:UpdateUIPositions() end PTSettingsGui.UpdateFrameOptions() end function GetFramePosition(frameName) if not (PTOptions.FrameOptions[frameName] and PTOptions.FrameOptions[frameName].Position) then return "TOPLEFT", (GetScreenWidth() / 2), -(GetScreenHeight() / 2) end return unpack(PTOptions.FrameOptions[frameName].Position) end function SaveFramePositions() for frameName, group in pairs(Puppeteer.UnitFrameGroups) do if not PTOptions.FrameOptions[frameName] then PTOptions.FrameOptions[frameName] = {} end local anchor, _, _, x, y = group:GetContainer():GetPoint(1) PTOptions.FrameOptions[frameName].Position = {anchor, x, y} end end