Mercurial > wow > reaction
comparison modules/ReAction_PetAction/ReAction_PetAction.lua @ 53:7e09c02ae620
Pet Action support
| author | Flick <flickerstreak@gmail.com> |
|---|---|
| date | Fri, 25 Apr 2008 20:35:55 +0000 |
| parents | 21bcaf8215ff |
| children | 88283658fec4 |
comparison
equal
deleted
inserted
replaced
| 52:c9df7866ff31 | 53:7e09c02ae620 |
|---|---|
| 1 --[[ | 1 --[[ |
| 2 ReAction Pet Action Bar module | 2 ReAction Pet Action button module |
| 3 | |
| 4 The button module implements standard action button functionality by wrapping Blizzard's | |
| 5 PetActionButton frame and associated functions. It also provides some button layout | |
| 6 modification tools. | |
| 3 | 7 |
| 4 --]] | 8 --]] |
| 5 | 9 |
| 6 -- local imports | 10 -- local imports |
| 7 local ReAction = ReAction | 11 local ReAction = ReAction |
| 8 local L = ReAction.L | 12 local L = ReAction.L |
| 9 local _G = _G | 13 local _G = _G |
| 14 local CreateFrame = CreateFrame | |
| 10 | 15 |
| 11 -- module declaration | 16 -- module declaration |
| 12 local moduleID = "PetAction" | 17 local moduleID = "PetAction" |
| 13 local module = ReAction:NewModule( moduleID ) | 18 local module = ReAction:NewModule( moduleID ) |
| 14 | 19 |
| 15 | |
| 16 -- module methods | 20 -- module methods |
| 17 function module:OnInitialize() | 21 function module:OnInitialize() |
| 18 self.db = ReAction.db:RegisterNamespace( moduleID, | 22 self.db = ReAction.db:RegisterNamespace( moduleID, |
| 19 { | 23 { |
| 20 profile = { | 24 profile = { |
| 21 buttons = { } | 25 buttons = { } |
| 22 } | 26 } |
| 23 } | 27 } |
| 24 ) | 28 ) |
| 25 | |
| 26 self.buttons = { } | 29 self.buttons = { } |
| 30 | |
| 31 ReAction:RegisterOptions("global", self, { | |
| 32 }) | |
| 27 end | 33 end |
| 28 | 34 |
| 29 function module:OnEnable() | 35 function module:OnEnable() |
| 36 ReAction:RegisterBarType(L["Pet Action Bar"], | |
| 37 { | |
| 38 type = moduleID , | |
| 39 defaultButtonSize = 30, | |
| 40 defaultBarRows = 1, | |
| 41 defaultBarCols = 10, | |
| 42 defaultBarSpacing = 8 | |
| 43 }) | |
| 30 end | 44 end |
| 31 | 45 |
| 32 function module:OnDisable() | 46 function module:OnDisable() |
| 33 end | 47 ReAction:UnregisterBarType(L["Pet Action Bar"]) |
| 34 | 48 end |
| 35 function module:GetGlobalBarOptions(opts) | 49 |
| 36 if self.globalBarOpts == nil then | 50 function module:ApplyToBar(bar) |
| 37 self.globalBarOpts = { | 51 if bar.config.type == moduleID then |
| 38 newActionBar = { | 52 -- auto show/hide when pet exists |
| 39 type = "execute", | 53 bar:GetFrame():SetAttribute("unit","pet") |
| 40 name = L["New Pet Action Bar"], | 54 RegisterUnitWatch(bar:GetFrame()) |
| 41 desc = L["Create a new bar of pet action buttons"], | 55 self:RefreshBar(bar) |
| 42 func = function() | 56 end |
| 43 ReAction:CreateBar() | 57 end |
| 44 end, | 58 |
| 45 disabled = InCombatLockdown, | 59 function module:RefreshBar(bar) |
| 46 } | 60 if bar.config.type == moduleID then |
| 47 } | 61 if self.buttons[bar] == nil then |
| 48 end | 62 self.buttons[bar] = { } |
| 49 return self.globalBarOpts | 63 end |
| 50 end | 64 local btns = self.buttons[bar] |
| 65 local profile = self.db.profile | |
| 66 local barName = bar:GetName() | |
| 67 if profile.buttons[barName] == nil then | |
| 68 profile.buttons[barName] = {} | |
| 69 end | |
| 70 local btnCfg = profile.buttons[barName] | |
| 71 | |
| 72 local r, c = bar:GetButtonGrid() | |
| 73 local n = r*c | |
| 74 for i = 1, n do | |
| 75 if btnCfg[i] == nil then | |
| 76 btnCfg[i] = {} | |
| 77 end | |
| 78 if btns[i] == nil then | |
| 79 local ok, b = pcall(self.BtnClass.new, self.BtnClass, bar, i, btnCfg[i]) | |
| 80 if ok and b then | |
| 81 btns[i] = b | |
| 82 end | |
| 83 else | |
| 84 btns[i]:Refresh(bar,i) | |
| 85 end | |
| 86 end | |
| 87 for i = n+1, #btns do | |
| 88 if btns[i] then | |
| 89 btns[i] = btns[i]:Destroy() | |
| 90 if btnCfg[i] then | |
| 91 btnCfg[i] = nil | |
| 92 end | |
| 93 end | |
| 94 end | |
| 95 end | |
| 96 end | |
| 97 | |
| 98 function module:RemoveFromBar(bar) | |
| 99 if self.buttons[bar] then | |
| 100 local btns = self.buttons[bar] | |
| 101 for _,b in pairs(btns) do | |
| 102 if b then | |
| 103 b:Destroy() | |
| 104 end | |
| 105 end | |
| 106 self.buttons[bar] = nil | |
| 107 end | |
| 108 end | |
| 109 | |
| 110 function module:EraseBarConfig(barName) | |
| 111 self.db.profile.buttons[barName] = nil | |
| 112 end | |
| 113 | |
| 114 function module:RenameBarConfig(oldname, newname) | |
| 115 local b = self.db.profile.buttons | |
| 116 b[newname], b[oldname] = b[oldname], nil | |
| 117 end | |
| 118 | |
| 119 | |
| 120 function module:ApplyConfigMode(mode,bars) | |
| 121 for _, bar in pairs(bars) do | |
| 122 if bar and self.buttons[bar] then | |
| 123 for _, b in pairs(self.buttons[bar]) do | |
| 124 if b then | |
| 125 if mode then | |
| 126 self:showActionIDLabel(b) | |
| 127 else | |
| 128 ReAction:Print("Hiding action id "..b:GetActionID()) | |
| 129 self:hideActionIDLabel(b) | |
| 130 end | |
| 131 end | |
| 132 end | |
| 133 local f = bar:GetFrame() | |
| 134 if mode then | |
| 135 UnregisterUnitWatch(f) | |
| 136 f:Show() | |
| 137 else | |
| 138 RegisterUnitWatch(f) | |
| 139 end | |
| 140 end | |
| 141 end | |
| 142 end | |
| 143 | |
| 144 function module:showActionIDLabel(button) | |
| 145 -- store the action ID label in the frame due to frame recycling | |
| 146 if not button:GetFrame().actionIDLabel and button:GetActionID() then | |
| 147 local label = button:GetFrame():CreateFontString(nil,"OVERLAY","GameFontNormalLarge") | |
| 148 label:SetAllPoints() | |
| 149 label:SetJustifyH("CENTER") | |
| 150 label:SetShadowColor(0,0,0,1) | |
| 151 label:SetShadowOffset(2,-2) | |
| 152 label:SetText(tostring(button:GetActionID())) | |
| 153 button:GetFrame().actionIDLabel = label | |
| 154 end | |
| 155 button:GetFrame().actionIDLabel:Show() | |
| 156 end | |
| 157 | |
| 158 function module:hideActionIDLabel(button) | |
| 159 if button:GetFrame().actionIDLabel then | |
| 160 button:GetFrame().actionIDLabel:Hide() | |
| 161 else | |
| 162 ReAction:Print("actionIDLabel not found") | |
| 163 end | |
| 164 end | |
| 165 | |
| 51 | 166 |
| 52 | 167 |
| 53 -- use-count of action IDs | 168 -- use-count of action IDs |
| 169 local nActionIDs = NUM_PET_ACTION_SLOTS | |
| 54 local ActionIDList = setmetatable( {}, { | 170 local ActionIDList = setmetatable( {}, { |
| 55 __index = function(self, idx) | 171 __index = function(self, idx) |
| 56 if idx == nil then | 172 if idx == nil then |
| 57 for i = 1, 10 do | 173 for i = 1, nActionIDs do |
| 58 if rawget(self,i) == nil then | 174 if rawget(self,i) == nil then |
| 59 rawset(self,i,1) | 175 rawset(self,i,1) |
| 60 return i | 176 return i |
| 61 end | 177 end |
| 62 end | 178 end |
| 179 error("ran out of pet action IDs") | |
| 63 else | 180 else |
| 64 local c = rawget(self,idx) or 0 | 181 local c = rawget(self,idx) or 0 |
| 65 rawset(self,idx,c+1) | 182 rawset(self,idx,c+1) |
| 66 return idx | 183 return idx |
| 67 end | 184 end |
| 77 end | 194 end |
| 78 rawset(self,idx,value) | 195 rawset(self,idx,value) |
| 79 end | 196 end |
| 80 }) | 197 }) |
| 81 | 198 |
| 82 | 199 local frameRecycler = {} |
| 83 -- button class methods | 200 |
| 201 | |
| 202 ------ Button class ------ | |
| 84 local Button = { } | 203 local Button = { } |
| 85 | 204 |
| 86 local function Constructor( self, bar, idx, config ) | 205 local function Constructor( self, bar, idx, config ) |
| 87 self.bar, self.idx, self.config = bar, idx, config | 206 self.bar, self.idx, self.config = bar, idx, config |
| 88 | 207 |
| 89 local barFrame = bar:GetFrame() | 208 local barFrame = bar:GetFrame() |
| 90 | 209 |
| 91 self.name = config.name or "ReAction_"..bar:GetName().."_Pet_"..idx | 210 local name = config.name or "ReAction_"..bar:GetName().."_Pet_"..idx |
| 211 config.name = name | |
| 212 self.name = config.name | |
| 92 config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured | 213 config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured |
| 93 | 214 |
| 94 local f = CreateFrame("CheckButton", self.name, barFrame, "PetActionButtonTemplate") | 215 -- have to recycle frames with the same name: |
| 95 f:SetID(config.actionID) -- PetActionButtonTemplate isn't a proper SecureActionButton (question: is this protected? does it cause taint?) | 216 -- otherwise you either get references to old textures because named CreateFrame() |
| 217 -- doesn't overwrite existing globals (below) | |
| 218 -- or, if you set them to nil in the global table, you get taint because of the | |
| 219 -- crappy PetActionBar code. | |
| 220 local f = frameRecycler[name] | |
| 221 if f then | |
| 222 f:SetParent(barFrame) | |
| 223 f:Show() | |
| 224 else | |
| 225 f = CreateFrame("CheckButton", name, barFrame, "PetActionButtonTemplate") | |
| 226 end | |
| 227 if config.actionID then | |
| 228 f:SetID(config.actionID) -- PetActionButtonTemplate isn't a proper SecureActionButton | |
| 229 end | |
| 230 f:SetFrameStrata("MEDIUM") | |
| 231 | |
| 232 barFrame:SetAttribute("addchild",f) | |
| 233 | |
| 96 self.frame = f | 234 self.frame = f |
| 97 barFrame:SetAttribute("addchild",f) | 235 self.icon = _G[("%sIcon"):format(name)] |
| 98 | 236 self.acTex = _G[("%sAutoCastable"):format(name)] |
| 99 -- auto show/hide when pet exists | 237 self.acModel = _G[("%sAutoCast"):format(name)] |
| 100 -- this gets called once per button, which is inefficient but otherwise harmless | 238 self.cooldown = _G[("%sCooldown"):format(name)] |
| 101 barFrame:SetAttribute("unit","pet") | 239 self.hotkey = _G[("%sHotKey"):format(name)] |
| 102 RegisterUnitWatch(barFrame) | 240 |
| 241 f:HookScript("OnDragStart", function() self:Update() end) | |
| 242 f:HookScript("OnReceiveDrag", function() self:Update() end) | |
| 243 | |
| 244 f:RegisterEvent("PLAYER_CONTROL_LOST"); | |
| 245 f:RegisterEvent("PLAYER_CONTROL_GAINED"); | |
| 246 f:RegisterEvent("PLAYER_FARSIGHT_FOCUS_CHANGED"); | |
| 247 f:RegisterEvent("UNIT_PET"); | |
| 248 f:RegisterEvent("UNIT_FLAGS"); | |
| 249 f:RegisterEvent("UNIT_AURA"); | |
| 250 f:RegisterEvent("PET_BAR_UPDATE"); | |
| 251 f:RegisterEvent("PET_BAR_UPDATE_COOLDOWN"); | |
| 252 | |
| 253 f:SetScript("OnEvent", | |
| 254 function(event,arg1) | |
| 255 if event =="PET_BAR_UPDATE_COOLDOWN" then | |
| 256 self:UpdateCooldown() | |
| 257 elseif event == "UPDATE_BINDINGS" then | |
| 258 self:UpdateHotkey() | |
| 259 else | |
| 260 self:Update() | |
| 261 end | |
| 262 end) | |
| 103 | 263 |
| 104 self:Refresh(bar,idx) | 264 self:Refresh(bar,idx) |
| 105 end | 265 end |
| 106 | 266 |
| 107 function Button:Destroy() | 267 function Button:Destroy() |
| 109 f:UnregisterAllEvents() | 269 f:UnregisterAllEvents() |
| 110 f:Hide() | 270 f:Hide() |
| 111 f:SetParent(UIParent) | 271 f:SetParent(UIParent) |
| 112 f:ClearAllPoints() | 272 f:ClearAllPoints() |
| 113 if self.name then | 273 if self.name then |
| 274 frameRecycler[self.name] = f | |
| 114 _G[self.name] = nil | 275 _G[self.name] = nil |
| 115 end | 276 end |
| 116 ActionIDList[self.config.actionID] = nil | 277 if self.config.actionID then |
| 278 ActionIDList[self.config.actionID] = nil | |
| 279 end | |
| 117 self.frame = nil | 280 self.frame = nil |
| 118 self.config = nil | 281 self.config = nil |
| 119 self.bar = nil | 282 self.bar = nil |
| 120 end | 283 end |
| 121 | 284 |
| 285 function Button:Refresh(bar,idx) | |
| 286 bar:PlaceButton(self.frame, idx, 30, 30) | |
| 287 self:Update() | |
| 288 self:UpdateHotkey() | |
| 289 end | |
| 290 | |
| 291 function Button:GetFrame() | |
| 292 return self.frame | |
| 293 end | |
| 294 | |
| 295 function Button:GetName() | |
| 296 return self.name | |
| 297 end | |
| 298 | |
| 299 function Button:GetActionID() | |
| 300 return self.config.actionID | |
| 301 end | |
| 302 | |
| 303 function Button:Update() | |
| 304 local id = self.frame:GetID() | |
| 305 local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(id); | |
| 306 local f = self.frame | |
| 307 --ReAction:Print(("id %d: '%s', '%s', '%s', '%s', '%s', '%s', '%s'"):format(tostring(id), tostring(name),tostring(subtext),tostring(texture),tostring(isToken),tostring(isActive),tostring(autoCastAllowed),tostring(autoCastEnabled))) | |
| 308 | |
| 309 if isToken then | |
| 310 self.icon:SetTexture(_G[texture]); | |
| 311 f.tooltipName = _G[name]; | |
| 312 else | |
| 313 self.icon:SetTexture(texture); | |
| 314 f.tooltipName = name; | |
| 315 end | |
| 316 | |
| 317 f.isToken = isToken; | |
| 318 f.tooltipSubtext = subtext; | |
| 319 f:SetChecked( isActive and 1 or 0); | |
| 320 | |
| 321 if autoCastAllowed then | |
| 322 self.acTex:Show(); | |
| 323 else | |
| 324 self.acTex:Hide(); | |
| 325 end | |
| 326 | |
| 327 if autoCastEnabled then | |
| 328 self.acModel:Show(); | |
| 329 else | |
| 330 self.acModel:Hide(); | |
| 331 end | |
| 332 | |
| 333 if texture then | |
| 334 if GetPetActionsUsable() then | |
| 335 SetDesaturation(self.icon,nil) | |
| 336 else | |
| 337 SetDesaturation(self.icon,1) | |
| 338 end | |
| 339 self.icon:Show(); | |
| 340 f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2"); | |
| 341 else | |
| 342 self.icon:Hide(); | |
| 343 f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot"); | |
| 344 end | |
| 345 | |
| 346 self:UpdateCooldown() | |
| 347 end | |
| 348 | |
| 349 function Button:UpdateCooldown() | |
| 350 local start, duration, enable = GetPetActionCooldown(self.frame:GetID()); | |
| 351 CooldownFrame_SetTimer(self.cooldown, start, duration, enable); | |
| 352 end | |
| 353 | |
| 354 function Button:UpdateHotkey() | |
| 355 | |
| 356 end | |
| 122 | 357 |
| 123 -- export as a class-factory to module | 358 -- export as a class-factory to module |
| 124 module.BtnClass = { | 359 module.BtnClass = { |
| 125 new = function(self, ...) | 360 new = function(self, ...) |
| 126 local x = { } | 361 local x = { } |
