├── Bindings.xml
├── HealingBar.xml
├── QuickClick.lua
├── QuickHeal.lua
├── QuickHeal.toc
├── QuickHeal.xml
├── QuickHealDruid.lua
├── QuickHealPaladin.lua
├── QuickHealPriest.lua
├── QuickHealShaman.lua
├── README.md
├── libs
├── AceAddon-2.0
│ └── AceAddon-2.0.lua
├── AceConsole-2.0
│ └── AceConsole-2.0.lua
├── AceEvent-2.0
│ └── AceEvent-2.0.lua
├── HealComm-1.0
│ └── HealComm-1.0.lua
└── RosterLib-2.0
│ └── RosterLib-2.0.lua
├── localization.de.lua
├── localization.en.lua
└── localization.fr.lua
/Bindings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | if QUICKHEAL_LOADED then QuickHeal() end
4 |
5 |
6 | if QUICKHEAL_LOADED then QuickHeal('subgroup') end
7 |
8 |
9 | if QUICKHEAL_LOADED then QuickHeal('party') end
10 |
11 |
12 | if QUICKHEAL_LOADED then QuickHeal('mt') end
13 |
14 |
15 | if QUICKHEAL_LOADED then QuickHeal('nonmt') end
16 |
17 |
18 | if QUICKHEAL_LOADED then QuickHeal('player') end
19 |
20 |
21 | if QUICKHEAL_LOADED then QuickHeal('target') end
22 |
23 |
24 | if QUICKHEAL_LOADED then QuickHeal('targettarget') end
25 |
26 |
27 | if QUICKHEAL_LOADED then QuickHeal_Toggle_Healthy_Threshold() end
28 |
29 |
30 | if QUICKHEAL_LOADED then ToggleDownrankWindow() end
31 |
32 |
--------------------------------------------------------------------------------
/HealingBar.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | this:SetMinMaxValues(0,1);
73 | this:SetValue(0.5);
74 | this:SetFrameLevel(this:GetFrameLevel() - 1)
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | this:SetMinMaxValues(0,2);
112 | this:SetValue(1);
113 | this:SetFrameLevel(this:GetFrameLevel() - 2)
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | if QuickHealConfig:IsVisible() and (arg1 == "LeftButton") then
123 | this:StartMoving();
124 | end
125 |
126 |
127 | if QuickHealConfig:IsVisible() then
128 | if (arg1 == "LeftButton") then
129 | this:StopMovingOrSizing();
130 | elseif (arg1 == "RightButton") then
131 | QuickHealHealingBar:ClearAllPoints();
132 | QuickHealHealingBar:SetPoint("CENTER",CastingBarFrame,"CENTER",0,30)
133 | end
134 | end
135 |
136 |
137 | if QuickHealConfig:IsVisible() then
138 | GameTooltip:SetOwner(this,"ANCHOR_TOPLEFT");
139 | GameTooltip:SetText("Healing Bar Configuration\nLeft-click to drag.\nRight-click to re-attach to Casting Bar.");
140 | this.tooltipShown = true;
141 | end
142 |
143 |
144 | GameTooltip:Hide();
145 | this.tooltipShown = false;
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
--------------------------------------------------------------------------------
/QuickClick.lua:
--------------------------------------------------------------------------------
1 | local IsQuickClickKeyDown = IsControlKeyDown;
2 | local MouseButton = "LeftButton";
3 | local BlizzardFrames = {"PlayerFrame","PetFrame","TargetFrame","TargetofTarget","PartyMemberFrame","PartyMemberPetFrame"};
4 | QuickClick_OldOnClick = {};
5 |
6 | --[ Click event handlers ]--
7 |
8 | local function QuickClick(button,unit)
9 | if IsQuickClickKeyDown() and button == MouseButton then
10 | QuickHeal(unit);
11 | return true;
12 | else return false end
13 | end
14 |
15 | -- PlayerFrame
16 | function QuickClick_PlayerFrame_OnClick(button)
17 | if not QuickClick(button,this.unit) then QuickClick_OldOnClick.PlayerFrame(button) end
18 | end
19 | -- PetFrame
20 | function QuickClick_PetFrame_OnClick(button)
21 | if not QuickClick(button,this.unit) then QuickClick_OldOnClick.PetFrame(button) end
22 | end
23 | -- TargetFrame
24 | function QuickClick_TargetFrame_OnClick(button)
25 | if not QuickClick(button,this.unit) then QuickClick_OldOnClick.TargetFrame(button) end
26 | end
27 | -- TargetofTarget
28 | function QuickClick_TargetofTarget_OnClick(button)
29 | if not QuickClick(button,this.unit) then QuickClick_OldOnClick.TargetofTarget(button) end
30 | end
31 | -- PartyMemberFrame
32 | function QuickClick_PartyMemberFrame_OnClick(partyFrame)
33 | if not QuickClick(arg1,this.unit) then QuickClick_OldOnClick.PartyMemberFrame(partyFrame) end
34 | end
35 | -- PartyMemberPetFrame
36 | function QuickClick_PartyMemberPetFrame_OnClick()
37 | if not QuickClick(arg1,this.unit) then QuickClick_OldOnClick.PartyMemberPetFrame() end
38 | end
39 |
40 | -- EasyRaid
41 | function QuickClick_ER_RaidPulloutButton_OnClick()
42 | if not QuickClick(arg1, this.unit or this:GetParent().unit) then QuickClick_OldOnClick.ER_RaidPulloutButton() end
43 | end
44 | function QuickClick_ER_MainTankButton_OnClick()
45 | if not QuickClick(arg1, this.unit or this:GetParent().unit) then QuickClick_OldOnClick.ER_MainTankButton() end
46 | end
47 |
48 | -- Discord Unit Frames
49 | function QuickClick_DUF_UnitFrame_OnClick(button)
50 | if not QuickClick(button, this.unit) then QuickClick_OldOnClick.DUF_UnitFrame(button) end
51 | end
52 | function QuickClick_DUF_Element_OnClick(button)
53 | if not QuickClick(button, this.unit or this:GetParent().unit) then QuickClick_OldOnClick.DUF_Element(button) end
54 | end
55 |
56 | --[[ Loading and Unloading ]]--
57 |
58 | function QuickClick_Load()
59 | -- Hook all Blizzard provided player frames
60 | for i,v in ipairs(BlizzardFrames) do
61 | loadstring("if type("..v.."_OnClick) == \"function\" then QuickClick_OldOnClick."..v..","..v.."_OnClick = "..v.."_OnClick,QuickClick_"..v.."_OnClick end")();
62 | end
63 |
64 | -- Hook CT_RA_CustomOnClickFunction
65 | QuickClick_OldOnClick.CT_RA_CustomOnClickFunction,CT_RA_CustomOnClickFunction = CT_RA_CustomOnClickFunction,QuickClick;
66 |
67 | -- Hook EasyRaid
68 | if IsAddOnLoaded("EasyRaid") then
69 | if (type(ER_RaidPulloutButton_OnClick) == "function") and (type(ER_MainTankButton_OnClick) == "function") then
70 | QuickClick_OldOnClick.ER_RaidPulloutButton,ER_RaidPulloutButton_OnClick = ER_RaidPulloutButton_OnClick,QuickClick_ER_RaidPulloutButton_OnClick;
71 | QuickClick_OldOnClick.ER_MainTankButton,ER_MainTankButton_OnClick = ER_MainTankButton_OnClick,QuickClick_ER_MainTankButton_OnClick;
72 | end
73 | end
74 |
75 | -- Hook Perl Classic Unit Frames and X-Perl
76 | QuickClick_OldOnClick.Perl_Custom_ClickFunction,Perl_Custom_ClickFunction = Perl_Custom_ClickFunction,QuickClick;
77 |
78 | -- Hook Discord Unit Frames
79 | if IsAddOnLoaded("DiscordUnitFrames") then
80 | if (type(DUF_UnitFrame_OnClick) == "function") and (type(DUF_Element_OnClick) == "function") then
81 | QuickClick_OldOnClick.DUF_UnitFrame,DUF_UnitFrame_OnClick = DUF_UnitFrame_OnClick,QuickClick_DUF_UnitFrame_OnClick;
82 | QuickClick_OldOnClick.DUF_Element,DUF_Element_OnClick = DUF_Element_OnClick,QuickClick_DUF_Element_OnClick;
83 | end
84 | end
85 | end
86 |
87 | function QuickClick_Unload()
88 | -- Unhook all Blizzard provided player frames
89 | for i,v in ipairs(BlizzardFrames) do
90 | loadstring("if type(QuickClick_OldOnClick."..v..") == \"function\" then "..v.."_OnClick = QuickClick_OldOnClick."..v.." end")();
91 | end
92 |
93 | -- Unhook CT_RA_CustomOnClickFunction
94 | CT_RA_CustomOnClickFunction = QuickClick_OldOnClick.CT_RA_CustomOnClickFunction;
95 |
96 | -- Unhook EasyRaid
97 | if IsAddOnLoaded("EasyRaid") then
98 | if (type(QuickClick_OldOnClick.ER_RaidPulloutButton) == "function") and (type(QuickClick_OldOnClick.ER_MainTankButton) == "function") then
99 | ER_RaidPulloutButton_OnClick = QuickClick_OldOnClick.ER_RaidPulloutButton;
100 | ER_MainTankButton_OnClick = QuickClick_OldOnClick.ER_MainTankButton;
101 | end
102 | end
103 |
104 | -- Unhook Perl Classic Unit Frames and X-Perl
105 | Perl_Custom_ClickFunction = QuickClick_OldOnClick.Perl_Custom_ClickFunction;
106 |
107 | -- Unhook Discord Unit Frames
108 | if IsAddOnLoaded("DiscordUnitFrames") then
109 | if (type(QuickClick_OldOnClick.DUF_UnitFrame) == "function") and (type(QuickClick_OldOnClick.DUF_Element) == "function") then
110 | DUF_UnitFrame_OnClick = QuickClick_OldOnClick.DUF_UnitFrame;
111 | DUF_Element_OnClick = QuickClick_OldOnClick.DUF_Element;
112 | end
113 | end
114 |
115 | QuickClick_OldOnClick = {};
116 | end
117 |
118 |
119 |
--------------------------------------------------------------------------------
/QuickHeal.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 11200
2 | ## Title: QuickHeal
3 | ## Author: Thomas Thorsen, Scott Geeding and Kostas Karachalios
4 | ## Notes: Quick healing of party/raid members
5 | ## OptionalDeps: BonusScanner,Titan Panel,myAddOns,CT_RaidAssist
6 | ## SavedVariables:
7 | ## SavedVariablesPerCharacter: QuickHealVariables
8 |
9 | libs\RosterLib-2.0\RosterLib-2.0.lua
10 |
11 | libs\HealComm-1.0\HealComm-1.0.lua
12 |
13 | QuickHeal.xml
14 | HealingBar.xml
15 |
--------------------------------------------------------------------------------
/QuickHealDruid.lua:
--------------------------------------------------------------------------------
1 |
2 | function QuickHeal_Druid_GetRatioHealthyExplanation()
3 | local RatioHealthy = QuickHeal_GetRatioHealthy();
4 | local RatioFull = QuickHealVariables["RatioFull"];
5 |
6 | if RatioHealthy >= RatioFull then
7 | return QUICKHEAL_SPELL_REGROWTH .. " will always be used in combat, and " .. QUICKHEAL_SPELL_HEALING_TOUCH .. " will be used when out of combat. ";
8 | else
9 | if RatioHealthy > 0 then
10 | return QUICKHEAL_SPELL_REGROWTH .. " will be used in combat if the target has less than " .. RatioHealthy*100 .. "% life, and " .. QUICKHEAL_SPELL_HEALING_TOUCH .. " will be used otherwise. ";
11 | else
12 | return QUICKHEAL_SPELL_REGROWTH .. " will never be used. " .. QUICKHEAL_SPELL_HEALING_TOUCH .. " will always be used in and out of combat. ";
13 | end
14 | end
15 | end
16 |
17 | function QuickHeal_Druid_FindSpellToUse(Target)
18 | local SpellID = nil;
19 | local HealSize = 0;
20 |
21 | -- +Healing-PenaltyFactor = (1-((20-LevelLearnt)*0.0375)) for all spells learnt before level 20
22 | local PF1 = 0.2875;
23 | local PF8 = 0.55;
24 | local PFRG1 = 0.7 * 1.042; -- Rank 1 of RG (1.041 compensates for the 0.50 factor that should be 0.48 for RG1)
25 | local PF14 = 0.775;
26 | local PFRG2 = 0.925;
27 |
28 | -- Local aliases to access main module functionality and settings
29 | local RatioFull = QuickHealVariables["RatioFull"];
30 | local RatioHealthy = QuickHeal_GetRatioHealthy();
31 | local UnitHasHealthInfo = QuickHeal_UnitHasHealthInfo;
32 | local EstimateUnitHealNeed = QuickHeal_EstimateUnitHealNeed;
33 | local GetSpellIDs = QuickHeal_GetSpellIDs;
34 | local debug = QuickHeal_debug;
35 |
36 | -- Return immediately if no player needs healing
37 | if not Target then
38 | return SpellID,HealSize;
39 | end
40 |
41 | -- Determine health and heal need of target
42 | local healneed;
43 | local Health;
44 | if UnitHasHealthInfo(Target) then
45 | -- Full info available
46 | healneed = UnitHealthMax(Target) - UnitHealth(Target) - HealComm:getHeal(UnitName(Target)); -- Implementatio for HealComm
47 | Health = UnitHealth(Target) / UnitHealthMax(Target);
48 | else
49 | -- Estimate target health
50 | healneed = EstimateUnitHealNeed(Target,true);
51 | Health = UnitHealth(Target)/100;
52 | end
53 |
54 | -- if BonusScanner is running, get +Healing bonus
55 | local Bonus = 0;
56 | if (BonusScanner) then
57 | Bonus = tonumber(BonusScanner:GetBonus("HEAL"));
58 | debug(string.format("Equipment Healing Bonus: %d", Bonus));
59 | end
60 |
61 | -- Calculate healing bonus
62 | local healMod15 = (1.5/3.5) * Bonus;
63 | local healMod20 = (2.0/3.5) * Bonus;
64 | local healMod25 = (2.5/3.5) * Bonus;
65 | local healMod30 = (3.0/3.5) * Bonus;
66 | local healMod35 = Bonus;
67 | local healModRG = (2.0/3.5) * Bonus * 0.5; -- The 0.5 factor is calculated as DirectHeal/(DirectHeal+HoT)
68 | debug("Final Healing Bonus (1.5,2.0,2.5,3.0,3.5,Regrowth)", healMod15,healMod20,healMod25,healMod30,healMod35,healModRG);
69 |
70 | local InCombat = UnitAffectingCombat('player') or UnitAffectingCombat(Target);
71 |
72 | -- Gift of Nature - Increases healing by 2% per rank
73 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12);
74 | local gnMod = 2*talentRank/100 + 1;
75 | debug(string.format("Gift of Nature modifier: %f", gnMod));
76 |
77 | -- Tranquil Spirit - Decreases mana usage by 2% per rank on HT only
78 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,9);
79 | local tsMod = 1 - 2*talentRank/100;
80 | debug(string.format("Tranquil Spirit modifier: %f", tsMod));
81 |
82 | -- Moonglow - Decrease mana usage by 3% per rank
83 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,14);
84 | local mgMod = 1 - 3*talentRank/100;
85 | debug(string.format("Moonglow modifier: %f", mgMod));
86 |
87 | -- Improved Rejuvenation -- Increases Rejuvenation effects by 5% per rank
88 | --local _,_,_,_,talentRank,_ = GetTalentInfo(3,10);
89 | --local irMod = 5*talentRank/100 + 1;
90 | --debug(string.format("Improved Rejuvenation modifier: %f", irMod));
91 |
92 | local TargetIsHealthy = Health >= RatioHealthy;
93 | local ManaLeft = UnitMana('player');
94 |
95 | if TargetIsHealthy then
96 | debug("Target is healthy ",Health);
97 | end
98 |
99 | -- Detect Clearcasting (from Omen of Clarity, talent(1,9))
100 | if QuickHeal_DetectBuff('player',"Spell_Shadow_ManaBurn",1) then -- Spell_Shadow_ManaBurn (1)
101 | ManaLeft = UnitManaMax('player'); -- set to max mana so max spell rank will be cast
102 | healneed = 10^6; -- deliberate overheal (mana is free)
103 | debug("BUFF: Clearcasting (Omen of Clarity)");
104 | end
105 |
106 | -- Detect Nature's Swiftness (next nature spell is instant cast)
107 | if QuickHeal_DetectBuff('player',"Spell_Nature_RavenForm") then
108 | debug("BUFF: Nature's Swiftness (out of combat healing forced)");
109 | InCombat = false;
110 | end
111 |
112 | -- Detect proc of 'Hand of Edward the Odd' mace (next spell is instant cast)
113 | if QuickHeal_DetectBuff('player',"Spell_Holy_SearingLight") then
114 | debug("BUFF: Hand of Edward the Odd (out of combat healing forced)");
115 | InCombat = false;
116 | end
117 |
118 | -- Get total healing modifier (factor) caused by healing target debuffs
119 | local HDB = QuickHeal_GetHealModifier(Target);
120 | debug("Target debuff healing modifier",HDB);
121 | healneed = healneed/HDB;
122 |
123 | -- Get a list of ranks available for all spells
124 | local SpellIDsHT = GetSpellIDs(QUICKHEAL_SPELL_HEALING_TOUCH);
125 | local SpellIDsRG = GetSpellIDs(QUICKHEAL_SPELL_REGROWTH);
126 | --local SpellIDsRJ = GetSpellIDs(QUICKHEAL_SPELL_REJUVENATION);
127 |
128 | local maxRankHT = table.getn(SpellIDsHT);
129 | local maxRankRG = table.getn(SpellIDsRG);
130 | --local maxRankRJ = table.getn(SpellIDsRJ);
131 |
132 | debug(string.format("Found HT up to rank %d, RG up to rank %d", maxRankHT, maxRankRG));
133 |
134 | -- Compensation for health lost during combat
135 | local k=1.0;
136 | local K=1.0;
137 | if InCombat then
138 | k=0.9;
139 | K=0.8;
140 | end
141 |
142 | -- Find suitable SpellID based on the defined criteria
143 | if not InCombat or TargetIsHealthy or maxRankRG<1 then
144 | -- Not in combat or target is healthy so use the closest available mana efficient healing
145 | debug(string.format("Not in combat or target healthy or no Regrowth available, will use Healing Touch"))
146 | if Health < RatioFull then
147 | SpellID = SpellIDsHT[1]; HealSize = 44*gnMod+healMod15*PF1; -- Default to rank 1
148 | if healneed > ( 100*gnMod+healMod20*PF8 )*k and ManaLeft >= 55*tsMod*mgMod and maxRankHT >= 2 then SpellID = SpellIDsHT[2]; HealSize = 100*gnMod+healMod20*PF8 end
149 | if healneed > ( 219*gnMod+healMod25*PF14)*K and ManaLeft >= 110*tsMod*mgMod and maxRankHT >= 3 then SpellID = SpellIDsHT[3]; HealSize = 219*gnMod+healMod25*PF14 end
150 | if healneed > ( 404*gnMod+healMod30)*K and ManaLeft >= 185*tsMod*mgMod and maxRankHT >= 4 then SpellID = SpellIDsHT[4]; HealSize = 404*gnMod+healMod30 end
151 | if healneed > ( 633*gnMod+healMod35)*K and ManaLeft >= 270*tsMod*mgMod and maxRankHT >= 5 then SpellID = SpellIDsHT[5]; HealSize = 633*gnMod+healMod35 end
152 | if healneed > ( 818*gnMod+healMod35)*K and ManaLeft >= 335*tsMod*mgMod and maxRankHT >= 6 then SpellID = SpellIDsHT[6]; HealSize = 818*gnMod+healMod35 end
153 | if healneed > (1028*gnMod+healMod35)*K and ManaLeft >= 405*tsMod*mgMod and maxRankHT >= 7 then SpellID = SpellIDsHT[7]; HealSize = 1028*gnMod+healMod35 end
154 | if healneed > (1313*gnMod+healMod35)*K and ManaLeft >= 495*tsMod*mgMod and maxRankHT >= 8 then SpellID = SpellIDsHT[8]; HealSize = 1313*gnMod+healMod35 end
155 | if healneed > (1656*gnMod+healMod35)*K and ManaLeft >= 600*tsMod*mgMod and maxRankHT >= 9 then SpellID = SpellIDsHT[9]; HealSize = 1656*gnMod+healMod35 end
156 | if healneed > (2060*gnMod+healMod35)*K and ManaLeft >= 720*tsMod*mgMod and maxRankHT >= 10 then SpellID = SpellIDsHT[10]; HealSize = 2060*gnMod+healMod35 end
157 | if healneed > (2472*gnMod+healMod35)*K and ManaLeft >= 800*tsMod*mgMod and maxRankHT >= 11 then SpellID = SpellIDsHT[11]; HealSize = 2472*gnMod+healMod35 end
158 | end
159 | else
160 | -- In combat and target is unhealthy and player has Regrowth
161 | debug(string.format("In combat and target unhealthy and Regrowth available, will use Regrowth"));
162 | if Health < RatioFull then
163 | SpellID = SpellIDsRG[1]; HealSize = 91*gnMod+healModRG*PFRG1; -- Default to rank 1
164 | if healneed > ( 176*gnMod+healModRG*PFRG2)*k and ManaLeft >= 205*mgMod and maxRankRG >= 2 then SpellID = SpellIDsRG[2]; HealSize = 176*gnMod+healModRG*PFRG2 end
165 | if healneed > ( 257*gnMod+healModRG)*k and ManaLeft >= 280*mgMod and maxRankRG >= 3 then SpellID = SpellIDsRG[3]; HealSize = 257*gnMod+healModRG end
166 | if healneed > ( 339*gnMod+healModRG)*k and ManaLeft >= 350*mgMod and maxRankRG >= 4 then SpellID = SpellIDsRG[4]; HealSize = 339*gnMod+healModRG end
167 | if healneed > ( 431*gnMod+healModRG)*k and ManaLeft >= 420*mgMod and maxRankRG >= 5 then SpellID = SpellIDsRG[5]; HealSize = 431*gnMod+healModRG end
168 | if healneed > ( 543*gnMod+healModRG)*k and ManaLeft >= 510*mgMod and maxRankRG >= 6 then SpellID = SpellIDsRG[6]; HealSize = 543*gnMod+healModRG end
169 | if healneed > ( 686*gnMod+healModRG)*k and ManaLeft >= 615*mgMod and maxRankRG >= 7 then SpellID = SpellIDsRG[7]; HealSize = 686*gnMod+healModRG end
170 | if healneed > ( 857*gnMod+healModRG)*k and ManaLeft >= 740*mgMod and maxRankRG >= 8 then SpellID = SpellIDsRG[8]; HealSize = 857*gnMod+healModRG end
171 | if healneed > (1061*gnMod+healModRG)*k and ManaLeft >= 880*mgMod and maxRankRG >= 9 then SpellID = SpellIDsRG[9]; HealSize = 1061*gnMod+healModRG end
172 | end
173 | end
174 |
175 | return SpellID,HealSize*HDB;
176 | end
177 |
--------------------------------------------------------------------------------
/QuickHealPaladin.lua:
--------------------------------------------------------------------------------
1 |
2 | function QuickHeal_Paladin_GetRatioHealthyExplanation()
3 | local RatioHealthy = QuickHeal_GetRatioHealthy();
4 | local RatioFull = QuickHealVariables["RatioFull"];
5 |
6 | if RatioHealthy >= RatioFull then
7 | return QUICKHEAL_SPELL_HOLY_LIGHT .. " will never be used in combat. ";
8 | else
9 | if RatioHealthy > 0 then
10 | return QUICKHEAL_SPELL_HOLY_LIGHT .. " will only be used in combat if the target has more than " .. RatioHealthy*100 .. "% life, and only if the healing done is greater than the greatest " .. QUICKHEAL_SPELL_FLASH_OF_LIGHT .. " available. ";
11 | else
12 | return QUICKHEAL_SPELL_HOLY_LIGHT .. " will only be used in combat if the healing done is greater than the greatest " .. QUICKHEAL_SPELL_FLASH_OF_LIGHT .. " available. ";
13 | end
14 | end
15 | end
16 |
17 | function QuickHeal_Paladin_FindSpellToUse(Target)
18 | local SpellID = nil;
19 | local HealSize = 0;
20 |
21 | -- +Healing-PenaltyFactor = (1-((20-LevelLearnt)*0.0375)) for all spells learnt before level 20
22 | local PF1 = 0.2875;
23 | local PF6 = 0.475;
24 | local PF14 = 0.775;
25 |
26 | -- Local aliases to access main module functionality and settings
27 | local RatioFull = QuickHealVariables["RatioFull"];
28 | local RatioHealthy = QuickHeal_GetRatioHealthy();
29 | local UnitHasHealthInfo = QuickHeal_UnitHasHealthInfo;
30 | local EstimateUnitHealNeed = QuickHeal_EstimateUnitHealNeed;
31 | local GetSpellIDs = QuickHeal_GetSpellIDs;
32 | local debug = QuickHeal_debug;
33 |
34 | -- Return immediatly if no player needs healing
35 | if not Target then
36 | return SpellID,HealSize;
37 | end
38 |
39 | -- Determine health and healneed of target
40 | local healneed;
41 | local Health;
42 |
43 | if UnitHasHealthInfo(Target) then
44 | -- Full info available
45 | healneed = UnitHealthMax(Target) - UnitHealth(Target) - HealComm:getHeal(UnitName(Target)); -- Implementatio for HealComm
46 | Health = UnitHealth(Target) / UnitHealthMax(Target);
47 | else
48 | -- Estimate target health
49 | healneed = EstimateUnitHealNeed(Target,true);
50 | Health = UnitHealth(Target)/100;
51 | end
52 |
53 | -- if BonusScanner is running, get +Healing bonus
54 | local Bonus = 0;
55 | if (BonusScanner) then
56 | Bonus = tonumber(BonusScanner:GetBonus("HEAL"));
57 | debug(string.format("Equipment Healing Bonus: %d", Bonus));
58 | end
59 |
60 | -- Calculate healing bonus
61 | local healMod15 = (1.5/3.5) * Bonus;
62 | local healMod25 = (2.5/3.5) * Bonus;
63 | debug("Final Healing Bonus (1.5,2.5)", healMod15,healMod25);
64 |
65 | local InCombat = UnitAffectingCombat('player') or UnitAffectingCombat(Target);
66 |
67 | -- Healing Light Talent (increases healing by 4% per rank)
68 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5);
69 | local hlMod = 4*talentRank/100 + 1;
70 | debug(string.format("Healing Light talentmodification: %f", hlMod))
71 |
72 | local TargetIsHealthy = Health >= RatioHealthy;
73 | local ManaLeft = UnitMana('player');
74 |
75 | if TargetIsHealthy then
76 | debug("Target is healthy",Health);
77 | end
78 |
79 | -- Detect proc of 'Hand of Edward the Odd' mace (next spell is instant cast)
80 | if QuickHeal_DetectBuff('player',"Spell_Holy_SearingLight") then
81 | debug("BUFF: Hand of Edward the Odd (out of combat healing forced)");
82 | InCombat = false;
83 | end
84 |
85 | -- Get total healing modifier (factor) caused by healing target debuffs
86 | local HDB = QuickHeal_GetHealModifier(Target);
87 | debug("Target debuff healing modifier",HDB);
88 | healneed = healneed/HDB;
89 |
90 | -- Get a list of ranks available of 'Lesser Healing Wave' and 'Healing Wave'
91 | local SpellIDsHL = GetSpellIDs(QUICKHEAL_SPELL_HOLY_LIGHT);
92 | local SpellIDsFL = GetSpellIDs(QUICKHEAL_SPELL_FLASH_OF_LIGHT);
93 | local maxRankHL = table.getn(SpellIDsHL);
94 | local maxRankFL = table.getn(SpellIDsFL);
95 | local NoFL = maxRankFL < 1;
96 | debug(string.format("Found HL up to rank %d, and found FL up to rank %d", maxRankHL, maxRankFL))
97 |
98 | --Get max HealRanks that are allowed to be used
99 | local downRankFH = QuickHealVariables.DownrankValueFH -- rank for 1.5 sec heals
100 | local downRankNH = QuickHealVariables.DownrankValueNH -- rank for < 1.5 sec heals
101 |
102 |
103 | -- below changed to not differentiate between in or out if combat. Original code down below
104 | -- Find suitable SpellID based on the defined criteria
105 | local k = 1;
106 | local K = 1;
107 | if InCombat then
108 | local k = 0.9; -- In combat means that target is loosing life while casting, so compensate
109 | local K = 0.8; -- k for fast spells (LHW and HW Rank 1 and 2) and K for slow spells (HW) 3 = 4 | 3 < 4 | 3 > 4
110 | end
111 |
112 | if Health < RatioFull then
113 | if maxRankFL >=1 then SpellID = SpellIDsFL[1]; HealSize = 67*hlMod+healMod15 else SpellID = SpellIDsHL[1]; HealSize = 43*hlMod+healMod25*PF1 end -- Default to rank 1 of FL or HL
114 | if healneed > ( 83*hlMod+healMod25*PF6 )*K and ManaLeft >= 60 and maxRankHL >=2 and (TargetIsHealthy and maxRankFL <= 1 or NoFL) then SpellID = SpellIDsHL[2]; HealSize = 83*hlMod+healMod25*PF6 end
115 | if healneed > (103*hlMod+healMod15) *k and ManaLeft >= 50 and maxRankFL >=2 and downRankFH >= 2 then SpellID = SpellIDsFL[2]; HealSize = 103*hlMod+healMod15 end
116 | if healneed > (154*hlMod+healMod15) *k and ManaLeft >= 70 and maxRankFL >=3 and downRankFH >= 3 then SpellID = SpellIDsFL[3]; HealSize = 154*hlMod+healMod15 end
117 | if healneed > (173*hlMod+healMod25*PF14)*K and ManaLeft >= 110 and maxRankHL >=3 and (TargetIsHealthy and maxRankFL <= 3 or NoFL) then SpellID = SpellIDsHL[3]; HealSize = 173*hlMod+healMod25*PF14 end
118 | if healneed > (209*hlMod+healMod15) *k and ManaLeft >= 90 and maxRankFL >=4 and downRankFH >= 4 then SpellID = SpellIDsFL[4]; HealSize = 209*hlMod+healMod15 end
119 | if healneed > (283*hlMod+healMod15) *k and ManaLeft >= 115 and maxRankFL >=5 and downRankFH >= 5 then SpellID = SpellIDsFL[5]; HealSize = 283*hlMod+healMod15 end
120 | if healneed > (333*hlMod+healMod25) *K and ManaLeft >= 190 and maxRankHL >=4 and (TargetIsHealthy and maxRankFL <= 5 or NoFL) then SpellID = SpellIDsHL[4]; HealSize = 333*hlMod+healMod25 end
121 | if healneed > (363*hlMod+healMod15) *k and ManaLeft >= 140 and maxRankFL >=6 and downRankFH >= 6 then SpellID = SpellIDsFL[6]; HealSize = 363*hlMod+healMod15 end
122 | if healneed > (522*hlMod+healMod25) *K and ManaLeft >= 275 and maxRankHL >=5 and (TargetIsHealthy and maxRankFL <= 6 or NoFL) then SpellID = SpellIDsHL[5]; HealSize = 522*hlMod+healMod25 end
123 | if healneed > (739*hlMod+healMod25) *K and ManaLeft >= 365 and maxRankHL >=6 and (TargetIsHealthy and maxRankFL <= 6 or NoFL) then SpellID = SpellIDsHL[6]; HealSize = 739*hlMod+healMod25 end
124 | if healneed > (999*hlMod+healMod25) *K and ManaLeft >= 465 and maxRankHL >=7 and (TargetIsHealthy and maxRankFL <= 6 or NoFL) then SpellID = SpellIDsHL[7]; HealSize = 999*hlMod+healMod25 end
125 | if healneed > (1317*hlMod+healMod25) *K and ManaLeft >= 580 and maxRankHL >=8 and (TargetIsHealthy and maxRankFL <= 6 or NoFL) then SpellID = SpellIDsHL[8]; HealSize = 1317*hlMod+healMod25 end
126 | if healneed > (1680*hlMod+healMod25) *K and ManaLeft >= 660 and maxRankHL >=9 and (TargetIsHealthy and maxRankFL <= 6 or NoFL) then SpellID = SpellIDsHL[9]; HealSize = 1680*hlMod+healMod25 end
127 | end
128 | return SpellID,HealSize*HDB;
129 | end
130 |
131 |
132 |
133 |
134 | --Original Code
135 | -- -- Find suitable SpellID based on the defined criteria
136 | -- if InCombat then
137 | -- local k = 0.9; -- In combat means that target is loosing life while casting, so compensate
138 | -- local K = 0.8; -- k for fast spells (LHW and HW Rank 1 and 2) and K for slow spells (HW)
139 | -- if Health < RatioFull then
140 | -- if maxRankFL >=1 then SpellID = SpellIDsFL[1]; HealSize = 67*hlMod+healMod15 else SpellID = SpellIDsHL[1]; HealSize = 43*hlMod+healMod25*PF1 end -- Default to rank 1 of FL or HL
141 | -- if healneed > ( 83*hlMod+healMod25*PF6 )*K and ManaLeft >= 60 and maxRankHL >=2 and (TargetIsHealthy and maxRankFL <= 1 or NoFL) then SpellID = SpellIDsHL[2]; HealSize = 83*hlMod+healMod25*PF6 end
142 | -- if healneed > (103*hlMod+healMod15) *k and ManaLeft >= 50 and maxRankFL >=2 then SpellID = SpellIDsFL[2]; HealSize = 103*hlMod+healMod15 end
143 | -- if healneed > (154*hlMod+healMod15) *k and ManaLeft >= 70 and maxRankFL >=3 then SpellID = SpellIDsFL[3]; HealSize = 154*hlMod+healMod15 end
144 | -- if healneed > (173*hlMod+healMod25*PF14)*K and ManaLeft >= 110 and maxRankHL >=3 and (TargetIsHealthy and maxRankFL <= 3 or NoFL) then SpellID = SpellIDsHL[3]; HealSize = 173*hlMod+healMod25*PF14 end
145 | -- if healneed > (209*hlMod+healMod15) *k and ManaLeft >= 90 and maxRankFL >=4 then SpellID = SpellIDsFL[4]; HealSize = 209*hlMod+healMod15 end
146 | -- if healneed > (283*hlMod+healMod15) *k and ManaLeft >= 115 and maxRankFL >=5 then SpellID = SpellIDsFL[5]; HealSize = 283*hlMod+healMod15 end
147 | -- if healneed > (333*hlMod+healMod25) *K and ManaLeft >= 190 and maxRankHL >=4 and (TargetIsHealthy and maxRankFL <= 5 or NoFL) then SpellID = SpellIDsHL[4]; HealSize = 333*hlMod+healMod25 end
148 | -- if healneed > (363*hlMod+healMod15) *k and ManaLeft >= 140 and maxRankFL >=6 then SpellID = SpellIDsFL[6]; HealSize = 363*hlMod+healMod15 end
149 | -- if healneed > (522*hlMod+healMod25) *K and ManaLeft >= 275 and maxRankHL >=5 and (TargetIsHealthy and maxRankFL <= 6 or NoFL) then SpellID = SpellIDsHL[5]; HealSize = 522*hlMod+healMod25 end
150 | -- if healneed > (739*hlMod+healMod25) *K and ManaLeft >= 365 and maxRankHL >=6 and (TargetIsHealthy and maxRankFL <= 6 or NoFL) then SpellID = SpellIDsHL[6]; HealSize = 739*hlMod+healMod25 end
151 | -- if healneed > (999*hlMod+healMod25) *K and ManaLeft >= 465 and maxRankHL >=7 and (TargetIsHealthy and maxRankFL <= 6 or NoFL) then SpellID = SpellIDsHL[7]; HealSize = 999*hlMod+healMod25 end
152 | -- if healneed > (1317*hlMod+healMod25) *K and ManaLeft >= 580 and maxRankHL >=8 and (TargetIsHealthy and maxRankFL <= 6 or NoFL) then SpellID = SpellIDsHL[8]; HealSize = 1317*hlMod+healMod25 end
153 | -- if healneed > (1680*hlMod+healMod25) *K and ManaLeft >= 660 and maxRankHL >=9 and (TargetIsHealthy and maxRankFL <= 6 or NoFL) then SpellID = SpellIDsHL[9]; HealSize = 1680*hlMod+healMod25 end
154 | -- end
155 | -- else
156 | -- -- Not in combat
157 | -- if Health < RatioFull then
158 | -- if maxRankFL >=1 then SpellID = SpellIDsFL[1]; HealSize = 67*hlMod+healMod15 else SpellID = SpellIDsHL[1]; HealSize = 43*hlMod+healMod25*PF1 end -- Default to rank 1 of FL or HL
159 | -- if healneed > ( 83*hlMod+healMod25*PF6 ) and ManaLeft >= 60 and maxRankHL >=2 and maxRankFL <= 1 then SpellID = SpellIDsHL[2]; HealSize = 83*hlMod+healMod25*PF6 end
160 | -- if healneed > (103*hlMod+healMod15) and ManaLeft >= 50 and maxRankFL >=2 then SpellID = SpellIDsFL[2]; HealSize = 103*hlMod+healMod15 end
161 | -- if healneed > (154*hlMod+healMod15) and ManaLeft >= 70 and maxRankFL >=3 then SpellID = SpellIDsFL[3]; HealSize = 154*hlMod+healMod15 end
162 | -- if healneed > (173*hlMod+healMod25*PF14) and ManaLeft >= 110 and maxRankHL >=3 and maxRankFL <= 3 then SpellID = SpellIDsHL[3]; HealSize = 173*hlMod+healMod25*PF14 end
163 | -- if healneed > (209*hlMod+healMod15) and ManaLeft >= 90 and maxRankFL >=4 then SpellID = SpellIDsFL[4]; HealSize = 209*hlMod+healMod15 end
164 | -- if healneed > (283*hlMod+healMod15) and ManaLeft >= 115 and maxRankFL >=5 then SpellID = SpellIDsFL[5]; HealSize = 283*hlMod+healMod15 end
165 | -- if healneed > (333*hlMod+healMod25) and ManaLeft >= 190 and maxRankHL >=4 and maxRankFL <= 5 then SpellID = SpellIDsHL[4]; HealSize = 333*hlMod+healMod25 end
166 | -- if healneed > (363*hlMod+healMod15) and ManaLeft >= 140 and maxRankFL >=6 then SpellID = SpellIDsFL[6]; HealSize = 363*hlMod+healMod15 end
167 | -- if healneed > (522*hlMod+healMod25) and ManaLeft >= 275 and maxRankHL >=5 then SpellID = SpellIDsHL[5]; HealSize = 522*hlMod+healMod25 end
168 | -- if healneed > (739*hlMod+healMod25) and ManaLeft >= 365 and maxRankHL >=6 then SpellID = SpellIDsHL[6]; HealSize = 739*hlMod+healMod25 end
169 | -- if healneed > (999*hlMod+healMod25) and ManaLeft >= 465 and maxRankHL >=7 then SpellID = SpellIDsHL[7]; HealSize = 999*hlMod+healMod25 end
170 | -- if healneed > (1317*hlMod+healMod25) and ManaLeft >= 580 and maxRankHL >=8 then SpellID = SpellIDsHL[8]; HealSize = 1317*hlMod+healMod25 end
171 | -- if healneed > (1680*hlMod+healMod25) and ManaLeft >= 660 and maxRankHL >=9 then SpellID = SpellIDsHL[9]; HealSize = 1680*hlMod+healMod25 end
172 | -- end
173 | -- end
174 | -- return SpellID,HealSize*HDB;
175 | --end
--------------------------------------------------------------------------------
/QuickHealPriest.lua:
--------------------------------------------------------------------------------
1 | local function writeLine(s,r,g,b)
2 | if DEFAULT_CHAT_FRAME then
3 | DEFAULT_CHAT_FRAME:AddMessage(s, r or 1, g or 1, b or 0.5)
4 | end
5 | end
6 |
7 | function QuickHeal_Priest_GetRatioHealthyExplanation()
8 | if QuickHealVariables.RatioHealthyPriest >= QuickHealVariables.RatioFull then
9 | return QUICKHEAL_SPELL_FLASH_HEAL .. " will always be used in combat, and " .. QUICKHEAL_SPELL_LESSER_HEAL .. ", " .. QUICKHEAL_SPELL_HEAL .. " or " .. QUICKHEAL_SPELL_GREATER_HEAL .. " will be used when out of combat. ";
10 | else
11 | if QuickHealVariables.RatioHealthyPriest > 0 then
12 | return QUICKHEAL_SPELL_FLASH_HEAL .. " will be used in combat if the target has less than " .. QuickHealVariables.RatioHealthyPriest*100 .. "% life, and " .. QUICKHEAL_SPELL_LESSER_HEAL .. ", " .. QUICKHEAL_SPELL_HEAL .. " or " .. QUICKHEAL_SPELL_GREATER_HEAL .. " will be used otherwise. ";
13 | else
14 | return QUICKHEAL_SPELL_FLASH_HEAL .. " will never be used. " .. QUICKHEAL_SPELL_LESSER_HEAL .. ", " .. QUICKHEAL_SPELL_HEAL .. " or " .. QUICKHEAL_SPELL_GREATER_HEAL .. " will always be used in and out of combat. ";
15 | end
16 | end
17 | end
18 |
19 | function QuickHeal_Priest_FindSpellToUse(Target)
20 | local SpellID = nil;
21 | local HealSize = 0;
22 | -- Return immediatly if no player needs healing
23 | if not Target then
24 | return SpellID,HealSize;
25 | end
26 |
27 | -- +Healing-PenaltyFactor = (1-((20-LevelLearnt)*0.0375)) for all spells learnt before level 20
28 | local PF1 = 0.2875;
29 | local PF4 = 0.4;
30 | local PF10 = 0.625;
31 | local PF18 = 0.925;
32 |
33 | -- Determine health and healneed of target
34 | local healneed;
35 | local Health;
36 |
37 | if QuickHeal_UnitHasHealthInfo(Target) then
38 | -- Full info available
39 | healneed = UnitHealthMax(Target) - UnitHealth(Target) - HealComm:getHeal(UnitName(Target)); -- Implementatin for HealComm
40 | Health = UnitHealth(Target) / UnitHealthMax(Target);
41 | else
42 | -- Estimate target health
43 | healneed = QuickHeal_EstimateUnitHealNeed(Target,true); -- needs HealComm implementation maybe
44 | Health = UnitHealth(Target)/100;
45 | end
46 |
47 | -- if BonusScanner is running, get +Healing bonus
48 | local Bonus = 0;
49 | if (BonusScanner) then
50 | Bonus = tonumber(BonusScanner:GetBonus("HEAL"));
51 | QuickHeal_debug(string.format("Equipment Healing Bonus: %d", Bonus));
52 | end
53 |
54 | -- Spiritual Guidance - Increases spell damage and healing by up to 5% (per rank) of your total Spirit.
55 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14);
56 | local _,Spirit,_,_ = UnitStat('player',5);
57 | local sgMod = Spirit * 5*talentRank/100;
58 | QuickHeal_debug(string.format("Spiritual Guidance Bonus: %f", sgMod));
59 |
60 | -- Calculate healing bonus
61 | local healMod15 = (1.5/3.5) * (sgMod + Bonus);
62 | local healMod20 = (2.0/3.5) * (sgMod + Bonus);
63 | local healMod25 = (2.5/3.5) * (sgMod + Bonus);
64 | local healMod30 = (3.0/3.5) * (sgMod + Bonus);
65 | QuickHeal_debug("Final Healing Bonus (1.5,2.0,2.5,3.0)", healMod15,healMod20,healMod25,healMod30);
66 |
67 | local InCombat = UnitAffectingCombat('player') or UnitAffectingCombat(Target);
68 |
69 | -- Spiritual Healing - Increases healing by 2% per rank on all spells
70 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,15);
71 | local shMod = 2*talentRank/100 + 1;
72 | QuickHeal_debug(string.format("Spiritual Healing modifier: %f", shMod));
73 |
74 | -- Improved Healing - Decreases mana usage by 5% per rank on LH,H and GH
75 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,10);
76 | local ihMod = 1 - 5*talentRank/100;
77 | QuickHeal_debug(string.format("Improved Healing modifier: %f", ihMod));
78 |
79 | local TargetIsHealthy = Health >= QuickHealVariables.RatioHealthyPriest;
80 | local ManaLeft = UnitMana('player');
81 |
82 | if TargetIsHealthy then
83 | QuickHeal_debug("Target is healthy",Health);
84 | end
85 |
86 | -- Detect proc of 'Hand of Edward the Odd' mace (next spell is instant cast)
87 | if QuickHeal_DetectBuff('player',"Spell_Holy_SearingLight") then
88 | QuickHeal_debug("BUFF: Hand of Edward the Odd (out of combat healing forced)");
89 | InCombat = false;
90 | end
91 |
92 | -- Detect Inner Focus or Spirit of Redemption (hack ManaLeft and healneed)
93 | if QuickHeal_DetectBuff('player',"Spell_Frost_WindWalkOn",1) or QuickHeal_DetectBuff('player',"Spell_Holy_GreaterHeal") then
94 | QuickHeal_debug("Inner Focus or Spirit of Redemption active");
95 | ManaLeft = UnitManaMax('player'); -- Infinite mana
96 | healneed = 10^6; -- Deliberate overheal (mana is free)
97 | end
98 |
99 | -- Get total healing modifier (factor) caused by healing target debuffs
100 | local HDB = QuickHeal_GetHealModifier(Target);
101 | QuickHeal_debug("Target debuff healing modifier",HDB);
102 | healneed = healneed/HDB;
103 |
104 | -- Get a list of ranks available for all spells
105 | local SpellIDsLH = QuickHeal_GetSpellIDs(QUICKHEAL_SPELL_LESSER_HEAL);
106 | local SpellIDsH = QuickHeal_GetSpellIDs(QUICKHEAL_SPELL_HEAL);
107 | local SpellIDsGH = QuickHeal_GetSpellIDs(QUICKHEAL_SPELL_GREATER_HEAL);
108 | local SpellIDsFH = QuickHeal_GetSpellIDs(QUICKHEAL_SPELL_FLASH_HEAL);
109 |
110 | local maxRankLH = table.getn(SpellIDsLH);
111 | local maxRankH = table.getn(SpellIDsH);
112 | local maxRankGH = table.getn(SpellIDsGH);
113 | local maxRankFH = table.getn(SpellIDsFH);
114 |
115 | QuickHeal_debug(string.format("Found LH up to rank %d, H up top rank %d, GH up to rank %d, and FH up to rank %d", maxRankLH, maxRankH, maxRankGH, maxRankFH));
116 |
117 | --Get max HealRanks that are allowed to be used
118 | local downRankFH = QuickHealVariables.DownrankValueFH -- rank for 1.5 sec heals
119 | local downRankNH = QuickHealVariables.DownrankValueNH -- rank for < 1.5 sec heals
120 |
121 | -- Compensation for health lost during combat
122 | local k=1.0;
123 | local K=1.0;
124 | if InCombat then
125 | k=0.9;
126 | K=0.8;
127 | end
128 |
129 | -- Find suitable SpellID based on the defined criteria
130 | if not InCombat or TargetIsHealthy or maxRankFH<1 then
131 | -- Not in combat or target is healthy so use the closest available mana efficient healing
132 | QuickHeal_debug(string.format("Not in combat or target healthy or no flash heal available, will use closest available LH, H or GH (not FH)"))
133 | if Health < QuickHealVariables.RatioFull then
134 | SpellID = SpellIDsLH[1]; HealSize = 53*shMod+healMod15*PF1; -- Default to LH
135 | if healneed > ( 84*shMod+healMod20*PF4) *k and ManaLeft >= 45*ihMod and maxRankLH >=2 and downRankNH >= 2 then SpellID = SpellIDsLH[2]; HealSize = 84*shMod+healMod20*PF4 end
136 | if healneed > ( 154*shMod+healMod25*PF10)*K and ManaLeft >= 75*ihMod and maxRankLH >=3 and downRankNH >= 3 then SpellID = SpellIDsLH[3]; HealSize = 154*shMod+healMod25*PF10 end
137 | if healneed > ( 318*shMod+healMod30*PF18)*K and ManaLeft >= 155*ihMod and maxRankH >=1 and downRankNH >= 4 then SpellID = SpellIDsH[1] ; HealSize = 318*shMod+healMod30*PF18 end
138 | if healneed > ( 460*shMod+healMod30)*K and ManaLeft >= 205*ihMod and maxRankH >=2 and downRankNH >= 5 then SpellID = SpellIDsH[2] ; HealSize = 460*shMod+healMod30 end
139 | if healneed > ( 604*shMod+healMod30)*K and ManaLeft >= 255*ihMod and maxRankH >=3 and downRankNH >= 6 then SpellID = SpellIDsH[3] ; HealSize = 604*shMod+healMod30 end
140 | if healneed > ( 758*shMod+healMod30)*K and ManaLeft >= 305*ihMod and maxRankH >=4 and downRankNH >= 7 then SpellID = SpellIDsH[4] ; HealSize = 758*shMod+healMod30 end
141 | if healneed > ( 956*shMod+healMod30)*K and ManaLeft >= 370*ihMod and maxRankGH >=1 and downRankNH >= 8 then SpellID = SpellIDsGH[1]; HealSize = 956*shMod+healMod30 end
142 | if healneed > (1219*shMod+healMod30)*K and ManaLeft >= 455*ihMod and maxRankGH >=2 and downRankNH >= 9 then SpellID = SpellIDsGH[2]; HealSize = 1219*shMod+healMod30 end
143 | if healneed > (1523*shMod+healMod30)*K and ManaLeft >= 545*ihMod and maxRankGH >=3 and downRankNH >= 10 then SpellID = SpellIDsGH[3]; HealSize = 1523*shMod+healMod30 end
144 | if healneed > (1902*shMod+healMod30)*K and ManaLeft >= 655*ihMod and maxRankGH >=4 and downRankNH >= 11 then SpellID = SpellIDsGH[4]; HealSize = 1902*shMod+healMod30 end
145 | if healneed > (2080*shMod+healMod30)*K and ManaLeft >= 710*ihMod and maxRankGH >=5 and downRankNH >= 12 then SpellID = SpellIDsGH[5]; HealSize = 2080*shMod+healMod30 end
146 | end
147 | else
148 | -- In combat and target is unhealthy and player has flash heal
149 | QuickHeal_debug(string.format("In combat and target unhealthy and player has flash heal, will only use FH"));
150 | if Health < QuickHealVariables.RatioFull then
151 | SpellID = SpellIDsFH[1]; HealSize = 215*shMod+healMod15; -- Default to FH
152 | if healneed > (286*shMod+healMod15)*k and ManaLeft >= 155 and maxRankFH >=2 and downRankFH >= 2 then SpellID = SpellIDsFH[2]; HealSize = 286*shMod+healMod15 end
153 | if healneed > (360*shMod+healMod15)*k and ManaLeft >= 185 and maxRankFH >=3 and downRankFH >= 3 then SpellID = SpellIDsFH[3]; HealSize = 360*shMod+healMod15 end
154 | if healneed > (439*shMod+healMod15)*k and ManaLeft >= 215 and maxRankFH >=4 and downRankFH >= 4 then SpellID = SpellIDsFH[4]; HealSize = 439*shMod+healMod15 end
155 | if healneed > (567*shMod+healMod15)*k and ManaLeft >= 265 and maxRankFH >=5 and downRankFH >= 5 then SpellID = SpellIDsFH[5]; HealSize = 567*shMod+healMod15 end
156 | if healneed > (704*shMod+healMod15)*k and ManaLeft >= 315 and maxRankFH >=6 and downRankFH >= 6 then SpellID = SpellIDsFH[6]; HealSize = 704*shMod+healMod15 end
157 | if healneed > (885*shMod+healMod15)*k and ManaLeft >= 380 and maxRankFH >=7 and downRankFH >= 7 then SpellID = SpellIDsFH[7]; HealSize = 885*shMod+healMod15 end
158 | end
159 | end
160 |
161 | return SpellID,HealSize*HDB;
162 | end
163 |
--------------------------------------------------------------------------------
/QuickHealShaman.lua:
--------------------------------------------------------------------------------
1 |
2 | function QuickHeal_Shaman_GetRatioHealthyExplanation()
3 | local RatioHealthy = QuickHeal_GetRatioHealthy();
4 | local RatioFull = QuickHealVariables["RatioFull"];
5 |
6 | if RatioHealthy >= RatioFull then
7 | return QUICKHEAL_SPELL_HEALING_WAVE .. " will never be used in combat. ";
8 | else
9 | if RatioHealthy > 0 then
10 | return QUICKHEAL_SPELL_HEALING_WAVE .. " will only be used in combat if the target has more than " .. RatioHealthy*100 .. "% life, and only if the healing done is greater than the greatest " .. QUICKHEAL_SPELL_LESSER_HEALING_WAVE .. " available. ";
11 | else
12 | return QUICKHEAL_SPELL_HEALING_WAVE .. " will only be used in combat if the healing done is greater than the greatest " .. QUICKHEAL_SPELL_LESSER_HEALING_WAVE .. " available. ";
13 | end
14 | end
15 | end
16 |
17 | function QuickHeal_Shaman_FindSpellToUse(Target)
18 | local SpellID = nil;
19 | local HealSize = 0;
20 |
21 | -- +Healing-PenaltyFactor = (1-((20-LevelLearnt)*0.0375)) for all spells learnt before level 20
22 | local PF1 = 0.2875;
23 | local PF6 = 0.475;
24 | local PF12 = 0.7;
25 | local PF18 = 0.925;
26 |
27 | -- Local aliases to access main module functionality and settings
28 | local RatioFull = QuickHealVariables["RatioFull"];
29 | local RatioHealthy = QuickHeal_GetRatioHealthy();
30 | local UnitHasHealthInfo = QuickHeal_UnitHasHealthInfo;
31 | local EstimateUnitHealNeed = QuickHeal_EstimateUnitHealNeed;
32 | local GetSpellIDs = QuickHeal_GetSpellIDs;
33 | local debug = QuickHeal_debug;
34 |
35 | -- Return immediatly if no player needs healing
36 | if not Target then
37 | return SpellID,HealSize;
38 | end
39 |
40 | -- Determine health and healneed of target
41 | local healneed;
42 | local Health;
43 | if UnitHasHealthInfo(Target) then
44 | -- Full info available
45 | healneed = UnitHealthMax(Target) - UnitHealth(Target) - HealComm:getHeal(UnitName(Target)); -- Implementatio for HealComm
46 | Health = UnitHealth(Target) / UnitHealthMax(Target);
47 | else
48 | -- Estimate target health
49 | healneed = EstimateUnitHealNeed(Target,true);
50 | Health = UnitHealth(Target)/100;
51 | end
52 |
53 | -- if BonusScanner is running, get +Healing bonus
54 | local Bonus = 0;
55 | if (BonusScanner) then
56 | Bonus = tonumber(BonusScanner:GetBonus("HEAL"));
57 | debug(string.format("Equipment Healing Bonus: %d", Bonus));
58 | end
59 |
60 | -- Calculate healing bonus
61 | local healModLHW = (1.5/3.5) * Bonus;
62 | local healMod15 = (1.5/3.5) * Bonus;
63 | local healMod20 = (2.0/3.5) * Bonus;
64 | local healMod25 = (2.5/3.5) * Bonus;
65 | local healMod30 = (3.0/3.5) * Bonus;
66 | debug("Final Healing Bonus (1.5,2.0,2.5,3.0,LHW)", healMod15,healMod20,healMod25,healMod30,healModLHW);
67 |
68 | local InCombat = UnitAffectingCombat('player') or UnitAffectingCombat(Target);
69 |
70 | -- Purification Talent (increases healing by 2% per rank)
71 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14);
72 | local pMod = 2*talentRank/100 + 1;
73 | debug(string.format("Purification modifier: %f", pMod))
74 |
75 | -- Tidal Focus - Decreases mana usage by 1% per rank on healing
76 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,2);
77 | local tfMod = 1 - talentRank/100;
78 | debug(string.format("Improved Healing modifier: %f", tfMod));
79 |
80 | local TargetIsHealthy = Health >= RatioHealthy;
81 | local ManaLeft = UnitMana('player');
82 |
83 | if TargetIsHealthy then
84 | debug("Target is healthy",Health)
85 | end
86 |
87 | -- Detect Nature's Swiftness (next nature spell is instant cast)
88 | if QuickHeal_DetectBuff('player',"Spell_Nature_RavenForm") then
89 | debug("BUFF: Nature's Swiftness (out of combat healing forced)");
90 | InCombat = false;
91 | end
92 |
93 | -- Detect proc of 'Hand of Edward the Odd' mace (next spell is instant cast)
94 | if QuickHeal_DetectBuff('player',"Spell_Holy_SearingLight") then
95 | debug("BUFF: Hand of Edward the Odd (out of combat healing forced)");
96 | InCombat = false;
97 | end
98 |
99 | -- Get total healing modifier (factor) caused by healing target debuffs
100 | local HDB = QuickHeal_GetHealModifier(Target);
101 | debug("Target debuff healing modifier",HDB);
102 | healneed = healneed/HDB;
103 |
104 | -- Detect healing way on target
105 | local hwMod = QuickHeal_DetectBuff(Target,"Spell_Nature_HealingWay");
106 | if hwMod then hwMod = 1+0.06*hwMod else hwMod = 1 end;
107 | debug("Healing Way healing modifier",hwMod);
108 |
109 | -- Get a list of ranks available of 'Lesser Healing Wave' and 'Healing Wave'
110 | local SpellIDsHW = GetSpellIDs(QUICKHEAL_SPELL_HEALING_WAVE);
111 | local SpellIDsLHW = GetSpellIDs(QUICKHEAL_SPELL_LESSER_HEALING_WAVE);
112 | local maxRankHW = table.getn(SpellIDsHW);
113 | local maxRankLHW = table.getn(SpellIDsLHW);
114 | local NoLHW = maxRankLHW < 1;
115 | debug(string.format("Found HW up to rank %d, and found LHW up to rank %d", maxRankHW, maxRankLHW))
116 |
117 | -- Find suitable SpellID based on the defined criteria
118 | if InCombat then
119 | -- In combat so use LHW unless:
120 | -- Target is healthy (health > RatioHealthy)
121 | -- AND The HW in question is larger than any available LHW
122 | -- OR LHW is unavailable (sub level 20 characters)
123 | debug(string.format("In combat, will prefer LHW"))
124 | if Health < RatioFull then
125 | local k = 0.9; -- In combat means that target is losing life while casting, so compensate
126 | local K = 0.8; -- k for fast spells (LHW and HW Rank 1 and 2) and K for slow spells (HW)
127 | if maxRankLHW >=1 then SpellID = SpellIDsLHW[1]; HealSize = 174*pMod+healModLHW else SpellID = SpellIDsHW[1]; HealSize = 39*pMod*hwMod+healMod15*PF1 end -- Default to HW or LHW
128 | if healneed > ( 71*pMod*hwMod+healMod20*PF6 )*k and ManaLeft >= 45*tfMod and maxRankHW >=2 and NoLHW then SpellID = SpellIDsHW[2]; HealSize = 71*pMod*hwMod+healMod20*PF6 end
129 | if healneed > ( 142*pMod*hwMod+healMod25*PF12)*K and ManaLeft >= 80*tfMod and maxRankHW >=3 and NoLHW then SpellID = SpellIDsHW[3]; HealSize = 142*pMod*hwMod+healMod25*PF12 end
130 | if healneed > (174*pMod+healModLHW)*k and ManaLeft >= 105*tfMod and maxRankLHW >=1 then SpellID = SpellIDsLHW[1]; HealSize = 174*pMod+healModLHW end
131 | if healneed > (264*pMod+healModLHW)*k and ManaLeft >= 145*tfMod and maxRankLHW >=2 then SpellID = SpellIDsLHW[2]; HealSize = 264*pMod+healModLHW end
132 | if healneed > ( 292*pMod*hwMod+healMod30*PF18)*K and ManaLeft >= 155*tfMod and maxRankHW >=4 and (TargetIsHealthy and maxRankLHW <= 2 or NoLHW) then SpellID = SpellIDsHW[4]; HealSize = 292*pMod*hwMod+healMod30*PF18 end
133 | if healneed > (359*pMod+healModLHW)*k and ManaLeft >= 185*tfMod and maxRankLHW >=3 then SpellID = SpellIDsLHW[3]; HealSize = 359*pMod+healModLHW end
134 | if healneed > ( 408*pMod*hwMod+healMod30)*K and ManaLeft >= 200*tfMod and maxRankHW >=5 and (TargetIsHealthy and maxRankLHW <= 3 or NoLHW) then SpellID = SpellIDsHW[5]; HealSize = 408*pMod*hwMod+healMod30 end
135 | if healneed > (486*pMod+healModLHW)*k and ManaLeft >= 235*tfMod and maxRankLHW >=4 then SpellID = SpellIDsLHW[4]; HealSize = 486*pMod+healModLHW end
136 | if healneed > ( 579*pMod*hwMod+healMod30)*K and ManaLeft >= 265*tfMod and maxRankHW >=6 and (TargetIsHealthy and maxRankLHW <= 4 or NoLHW) then SpellID = SpellIDsHW[6]; HealSize = 579*pMod*hwMod+healMod30 end
137 | if healneed > (668*pMod+healModLHW)*k and ManaLeft >= 305*tfMod and maxRankLHW >=5 then SpellID = SpellIDsLHW[5]; HealSize = 668*pMod+healModLHW end
138 | if healneed > ( 797*pMod*hwMod+healMod30)*K and ManaLeft >= 340*tfMod and maxRankHW >=7 and (TargetIsHealthy and maxRankLHW <= 5 or NoLHW) then SpellID = SpellIDsHW[7]; HealSize = 797*pMod*hwMod+healMod30 end
139 | if healneed > (880*pMod+healModLHW)*k and ManaLeft >= 380*tfMod and maxRankLHW >=6 then SpellID = SpellIDsLHW[6]; HealSize = 880*pMod+healModLHW end
140 | if healneed > (1092*pMod*hwMod+healMod30)*K and ManaLeft >= 440*tfMod and maxRankHW >=8 and (TargetIsHealthy and maxRankLHW <= 6 or NoLHW) then SpellID = SpellIDsHW[8]; HealSize = 1092*pMod*hwMod+healMod30 end
141 | if healneed > (1464*pMod*hwMod+healMod30)*K and ManaLeft >= 560*tfMod and maxRankHW >=9 and (TargetIsHealthy and maxRankLHW <= 6 or NoLHW) then SpellID = SpellIDsHW[9]; HealSize = 1464*pMod*hwMod+healMod30 end
142 | if healneed > (1735*pMod*hwMod+healMod30)*K and ManaLeft >= 620*tfMod and maxRankHW >=10 and (TargetIsHealthy and maxRankLHW <= 6 or NoLHW) then SpellID = SpellIDsHW[10]; HealSize = 1735*pMod*hwMod+healMod30 end
143 | end
144 | else
145 | -- Not in combat so use the closest available healing
146 | debug(string.format("Not in combat, will use closest available HW or LHW"))
147 | if Health < RatioFull then
148 | SpellID = SpellIDsHW[1]; HealSize = 39*pMod*hwMod+healMod15*PF1;
149 | if healneed > ( 71*pMod*hwMod+healMod20*PF6 ) and ManaLeft >= 45*tfMod and maxRankHW >=2 then SpellID = SpellIDsHW[2]; HealSize = 71*pMod*hwMod+healMod20*PF6 end
150 | if healneed > (142*pMod*hwMod+healMod25*PF12) and ManaLeft >= 80*tfMod and maxRankHW >=3 then SpellID = SpellIDsHW[3]; HealSize = 142*pMod*hwMod+healMod25*PF12 end
151 | if healneed > (174*pMod+healModLHW) and ManaLeft >= 105*tfMod and maxRankLHW >=1 then SpellID = SpellIDsLHW[1]; HealSize = 174*pMod+healModLHW end
152 | if healneed > (264*pMod+healModLHW) and ManaLeft >= 145*tfMod and maxRankLHW >=2 then SpellID = SpellIDsLHW[2]; HealSize = 264*pMod+healModLHW end
153 | if healneed > (292*pMod*hwMod+healMod30*PF18) and ManaLeft >= 155*tfMod and maxRankHW >=4 then SpellID = SpellIDsHW[4]; HealSize = 292*pMod*hwMod+healMod30*PF18 end
154 | if healneed > (359*pMod+healModLHW) and ManaLeft >= 185*tfMod and maxRankLHW >=3 then SpellID = SpellIDsLHW[3]; HealSize = 359*pMod+healModLHW end
155 | if healneed > (408*pMod*hwMod+healMod30) and ManaLeft >= 200*tfMod and maxRankHW >=5 then SpellID = SpellIDsHW[5]; HealSize = 408*pMod*hwMod+healMod30 end
156 | if healneed > (486*pMod+healModLHW) and ManaLeft >= 235*tfMod and maxRankLHW >=4 then SpellID = SpellIDsLHW[4]; HealSize = 486*pMod+healModLHW end
157 | if healneed > (579*pMod*hwMod+healMod30) and ManaLeft >= 265*tfMod and maxRankHW >=6 then SpellID = SpellIDsHW[6]; HealSize = 579*pMod*hwMod+healMod30 end
158 | if healneed > (668*pMod+healModLHW) and ManaLeft >= 305*tfMod and maxRankLHW >=5 then SpellID = SpellIDsLHW[5]; HealSize = 668*pMod+healModLHW end
159 | if healneed > (797*pMod*hwMod+healMod30) and ManaLeft >= 340*tfMod and maxRankHW >=7 then SpellID = SpellIDsHW[7]; HealSize = 797*pMod*hwMod+healMod30 end
160 | if healneed > (880*pMod+healModLHW) and ManaLeft >= 380*tfMod and maxRankLHW >=6 then SpellID = SpellIDsLHW[6]; HealSize = 880*pMod+healModLHW end
161 | if healneed > (1092*pMod*hwMod+healMod30) and ManaLeft >= 440*tfMod and maxRankHW >=8 then SpellID = SpellIDsHW[8]; HealSize = 1092*pMod*hwMod+healMod30 end
162 | if healneed > (1464*pMod*hwMod+healMod30) and ManaLeft >= 560*tfMod and maxRankHW >=9 then SpellID = SpellIDsHW[9]; HealSize = 1464*pMod*hwMod+healMod30 end
163 | if healneed > (1735*pMod*hwMod+healMod30) and ManaLeft >= 620*tfMod and maxRankHW >=10 then SpellID = SpellIDsHW[10]; HealSize = 1735*pMod*hwMod+healMod30 end
164 | end
165 | end
166 |
167 | return SpellID,HealSize*HDB;
168 | end
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # QuickHeal
2 | QuickHeal for Vanilla WoW 1.12. with integration for HealComm (Luna unit Frames).
3 |
4 | I'm not the author of QuickHeal.
5 |
6 | I just did the implementation for QuckHeal to use Healcom to heal smarter.
7 | I also did some other additions and improvements.
8 |
9 | I got the original version of QuickHeal from https://wow.curseforge.com/projects/project-2800.
10 |
11 | # Installation
12 | - Download QuickHeal from this repository into your Interface folder and remove the "-master" in the folder name
13 | - Download HealComm or Luna unit Frames: https://github.com/Aviana/LunaUnitFrames
14 | - Download Bonusscanner (Makes QhickHeal and HealComm (Luna unit Frames) more accurate by taking gear and +Heal into account: http://www.vanilla-addons.com/dls/bonusscanner/
15 |
16 | # What this version of QuickHeal does:
17 |
18 | **Integration of HealComm**
19 |
20 | - QuickHeal is now using the incomming heal information, broadcasted by HealComm (Luna unit Frames), through the addonchannel to reduce overhealing and making this addon used by multible raidmembers more effective.
21 | - Also there is the option to downrank the spells being used, so healing can be more effitient.
22 |
23 | **How to use**
24 | - Find the original description here: https://wow.curseforge.com/projects/project-2800
25 |
26 | - Help
27 | "/qh help" displays all a
28 |
29 | - Heal:
30 | To do a heal make a macro with "/qh" or set Keybind:
31 |
32 | 
33 |
34 | - Downrank
35 | To conserve mana and heal more effitiently you can limit the max rank that Quick Heal will use. It is done by moving the slider. on the Downrank Window. "/qh dr" to open the Downrank Window.
36 | 
37 | 
38 |
39 | - Change Heal mode
40 | There are 3 modes for healing.
41 |
42 | "/qh hm 1" - Default
43 | Priest: Will only cast Greater Heal, Heal and Lesser Heal.
44 | Paladin: Will only use Flash of Light
45 |
46 | "/qh hm 2"
47 | Priest: Will only cast Flash Heal
48 | Paladin: Will only cast Holy Light
49 |
50 | "/qh hm 3" - Most HPS
51 | Will cast the heal with the most HPS.
52 | Priest: Will cast Prayer of Healing if possible
53 |
54 | The Heal mode can tbe set with macro or Key bind. The ">" indicate the selected mode.
55 | 
56 |
57 | # Changes:
58 |
59 | hc05: (get from Branch)
60 | - Healmodes for Paladins and Priests now controll the spells used. See How to Use
61 | - Priests: in healmode 3 Prayer of Heal is cast if possible
62 | - Finalization of the addon, for the possibility of localization [@shikulja](https://github.com/shikulja). Special thanks, for the help and instructions Lichery.
63 | - Fixed overhealing sound playing
64 | - Added colored target names (enabled by default)
65 |
66 | hc04:
67 | - new command: /qh healpct - Will prioritise the player with the lowest percentage of health. (override changes of hc03, where priests heal the target with the most healing needed and paladins the lowest target)
68 |
69 |
70 | hc03:
71 | - /qh downrank or /qh dr toggles a window where the maximum spell rank to be used for healspells can be set. (hold rightclick on frame to drag the window)
72 | - Keybind for toggeling downrank window
73 | - /qh toggle will change between Flash heals and Normal heals on Priest
74 | - Keybind to toggle between Flash heals and Normal heals on Priest
75 | - Heal sent from other players via HealComm will now be considered in selv preservation
76 | - Heal sent from other players via HealComm will now be considered for player that is target of target prioity healing
77 | - Priests will now heal the player with the most health missing
78 | - Paladin will now heal the player with the lowest amount of health
79 | - For Paladins healing out of fight will now use the same spells as infight
80 |
--------------------------------------------------------------------------------
/libs/AceAddon-2.0/AceAddon-2.0.lua:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sulpitz/QuickHeal/33a3172bbcfa930b57bb3f0b9002eb09f99d4760/libs/AceAddon-2.0/AceAddon-2.0.lua
--------------------------------------------------------------------------------
/libs/AceEvent-2.0/AceEvent-2.0.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | Name: AceEvent-2.0
3 | Revision: $Rev: 17638 $
4 | Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
5 | Inspired By: Ace 1.x by Turan (turan@gryphon.com)
6 | Website: http://www.wowace.com/
7 | Documentation: http://www.wowace.com/index.php/AceEvent-2.0
8 | SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
9 | Description: Mixin to allow for event handling, scheduling, and inter-addon
10 | communication.
11 | Dependencies: AceLibrary, AceOO-2.0
12 | ]]
13 |
14 | local MAJOR_VERSION = "AceEvent-2.0"
15 | local MINOR_VERSION = "$Revision: 17638 $"
16 |
17 | if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
18 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
19 |
20 | if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
21 | if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
22 |
23 | local AceOO = AceLibrary:GetInstance("AceOO-2.0")
24 | local Mixin = AceOO.Mixin
25 | local AceEvent = Mixin {
26 | "RegisterEvent",
27 | "RegisterAllEvents",
28 | "UnregisterEvent",
29 | "UnregisterAllEvents",
30 | "TriggerEvent",
31 | "ScheduleEvent",
32 | "ScheduleRepeatingEvent",
33 | "CancelScheduledEvent",
34 | "CancelAllScheduledEvents",
35 | "IsEventRegistered",
36 | "IsEventScheduled",
37 | "RegisterBucketEvent",
38 | "UnregisterBucketEvent",
39 | "UnregisterAllBucketEvents",
40 | "IsBucketEventRegistered",
41 | }
42 |
43 | local table_setn
44 | do
45 | local version = GetBuildInfo()
46 | if string.find(version, "^2%.") then
47 | -- 2.0.0
48 | table_setn = function() end
49 | else
50 | table_setn = table.setn
51 | end
52 | end
53 |
54 | local weakKey = {__mode="k"}
55 | local new, del
56 | do
57 | local list = setmetatable({}, weakKey)
58 | function new()
59 | local t = next(list)
60 | if t then
61 | list[t] = nil
62 | return t
63 | else
64 | return {}
65 | end
66 | end
67 |
68 | function del(t)
69 | setmetatable(t, nil)
70 | for k in pairs(t) do
71 | t[k] = nil
72 | end
73 | list[t] = true
74 | end
75 | end
76 |
77 | local FAKE_NIL
78 | local RATE
79 |
80 | local eventsWhichHappenOnce = {
81 | PLAYER_LOGIN = true,
82 | AceEvent_FullyInitialized = true,
83 | VARIABLES_LOADED = true,
84 | PLAYER_LOGOUT = true,
85 | }
86 |
87 | local registeringFromAceEvent
88 | function AceEvent:RegisterEvent(event, method, once)
89 | AceEvent:argCheck(event, 2, "string")
90 | if self == AceEvent and not registeringFromAceEvent then
91 | AceEvent:argCheck(method, 3, "function")
92 | self = method
93 | else
94 | AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
95 | if type(method) == "boolean" or type(method) == "number" then
96 | AceEvent:argCheck(once, 4, "nil")
97 | once, method = method, event
98 | end
99 | end
100 | AceEvent:argCheck(once, 4, "number", "boolean", "nil")
101 | if eventsWhichHappenOnce[event] then
102 | once = true
103 | end
104 | local throttleRate
105 | if type(once) == "number" then
106 | throttleRate, once = once
107 | end
108 | if not method then
109 | method = event
110 | end
111 | if type(method) == "string" and type(self[method]) ~= "function" then
112 | AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
113 | else
114 | assert(type(method) == "function" or type(method) == "string")
115 | end
116 |
117 | local AceEvent_registry = AceEvent.registry
118 | if not AceEvent_registry[event] then
119 | AceEvent_registry[event] = new()
120 | AceEvent.frame:RegisterEvent(event)
121 | end
122 |
123 | local remember = true
124 | if AceEvent_registry[event][self] then
125 | remember = false
126 | end
127 | AceEvent_registry[event][self] = method
128 |
129 | local AceEvent_onceRegistry = AceEvent.onceRegistry
130 | if once then
131 | if not AceEvent_onceRegistry then
132 | AceEvent.onceRegistry = new()
133 | AceEvent_onceRegistry = AceEvent.onceRegistry
134 | end
135 | if not AceEvent_onceRegistry[event] then
136 | AceEvent_onceRegistry[event] = new()
137 | end
138 | AceEvent_onceRegistry[event][self] = true
139 | else
140 | if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
141 | AceEvent_onceRegistry[event][self] = nil
142 | if not next(AceEvent_onceRegistry[event]) then
143 | AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
144 | end
145 | end
146 | end
147 |
148 | local AceEvent_throttleRegistry = AceEvent.throttleRegistry
149 | if throttleRate then
150 | if not AceEvent_throttleRegistry then
151 | AceEvent.throttleRegistry = new()
152 | AceEvent_throttleRegistry = AceEvent.throttleRegistry
153 | end
154 | if not AceEvent_throttleRegistry[event] then
155 | AceEvent_throttleRegistry[event] = new()
156 | end
157 | if AceEvent_throttleRegistry[event][self] then
158 | AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
159 | end
160 | AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
161 | local t = AceEvent_throttleRegistry[event][self]
162 | t[RATE] = throttleRate
163 | else
164 | if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
165 | if AceEvent_throttleRegistry[event][self] then
166 | AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
167 | end
168 | if not next(AceEvent_throttleRegistry[event]) then
169 | AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
170 | end
171 | end
172 | end
173 |
174 | if remember then
175 | AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
176 | end
177 | end
178 |
179 | local ALL_EVENTS
180 |
181 | function AceEvent:RegisterAllEvents(method)
182 | if self == AceEvent then
183 | AceEvent:argCheck(method, 1, "function")
184 | self = method
185 | else
186 | AceEvent:argCheck(method, 1, "string", "function")
187 | if type(method) == "string" and type(self[method]) ~= "function" then
188 | AceEvent:error("Cannot register all events to method %q, it does not exist", method)
189 | end
190 | end
191 |
192 | local AceEvent_registry = AceEvent.registry
193 | if not AceEvent_registry[ALL_EVENTS] then
194 | AceEvent_registry[ALL_EVENTS] = new()
195 | AceEvent.frame:RegisterAllEvents()
196 | end
197 |
198 | AceEvent_registry[ALL_EVENTS][self] = method
199 | end
200 |
201 | local _G = getfenv(0)
202 | local memstack, timestack = {}, {}
203 | local memdiff, timediff
204 | function AceEvent:TriggerEvent(event, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
205 | AceEvent:argCheck(event, 2, "string")
206 | local AceEvent_registry = AceEvent.registry
207 | if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then
208 | return
209 | end
210 | local _G_event = _G.event
211 | _G.event = event
212 | local lastEvent = AceEvent.currentEvent
213 | AceEvent.currentEvent = event
214 |
215 | local AceEvent_onceRegistry = AceEvent.onceRegistry
216 | local AceEvent_debugTable = AceEvent.debugTable
217 | if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
218 | local tmp = new()
219 | for obj, method in pairs(AceEvent_onceRegistry[event]) do
220 | tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
221 | end
222 | local obj = next(tmp)
223 | while obj do
224 | local mem, time
225 | if AceEvent_debugTable then
226 | if not AceEvent_debugTable[event] then
227 | AceEvent_debugTable[event] = new()
228 | end
229 | if not AceEvent_debugTable[event][obj] then
230 | AceEvent_debugTable[event][obj] = new()
231 | AceEvent_debugTable[event][obj].mem = 0
232 | AceEvent_debugTable[event][obj].time = 0
233 | AceEvent_debugTable[event][obj].count = 0
234 | end
235 | if memdiff then
236 | table.insert(memstack, memdiff)
237 | table.insert(timestack, timediff)
238 | end
239 | memdiff, timediff = 0, 0
240 | mem, time = gcinfo(), GetTime()
241 | end
242 | local method = tmp[obj]
243 | AceEvent.UnregisterEvent(obj, event)
244 | if type(method) == "string" then
245 | local obj_method = obj[method]
246 | if obj_method then
247 | obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
248 | end
249 | elseif method then -- function
250 | method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
251 | end
252 | if AceEvent_debugTable then
253 | local dmem, dtime = memdiff, timediff
254 | mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
255 | AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
256 | AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
257 | AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
258 |
259 | memdiff, timediff = table.remove(memstack), table.remove(timestack)
260 | if memdiff then
261 | memdiff = memdiff + mem + dmem
262 | timediff = timediff + time + dtime
263 | end
264 | end
265 | tmp[obj] = nil
266 | obj = next(tmp)
267 | end
268 | del(tmp)
269 | end
270 |
271 | local AceEvent_throttleRegistry = AceEvent.throttleRegistry
272 | local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
273 | if AceEvent_registry[event] then
274 | local tmp = new()
275 | for obj, method in pairs(AceEvent_registry[event]) do
276 | tmp[obj] = method
277 | end
278 | local obj = next(tmp)
279 | while obj do
280 | local method = tmp[obj]
281 | local continue = false
282 | if throttleTable and throttleTable[obj] then
283 | local a1 = a1
284 | if a1 == nil then
285 | a1 = FAKE_NIL
286 | end
287 | if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
288 | throttleTable[obj][a1] = GetTime()
289 | else
290 | continue = true
291 | end
292 | end
293 | if not continue then
294 | local mem, time
295 | if AceEvent_debugTable then
296 | if not AceEvent_debugTable[event] then
297 | AceEvent_debugTable[event] = new()
298 | end
299 | if not AceEvent_debugTable[event][obj] then
300 | AceEvent_debugTable[event][obj] = new()
301 | AceEvent_debugTable[event][obj].mem = 0
302 | AceEvent_debugTable[event][obj].time = 0
303 | AceEvent_debugTable[event][obj].count = 0
304 | end
305 | if memdiff then
306 | table.insert(memstack, memdiff)
307 | table.insert(timestack, timediff)
308 | end
309 | memdiff, timediff = 0, 0
310 | mem, time = gcinfo(), GetTime()
311 | end
312 | if type(method) == "string" then
313 | local obj_method = obj[method]
314 | if obj_method then
315 | obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
316 | end
317 | elseif method then -- function
318 | method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
319 | end
320 | if AceEvent_debugTable then
321 | local dmem, dtime = memdiff, timediff
322 | mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
323 | AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
324 | AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
325 | AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
326 |
327 | memdiff, timediff = table.remove(memstack), table.remove(timestack)
328 | if memdiff then
329 | memdiff = memdiff + mem + dmem
330 | timediff = timediff + time + dtime
331 | end
332 | end
333 | end
334 | tmp[obj] = nil
335 | obj = next(tmp)
336 | end
337 | del(tmp)
338 | end
339 | if AceEvent_registry[ALL_EVENTS] then
340 | local tmp = new()
341 | for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
342 | tmp[obj] = method
343 | end
344 | local obj = next(tmp)
345 | while obj do
346 | local method = tmp[obj]
347 | local mem, time
348 | if AceEvent_debugTable then
349 | if not AceEvent_debugTable[event] then
350 | AceEvent_debugTable[event] = new()
351 | end
352 | if not AceEvent_debugTable[event][obj] then
353 | AceEvent_debugTable[event][obj] = new()
354 | AceEvent_debugTable[event][obj].mem = 0
355 | AceEvent_debugTable[event][obj].time = 0
356 | AceEvent_debugTable[event][obj].count = 0
357 | end
358 | if memdiff then
359 | table.insert(memstack, memdiff)
360 | table.insert(timestack, timediff)
361 | end
362 | memdiff, timediff = 0, 0
363 | mem, time = gcinfo(), GetTime()
364 | end
365 | if type(method) == "string" then
366 | local obj_method = obj[method]
367 | if obj_method then
368 | obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
369 | end
370 | elseif method then -- function
371 | method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
372 | end
373 | if AceEvent_debugTable then
374 | local dmem, dtime = memdiff, timediff
375 | mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
376 | AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
377 | AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
378 | AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
379 |
380 | memdiff, timediff = table.remove(memstack), table.remove(timestack)
381 | if memdiff then
382 | memdiff = memdiff + mem + dmem
383 | timediff = timediff + time + dtime
384 | end
385 | end
386 | tmp[obj] = nil
387 | obj = next(tmp)
388 | end
389 | del(tmp)
390 | end
391 | _G.event = _G_event
392 | AceEvent.currentEvent = lastEvent
393 | end
394 |
395 | -- local accessors
396 | local getn = table.getn
397 | local tinsert = table.insert
398 | local tremove = table.remove
399 | local floor = math.floor
400 | local GetTime = GetTime
401 | local next = next
402 | local pairs = pairs
403 | local unpack = unpack
404 |
405 | local delayRegistry
406 | local tmp = {}
407 | local function OnUpdate()
408 | local t = GetTime()
409 | for k,v in pairs(delayRegistry) do
410 | tmp[k] = true
411 | end
412 | for k in pairs(tmp) do
413 | local v = delayRegistry[k]
414 | if v then
415 | local v_time = v.time
416 | if not v_time then
417 | delayRegistry[k] = del(v)
418 | elseif v_time <= t then
419 | local v_repeatDelay = v.repeatDelay
420 | if v_repeatDelay then
421 | -- use the event time, not the current time, else timing inaccuracies add up over time
422 | v.time = v_time + v_repeatDelay
423 | end
424 | local event = v.event
425 | local mem, time
426 | if AceEvent_debugTable then
427 | mem, time = gcinfo(), GetTime()
428 | end
429 | if type(event) == "function" then
430 | event(unpack(v))
431 | else
432 | AceEvent:TriggerEvent(event, unpack(v))
433 | end
434 | if AceEvent_debugTable then
435 | mem, time = gcinfo() - mem, GetTime() - time
436 | v.mem = v.mem + mem
437 | v.timeSpent = v.timeSpent + time
438 | v.count = v.count + 1
439 | end
440 | if not v_repeatDelay then
441 | local x = delayRegistry[k]
442 | if x and x.time == v_time then -- check if it was manually reset
443 | delayRegistry[k] = del(v)
444 | end
445 | end
446 | end
447 | end
448 | end
449 | for k in pairs(tmp) do
450 | tmp[k] = nil
451 | end
452 | if not next(delayRegistry) then
453 | AceEvent.frame:Hide()
454 | end
455 | end
456 |
457 | local function ScheduleEvent(self, repeating, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
458 | local id
459 | if type(event) == "string" or type(event) == "table" then
460 | if type(event) == "table" then
461 | if not delayRegistry or not delayRegistry[event] then
462 | AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
463 | end
464 | end
465 | if type(delay) ~= "number" then
466 | id, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
467 | AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
468 | AceEvent:argCheck(delay, 4, "number")
469 | self:CancelScheduledEvent(id)
470 | end
471 | else
472 | AceEvent:argCheck(event, 2, "string", "function")
473 | AceEvent:argCheck(delay, 3, "number")
474 | end
475 |
476 | if not delayRegistry then
477 | AceEvent.delayRegistry = new()
478 | delayRegistry = AceEvent.delayRegistry
479 | AceEvent.frame:SetScript("OnUpdate", OnUpdate)
480 | end
481 | local t
482 | if type(id) == "table" then
483 | for k in pairs(id) do
484 | id[k] = nil
485 | end
486 | t = id
487 | else
488 | t = new()
489 | end
490 | t[1] = a1
491 | t[2] = a2
492 | t[3] = a3
493 | t[4] = a4
494 | t[5] = a5
495 | t[6] = a6
496 | t[7] = a7
497 | t[8] = a8
498 | t[9] = a9
499 | t[10] = a10
500 | t[11] = a11
501 | t[12] = a12
502 | t[13] = a13
503 | t[14] = a14
504 | t[15] = a15
505 | t[16] = a16
506 | t[17] = a17
507 | t[18] = a18
508 | t[19] = a19
509 | t[20] = a20
510 | table_setn(t, 20)
511 | t.event = event
512 | t.time = GetTime() + delay
513 | t.self = self
514 | t.id = id or t
515 | t.repeatDelay = repeating and delay
516 | if AceEvent_debugTable then
517 | t.mem = 0
518 | t.count = 0
519 | t.timeSpent = 0
520 | end
521 | delayRegistry[t.id] = t
522 | AceEvent.frame:Show()
523 | return t.id
524 | end
525 |
526 | function AceEvent:ScheduleEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
527 | if type(event) == "string" or type(event) == "table" then
528 | if type(event) == "table" then
529 | if not delayRegistry or not delayRegistry[event] then
530 | AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
531 | end
532 | end
533 | if type(delay) ~= "number" then
534 | AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
535 | AceEvent:argCheck(a1, 4, "number")
536 | end
537 | else
538 | AceEvent:argCheck(event, 2, "string", "function")
539 | AceEvent:argCheck(delay, 3, "number")
540 | end
541 |
542 | return ScheduleEvent(self, false, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
543 | end
544 |
545 | function AceEvent:ScheduleRepeatingEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
546 | if type(event) == "string" or type(event) == "table" then
547 | if type(event) == "table" then
548 | if not delayRegistry or not delayRegistry[event] then
549 | AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
550 | end
551 | end
552 | if type(delay) ~= "number" then
553 | AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
554 | AceEvent:argCheck(a1, 4, "number")
555 | end
556 | else
557 | AceEvent:argCheck(event, 2, "string", "function")
558 | AceEvent:argCheck(delay, 3, "number")
559 | end
560 |
561 | return ScheduleEvent(self, true, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
562 | end
563 |
564 | function AceEvent:CancelScheduledEvent(t)
565 | AceEvent:argCheck(t, 2, "string", "table")
566 | if delayRegistry then
567 | local v = delayRegistry[t]
568 | if v then
569 | delayRegistry[t] = del(v)
570 | if not next(delayRegistry) then
571 | AceEvent.frame:Hide()
572 | end
573 | return true
574 | end
575 | end
576 | return false
577 | end
578 |
579 | function AceEvent:IsEventScheduled(t)
580 | AceEvent:argCheck(t, 2, "string", "table")
581 | if delayRegistry then
582 | local v = delayRegistry[t]
583 | if v then
584 | return true, v.time - GetTime()
585 | end
586 | end
587 | return false, nil
588 | end
589 |
590 | function AceEvent:UnregisterEvent(event)
591 | AceEvent:argCheck(event, 2, "string")
592 | local AceEvent_registry = AceEvent.registry
593 | if AceEvent_registry[event] and AceEvent_registry[event][self] then
594 | AceEvent_registry[event][self] = nil
595 | local AceEvent_onceRegistry = AceEvent.onceRegistry
596 | if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
597 | AceEvent_onceRegistry[event][self] = nil
598 | if not next(AceEvent_onceRegistry[event]) then
599 | AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
600 | end
601 | end
602 | local AceEvent_throttleRegistry = AceEvent.throttleRegistry
603 | if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
604 | AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
605 | if not next(AceEvent_throttleRegistry[event]) then
606 | AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
607 | end
608 | end
609 | if not next(AceEvent_registry[event]) then
610 | AceEvent_registry[event] = del(AceEvent_registry[event])
611 | if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
612 | AceEvent.frame:UnregisterEvent(event)
613 | end
614 | end
615 | else
616 | if self == AceEvent then
617 | error(string.format("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0.", event), 2)
618 | else
619 | AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
620 | end
621 | end
622 | AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
623 | end
624 |
625 | function AceEvent:UnregisterAllEvents()
626 | local AceEvent_registry = AceEvent.registry
627 | if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
628 | AceEvent_registry[ALL_EVENTS][self] = nil
629 | if not next(AceEvent_registry[ALL_EVENTS]) then
630 | del(AceEvent_registry[ALL_EVENTS])
631 | AceEvent.frame:UnregisterAllEvents()
632 | for k,v in pairs(AceEvent_registry) do
633 | if k ~= ALL_EVENTS then
634 | AceEvent.frame:RegisterEvent(k)
635 | end
636 | end
637 | AceEvent_registry[event] = nil
638 | end
639 | end
640 | local first = true
641 | for event, data in pairs(AceEvent_registry) do
642 | if first then
643 | if AceEvent_registry.AceEvent_EventUnregistered then
644 | event = "AceEvent_EventUnregistered"
645 | else
646 | first = false
647 | end
648 | end
649 | local x = data[self]
650 | data[self] = nil
651 | if x and event ~= ALL_EVENTS then
652 | if not next(data) then
653 | del(data)
654 | if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
655 | AceEvent.frame:UnregisterEvent(event)
656 | end
657 | AceEvent_registry[event] = nil
658 | end
659 | AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
660 | end
661 | if first then
662 | event = nil
663 | end
664 | end
665 | if AceEvent.onceRegistry then
666 | for event, data in pairs(AceEvent.onceRegistry) do
667 | data[self] = nil
668 | end
669 | end
670 | end
671 |
672 | function AceEvent:CancelAllScheduledEvents()
673 | if delayRegistry then
674 | for k,v in pairs(delayRegistry) do
675 | if v.self == self then
676 | delayRegistry[k] = del(v)
677 | end
678 | end
679 | if not next(delayRegistry) then
680 | AceEvent.frame:Hide()
681 | end
682 | end
683 | end
684 |
685 | function AceEvent:IsEventRegistered(event)
686 | AceEvent:argCheck(event, 2, "string")
687 | local AceEvent_registry = AceEvent.registry
688 | if self == AceEvent then
689 | return AceEvent_registry[event] and next(AceEvent_registry[event]) and true or false
690 | end
691 | if AceEvent_registry[event] and AceEvent_registry[event][self] then
692 | return true, AceEvent_registry[event][self]
693 | end
694 | return false, nil
695 | end
696 |
697 | local bucketfunc
698 | function AceEvent:RegisterBucketEvent(event, delay, method)
699 | AceEvent:argCheck(event, 2, "string", "table")
700 | if type(event) == "table" then
701 | for k,v in pairs(event) do
702 | if type(k) ~= "number" then
703 | AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
704 | elseif type(v) ~= "string" then
705 | AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
706 | end
707 | end
708 | end
709 | AceEvent:argCheck(delay, 3, "number")
710 | if AceEvent == self then
711 | AceEvent:argCheck(method, 4, "function")
712 | self = method
713 | else
714 | if type(event) == "string" then
715 | AceEvent:argCheck(method, 4, "string", "function", "nil")
716 | if not method then
717 | method = event
718 | end
719 | else
720 | AceEvent:argCheck(method, 4, "string", "function")
721 | end
722 |
723 | if type(method) == "string" and type(self[method]) ~= "function" then
724 | AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
725 | end
726 | end
727 | if not AceEvent.buckets then
728 | AceEvent.buckets = new()
729 | end
730 | if not AceEvent.buckets[event] then
731 | AceEvent.buckets[event] = new()
732 | end
733 | if not AceEvent.buckets[event][self] then
734 | AceEvent.buckets[event][self] = new()
735 | AceEvent.buckets[event][self].current = new()
736 | AceEvent.buckets[event][self].self = self
737 | else
738 | AceEvent.CancelScheduledEvent(self, AceEvent.buckets[event][self].id)
739 | end
740 | local bucket = AceEvent.buckets[event][self]
741 | bucket.method = method
742 |
743 | local func = function(arg1)
744 | bucket.run = true
745 | if arg1 then
746 | bucket.current[arg1] = true
747 | end
748 | end
749 | AceEvent.buckets[event][self].func = func
750 | if type(event) == "string" then
751 | AceEvent.RegisterEvent(self, event, func)
752 | else
753 | for _,v in ipairs(event) do
754 | AceEvent.RegisterEvent(self, v, func)
755 | end
756 | end
757 | if not bucketfunc then
758 | bucketfunc = function(bucket)
759 | local current = bucket.current
760 | local method = bucket.method
761 | local self = bucket.self
762 | if bucket.run then
763 | if type(method) == "string" then
764 | self[method](self, current)
765 | elseif method then -- function
766 | method(current)
767 | end
768 | for k in pairs(current) do
769 | current[k] = nil
770 | k = nil
771 | end
772 | bucket.run = false
773 | end
774 | end
775 | end
776 | bucket.id = AceEvent.ScheduleRepeatingEvent(self, bucketfunc, delay, bucket)
777 | end
778 |
779 | function AceEvent:IsBucketEventRegistered(event)
780 | AceEvent:argCheck(event, 2, "string", "table")
781 | return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
782 | end
783 |
784 | function AceEvent:UnregisterBucketEvent(event)
785 | AceEvent:argCheck(event, 2, "string", "table")
786 | if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
787 | AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
788 | end
789 |
790 | local bucket = AceEvent.buckets[event][self]
791 |
792 | if type(event) == "string" then
793 | AceEvent.UnregisterEvent(self, event)
794 | else
795 | for _,v in ipairs(event) do
796 | AceEvent.UnregisterEvent(self, v)
797 | end
798 | end
799 | AceEvent:CancelScheduledEvent(bucket.id)
800 |
801 | del(bucket.current)
802 | AceEvent.buckets[event][self] = del(AceEvent.buckets[event][self])
803 | if not next(AceEvent.buckets[event]) then
804 | AceEvent.buckets[event] = del(AceEvent.buckets[event])
805 | end
806 | end
807 |
808 | function AceEvent:UnregisterAllBucketEvents()
809 | if not AceEvent.buckets or not next(AceEvent.buckets) then
810 | return
811 | end
812 | for k,v in pairs(AceEvent.buckets) do
813 | if v == self then
814 | AceEvent.UnregisterBucketEvent(self, k)
815 | k = nil
816 | end
817 | end
818 | end
819 |
820 | function AceEvent:OnEmbedDisable(target)
821 | self.UnregisterAllEvents(target)
822 |
823 | self.CancelAllScheduledEvents(target)
824 |
825 | self.UnregisterAllBucketEvents(target)
826 | end
827 |
828 | function AceEvent:EnableDebugging()
829 | if not self.debugTable then
830 | self.debugTable = new()
831 |
832 | if delayRegistry then
833 | for k,v in pairs(self.delayRegistry) do
834 | if not v.mem then
835 | v.mem = 0
836 | v.count = 0
837 | v.timeSpent = 0
838 | end
839 | end
840 | end
841 | end
842 | end
843 |
844 | function AceEvent:IsFullyInitialized()
845 | return self.postInit or false
846 | end
847 |
848 | function AceEvent:IsPostPlayerLogin()
849 | return self.playerLogin or false
850 | end
851 |
852 | function AceEvent:activate(oldLib, oldDeactivate)
853 | AceEvent = self
854 |
855 | if oldLib then
856 | self.onceRegistry = oldLib.onceRegistry
857 | self.throttleRegistry = oldLib.throttleRegistry
858 | self.delayRegistry = oldLib.delayRegistry
859 | self.buckets = oldLib.buckets
860 | self.registry = oldLib.registry
861 | self.frame = oldLib.frame
862 | self.debugTable = oldLib.debugTable
863 | self.playerLogin = oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true
864 | self.postInit = oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
865 | self.ALL_EVENTS = oldLib.ALL_EVENTS
866 | self.FAKE_NIL = oldLib.FAKE_NIL
867 | self.RATE = oldLib.RATE
868 | end
869 | if not self.registry then
870 | self.registry = {}
871 | end
872 | if not self.frame then
873 | self.frame = CreateFrame("Frame", "AceEvent20Frame")
874 | end
875 | if not self.ALL_EVENTS then
876 | self.ALL_EVENTS = {}
877 | end
878 | if not self.FAKE_NIL then
879 | self.FAKE_NIL = {}
880 | end
881 | if not self.RATE then
882 | self.RATE = {}
883 | end
884 | ALL_EVENTS = self.ALL_EVENTS
885 | FAKE_NIL = self.FAKE_NIL
886 | RATE = self.RATE
887 | local inPlw = false
888 | local blacklist = {
889 | UNIT_INVENTORY_CHANGED = true,
890 | BAG_UPDATE = true,
891 | ITEM_LOCK_CHANGED = true,
892 | ACTIONBAR_SLOT_CHANGED = true,
893 | }
894 | self.frame:SetScript("OnEvent", function()
895 | local event = event
896 | if event == "PLAYER_ENTERING_WORLD" then
897 | inPlw = false
898 | elseif event == "PLAYER_LEAVING_WORLD" then
899 | inPlw = true
900 | end
901 | if event and (not inPlw or not blacklist[event]) then
902 | self:TriggerEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
903 | end
904 | end)
905 | if self.delayRegistry then
906 | delayRegistry = self.delayRegistry
907 | self.frame:SetScript("OnUpdate", OnUpdate)
908 | end
909 |
910 | self:UnregisterAllEvents()
911 | self:CancelAllScheduledEvents()
912 |
913 | registeringFromAceEvent = true
914 | self:RegisterEvent("LOOT_OPENED", function()
915 | SendAddonMessage("LOOT_OPENED", "", "RAID")
916 | end)
917 | registeringFromAceEvent = nil
918 |
919 | if not self.playerLogin then
920 | registeringFromAceEvent = true
921 | self:RegisterEvent("PLAYER_LOGIN", function()
922 | self.playerLogin = true
923 | end, true)
924 | registeringFromAceEvent = nil
925 | end
926 |
927 | if not self.postInit then
928 | local isReload = true
929 | local function func()
930 | self.postInit = true
931 | self:TriggerEvent("AceEvent_FullyInitialized")
932 | if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
933 | self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
934 | end
935 | if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
936 | self:UnregisterEvent("MEETINGSTONE_CHANGED")
937 | end
938 | if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
939 | self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
940 | end
941 | if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
942 | self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
943 | end
944 | end
945 | registeringFromAceEvent = true
946 | local f = function()
947 | self.playerLogin = true
948 | self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
949 | end
950 | self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
951 | self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
952 | self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.05)
953 | end)
954 | self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
955 | if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
956 | self:UnregisterEvent("MEETINGSTONE_CHANGED")
957 | self:RegisterEvent("MINIMAP_ZONE_CHANGED", f, true)
958 | end
959 | end)
960 | registeringFromAceEvent = nil
961 | end
962 |
963 | self.super.activate(self, oldLib, oldDeactivate)
964 | if oldLib then
965 | oldDeactivate(oldLib)
966 | end
967 | end
968 |
969 | AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, AceEvent.activate)
970 | AceEvent = AceLibrary(MAJOR_VERSION)
971 |
--------------------------------------------------------------------------------
/libs/HealComm-1.0/HealComm-1.0.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | Name: HealComm-1.0
3 | Revision: $Rev: 11430 $
4 | Author(s): aviana
5 | Website: https://github.com/Aviana
6 | Description: A library to provide communication of heals and resurrections.
7 | Dependencies: AceLibrary, AceEvent-2.0, RosterLib-2.0
8 | ]]
9 |
10 | local MAJOR_VERSION = "HealComm-1.0"
11 | local MINOR_VERSION = "$Revision: 11430 $"
12 |
13 | if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
14 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
15 | if not AceLibrary:HasInstance("RosterLib-2.0") then error(MAJOR_VERSION .. " requires RosterLib-2.0") end
16 | if not AceLibrary:HasInstance("AceEvent-2.0") then error(MAJOR_VERSION .. " requires AceEvent-2.0") end
17 | if not AceLibrary:HasInstance("AceHook-2.1") then error(MAJOR_VERSION .. " requires AceHook-2.1") end
18 |
19 | local roster = AceLibrary("RosterLib-2.0")
20 | local console = AceLibrary("AceConsole-2.0") --HCSpy
21 | local HealComm = {}
22 |
23 | ------------------------------------------------
24 | -- Locales
25 | ------------------------------------------------
26 |
27 | local L = {}
28 | if( GetLocale() == "deDE" ) then
29 | L["Renew"] = "Erneuerung"
30 | L["Rejuvenation"] = "Verj\195\188ngung"
31 | L["Holy Light"] = "Heiliges Licht"
32 | L["Flash of Light"] = "Lichtblitz"
33 | L["Healing Wave"] = "Welle der Heilung"
34 | L["Lesser Healing Wave"] = "Geringe Welle der Heilung"
35 | L["Chain Heal"] = "Kettenheilung"
36 | L["Lesser Heal"] = "Geringes Heilen"
37 | L["Heal"] = "Heilen"
38 | L["Flash Heal"] = "Blitzheilung"
39 | L["Greater Heal"] = "Große Heilung"
40 | L["Prayer of Healing"] = "Gebet der Heilung"
41 | L["Healing Touch"] = "Heilende Ber\195\188hrung"
42 | L["Regrowth"] = "Nachwachsen"
43 | L["Resurrection"] = "Wiederbelebung"
44 | L["Rebirth"] = "Wiedergeburt"
45 | L["Redemption"] = "Erl\195\182sung"
46 | L["Ancestral Spirit"] = "Geist der Ahnen"
47 | L["Libram of Divinity"] = "Buchband der Offenbarung"
48 | L["Libram of Light"] = "Buchband des Lichts"
49 | L["Totem of Sustaining"] = "Totem der Erhaltung"
50 | L["Totem of Life"] = "Totem des Lebens"
51 | L["Power Infusion"] = "Seele der Macht"
52 | L["Divine Favor"] = "G\195\182ttliche Gunst"
53 | L["Nature Aligned"] = "Naturverbundenheit"
54 | L["Crusader's Wrath"] = "Zorn des Kreuzfahrers"
55 | L["The Furious Storm"] = "Der wilde Sturm"
56 | L["Holy Power"] = "Heilige Kraft"
57 | L["Prayer Beads Blessing"] = "Segen der Gebetsperlen"
58 | L["Chromatic Infusion"] = "Erf\195\188llt mit chromatischer Macht"
59 | L["Ascendance"] = "\154berlegenheit"
60 | L["Ephemeral Power"] = "Ephemere Macht"
61 | L["Unstable Power"] = "Instabile Macht"
62 | L["Healing of the Ages"] = "Heilung der Urzeiten"
63 | L["Essence of Sapphiron"] = "Essenz Saphirons"
64 | L["The Eye of the Dead"] = "Das Auge des Todes"
65 | L["Mortal Strike"] = "T\195\182dlicher Stoß"
66 | L["Wound Poison"] = "Wundgift"
67 | L["Curse of the Deadwood"] = "Fluch der Totenwaldfelle"
68 | L["Veil of Shadow"] = "Schattenschleier"
69 | L["Gehennas' Curse"] = "Gehennas' Fluch"
70 | L["Mortal Wound"] = "Trauma"
71 | L["Necrotic Poison"] = "Nekrotisches Gift"
72 | L["Necrotic Aura"] = "Nekrotische Aura"
73 | L["Healing Way"] = "Pfad der Heilung"
74 | L["Warsong Gulch"] = "Kriegshymnenschlucht"
75 | L["Arathi Basin"] = "Arathibecken"
76 | L["Alterac Valley"] = "Alteractal"
77 | L["Blessing of Light"] = "Segen des Lichts"
78 | L["Blood Fury"] = "Kochendes Blut"
79 | L["Set: Increases the duration of your Rejuvenation spell by 3 sec."] = "Set: Erh\195\182ht die Dauer Eures Zaubers \'Verj\195\188ngung\' um 3 Sek."
80 | L["Set: Increases the duration of your Renew spell by 3 sec."] = "Set: Erh\195\182ht die Dauer Eures Zaubers 'Erneuerung' um 3 Sek."
81 | L["^Corpse of (.+)$"] = "^Leichnam von (.+)$"
82 | elseif ( GetLocale() == "frFR" ) then
83 | L["Renew"] = "R\195\169novation"
84 | L["Rejuvenation"] = "R\195\169cup\195\169ration"
85 | L["Holy Light"] = "Lumi\195\168re sacr\195\169e"
86 | L["Flash of Light"] = "Eclair lumineux"
87 | L["Healing Wave"] = "Vague de soins"
88 | L["Lesser Healing Wave"] = "Vague de soins inf\195\169rieurs"
89 | L["Chain Heal"] = "Salve de gu\195\169rison"
90 | L["Lesser Heal"] = "Soins inf\195\169rieurs"
91 | L["Heal"] = "Soins"
92 | L["Flash Heal"] = "Soins rapides"
93 | L["Greater Heal"] = "Soins sup\195\169rieurs"
94 | L["Prayer of Healing"] = "Pri\195\168re de soins"
95 | L["Healing Touch"] = "Toucher gu\195\169risseur"
96 | L["Regrowth"] = "R\195\169tablissement"
97 | L["Resurrection"] = "R\195\169surrection"
98 | L["Rebirth"] = "Renaissance"
99 | L["Redemption"] = "R\195\169demption"
100 | L["Ancestral Spirit"] = "Esprit ancestral"
101 | L["Libram of Divinity"] = "Libram de divinit\195\169"
102 | L["Libram of Light"] = "Libram de lumi\195\168re"
103 | L["Totem of Sustaining"] = "Totem de soutien"
104 | L["Totem of Life"] = "Totem de vie"
105 | L["Power Infusion"] = "Infusion de puissance"
106 | L["Divine Favor"] = "Faveur divine"
107 | L["Nature Aligned"] = "Alignement sur la nature"
108 | L["Crusader's Wrath"] = "Col\195\168re du crois\195\169"
109 | L["The Furious Storm"] = "La temp\195\170te furieuse"
110 | L["Holy Power"] = "Puissance sacr\195\169e"
111 | L["Prayer Beads Blessing"] = "B\195\169n\195\169diction du chapelet"
112 | L["Chromatic Infusion"] = "Infusion chromatique"
113 | L["Ascendance"] = "Ascendance"
114 | L["Ephemeral Power"] = "Puissance \195\169ph\195\169m\195\168re"
115 | L["Unstable Power"] = "Puissance instable"
116 | L["Healing of the Ages"] = "Soins des \195\162ges"
117 | L["Essence of Sapphiron"] = "Essence de Saphiron"
118 | L["The Eye of the Dead"] = "L'Oeil du mort"
119 | L["Mortal Strike"] = "Frappe mortelle"
120 | L["Wound Poison"] = "Poison douloureux"
121 | L["Curse of the Deadwood"] = "Mal\195\169diction des Mort-bois"
122 | L["Veil of Shadow"] = "Voile de l'ombre"
123 | L["Gehennas' Curse"] = "Mal\195\169diction de Gehennas"
124 | L["Mortal Wound"] = "Blessures mortelles"
125 | L["Necrotic Poison"] = "Poison n\195\169crotique"
126 | L["Necrotic Aura"] = "Aura n\195\169crotique"
127 | L["Healing Way"] = "Flots de soins"
128 | L["Warsong Gulch"] = "Goulet des Warsong"
129 | L["Arathi Basin"] = "Bassin d'Arathi"
130 | L["Alterac Valley"] = "Vall\195\169e d'Alterac"
131 | L["Blood Fury"] = "Fureur sanguinaire"
132 | L["Blessing of Light"] = "B\195\169n\195\169diction de lumi\195\168re"
133 | L["Set: Increases the duration of your Rejuvenation spell by 3 sec."] = "Set: Augmente la dur\195\169e de votre sort R\195\169cup\195\169ration de 3 s."
134 | L["Set: Increases the duration of your Renew spell by 3 sec."] = "Set: Augmente la dur\195\169e de votre sort R\195\169novation de 3 s."
135 | L["^Corpse of (.+)$"] = "^Cadavre |2 (.+)$"
136 | elseif GetLocale() == "zhCN" then
137 | if AceLibrary:HasInstance("Babble-Spell-2.2") then
138 | L.BS = AceLibrary("Babble-Spell-2.2")
139 | end
140 | if AceLibrary:HasInstance("Babble-Zone-2.2") then
141 | L.BZ = AceLibrary("Babble-Zone-2.2")
142 | end
143 | setmetatable(L, {__index = function(table, key)
144 | if table.BS and table.BS:HasTranslation(key) then
145 | return table.BS[key]
146 | elseif table.BZ and table.BZ:HasTranslation(key) then
147 | return table.BZ[key]
148 | end
149 | end})
150 | L["Libram of Divinity"] = "神性圣契"
151 | L["Libram of Light"] = "光明圣契"
152 | L["Necrotic Aura"] = "死灵光环" -- 这个技能不知道是否存在
153 | L["Set: Increases the duration of your Rejuvenation spell by 3 sec."] = "套装:使你的回春术的持续时间延长3秒。" -- T2
154 | L["Set: Increases the duration of your Renew spell by 3 sec."] = "套装:使你的恢复术的持续时间延长3秒。" -- T2.5
155 | L["Totem of Life"] = "生命图腾"
156 | L["Totem of Sustaining"] = "持久图腾"
157 | L["^Corpse of (.+)$"] = "(.+)的尸体"
158 | else
159 | L["Renew"] = "Renew"
160 | L["Rejuvenation"] = "Rejuvenation"
161 | L["Holy Light"] = "Holy Light"
162 | L["Flash of Light"] = "Flash of Light"
163 | L["Healing Wave"] = "Healing Wave"
164 | L["Lesser Healing Wave"] = "Lesser Healing Wave"
165 | L["Chain Heal"] = "Chain Heal"
166 | L["Lesser Heal"] = "Lesser Heal"
167 | L["Heal"] = "Heal"
168 | L["Flash Heal"] = "Flash Heal"
169 | L["Greater Heal"] = "Greater Heal"
170 | L["Prayer of Healing"] = "Prayer of Healing"
171 | L["Healing Touch"] = "Healing Touch"
172 | L["Regrowth"] = "Regrowth"
173 | L["Resurrection"] = "Resurrection"
174 | L["Rebirth"] = "Rebirth"
175 | L["Redemption"] = "Redemption"
176 | L["Ancestral Spirit"] = "Ancestral Spirit"
177 | L["Libram of Divinity"] = "Libram of Divinity"
178 | L["Libram of Light"] = "Libram of Light"
179 | L["Totem of Sustaining"] = "Totem of Sustaining"
180 | L["Totem of Life"] = "Totem of Life"
181 | L["Power Infusion"] = "Power Infusion"
182 | L["Divine Favor"] = "Divine Favor"
183 | L["Nature Aligned"] = "Nature Aligned"
184 | L["Crusader's Wrath"] = "Crusader's Wrath"
185 | L["The Furious Storm"] = "The Furious Storm"
186 | L["Holy Power"] = "Holy Power"
187 | L["Prayer Beads Blessing"] = "Prayer Beads Blessing"
188 | L["Chromatic Infusion"] = "Chromatic Infusion"
189 | L["Ascendance"] = "Ascendance"
190 | L["Ephemeral Power"] = "Ephemeral Power"
191 | L["Unstable Power"] = "Unstable Power"
192 | L["Healing of the Ages"] = "Healing of the Ages"
193 | L["Essence of Sapphiron"] = "Essence of Sapphiron"
194 | L["The Eye of the Dead"] = "The Eye of the Dead"
195 | L["Mortal Strike"] = "Mortal Strike"
196 | L["Wound Poison"] = "Wound Poison"
197 | L["Curse of the Deadwood"] = "Curse of the Deadwood"
198 | L["Veil of Shadow"] = "Veil of Shadow"
199 | L["Gehennas' Curse"] = "Gehennas' Curse"
200 | L["Mortal Wound"] = "Mortal Wound"
201 | L["Necrotic Poison"] = "Necrotic Poison"
202 | L["Necrotic Aura"] = "Necrotic Aura"
203 | L["Healing Way"] = "Healing Way"
204 | L["Warsong Gulch"] = "Warsong Gulch"
205 | L["Arathi Basin"] = "Arathi Basin"
206 | L["Alterac Valley"] = "Alterac Valley"
207 | L["Blessing of Light"] = "Blessing of Light"
208 | L["Blood Fury"] = "Blood Fury"
209 | L["Set: Increases the duration of your Rejuvenation spell by 3 sec."] = "Set: Increases the duration of your Rejuvenation spell by 3 sec."
210 | L["Set: Increases the duration of your Renew spell by 3 sec."] = "Set: Increases the duration of your Renew spell by 3 sec."
211 | L["^Corpse of (.+)$"] = "^Corpse of (.+)$"
212 | end
213 |
214 | ------------------------------------------------
215 | -- activate, enable, disable
216 | ------------------------------------------------
217 |
218 | local function activate(self, oldLib, oldDeactivate)
219 | HealComm = self
220 | if oldLib then
221 | self.Heals = oldLib.Heals
222 | self.GrpHeals = oldLib.GrpHeals
223 | self.Lookup = oldLib.Lookup
224 | self.pendingResurrections = oldlib.pendingResurrections
225 | self.Hots = oldLib.Hots
226 | self.SpellCastInfo = oldLib.SpellCastInfo
227 | oldLib:UnregisterAllEvents()
228 | oldLib:CancelAllScheduledEvents()
229 | end
230 | if not self.Heals then
231 | self.Heals = {}
232 | end
233 | if not self.GrpHeals then
234 | self.GrpHeals = {}
235 | end
236 | if not self.Lookup then
237 | self.Lookup = {}
238 | end
239 | if not self.pendingResurrections then
240 | self.pendingResurrections = {}
241 | end
242 | if not self.Hots then
243 | self.Hots = {}
244 | end
245 | if not self.SpellCastInfo then
246 | self.SpellCastInfo = {}
247 | end
248 | if oldDeactivate then oldDeactivate(oldLib) end
249 | end
250 |
251 | local function external(self, major, instance)
252 | if major == "AceEvent-2.0" then
253 | local AceEvent = instance
254 | AceEvent:embed(self)
255 | self:RegisterEvent("SPELLCAST_START")
256 | self:RegisterEvent("SPELLCAST_INTERRUPTED", "SPELLCAST_FAILED")
257 | self:RegisterEvent("SPELLCAST_FAILED")
258 | self:RegisterEvent("SPELLCAST_DELAYED")
259 | self:RegisterEvent("SPELLCAST_STOP")
260 | self:RegisterEvent("CHAT_MSG_ADDON")
261 | self:RegisterEvent("UNIT_AURA")
262 | self:RegisterEvent("UNIT_HEALTH")
263 | self:RegisterEvent("PLAYER_LOGIN")
264 | self:TriggerEvent("HealComm_Enabled")
265 | end
266 | if major == "AceHook-2.1" then
267 | local AceHook = instance
268 | AceHook:embed(self)
269 | end
270 | end
271 |
272 | function HealComm:PLAYER_LOGIN()
273 | self:HookScript(WorldFrame, "OnMouseDown", "OnMouseDown")
274 | self:Hook("CastSpell")
275 | self:Hook("CastSpellByName")
276 | self:Hook("UseAction")
277 | self:Hook("SpellTargetUnit")
278 | self:Hook("SpellStopTargeting")
279 | self:Hook("TargetUnit")
280 | end
281 |
282 | function HealComm:Enable()
283 | -- not used anymore, but as addons still might be calling this method, we're keeping it.
284 | end
285 |
286 |
287 | function HealComm:Disable()
288 | -- not used anymore, but as addons still might be calling this method, we're keeping it.
289 | end
290 |
291 | ------------------------------------------------
292 | -- Addon Code
293 | ------------------------------------------------
294 |
295 | function strmatch(str, pat, init)
296 | local a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a13,a14,a15,a16,a17,a18,a19,a20 = string.find(str, pat, init)
297 | return a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a13,a14,a15,a16,a17,a18,a19,a20
298 | end
299 |
300 | HealComm.Spells = {
301 | [L["Holy Light"]] = {
302 | [1] = function (SpellPower)
303 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
304 | local hlMod = 4*talentRank/100 + 1
305 | return (44*hlMod+(((2.5/3.5) * SpellPower)*0.1))
306 | end;
307 | [2] = function (SpellPower)
308 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
309 | local hlMod = 4*talentRank/100 + 1
310 | return (88*hlMod+(((2.5/3.5) * SpellPower)*0.224))
311 | end;
312 | [3] = function (SpellPower)
313 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
314 | local hlMod = 4*talentRank/100 + 1
315 | return (174*hlMod+(((2.5/3.5) * SpellPower)*0.476))
316 | end;
317 | [4] = function (SpellPower)
318 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
319 | local hlMod = 4*talentRank/100 + 1
320 | return (334*hlMod+((2.5/3.5) * SpellPower))
321 | end;
322 | [5] = function (SpellPower)
323 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
324 | local hlMod = 4*talentRank/100 + 1
325 | return (522*hlMod+((2.5/3.5) * SpellPower))
326 | end;
327 | [6] = function (SpellPower)
328 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
329 | local hlMod = 4*talentRank/100 + 1
330 | return (740*hlMod+((2.5/3.5) * SpellPower))
331 | end;
332 | [7] = function (SpellPower)
333 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
334 | local hlMod = 4*talentRank/100 + 1
335 | return (1000*hlMod+((2.5/3.5) * SpellPower))
336 | end;
337 | [8] = function (SpellPower)
338 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
339 | local hlMod = 4*talentRank/100 + 1
340 | return (1318*hlMod+((2.5/3.5) * SpellPower))
341 | end;
342 | [9] = function (SpellPower)
343 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
344 | local hlMod = 4*talentRank/100 + 1
345 | return (1681*hlMod+((2.5/3.5) * SpellPower))
346 | end;
347 | };
348 | [L["Flash of Light"]] = {
349 | [1] = function (SpellPower)
350 | local lp = 0
351 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
352 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
353 | local name = GetItemInfo(itemstring)
354 | if name == "Libram of Divinity" then
355 | lp = 53
356 | elseif name == "Libram of Light" then
357 | lp = 83
358 | end
359 | end
360 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
361 | local hlMod = 4*talentRank/100 + 1
362 | return (68*hlMod+lp+((1.5/3.5) * SpellPower))
363 | end;
364 | [2] = function (SpellPower)
365 | local lp = 0
366 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
367 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
368 | local name = GetItemInfo(itemstring)
369 | if name == "Libram of Divinity" then
370 | lp = 53
371 | elseif name == "Libram of Light" then
372 | lp = 83
373 | end
374 | end
375 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
376 | local hlMod = 4*talentRank/100 + 1
377 | return (104*hlMod+lp+((1.5/3.5) * SpellPower))
378 | end;
379 | [3] = function (SpellPower)
380 | local lp = 0
381 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
382 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
383 | local name = GetItemInfo(itemstring)
384 | if name == "Libram of Divinity" then
385 | lp = 53
386 | elseif name == "Libram of Light" then
387 | lp = 83
388 | end
389 | end
390 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
391 | local hlMod = 4*talentRank/100 + 1
392 | return (155*hlMod+lp+((1.5/3.5) * SpellPower))
393 | end;
394 | [4] = function (SpellPower)
395 | local lp = 0
396 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
397 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
398 | local name = GetItemInfo(itemstring)
399 | if name == "Libram of Divinity" then
400 | lp = 53
401 | elseif name == "Libram of Light" then
402 | lp = 83
403 | end
404 | end
405 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
406 | local hlMod = 4*talentRank/100 + 1
407 | return (210*hlMod+lp+((1.5/3.5) * SpellPower))
408 | end;
409 | [5] = function (SpellPower)
410 | local lp = 0
411 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
412 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
413 | local name = GetItemInfo(itemstring)
414 | if name == "Libram of Divinity" then
415 | lp = 53
416 | elseif name == "Libram of Light" then
417 | lp = 83
418 | end
419 | end
420 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
421 | local hlMod = 4*talentRank/100 + 1
422 | return (284*hlMod+lp+((1.5/3.5) * SpellPower))
423 | end;
424 | [6] = function (SpellPower)
425 | local lp = 0
426 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
427 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
428 | local name = GetItemInfo(itemstring)
429 | if name == "Libram of Divinity" then
430 | lp = 53
431 | elseif name == "Libram of Light" then
432 | lp = 83
433 | end
434 | end
435 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
436 | local hlMod = 4*talentRank/100 + 1
437 | return (364*hlMod+lp+((1.5/3.5) * SpellPower))
438 | end;
439 | [7] = function (SpellPower)
440 | local lp = 0
441 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
442 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
443 | local name = GetItemInfo(itemstring)
444 | if name == "Libram of Divinity" then
445 | lp = 53
446 | elseif name == "Libram of Light" then
447 | lp = 83
448 | end
449 | end
450 | local _,_,_,_,talentRank,_ = GetTalentInfo(1,5)
451 | local hlMod = 4*talentRank/100 + 1
452 | return (481*hlMod+lp+((1.5/3.5) * SpellPower))
453 | end;
454 | };
455 | [L["Healing Wave"]] = {
456 | [1] = function (SpellPower)
457 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
458 | local pMod = 2*talentRank/100 + 1
459 | return (40*pMod+(((1.5/3.5) * SpellPower)*0.22))
460 | end;
461 | [2] = function (SpellPower)
462 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
463 | local pMod = 2*talentRank/100 + 1
464 | return (72*pMod+(((2/3.5) * SpellPower)*0.38))
465 | end;
466 | [3] = function (SpellPower)
467 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
468 | local pMod = 2*talentRank/100 + 1
469 | return (143*pMod+(((2.5/3.5) * SpellPower)*0.446))
470 | end;
471 | [4] = function (SpellPower)
472 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
473 | local pMod = 2*talentRank/100 + 1
474 | return (293*pMod+(((3/3.5) * SpellPower)*0.7))
475 | end;
476 | [5] = function (SpellPower)
477 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
478 | local pMod = 2*talentRank/100 + 1
479 | return (409*pMod+((3/3.5) * SpellPower))
480 | end;
481 | [6] = function (SpellPower)
482 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
483 | local pMod = 2*talentRank/100 + 1
484 | return (580*pMod+((3/3.5) * SpellPower))
485 | end;
486 | [7] = function (SpellPower)
487 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
488 | local pMod = 2*talentRank/100 + 1
489 | return (798*pMod+((3/3.5) * SpellPower))
490 | end;
491 | [8] = function (SpellPower)
492 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
493 | local pMod = 2*talentRank/100 + 1
494 | return (1093*pMod+((3/3.5) * SpellPower))
495 | end;
496 | [9] = function (SpellPower)
497 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
498 | local pMod = 2*talentRank/100 + 1
499 | return (1465*pMod+((3/3.5) * SpellPower))
500 | end;
501 | [10] = function (SpellPower)
502 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
503 | local pMod = 2*talentRank/100 + 1
504 | return (1736*pMod+((3/3.5) * SpellPower))
505 | end;
506 | };
507 | [L["Lesser Healing Wave"]] = {
508 | [1] = function (SpellPower)
509 | local tp = 0
510 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
511 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
512 | local name = GetItemInfo(itemstring)
513 | if name == "Totem of Sustaining" then
514 | tp = 53
515 | elseif name == "Totem of Life" then
516 | tp = 80
517 | end
518 | end
519 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
520 | local pMod = 2*talentRank/100 + 1
521 | return (175*pMod+tp+((1.5/3.5) * SpellPower))
522 | end;
523 | [2] = function (SpellPower)
524 | local tp = 0
525 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
526 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
527 | local name = GetItemInfo(itemstring)
528 | if name == "Totem of Sustaining" then
529 | tp = 53
530 | elseif name == "Totem of Life" then
531 | tp = 80
532 | end
533 | end
534 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
535 | local pMod = 2*talentRank/100 + 1
536 | return (265*pMod+tp+((1.5/3.5) * SpellPower))
537 | end;
538 | [3] = function (SpellPower)
539 | local tp = 0
540 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
541 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
542 | local name = GetItemInfo(itemstring)
543 | if name == "Totem of Sustaining" then
544 | tp = 53
545 | elseif name == "Totem of Life" then
546 | tp = 80
547 | end
548 | end
549 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
550 | local pMod = 2*talentRank/100 + 1
551 | return (360*pMod+tp+((1.5/3.5) * SpellPower))
552 | end;
553 | [4] = function (SpellPower)
554 | local tp = 0
555 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
556 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
557 | local name = GetItemInfo(itemstring)
558 | if name == "Totem of Sustaining" then
559 | tp = 53
560 | elseif name == "Totem of Life" then
561 | tp = 80
562 | end
563 | end
564 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
565 | local pMod = 2*talentRank/100 + 1
566 | return (487*pMod+tp+((1.5/3.5) * SpellPower))
567 | end;
568 | [5] = function (SpellPower)
569 | local tp = 0
570 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
571 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
572 | local name = GetItemInfo(itemstring)
573 | if name == "Totem of Sustaining" then
574 | tp = 53
575 | elseif name == "Totem of Life" then
576 | tp = 80
577 | end
578 | end
579 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
580 | local pMod = 2*talentRank/100 + 1
581 | return (669*pMod+tp+((1.5/3.5) * SpellPower))
582 | end;
583 | [6] = function (SpellPower)
584 | local tp = 0
585 | if GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")) then
586 | local _,_,itemstring = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("RangedSlot")), "|H(.+)|h")
587 | local name = GetItemInfo(itemstring)
588 | if name == "Totem of Sustaining" then
589 | tp = 53
590 | elseif name == "Totem of Life" then
591 | tp = 80
592 | end
593 | end
594 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
595 | local pMod = 2*talentRank/100 + 1
596 | return (881*pMod+tp+((1.5/3.5) * SpellPower))
597 | end;
598 | };
599 | [L["Chain Heal"]] = {
600 | [1] = function (SpellPower)
601 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
602 | local pMod = 2*talentRank/100 + 1
603 | return (344*pMod+((2.5/3.5) * SpellPower))
604 | end;
605 | [2] = function (SpellPower)
606 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
607 | local pMod = 2*talentRank/100 + 1
608 | return (435*pMod+((2.5/3.5) * SpellPower))
609 | end;
610 | [3] = function (SpellPower)
611 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,14)
612 | local pMod = 2*talentRank/100 + 1
613 | return (591*pMod+((2.5/3.5) * SpellPower))
614 | end;
615 | };
616 | [L["Lesser Heal"]] = {
617 | [1] = function (SpellPower)
618 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
619 | local _,Spirit,_,_ = UnitStat("player",5)
620 | local sgMod = Spirit * 5*talentRank/100
621 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
622 | local shMod = 2*talentRank2/100 + 1
623 | return (52*shMod+((1.5/3.5) * (SpellPower+sgMod))*0.19)
624 | end;
625 | [2] = function (SpellPower)
626 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
627 | local _,Spirit,_,_ = UnitStat("player",5)
628 | local sgMod = Spirit * 5*talentRank/100
629 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
630 | local shMod = 2*talentRank2/100 + 1
631 | return (79*shMod+((2/3.5) * (SpellPower+sgMod))*0.34)
632 | end;
633 | [3] = function (SpellPower)
634 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
635 | local _,Spirit,_,_ = UnitStat("player",5)
636 | local sgMod = Spirit * 5*talentRank/100
637 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
638 | local shMod = 2*talentRank2/100 + 1
639 | return (147*shMod+((2.5/3.5) * (SpellPower+sgMod))*0.6)
640 | end;
641 | };
642 | [L["Heal"]] = {
643 | [1] = function (SpellPower)
644 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
645 | local _,Spirit,_,_ = UnitStat("player",5)
646 | local sgMod = Spirit * 5*talentRank/100
647 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
648 | local shMod = 2*talentRank2/100 + 1
649 | return (319*shMod+((3/3.5) * (SpellPower+sgMod))*0.586)
650 | end;
651 | [2] = function (SpellPower)
652 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
653 | local _,Spirit,_,_ = UnitStat("player",5)
654 | local sgMod = Spirit * 5*talentRank/100
655 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
656 | local shMod = 2*talentRank2/100 + 1
657 | return (471*shMod+((3/3.5) * (SpellPower+sgMod)))
658 | end;
659 | [3] = function (SpellPower)
660 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
661 | local _,Spirit,_,_ = UnitStat("player",5)
662 | local sgMod = Spirit * 5*talentRank/100
663 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
664 | local shMod = 2*talentRank2/100 + 1
665 | return (610*shMod+((3/3.5) * (SpellPower+sgMod)))
666 | end;
667 | [4] = function (SpellPower)
668 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
669 | local _,Spirit,_,_ = UnitStat("player",5)
670 | local sgMod = Spirit * 5*talentRank/100
671 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
672 | local shMod = 2*talentRank2/100 + 1
673 | return (759*shMod+((3/3.5) * (SpellPower+sgMod)))
674 | end;
675 | };
676 | [L["Flash Heal"]] = {
677 | [1] = function (SpellPower)
678 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
679 | local _,Spirit,_,_ = UnitStat("player",5)
680 | local sgMod = Spirit * 5*talentRank/100
681 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
682 | local shMod = 2*talentRank2/100 + 1
683 | return (216*shMod+((1.5/3.5) * (SpellPower+sgMod)))
684 | end;
685 | [2] = function (SpellPower)
686 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
687 | local _,Spirit,_,_ = UnitStat("player",5)
688 | local sgMod = Spirit * 5*talentRank/100
689 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
690 | local shMod = 2*talentRank2/100 + 1
691 | return (287*shMod+((1.5/3.5) * (SpellPower+sgMod)))
692 | end;
693 | [3] = function (SpellPower)
694 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
695 | local _,Spirit,_,_ = UnitStat("player",5)
696 | local sgMod = Spirit * 5*talentRank/100
697 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
698 | local shMod = 2*talentRank2/100 + 1
699 | return (361*shMod+((1.5/3.5) * (SpellPower+sgMod)))
700 | end;
701 | [4] = function (SpellPower)
702 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
703 | local _,Spirit,_,_ = UnitStat("player",5)
704 | local sgMod = Spirit * 5*talentRank/100
705 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
706 | local shMod = 2*talentRank2/100 + 1
707 | return (440*shMod+((1.5/3.5) * (SpellPower+sgMod)))
708 | end;
709 | [5] = function (SpellPower)
710 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
711 | local _,Spirit,_,_ = UnitStat("player",5)
712 | local sgMod = Spirit * 5*talentRank/100
713 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
714 | local shMod = 2*talentRank2/100 + 1
715 | return (568*shMod+((1.5/3.5) * (SpellPower+sgMod)))
716 | end;
717 | [6] = function (SpellPower)
718 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
719 | local _,Spirit,_,_ = UnitStat("player",5)
720 | local sgMod = Spirit * 5*talentRank/100
721 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
722 | local shMod = 2*talentRank2/100 + 1
723 | return (705*shMod+((1.5/3.5) * (SpellPower+sgMod)))
724 | end;
725 | [7] = function (SpellPower)
726 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
727 | local _,Spirit,_,_ = UnitStat("player",5)
728 | local sgMod = Spirit * 5*talentRank/100
729 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
730 | local shMod = 2*talentRank2/100 + 1
731 | return (886*shMod+((1.5/3.5) * (SpellPower+sgMod)))
732 | end;
733 | };
734 | [L["Greater Heal"]] = {
735 | [1] = function (SpellPower)
736 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
737 | local _,Spirit,_,_ = UnitStat("player",5)
738 | local sgMod = Spirit * 5*talentRank/100
739 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
740 | local shMod = 2*talentRank2/100 + 1
741 | return (957*shMod+((3/3.5) * (SpellPower+sgMod)))
742 | end;
743 | [2] = function (SpellPower)
744 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
745 | local _,Spirit,_,_ = UnitStat("player",5)
746 | local sgMod = Spirit * 5*talentRank/100
747 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
748 | local shMod = 2*talentRank2/100 + 1
749 | return (1220*shMod+((3/3.5) * (SpellPower+sgMod)))
750 | end;
751 | [3] = function (SpellPower)
752 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
753 | local _,Spirit,_,_ = UnitStat("player",5)
754 | local sgMod = Spirit * 5*talentRank/100
755 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
756 | local shMod = 2*talentRank2/100 + 1
757 | return (1524*shMod+((3/3.5) * (SpellPower+sgMod)))
758 | end;
759 | [4] = function (SpellPower)
760 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
761 | local _,Spirit,_,_ = UnitStat("player",5)
762 | local sgMod = Spirit * 5*talentRank/100
763 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
764 | local shMod = 2*talentRank2/100 + 1
765 | return (1903*shMod+((3/3.5) * (SpellPower+sgMod)))
766 | end;
767 | [5] = function (SpellPower)
768 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
769 | local _,Spirit,_,_ = UnitStat("player",5)
770 | local sgMod = Spirit * 5*talentRank/100
771 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
772 | local shMod = 2*talentRank2/100 + 1
773 | return (2081*shMod+((3/3.5) * (SpellPower+sgMod)))
774 | end;
775 | };
776 | [L["Prayer of Healing"]] = {
777 | [1] = function (SpellPower)
778 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
779 | local _,Spirit,_,_ = UnitStat("player",5)
780 | local sgMod = Spirit * 5*talentRank/100
781 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
782 | local shMod = 2*talentRank2/100 + 1
783 | return (311*shMod+((3/3.5/3) * (SpellPower+sgMod)))
784 | end;
785 | [2] = function (SpellPower)
786 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
787 | local _,Spirit,_,_ = UnitStat("player",5)
788 | local sgMod = Spirit * 5*talentRank/100
789 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
790 | local shMod = 2*talentRank2/100 + 1
791 | return (460*shMod+((3/3.5/3) * (SpellPower+sgMod)))
792 | end;
793 | [3] = function (SpellPower)
794 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
795 | local _,Spirit,_,_ = UnitStat("player",5)
796 | local sgMod = Spirit * 5*talentRank/100
797 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
798 | local shMod = 2*talentRank2/100 + 1
799 | return (676*shMod+((3/3.5/3) * (SpellPower+sgMod)))
800 | end;
801 | [4] = function (SpellPower)
802 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
803 | local _,Spirit,_,_ = UnitStat("player",5)
804 | local sgMod = Spirit * 5*talentRank/100
805 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
806 | local shMod = 2*talentRank2/100 + 1
807 | return (965*shMod+((3/3.5/3) * (SpellPower+sgMod)))
808 | end;
809 | [5] = function (SpellPower)
810 | local _,_,_,_,talentRank,_ = GetTalentInfo(2,14)
811 | local _,Spirit,_,_ = UnitStat("player",5)
812 | local sgMod = Spirit * 5*talentRank/100
813 | local _,_,_,_,talentRank2,_ = GetTalentInfo(2,15)
814 | local shMod = 2*talentRank2/100 + 1
815 | return (1070*shMod+((3/3.5/3) * (SpellPower+sgMod)))
816 | end;
817 | };
818 | [L["Healing Touch"]] = {
819 | [1] = function (SpellPower)
820 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
821 | local gnMod = 2*talentRank/100 + 1
822 | return (43*gnMod+((1.5/3.5) * SpellPower * (1-((20-4)*0.0375))))
823 | end;
824 | [2] = function (SpellPower)
825 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
826 | local gnMod = 2*talentRank/100 + 1
827 | return (101*gnMod+((2/3.5) * SpellPower * (1-((20-13)*0.0375))))
828 | end;
829 | [3] = function (SpellPower)
830 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
831 | local gnMod = 2*talentRank/100 + 1
832 | return (220*gnMod+((2.5/3.5) * SpellPower))
833 | end;
834 | [4] = function (SpellPower)
835 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
836 | local gnMod = 2*talentRank/100 + 1
837 | return (435*gnMod+((3/3.5) * SpellPower))
838 | end;
839 | [5] = function (SpellPower)
840 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
841 | local gnMod = 2*talentRank/100 + 1
842 | return ((634*gnMod)+SpellPower)
843 | end;
844 | [6] = function (SpellPower)
845 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
846 | local gnMod = 2*talentRank/100 + 1
847 | return ((819*gnMod)+SpellPower)
848 | end;
849 | [7] = function (SpellPower)
850 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
851 | local gnMod = 2*talentRank/100 + 1
852 | return ((1029*gnMod)+SpellPower)
853 | end;
854 | [8] = function (SpellPower)
855 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
856 | local gnMod = 2*talentRank/100 + 1
857 | return ((1314*gnMod)+SpellPower)
858 | end;
859 | [9] = function (SpellPower)
860 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
861 | local gnMod = 2*talentRank/100 + 1
862 | return ((1657*gnMod)+SpellPower)
863 | end;
864 | [10] = function (SpellPower)
865 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
866 | local gnMod = 2*talentRank/100 + 1
867 | return ((2061*gnMod)+SpellPower)
868 | end;
869 | [11] = function (SpellPower)
870 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
871 | local gnMod = 2*talentRank/100 + 1
872 | return ((2473*gnMod)+SpellPower)
873 | end;
874 | };
875 | [L["Regrowth"]] = {
876 | [1] = function (SpellPower)
877 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
878 | local gnMod = 2*talentRank/100 + 1
879 | return ((91*gnMod)+(((2/3.5)*SpellPower)*0.5*0.38))
880 | end;
881 | [2] = function (SpellPower)
882 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
883 | local gnMod = 2*talentRank/100 + 1
884 | return ((177*gnMod)+(((2/3.5)*SpellPower)*0.5*0.513))
885 | end;
886 | [3] = function (SpellPower)
887 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
888 | local gnMod = 2*talentRank/100 + 1
889 | return ((258*gnMod)+(((2/3.5)*SpellPower)*0.5))
890 | end;
891 | [4] = function (SpellPower)
892 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
893 | local gnMod = 2*talentRank/100 + 1
894 | return ((340*gnMod)+(((2/3.5)*SpellPower)*0.5))
895 | end;
896 | [5] = function (SpellPower)
897 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
898 | local gnMod = 2*talentRank/100 + 1
899 | return ((432*gnMod)+(((2/3.5)*SpellPower)*0.5))
900 | end;
901 | [6] = function (SpellPower)
902 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
903 | local gnMod = 2*talentRank/100 + 1
904 | return ((544*gnMod)+(((2/3.5)*SpellPower)*0.5))
905 | end;
906 | [7] = function (SpellPower)
907 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
908 | local gnMod = 2*talentRank/100 + 1
909 | return ((686*gnMod)+(((2/3.5)*SpellPower)*0.5))
910 | end;
911 | [8] = function (SpellPower)
912 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
913 | local gnMod = 2*talentRank/100 + 1
914 | return ((858*gnMod)+(((2/3.5)*SpellPower)*0.5))
915 | end;
916 | [9] = function (SpellPower)
917 | local _,_,_,_,talentRank,_ = GetTalentInfo(3,12)
918 | local gnMod = 2*talentRank/100 + 1
919 | return ((1062*gnMod)+(((2/3.5)*SpellPower)*0.5))
920 | end;
921 | };
922 | }
923 |
924 | local Resurrections = {
925 | [L["Resurrection"]] = true;
926 | [L["Rebirth"]] = true;
927 | [L["Redemption"]] = true;
928 | [L["Ancestral Spirit"]] = true;
929 | }
930 |
931 | local function strsplit(pString, pPattern)
932 | local Table = {}
933 | local fpat = "(.-)" .. pPattern
934 | local last_end = 1
935 | local s, e, cap = strfind(pString, fpat, 1)
936 | while s do
937 | if s ~= 1 or cap ~= "" then
938 | table.insert(Table,cap)
939 | end
940 | last_end = e+1
941 | s, e, cap = strfind(pString, fpat, last_end)
942 | end
943 | if last_end <= strlen(pString) then
944 | cap = strfind(pString, last_end)
945 | table.insert(Table, cap)
946 | end
947 | return Table
948 | end
949 |
950 | local healcommTip = CreateFrame("GameTooltip", "healcommTip", nil, "GameTooltipTemplate")
951 | healcommTip:SetOwner(WorldFrame, "ANCHOR_NONE")
952 |
953 | HealComm.Buffs = {
954 | [L["Power Infusion"]] = {amount = 0, mod = 0.2, icon = "Interface\\Icons\\Spell_Holy_PowerInfusion"};
955 | [L["Divine Favor"]] = {amount = 0, mod = 0.5, icon = "Interface\\Icons\\Spell_Holy_Heal"};
956 | [L["Nature Aligned"]] = {amount = 0, mod = 0.2, icon = "Interface\\Icons\\Spell_Nature_SpiritArmor"};
957 | [L["Crusader's Wrath"]] = {amount = 95, mod = 0, icon = "Interface\\Icons\\Spell_Nature_GroundingTotem"};
958 | [L["The Furious Storm"]] = {amount = 95, mod = 0, icon = "Interface\\Icons\\Spell_Nature_CallStorm"};
959 | [L["Holy Power"]] = {amount = 80, mod = 0, icon = "Interface\\Icons\\Spell_Holy_HolyNova"};
960 | [L["Prayer Beads Blessing"]] = {amount = 190, mod = 0, icon = "Interface\\Icons\\Inv_Jewelry_Necklace_11"};
961 | [L["Chromatic Infusion"]] = {amount = 190, mod = 0, icon = "Interface\\Icons\\Spell_Holy_MindVision"};
962 | [L["Ascendance"]] = {amount = 75, mod = 0, icon = "Interface\\Icons\\Spell_Lightning_LightningBolt01"};
963 | [L["Ephemeral Power"]] = {amount = 175, mod = 0, icon = "Interface\\Icons\\Spell_Holy_MindVision"};
964 | [L["Unstable Power"]] = {amount = 34, mod = 0, icon = "Interface\\Icons\\Spell_Lightning_LightningBolt01"};
965 | [L["Healing of the Ages"]] = {amount = 350, mod = 0, icon = "Interface\\Icons\\Spell_Nature_HealingWaveGreater"};
966 | [L["Essence of Sapphiron"]] = {amount = 130, mod = 0, icon = "Interface\\Icons\\Inv_Trinket_Naxxramas06"};
967 | [L["The Eye of the Dead"]] = {amount = 450, mod = 0, icon = "Interface\\Icons\\Inv_Trinket_Naxxramas01"}
968 | }
969 |
970 | HealComm.Debuffs = {
971 | [L["Mortal Strike"]] = {amount = 0, mod = 0.5, icon = "Interface\\Icons\\Ability_Warrior_SavageBlow"};
972 | [L["Wound Poison"]] = {amount = -135, mod = 0, icon = "Interface\\Icons\\Inv_Misc_Herb_16"};
973 | [L["Curse of the Deadwood"]] = {amount = 0, mod = 0.5, icon = "Interface\\Icons\\Spell_Shadow_GatherShadows"};
974 | [L["Veil of Shadow"]] = {amount = 0, mod = 0.75, icon = "Interface\\Icons\\Spell_Shadow_GatherShadows"};
975 | [L["Gehennas' Curse"]] = {amount = 0, mod = 0.75, icon = "Interface\\Icons\\Spell_Shadow_GatherShadows"};
976 | [L["Mortal Wound"]] = {amount = 0, mod = 0.1, icon = "Interface\\Icons\\Ability_CriticalStrike"};
977 | [L["Necrotic Poison"]] = {amount = 0, mod = 0.9, icon = "Interface\\Icons\\Ability_Creature_Poison_03"};
978 | [L["Blood Fury"]] = {amount = 0, mod = 0.5, icon = "Interface\\Icons\\Ability_Rogue_FeignDeath"};
979 | [L["Necrotic Aura"]] = {amount = 0, mod = 1, icon = "Interface\\Icons\\Ability_Creature_Disease_05"}
980 | }
981 |
982 | local function getSetBonus()
983 | healcommTip:SetInventoryItem("player", 1)
984 | local text = getglobal("healcommTipTextLeft"..healcommTip:NumLines()):GetText()
985 | if text == L["Set: Increases the duration of your Rejuvenation spell by 3 sec."] or text == L["Set: Increases the duration of your Renew spell by 3 sec."] then
986 | return true
987 | else
988 | return nil
989 | end
990 | end
991 |
992 | function HealComm:GetBuffSpellPower()
993 | local Spellpower = 0
994 | local healmod = 1
995 | for i=1, 16 do
996 | local buffTexture, buffApplications = UnitBuff("player", i)
997 | if not buffTexture then
998 | return Spellpower, healmod
999 | end
1000 | healcommTip:SetUnitBuff("player", i)
1001 | local buffName = healcommTipTextLeft1:GetText()
1002 | if self.Buffs[buffName] and self.Buffs[buffName].icon == buffTexture then
1003 | Spellpower = (self.Buffs[buffName].amount * buffApplications) + Spellpower
1004 | healmod = (self.Buffs[buffName].mod * buffApplications) + healmod
1005 | end
1006 | end
1007 | return Spellpower, healmod
1008 | end
1009 |
1010 | function HealComm:GetTargetSpellPower(spell)
1011 | local targetpower = 0
1012 | local targetmod = 1
1013 | local buffTexture, buffApplications
1014 | local debuffTexture, debuffApplications
1015 | for i=1, 16 do
1016 | if UnitIsVisible("target") and UnitIsConnected("target") and UnitReaction("target", "player") > 4 then
1017 | buffTexture, buffApplications = UnitBuff("target", i)
1018 | healcommTip:SetUnitBuff("target", i)
1019 | else
1020 | buffTexture, buffApplications = UnitBuff("player", i)
1021 | healcommTip:SetUnitBuff("player", i)
1022 | end
1023 | if not buffTexture then
1024 | break
1025 | end
1026 | local buffName = healcommTipTextLeft1:GetText()
1027 | if buffName == L["Blessing of Light"] then
1028 | local HLBonus, FoLBonus = strmatch(healcommTipTextLeft2:GetText(),"(%d+).-(%d+)")
1029 | if (spell == L["Flash of Light"]) then
1030 | targetpower = FoLBonus + targetpower
1031 | elseif spell == L["Holy Light"] then
1032 | targetpower = HLBonus + targetpower
1033 | end
1034 | end
1035 | if buffName == L["Healing Way"] and spell == L["Healing Wave"] then
1036 | targetmod = targetmod * ((buffApplications * 0.06) + 1)
1037 | end
1038 | end
1039 | for i=1, 16 do
1040 | if UnitIsVisible("target") and UnitIsConnected("target") and UnitReaction("target", "player") > 4 then
1041 | debuffTexture, debuffApplications = UnitDebuff("target", i)
1042 | healcommTip:SetUnitDebuff("target", i)
1043 | else
1044 | debuffTexture, debuffApplications = UnitDebuff("player", i)
1045 | healcommTip:SetUnitDebuff("player", i)
1046 | end
1047 | if not debuffTexture then
1048 | break
1049 | end
1050 | local debuffName = healcommTipTextLeft1:GetText()
1051 | if self.Debuffs[debuffName] then
1052 | targetpower = (self.Debuffs[debuffName].amount * debuffApplications) + targetpower
1053 | targetmod = (1-(self.Debuffs[debuffName].mod * debuffApplications)) * targetmod
1054 | end
1055 | end
1056 | return targetpower, targetmod
1057 | end
1058 |
1059 | function HealComm:UNIT_HEALTH()
1060 | local name = UnitName(arg1)
1061 | if self.pendingResurrections[name] then
1062 | for k,v in pairs(self.pendingResurrections[name]) do
1063 | self.pendingResurrections[name][k] = nil
1064 | end
1065 | self:TriggerEvent("HealComm_Ressupdate", name)
1066 | end
1067 | end
1068 |
1069 | function HealComm:stopHeal(caster)
1070 | if self:IsEventScheduled("Healcomm_"..caster) then
1071 | self:CancelScheduledEvent("Healcomm_"..caster)
1072 | end
1073 | if self.Lookup[caster] then
1074 | self.Heals[self.Lookup[caster]][caster] = nil
1075 | self:TriggerEvent("HealComm_Healupdate", self.Lookup[caster])
1076 | self.Lookup[caster] = nil
1077 | end
1078 | end
1079 |
1080 | function HealComm:startHeal(caster, target, size, casttime)
1081 |
1082 | -- HCSpy
1083 | --console:Print(caster)
1084 |
1085 |
1086 |
1087 |
1088 |
1089 | self:ScheduleEvent("Healcomm_"..caster, self.stopHeal, (casttime/1000), self, caster)
1090 | if not self.Heals[target] then
1091 | self.Heals[target] = {}
1092 | end
1093 | if self.Lookup[caster] then
1094 | self.Heals[self.Lookup[caster]][caster] = nil
1095 | self.Lookup[caster] = nil
1096 | end
1097 | self.Heals[target][caster] = {amount = size, ctime = (casttime/1000)+GetTime()}
1098 | self.Lookup[caster] = target
1099 | self:TriggerEvent("HealComm_Healupdate", target)
1100 | end
1101 |
1102 | function HealComm:delayHeal(caster, delay)
1103 | self:CancelScheduledEvent("Healcomm_"..caster)
1104 | if self.Lookup[caster] and self.Heals[self.Lookup[caster]] then
1105 | self.Heals[self.Lookup[caster]][caster].ctime = self.Heals[self.Lookup[caster]][caster].ctime + (delay/1000)
1106 | self:ScheduleEvent("Healcomm_"..caster, self.stopHeal, (self.Heals[self.Lookup[caster]][caster].ctime-GetTime()), self, caster)
1107 | end
1108 | end
1109 |
1110 | function HealComm:startGrpHeal(caster, size, casttime, party1, party2, party3, party4, party5)
1111 | self:ScheduleEvent("Healcomm_"..caster, self.stopGrpHeal, (casttime/1000), self, caster)
1112 | self.GrpHeals[caster] = {amount = size, ctime = (casttime/1000)+GetTime(), targets = {party1, party2, party3, party4, party5}}
1113 | for i=1,getn(self.GrpHeals[caster].targets) do
1114 | self:TriggerEvent("HealComm_Healupdate", self.GrpHeals[caster].targets[i])
1115 | end
1116 | end
1117 |
1118 | function HealComm:stopGrpHeal(caster)
1119 | if self:IsEventScheduled("Healcomm_"..caster) then
1120 | self:CancelScheduledEvent("Healcomm_"..caster)
1121 | end
1122 | local targets
1123 | if self.GrpHeals[caster] then
1124 | targets = self.GrpHeals[caster].targets
1125 | end
1126 | self.GrpHeals[caster] = nil
1127 | if targets then
1128 | for i=1,getn(targets) do
1129 | self:TriggerEvent("HealComm_Healupdate", targets[i])
1130 | end
1131 | end
1132 | end
1133 |
1134 | function HealComm:delayGrpHeal(caster, delay)
1135 | self:CancelScheduledEvent("Healcomm_"..caster)
1136 | if self.GrpHeals[caster] then
1137 | self.GrpHeals[caster].ctime = self.GrpHeals[caster].ctime + (delay/1000)
1138 | self:ScheduleEvent("Healcomm_"..caster, self.stopGrpHeal, (self.GrpHeals[caster].ctime-GetTime()), self, caster)
1139 | end
1140 | end
1141 |
1142 | function HealComm:startResurrection(caster, target)
1143 | if not self.pendingResurrections[target] then
1144 | self.pendingResurrections[target] = {}
1145 | end
1146 | self.pendingResurrections[target][caster] = GetTime()+70
1147 | self:ScheduleEvent("Healcomm_"..caster..target, self.RessExpire, 70, self, caster, target)
1148 | self:TriggerEvent("HealComm_Ressupdate", target)
1149 | end
1150 |
1151 | function HealComm:cancelResurrection(caster)
1152 | for k,v in pairs(self.pendingResurrections) do
1153 | if v[caster] and (v[caster]-GetTime()) > 60 then
1154 | self.pendingResurrections[k][caster] = nil
1155 | self:TriggerEvent("HealComm_Ressupdate", k)
1156 | end
1157 | end
1158 | end
1159 |
1160 | function HealComm:RessExpire(caster, target)
1161 | self.pendingResurrections[target][caster] = nil
1162 | self:TriggerEvent("HealComm_Ressupdate", target)
1163 | end
1164 |
1165 | function HealComm:SendAddonMessage(msg)
1166 | local zone = GetRealZoneText()
1167 | if zone == L["Warsong Gulch"] or zone == L["Arathi Basin"] or zone == L["Alterac Valley"] then
1168 | SendAddonMessage("HealComm", msg, "BATTLEGROUND")
1169 | else
1170 | SendAddonMessage("HealComm", msg, "RAID")
1171 | end
1172 | end
1173 |
1174 | function HealComm:SPELLCAST_START()
1175 |
1176 | if ( self.SpellCastInfo and self.SpellCastInfo[1] == arg1 and self.Spells[arg1] ) then
1177 | local Bonus = 0
1178 | if BonusScanner then
1179 | Bonus = tonumber(BonusScanner:GetBonus("HEAL"))
1180 | end
1181 | local buffpower, buffmod = self:GetBuffSpellPower()
1182 | local targetpower, targetmod = self.SpellCastInfo[4], self.SpellCastInfo[5]
1183 | local Bonus = Bonus + buffpower
1184 | local amount = ((math.floor(self.Spells[self.SpellCastInfo[1]][tonumber(self.SpellCastInfo[2])](Bonus))+targetpower)*buffmod*targetmod)
1185 | if arg1 == L["Prayer of Healing"] then
1186 | local targets = {UnitName("player")}
1187 | local targetsstring = UnitName("player").."/"
1188 | for i=1,4 do
1189 | if CheckInteractDistance("party"..i, 4) then
1190 | table.insert(targets, i ,UnitName("party"..i))
1191 | targetsstring = targetsstring..UnitName("party"..i).."/"
1192 | end
1193 | end
1194 | self:SendAddonMessage("GrpHeal/"..amount.."/"..arg2.."/"..targetsstring)
1195 | self:startGrpHeal(UnitName("player"), amount, arg2, targets[1], targets[2], targets[3], targets[4], targets[5])
1196 | else
1197 | self:SendAddonMessage("Heal/"..self.SpellCastInfo[3].."/"..amount.."/"..arg2.."/")
1198 | self:startHeal(UnitName("player"), self.SpellCastInfo[3], amount, arg2)
1199 | end
1200 | elseif ( self.SpellCastInfo and self.SpellCastInfo[1] == arg1 and Resurrections[arg1] ) then
1201 | self:SendAddonMessage("Resurrection/"..self.SpellCastInfo[3].."/start/")
1202 | self:startResurrection(UnitName("player"), self.SpellCastInfo[3])
1203 | end
1204 | self.spellIsCasting = arg1
1205 | end
1206 |
1207 | function HealComm:SPELLCAST_FAILED()
1208 |
1209 | if self:IsEventScheduled("TriggerRegrowthHot") then
1210 | self:CancelScheduledEvent("TriggerRegrowthHot")
1211 | end
1212 |
1213 | if self.Spells[self.spellIsCasting] then
1214 | if self.spellIsCasting == L["Prayer of Healing"] then
1215 | self:SendAddonMessage("GrpHealstop")
1216 | self:stopGrpHeal(UnitName("player"))
1217 | else
1218 | self:SendAddonMessage("Healstop")
1219 | self:stopHeal(UnitName("player"))
1220 | end
1221 | elseif Resurrections[self.spellIsCasting] then
1222 | self:SendAddonMessage("Resurrection/stop/")
1223 | self:cancelResurrection(UnitName("player"))
1224 | end
1225 | self.CurrentSpellRank = nil
1226 | self.CurrentSpellName = nil
1227 | self.spellIsCasting = nil
1228 | for key in pairs(self.SpellCastInfo) do
1229 | self.SpellCastInfo[key] = nil
1230 | end
1231 | end
1232 |
1233 | function HealComm:SPELLCAST_DELAYED()
1234 | if self.spellIsCasting == L["Prayer of Healing"] then
1235 | self:SendAddonMessage("GrpHealdelay/"..arg1.."/")
1236 | self:delayGrpHeal(UnitName("player"), arg1)
1237 | else
1238 | self:SendAddonMessage("Healdelay/"..arg1.."/")
1239 | self:delayHeal(UnitName("player"), arg1)
1240 | end
1241 | end
1242 |
1243 | function HealComm:TriggerRegrowthHot()
1244 | local dur = 21
1245 | self:SendAddonMessage("Regr/"..self.savetarget.."/"..dur.."/")
1246 | if not self.Hots[self.savetarget] then
1247 | self.Hots[self.savetarget] = {}
1248 | end
1249 | if not self.Hots[self.savetarget]["Regr"] then
1250 | self.Hots[self.savetarget]["Regr"]= {}
1251 | end
1252 | self.Hots[self.savetarget]["Regr"].start = GetTime()
1253 | self.Hots[self.savetarget]["Regr"].dur = dur
1254 | self:TriggerEvent("HealComm_Hotupdate", roster:GetUnitIDFromName(self.savetarget), "Regrowth")
1255 | end
1256 |
1257 | function HealComm:SPELLCAST_STOP()
1258 | if not self.SpellCastInfo then return end
1259 | local targetUnit = roster:GetUnitIDFromName(self.SpellCastInfo[3])
1260 | if targetUnit then
1261 | if self.SpellCastInfo[1] == L["Renew"] then
1262 | local dur = getSetBonus() and 18 or 15
1263 | self:SendAddonMessage("Renew/"..self.SpellCastInfo[3].."/"..dur.."/")
1264 | if not self.Hots[self.SpellCastInfo[3]] then
1265 | self.Hots[self.SpellCastInfo[3]] = {}
1266 | end
1267 | if not self.Hots[self.SpellCastInfo[3]]["Renew"] then
1268 | self.Hots[self.SpellCastInfo[3]]["Renew"]= {}
1269 | end
1270 | self.Hots[self.SpellCastInfo[3]]["Renew"].start = GetTime()
1271 | self.Hots[self.SpellCastInfo[3]]["Renew"].dur = dur
1272 | self:TriggerEvent("HealComm_Hotupdate", targetUnit, "Renew")
1273 | elseif self.SpellCastInfo[1] == L["Rejuvenation"] then
1274 | local dur = getSetBonus() and 15 or 12
1275 | self:SendAddonMessage("Reju/"..self.SpellCastInfo[3].."/"..dur.."/")
1276 | if not self.Hots[self.SpellCastInfo[3]] then
1277 | self.Hots[self.SpellCastInfo[3]] = {}
1278 | end
1279 | if not self.Hots[self.SpellCastInfo[3]]["Reju"] then
1280 | self.Hots[self.SpellCastInfo[3]]["Reju"]= {}
1281 | end
1282 | self.Hots[self.SpellCastInfo[3]]["Reju"].start = GetTime()
1283 | self.Hots[self.SpellCastInfo[3]]["Reju"].dur = dur
1284 | self:TriggerEvent("HealComm_Hotupdate", targetUnit, "Rejuvenation")
1285 | elseif self.SpellCastInfo[1] == L["Regrowth"] then
1286 | self.savetarget = self.SpellCastInfo[3]
1287 | self:ScheduleEvent("TriggerRegrowthHot", self.TriggerRegrowthHot, 0.3, self)
1288 | end
1289 | end
1290 | self.CurrentSpellRank = nil
1291 | self.CurrentSpellName = nil
1292 | for key in pairs(self.SpellCastInfo) do
1293 | self.SpellCastInfo[key] = nil
1294 | end
1295 | end
1296 |
1297 | function HealComm:CHAT_MSG_ADDON()
1298 | if arg1 == "HealComm" and arg4 ~= UnitName("player") then
1299 | local result = strsplit(arg2,"/")
1300 | --console:Print("HealComm user has Startet casting: "..UnitName("player")) --HCSpy
1301 | if result[1] == "Heal" then
1302 | self:startHeal(arg4, result[2], result[3], result[4])
1303 | elseif arg2 == "Healstop" then
1304 | self:stopHeal(arg4)
1305 | elseif result[1] == "Healdelay" then
1306 | self:delayHeal(arg4, result[2])
1307 | elseif result[1] == "Resurrection" and result[2] == "stop" then
1308 | self:cancelResurrection(arg4)
1309 | elseif result[1] == "Resurrection" and result[3] == "start" then
1310 | self:startResurrection(arg4, result[2])
1311 | elseif result[1] == "GrpHeal" then
1312 | self:startGrpHeal(arg4, result[2], result[3], result[4], result[5], result[6], result[7], result[8])
1313 | elseif arg2 == "GrpHealstop" then
1314 | self:stopGrpHeal(arg4)
1315 | elseif result[1] == "GrpHealdelay" then
1316 | self:delayGrpHeal(arg4, result[2])
1317 | elseif result[1] == "Renew" then
1318 | if not self.Hots[result[2]] then
1319 | self.Hots[result[2]] = {}
1320 | end
1321 | if not self.Hots[result[2]]["Renew"] then
1322 | self.Hots[result[2]]["Renew"]= {}
1323 | end
1324 | self.Hots[result[2]]["Renew"].dur = result[3]
1325 | self.Hots[result[2]]["Renew"].start = GetTime()
1326 | local targetUnit = roster:GetUnitIDFromName(result[2])
1327 | self:TriggerEvent("HealComm_Hotupdate", targetUnit, "Renew")
1328 | elseif result[1] == "Reju" then
1329 | if not self.Hots[result[2]] then
1330 | self.Hots[result[2]] = {}
1331 | end
1332 | if not self.Hots[result[2]]["Reju"] then
1333 | self.Hots[result[2]]["Reju"]= {}
1334 | end
1335 | self.Hots[result[2]]["Reju"].dur = result[3]
1336 | self.Hots[result[2]]["Reju"].start = GetTime()
1337 | local targetUnit = roster:GetUnitIDFromName(result[2])
1338 | self:TriggerEvent("HealComm_Hotupdate", targetUnit, "Rejuvenation")
1339 | elseif result[1] == "Regr" then
1340 | if not self.Hots[result[2]] then
1341 | self.Hots[result[2]] = {}
1342 | end
1343 | if not self.Hots[result[2]]["Regr"] then
1344 | self.Hots[result[2]]["Regr"]= {}
1345 | end
1346 | self.Hots[result[2]]["Regr"].dur = result[3]
1347 | self.Hots[result[2]]["Regr"].start = GetTime()
1348 | local targetUnit = roster:GetUnitIDFromName(result[2])
1349 | self:TriggerEvent("HealComm_Hotupdate", targetUnit, "Regrowth")
1350 | end
1351 | end
1352 | end
1353 |
1354 | function HealComm:UNIT_AURA()
1355 | local name = UnitName(arg1)
1356 | if self.Hots[name] and (self.Hots[name]["Regr"] or self.Hots[name]["Reju"] or self.Hots[name]["Renew"]) then
1357 | local regr,reju,renew
1358 | for i=1,32 do
1359 | if not UnitBuff(arg1,i) then
1360 | break
1361 | end
1362 | healcommTip:ClearLines()
1363 | healcommTip:SetUnitBuff(arg1,i)
1364 | regr = regr or healcommTipTextLeft1:GetText() == L["Regrowth"]
1365 | reju = reju or healcommTipTextLeft1:GetText() == L["Rejuvenation"]
1366 | renew = renew or healcommTipTextLeft1:GetText() == L["Renew"]
1367 | end
1368 | if not regr then
1369 | self.Hots[name]["Regr"] = nil
1370 | self:TriggerEvent("HealComm_Hotupdate", arg1, "Regrowth")
1371 | end
1372 | if not reju then
1373 | self.Hots[name]["Reju"] = nil
1374 | self:TriggerEvent("HealComm_Hotupdate", arg1, "Rejuvenation")
1375 | end
1376 | if not renew then
1377 | self.Hots[name]["Renew"] = nil
1378 | self:TriggerEvent("HealComm_Hotupdate", arg1, "Renew")
1379 | end
1380 | end
1381 | end
1382 |
1383 | function HealComm:getRegrTime(unit)
1384 | if unit == UNKNOWNOBJECT or unit == UKNOWNBEING then
1385 | return
1386 | end
1387 | local dbUnit = self.Hots[UnitName(unit)]
1388 | if dbUnit and dbUnit["Regr"] and (dbUnit["Regr"].start + dbUnit["Regr"].dur) > GetTime() then
1389 | return dbUnit["Regr"].start, dbUnit["Regr"].dur
1390 | else
1391 | return
1392 | end
1393 | end
1394 |
1395 | function HealComm:getRejuTime(unit)
1396 | if unit == UNKNOWNOBJECT or unit == UKNOWNBEING then
1397 | return
1398 | end
1399 | local dbUnit = self.Hots[UnitName(unit)]
1400 | if dbUnit and dbUnit["Reju"] and (dbUnit["Reju"].start + dbUnit["Reju"].dur) > GetTime() then
1401 | return dbUnit["Reju"].start, dbUnit["Reju"].dur
1402 | else
1403 | return
1404 | end
1405 | end
1406 |
1407 | function HealComm:getRenewTime(unit)
1408 | if unit == UNKNOWNOBJECT or unit == UKNOWNBEING then
1409 | return
1410 | end
1411 | local dbUnit = self.Hots[UnitName(unit)]
1412 | if dbUnit and dbUnit["Renew"] and (dbUnit["Renew"].start + dbUnit["Renew"].dur) > GetTime() then
1413 | return dbUnit["Renew"].start, dbUnit["Renew"].dur
1414 | else
1415 | return
1416 | end
1417 | end
1418 |
1419 | function HealComm:getHeal(unit)
1420 | if unit == UNKNOWNOBJECT or unit == UKNOWNBEING then
1421 | return 0
1422 | end
1423 | local healamount = 0
1424 | if self.Heals[unit] then
1425 | for k,v in self.Heals[unit] do
1426 | healamount = healamount+v.amount
1427 | end
1428 | end
1429 | for k,v in pairs(self.GrpHeals) do
1430 | for j,c in pairs(v.targets) do
1431 | if unit == c then
1432 | healamount = healamount+v.amount
1433 | end
1434 | end
1435 | end
1436 | return healamount
1437 | end
1438 |
1439 | function HealComm:UnitisResurrecting(unit)
1440 | local resstime
1441 | if self.pendingResurrections[unit] then
1442 | for k,v in pairs(self.pendingResurrections[unit]) do
1443 | if v < GetTime() then
1444 | self.pendingResurrections[unit][k] = nil
1445 | elseif not resstime or resstime > v then
1446 | resstime = v
1447 | end
1448 | end
1449 | end
1450 | return resstime
1451 | end
1452 |
1453 | function HealComm:getNumHeals(unit)
1454 | if unit == UNKNOWNOBJECT or unit == UKNOWNBEING then
1455 | return 0
1456 | end
1457 | local heals = 0
1458 | if self.Heals[unit] then
1459 | for _ in self.Heals[unit] do
1460 | heals = heals + 1
1461 | end
1462 | end
1463 | for _,v in pairs(self.GrpHeals) do
1464 | for _,c in pairs(v.targets) do
1465 | if unit == c then
1466 | heals = heals + 1
1467 | end
1468 | end
1469 | end
1470 | return heals
1471 | end
1472 |
1473 |
1474 | function HealComm:CastSpell(spellId, spellbookTabNum)
1475 | self.hooks.CastSpell(spellId, spellbookTabNum)
1476 | local spellName, rank = GetSpellName(spellId, spellbookTabNum)
1477 | _,_,rank = string.find(rank,"(%d+)")
1478 | if ( SpellIsTargeting() ) then
1479 | -- Spell is waiting for a target
1480 | self.CurrentSpellName = spellName
1481 | self.CurrentSpellRank = rank
1482 | elseif ( UnitIsVisible("target") and UnitIsConnected("target") and UnitCanAssist("player", "target") ) then
1483 | -- Spell is being cast on the current target.
1484 | -- If ClearTarget() had been called, we'd be waiting target
1485 | if UnitIsPlayer("target") then
1486 | self:ProcessSpellCast(spellName, rank, UnitName("target"))
1487 | end
1488 | else
1489 | self:ProcessSpellCast(spellName, rank, UnitName("player"))
1490 | end
1491 | end
1492 |
1493 | function HealComm:CastSpellByName(spellName, onSelf)
1494 | self.hooks.CastSpellByName(spellName, onSelf)
1495 | local _,_,rank = string.find(spellName,"(%d+)")
1496 | local _, _, spellName = string.find(spellName, "^([^%(]+)")
1497 | if not rank then
1498 | local i = 1
1499 | while GetSpellName(i, BOOKTYPE_SPELL) do
1500 | local s, r = GetSpellName(i, BOOKTYPE_SPELL)
1501 | if s == spellName then
1502 | rank = r
1503 | end
1504 | i = i+1
1505 | end
1506 | if rank then
1507 | _,_,rank = string.find(rank,"(%d+)")
1508 | end
1509 | end
1510 | if ( spellName ) then
1511 | if ( SpellIsTargeting() ) then
1512 | self.CurrentSpellName = spellName
1513 | self.CurrentSpellRank = rank
1514 | else
1515 | if UnitIsVisible("target") and UnitIsConnected("target") and UnitCanAssist("player", "target") and onSelf ~= 1 then
1516 | if UnitIsPlayer("target") then
1517 | self:ProcessSpellCast(spellName, rank, UnitName("target"))
1518 | end
1519 | else
1520 | self:ProcessSpellCast(spellName, rank, UnitName("player"))
1521 | end
1522 | end
1523 | end
1524 | end
1525 |
1526 | function HealComm:OnMouseDown(object)
1527 | -- If we're waiting to target
1528 | local targetName
1529 |
1530 | if ( self.CurrentSpellName and UnitExists("mouseover") ) then
1531 | targetName = UnitName("mouseover")
1532 | elseif ( self.CurrentSpellName and GameTooltipTextLeft1:IsVisible() ) then
1533 | local _, _, name = string.find(GameTooltipTextLeft1:GetText(), L["^Corpse of (.+)$"])
1534 | if ( name ) then
1535 | targetName = name
1536 | end
1537 | end
1538 | if ( self.hooks[object]["OnMouseDown"] ) then
1539 | self.hooks[object]["OnMouseDown"]()
1540 | end
1541 | if ( self.CurrentSpellName and targetName ) then
1542 | self:ProcessSpellCast(self.CurrentSpellName, self.CurrentSpellRank, targetName)
1543 | end
1544 | end
1545 |
1546 | function HealComm:UseAction(slot, checkCursor, onSelf)
1547 | healcommTip:ClearLines()
1548 | healcommTip:SetAction(slot)
1549 | local spellName = healcommTipTextLeft1:GetText()
1550 |
1551 | -- Test to see if this is a macro
1552 | if not GetActionText(slot) then
1553 | self.CurrentSpellName = spellName
1554 | end
1555 |
1556 | self.hooks.UseAction(slot, checkCursor, onSelf)
1557 |
1558 | -- Test to see if this is a macro
1559 | if ( not self.CurrentSpellName ) then
1560 | return
1561 | end
1562 | local rank = healcommTipTextRight1:GetText()
1563 | if rank then
1564 | _,_,rank = string.find(rank,"(%d+)")
1565 | end
1566 | if not rank then
1567 | rank = 1
1568 | end
1569 | self.CurrentSpellRank = rank
1570 | if ( SpellIsTargeting() ) then
1571 | -- Spell is waiting for a target
1572 | return
1573 | elseif ( UnitIsVisible("target") and UnitIsConnected("target") and UnitCanAssist("player", "target") and onSelf ~= 1) then
1574 | -- Spell is being cast on the current target
1575 | if UnitIsPlayer("target") then
1576 | self:ProcessSpellCast(spellName, rank, UnitName("target"))
1577 | end
1578 | else
1579 | -- Spell is being cast on the player
1580 | self:ProcessSpellCast(spellName, rank, UnitName("player"))
1581 | end
1582 | end
1583 |
1584 | function HealComm:SpellTargetUnit(unit)
1585 | local shallTargetUnit
1586 | if ( SpellIsTargeting() ) then
1587 | shallTargetUnit = true
1588 | end
1589 | self.hooks.SpellTargetUnit(unit)
1590 | if ( shallTargetUnit and self.CurrentSpellName and not SpellIsTargeting() ) then
1591 | if UnitIsPlayer(unit) then
1592 | self:ProcessSpellCast(self.CurrentSpellName, self.CurrentSpellRank, UnitName(unit))
1593 | end
1594 | self.CurrentSpellName = nil
1595 | self.CurrentSpellRank = nil
1596 | end
1597 | end
1598 |
1599 | function HealComm:SpellStopTargeting()
1600 | self.hooks.SpellStopTargeting()
1601 | self.CurrentSpellName = nil
1602 | self.CurrentSpellRank = nil
1603 | end
1604 |
1605 | function HealComm:TargetUnit(unit)
1606 | -- Look to see if we're currently waiting for a target internally
1607 | -- If we are, then well glean the target info here.
1608 | if ( self.CurrentSpellName and UnitExists(unit) ) and UnitIsPlayer(unit) then
1609 | self:ProcessSpellCast(self.CurrentSpellName, self.CurrentSpellRank, UnitName(unit))
1610 | end
1611 | self.hooks.TargetUnit(unit)
1612 | end
1613 |
1614 | function HealComm:ProcessSpellCast(spellName, rank, targetName)
1615 | local power, mod = self:GetTargetSpellPower(spellName)
1616 | self.SpellCastInfo[1] = self.SpellCastInfo[1] or spellName
1617 | self.SpellCastInfo[2] = self.SpellCastInfo[2] or rank
1618 | self.SpellCastInfo[3] = self.SpellCastInfo[3] or targetName
1619 | self.SpellCastInfo[4] = power
1620 | self.SpellCastInfo[5] = mod
1621 | end
1622 |
1623 | AceLibrary:Register(HealComm, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
1624 | HealComm = nil
--------------------------------------------------------------------------------
/libs/RosterLib-2.0/RosterLib-2.0.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | Name: RosterLib-2.0
3 | Revision: $Revision: 16213 $
4 | X-ReleaseDate: $Date: 2006-08-10 08:55:29 +0200 (Thu, 10 Aug 2006) $
5 | Author: Maia (maia.proudmoore@gmail.com)
6 | Website: http://wiki.wowace.com/index.php/RosterLib-2.0
7 | Documentation: http://wiki.wowace.com/index.php/RosterLib-2.0_API_Documentation
8 | SVN: http://svn.wowace.com/root/trunk/RosterLib-2.0/
9 | Description: party/raid roster management
10 | Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0
11 | ]]
12 |
13 | local MAJOR_VERSION = "RosterLib-2.0"
14 | local MINOR_VERSION = "$Revision: 16213 $"
15 |
16 | if not AceLibrary then error(vmajor .. " requires AceLibrary.") end
17 | if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
18 | if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
19 | if not AceLibrary:HasInstance("AceEvent-2.0") then error(MAJOR_VERSION .. " requires AceEvent-2.0") end
20 |
21 | local updatedUnits = {}
22 | local unknownUnits = {}
23 | local RosterLib = {}
24 | local roster
25 |
26 | ------------------------------------------------
27 | -- activate, enable, disable
28 | ------------------------------------------------
29 |
30 | local function print(text)
31 | ChatFrame3:AddMessage(text)
32 | end
33 |
34 | local function activate(self, oldLib, oldDeactivate)
35 | RosterLib = self
36 | if oldLib then
37 | self.roster = oldLib.roster
38 | oldLib:UnregisterAllEvents()
39 | oldLib:CancelAllScheduledEvents()
40 | end
41 | if not self.roster then self.roster = {} end
42 | if oldDeactivate then oldDeactivate(oldLib) end
43 | roster = self.roster
44 | end
45 |
46 |
47 | local function external(self, major, instance)
48 | if major == "AceEvent-2.0" then
49 | AceEvent = instance
50 | AceEvent:embed(self)
51 | self:UnregisterAllEvents()
52 | self:CancelAllScheduledEvents()
53 | if AceEvent:IsFullyInitialized() then
54 | self:AceEvent_FullyInitialized()
55 | else
56 | self:RegisterEvent("AceEvent_FullyInitialized", "AceEvent_FullyInitialized", true)
57 | end
58 | elseif major == "Compost-2.0" then
59 | Compost = instance
60 | end
61 | end
62 |
63 |
64 | function RosterLib:Enable()
65 | -- not used anymore, but as addons still might be calling this method, we're keeping it.
66 | end
67 |
68 |
69 | function RosterLib:Disable()
70 | -- not used anymore, but as addons still might be calling this method, we're keeping it.
71 | end
72 |
73 | ------------------------------------------------
74 | -- Internal functions
75 | ------------------------------------------------
76 |
77 | function RosterLib:AceEvent_FullyInitialized()
78 | self:TriggerEvent("RosterLib_Enabled")
79 | self:RegisterEvent("RAID_ROSTER_UPDATE","ScanFullRoster")
80 | self:RegisterEvent("PARTY_MEMBERS_CHANGED","ScanFullRoster")
81 | self:RegisterEvent("UNIT_PET","ScanPet")
82 | self:ScanFullRoster()
83 | end
84 |
85 |
86 | ------------------------------------------------
87 | -- Unit iterator
88 | ------------------------------------------------
89 |
90 | local playersent, petsent, unitcount, petcount, pmem, rmem, unit
91 |
92 | local function NextUnit()
93 | -- STEP 1: pet
94 | if not petsent then
95 | petsent = true
96 | if rmem == 0 then
97 | unit = "pet"
98 | if UnitExists(unit) then return unit end
99 | end
100 | end
101 | -- STEP 2: player
102 | if not playersent then
103 | playersent = true
104 | if rmem == 0 then
105 | unit = "player"
106 | if UnitExists(unit) then return unit end
107 | end
108 | end
109 | -- STEP 3: raid units
110 | if rmem > 0 then
111 | -- STEP 3a: pet units
112 | for i = petcount, rmem do
113 | unit = string.format("raidpet%d", i)
114 | petcount = petcount + 1
115 | if UnitExists(unit) then return unit end
116 | end
117 | -- STEP 3b: player units
118 | for i = unitcount, rmem do
119 | unit = string.format("raid%d", i)
120 | unitcount = unitcount + 1
121 | if UnitExists(unit) then return unit end
122 | end
123 | -- STEP 4: party units
124 | elseif pmem > 0 then
125 | -- STEP 3a: pet units
126 | for i = petcount, pmem do
127 | unit = string.format("partypet%d", i)
128 | petcount = petcount + 1
129 | if UnitExists(unit) then return unit end
130 | end
131 | -- STEP 3b: player units
132 | for i = unitcount, pmem do
133 | unit = string.format("party%d", i)
134 | unitcount = unitcount + 1
135 | if UnitExists(unit) then return unit end
136 | end
137 | end
138 | end
139 |
140 | local function UnitIterator()
141 | playersent, petsent, unitcount, petcount, pmem, rmem = false, false, 1, 1, GetNumPartyMembers(), GetNumRaidMembers()
142 | return NextUnit
143 | end
144 |
145 | ------------------------------------------------
146 | -- Roster code
147 | ------------------------------------------------
148 |
149 |
150 | function RosterLib:ScanFullRoster()
151 | -- save all units we currently have, this way we can check who to remove from roster later.
152 | local temp = Compost and Compost:Acquire() or {}
153 | for name in pairs(roster) do
154 | temp[name] = true
155 | end
156 | -- update data
157 | for unitid in UnitIterator() do
158 | local name = self:CreateOrUpdateUnit(unitid)
159 | -- we successfully added a unit, so we don't need to remove it next step
160 | if name then temp[name] = nil end
161 | end
162 | -- clear units we had in roster that either left the raid or are unknown for some reason.
163 | for name in pairs(temp) do
164 | self:RemoveUnit(name)
165 | end
166 | if Compost then Compost:Reclaim(temp) end
167 | self:ProcessRoster()
168 | end
169 |
170 |
171 | function RosterLib:ScanPet(owner)
172 | local unitid = self:GetPetFromOwner(owner)
173 | if not unitid then
174 | return
175 | elseif not UnitExists(unitid) then
176 | unknownUnits[unitid] = nil
177 | -- find the pet in the roster we need to delete
178 | for _,u in pairs(roster) do
179 | if u.unitid == unitid then
180 | self:RemoveUnit(u.name)
181 | end
182 | end
183 | else
184 | self:CreateOrUpdateUnit(unitid)
185 | end
186 | self:ProcessRoster()
187 | end
188 |
189 |
190 | function RosterLib:GetPetFromOwner(id)
191 | -- convert party3 crap to raid IDs when in raid.
192 | local owner = self:GetUnitIDFromUnit(id)
193 | if not owner then
194 | return
195 | end
196 | -- get ID
197 | if string.find(owner,"raid") then
198 | return string.gsub(owner, "raid", "raidpet")
199 | elseif string.find(owner,"party") then
200 | return string.gsub(owner, "party", "partypet")
201 | elseif owner == "player" then
202 | return "pet"
203 | else
204 | return nil
205 | end
206 | end
207 |
208 |
209 | function RosterLib:ScanUnknownUnits()
210 | local name
211 | for unitid in pairs(unknownUnits) do
212 | if UnitExists(unitid) then
213 | name = self:CreateOrUpdateUnit(unitid)
214 | else
215 | unknownUnits[unitid] = nil
216 | end
217 | -- some pets never have a name. too bad for them, farewell!
218 | if not name and string.find(unitid,"pet") then
219 | unknownUnits[unitid] = nil
220 | end
221 | end
222 | self:ProcessRoster()
223 | end
224 |
225 |
226 | function RosterLib:ProcessRoster()
227 | if next(updatedUnits, nil) then
228 | self:TriggerEvent("RosterLib_RosterChanged", updatedUnits)
229 | for name in pairs(updatedUnits) do
230 | local u = updatedUnits[name]
231 | self:TriggerEvent("RosterLib_UnitChanged", u.unitid, u.name, u.class, u.subgroup, u.rank, u.oldname, u.oldunitid, u.oldclass, u.oldsubgroup, u.oldrank)
232 | if Compost then Compost:Reclaim(updatedUnits[name]) end
233 | updatedUnits[name] = nil
234 | end
235 | end
236 | if next(unknownUnits, nil) then
237 | self:CancelScheduledEvent("ScanUnknownUnits")
238 | self:ScheduleEvent("ScanUnknownUnits",self.ScanUnknownUnits, 1, self)
239 | end
240 | end
241 |
242 |
243 | function RosterLib:CreateOrUpdateUnit(unitid)
244 | local old = nil
245 | -- check for name
246 | local name = UnitName(unitid)
247 | if name and name ~= UNKNOWNOBJECT and name ~= UKNOWNBEING and not UnitIsCharmed(unitid) then
248 | -- clear stuff
249 | unknownUnits[unitid] = nil
250 | -- return if a pet attempts to replace a player name
251 | -- this doesnt fix the problem with 2 pets overwriting each other FIXME
252 | if string.find(unitid,"pet") then
253 | if roster[name] and roster[name].class ~= "pet" then
254 | return name
255 | end
256 | end
257 | -- save old data if existing
258 | if roster[name] then
259 | old = Compost and Compost:Acquire() or {}
260 | old.name = roster[name].name
261 | old.unitid = roster[name].unitid
262 | old.class = roster[name].class
263 | old.rank = roster[name].rank
264 | old.subgroup = roster[name].subgroup
265 | old.online = roster[name].online
266 | end
267 | -- object
268 | if not roster[name] then
269 | roster[name] = Compost and Compost:Acquire() or {}
270 | end
271 | -- name
272 | roster[name].name = name
273 | -- unitid
274 | roster[name].unitid = unitid
275 | -- class
276 | if string.find(unitid,"pet") then
277 | roster[name].class = "PET"
278 | else
279 | _,roster[name].class = UnitClass(unitid)
280 | end
281 | -- subgroup and rank
282 | if GetNumRaidMembers() > 0 then
283 | local _,_,num = string.find(unitid, "(%d+)")
284 | _,roster[name].rank,roster[name].subgroup = GetRaidRosterInfo(num)
285 | else
286 | roster[name].subgroup = 1
287 | roster[name].rank = 0
288 | end
289 | -- online/offline status
290 | roster[name].online = UnitIsConnected(unitid)
291 |
292 | -- compare data
293 | if not old
294 | or roster[name].name ~= old.name
295 | or roster[name].unitid ~= old.unitid
296 | or roster[name].class ~= old.class
297 | or roster[name].subgroup ~= old.subgroup
298 | or roster[name].rank ~= old.rank
299 | or roster[name].online ~= old.online
300 | then
301 | updatedUnits[name] = Compost and Compost:Acquire() or {}
302 | updatedUnits[name].oldname = (old and old.name) or nil
303 | updatedUnits[name].oldunitid = (old and old.unitid) or nil
304 | updatedUnits[name].oldclass = (old and old.class) or nil
305 | updatedUnits[name].oldsubgroup = (old and old.subgroup) or nil
306 | updatedUnits[name].oldrank = (old and old.rank) or nil
307 | updatedUnits[name].oldonline = (old and old.online) or nil
308 | updatedUnits[name].name = roster[name].name
309 | updatedUnits[name].unitid = roster[name].unitid
310 | updatedUnits[name].class = roster[name].class
311 | updatedUnits[name].subgroup = roster[name].subgroup
312 | updatedUnits[name].rank = roster[name].rank
313 | updatedUnits[name].online = roster[name].online
314 | end
315 | -- compost our table
316 | if old and Compost then
317 | Compost:Reclaim(old)
318 | end
319 | return name
320 | else
321 | unknownUnits[unitid] = true
322 | return false
323 | end
324 | end
325 |
326 |
327 | function RosterLib:RemoveUnit(name)
328 | updatedUnits[name] = Compost and Compost:Acquire() or {}
329 | updatedUnits[name].oldname = roster[name].name
330 | updatedUnits[name].oldunitid = roster[name].unitid
331 | updatedUnits[name].oldclass = roster[name].class
332 | updatedUnits[name].oldsubgroup = roster[name].subgroup
333 | updatedUnits[name].oldrank = roster[name].rank
334 | if Compost then Compost:Reclaim(roster[name]) end
335 | roster[name] = nil
336 | end
337 |
338 |
339 | ------------------------------------------------
340 | -- API
341 | ------------------------------------------------
342 |
343 | function RosterLib:GetUnitIDFromName(name)
344 | if roster[name] then
345 | return roster[name].unitid
346 | else
347 | return nil
348 | end
349 | end
350 |
351 |
352 | function RosterLib:GetUnitIDFromUnit(unit)
353 | local name = UnitName(unit)
354 | if name and roster[name] then
355 | return roster[name].unitid
356 | else
357 | return nil
358 | end
359 | end
360 |
361 |
362 | function RosterLib:GetUnitObjectFromName(name)
363 | if roster[name] then
364 | return roster[name]
365 | else
366 | return nil
367 | end
368 | end
369 |
370 |
371 | function RosterLib:GetUnitObjectFromUnit(unit)
372 | local name = UnitName(unit)
373 | if roster[name] then
374 | return roster[name]
375 | else
376 | return nil
377 | end
378 | end
379 |
380 |
381 | function RosterLib:IterateRoster(pets)
382 | local key
383 | return function()
384 | repeat
385 | key = next(roster, key)
386 | until (roster[key] == nil or pets or roster[key].class ~= "PET")
387 |
388 | return roster[key]
389 | end
390 | end
391 |
392 |
393 | AceLibrary:Register(RosterLib, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
394 |
--------------------------------------------------------------------------------
/localization.de.lua:
--------------------------------------------------------------------------------
1 | if (GetLocale() == "deDE") then
2 |
3 | -- Shaman
4 | QUICKHEAL_SPELL_LESSER_HEALING_WAVE = 'Geringe Welle der Heilung';
5 | QUICKHEAL_SPELL_HEALING_WAVE = 'Welle der Heilung';
6 |
7 | -- Priest
8 | QUICKHEAL_SPELL_LESSER_HEAL = 'Geringes Heilen';
9 | QUICKHEAL_SPELL_HEAL = 'Heilen';
10 | QUICKHEAL_SPELL_GREATER_HEAL = 'Gro\195\159e Heilung';
11 | QUICKHEAL_SPELL_FLASH_HEAL = 'Blitzheilung';
12 |
13 | -- Paladin
14 | QUICKHEAL_SPELL_HOLY_LIGHT = 'Heiliges Licht';
15 | QUICKHEAL_SPELL_FLASH_OF_LIGHT = 'Lichtblitz';
16 |
17 | -- Druid
18 | QUICKHEAL_SPELL_HEALING_TOUCH = 'Heilende Ber\195\188hrung';
19 | QUICKHEAL_SPELL_REGROWTH = 'Nachwachsen';
20 |
21 | end
--------------------------------------------------------------------------------
/localization.en.lua:
--------------------------------------------------------------------------------
1 | -- Shaman
2 | QUICKHEAL_SPELL_LESSER_HEALING_WAVE = "Lesser Healing Wave";
3 | QUICKHEAL_SPELL_HEALING_WAVE = "Healing Wave";
4 |
5 | -- Priest
6 | QUICKHEAL_SPELL_LESSER_HEAL = 'Lesser Heal';
7 | QUICKHEAL_SPELL_HEAL = 'Heal';
8 | QUICKHEAL_SPELL_GREATER_HEAL = 'Greater Heal';
9 | QUICKHEAL_SPELL_FLASH_HEAL = 'Flash Heal';
10 |
11 | -- Paladin
12 | QUICKHEAL_SPELL_HOLY_LIGHT = 'Holy Light';
13 | QUICKHEAL_SPELL_FLASH_OF_LIGHT = 'Flash of Light';
14 |
15 | -- Druid
16 | QUICKHEAL_SPELL_HEALING_TOUCH = 'Healing Touch';
17 | QUICKHEAL_SPELL_REGROWTH = 'Regrowth';
--------------------------------------------------------------------------------
/localization.fr.lua:
--------------------------------------------------------------------------------
1 | if (GetLocale() == "frFR") then
2 |
3 | -- Shaman
4 | QUICKHEAL_SPELL_LESSER_HEALING_WAVE = 'Vague de soins inf\195\169rieurs';
5 | QUICKHEAL_SPELL_HEALING_WAVE = 'Vague de soins';
6 |
7 | -- Priest
8 | QUICKHEAL_SPELL_LESSER_HEAL = 'Soins inf\195\169rieurs';
9 | QUICKHEAL_SPELL_HEAL = 'Soins';
10 | QUICKHEAL_SPELL_GREATER_HEAL = 'Soins sup\195\169rieurs';
11 | QUICKHEAL_SPELL_FLASH_HEAL = 'Soins rapides';
12 |
13 | -- Paladin
14 | QUICKHEAL_SPELL_HOLY_LIGHT = 'Lumi\195\168re sacr\195\169e';
15 | QUICKHEAL_SPELL_FLASH_OF_LIGHT = 'Eclair lumineux';
16 |
17 | -- Druid
18 | QUICKHEAL_SPELL_HEALING_TOUCH = 'Toucher gu\195\169risseur';
19 | QUICKHEAL_SPELL_REGROWTH = 'R\195\169tablissement';
20 |
21 | end
--------------------------------------------------------------------------------