Advertisement
Guest User

Forte_Core.lua

a guest
Jul 25th, 2016
281
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 75.29 KB | None | 0 0
  1. --ForteXorcist v1.980.8 by Xus 28-09-2012 for 5.0
  2.  
  3. --## X-Curse-Packaged-Version: r9\r\n## X-Curse-Project-Name: ForteXorcist\r\n## X-Curse-Project-ID: fortexorcist\r\n## X-Curse-Repository-ID: wow/fortexorcist/mainline
  4.  
  5. -- 26.07.2016 : Removed things related to the glyphs, contact : Bodo#2718
  6.  
  7. FW = {}; -- core table
  8. local FW = FW;
  9.  
  10. FC_Saved = {}; -- old save table
  11. local FC_Saved;
  12. FX_Saved = {}; -- new save table
  13. local FX_Saved;
  14. FW.InstanceDefault = {};
  15. local FW_Debug = false;
  16.  
  17. FW.TITLE = "ForteXorcist";
  18. local VERSION = "v"..GetAddOnMetadata("Forte_Core", "Version");
  19. FW.VERSION = VERSION;
  20. local ENABLE = false;
  21.  
  22. local STATES = {};
  23. FW.STATES = STATES;
  24. STATES.GROUPED = false;
  25. STATES.RAID = false;
  26. STATES.INCOMBAT = false;
  27.  
  28. FW.L = {}; -- locale table
  29. local FWL = FW.L;
  30.  
  31. FW.Frames = {};
  32. FW.ICON = {};
  33. FW.REDUCED_ALPHA = 0.33;
  34. FW.EXPAND = 1;
  35. --[[
  36. special ability events:
  37. SPELL_ACTIVATION_OVERLAY_SHOW #1:17941 #2:TEXTURES\SPELLACTIVATIONOVERLAYS\NIGHTFALL.BLP #3:Left + Right (Flipped) #4:1 #5:255 #6:255 #7:255
  38. SPELL_ACTIVATION_OVERLAY_GLOW_SHOW #1:686
  39.  
  40. COMBAT_TEXT_UPDATE #1:SPELL_CAST #2:Shadow Trance
  41. ]]
  42.  
  43. FW.DIS_COL = "|cff999999"; -- colour to use for disabled options
  44.  
  45. local Frames = FW.Frames;
  46. local Commands = {};
  47.  
  48. --local FW_Loaded = {};
  49. local FW_DelayedLoaded = {};
  50. local FW_VariablesLoaded = {};
  51. local FW_Messages = {};
  52. local FW_oRAMessages = {};
  53. local FW_EnterPartyRaid = {};
  54. local FW_OnEnterCombat = {};
  55. local FW_OnLeaveCombat = {};
  56.  
  57. local FilterRefresh = {};
  58.  
  59. local strfind = strfind;
  60. local strformat = string.format;
  61. local ipairs = ipairs;
  62. local pairs = pairs;
  63. local unpack = unpack;
  64. local select = select;
  65. local GetTime = GetTime;
  66. local type = type;
  67. local _G = _G;
  68.  
  69. local GetNumGroupMembers = GetNumGroupMembers;
  70.  
  71. do
  72.     local RAID = {};
  73.     for i=1,40,1 do tinsert(RAID,"raid"..i);end
  74.     local PARTY = {};
  75.     for i=1,4,1 do tinsert(PARTY,"party"..i);end
  76.    
  77.     function FW:ForGroupMembers(func,...)
  78.         local ret;
  79.         if IsInRaid() then
  80.             for i=1,GetNumGroupMembers(),1 do
  81.                 ret = func(RAID[i],...);
  82.                 if ret then return ret; end
  83.             end    
  84.         else
  85.             if IsInGroup() then
  86.                 for i=1,GetNumGroupMembers()-1,1 do -- player can't be identified by partyN, but full party count IS 5 members...
  87.                     ret = func(PARTY[i],...);
  88.                     if ret then return ret; end
  89.                 end
  90.             end
  91.             ret = func("player",...);
  92.             if ret then return ret; end
  93.         end
  94.     end
  95. end
  96.  
  97. do
  98.     local origUnitName = UnitName;
  99.     FW.FullUnitName = function(token)
  100.         local name, realm = origUnitName(token);
  101.         if realm and realm~="" then
  102.             return name.."-"..realm;
  103.         else
  104.             return name;
  105.         end
  106.     end
  107. end
  108. local UnitName = FW.FullUnitName;
  109. local UnitClass = UnitClass;
  110.  
  111. ----------------------------------------------------------------------------------------------------------------------------
  112. --------- STUFF TO MINIMIZE TABLE MEMORY GARBAGE SINCE I LIKE TO USE '2D' TABLES A LOT -------------------------------------
  113. ----------------------------------------------------------------------------------------------------------------------------
  114.  
  115. do
  116.     local function FW_BSTR(t,i,j,c,asc,a)
  117.         local val1 = t[j-1][ c[a] ];
  118.         local val2 = t[j][ c[a] ];
  119.        
  120.         if val1 == val2 then
  121.             if c[a+1] then     
  122.                 FW_BSTR(t,i,j,c,asc,a+1);
  123.             end
  124.         elseif asc[a] == (val1 > val2) then
  125.             t[j-1],t[j] = t[j],t[j-1];
  126.         end
  127.     end
  128.  
  129.     local function FW_BST(t,c,asc) -- sorts my '2d table', using 'column - ascending' table pairs
  130.         local i = 1;
  131.         local j;
  132.         while i <= t.rows do
  133.             j = t.rows;
  134.             while i<j do
  135.                 FW_BSTR(t,i,j,c,asc,1);
  136.                 j=j-1;
  137.             end
  138.             i=i+1;
  139.         end
  140.     end
  141.  
  142.     local function FW_INS(t,...) -- insert new row, must be the same number of columns (for sort to work properly)!!
  143.         t.rows = t.rows + 1;
  144.         if t[t.rows] then
  145.             for i=1,select('#',...),1 do
  146.                 t[t.rows][i] = select(i,...);
  147.             end
  148.         else
  149.             tinsert(t,{...});
  150.         end
  151.     end
  152.  
  153.     local function FW_REM(t,row) -- remove row
  154.         if row and row <= t.rows then
  155.             t.rows=t.rows-1;
  156.             for r=row,t.rows,1 do
  157.                 t[r],t[r+1] = t[r+1],t[r];
  158.             end
  159.         end
  160.     end
  161.  
  162.     local function FW_ERASE2(t) -- erases my 2d tables ONLY
  163.         t.rows = 0; -- lol :p
  164.     end
  165.    
  166.     local function FW_FIND(t,v,c) -- find value v in '2d table' t at column c, returns ROW
  167.         for r=1,t.rows,1 do
  168.             if t[r][c]==v then
  169.                 return r;
  170.             end
  171.         end
  172.     end
  173.  
  174.     local function FW_FIND2(t,v1,c1,v2,c2) -- returns ROW
  175.         for r=1,t.rows,1 do
  176.             if t[r][c1]==v1 and t[r][c2]==v2 then
  177.                 return r;
  178.             end
  179.         end
  180.     end
  181.  
  182.     local function FW_FIND3(t,v1,c1,v2,c2,v3,c3) -- returns ROW
  183.         for r=1,t.rows,1 do
  184.             if t[r][c1]==v1 and t[r][c2]==v2 and t[r][c3]==v3 then
  185.                 return r;
  186.             end
  187.         end
  188.     end
  189.  
  190.     local function FW_SETKEY(t,k,...) -- Set a row with 'key', MUST have the same num columns!
  191.         local n = FW_FIND(t,k,1);
  192.         if n then
  193.             for i=1,select('#',...),1 do
  194.                 t[n][i+1] = select(i,...);
  195.             end
  196.         else
  197.             FW_INS(t,k,...);
  198.         end
  199.     end
  200.  
  201.     local function FW_P(t)
  202.         local str;
  203.         for r=1,t.rows,1 do
  204.             str = r..":";
  205.             for c=1,#t[r],1 do
  206.                 str = str.." ["..c.."]"..tostring(t[r][c]);
  207.             end
  208.             FW:Show(str);
  209.         end
  210.     end
  211.  
  212.     function FW:NEW2D() -- CURRENTLY ONLY SUPPORTS A STATIC NUMBER OF COLUMNS (for one 2d table) TO INCREASE PERFORMANCE!!
  213.         local t = {};
  214.         t.rows = 0;
  215.         t.erase = FW_ERASE2;
  216.         t.remove = FW_REM;
  217.         t.insert = FW_INS;
  218.         t.find = FW_FIND;
  219.         t.find2 = FW_FIND2;
  220.         t.find3 = FW_FIND3;
  221.         t.sort = FW_BST;
  222.         t.setkey = FW_SETKEY;
  223.         t.print = FW_P;
  224.         return t;
  225.     end
  226. end
  227.  
  228. ----------------------------------------------------------------------------------------------------------------------------
  229. ----------------------------------------------------------------------------------------------------------------------------
  230. ----------------------------------------------------------------------------------------------------------------------------
  231. local LastRess;
  232. local LeaveCombat;
  233.  
  234. local function FW_EnterCombat()
  235.     --FW:Debug("enter combat");
  236.     for i,f in ipairs(FW_OnEnterCombat) do
  237.         f();
  238.     end
  239.     STATES.INCOMBAT = true;
  240. end
  241. local function FW_LeaveCombat()
  242.     --FW:Debug("leave combat");
  243.     STATES.INCOMBAT = false;
  244.     for i,f in ipairs(FW_OnLeaveCombat) do
  245.         f();
  246.     end
  247. end
  248.  
  249. local function FW_Ress()
  250.     if not UnitIsDeadOrGhost("player") and not LastRess then
  251.         LastRess = GetTime()+5; -- wait 5 seconds with checking combat
  252.     end
  253. end
  254.  
  255. local InCombatLockdown = InCombatLockdown;
  256. local function FC_ExtraCombatCheck()
  257.     if not InCombatLockdown() then FW_LeaveCombat(); end
  258. end
  259.  
  260. do -- update frame related stuff uses locals with the smallest scope possible
  261.     local FC_UpdateFrame = CreateFrame("Frame");
  262.     local FW_Events = {};
  263.     local FW_Updated = {};
  264.     local FC_DelayedExecQueue = FW:NEW2D();
  265.     local GetTime = GetTime;
  266.    
  267.     function FW:RegisterToEvent(event,func)
  268.         if not FW_Events[event] then
  269.             FC_UpdateFrame:RegisterEvent(event);
  270.             FW_Events[event] = {};
  271.         end
  272.         for i,f in ipairs(FW_Events[event]) do
  273.             if f == func then
  274.                 return;
  275.             end
  276.         end
  277.         tinsert(FW_Events[event],func);
  278.     end
  279.     function FW:UnregisterToEvent(event,func)
  280.         if not FW_Events[event] then return; end
  281.         for i,f in ipairs(FW_Events[event]) do
  282.             if f == func then
  283.                 tremove(FW_Events[event],i);
  284.                 if #FW_Events[event]==0 then
  285.                     FW_Events[event] = nil;
  286.                     FC_UpdateFrame:UnregisterEvent(event);
  287.                 end
  288.                 return;
  289.             end
  290.         end
  291.     end
  292.     function FW:RegisterUpdatedEvent(func)
  293.         tinsert(FW_Updated,func);
  294.     end
  295.  
  296.     function FW:UnregisterUpdatedEvent(func)
  297.         for i,f in ipairs(FW_Updated) do
  298.             if f == func then
  299.                 tremove(FW_Updated,i);
  300.                 return;
  301.             end
  302.         end
  303.     end
  304.  
  305.     function FW:DelayedExec(delay,times,func,...)
  306.         FC_DelayedExecQueue:insert(GetTime()+delay,delay,times,func,...);
  307.     end
  308.     local function FC_OnEvent(self,event,...)
  309.         --[[if strfind(event,"COMBAT_LOG") then
  310.             if strfind(select(2,...),"SPELL") then
  311.                 local d = GetTime().." "..event;
  312.                 for i=1,select('#',...),1 do
  313.                     if select(i,...) ~= nil then d = d.." #"..i..":"..tostring(select(i,...)); end
  314.                 end
  315.                 FW:Show(d,0,1,1);
  316.             end
  317.         end]]
  318.        
  319.         --if FW_Events[event] then -- check can be removed in theory... IF NOT ALL EVENTS ARE REGISTERED
  320.         for k,v in ipairs(FW_Events[event]) do
  321.             v(event,...);
  322.         end
  323.         --end
  324.     end
  325.     local FW_Timed = {};
  326.    
  327.     function FW:RegisterTimedEvent(interval,func)
  328.         if type(interval) == "string" then
  329.             if type(FW.Settings[interval]) == "table" then
  330.                 interval = FW.Settings[interval][1];
  331.             else
  332.                 if FW.Settings[interval] then
  333.                     interval = FW.Settings[interval];
  334.                 else
  335.                     FW:Show("error adding interval: "..interval);
  336.                 end
  337.             end
  338.         end
  339.         if not FW_Timed[interval] then
  340.             FW_Timed[interval] = {[0]=0};
  341.         end
  342.         tinsert(FW_Timed[interval],func);
  343.     end
  344.  
  345.     function FW:UnregisterTimedEvent(interval,func)
  346.         if type(interval) == "string" then
  347.             if type(FW.Settings[interval]) == "table" then
  348.                 interval = FW.Settings[interval][1];
  349.             else
  350.                 if FW.Settings[interval] then
  351.                     interval = FW.Settings[interval];
  352.                 else
  353.                     FW:Show("error removing interval: "..interval);
  354.                 end
  355.             end
  356.         end
  357.         if FW_Timed[interval] then
  358.             for i,f in ipairs(FW_Timed[interval]) do
  359.                 if f == func then
  360.                     tremove(FW_Timed[interval],i);
  361.                     return;
  362.                 end
  363.             end
  364.         end
  365.     end
  366.    
  367.     local function FC_OnUpdate(self, elapsed) -- normal onupdate
  368.         if LastRess and LastRess <= GetTime() then -- delays combat checking when you're ressed, so in case of a combat res or ss use your timers wont be cleared instantly
  369.             FC_ExtraCombatCheck();
  370.             LastRess = nil;
  371.         end
  372.         if LeaveCombat then -- this is only used when zoning, to make sure buttons arent still locked when FW_LeaveCombat is called
  373.             FC_ExtraCombatCheck();
  374.             LeaveCombat = nil;
  375.         end
  376.         -- run the timed events
  377.         for key, val in pairs(FW_Timed) do
  378.             FW_Timed[key][0] = FW_Timed[key][0] + elapsed;
  379.             if FW_Timed[key][0] >= key then
  380.                 FW_Timed[key][0] = FW_Timed[key][0]%key;
  381.                 for k, v in ipairs(FW_Timed[key]) do
  382.                     v();
  383.                 end
  384.             end
  385.         end
  386.         for i, f in ipairs(FW_Updated) do
  387.             f(elapsed);
  388.         end
  389.         -- delayed exec code
  390.         local t = GetTime();
  391.         local i = 1;
  392.         while i <= FC_DelayedExecQueue.rows do
  393.             if FC_DelayedExecQueue[i][1] <= t then
  394.                 FC_DelayedExecQueue[i][4](unpack(FC_DelayedExecQueue[i],5));
  395.                 if FC_DelayedExecQueue[i][3] > 1 then
  396.                     FC_DelayedExecQueue[i][3]=FC_DelayedExecQueue[i][3]-1;
  397.                     FC_DelayedExecQueue[i][1] = FC_DelayedExecQueue[i][1] + FC_DelayedExecQueue[i][2];
  398.                  else
  399.                     for k in ipairs(FC_DelayedExecQueue[i]) do -- erase all data so i can use any argument count
  400.                         FC_DelayedExecQueue[i][k] = nil;
  401.                     end
  402.                     FC_DelayedExecQueue:remove(i);
  403.                 end
  404.             else
  405.                 i=i+1;
  406.             end
  407.         end
  408.     end
  409.     local UILoaded;
  410.     local function FC_OnPreUpdate(self, elapsed) -- pre onupdate
  411.         if UILoaded then -- enable update actions 2 sec after UI is fully loaded
  412.             if GetTime() >= UILoaded then
  413.                 FC_UpdateFrame:SetScript("OnUpdate", FC_OnUpdate); -- start doing stuff when the addon is fully enabled!
  414.                 for i, f in ipairs(FW_DelayedLoaded) do
  415.                     f();
  416.                 end
  417.             end
  418.         elseif FW.Settings and FW.Settings.LoadDelay then
  419.             UILoaded = GetTime() + FW.Settings.LoadDelay;
  420.         end
  421.     end
  422.     FC_UpdateFrame:SetScript("OnEvent", FC_OnEvent);
  423.     FC_UpdateFrame:SetScript("OnUpdate", FC_OnPreUpdate);
  424.     --FC_UpdateFrame:RegisterAllEvents(); -- for debugging only
  425.     function FW:UnregisterAllEvents()
  426.         FC_UpdateFrame:UnregisterAllEvents();
  427.     end
  428. end
  429.  
  430. do
  431.     local type = type;
  432.     local origUnitAura = UnitAura;
  433.     local CustomIDToName = {};
  434.     local CustomNameToID = {};
  435.     FW.UnitAura = function(unit,buff,r,filter) -- works exactly like the original, but takes custom names into account
  436.         if type(buff) == "string" then
  437.             local id = CustomNameToID[buff];
  438.             if id then
  439.                 local i = 1;
  440.                 while true do
  441.                     local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId, canApplyAura, isBossDebuff, value1, value2, value3 = origUnitAura(unit,i,filter);
  442.                     if name then
  443.                         if id == spellId then
  444.                             return buff, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId, canApplyAura, isBossDebuff, value1, value2, value3;
  445.                         end
  446.                         i=i+1;
  447.                     else
  448.                         return nil;
  449.                     end
  450.                 end
  451.             else
  452.                 return origUnitAura(unit,buff,r,filter);
  453.             end
  454.         else
  455.             local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId, canApplyAura, isBossDebuff, value1, value2, value3 = origUnitAura(unit,buff,r,filter);
  456.             return CustomIDToName[spellId] or name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId, canApplyAura, isBossDebuff, value1, value2, value3;
  457.         end
  458.     end
  459.     function FW:SetCustomName(id,name)
  460.         CustomIDToName[id] = name;
  461.         CustomNameToID[name] = id;
  462.     end
  463.     local GetSpellInfo = GetSpellInfo;
  464.     function FW:SpellName(spell)
  465.         local s,_,t = GetSpellInfo(spell);
  466.         s = CustomIDToName[spell] or s;
  467.         if s then
  468.             if not FW.SpellInfo[s] then
  469.                 FW.SpellInfo[s] = {spell,0,0,0};
  470.             end
  471.             return s,t;
  472.         else
  473.             --FW:Show("spell:"..spell);
  474.             return "spell:"..spell;
  475.         end
  476.     end
  477. end
  478.  
  479. FW.Sets = {};
  480.  
  481. FW.BORDER = 3;
  482. --FW.pet,target,focus is also non-nil (guid) when present
  483. FW.PLAYER = UnitName("player");
  484. FW.CLASS = select(2,UnitClass("player"));
  485. FW.SERVER = GetRealmName();
  486. FW.RACE = select(2,UnitRace("player"));
  487.  
  488. FW.ID_HEALTHSTONE = 5512;
  489.  
  490. FW.OPTION_COLOR = {};
  491. FW.OPTION_COLOR.CLASS = {RAID_CLASS_COLORS[FW.CLASS].r,RAID_CLASS_COLORS[FW.CLASS].g,RAID_CLASS_COLORS[FW.CLASS].b};
  492. FW.OPTION_COLOR.COOLDOWN = {0.00,1.00,0.50};
  493. FW.OPTION_COLOR.TIMER = {1.00,0.50,0.00};
  494.  
  495. FW.OPTION_COLOR.SOULSTONE = {0.55,0.00,0.70};
  496. FW.OPTION_COLOR.SHARD = {0.55,0.00,0.70};
  497. FW.OPTION_COLOR.HEALTHSTONE = {0.00,1.00,0.00};
  498. FW.OPTION_COLOR.SHARDMANAGER = {0.55,0.00,0.70};
  499. FW.OPTION_COLOR.SUMMON = {0.55,0.00,0.70};
  500. FW.OPTION_COLOR.TALENT = {1.00,0.00,0.00};
  501.  
  502. FW.OPTION_COLOR.RAIDMESSAGES = {0.00,0.50,1.00};
  503. FW.OPTION_COLOR.SELFMESSAGES = {0.00,0.50,1.00};
  504. FW.OPTION_COLOR.SOUND = {0.00,0.50,1.00};
  505. FW.OPTION_COLOR.ABOUT = {1.00,1.00,0.00};
  506.  
  507. FW.FLAG = {};
  508. FW.FLAG.RES = 0; -- can res with ss
  509. FW.FLAG.DI = 1; -- is di-ed
  510. FW.FLAG.TIME = 2; -- normal soulstone duration
  511. FW.FLAG.WARLOCK = 6203; -- Soulstone
  512. FW.FLAG.DRUID = 20484; -- Rebirth
  513. FW.FLAG.PALADIN = 114153; -- Divine Intervention MOP
  514. FW.FLAG.SHAMAN = 20608; -- Reincarnation
  515.  
  516. FW.ORA3_COOLDOWN = "^1^SCooldown^N%d^N%d^^";
  517.  
  518. FW.FLAG.LEFT = -2;
  519. FW.FLAG.OFFLINE = -1;
  520. FW.FLAG.NORMAL = 0;
  521. FW.FLAG.UNKNOWN = 1;
  522. FW.FLAG.DEAD = 2;
  523.  
  524. FW.FILTER_ALWAYS = 3;
  525. FW.FILTER_SHOW = 1;
  526. FW.FILTER_NONE = 0;
  527. FW.FILTER_HIDE = -1;
  528. FW.FILTER_COLOR = -2;
  529. FW.FILTER_SHOW_COLOR = 2;
  530.  
  531. FW.RaidIcons = {"{rt1}","{rt2}","{rt3}","{rt4}","{rt5}","{rt6}","{rt7}","{rt8}"};
  532.  
  533. FW.FontList = {};
  534. FW.SoundList = {};
  535. FW.BorderList = {};
  536. FW.BackgroundList = {};
  537.  
  538. --[[function FW:RT(val,roundto)
  539.     FW:Show(tostring(FW:RoundTo(val,roundto)));
  540. end]]
  541.  
  542. function FW:RoundTo(val,roundto)
  543.     if not roundto or roundto <= 0 then
  544.         return val;
  545.     end
  546.     local f = 100;
  547.     val = f*val;
  548.     roundto = f*roundto;
  549.    
  550.     local remain = val%roundto;
  551.     val = val - remain;
  552.     if remain >= roundto*0.5 then
  553.         return (val + roundto)/f;
  554.     elseif remain < -roundto*0.5 then
  555.         return (val - roundto)/f;
  556.     else
  557.         return val/f;
  558.     end
  559. end
  560.  
  561. function FW:Show(msg,r,g,b,a) DEFAULT_CHAT_FRAME:AddMessage(tostring(msg),r,g,b,a); end
  562.  
  563. function FW:Debug(msg) if FW_Debug then FW:Show("Debug: "..tostring(msg),1,0.5,0); end end
  564.  
  565. function FW:RegisterFont(path,name)
  566.     tinsert(FW.FontList,{path,name});
  567. end
  568.  
  569. function FW:RegisterBorder(path,name)
  570.     tinsert(FW.BorderList,{path,name});
  571. end
  572.  
  573. function FW:RegisterBackground(path,name)
  574.     tinsert(FW.BackgroundList,{path,name});
  575. end
  576.  
  577. function FW:RegisterSound(path,name)
  578.     tinsert(FW.SoundList,{path,name});
  579. end
  580.  
  581. function FW:SetDefaultFont(path,size)
  582.     FW.Default.Font = {path,size};
  583.      -- setting the options default font here makes more sense
  584.     FW.Default.OptionsFont = FW.Default.Font;
  585.     FW.Default.OptionsHeaderFont = {};
  586.     if FW.Default.Font[1] == "Interface\\AddOns\\Forte_Core\\Fonts\\GOTHIC.TTF" then
  587.         FW.Default.OptionsHeaderFont[1] = "Interface\\AddOns\\Forte_Core\\Fonts\\GOTHICB.TTF";
  588.     else
  589.         FW.Default.OptionsHeaderFont[1] = FW.Default.Font[1];
  590.     end
  591.     FW.Default.OptionsHeaderFont[2] = FW.Default.Font[2];
  592. end
  593.  
  594. FW.ERASE = function(t) -- erases any table
  595.     for k in pairs(t) do
  596.         if type(t[k])=="table" then
  597.             FW.ERASE(t[k]);
  598.         end
  599.         t[k]= nil;
  600.     end
  601. end
  602. local erase = FW.ERASE;
  603.  
  604. FW:RegisterFont("Fonts\\ARIALN.TTF", "Arial Narrow");
  605. FW:RegisterFont("Fonts\\FRIZQT__.TTF", "Friz Quadrata TT");
  606. FW:RegisterFont("Fonts\\MORPHEUS.TTF", "Morpheus");
  607. FW:RegisterFont("Fonts\\SKURRI.TTF", "Skurri");
  608. FW:RegisterFont("Interface\\AddOns\\Forte_Core\\Fonts\\FORTE.TTF", "Forte");
  609. FW:RegisterFont("Interface\\AddOns\\Forte_Core\\Fonts\\HandelGothicBT.TTF", "Handel Gothic BT");
  610. FW:RegisterFont("Interface\\AddOns\\Forte_Core\\Fonts\\GOTHIC.TTF", "Century Gothic");
  611. FW:RegisterFont("Interface\\AddOns\\Forte_Core\\Fonts\\GOTHICB.TTF", "Century Gothic Bold");
  612.  
  613. FW:RegisterBorder("None", "None");
  614. FW:RegisterBorder("Interface\\AddOns\\Forte_Core\\Textures\\Border", "ForteXorcist");
  615.  
  616. FW:RegisterBackground("None", "None");
  617. FW:RegisterBackground("Interface\\AddOns\\Forte_Core\\Textures\\Background", "ForteXorcist");
  618. FW:RegisterBackground("Interface\\AddOns\\Forte_Core\\Textures\\Otravi", "Otravi");
  619. FW:RegisterBackground("Interface\\AddOns\\Forte_Core\\Textures\\Smooth", "Smooth");
  620.  
  621. FW:RegisterSound("Interface\\AddOns\\Forte_Core\\Sounds\\SoulstoneExpire.mp3", "FX: Soulstone Expire");
  622. FW:RegisterSound("Sound\\Spells\\SoulstoneResurrection_Base.wav","Soulstone");
  623. FW:RegisterSound("Sound\\Spells\\EnlargeCast.wav","Enlarge");
  624. FW:RegisterSound("Sound\\Spells\\FluteRun.wav","Flute");
  625. FW:RegisterSound("Sound\\Spells\\ShadowWard.wav","Shadow Ward");
  626. FW:RegisterSound("Sound\\Spells\\ShadowWordSilence.wav","Silence");
  627. FW:RegisterSound("Sound\\Spells\\ShadowWordPain_Chest.wav","Shadow Word Pain");
  628. FW:RegisterSound("Sound\\Spells\\ShadowWordFumble.wav","Fumble");
  629. FW:RegisterSound("Sound\\Spells\\AntiHoly.wav","Anti Holy");
  630. FW:RegisterSound("Sound\\Spells\\Bonk1.wav","Bonk1");
  631. FW:RegisterSound("Sound\\Spells\\Bonk2.wav","Bonk2");
  632. FW:RegisterSound("Sound\\Spells\\Bonk3.wav","Bonk3");
  633. FW:RegisterSound("Sound\\Spells\\consume_magic_impact.wav","Consume Magic");
  634. FW:RegisterSound("Sound\\Spells\\Creature_SpellPortalLarge_All_Colors.wav","Spell Portal");
  635. FW:RegisterSound("Sound\\Spells\\Ingvar_ResurrectionGroundVisual.wav","Resurrection Ground");
  636. FW:RegisterSound("Sound\\Spells\\Resurrection.wav","Resurrection");
  637. FW:RegisterSound("Sound\\Spells\\Rogue_shadowdance_state.wav","Shadow Dance");
  638. FW:RegisterSound("Sound\\Spells\\ShaysBell.wav","Shay's Bell");
  639. FW:RegisterSound("Sound\\Spells\\SimonGame_Visual_BadPress.wav","Simon Error");
  640. FW:RegisterSound("Sound\\Spells\\SimonGame_Visual_GameFailedLarge.wav","Simon Failed Large");
  641. FW:RegisterSound("Sound\\Spells\\SimonGame_Visual_GameFailedSmall.wav","Simon Failed Small");
  642. FW:RegisterSound("Sound\\Spells\\SimonGame_Visual_GameStart.wav","Simon Start");
  643. FW:RegisterSound("Sound\\Spells\\SimonGame_Visual_GameTick.wav","Simon Tick");
  644. FW:RegisterSound("Sound\\Spells\\SimonGame_Visual_LevelStart.wav","Simon Level Start");
  645.  
  646. FW.TextureList = {
  647.     "Interface\\AddOns\\Forte_Core\\Textures\\Aluminium",
  648.     "Interface\\AddOns\\Forte_Core\\Textures\\Minimalist",
  649.     "Interface\\AddOns\\Forte_Core\\Textures\\Xus",
  650.     "Interface\\AddOns\\Forte_Core\\Textures\\Otravi",
  651.     "Interface\\AddOns\\Forte_Core\\Textures\\LiteStep",
  652.     "Interface\\AddOns\\Forte_Core\\Textures\\BantoBar",
  653.     "Interface\\AddOns\\Forte_Core\\Textures\\Charcoal",
  654.     "Interface\\AddOns\\Forte_Core\\Textures\\Perl",
  655.     "Interface\\AddOns\\Forte_Core\\Textures\\Smooth",
  656.     "Interface\\AddOns\\Forte_Core\\Textures\\Smudge",
  657.     "Interface\\AddOns\\Forte_Core\\Textures\\Striped",
  658.     "Interface\\AddOns\\Forte_Core\\Textures\\Glaze",
  659.     "Interface\\AddOns\\Forte_Core\\Textures\\Frost",
  660.     "Interface\\AddOns\\Forte_Core\\Textures\\HealBot",
  661.     "Interface\\AddOns\\Forte_Core\\Textures\\Rocks",
  662.     "Interface\\AddOns\\Forte_Core\\Textures\\Runes",
  663.     "Interface\\AddOns\\Forte_Core\\Textures\\Xeon",
  664.     "Interface\\AddOns\\Forte_Core\\Textures\\SWSDefault",
  665.     "Interface\\AddOns\\Forte_Core\\Textures\\Flat",
  666.     "Interface\\TargetingFrame\\UI-StatusBar",
  667.     "Interface\\PaperDollInfoFrame\\UI-Character-Skills-Bar",
  668. };
  669.  
  670. function FW:SoundName(sound)
  671.     for i, data in ipairs(FW.SoundList) do
  672.         if strlower(data[1]) == strlower(sound) then
  673.             return data[2];
  674.         end
  675.     end
  676.     return "Custom Sound";
  677. end
  678.  
  679. function FW:FontName(font)
  680.     for i, data in ipairs(FW.FontList) do
  681.         if strlower(data[1]) == strlower(font) then
  682.             return data[2];
  683.         end
  684.     end
  685.     return "Custom Font";
  686. end
  687.  
  688. function FW:TypeName(t,list)
  689.     for i, data in ipairs(list) do
  690.         if data[1] == t then
  691.             return data[2];
  692.         end
  693.     end
  694. end
  695.  
  696. FW.Modules = {};
  697. function FW:ClassModule(module) -- only difference is setting the class module variable
  698.     FW.ClassModules = module;
  699.     return FW:Module(module,1);
  700. end
  701. function FW:Module(module,create)
  702.     FW.Modules[module] = FW.Modules[module] or (create and {}) or nil;
  703.     return FW.Modules[module];
  704. end
  705.  
  706. local DeleteOld = 1800;
  707.  
  708. FW.GET_SHARDS = "SG";
  709. FW.GET_HEALTHSTONE = "HG"
  710. FW.SEND_HEALTHSTONE = "HS";
  711. FW.SEND_SHARDS = "SH";
  712.  
  713. local SEND_VERSION = "VE"
  714. local GET_VERSION = "VG";
  715. local GET_SPECC = "SPG";
  716. local SEND_SPECC = "SPS";
  717.  
  718. FW.LastHSCheck = 0;
  719.  
  720. FW.Healthstone = {};
  721.  
  722. FW.Zones = {};
  723. FW.Ranks = {};
  724. FW.Ready = {};
  725.  
  726. FW.SetBonus = {};
  727. FW.Talent = {};
  728. FW.Glyph = {};
  729.  
  730. FW.SpellInfo = {};-- id [,casttime,minrange,maxrange]
  731.  
  732. do
  733.     local SpecialCastTimes = {};
  734.     function FW:RegisterSpecialCastTime(spell,func)
  735.         spell = FW:SpellName(spell);
  736.         SpecialCastTimes[spell] = func;
  737.     end
  738.  
  739.     function FW:CastTime(spell)
  740.         if SpecialCastTimes[spell] then
  741.             return SpecialCastTimes[spell]() or 0;
  742.         else
  743.             return FW.SpellInfo[spell] and FW.SpellInfo[spell][2] or 0;
  744.         end
  745.     end
  746. end
  747.  
  748. function FW:SpellId(name)
  749.     return FW.SpellInfo[name][1] or name;
  750. end
  751.  
  752. function FW:FrameScaleCheck(editbox)
  753.     local num = tonumber(editbox:GetText());
  754.     if num then
  755.         if num < 0.2 then
  756.             return 0.2;
  757.         elseif num > 5.0 then
  758.             return 5.0;
  759.         end
  760.         return num;
  761.     end
  762. end
  763. function FW:FrameAlphaCheck(editbox)
  764.     local num = tonumber(editbox:GetText());
  765.     if num then
  766.         if num < 0.1 then
  767.             return 0.1;
  768.         elseif num > 1.0 then
  769.             return 1.0;
  770.         end
  771.         return num;
  772.     end
  773. end
  774.  
  775. function FW:NumberCheck(editbox)
  776.     local num = tonumber(editbox:GetText());
  777.     if num then
  778.         if editbox.maximum and num>editbox.maximum then
  779.             return editbox.maximum;
  780.         elseif editbox.minimum and num<editbox.minimum then
  781.             return editbox.minimum;
  782.         end
  783.         return num;
  784.     end
  785. end
  786.  
  787. function FW:GetNumSpellBookSpells()
  788.     local num = 0;
  789.     for i = 1, GetNumSpellTabs() do
  790.         local _, _, _, numSpells, _ = GetSpellTabInfo(i);
  791.         num = num + numSpells;
  792.     end
  793.     return num;
  794. end
  795.  
  796. do
  797.     local max = math.max;
  798.     function FW:FixIntensity(r,g,b)
  799.         local largest = max(max(r,g),b);
  800.         if largest == 1 then
  801.             return 0.7*r+0.3,0.7*g+0.3,0.7*b+0.3;
  802.         elseif largest > 0 and largest < 1 then
  803.             return 0.7*r/largest+0.3,0.7*g/largest+0.3,0.7*b/largest+0.3;
  804.         else
  805.             return 1,1,1;
  806.         end
  807.     end
  808.  
  809.     local GetItemInfo = GetItemInfo;
  810.     function FW:ItemName(item)
  811.         local name = GetItemInfo(item);
  812.         if name then
  813.             return name,true;
  814.         else
  815.             return "item:"..item,false;
  816.         end
  817.     end
  818.     local UnitGUID = UnitGUID;
  819.     function FW:Changed(unit)
  820.         FW[unit] = UnitGUID(unit);
  821.     end
  822.    
  823.     local GameTooltip = _G.GameTooltip;
  824.     local GameTooltip_SetDefaultAnchor = _G.GameTooltip_SetDefaultAnchor;
  825.     function FW:ShowTip(self)
  826.         if self.tip and self.title and FW.Settings.Tips then
  827.             GameTooltip_SetDefaultAnchor(GameTooltip, self);
  828.             GameTooltip:SetText(self.title, 1.0, 1.0, 1.0);
  829.             GameTooltip:AddLine(self.tip, _G.NORMAL_FONT_COLOR.r, _G.NORMAL_FONT_COLOR.g, _G.NORMAL_FONT_COLOR.b, 1);
  830.             GameTooltip:Show();
  831.         end
  832.     end
  833.    
  834.     function FW:ShowSpellTip(self)
  835.         if FW.Settings.Tips then
  836.             if self.token == "" then
  837.                 local i = 1;
  838.                 local spell;
  839.                 local m = FW:GetNumSpellBookSpells();
  840.                 while i<=m do
  841.                     spell = select(2,GetSpellBookItemInfo(i,"player"));
  842.                     if spell then
  843.                         spell = FW:SpellName(spell);
  844.                         --FW:Show(spell);
  845.                         if (spell == self.spell) then
  846.                             GameTooltip_SetDefaultAnchor(GameTooltip, self);
  847.                             GameTooltip:SetSpellBookItem(i,"player");
  848.                             --GameTooltip:AddLine(self.tip, _G.NORMAL_FONT_COLOR.r, _G.NORMAL_FONT_COLOR.g, _G.NORMAL_FONT_COLOR.b, 1);
  849.                             GameTooltip:Show();
  850.                             return;
  851.                         end
  852.                         i=i+1;
  853.                     else
  854.                         break;
  855.                     end
  856.                 end
  857.                 i=1;
  858.                 while true do
  859.                     spell = select(2,GetSpellBookItemInfo(i,"pet"));
  860.                     if spell then
  861.                         spell = FW:SpellName(spell);
  862.                         --FW:Show(spell);
  863.                         if (spell == self.spell) then
  864.                             GameTooltip_SetDefaultAnchor(GameTooltip, self);
  865.                             GameTooltip:SetSpellBookItem(i,"pet");
  866.                             --GameTooltip:SetText(self.title, 1.0, 1.0, 1.0);
  867.                             --GameTooltip:AddLine(self.tip, _G.NORMAL_FONT_COLOR.r, _G.NORMAL_FONT_COLOR.g, _G.NORMAL_FONT_COLOR.b, 1);
  868.                             GameTooltip:Show();
  869.                             return;
  870.                         end
  871.                         i=i+1;
  872.                     else
  873.                         break;
  874.                     end
  875.                 end
  876.             else
  877.                 GameTooltip_SetDefaultAnchor(GameTooltip, self);
  878.                 GameTooltip:SetUnitAura(self.token,self.buffid,self.friendly == 1 and "HELPFUL" or "HARMFUL");
  879.                 GameTooltip:Show();
  880.             end
  881.         end
  882.     end
  883.    
  884.     local HideUIPanel = HideUIPanel;
  885.     function FW:HideTip(self)
  886.         HideUIPanel(GameTooltip);
  887.     end
  888. end
  889.  
  890. local function FW_VersionCheck()
  891.     FW:SendData(GET_VERSION);
  892. end
  893. --[[local function FW_GetSpeccInfo()
  894.     FW:SendData(GET_SPECC);
  895. end]]
  896.  
  897. local function FW_MakeSpeccInfo(inspect) -- creates you own specc information string, or that of someone you're inspecting
  898.     --[[local player,class;
  899.     if inspect then
  900.         if not InspectFrame or not InspectFrame.unit then return; end -- avoid saving wrong speccs to the wrong ppl for now!!
  901.         player = UnitName("target");
  902.         class = select(2,UnitClass("target"));
  903.         if not player or not class or (not UnitInParty("target") and not UnitInRaid("target")) or player == FW.PLAYER then return;end
  904.     else
  905.         player = FW.PLAYER;
  906.         class = FW.CLASS;
  907.     end
  908.     --FW:Show("building talents for "..player);
  909.     local currentRank;
  910.     local str = "";
  911.     for tab=1,GetNumSpecializations(inspect),1 do
  912.         for i=1,GetNumTalents(tab,inspect),1 do
  913.             currentRank = ( select( 5,GetTalentInfo(tab,i,inspect,nil,GetActiveSpecGroup(inspect)) ) );
  914.             if currentRank > 0 then
  915.                 str = str..strformat("%02d",i)..currentRank;
  916.             end
  917.         end
  918.         str=str.." ";
  919.     end
  920.     if not FX_Saved.Speccs[class] then
  921.         FX_Saved.Speccs[class] = {};
  922.     end
  923.     FX_Saved.Speccs[class][player] = str.."00";]]
  924.     -- will later use the last digits for other classes as well, for now it's always zero for non-warlocks
  925. end
  926.  
  927. ------------------------------------------------------------------------------------------------------------------
  928. local FW_Scans = {};
  929. local UnitIsConnected = UnitIsConnected;
  930. local UnitIsDeadOrGhost = UnitIsDeadOrGhost;
  931. --FW.Online = {};
  932.  
  933. local function FW_ScanUnit(unit,update)
  934.     local unitName = UnitName(unit);
  935.     local _, unitClass = UnitClass(unit);
  936.     local flag;
  937.     if UnitIsConnected(unit) then
  938.         if UnitIsDeadOrGhost(unit) then
  939.             flag = FW.FLAG.DEAD;
  940.         else
  941.             flag = FW.FLAG.NORMAL;
  942.         end
  943.     else
  944.         flag = FW.FLAG.OFFLINE;
  945.     end
  946.    
  947.     for i,f in ipairs(FW_Scans) do
  948.         f(unit,unitName,unitClass,flag,update);
  949.     end
  950. end
  951.  
  952.  
  953. local function FW_Scan()
  954.     local update = GetTime();
  955.     FW:RosterInfo();
  956.     for k in pairs(FX_Saved.RaidStatus) do -- in case i want to be able to tell who left the raid
  957.         FX_Saved.RaidStatus[k][1] = FW.FLAG.LEFT;
  958.     end
  959.     FW:ForGroupMembers(FW_ScanUnit,update);
  960.     FX_Saved.Update = update;
  961.     -- updating raw data complete
  962. end
  963.  
  964. local fx2temp = {};
  965. local ora3temp = {};
  966.  
  967. local function FW_RaidStatusScan(unit,unitName,unitClass,flag,update)
  968.     if not FX_Saved.RaidStatus[unitName] then
  969.         FX_Saved.RaidStatus[unitName] = {flag,update,unitClass,(unitName==FW.PLAYER and VERSION) or fx2temp[unitName] or (unitName==FW.PLAYER and _G.oRA3 and _G.oRA3.VERSION) or ora3temp[unitName]};
  970.     end
  971.     FX_Saved.RaidStatus[unitName][1] = flag;
  972.     FX_Saved.RaidStatus[unitName][3] = unitClass;
  973.     if flag ~= FW.FLAG.OFFLINE then
  974.         FX_Saved.RaidStatus[unitName][2] = update;
  975.     end
  976. end
  977.  
  978. local SpecialSaved = {};
  979. local function FW_Reset()
  980.     for k, v in pairs(SpecialSaved) do
  981.         if v==true then
  982.             erase(FX_Saved[k]);
  983.         end
  984.     end
  985. end
  986.  
  987. local function FW_ResetOld(t)
  988.     for k, v in pairs(FX_Saved.RaidStatus) do
  989.         if (t-v[2] > DeleteOld) then
  990.             FX_Saved.RaidStatus[k] = nil;
  991.         end
  992.     end
  993.     for key, val in pairs(SpecialSaved) do
  994.         if val==true then
  995.             for k, v in pairs(FX_Saved[key]) do
  996.                 if k == "Timers" then -- still old style
  997.                     if (t-v[2] > DeleteOld) then
  998.                         FX_Saved[key][k] = nil;
  999.                     end
  1000.                 elseif not FX_Saved["RaidStatus"][k] then
  1001.                     FX_Saved[key][k] = nil;
  1002.                 end
  1003.             end
  1004.         end
  1005.     end
  1006. end
  1007.  
  1008. local function FW_RefreshAllFilters()
  1009.     for i,f in ipairs(FilterRefresh) do
  1010.         f();
  1011.     end
  1012. end
  1013.  
  1014. --[[do
  1015.     local type = type;
  1016.     local function MatchOption(self,from,to,name)
  1017.         if type(from[name]) == type(to[name]) then
  1018.             if type(from[name]) == "table" then
  1019.                 local m = true;
  1020.                 for k, v in pairs(from[name]) do
  1021.                     if not MatchOption(self,from[name],to[name],k) then
  1022.                         m = false;
  1023.                         break;
  1024.                     end
  1025.                 end
  1026.                 return m;
  1027.             else
  1028.                 return to[name] == from[name];
  1029.             end
  1030.         else
  1031.             return false;
  1032.         end
  1033.     end
  1034.  
  1035.     FW.MatchOption = MatchOption;
  1036. end
  1037. do
  1038.     local type = type;
  1039.     function CopyOption(self,from,to,name)
  1040.         if type(from[name]) == "table" then
  1041.             if type(to[name]) == "table" then
  1042.                 erase(to[name]);
  1043.             else
  1044.                 to[name] = {};
  1045.             end
  1046.             for k, v in pairs(from[name]) do
  1047.                 CopyOption(self,from[name],to[name],k)
  1048.             end
  1049.         else
  1050.             to[name] = from[name];
  1051.         end
  1052.     end
  1053.     FW.CopyOption = CopyOption;
  1054. end
  1055. ]]
  1056.  
  1057. local function FW_CopyNew(from,to) -- copies only new values or values of wrong old type
  1058.     for key, val in pairs(from) do
  1059.         if type(val) == "table" then
  1060.             if to[key] == nil or type(to[key]) ~= "table" then
  1061.                 to[key] = {};
  1062.             end
  1063.             FW_CopyNew(val,to[key]);
  1064.         else
  1065.             if to[key] == nil or type(to[key]) ~= type(from[key]) then
  1066.                 to[key] = val;
  1067.             end
  1068.         end
  1069.     end
  1070. end
  1071.  
  1072. function FW:CopyCloneSettings(from,to)
  1073.     FW_CopyNew(from,to);
  1074. end
  1075.  
  1076. function FW:FullName()
  1077.     return FW.PLAYER.."-"..FW.SERVER;
  1078. end
  1079.  
  1080. local function FW_InitConfig()
  1081.     if FW.Saved.Profiles.Characters[FW:FullName()] then -- load the proper profile or use the last used one if loading for the first time
  1082.         FW:UseProfile(FW.Saved.Profiles.Characters[FW:FullName()],1); -- <-- new style profiles
  1083.     else
  1084.         FW:UseProfile(FW.Saved.Profiles.Active,1); -- <-- simply use the last active profile if i can't find any match
  1085.     end
  1086. end
  1087.  
  1088. function FW:FixStringFormat(str)
  1089.     str = gsub(str,"%%","%%%%");
  1090.     str = gsub(str,"%%%%s","%%s");
  1091.     return str;
  1092. end
  1093.  
  1094. local function fixTimerSettings19743(settings)
  1095.     if settings then
  1096.         if settings["Time"] ~= nil then
  1097.             settings["TimeRight"] = settings["Time"];
  1098.             settings["Time"] = true;
  1099.         end
  1100.     end
  1101. end
  1102.  
  1103. local function renameOption(from,to,settings)
  1104.     if settings[from] then
  1105.         settings[to] = settings[from];
  1106.         settings[from] = nil;
  1107.     end
  1108. end
  1109.  
  1110. local function fixCooldownSettings19746(settings)
  1111.     if settings then
  1112.         if settings["IconTextColor"] ~= nil then
  1113.             if settings["IconTextColor"][4] == 0.00 and settings["IconTextEnable"] == true then
  1114.                 settings["IconText"] = false;
  1115.                 settings["IconTextColor"][4] = 1.00;
  1116.             end
  1117.         end
  1118.     end
  1119. end
  1120. local function fixCooldownSettings1975(settings)
  1121.     if settings then
  1122.         if settings["IconText"] ~= nil then
  1123.             settings["IconTime"] = settings["IconText"];
  1124.             settings["IconText"] = nil;
  1125.         end
  1126.     end
  1127. end
  1128.  
  1129. local function fixTimerSettings(settings)
  1130.     if settings then
  1131.         -- fix downgrade-upgrade bug...
  1132.         if type(settings["Blink"]) == "boolean" then
  1133.             settings["BlinkEnable"] = settings["Blink"] or true;
  1134.             settings["Blink"] = 3;
  1135.         end
  1136.  
  1137.         -- fix spark settings
  1138.         if type(settings["Spark"]) == "boolean" then
  1139.             settings["SparkEnable"] = true;
  1140.             settings["Spark"] = 0.7;
  1141.             settings["SparkColor"]  = nil;
  1142.         end
  1143.        
  1144.         if type(settings["CastSpark"]) == "boolean" then
  1145.             settings["CastSparkEnable"] = settings["CastSpark"] or true;
  1146.             settings["CastSpark"] = 0.3;
  1147.         end
  1148.         if type(settings["Ticks"]) == "boolean" then
  1149.             settings["TicksEnable"] = settings["Ticks"] or true;
  1150.             settings["Ticks"] = 0.3;
  1151.         end
  1152.        
  1153.         -- fix raid icon setting
  1154.         if type(settings["RaidTargets"]) == "boolean" then
  1155.             settings["RaidTargetsEnable"] = settings["RaidTargets"] or false;
  1156.             settings["RaidTargets"] = settings["RaidTargetsAlpha"] or 0.7;
  1157.         end
  1158.        
  1159.         if settings["Filter"] then
  1160.             -- fix old unknown spells that got saved as numbers
  1161.             for k,v in pairs(settings["Filter"]) do
  1162.                 if type(k) == "number" then
  1163.                     settings["Filter"][k] = nil;
  1164.                 end
  1165.             end
  1166.         end
  1167.     end
  1168. end
  1169.  
  1170. local function fixCooldownSettings(settings)
  1171.     if settings then
  1172.         -- fix spark settings
  1173.         if type(settings["Spark"]) == "boolean" then
  1174.             settings["SparkEnable"] = true;
  1175.             settings["Spark"] = 1.0;
  1176.         end
  1177.         if settings["Filter"] then
  1178.             -- fix old unknown spells that got saved as numbers
  1179.             for k,v in pairs(settings["Filter"]) do
  1180.                 if type(k) == "number" then
  1181.                     settings["Filter"][k] = nil;
  1182.                 end
  1183.             end
  1184.         end
  1185.     end
  1186. end
  1187.  
  1188. local function fixFilterRenames(settings)
  1189.     --" - Bear" -> " (Bear)"
  1190.     --" - Cat" -> " (Cat)"
  1191.     if settings and settings["Filter"] then
  1192.         -- fix old unknown spells that got saved as numbers
  1193.         for k,v in pairs(settings["Filter"]) do
  1194.             local v1 = strfind(k," %- Bear");
  1195.             if v1 then
  1196.                 local newkey = strsub(k,0,v1-1).." (Bear)";
  1197.                 --local newkey = gsub(k," %- Bear$"," (Bear)");
  1198.                 settings["Filter"][newkey] = {settings["Filter"][k][1],settings["Filter"][k][2],settings["Filter"][k][3],settings["Filter"][k][4]};
  1199.                 settings["Filter"][k] = nil;
  1200.             end
  1201.             local v2 = strfind(k," %- Cat");
  1202.             if v2 then
  1203.                 local newkey = strsub(k,0,v2-1).." (Cat)";
  1204.                 settings["Filter"][newkey] = {settings["Filter"][k][1],settings["Filter"][k][2],settings["Filter"][k][3],settings["Filter"][k][4]};
  1205.                 settings["Filter"][k] = nil;
  1206.             end
  1207.         end
  1208.     end
  1209. end
  1210.  
  1211. local function fixOptions1975(settings)
  1212.     local _,f,t1,t2,t3,t4,t5;
  1213.     if settings then -- check if this group of settings exists
  1214.         settings["RAID"] = nil;
  1215.         settings["PARTY"] = nil;
  1216.         for k, v in pairs(settings) do
  1217.            
  1218.             if type(v) == "table" then
  1219.                 --COLOR type options
  1220.                 _,_,f = strfind(k,"(.+)Color$");
  1221.                 if f then
  1222.                     settings[k][0] = settings[f.."Enable"];
  1223.                     for i,v in ipairs(settings[k]) do
  1224.                         settings[k][i] = FW:RoundTo(settings[k][i],0.01); -- fix to 2 decimals only
  1225.                     end
  1226.                     settings[f.."Enable"] = nil;
  1227.                 end
  1228.             else
  1229.                 -- MSG type options
  1230.                 _,_,f = strfind(k,"(.+)Msg$");
  1231.                 if f then
  1232.                     t1 = settings[f];
  1233.                     t2 = settings[k];
  1234.                     settings[f] = {t2};
  1235.                     settings[f][0] = t1;
  1236.                     settings[k] = nil;
  1237.                 end
  1238.                 -- FONT type options
  1239.                 f = strfind(k,"Font$");
  1240.                 if f then
  1241.                     t1 = settings[k];
  1242.                     t2 = settings[k.."Size"];
  1243.                     settings[k] = {t1,t2};
  1244.                     settings[k.."Size"] = nil;
  1245.                 end
  1246.                 -- SOUND type options
  1247.                 f = strfind(k,"Sound$");
  1248.                 if f then
  1249.                     t1 = settings[k];
  1250.                     t2 = settings[k.."Volume"];
  1251.                     settings[k] = {t1,t2};
  1252.                     settings[k][0] = settings[k.."Enable"];
  1253.                     settings[k.."Volume"] = nil;
  1254.                     settings[k.."Enable"] = nil;
  1255.                 end
  1256.             end
  1257.         end
  1258.         -- DO THIS AFTER SOUND (because of SoundEnable)
  1259.         for k, v in pairs(settings) do
  1260.             if type(v) ~= "table" then
  1261.                 -- NU2 type options
  1262.                 _,_,f = strfind(k,"(.+)Enable$");
  1263.                 if f then
  1264.                     if type(settings[f])=="number" then
  1265.                         --FW:Show("found "..k);
  1266.                         t1 = settings[f];
  1267.                         t2 = settings[k];
  1268.                        
  1269.                         settings[f] = {t1};
  1270.                         settings[f][0] = t2;
  1271.                         settings[k] = nil;
  1272.                     end
  1273.                 end
  1274.             end
  1275.         end
  1276.     end
  1277. end
  1278.  
  1279. function FW:Popup1975(update)
  1280.     local txt = "|cff00ff00This version introduces 'Options linking'!\n\nYou can choose to link all your profiles and clones together now, and link the options that are the same everywhere. This will also automatically link every new profile or clone in the future.\n\nYou can always change or re-run this at 'Advanced Options > Options linking'.|r\n\n|cffffcc00Do you want to smart link everything now?\nSELECT 'NO' IF YOU'RE NOT SURE!|r";
  1281.     if update then
  1282.         txt = "|cffff6600Your settings are now converted for v1.975+. ForteXorcist keeps a backup of your current configuration in case you want to revert back to a previous version. If you go back to using a previous version, your settings will go back to this backup!|r\n\n"..txt;
  1283.     end
  1284.     if LUI_versions and tostring(LUI_versions.forte) < "v1.975" then
  1285.         txt = "|cffff0000This version of ForteXorcist is incompatible with your current version of LUI. Please install the latest version of LUI (or just the latest forte LUI module) or reinstall ForteXorcist v1.974.8.|r\n\n"..txt;
  1286.     end
  1287.     _G.StaticPopupDialogs["FX_MULTI_PURPOSE"].button1 = "Yes, smart link now!";
  1288.     _G.StaticPopupDialogs["FX_MULTI_PURPOSE"].button2 = "No thanks, maybe later.";
  1289.     _G.StaticPopupDialogs["FX_MULTI_PURPOSE"].OnAccept = FW.SmartLinkAll;
  1290.     _G.StaticPopup_Show("FX_MULTI_PURPOSE","A MESSAGE FROM FORTEXORCIST\n\n"..txt);
  1291. end
  1292.  
  1293. local function IsOldModuleLoaded()
  1294.     local loaded = false;
  1295.     local modules = {
  1296.         "Forte_DeathKnight",
  1297.         "Forte_Druid",
  1298.         "Forte_Hunter",
  1299.         "Forte_Mage",
  1300.         "Forte_Paladin",
  1301.         "Forte_Priest",
  1302.         "Forte_Rogue",
  1303.         "Forte_Shaman",
  1304.         "Forte_Vehicle",
  1305.         "Forte_Warlock",
  1306.         "Forte_Warrior"
  1307.     };
  1308.     for i,module in ipairs(modules) do
  1309.         if IsAddOnLoaded(module) then
  1310.             DisableAddOn(module);
  1311.             loaded = true;
  1312.         end
  1313.     end
  1314.    
  1315.     return loaded;
  1316. end
  1317.  
  1318. local function FW_Variables()
  1319.     FW:UnregisterToEvent("PLAYER_ENTERING_WORLD",   FW_Variables);
  1320.    
  1321.     local t = GetTime();
  1322.    
  1323.     FC_Saved = _G.FC_Saved; -- sets the local upval again
  1324.     FX_Saved = _G.FX_Saved; -- sets the local upval again
  1325.    
  1326.     if FW:Size(FX_Saved) == 0 then -- only copy if empty!!
  1327.         FW_CopyNew(FC_Saved,FX_Saved); -- rename saved table and keep old table in tact for now
  1328.     end
  1329.     FX_Saved.RESETTING = nil;
  1330.    
  1331.     FW.Saved = FX_Saved; -- use to access the saved table globally
  1332.    
  1333.     FW:RegisterSpecialSaved("Profiles",false,{Active=1,Characters={},Instances={{}},Data={{name=FW:FullName()}}, Links={}});
  1334.     FW:RegisterSpecialSaved("VERSION",false,"");
  1335.     FW:RegisterSpecialSaved("RAID",false,false);
  1336.     FW:RegisterSpecialSaved("GROUPED",false,false);
  1337.  
  1338.     FW:RegisterSpecialSaved("CATEGORIES",false,{});
  1339.    
  1340.     --FW:RegisterSpecialSaved("Speccs",false,{});
  1341.     FW:RegisterSpecialSaved("Exceptions",false,{});
  1342.     FW:RegisterSpecialSaved("Update",false,0);
  1343.    
  1344.     FW:RegisterSpecialSaved("RaidStatus",true,{});   -- need a last seen table
  1345.    
  1346.     FW:RegisterSpecialSaved("Timers",true,{}); -- old style
  1347.     FW:RegisterSpecialSaved("Cooldowns",true,{}); -- old style
  1348.  
  1349.     FW:RegisterSpecialSaved("Healthstone",true,{}); -- new style
  1350.  
  1351.     FW_CopyNew(FW.Exceptions,FX_Saved.Exceptions);
  1352.    
  1353.     --FX_Saved.VERSION = "v1.959.1"; -- REMOVE IF NOT TESTING!!!!!
  1354.     if IsOldModuleLoaded() then
  1355.         EnableAddOn("Forte_Class");
  1356.         local err = "|cffffffffYou still had old Class Modules enabled. These will automatically be disabled when you reload your interface. ForteXorcist will not function before you do this.\n\n To make sure you don't get this message on other characters, delete or disable Forte_DeathKnight, Forte_Druid, Forte_Hunter, Forte_Mage, Forte_Paladin, Forte_Priest, Forte_Rogue, Forte_Shaman, Forte_Vehicle, Forte_Warlock and Forte_Warrior.";
  1357.         _G.StaticPopupDialogs["FX_MULTI_PURPOSE"].button1 = "Okay, reload now";
  1358.         _G.StaticPopupDialogs["FX_MULTI_PURPOSE"].button2 = "No, reload later";
  1359.         _G.StaticPopupDialogs["FX_MULTI_PURPOSE"].OnAccept = ReloadUI;
  1360.         _G.StaticPopup_Show("FX_MULTI_PURPOSE","A MESSAGE FROM FORTEXORCIST\n\n"..err);
  1361.  
  1362.         FW:UnregisterAllEvents();
  1363.         FW.Settings = {};
  1364.         return;
  1365.     end
  1366.    
  1367.     if FX_Saved.VERSION ~= VERSION then -- version change
  1368.    
  1369.         -- !!! COMPATIBILITY FIXES - ONLY DONE ONCE SO MAKE SURE ALL PROFILES GET UPDATED AT ONCE !!! --
  1370.         -- always use real values for defaults in modules, since these defaults/modules may not be loaded
  1371.  
  1372.         if FX_Saved.VERSION ~= "" then
  1373.             -- this check is to fix the v1.975(.1) bug and will check if the format is really pre-v1.975
  1374.             if not FX_Saved.Profiles.Instances or FW:Size(FX_Saved.Profiles.Instances) == 0 then
  1375.            
  1376.                 if FX_Saved.VERSION < "v1.90" then
  1377.                     local err = "|cffff0000You are updating from a too old version. If you want to keep your settings and make this work, install and run v1.958 first and then this version. If you don't care about keeping your old settings they can be reset now. ForteXorcist will then restart as if it were a fresh install.|r\n\n|cffffcc00Do you want to reset ForteXorcist now?|r";
  1378.                     _G.StaticPopupDialogs["FX_MULTI_PURPOSE"].button1 = "Okay, wipe my settings";
  1379.                     _G.StaticPopupDialogs["FX_MULTI_PURPOSE"].button2 = "No, I will install v1.958";
  1380.                     _G.StaticPopupDialogs["FX_MULTI_PURPOSE"].OnAccept = Commands["resetall"];
  1381.                     _G.StaticPopup_Show("FX_MULTI_PURPOSE","A MESSAGE FROM FORTEXORCIST\n\n"..err);
  1382.            
  1383.                     FW:UnregisterAllEvents();
  1384.                     FW.Settings = {};
  1385.                     return;
  1386.                 end
  1387.                 if FX_Saved.VERSION < "v1.959.2" then
  1388.                     if FX_Saved.Profiles then
  1389.                         FX_Saved.ProfileNames = {};
  1390.                         for p,d in pairs( FX_Saved.Profiles ) do
  1391.                             tinsert(FX_Saved.ProfileNames,{p,p});
  1392.                         end
  1393.                     end
  1394.                 end
  1395.                 if FX_Saved.VERSION < "v1.959.5" then
  1396.                     FX_Saved.GotORA = nil; -- no longer used
  1397.                     FX_Saved.Warlocks = nil; -- no longer used
  1398.                    
  1399.                     FX_Saved.Healthstone = {}; -- reset
  1400.                     FX_Saved.Cooldowns = {}; -- reset
  1401.                 end
  1402.                 if FX_Saved.VERSION < "v1.959.7" then
  1403.                     FX_Saved.PARTY = nil; -- no longer used
  1404.                 end
  1405.                 if FX_Saved.VERSION < "v1.966.1" then
  1406.                     if FX_Saved.Profiles then
  1407.                         for p,d in pairs( FX_Saved.Profiles ) do
  1408.  
  1409.                             if type(FX_Saved.Profiles[p]["GlobalSpark"]) == "boolean" then -- fix downgrade-upgrade bug...
  1410.                                 FX_Saved.Profiles[p]["GlobalSparkEnable"] = FX_Saved.Profiles[p]["GlobalSpark"] or FW.Default.GlobalSparkEnable;
  1411.                                 FX_Saved.Profiles[p]["GlobalSpark"] = FW.Default.GlobalSpark;
  1412.                             end
  1413.                            
  1414.                             fixTimerSettings(FX_Saved.Profiles[p]["Timer"]);
  1415.                             if FX_Saved.Profiles[p]["CustomInstances"] and FX_Saved.Profiles[p]["CustomInstances"]["Timer"] then
  1416.                                 for clone,data in ipairs(FX_Saved.Profiles[p]["CustomInstances"]["Timer"]) do
  1417.                                     fixTimerSettings(FX_Saved.Profiles[p][ data[1] ]);
  1418.                                 end
  1419.                             end
  1420.                             fixCooldownSettings(FX_Saved.Profiles[p]["Cooldown"]);
  1421.                            
  1422.                             -- set ignore cd time to 2.99 instead of 3.00
  1423.                             FX_Saved.Profiles[p]["IgnoreCooldown"] = 2.99;
  1424.                         end
  1425.                     end
  1426.                 end
  1427.                 if FX_Saved.VERSION < "v1.966.3" then
  1428.                     FX_Saved.Shards = nil; -- no longer used
  1429.                 end
  1430.                 if FX_Saved.VERSION < "v1.966.5" then
  1431.                     if FX_Saved.Profiles then
  1432.                         for p,d in pairs( FX_Saved.Profiles ) do
  1433.                             if FX_Saved.Profiles[p]["TimerSortOrder"] then
  1434.                                 FX_Saved.Profiles[p]["TimerSortOrder"] = gsub(FX_Saved.Profiles[p]["TimerSortOrder"],","," ");
  1435.                             end
  1436.                         end
  1437.                     end
  1438.                 end
  1439.                 if FX_Saved.VERSION < "v1.966.6" then
  1440.                     if FX_Saved.Profiles then
  1441.                         for p,d in pairs( FX_Saved.Profiles ) do
  1442.                             FX_Saved.Profiles[p]["AnimateScroll"] = false;
  1443.                            
  1444.                             fixFilterRenames(FX_Saved.Profiles[p]["Timer"]);
  1445.                             if FX_Saved.Profiles[p]["CustomInstances"] and FX_Saved.Profiles[p]["CustomInstances"]["Timer"] then
  1446.                                 for clone,data in ipairs(FX_Saved.Profiles[p]["CustomInstances"]["Timer"]) do
  1447.                                     fixFilterRenames(FX_Saved.Profiles[p][ data[1] ]);
  1448.                                 end
  1449.                             end
  1450.                             fixFilterRenames(FX_Saved.Profiles[p]["Cooldown"]);
  1451.                         end
  1452.                     end
  1453.                 end
  1454.                 if FX_Saved.VERSION < "v1.974.3" then
  1455.                     if FX_Saved.Profiles then
  1456.                         for p,d in pairs( FX_Saved.Profiles ) do
  1457.                             fixTimerSettings19743(FX_Saved.Profiles[p]["Timer"]);
  1458.                             if FX_Saved.Profiles[p]["CustomInstances"] and FX_Saved.Profiles[p]["CustomInstances"]["Timer"] then
  1459.                                 for clone,data in ipairs(FX_Saved.Profiles[p]["CustomInstances"]["Timer"]) do
  1460.                                     fixTimerSettings19743(FX_Saved.Profiles[p][ data[1] ]);
  1461.                                 end
  1462.                             end
  1463.                         end
  1464.                     end
  1465.                 end
  1466.                 if FX_Saved.VERSION < "v1.974.6" then
  1467.                     if FX_Saved.Profiles then
  1468.                         for p,d in pairs( FX_Saved.Profiles ) do
  1469.                             fixCooldownSettings19746(FX_Saved.Profiles[p]["Cooldown"]);
  1470.                         end
  1471.                     end
  1472.                 end
  1473.                 if FX_Saved.VERSION < "v1.975" then
  1474.                     if FX_Saved.Profiles then
  1475.                         for p,d in pairs( FX_Saved.Profiles ) do
  1476.                            
  1477.                             FX_Saved.Profiles[p].OptionsSubHeaderBackdrop = nil;
  1478.                             FX_Saved.Profiles[p].OptionsHeaderBackdrop = nil;
  1479.                        
  1480.                             fixOptions1975(FX_Saved.Profiles[p]);  
  1481.                        
  1482.                             if FX_Saved.Profiles[p]["Timer"] then -- move and fix
  1483.                                 local temp = {Active=1,Instance="Timer",Instances={}, Links={}, Data={}};
  1484.                                 local index = FW:InstanceCreate(FWL.SPELL_TIMER or "Spell Timer",temp,FX_Saved.Profiles[p]["Timer"]);
  1485.                                 fixOptions1975(temp.Instances[index]);
  1486.                                 FX_Saved.Profiles[p]["Timer"] = {};
  1487.                                 if FX_Saved.Profiles[p]["CustomInstances"] and FX_Saved.Profiles[p]["CustomInstances"]["Timer"] then
  1488.                                     for clone,data in ipairs(FX_Saved.Profiles[p]["CustomInstances"]["Timer"]) do
  1489.                                         index = FW:InstanceCreate(data[2],temp,FX_Saved.Profiles[p][ data[1] ]);
  1490.                                         fixOptions1975(temp.Instances[index]);
  1491.                                         FX_Saved.Profiles[p][ data[1] ] = nil;
  1492.                                     end
  1493.                                     FX_Saved.Profiles[p]["CustomInstances"] = nil;
  1494.                                 end
  1495.                                 FW_CopyNew(temp,FX_Saved.Profiles[p]["Timer"]);
  1496.                             end
  1497.                             if FX_Saved.Profiles[p]["Cooldown"] then -- move and fix
  1498.                                 local temp = {Active=1,Instance="Cooldown",Instances={}, Links={}, Data={}};
  1499.                                 local index = FW:InstanceCreate(FWL.COOLDOWN_TIMER or "Cooldown Timer",temp,FX_Saved.Profiles[p]["Cooldown"]);
  1500.                                 fixOptions1975(temp.Instances[index]);
  1501.                                 FX_Saved.Profiles[p]["Cooldown"] = {};
  1502.                                 FW_CopyNew(temp,FX_Saved.Profiles[p]["Cooldown"]);
  1503.                             end
  1504.                             if FX_Saved.Profiles[p]["Splash"] then -- move and fix
  1505.                                 local temp = {Active=1,Instance="Splash",Instances={}, Links={}, Data={}};
  1506.                                 local index = FW:InstanceCreate(FWL.SECONDARY_SPLASH or "Secondary Splash",temp,FX_Saved.Profiles[p]["Splash"]);
  1507.                                 fixCooldownSettings1975(temp.Instances[index])
  1508.                                 fixOptions1975(temp.Instances[index]);
  1509.                                 FX_Saved.Profiles[p]["Splash"] = {};
  1510.                                 FW_CopyNew(temp,FX_Saved.Profiles[p]["Splash"]);
  1511.                             end
  1512.                         end
  1513.                         local temp = {Active=1,Characters={},Instances={}, Links={}, Data={}};
  1514.                         for i,d in ipairs( FX_Saved.ProfileNames ) do
  1515.                             FW:InstanceCreate(d[2],temp, FX_Saved.Profiles[ d[1] ]);
  1516.                             if FX_Saved.PROFILE == d[1] then
  1517.                                 temp.Active = i;
  1518.                             end
  1519.                             for key, val in pairs(FX_Saved.PROFILES) do
  1520.                                 if val == d[1] then
  1521.                                     temp.Characters[key] = i;
  1522.                                 end
  1523.                             end
  1524.                         end
  1525.                         FX_Saved.Profiles = {}; -- clear the old options
  1526.                         FW_CopyNew(temp,FX_Saved.Profiles);
  1527.                         -- delete old tables
  1528.                         FX_Saved.ProfileNames = nil; -- old
  1529.                         FX_Saved.PROFILES = nil; -- old
  1530.                         FX_Saved.PROFILE = nil; -- old
  1531.                         FX_Saved.SCALE = nil; -- old
  1532.                         FX_Saved.Speccs = nil; -- incompatible data
  1533.                         FX_Saved.Shards = nil; -- module removed
  1534.                     end
  1535.                 end
  1536.             end -- end of fix for v1.975(.1) bug
  1537.             -- add new compatibility fixes here:
  1538.            
  1539.             if FX_Saved.VERSION < "v1.975.7" then
  1540.                 for instance,settings in ipairs( FX_Saved.Profiles.Instances ) do
  1541.                     if settings.RebirthStart then
  1542.                         settings.RebirthStart[1] = ">>> Rebirth on %s <<<";
  1543.                     end
  1544.                     if settings.InnervateStart then
  1545.                         settings.InnervateStart[1] = ">>> Innervate on %s <<<";
  1546.                     end
  1547.                 end
  1548.             end
  1549.             if FX_Saved.VERSION < "v1.976" then
  1550.                 for instance,settings in ipairs( FX_Saved.Profiles.Instances ) do
  1551.                     if settings.Timer then
  1552.                         for i,s in ipairs( settings.Timer.Instances ) do
  1553.                             renameOption("FailColor","Fail",s);
  1554.                            
  1555.                             renameOption("DrainColor","Drain",s);
  1556.                             renameOption("MagicColor","Default",s);
  1557.                             renameOption("CurseColor","Shared1",s);
  1558.                             renameOption("Shared2Color","Shared2",s);
  1559.                             renameOption("Shared3Color","Shared3",s);
  1560.                             renameOption("CrowdColor","Unique",s);
  1561.                             renameOption("PetColor","Pet",s);
  1562.                             renameOption("BuffColor","SelfBuff",s);
  1563.                             renameOption("BuffOtherColor","SelfBuffOther",s);
  1564.                             renameOption("SelfDebuffColor","SelfDebuff",s);
  1565.                             renameOption("SelfDebuffOtherColor","SelfDebuffOther",s);
  1566.                             renameOption("CooldownsColor","Cooldown",s);
  1567.                             renameOption("CooldownsOtherColor","CooldownOther",s);
  1568.                             renameOption("DebuffsColor","TargetDebuff",s);
  1569.                             renameOption("DebuffsOtherColor","TargetDebuffOther",s);
  1570.                             renameOption("HealColor","Heal",s);
  1571.                             renameOption("FriendlyBuffColor","Buff",s);
  1572.                            
  1573.                             renameOption("TotemFireColor","TotemFire",s);
  1574.                             renameOption("TotemEarthColor","TotemEarth",s);
  1575.                             renameOption("TotemWaterColor","TotemWater",s);
  1576.                             renameOption("TotemAirColor","TotemAir",s);
  1577.                         end
  1578.                     end
  1579.                 end
  1580.             end
  1581.             if FX_Saved.VERSION < "v1.976.1" then
  1582.                 for instance,settings in ipairs( FX_Saved.Profiles.Instances ) do
  1583.                     if settings.Timer then
  1584.                         for i,s in ipairs( settings.Timer.Instances ) do
  1585.                             renameOption("Drain","Channel",s);
  1586.                             renameOption("Shared1","Curse",s);
  1587.                             renameOption("Shared2","Bane",s);
  1588.                             renameOption("Unique","Crowd",s);
  1589.                             s["Shared3"] = nil;
  1590.                         end
  1591.                     end
  1592.                 end
  1593.             end
  1594.             if FX_Saved.VERSION < "v1.976.3" then
  1595.                 for instance,settings in ipairs( FX_Saved.Profiles.Instances ) do
  1596.                     if settings.Cooldown then
  1597.                         for i,s in ipairs( settings.Cooldown.Instances ) do
  1598.                             renameOption("SpellColor","Spell",s);
  1599.                             renameOption("PetColor","Pet",s);
  1600.                             renameOption("ItemColor","Item",s);
  1601.                             renameOption("SoulstoneColor","Soulstone",s);
  1602.                             renameOption("HealthstoneColor","Healthstone",s);
  1603.                             renameOption("PotionColor","Potion",s);
  1604.                             renameOption("PowerupColor","Powerup",s);
  1605.                             renameOption("ResTimerColor","ResTimer",s);
  1606.                            
  1607.                             renameOption("BuffColor","Buff",s);
  1608.                             renameOption("BuffOtherColor","BuffOther",s);
  1609.                             renameOption("DebuffColor","Debuff",s);
  1610.                             renameOption("DebuffOtherColor","DebuffOther",s);
  1611.                            
  1612.                             renameOption("EnchantColor","Enchant",s);
  1613.                            
  1614.                             renameOption("RuneBloodColor","RuneBlood",s);
  1615.                             renameOption("RuneDeathColor","RuneDeath",s);
  1616.                             renameOption("RuneFrostColor","RuneFrost",s);
  1617.                         end
  1618.                     end
  1619.                 end
  1620.             end
  1621.         end
  1622.         if FX_Saved.VERSION < "v1.975" then
  1623.             FW:Popup1975(FX_Saved.VERSION ~= "");
  1624.         end
  1625.         -- !!! END COMPATIBILITY FIXES !!! --
  1626.         FX_Saved.VERSION = VERSION;
  1627.     end
  1628.     STATES.GROUPED = FX_Saved.GROUPED;
  1629.     STATES.RAID = FX_Saved.RAID;
  1630.    
  1631.     FW:RegisterFrame("FWOptions",FW:NewOptionsPanel()); -- needs to be done at least before FW_InitConfig!!!
  1632.    
  1633.     FW_InitConfig(); -- set the right profile
  1634.    
  1635.     if FW.Settings.ShowStartupText then
  1636.         FW:Show(FW:Title().." - /fx for options",0,1,0);
  1637.         FW:Show("Class Module: "..FW.ClassModules.." - Modules: "..FW:Size(FW.Modules),0,1,0); 
  1638.     end
  1639.     FW:Debug("Warning: Debug mode is on!");
  1640.    
  1641.     if FX_Saved.Update > t then -- pc rebooted, have to clear all timers
  1642.         FW_Reset();
  1643.     else
  1644.         FW_ResetOld(t);
  1645.     end
  1646.  
  1647.     for i,f in ipairs(FW_VariablesLoaded) do
  1648.         f();
  1649.     end
  1650. end
  1651.  
  1652. function FW:Title()
  1653.     return FW.TITLE.." "..VERSION.." by Xus - "..FW:InstanceIndexToName(FW.Saved.Profiles.Active,FW.Saved.Profiles);
  1654. end
  1655.  
  1656. function FW:RegisterEnterPartyRaid(func)
  1657.     tinsert(FW_EnterPartyRaid,func);
  1658. end
  1659.  
  1660. local function FW_PartyRaid() -- also run on ui load plx!
  1661.     for i,f in ipairs(FW_EnterPartyRaid) do
  1662.         f(STATES.GROUPED);
  1663.     end
  1664. end
  1665.  
  1666. local function FW_TimedRaidParty()
  1667.     local t1, t2 = IsInInstance();
  1668.     local t3;
  1669.     local party,raid;
  1670.     if t1 and t2 ~= "raid" and t2 ~= "party" then -- switch everything raid related off if we're inside a battleground
  1671.         party = false;
  1672.         raid = false;
  1673.     else
  1674.         party = IsInGroup();
  1675.         raid = IsInRaid();
  1676.     end
  1677.     t3 = (party or raid);
  1678.     if STATES.RAID ~= raid then
  1679.         FX_Saved.RAID = raid;
  1680.         STATES.RAID = raid;
  1681.     end
  1682.     if STATES.GROUPED ~= t3 then
  1683.         FX_Saved.GROUPED = t3;
  1684.         STATES.GROUPED = t3;
  1685.         FW_PartyRaid();
  1686.     end
  1687. end
  1688.  
  1689. -- ids here is in numbers too!
  1690. function FW:RegisterSet(name,...)
  1691.     for i=1,select('#',...), 1 do
  1692.         FW.Sets[select(i,...)] = name;
  1693.     end
  1694.     if not FW.SetBonus[name] then FW.SetBonus[name] = 0; end
  1695. end
  1696.  
  1697. local function FW_RelevantTalent()
  1698.     --FW:Show("TALENTS");
  1699.     --[[for tab=1,GetNumSpecializations(),1 do
  1700.         for i=1,GetNumTalents(tab),1 do
  1701.             local name, _, _, _, rank = GetTalentInfo(tab, i, nil,nil,GetActiveSpecGroup());
  1702.             if FW.Talent[name] then
  1703.                 FW.Talent[name] = rank;
  1704.             end
  1705.         end
  1706.     end]]
  1707. end
  1708.  
  1709. local function FW_RelevantStance()
  1710.     FW.Stance = GetShapeshiftForm();
  1711.     --FW:Show("STANCE "..FW.Stance);
  1712. end
  1713.  
  1714. -- 26.07.2016 : Manually removed glyph function
  1715.    
  1716. local function FW_RelevantSetBonus()
  1717.     --FW:Show( "SET SCAN" );
  1718.     for k, v in pairs(FW.SetBonus) do
  1719.         FW.SetBonus[k] = 0;
  1720.     end
  1721.     local t1;
  1722.     for i=1,12,1 do -- from head to 2nd ring
  1723.         t1 = GetInventoryItemID("player", i); -- is a number
  1724.         if t1 then
  1725.             t1 = FW.Sets[t1];
  1726.             if t1 then
  1727.                 FW.SetBonus[t1] = FW.SetBonus[t1] + 1;
  1728.             end
  1729.         end
  1730.     end
  1731. end
  1732.  
  1733. function FW:SecToTimeD(t)
  1734.     if FW.Settings.TimeFormat then
  1735.         if t >= 60 then
  1736.             return math.floor(t/60)..":"..strformat("%02d",t%60);
  1737.         else
  1738.             return strformat("%.1f",t);
  1739.         end
  1740.     else
  1741.         if t >= 3600 then
  1742.             return ceil(t/3600).."h";
  1743.         elseif t >= 60 then
  1744.             return ceil(t/60).."m";
  1745.         else
  1746.             return floor(t).."s";
  1747.         end
  1748.     end
  1749. end
  1750.  
  1751. function FW:SecToTime(t)
  1752.     if FW.Settings.TimeFormat then
  1753.         return math.floor(t/60)..":"..strformat("%02d",t%60);
  1754.     else
  1755.         if t >= 3600 then
  1756.             return ceil(t/3600).."h";
  1757.         elseif t >= 60 then
  1758.             return ceil(t/60).."m";
  1759.         else
  1760.             return floor(t).."s";
  1761.         end
  1762.     end
  1763. end
  1764. do
  1765.     local function MatchNameToId(unit,name)
  1766.         if name == UnitName(unit) then
  1767.             return unit;
  1768.         end
  1769.     end
  1770.     function FW:NameToID(name)
  1771.         if name == FW.PLAYER then return "player";end
  1772.         return FW:ForGroupMembers(MatchNameToId,name);
  1773.     end
  1774. end
  1775.  
  1776. function FW:RosterInfo()
  1777.     if GetNumGroupMembers()>0 then
  1778.         local name,rank,zone,_;
  1779.         for i=1,40,1 do
  1780.             name, rank, _, _, _, _, zone = GetRaidRosterInfo(i);
  1781.             if name then
  1782.                 FW.Ranks[name] = rank;
  1783.                 FW.Zones[name] = zone;
  1784.             end
  1785.         end
  1786.     end
  1787. end
  1788.  
  1789.  
  1790. function FW:IsWarlock(unit)
  1791.     if select(2,UnitClass(unit)) == "WARLOCK" then return 1;end
  1792. end
  1793.  
  1794. do
  1795.     local GetItemCount = GetItemCount;
  1796.     function FW:GotHealthstone() -- returns the name of the best hs in your inventory
  1797.         return GetItemCount(FW.ID_HEALTHSTONE);
  1798.     end
  1799. end
  1800.  
  1801. function FW:BestSoulstone() -- returns name of best soulstone you can create, ising in cooldown and soulstone module
  1802.     if FW.CLASS == "WARLOCK" then
  1803.         return FW:ItemName(FW.ID_SOULSTONE);
  1804.     else
  1805.         return FWL.NONE;
  1806.     end
  1807. end
  1808.  
  1809. function FW:BestHealthstone()
  1810.     if FW.CLASS == "WARLOCK" then
  1811.         return FW:ItemName(FW.ID_HEALTHSTONE);
  1812.     else
  1813.         return FWL.NONE;
  1814.     end
  1815. end
  1816.  
  1817. --[[
  1818. function FW:TimeStart()
  1819.     FW.StartTime = GetTime();
  1820. end
  1821.  
  1822. function FW:TimeEnd(label)
  1823.     FW:Show(label..": "..(GetTime()-FW.StartTime),0,0,1);
  1824. end]]
  1825.  
  1826. local function FW_SendVersion()
  1827.     FW:SendData(SEND_VERSION..VERSION);
  1828. end
  1829.  
  1830.  
  1831. --[[local function FW_SendSpeccInfo()
  1832.     if FX_Saved.Speccs[FW.CLASS] and FX_Saved.Speccs[FW.CLASS][FW.PLAYER] then
  1833.         FW:SendData(SEND_SPECC..FX_Saved.Speccs[FW.CLASS][FW.PLAYER]);
  1834.     --else
  1835.         --FW:Show("failed to send");
  1836.     end
  1837. end]]
  1838.  
  1839. local function FW_AddonMessage(msg,from)
  1840.     for i,d in ipairs(FW_Messages) do
  1841.         if strfind(msg,d[1]) then
  1842.             FW:Debug("FX2 Running function for "..d[1],0,1,1);
  1843.             if d[2]( strsub(msg,strlen(d[1])), from ) then return; end
  1844.         end
  1845.     end
  1846. end
  1847.  
  1848. local function FW_AddonMessageReceived(event,...)
  1849.     local arg1,arg2,arg3,arg4 = ...;
  1850.     if arg1 == "FX2" then
  1851.         --FW:Debug(arg4..": "..arg2,0,1,1);
  1852.         if arg4 ~= FW.PLAYER then -- ignore messages from self
  1853.             FW_AddonMessage(arg2,arg4);
  1854.         end
  1855.     elseif arg1 == "oRA3" then
  1856.         if FX_Saved.RaidStatus[arg4] then
  1857.             if not FX_Saved.RaidStatus[arg4][4] then
  1858.                 FX_Saved.RaidStatus[arg4][4] = 1;
  1859.             end
  1860.         else
  1861.             ora3temp[arg4] = 1;
  1862.         end
  1863.         --[[local debug = GetTime().." "..event;
  1864.         if arg1 then debug = debug.." "..tostring(arg1); end
  1865.         if arg2 then debug = debug.." "..tostring(arg2); end
  1866.         if arg3 then debug = debug.." "..tostring(arg3); end
  1867.         if arg4 then debug = debug.." "..tostring(arg4); end
  1868.         FW:Show(debug,0,1,1);]]
  1869.         local _,t1,t2;
  1870.         for i,d in ipairs(FW_oRAMessages) do
  1871.             _,_,t1,t2 = strfind(arg2,d[1]);
  1872.             if t1 then
  1873.                 FW:Debug("oRA3 Running function for "..d[1],0,1,1);
  1874.                 if d[2]( t1,t2, arg4 ) then return; end -- stop looking if function actually returns something
  1875.             end
  1876.         end
  1877.     end
  1878. end
  1879.  
  1880. --------------------------------------------
  1881.  
  1882. function FW:SendData(msg)
  1883.     FW_AddonMessage(msg,FW.PLAYER);
  1884.     if FW.STATES.GROUPED then
  1885.         SendAddonMessage("FX2",msg,"RAID");
  1886.     end
  1887. end
  1888. --------------------------------------------
  1889.  
  1890. local function FW_CheckHealthstone()
  1891.     FW:Debug("HS check response");
  1892.     FW:SendHealthstone(FX_Saved.Healthstone[FW.PLAYER] or -1);
  1893. end
  1894.  
  1895. function FW:SendHealthstone(id)
  1896.     SendAddonMessage("FX2",FW.SEND_HEALTHSTONE..id,"RAID");--can completely ignore this yourself
  1897. end
  1898.  
  1899. ---------------------------------------------------------------------------
  1900. -- register functions
  1901. ---------------------------------------------------------------------------
  1902. local FW_Throttle = FW:NEW2D();
  1903.  
  1904. function FW:RegisterThrottle(func,arg1) -- every same function will only be triggered 20x per second by default
  1905.     for i=1,FW_Throttle.rows,1 do
  1906.          if FW_Throttle[i][1] == func and FW_Throttle[i][2] == arg1 then
  1907.             return;
  1908.          end
  1909.     end
  1910.     FW_Throttle:insert(func,arg1);
  1911. end
  1912.  
  1913. local function FW_ExecuteThrottle()
  1914.     for i=1,FW_Throttle.rows,1 do
  1915.         --FW:Show(tostring(FW_Throttle[i][1]).."("..tostring(FW_Throttle[i][2])..")");
  1916.         FW_Throttle[i][1](FW_Throttle[i][2]);
  1917.     end
  1918.     FW_Throttle:erase();
  1919. end
  1920.  
  1921. function FW:RegisterORAMessage(start,func,ignorewithfw) -- note that the ora message recognition needs the function to give a return value to stop/break early
  1922.     tinsert(FW_oRAMessages,{"^"..start,func}); -- ignorewithfw IS DISABLED
  1923. end
  1924.  
  1925. function FW:RegisterMessage(start,func,merge) -- will always stop/break when a prefix match is found at this time
  1926.     tinsert(FW_Messages,{"^"..start,func});
  1927. end
  1928.  
  1929. function FW:RegisterSpecialSaved(saved,reset,default)
  1930.     SpecialSaved[saved] = reset;
  1931.     if FX_Saved[saved]==nil then  FX_Saved[saved] = default; end
  1932. end
  1933.  
  1934. function FW:RegisterOnProfileChange(func)
  1935.     tinsert(FilterRefresh,func);
  1936. end
  1937.  
  1938. -- the normal events aren't accurate enough in case of zoning for instance
  1939. function FW:RegisterOnLeaveCombat(func)
  1940.     tinsert(FW_OnLeaveCombat,func);
  1941. end
  1942. function FW:RegisterOnEnterCombat(func)
  1943.     tinsert(FW_OnEnterCombat,func);
  1944. end
  1945.  
  1946. function FW:RegisterScan(func)
  1947.     tinsert(FW_Scans,func);
  1948. end
  1949.  
  1950. function FW:AddCommand(k,f)
  1951.     Commands[k] = f;
  1952. end
  1953.  
  1954. function FW:GetFrame(name)
  1955.     return Frames[name];
  1956. end
  1957.  
  1958. function FW:UnregisterFrame(name)
  1959.     Frames[name]:Hide();
  1960.     Frames[name] = nil;
  1961. end
  1962.  
  1963. function FW:RegisterFrame(name,frame,combat_sensitive,instanceof)
  1964.     Frames[name] = frame;
  1965.     Frames[name].combat_sensitive = combat_sensitive;
  1966.     Frames[name].name = name;
  1967.     Frames[name].instanceof = instanceof; -- for defaults only?
  1968. end
  1969.  
  1970. function FW:RegisterVariablesEvent(func)
  1971.     tinsert(FW_VariablesLoaded,func);
  1972. end
  1973.  
  1974. --[[function FW:RegisterLoadEvent(func)
  1975.     tinsert(FW_Loaded,func);
  1976. end]]
  1977.  
  1978. function FW:RegisterDelayedLoadEvent(func)
  1979.     tinsert(FW_DelayedLoaded,func);
  1980. end
  1981. ---------------------------------------------------------------------------
  1982. -- some local frame functions
  1983. ---------------------------------------------------------------------------
  1984. function FW:GetCenter(frame)
  1985.     local x,y = frame:GetCenter()
  1986.     return x*frame:GetEffectiveScale(),y*frame:GetEffectiveScale();
  1987. end
  1988.  
  1989. function FW:RefreshFrames()
  1990.     for f,d in pairs(Frames) do
  1991.         d:Update();
  1992.     end
  1993. end
  1994.  
  1995. function FW:SetPosition(frame,x,y)
  1996.     frame:ClearAllPoints();
  1997.     frame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x/frame:GetEffectiveScale(), y/frame:GetEffectiveScale());
  1998. end
  1999.  
  2000. function FW:InitFrameVars(frame) -- also contains compatibility fixes (these should be removed at some point, e.g. ver2.00)
  2001.     if not frame.instanceof then -- for old style frames
  2002.         if not FW.Settings[frame.name] then
  2003.             FW.Settings[frame.name] = {};
  2004.         end
  2005.         frame.s = FW.Settings[frame.name];
  2006.     end
  2007.     if frame.s.lock == nil then -- init value
  2008.         frame.s.lock = false; -- never lock by default
  2009.     end
  2010.     if frame.s.alpha == nil then -- init value
  2011.         frame.s.alpha = frame.instanceof and FW.InstanceDefault[frame.instanceof].alpha or 1;
  2012.     end
  2013.     if frame.s.scale == nil then -- init value
  2014.         frame.s.scale = frame.instanceof and FW.InstanceDefault[frame.instanceof].scale or 1;
  2015.     end
  2016.     if frame.s.x == nil or frame.s.y == nil then
  2017.         frame.s.x,frame.s.y = FW:GetCenter(UIParent);
  2018.     elseif not frame.combat_sensitive or not FW.STATES.INCOMBAT then
  2019.         FW:SetPosition(frame,frame.s.x,frame.s.y);
  2020.     end
  2021.     if frame.name == "FWOptions" then
  2022.         _G["FWOptions"] = frame;
  2023.         tinsert(UISpecialFrames,"FWOptions");
  2024.     elseif FW.Settings.GlobalFrameNames then
  2025.         _G[frame.name] = frame;
  2026.     end
  2027. end
  2028.  
  2029. ---------------------------------------------------------------------------
  2030. -- globally accessable
  2031. ---------------------------------------------------------------------------
  2032.  
  2033. function FW:ToGroup(msg)
  2034.     if not FW.Settings["OutputRaid"] then return; end
  2035.     if IsInRaid() then
  2036.         SendChatMessage(msg,"RAID");
  2037.     elseif GetNumGroupMembers() > 0 then
  2038.         SendChatMessage(msg,"PARTY");
  2039.     else
  2040.         FW:Show(msg);
  2041.     end
  2042.  
  2043. end
  2044.  
  2045. function FW:ToChannel(msg)
  2046.     if not (FW.Settings["Output"] and FW.Settings["Output"][0]) then return; end
  2047.     if strlower(FW.Settings["Output"][1]) == "say" then
  2048.         SendChatMessage(msg,"SAY");
  2049.     elseif strlower(FW.Settings["Output"][1]) == "yell" then
  2050.         SendChatMessage(msg,"YELL");
  2051.     else
  2052.         local index = tonumber(FW.Settings["Output"][1]) or GetChannelName(FW.Settings["Output"][1]);
  2053.         if index then
  2054.             SendChatMessage(msg,"CHANNEL",nil,index);
  2055.         end
  2056.     end
  2057. end
  2058.  
  2059. function FW:PlaySound(option)
  2060.     if FW.Settings[option][0] then
  2061.         for i=1,FW.Settings[option][2],1 do
  2062.             PlaySoundFile(FW.Settings[option][1]);
  2063.         end
  2064.     end
  2065. end
  2066.  
  2067. function FW:MixColors(v,c1,c2)
  2068.     -- v == 0 then color = c1, v == 1 then color = c2
  2069.     if v<0 then v=0; elseif v>1 then v=1;end
  2070.     return c1[1]*(1-v)+c2[1]*v,c1[2]*(1-v)+c2[2]*v,c1[3]*(1-v)+c2[3]*v;
  2071. end
  2072.  
  2073. function FW:MixColors2(v,c1r,c1g,c1b,c2r,c2g,c2b)
  2074.     -- v == 0 then color = c1, v == 1 then color = c2
  2075.     if v<0 then v=0; elseif v>1 then v=1;end
  2076.     return c1r*(1-v)+c2r*v,c1g*(1-v)+c2g*v,c1b*(1-v)+c2b*v;
  2077. end
  2078.  
  2079. function FW:Whisper(msg,to)
  2080.     SendChatMessage(msg,"WHISPER",nil,to);
  2081. end
  2082.  
  2083. function FW:Size(t)
  2084.     local i = 0;
  2085.     for k, v in pairs(t) do i=i+1;end
  2086.     return i;
  2087. end
  2088.  
  2089. local loadclones = {};
  2090. function FW:RegisterLoadClones(func)
  2091.     tinsert(loadclones,func);
  2092. end
  2093.  
  2094. local function FW_InitClones()
  2095.     for i,f in ipairs(loadclones) do
  2096.         f();
  2097.     end
  2098. end
  2099.  
  2100. function FW:InstanceDelete(index,root)
  2101.     if #root.Instances > 1 then
  2102.         FW:InstanceSetLink(index,root,nil); -- manage links
  2103.         tremove(root.Instances,index);
  2104.         tremove(root.Data,index);
  2105.         if root.Active == index then -- update active
  2106.             root.Active = 1;
  2107.             return 1, 1;
  2108.         elseif root.Active > index then
  2109.             root.Active = root.Active - 1;
  2110.         end
  2111.         --[[for i,v in ipairs(root.Instances) do -- also keep index updated
  2112.             v.index = i;
  2113.         end]]
  2114.         return 1;
  2115.     end
  2116. end
  2117.  
  2118. function FW:InstanceCreate(name,root,data) -- create new profile or clone
  2119.     tinsert(root.Data,{name=name});
  2120.     local index = #root.Data;
  2121.     tinsert(root.Instances,{--[[index=index]]});
  2122.     FW_CopyNew(data,root.Instances[index]);
  2123.    
  2124.     FW:LinkOnCreate(index,root);
  2125.  
  2126.     return index;
  2127. end
  2128.  
  2129. function FW:UseProfile(index,onload)
  2130.     if not FX_Saved.Profiles.Instances[index] then -- make sure i always load a profile!!!!
  2131.         if FX_Saved.Profiles.Instances[FW.Saved.Profiles.Active] then
  2132.             index = FW.Saved.Profiles.Active;
  2133.         else
  2134.             index = 1;
  2135.         end
  2136.     end
  2137.     FW.Saved.Profiles.Active = index;
  2138.     FW.Saved.Profiles.Characters[FW:FullName()] = index;
  2139.     FW.Settings = FX_Saved.Profiles.Instances[index];
  2140.     FW_CopyNew(FW.Default,FW.Settings);
  2141.    
  2142.     FW_InitClones();
  2143.     FW:RefreshFrames(); -- also updates the settings tables of clones, so make sure this is called before doing anything with them
  2144.     if not onload then
  2145.         FW_RefreshAllFilters();
  2146.         FW:BuildOptions();
  2147.         FW:RefreshOptions();
  2148.     end
  2149. end
  2150.  
  2151. function FW:InstanceNameToIndex(name,root,case) -- case insensitive by default
  2152.     if case then
  2153.         for i, v in ipairs(root.Data) do
  2154.             if v["name"] == name then
  2155.                 return i;
  2156.             end
  2157.         end
  2158.     else
  2159.         for i, v in ipairs(root.Data) do
  2160.             if strlower(v["name"]) == strlower(name) then
  2161.                 return i;
  2162.             end
  2163.         end
  2164.     end
  2165. end
  2166.  
  2167. function FW:InstanceIndexToName(index,root)
  2168.     return root.Data[index]["name"];
  2169. end
  2170.  
  2171. function FW:InstanceRename(index,newname,root)
  2172.     root.Data[index]["name"] = newname;
  2173. end
  2174.  
  2175. function FW:ShowTimeFor(spell,target,timeleft,iscooldown)
  2176.     if spell ~= target then -- really has a target
  2177.         if bit.band(1,FW.Settings.TimeLeft[0]) ~= 0 then
  2178.             FW:ToGroup( strformat( FW.Settings.TimeLeft[1],spell,target, FW:SecToTimeD(timeleft) ) );
  2179.         end
  2180.         if bit.band(2,FW.Settings.TimeLeft[0]) ~= 0 then
  2181.             FW:ToChannel( strformat( FW.Settings.TimeLeft[1],spell,target, FW:SecToTimeD(timeleft) ) );
  2182.         end
  2183.     else
  2184.         if iscooldown then
  2185.             if bit.band(1,FW.Settings.CooldownLeft[0]) ~= 0 then
  2186.                 FW:ToGroup( strformat( FW.Settings.CooldownLeft[1],spell,FW:SecToTimeD(timeleft) ) );
  2187.             end
  2188.             if bit.band(2,FW.Settings.CooldownLeft[0]) ~= 0 then
  2189.                 FW:ToChannel( strformat( FW.Settings.CooldownLeft[1],spell,FW:SecToTimeD(timeleft) ) );
  2190.             end
  2191.         else
  2192.             if bit.band(1,FW.Settings.TimeLeftNoTarg[0]) ~= 0 then
  2193.                 FW:ToGroup( strformat( FW.Settings.TimeLeftNoTarg[1],spell,FW:SecToTimeD(timeleft) ) );
  2194.             end
  2195.             if bit.band(2,FW.Settings.TimeLeftNoTarg[0]) ~= 0 then
  2196.                 FW:ToChannel( strformat( FW.Settings.TimeLeftNoTarg[1],spell,FW:SecToTimeD(timeleft) ) );
  2197.             end
  2198.         end
  2199.     end
  2200. end
  2201.  
  2202. function FW:MakeBackdrop(backdrop,bg,edge,tile,tilesize,edgesize)
  2203.     if not backdrop.insets then backdrop.insets = {}; end
  2204.     backdrop.bgFile = bg;
  2205.     backdrop.edgeFile = edge;
  2206.     backdrop.tile = tile;
  2207.     backdrop.tileSize = tilesize;
  2208.     backdrop.edgeSize = edgesize;
  2209.     backdrop.insets.left = edgesize;
  2210.     backdrop.insets.right = edgesize;
  2211.     backdrop.insets.top = edgesize;
  2212.     backdrop.insets.bottom = edgesize;
  2213. end
  2214.  
  2215. function FW:SetBackdrop(frame,bg,edge,tile,tilesize,edgesize)
  2216.     if not frame.backdrop then frame.backdrop = {}; end
  2217.     FW:MakeBackdrop(frame.backdrop,bg,edge,tile,tilesize,edgesize);
  2218.     frame:SetBackdrop(frame.backdrop);
  2219. end
  2220. ---------------------------------------------------------------------------
  2221. -- template/option functions
  2222. ---------------------------------------------------------------------------
  2223. local FW_Bindings = {};
  2224. function FW:RegisterButtonPress(bindingname,buttonname,button)
  2225.     tinsert(FW_Bindings, {bindingname,buttonname,button} );
  2226. end
  2227.  
  2228. local function FW_UpdateBindings()
  2229.     --FW:Show("update");
  2230.     if not STATES.INCOMBAT then
  2231.         for i,t in ipairs(FW_Bindings) do
  2232.             _G.ClearOverrideBindings(_G[t[2]]);
  2233.         end
  2234.         for i,t in ipairs(FW_Bindings) do
  2235.             local b1,b2 = _G.GetBindingKey(t[1]);
  2236.             if b1 then
  2237.                 _G.SetOverrideBindingClick(_G[t[2]], false, b1,t[2],t[3]);
  2238.             end
  2239.             if b2 then
  2240.                 _G.SetOverrideBindingClick(_G[t[2]], false, b2,t[2],t[3]);
  2241.             end
  2242.         end
  2243.     end
  2244. end
  2245.  
  2246. local function FW_ScanBags() -- send item counts regardless of installed modules to improve usefulness
  2247.     FW:Debug("scan bags");
  2248.  
  2249.     if not FX_Saved.Healthstone[FW.PLAYER] then
  2250.         FX_Saved.Healthstone[FW.PLAYER] = -1;
  2251.     end
  2252.     local t1 = FW:GotHealthstone();
  2253.     if FX_Saved.Healthstone[FW.PLAYER] ~= t1 then
  2254.         FX_Saved.Healthstone[FW.PLAYER] = t1;
  2255.         if STATES.GROUPED then
  2256.             FW:SendHealthstone(t1);
  2257.         end
  2258.     end
  2259. end
  2260. local function FW_ScanBagsChilled()
  2261.     FW:RegisterThrottle(FW_ScanBags);
  2262. end
  2263. ---------------------------------------------------------------------------
  2264. -- options & events
  2265. ---------------------------------------------------------------------------
  2266. FW:RegisterToEvent("VARIABLES_LOADED",FW_Variables);
  2267.  
  2268. -- things to do at load (after load delay)
  2269. FW:RegisterDelayedLoadEvent(FW_Scan);
  2270. FW:RegisterDelayedLoadEvent(FW_RelevantSetBonus);
  2271. FW:RegisterDelayedLoadEvent(FW_RelevantTalent);
  2272. FW:RegisterDelayedLoadEvent(FW_RelevantStance);
  2273. FW:RegisterDelayedLoadEvent(FW_TimedRaidParty);
  2274. FW:RegisterDelayedLoadEvent(FW_PartyRaid);
  2275. --FW:RegisterDelayedLoadEvent(FW_MakeSpeccInfo);--doesnt work yet at load event
  2276. FW:RegisterDelayedLoadEvent(FW_ScanBagsChilled);
  2277.  
  2278. --FW:RegisterOnLeaveCombat(FW_InitFramePositions); -- this is just a 'backup' init
  2279.  
  2280. FW:RegisterScan(FW_RaidStatusScan);
  2281. FW:RegisterEnterPartyRaid( function(joined) if joined then FW_VersionCheck();end end );
  2282. --FW:RegisterEnterPartyRaid( function(joined) if joined then FW_GetSpeccInfo();end end );
  2283.    
  2284. -- done when all addon variables are loaded
  2285. FW:RegisterVariablesEvent(function()
  2286.     FW:RegisterToEvent("UPDATE_BINDINGS",           FW_UpdateBindings);
  2287.  
  2288.     FW:RegisterToEvent("PLAYER_REGEN_ENABLED",      FW_LeaveCombat);
  2289.     FW:RegisterToEvent("PLAYER_REGEN_DISABLED",     FW_EnterCombat);
  2290.     FW:RegisterToEvent("PLAYER_ALIVE",              FW_Ress)
  2291.     FW:RegisterToEvent("PLAYER_UNGHOST",            FW_Ress);
  2292.     FW:RegisterToEvent("PLAYER_LEAVING_WORLD",      function() LeaveCombat = 1; end);
  2293.     FW:RegisterToEvent("UNIT_INVENTORY_CHANGED",    function() FW:RegisterThrottle(FW_RelevantSetBonus);end);
  2294.  
  2295.     --FW:RegisterToEvent("INSPECT_TALENT_READY",        function() FW_MakeSpeccInfo(1); end);
  2296.     FW:RegisterToEvent("CHAT_MSG_ADDON",            FW_AddonMessageReceived);
  2297.    
  2298.     if not IsAddonMessagePrefixRegistered("FX2") then
  2299.         RegisterAddonMessagePrefix("FX2");
  2300.     end
  2301.     if not IsAddonMessagePrefixRegistered("oRA3") then
  2302.         RegisterAddonMessagePrefix("oRA3");
  2303.     end
  2304.    
  2305.     FW:RegisterToEvent("UNIT_PET", function(event,arg1) if arg1 == "player" then FW:Changed("pet");end end);
  2306.  
  2307.     -- 26.07.2016 : Manually emoved glyph events
  2308.  
  2309.     FW:RegisterToEvent("GROUP_ROSTER_UPDATE",FW_TimedRaidParty);
  2310.  
  2311.     FW:RegisterToEvent("BAG_UPDATE",FW_ScanBagsChilled);
  2312.    
  2313.     FW:RegisterToEvent("UI_SCALE_CHANGED",FW.RefreshFrames);
  2314.     --FW:RegisterToEvent("UI_SCALE_CHANGED",function() FW:Show("scale"); end);
  2315.  
  2316.     FW:RegisterTimedEvent("UpdateInterval",     FW_TimedRaidParty);
  2317.     FW:RegisterTimedEvent("UpdateInterval",     FW_Scan);
  2318.     FW:RegisterTimedEvent("Chill",              FW_ExecuteThrottle);
  2319.    
  2320.     FW:RegisterToEvent("PLAYER_TALENT_UPDATE",  FW_RelevantTalent);
  2321.     --FW:RegisterToEvent("PLAYER_TALENT_UPDATE",    function() FW_MakeSpeccInfo(nil); end);
  2322.     --FW:RegisterToEvent("PLAYER_TALENT_UPDATE",    function() FW_SendSpeccInfo(nil); end);
  2323.    
  2324.     FW:RegisterToEvent("UPDATE_SHAPESHIFT_FORM", FW_RelevantStance);
  2325. end);
  2326.  
  2327. SlashCmdList["FORTEXORCIST"] = function(msg)
  2328.     local s = strsplit(" ",msg);
  2329.     if Commands[s] then
  2330.         Commands[s]( strsub(msg,strlen(s)+2) );
  2331.     else
  2332.         FW:ToggleOptions();
  2333.     end
  2334. end
  2335. SLASH_FORTEXORCIST1 = "/fw";
  2336. SLASH_FORTEXORCIST2 = "/fortewarlock";
  2337. SLASH_FORTEXORCIST3 = "/fx";
  2338. SLASH_FORTEXORCIST4 = "/fortexorcist";
  2339.    
  2340. FW:AddCommand("commands",
  2341.     function()
  2342.         for k,v in pairs(Commands) do
  2343.             FW:Show(k,1,1,0);
  2344.         end
  2345.     end
  2346. );
  2347.  
  2348. FW:AddCommand("version",
  2349.     function()
  2350.         for k, v in pairs(FX_Saved.RaidStatus) do
  2351.             if v[4] then
  2352.                 if type(v[4])=="string" then
  2353.                     FW:Show(k.." FX: "..v[4]);
  2354.                 else
  2355.                     FW:Show(k.." FX: no, oRA3: yes" );
  2356.                 end
  2357.             else
  2358.                 FW:Show(k.." FX: no, oRA3: ??");
  2359.             end
  2360.         end
  2361.     end
  2362. );
  2363.    
  2364. local function FW_ResetOptionsFrame()
  2365.     FW.Frames["FWOptions"]:Reset();
  2366. end
  2367.  
  2368. FW:AddCommand("position",FW_ResetOptionsFrame);
  2369. FW:AddCommand("reset",FW_ResetOptionsFrame);
  2370.  
  2371. FW:AddCommand("resetall",
  2372.     function()
  2373.         _G.FX_Saved = {RESETTING=true}; -- also indicate that I'm currently resetting to avoid copying the backup
  2374.         ReloadUI();
  2375.     end
  2376. );
  2377. FW:AddCommand("usebackup",
  2378.     function()
  2379.         if FW:Size(FC_Saved) > 0 then -- check if backup is available
  2380.             _G.FX_Saved = {};
  2381.             ReloadUI();
  2382.         end
  2383.     end
  2384. );
  2385.  
  2386. FW:AddCommand("profile",
  2387.     function(profile)
  2388.         FW:UseProfile( FW:InstanceNameToIndex(profile,FX_Saved.Profiles) );
  2389.     end
  2390. );
  2391.  
  2392. FW:AddCommand("debug",
  2393.     function()
  2394.         FW_Debug = not FW_Debug;
  2395.         if FW_Debug then
  2396.             FW:Show("fw debugging enabled",1,1,0);
  2397.         else
  2398.             FW:Show("fw debugging disabled",1,1,0);
  2399.         end
  2400.     end
  2401. );
  2402. FW:AddCommand("wowbuild",
  2403.     function()
  2404.         local version, build, date, tocversion = GetBuildInfo();
  2405.         FW:Show("version:"..version..", build:"..build..", date:"..date..", tocversion:"..tocversion);
  2406.     end
  2407. );
  2408. FW:AddCommand("resetfont",
  2409.     function()
  2410.         FW.Settings.OptionsHeaderFont[1] = FW.Default.OptionsHeaderFont[1];
  2411.         FW.Settings.OptionsHeaderFont[2] = FW.Default.OptionsHeaderFont[2];
  2412.         FW.Settings.OptionsFont[1] = FW.Default.OptionsFont[1];
  2413.         FW.Settings.OptionsFont[2] = FW.Default.OptionsFont[2];
  2414.         FW:RefreshOptions();
  2415.     end
  2416. );
  2417.  
  2418. FW:RegisterMessage(FW.GET_HEALTHSTONE,
  2419.     function()
  2420.         if FW.LastHSCheck + 5 < GetTime() then
  2421.             FW.LastHSCheck = GetTime();
  2422.             FW_CheckHealthstone();
  2423.         end
  2424.         return 1;
  2425.     end,
  2426. nil);
  2427. FW:RegisterMessage(GET_VERSION,FW_SendVersion,nil);
  2428. FW:RegisterMessage(SEND_VERSION,
  2429.     function(m,f)
  2430.         if FX_Saved.RaidStatus[f] then
  2431.             FX_Saved.RaidStatus[f][4] = m;
  2432.         else
  2433.             fx2temp[f] = a1;
  2434.         end
  2435.         return 1;
  2436.     end,
  2437. nil);
  2438. --[[FW:RegisterMessage(GET_SPECC,FW_SendSpeccInfo,nil);
  2439. FW:RegisterMessage(SEND_SPECC,
  2440.     function(m,f)
  2441.         local id = FW:NameToID(f);
  2442.         if id then
  2443.             local class = select(2,UnitClass(id));
  2444.             if not FX_Saved.Speccs[class] then
  2445.                 FX_Saved.Speccs[class] = {};
  2446.             end
  2447.             FX_Saved.Speccs[class][f] =  m;
  2448.         end
  2449.         return 1;
  2450.     end,
  2451. nil);]]
  2452.  
  2453. FW.Default = {
  2454.     OptionsFontLabelColor = {1,1,1},
  2455.     OptionsFontInputColor = {1,1,1},
  2456.  
  2457.     AnimationInterval = 0.04,
  2458.     LoadDelay = 1,
  2459.     UpdateInterval = 0.5,
  2460.     Chill = 0.05,
  2461.  
  2462.     AnimateScroll = false,
  2463.  
  2464.     FrameSnapDistance = 5,
  2465.     FrameDistance = 0,
  2466.     FrameSnap = true,
  2467.     --FrameAnchor = false,
  2468.     OptionsColums = 2,
  2469.     OptionsHeight = 440,
  2470.  
  2471.     TimeFormat = true,
  2472.     Texture = "Interface\\AddOns\\Forte_Core\\Textures\\Aluminium",
  2473.  
  2474.     RightClickOptions = true,
  2475.     RightClickIconOptions = true,
  2476.  
  2477.     LinkProfile = false,
  2478.     LinkClone = false,
  2479.  
  2480.     OptionBackgroundColor = {0.18,0.18,0.18,0.90},
  2481.  
  2482.     OptionHeaderColor =     {0.20,0.20,0.20},
  2483.     LinkProfileColor =      {[0]=true,1.00,1.00,0.00,0.10},
  2484.     LinkCloneColor =        {[0]=true,1.00,0.50,0.00,0.10},
  2485.     LinkBothColor =         {[0]=true,1.00,1.00,1.00,0.10},
  2486.     LinkNoneColor =         {[0]=false,0.50,0.00,1.00,0.10},
  2487.  
  2488.     DiffProfileColor =      {[0]=true,1.00,1.00,0.00,0.20},
  2489.     DiffCloneColor =        {[0]=true,1.00,0.50,0.00,0.20},
  2490.     DiffBothColor =         {[0]=true,1.00,1.00,1.00,0.20},
  2491.     DiffNoneColor =         {[0]=false,0.00,1.00,0.00,0.20},
  2492.  
  2493.     Font = {"Interface\\AddOns\\Forte_Core\\Fonts\\GOTHIC.TTF",11},
  2494.     GlobalLock = false,
  2495.     GlobalAlpha = 1.0,
  2496.     GlobalScale = 1.0,
  2497.     GlobalSpark = {[0]=true,0.7},
  2498.  
  2499.     --SparkOverrideEnable = false,
  2500.     --SparkOverrideColor = {1.00,1.00,1.00},
  2501.  
  2502.     OutputRaid = true,
  2503.     Output = {[0]=true,"MyProChannel"},
  2504.  
  2505.     OptionsModuleColor = true,
  2506.     Tips = true,
  2507.     SpellGroupTips = true,
  2508.  
  2509.     TimeLeft =          {[0]=1,">> %s on %s is fading in %s <<"},
  2510.     TimeLeftNoTarg =    {[0]=1,">> %s is fading in %s <<"},
  2511.     CooldownLeft =      {[0]=1,">> %s is ready in %s <<"},
  2512.  
  2513.     GlobalFrameNames = false,
  2514.  
  2515.     Strata = "MEDIUM",
  2516.  
  2517.     ShowStartupText = true,
  2518.     ExpandSubcats = false,
  2519.     LoadExpandSubcats = true,
  2520.  
  2521.     OptionsBackdrop = {
  2522.         "Interface\\AddOns\\Forte_Core\\Textures\\Background",
  2523.         "Interface\\AddOns\\Forte_Core\\Textures\\Border",
  2524.         false,16,5,5
  2525.     },
  2526.     OptionsHeaderTexture = "Interface\\AddOns\\Forte_Core\\Textures\\Otravi",
  2527.     OptionsSubHeaderTexture = "Interface\\AddOns\\Forte_Core\\Textures\\Minimalist",
  2528.    
  2529.     TimerSpellsTooltip = true,
  2530. };
  2531. FW:SetDefaultFont("Interface\\AddOns\\Forte_Core\\Fonts\\GOTHIC.TTF", 11);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement