Mercurial > wow > reaction
changeset 157:e77f716af1b7
Pushed state rule logic from State.lua to Bar.lua
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Fri, 12 Jun 2009 21:44:44 +0000 |
parents | 611e6ce08717 |
children | d2f289c3bae6 |
files | classes/Bar.lua modules/State.lua |
diffstat | 2 files changed, 204 insertions(+), 170 deletions(-) [+] |
line wrap: on
line diff
--- a/classes/Bar.lua Mon May 18 23:08:34 2009 +0000 +++ b/classes/Bar.lua Fri Jun 12 21:44:44 2009 +0000 @@ -127,6 +127,60 @@ end ]] .. _reaction_refresh +-- For reference +-- the option field names must match the field names of the options table, below +local stateProperties = { + hide = true, + --keybindState = true, TODO: broken + anchorEnable = true, + anchorFrame = true, + anchorPoint = true, + anchorRelPoint = true, + anchorX = true, + anchorY = true, + enableScale = true, + scale = true, + enableAlpha = true, + alpha = true, +} + + +---- Utility functions ---- + +-- traverse a table tree by key list and fetch the result or first nil +local function tfetch(t, ...) + for i = 1, select('#', ...) do + t = t and t[select(i, ...)] + end + return t +end + +-- traverse a table tree by key list and build tree as necessary +local function tbuild(t, ...) + for i = 1, select('#', ...) do + local key = select(i, ...) + if not t[key] then t[key] = { } end + t = t[key] + end + return t +end + +-- return a new array of keys of table 't', sorted by comparing +-- sub-fields (obtained via tfetch) of the table values +local function fieldsort( t, ... ) + local r = { } + for k in pairs(t) do + table.insert(r,k) + end + local path = { ... } + table.sort(r, function(lhs, rhs) + local olhs = tfetch(t[lhs], unpack(path)) or 0 + local orhs = tfetch(t[rhs], unpack(path)) or 0 + return olhs < orhs + end) + return r +end + ---- Bar class ---- local Bar = { } @@ -564,13 +618,29 @@ end end -function Bar:SetStateDriver( rule ) +function Bar:SetStateDriver( states ) + if states then + for state, props in pairs(states) do + self:SetSecureStateData(state, "active_", true) -- make sure there's a 'settings' field for this state + for propname, value in pairs(props) do + if propname == "anchorFrame" then + self:SetFrameRef("anchor-"..state, _G[value]) + elseif propname == "rule" then + -- do nothing + else + self:SetSecureStateData(state, propname, value) + end + end + end + end + local rule = states and self:BuildStateRule(states) if rule then RegisterStateDriver(self:GetFrame(),"reaction",rule) elseif self.statedriver then UnregisterStateDriver(self:GetFrame(),"reaction") end self.statedriver = rule + self:BuildStateKeybinds(states) self:RefreshSecureState() end @@ -589,7 +659,6 @@ self:RefreshSecureState() end --- set a keybind to push a value into "state-reaction" attribute function Bar:SetStateKeybind( key, state ) local f = self:GetFrame() local binds = self.statebinds @@ -604,7 +673,7 @@ end if key then - SetOverrideBinding(f, false, key, state, nil) -- state name is virtual mouse button + SetOverrideBindingClick(f, false, key, f:GetName(), state) -- state name is virtual mouse button end binds[state] = key end @@ -638,3 +707,129 @@ defaultAlpha = self:GetAttribute("defaultAlpha") ]]) end + +---- secure state driver rules ---- + +local playerClass = select(2, UnitClass("player")) +local function ClassFilter(...) + for i = 1, select('#',...) do + if playerClass == select(i,...) then + return false + end + end + return true +end + +local ruleformats = { + stealth = { format = "stealth", filter = ClassFilter("ROGUE","DRUID") }, + nostealth = { format = "nostealth", filter = ClassFilter("ROGUE","DRUID") }, + shadowdance = { format = "bonusbar:2", filter = ClassFilter("ROGUE") }, + shadowform = { format = "form:1", filter = ClassFilter("PRIEST") }, + noshadowform = { format = "noform", filter = ClassFilter("PRIEST") }, + battle = { format = "stance:1", filter = ClassFilter("WARRIOR") }, + defensive = { format = "stance:2", filter = ClassFilter("WARRIOR") }, + berserker = { format = "stance:3", filter = ClassFilter("WARRIOR") }, + caster = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") }, + bear = { format = "form:1", filter = ClassFilter("DRUID") }, + cat = { format = "form:3", filter = ClassFilter("DRUID") }, + tree = { format = "form:5", filter = ClassFilter("DRUID") }, + moonkin = { format = "form:5", filter = ClassFilter("DRUID") }, + pet = { format = "pet" }, + nopet = { format = "nopet" }, + harm = { format = "target=target,harm" }, + help = { format = "target=target,help" }, + notarget = { format = "target=target,noexists" }, + focusharm = { format = "target=focus,harm" }, + focushelp = { format = "target=focus,help" }, + nofocus = { format = "target=focus,noexists" }, + raid = { format = "group:raid" }, + party = { format = "group:party" }, + solo = { format = "nogroup" }, + combat = { format = "combat" }, + nocombat = { format = "nocombat" }, + possess = { format = "target=vehicle,noexists,bonusbar:5" }, + vehicle = { format = "target=vehicle,exists,bonusbar:5" }, +} + +function Bar.InitRuleFormats() + local forms = { } + for i = 1, GetNumShapeshiftForms() do + local _, name = GetShapeshiftFormInfo(i) + forms[name] = i; + end + -- use 9 if not found since 9 is never a valid stance/form + local defensive = forms[GetSpellInfo(71)] or 9 + local berserker = forms[GetSpellInfo(2458)] or 9 + local bear = forms[GetSpellInfo(9634)] or forms[GetSpellInfo(5487)] or 9 + local aquatic = forms[GetSpellInfo(1066)] or 9 + local cat = forms[GetSpellInfo(768)] or 9 + local travel = forms[GetSpellInfo(783)] or 9 + local tree = forms[GetSpellInfo(33891)] or 9 + local moonkin = forms[GetSpellInfo(24858)] or 9 + local flight = forms[GetSpellInfo(40120)] or forms[GetSpellInfo(33943)] or 9 + + ruleformats.defensive.format = "stance:"..defensive + ruleformats.berserker.format = "stance:"..berserker + ruleformats.caster.format = format("form:0/%d/%d/%d", aquatic, travel, flight) + ruleformats.bear.format = "form:"..bear + ruleformats.cat.format = "form:"..cat + ruleformats.tree.format = "form:"..tree + ruleformats.moonkin.format = "form:"..moonkin +end + +function Bar:BuildStateRule(states) + -- states is a table : + -- states[statename].rule = { + -- order = #, + -- type = "default"/"custom"/"any"/"all", + -- values = { ... }, -- keys of ruleformats[] + -- custom = "...", + -- } + local rules = { } + local default + + for idx, state in ipairs(fieldsort(states, "rule", "order")) do + local c = states[state].rule + local type = c.type + if type == "default" then + default = default or state + elseif type == "custom" then + if c.custom then + -- strip out all spaces from the custom rule + table.insert(rules, format("%s %s", c.custom:gsub("%s",""), state)) + end + elseif type == "any" or type == "all" then + if c.values then + local clauses = { } + for key, value in pairs(c.values) do + if ruleformats[key] and not ruleformats[key].filter then + table.insert(clauses, ruleformats[key].format) + end + end + if #clauses > 0 then + local sep = (type == "any") and "][" or "," + table.insert(rules, format("[%s] %s", table.concat(clauses,sep), state)) + end + end + end + end + -- make sure that the default, if any, is last + if default then + table.insert(rules, default) + end + return table.concat(rules,";") +end + +function Bar:BuildStateKeybinds( states ) + if states then + for name, state in pairs(states) do + local rule = tfetch(state, "rule") + if rule and rule.type == "keybind" then + self:SetStateKeybind(rule.keybind, name) + else + self:SetStateKeybind(nil, name) -- this clears an existing keybind + end + end + end +end +
--- a/modules/State.lua Mon May 18 23:08:34 2009 +0000 +++ b/modules/State.lua Fri Jun 12 21:44:44 2009 +0000 @@ -54,148 +54,10 @@ end -local InitRules, ApplyStates, CleanupStates, SetProperty, GetProperty, RegisterProperty +local ApplyStates, CleanupStates, SetProperty, GetProperty, RegisterProperty -- PRIVATE -- do - - -- the field names must match the field names of the options table, below - -- the field values are secure snippets or 'true' to skip the snippet for that property. - local properties = { - hide = true, - --keybindState = true, TODO: broken - anchorEnable = true, - anchorFrame = true, - anchorPoint = true, - anchorRelPoint = true, - anchorX = true, - anchorY = true, - enableScale = true, - scale = true, - enableAlpha = true, - alpha = true, - } - - local playerClass = select(2, UnitClass("player")) - local function ClassFilter(...) - for i = 1, select('#',...) do - if playerClass == select(i,...) then - return false - end - end - return true - end - - -- As far as I can tell the macro clauses are NOT locale-specific. - -- 'filter' specifies whether rules should be omitted from execution. - -- 'true' indicates they should be filtered out. - local ruleformats = { - stealth = { format = "stealth", filter = ClassFilter("ROGUE","DRUID") }, - nostealth = { format = "nostealth", filter = ClassFilter("ROGUE","DRUID") }, - shadowform = { format = "form:1", filter = ClassFilter("PRIEST") }, - noshadowform = { format = "noform", filter = ClassFilter("PRIEST") }, - battle = { format = "stance:1", filter = ClassFilter("WARRIOR") }, - defensive = { format = "stance:2", filter = ClassFilter("WARRIOR") }, - berserker = { format = "stance:3", filter = ClassFilter("WARRIOR") }, - caster = { format = "form:0/2/4/5/6", filter = ClassFilter("DRUID") }, - bear = { format = "form:1", filter = ClassFilter("DRUID") }, - cat = { format = "form:3", filter = ClassFilter("DRUID") }, - tree = { format = "form:5", filter = ClassFilter("DRUID") }, - moonkin = { format = "form:5", filter = ClassFilter("DRUID") }, - pet = { format = "pet" }, - nopet = { format = "nopet" }, - harm = { format = "target=target,harm" }, - help = { format = "target=target,help" }, - notarget = { format = "target=target,noexists" }, - focusharm = { format = "target=focus,harm" }, - focushelp = { format = "target=focus,help" }, - nofocus = { format = "target=focus,noexists" }, - raid = { format = "group:raid" }, - party = { format = "group:party" }, - solo = { format = "nogroup" }, - combat = { format = "combat" }, - nocombat = { format = "nocombat" }, - possess = { format = "bonusbar:5" }, - vehicle = { format = "target=vehicle,exists,bonusbar:5" }, - } - - -- Determine the stance #'s programmatically: they can vary if for some reason the - -- player is missing a stance/form (due to not training it). Also moonkin/flight/tree form - -- can be stance 5 or 6, depending. - function InitRules() - local forms = { } - for i = 1, GetNumShapeshiftForms() do - local _, name = GetShapeshiftFormInfo(i) - forms[name] = i; - end - -- use 9 if not found since 9 is never a valid stance/form - local defensive = forms[GetSpellInfo(71)] or 9 - local berserker = forms[GetSpellInfo(2458)] or 9 - local bear = forms[GetSpellInfo(9634)] or forms[GetSpellInfo(5487)] or 9 - local aquatic = forms[GetSpellInfo(1066)] or 9 - local cat = forms[GetSpellInfo(768)] or 9 - local travel = forms[GetSpellInfo(783)] or 9 - local tree = forms[GetSpellInfo(33891)] or 9 - local moonkin = forms[GetSpellInfo(24858)] or 9 - local flight = forms[GetSpellInfo(40120)] or forms[GetSpellInfo(33943)] or 9 - - ruleformats.defensive.format = format("stance:%d",defensive) - ruleformats.berserker.format = format("stance:%d",berserker) - ruleformats.caster.format = format("form:0/%d/%d/%d", aquatic, travel, flight) - ruleformats.bear.format = format("form:%d",bear) - ruleformats.cat.format = format("form:%d",cat) - ruleformats.tree.format = format("form:%d",tree) - ruleformats.moonkin.format = format("form:%d",moonkin) - end - - local function BuildRule(states) - local rules = { } - local default - - for idx, state in ipairs(fieldsort(states, "rule", "order")) do - local c = states[state].rule - local type = c.type - if type == "default" then - default = default or state - elseif type == "custom" then - if c.custom then - -- strip out all spaces from the custom rule - table.insert(rules, format("%s %s", c.custom:gsub("%s",""), state)) - end - elseif type == "any" or type == "all" then - if c.values then - local clauses = { } - for key, value in pairs(c.values) do - if ruleformats[key] and not ruleformats[key].filter then - table.insert(clauses, ruleformats[key].format) - end - end - if #clauses > 0 then - local sep = (type == "any") and "][" or "," - table.insert(rules, format("[%s] %s", table.concat(clauses,sep), state)) - end - end - end - end - -- make sure that the default, if any, is last - if default then - table.insert(rules, default) - end - return table.concat(rules,";") - end - - local function BuildKeybinds( bar, states ) - for name, state in pairs(states) do - local type = tfetch(state, "rule", "type") - if type == "keybind" then - local key = tfetch(state, "rule", "keybind") - bar:SetStateKeybind(key, name) - else - bar:SetStateKeybind(nil, name) -- this clears an existing keybind - end - end - end - function GetProperty( bar, state, propname ) return tfetch(module.db.profile.bars, bar:GetName(), "states", state, propname) end @@ -207,49 +69,25 @@ end function RegisterProperty( propname, snippet ) - properties[propname] = true for _, bar in ReAction:IterateBars() do - local states = tfetch(module.db.profile.bars, bar:GetName(), "states") - if states then - for name, s in pairs(states) do - bar:SetSecureStateData(name, propname, s[propname]) - end - bar:SetStateDriver(BuildRule(states)) - end if type(snippet) == "string" then bar:SetSecureStateExtension(propname,snippet) end + ApplyStates(bar) end end function UnregisterProperty( propname ) - properties[propname] = nil for _, bar in ReAction:IterateBars() do - local states = tfetch(module.db.profile.bars, bar:GetName(), "states") - if states then - for name, s in pairs(states) do - bar:SetSecureStateData(name, propname, nil) - end - end - bar:SetStateDriver(BuildRule(states)) bar:SetSecureStateExtension(propname,nil) + ApplyStates(bar) end end function ApplyStates( bar ) local states = tfetch(module.db.profile.bars, bar:GetName(), "states") if states then - for propname in pairs(properties) do - for name, s in pairs(states) do - if propname == "anchorFrame" then - bar:SetFrameRef("anchor-"..name, _G[s.anchorFrame]) - else - bar:SetSecureStateData(name, propname, s[propname]) - end - end - end - BuildKeybinds(bar, states) - bar:SetStateDriver(BuildRule(states)) + bar:SetStateDriver(states) end end @@ -290,7 +128,7 @@ -- Re-parse the rules table according to the new form list. -- This happens both at initial login (after PLAYER_ENTERING_WORLD) -- as well as when gaining new abilities. - InitRules() + ReAction.Bar.InitRuleFormats() for _, bar in ReAction:IterateBars() do ApplyStates(bar) end @@ -855,7 +693,7 @@ function StateHandler:SetAnchorFrame(info, value) local f = _G[self._anchorframes[value]] if f then - bar:SetFrameRef("anchor-"..self:GetName(), f) + self.bar:SetFrameRef("anchor-"..self:GetName(), f) self:SetProp(info, f:GetName()) end end