vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | --[[--------------------------------------------------------------------------------- |
2 | Clique by Cladhaire <cladhaire@gmail.com> |
||
3 | GUI concept/code by Gello |
||
4 | |||
5 | TODO: |
||
6 | |||
7 | ----------------------------------------------------------------------------------]] |
||
8 | |||
9 | --[[--------------------------------------------------------------------------------- |
||
10 | Create the AddOn object and create a local binding for AceLocale |
||
11 | ----------------------------------------------------------------------------------]] |
||
12 | |||
13 | Clique = AceLibrary("AceAddon-2.0"):new( |
||
14 | "AceHook-2.0", |
||
15 | "AceConsole-2.0", |
||
16 | "AceDB-2.0", |
||
17 | "AceEvent-2.0", |
||
18 | "AceModuleCore-2.0", |
||
19 | "AceDebug-2.0" |
||
20 | ) |
||
21 | |||
22 | Clique:RegisterDB("CliqueDB") |
||
23 | local L = AceLibrary:GetInstance("AceLocale-2.0"):new("Clique") |
||
24 | |||
25 | -- Expoxe AceHook and AceEvent to our modules |
||
26 | Clique:SetModuleMixins("AceHook-2.0", "AceEvent-2.0", "AceDebug-2.0") |
||
27 | |||
28 | --[[--------------------------------------------------------------------------------- |
||
29 | This is the actual addon object |
||
30 | ----------------------------------------------------------------------------------]] |
||
31 | |||
32 | function Clique:OnInitialize() |
||
33 | self:LevelDebug(2, "Clique:OnInitialize()") |
||
34 | self:CheckProfile() |
||
35 | |||
36 | self:LevelDebug(3, "Setting all modules to inactive.") |
||
37 | for name,module in self:IterateModules() do |
||
38 | self:ToggleModuleActive(name, false) |
||
39 | end |
||
40 | end |
||
41 | |||
42 | function Clique:OnEnable() |
||
43 | self:LevelDebug(2, "Clique:OnEnable()") |
||
44 | IndentationLib.addSmartCode(CliqueEditBox) |
||
45 | |||
46 | if GetCVar("AutoSelfCast") == "1" then |
||
47 | StaticPopup_Show("CLIQUE_AUTO_SELF_CAST") |
||
48 | return |
||
49 | end |
||
50 | |||
51 | -- Register for ADDON_LOADED so we can load plugins for LOD addons |
||
52 | self:RegisterEvent("ADDON_LOADED", "LoadModules") |
||
53 | |||
54 | -- Build the action table, so we have precompiled functions |
||
55 | self:ScanSpellbook() |
||
56 | self:BuildActionTable() |
||
57 | |||
58 | -- Enable tooltips in the GUI |
||
59 | self:EnableTooltips() |
||
60 | self:RegUtilFuncs() |
||
61 | |||
62 | -- Create the hook tables |
||
63 | self._OnClick = {} |
||
64 | |||
65 | -- Load any valid modules |
||
66 | self:LoadModules() |
||
67 | |||
68 | -- Hook the SpellBookFrame so we can hide/show as needed |
||
69 | self:HookScript(SpellBookFrame, "OnShow", "SpellBookFrame_OnShow") |
||
70 | for i=1,12 do |
||
71 | local button = getglobal("SpellButton"..i) |
||
72 | button:RegisterForClicks("LeftButtonUp","RightButtonUp", "MiddleButtonUp", "Button4Up", "Button5Up"); |
||
73 | self:HookScript(button, "OnClick", "SpellButton_OnClick") |
||
74 | end |
||
75 | end |
||
76 | |||
77 | function Clique:LoadModules() |
||
78 | for name,module in self:IterateModules() do |
||
79 | if not self:IsModuleActive(name) and not module.disabled then |
||
80 | -- Try to enable the module |
||
81 | |||
82 | local loadModule = nil |
||
83 | |||
84 | if module.Test and type(module.Test) == "function" then |
||
85 | if module:Test() then |
||
86 | loadModule = true |
||
87 | end |
||
88 | else |
||
89 | loadModule = true |
||
90 | end |
||
91 | |||
92 | if loadModule and not Clique:IsModuleActive(name) then |
||
93 | self:LevelDebug(1, "Enabling module \"%s\" for %s.", name, module.fullname) |
||
94 | Clique:ToggleModuleActive(name,true) |
||
95 | |||
96 | if module._OnClick then |
||
97 | self:LevelDebug(2, "Grabbing _OnClick from %s", name) |
||
98 | self._OnClick[name] = module |
||
99 | end |
||
100 | end |
||
101 | end |
||
102 | end |
||
103 | end |
||
104 | |||
105 | function Clique:CheckProfile() |
||
106 | self:LevelDebug(2, "Clique:CheckProfile()") |
||
107 | |||
108 | local profile = self.db.char |
||
109 | profile[L"DEFAULT_FRIENDLY"] = profile[L"DEFAULT_FRIENDLY"] or {} |
||
110 | profile[L"DEFAULT_HOSTILE"] = profile[L"DEFAULT_HOSTILE"] or {} |
||
111 | end |
||
112 | |||
113 | function Clique:BuildActionTable() |
||
114 | self:LevelDebug(2, "Clique:BuildActionTable()") |
||
115 | |||
116 | local actions = self:ClearTable(self.Actions) |
||
117 | self.Actions = actions |
||
118 | |||
119 | for k,v in pairs(self.db.char) do |
||
120 | actions[k] = {} |
||
121 | |||
122 | for i,entry in ipairs(v) do |
||
123 | local a = bit.band(entry.modifiers, 1) |
||
124 | local c = bit.band(entry.modifiers, 2) |
||
125 | local s = bit.band(entry.modifiers, 4) |
||
126 | |||
127 | -- Skip any non-bound entries |
||
128 | if entry.button ~= L"BINDING_NOT_DEFINED" then |
||
129 | local key = string.format("%s%d", entry.button, entry.modifiers) |
||
130 | local action = entry.action |
||
131 | if not action and not entry.custom then |
||
132 | local buff = self.spellbook[entry.name] |
||
133 | if buff then buff = tonumber(buff) end |
||
134 | if self:IsBuff(entry.name) and not entry.rank then |
||
135 | action = string.format("Clique:BestRank(\"%s\", Clique.unit)", entry.name) |
||
136 | elseif entry.rank then |
||
137 | action = string.format("Clique:CastSpell(\"%s(%s %d)\")", entry.name, L"RANK", entry.rank) |
||
138 | else |
||
139 | action = string.format("Clique:CastSpell(\"%s\")", entry.name) |
||
140 | end |
||
141 | end |
||
142 | |||
143 | --self:Print(action) |
||
144 | |||
145 | local func,errString = loadstring(action) |
||
146 | if func then |
||
147 | actions[k][key] = func |
||
148 | else |
||
149 | DEFAULT_CHAT_FRAME:AddMessage(string.format(L"ERROR_SCRIPT", errString)) |
||
150 | end |
||
151 | end |
||
152 | end |
||
153 | end |
||
154 | end |
||
155 | |||
156 | function Clique:OnClick(button, unit) |
||
157 | unit = unit or this.unit |
||
158 | button = button or arg1 |
||
159 | local a,c,s = IsAltKeyDown() or 0, IsControlKeyDown() or 0, IsShiftKeyDown() or 0 |
||
160 | |||
161 | local targettarget = nil |
||
162 | |||
163 | if not unit then |
||
164 | unit = this:GetParent().unit |
||
165 | if not unit then |
||
166 | error(string.format(L"NO_UNIT_FRAME", tostring(this:GetName()))) |
||
167 | end |
||
168 | end |
||
169 | |||
170 | if not UnitExists(unit) then |
||
171 | return |
||
172 | end |
||
173 | |||
174 | Clique.unit = unit |
||
175 | -- DEFAULT_CHAT_FRAME:AddMessage("Clique:OnClick("..tostring(button)..", "..tostring(unit)..")") |
||
176 | if not UnitExists(unit) then return end |
||
177 | |||
178 | -- If the casting hand is up on the screen, cast the waiting spell on |
||
179 | -- this unit |
||
180 | if SpellIsTargeting() then |
||
181 | if button == "LeftButton" then SpellTargetUnit(unit) |
||
182 | elseif button == "RightButton" then SpellStopTargeting() end |
||
183 | return true |
||
184 | end |
||
185 | |||
186 | -- If the cursor has an item and we're clicking on another player, |
||
187 | -- attempt to trade with them (or feed your pet, etc). If we |
||
188 | -- LeftButton drop it on ourselves, then equip the item. If we click |
||
189 | -- anything else, then put the item back in the backpack |
||
190 | if CursorHasItem() then |
||
191 | if button == "LeftButton" then |
||
192 | if unit == "player" then AutoEquipCursorItem() |
||
193 | else DropItemOnUnit(unit) end |
||
194 | else PutItemInBackpack() end |
||
195 | return |
||
196 | end |
||
197 | |||
198 | -- We need to determine which cast set we're coming from |
||
199 | local default = L"DEFAULT_FRIENDLY" |
||
200 | local restore = nil |
||
201 | |||
202 | if UnitCanAttack("player", unit) then |
||
203 | default = L"DEFAULT_HOSTILE" |
||
204 | end |
||
205 | |||
206 | Clique.set = default |
||
207 | |||
208 | -- Iterate the hooks here |
||
209 | for name,module in pairs(Clique._OnClick) do |
||
210 | if module:_OnClick(button, Clique.unit) then |
||
211 | self:LevelDebug(3, "Module %s has changed the clique set.", name) |
||
212 | break |
||
213 | end |
||
214 | end |
||
215 | |||
216 | if not Clique.set or not Clique.Actions[Clique.set] then |
||
217 | Clique.set = default |
||
218 | end |
||
219 | |||
220 | local modifiers = 0 |
||
221 | modifiers = bit.bor(modifiers, a * 1) |
||
222 | modifiers = bit.bor(modifiers, c * 2) |
||
223 | modifiers = bit.bor(modifiers, s * 4) |
||
224 | |||
225 | local key = string.format("%s%d", button, modifiers) |
||
226 | local func = Clique.Actions[Clique.set][key] |
||
227 | local entry = Clique.db.char[Clique.set][key] |
||
228 | |||
229 | self:LevelDebug(2, "Clique:OnClick("..button..", " .. modifiers..")") |
||
230 | |||
231 | if not func then |
||
232 | self:LevelDebug(3, "Casting from the default set instead.") |
||
233 | func = Clique.Actions[default][key] |
||
234 | entry = Clique.db.char[default][key] |
||
235 | end |
||
236 | |||
237 | if func then |
||
238 | func() |
||
239 | |||
240 | -- In case spell failed to apply |
||
241 | if SpellIsTargeting() then SpellStopTargeting() end |
||
242 | |||
243 | return true |
||
244 | else |
||
245 | --error("Could not find an action for key " .. key) |
||
246 | end |
||
247 | end |
||
248 | |||
249 | function Clique:CastSpell(spell, unit) |
||
250 | local restore = nil |
||
251 | unit = unit or Clique.unit |
||
252 | |||
253 | -- IMPORTANT: If the unit is targettarget or more, then we need to try |
||
254 | -- to convert it to a friendly unit (to make click-casting work |
||
255 | -- properly). If this isn't successful, set it up so we restore our |
||
256 | -- target |
||
257 | |||
258 | self:LevelDebug(2, "Clique:CastSpell("..tostring(spell)..", "..tostring(unit) .. ")") |
||
259 | |||
260 | if string.find(unit, "target") and string.len(unit) > 6 then |
||
261 | local friendly = Clique:GetFriendlyUnit(unit) |
||
262 | |||
263 | if friendly then |
||
264 | unit = friendly |
||
265 | else |
||
266 | self:LevelDebug(2, "Setting targettarget flag.") |
||
267 | targettarget = true |
||
268 | end |
||
269 | end |
||
270 | |||
271 | -- Lets resolve the targeting. If this is a hostile target and its |
||
272 | -- not currently our target, then we will need to target the unit |
||
273 | if UnitCanAttack("player", unit) then |
||
274 | if not UnitIsUnit(unit, "target") then |
||
275 | self:LevelDebug(2, "Changing to hostile target.") |
||
276 | TargetUnit(unit) |
||
277 | end |
||
278 | |||
279 | -- If we're looking at someone else's target, we have to change targets since |
||
280 | -- ClearTarget() will get rid of the blahtarget unitID entirely. We only do |
||
281 | -- this if this is a friendly target (since they will consume the spell) |
||
282 | elseif targettarget and not UnitCanAttack("player", "target") then |
||
283 | self:LevelDebug(2, "Changing target due to friendly target.") |
||
284 | TargetUnit(unit) |
||
285 | |||
286 | -- If the target is a friendly unit, and its not the unit we're casting on |
||
287 | elseif UnitExists("target") and not UnitCanAttack("player", "target") and not UnitIsUnit(unit, "target") then |
||
288 | self:LevelDebug(3, "Clearing the target") |
||
289 | ClearTarget() |
||
290 | restore = true |
||
291 | |||
292 | elseif UnitExists("target") and self:IsDualSpell(spell) and not UnitIsUnit(unit, "target") then |
||
293 | self:LevelDebug(3, "Clearing target for this dual spell") |
||
294 | ClearTarget() |
||
295 | restore = true |
||
296 | end |
||
297 | |||
298 | --self:Print("Clique:CastSpell(%s, %s)", spell, unit) |
||
299 | --self:Print("Dual Spell: %s, %s", spell, tostring(self:IsDualSpell(spell))) |
||
300 | |||
301 | CastSpellByName(spell) |
||
302 | |||
303 | if SpellIsTargeting() then |
||
304 | self:LevelDebug(3, "SpellTargetingUnit") |
||
305 | SpellTargetUnit(unit) |
||
306 | end |
||
307 | |||
308 | if SpellIsTargeting() then SpellStopTargeting() end |
||
309 | |||
310 | if restore then |
||
311 | self:LevelDebug(3, "Restoring with TargetLastTarget") |
||
312 | TargetLastTarget() |
||
313 | end |
||
314 | end |