# HG changeset patch # User Flick # Date 1250828109 0 # Node ID d0a41fc7b0d79d19d7d6862ea9ff8a662968f444 # Parent caec78119a17ee597b62b7d25fd8b4c0c237d54e Totem bar support diff -r caec78119a17 -r d0a41fc7b0d7 classes/ActionButton.lua --- a/classes/ActionButton.lua Sat Aug 08 00:04:04 2009 +0000 +++ b/classes/ActionButton.lua Fri Aug 21 04:15:09 2009 +0000 @@ -372,8 +372,7 @@ end function Action:UpdateIcon() - local action = self.actionID - local texture = GetActionTexture(action) + local texture, tLeft, tRight, tTop, tBottom = self:GetIconTexture() local icon = self.frames.icon local hotkey = self.frames.hotkey local f = self:GetFrame() @@ -388,6 +387,9 @@ if texture then icon:SetTexture(texture) + if tLeft then + icon:SetTexCoord(tLeft,tRight,tTop,tBottom) + end icon:Show() self.rangeTimer = -1 f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2") @@ -399,6 +401,10 @@ end end +function Action:GetIconTexture() + return GetActionTexture(self.actionID) +end + function Action:UpdateBorder() local action = self.actionID if ReAction:GetKeybindMode() then @@ -456,8 +462,8 @@ end function Action:UpdateUsable() - local isUsable, notEnoughMana = IsUsableAction(self.actionID) - local noRange = IsActionInRange(self.actionID) == 0 + local isUsable, notEnoughMana = self:GetUsable() + local noRange = self:GetInRange() isUsable = self.vehicleExitMode or (isUsable and not noRange) @@ -488,8 +494,20 @@ end end +function Action:GetUsable() + return IsUsableAction(self.actionID) +end + +function Action:GetInRange() + return IsActionInRange(self.actionID) == 0 +end + function Action:UpdateCooldown() - CooldownFrame_SetTimer(self.frames.cooldown, GetActionCooldown(self.actionID)) + CooldownFrame_SetTimer(self.frames.cooldown, self:GetCooldown()) +end + +function Action:GetCooldown() + return GetActionCooldown(self.actionID) end function Action:UpdateFlash() @@ -657,7 +675,9 @@ end function Action:OnAttributeChanged( attr, value ) - self:UpdateAction() + if attr ~= "statehidden" then + self:UpdateAction() + end end function Action:PostClick( ) diff -r caec78119a17 -r d0a41fc7b0d7 classes/MultiCastButton.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/classes/MultiCastButton.lua Fri Aug 21 04:15:09 2009 +0000 @@ -0,0 +1,639 @@ +local ReAction = ReAction +local L = ReAction.L +local _G = _G +local CreateFrame = CreateFrame +local format = string.format +local unpack = unpack +local GetCVar = GetCVar +local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor +local CooldownFrame_SetTimer = CooldownFrame_SetTimer +local InCombatLockdown = InCombatLockdown +local IsUsableSpell = IsUsableSpell +local IsUsableAction = IsUsableAction +local IsSpellKnown = IsSpellKnown +local IsSpellInRange = IsSpellInRange +local IsActionInRange = IsActionInRange +local GetSpellInfo = GetSpellInfo +local GetSpellCooldown = GetSpellCooldown +local GetActionCooldown = GetActionCooldown +local GetSpellTexture = GetSpellTexture +local GetActionTexture = GetActionTexture +local GetMultiCastTotemSpells = GetMultiCastTotemSpells + +ReAction:UpdateRevision("$Revision: 154 $") + + +--[[ + Blizzard Constants: + - NUM_MULTI_CAST_BUTTONS_PER_PAGE = 4 + - NUM_MULTI_CAST_PAGES = 3 + - TOTEM_PRIORITIES = { } -- sets the order of the totems + - TOTEM_MULTI_CAST_SUMMON_SPELLS = { } -- list of summon spellIDs + - TOTEM_MULTI_CAST_RECALL_SPELLS = { } -- list of recall spellIDs + + Blizzard Events: + - UPDATE_MULTI_CAST_ACTIONBAR + + Blizzard APIs: + - GetMultiCastBarOffset() : returns 6 + + - SetMultiCastSpell(actionID, spellID) (protected) OR + SetAttribute("type","multispell") + SetAttribute("action",actionID) + SetAttribute("spell",spellID) + + note: multicast actionID page is NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset(), + so that's action ID 132-144. + + - spell1, spell2, spell3, ... = GetMultiCastTotemSpells(slot) + returns spellIDs for all totems that fit that slot. + Note this is available in the secure environment, but because IsSpellKnown() is not, + it makes it pretty much useless. + + Blizzard textures: + All the textures for the multicast bar (arrows, empty-slot icons, etc) are part of a single + texture: each texture uses SetTexCoord() to display only a slice of the textures. I suppose + this is to slightly optimize texture load performance, but it makes the UI code more clumsy. + + Each totem button and arrow has a colored border indicating its elemental type. + TODO: update code to use these pretty per-slot icons, or start setting a border. + + Design Notes: + - Only the header has a secure context. All other frames execute in its context. + + - Each button is either type "spell" (summon/recall) or type "action" (totem action IDs are + GetBonusBarOffset()=6, 132-144) with 3 pages of 4 buttons. The paging is controlled by + the summon flyout, which is also paged with the summon spells (the recall button is not paged) + + - A spell list is updated in the secure context at setup time (TODO: redo setup when learning new + spells) with the list of spells known for each slot. + + - Each button (except recall) has an arrow button which appears on mouseover and when clicked + opens the flyout via a wrapped OnClick handler. When the flyout is open, the arrow does not + appear. + TODO: add an alt-button ("SHOWMULTICASTFLYOUT") statemachine to the bar to listen for alt key + presses and open/close the bar. Tapping the alt key toggles the flyout. + + - A single flyout with N+1 (1 slot is to select no totem for the set) flyout-buttons is a child + of the bar. Each time the flyout panel is opened, the individual buttons grab their corresponding + spell/type from the list, according to the slot which opened the flyout. Each button either sets + the current page (summon) or sets a multispell to an actionID via type="multispell". None of them + actually cast any spells (though, I suppose we could modify this so that e.g. configurable + right-click casts the spell). The flyout also has a close button which closes the flyout: the + flyout-open code positions the close button anchored to the last button in the flyout (which + changes dynamically because each slot has a different number of items in the list). + + - Multicast sets are not stances, there's no need (or ability) to handle swapping sets if one of + the summon spells is cast from elsewhere. Additionally, in the default UI Call of the Elements + always appears as the active summon when the UI is loaded, which is bad design that could be improved + upon. TODO: Store state in a config variable and restore it at load time. + + +]]-- + + +-- +-- Secure snippets +-- + +-- bar +local _bar_init = -- function(self) +[[ + -- set up some globals in the secure environment + flyout = self:GetFrameRef("flyout") + flyoutChildren = newtable() + nMultiCastSlots = self:GetAttribute("nMultiCastSlots") + baseActionID = self:GetAttribute("baseActionID") + currentMultiCastPage = currentMultiCastPage or 1 + multiCastSpellList = newtable() + for i = 1, nMultiCastSlots do + tinsert(multiCastSpellList, newtable()) + end +]] + +local _onstate_multispellpage = -- function(self, stateid, newstate) +[[ + currentMultiCastPage = tonumber(newstate) + control:ChildUpdate() +]] + + +-- buttons +local _childupdate = -- function(self, snippetid, message) +[[ + if self:GetAttribute("type") == "spell" then + self:SetAttribute("spell", self:GetAttribute("spell-page"..currentMultiCastPage)) + elseif self:GetAttribute("type") == "action" then + self:SetAttribute("action", self:GetAttribute("action-page"..currentMultiCastPage)) + end +]] + +local _onEnter = -- function(self) + -- for whatever reason, RegisterAutoHide is unreliable + -- unless you re-anchor the frame prior to calling it. + -- Even then, it's still not terribly reliable. +[[ + local idx = self:GetAttribute("bar-idx") + if not (flyout:IsVisible() and flyoutIdx == idx) then + local arrow = owner:GetFrameRef("arrow-"..idx) + if arrow and not arrow:IsShown() then + arrow:ClearAllPoints() + arrow:SetPoint("BOTTOM",self,"TOP",0,0) -- TODO: better anchoring + arrow:Show() + arrow:RegisterAutoHide(0) + arrow:AddToAutoHide(self) + end + end +]] + +local _onLeave = -- function(self) + -- to increase reliability (somewhat), re-register it for hide on leave +[[ + local arrow = owner:GetFrameRef("arrow-"..self:GetAttribute("bar-idx")) + if arrow then + arrow:RegisterAutoHide(0) + arrow:AddToAutoHide(self) + end +]] + + +-- flyout arrow +local _arrow_openFlyout = -- function(self) +[[ + local currentMultiCastSlot = self:GetAttribute("bar-idx") + local lastButton, lastIdx + for idx, b in ipairs(flyoutChildren) do + b:Hide() -- force the OnShow handler to run later + local spellID = multiCastSpellList[currentMultiCastSlot][idx] + if spellID then + b:SetAttribute("spell",spellID) -- does passing 0 work for no-totem? Do we have to convert to nil? + if currentMultiCastSlot == 1 then + b:SetAttribute("type","changePage") + else + b:SetAttribute("type","multispell") + local totemID = owner:GetAttribute("TOTEM_PRIORITY_"..(currentMultiCastSlot - 1)) + b:SetAttribute("action", baseActionID + (currentMultiCastPage - 1)*(nMultiCastSlots-2) + totemID) + end + b:Show() + lastButton = b + lastIdx = idx + end + end + + local close = owner:GetFrameRef("close") + if lastButton and close then + close:ClearAllPoints() + close:SetPoint("BOTTOM",lastButton,"TOP",0,0) -- TODO: better anchoring + close:Show() + end + + flyout:ClearAllPoints() + flyout:SetPoint("BOTTOM",self,"BOTTOM",0,0) -- TODO: better anchoring + if lastIdx then + flyout:SetHeight(lastIdx * 27 + (close and close:GetHeight() or 0)) + end + flyout:Show() + flyout:RegisterAutoHide(1) -- TODO: configurable + flyout:AddToAutoHide(owner) + flyoutIdx = currentMultiCastSlot + self:Hide() +]] + +local _closeFlyout = -- function(self) +[[ + flyout:Hide() +]] + + +-- flyout child buttons +local _flyout_child_preClick = -- function(self, button, down) +[[ + local button = button + if self:GetAttribute("type") == "changePage" then + owner:SetAttribute("state-multispellpage",self:GetAttribute("index")) + self:GetParent():Hide() + return false + else + return nil, "close" + end +]] + +local _flyout_child_postClick = -- function(self, message, button, down) +[[ + if message == "close" then + self:GetParent():Hide() -- hide flyout after selecting + end +]] + + +-- +-- The Blizzard totem bar textures are all actually one big texture, +-- with texcoord offsets +-- +local TOTEM_TEXTURE = "Interface\\Buttons\\UI-TotemBar" +local FLYOUT_UP_BUTTON_TCOORDS = { 99/128, 127/128, 84/256, 102/256 } +local FLYOUT_UP_BUTTON_HL_TCOORDS = { 72/128, 92/128, 88/256, 98/256 } +local FLYOUT_DOWN_BUTTON_TCOORDS = { 99/128, 127/128, 65/256, 83/256 } +local FLYOUT_DOWN_BUTTON_HL_TCOORDS = { 72/128, 92/128, 69/256, 79/256 } +local EMPTY_SLOT_TCOORDS = { 66/128, 96/128, 3/256, 33/256 } + +local eventList = { + -- TODO + "PLAYER_REGEN_ENABLED", + "PLAYER_ENTERING_WORLD", + "ACTIONBAR_PAGE_CHANGED", + "ACTIONBAR_SLOT_CHANGED", + "UPDATE_BINDINGS", + "ACTIONBAR_UPDATE_STATE", + "ACTIONBAR_UPDATE_USABLE", + "ACTIONBAR_UPDATE_COOLDOWN", + "UPDATE_INVENTORY_ALERTS", + "PLAYER_TARGET_CHANGED", + "TRADE_SKILL_SHOW", + "TRADE_SKILL_CLOSE", + "PLAYER_ENTER_COMBAT", + "PLAYER_LEAVE_COMBAT", + "START_AUTOREPEAT_SPELL", + "STOP_AUTOREPEAT_SPELL", + "UNIT_ENTERED_VEHICLE", + "UNIT_EXITED_VEHICLE", + "COMPANION_UPDATE", + "UPDATE_MULTI_CAST_ACTIONBAR", +} + +-- +-- MultiCast Button class +-- Inherits implementation methods from Action button class, but circumvents the constructor +-- and redefines/removes some methods. +-- +local Super = ReAction.Button +local Action = ReAction.Button.Action +local MultiCast = setmetatable( { }, { __index = Action } ) +ReAction.Button.MultiCast = MultiCast + +function MultiCast:New( idx, btnConfig, bar ) + if idx < 1 or idx > NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then + error("Multicast button index out of range") + end + + local name = format("ReAction_%s_Action_%d",bar:GetName(),idx) + + self = Super.New(self, name, btnConfig, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" ) + + local barFrame = bar:GetFrame() + local f = self:GetFrame() + + -- attributes + if idx == 1 or idx == NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then + f:SetAttribute("type","spell") + local spells = idx == 1 and TOTEM_MULTI_CAST_SUMMON_SPELLS or TOTEM_MULTI_CAST_RECALL_SPELLS + for i, spell in ipairs(spells) do + if spell and IsSpellKnown(spell) then + f:SetAttribute("spell-page"..i, spell) + if i == 1 then + -- TODO: store/restore last used summon + f:SetAttribute("spell",spell) + end + end + end + else + local baseAction = barFrame:GetAttribute("baseActionID") + TOTEM_PRIORITIES[idx-1] + f:SetAttribute("type","action") + f:SetAttribute("action", baseAction) + for i = 1, NUM_MULTI_CAST_PAGES do + f:SetAttribute("action-page"..i, baseAction + (i-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE) + end + end + f:SetAttribute("bar-idx",idx) + barFrame:SetFrameRef("slot-"..idx,f) + + -- non secure scripts + f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end) + f:SetScript("OnEnter", function(frame) self:OnEnter() end) + f:SetScript("OnLeave", function(frame) self:OnLeave() end) + f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end) + f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end) + + -- secure handlers + if idx ~= NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then + f:SetAttribute("_childupdate",_childupdate) + end + barFrame:WrapScript(f, "OnEnter", _onEnter) + + -- event registration + f:EnableMouse(true) + f:RegisterForClicks("AnyUp") + for _, evt in pairs(eventList) do + f:RegisterEvent(evt) + end + + -- attach to skinner + bar:SkinButton(self) + + f:Show() + + -- open arrow + if idx ~= NUM_MULTI_CAST_BUTTONS_PER_PAGE + 2 then + local arrow = CreateFrame("Button", nil, f, "SecureFrameTemplate") + arrow:SetWidth(28) + arrow:SetHeight(12) + arrow:SetPoint("BOTTOM",self:GetFrame(),"TOP",0,0) -- TODO: better anchoring + arrow:SetNormalTexture(TOTEM_TEXTURE) + arrow:GetNormalTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_TCOORDS) ) + arrow:SetHighlightTexture(TOTEM_TEXTURE) + arrow:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_UP_BUTTON_HL_TCOORDS) ) + arrow:SetAttribute("bar-idx",idx) + arrow:Hide() + barFrame:WrapScript(arrow, "OnClick", _arrow_openFlyout) + local arrowRef = "arrow-"..idx + barFrame:SetFrameRef(arrowRef,arrow) + end + + self:Refresh() + + return self +end + +function MultiCast:Destroy() + local barFrame = self:GetFrame() + Super.Destroy(self) +end + +function MultiCast:Refresh() + Super.Refresh(self) + self:UpdateAction() +end + +function MultiCast:ShowGrid( show ) +end + +function MultiCast:ShowGridTemp( show ) +end + +function MultiCast:AcquireActionID() +end + +function MultiCast:ReleaseActionID() +end + +function MultiCast:UpdateShowGrid() +end + +function MultiCast:UpdateBorder() +end + +function MultiCast:UpdateMacroText() +end + +function MultiCast:UpdateCount() +end + +function MultiCast:UpdateCheckedState() + local action = self:GetActionID() + if action and IsCurrentAction(action) then + self:GetFrame():SetChecked(1) + else + self:GetFrame():SetChecked(0) + end +end + +function MultiCast:RefreshHasActionAttributes() +end + +function MultiCast:UpdateFlash() +end + +function MultiCast:GetIconTexture() + local tx + if self.spellID then + tx = GetSpellTexture(GetSpellInfo(self.spellID)) + elseif self.actionID then + tx = GetActionTexture(self.actionID) + end + if tx then + return tx + else + return TOTEM_TEXTURE, unpack(EMPTY_SLOT_TCOORDS) + end +end + +function MultiCast:UpdateAction() + local action = self:GetActionID() + if action then + if action ~= self.actionID then + self.actionID = action + self:UpdateAll() + end + else + local spellID = self:GetSpellID() + if spellID ~= self.spellID then + self.spellID = spellID + self:UpdateAll() + end + end +end + +function MultiCast:GetActionID(page) + return self:GetFrame():GetAttribute("action") +end + +function MultiCast:GetSpellID(page) + return self:GetFrame():GetAttribute("spell") +end + +function MultiCast:SetActionID( id ) + error("Can not set action ID of multicast buttons") +end + +function MultiCast:SetTooltip() + local barFrame = self:GetFrame() + if GetCVar("UberTooltips") == "1" then + GameTooltip_SetDefaultAnchor(GameTooltip, barFrame) + else + GameTooltip:SetOwner(barFrame) + end + if self.spellID then + GameTooltip:SetSpellByID(self.spellID,false,true) + elseif self.actionID then + GameTooltip:SetAction(self.actionID) + end +end + +function MultiCast:GetUsable() + if self.spellID then + return IsUsableSpell((GetSpellInfo(self.spellID))) + elseif self.actionID then + return IsUsableAction(self.actionID) + end +end + +function MultiCast:GetInRange() + if self.spellID then + return IsSpellInRange((GetSpellInfo(self.spellID))) == 0 + elseif self.actionID then + return IsActionInRange(self.actionID) == 0 + end +end + +function MultiCast:GetCooldown() + if self.spellID then + return GetSpellCooldown((GetSpellInfo(self.spellID))) + elseif self.actionID then + return GetActionCooldown(self.actionID) + else + return 0, 0, 0 + end +end + +function MultiCast:UPDATE_MULTI_CAST_ACTIONBAR() + self:UpdateAll() +end + + +-- +-- flyout setup +-- +local function ShowFlyoutTooltip(barFrame) + if GetCVar("UberTooltips") == "1" then + GameTooltip_SetDefaultAnchor(GameTooltip, barFrame) + else + GameTooltip:SetOwner(barFrame) + end + local spell = barFrame:GetAttribute("spell") + if barFrame == 0 then + GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b) + else + GameTooltip:SetSpellByID(barFrame:GetAttribute("spell"),false,true) + end +end + +local function HideFlyoutTooltip() + GameTooltip:Hide() +end + +local function UpdateFlyoutIcon(frame) + local spellID = frame:GetAttribute("spell") + if spellID == 0 then + frame.icon:SetTexture(TOTEM_TEXTURE) + frame.icon:SetTexCoord( unpack(EMPTY_SLOT_TCOORDS) ) + elseif spellID then + frame.icon:SetTexture(GetSpellTexture(GetSpellInfo(spellID))) + frame.icon:SetTexCoord(0,1,0,1) + end +end + +function MultiCast.SetupBarHeader( bar ) -- call this as a static method + local summon = { } + local recall = { } + local maxIdx = 1 + + for idx, spell in ipairs(TOTEM_MULTI_CAST_SUMMON_SPELLS) do + if spell and IsSpellKnown(spell) then + tinsert(summon,spell) + maxIdx = max(idx,maxIdx) + end + end + + for idx, spell in ipairs(TOTEM_MULTI_CAST_RECALL_SPELLS) do + if spell and IsSpellKnown(spell) then + tinsert(recall,spell) + maxIdx = max(idx,maxIdx) + end + end + + if #summon == 0 and #recall == 0 then + return 0 -- no multicast capability + end + + local slots = { } + + tinsert(slots, summon) + + for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do + local slotSpells = { 0, GetMultiCastTotemSpells(TOTEM_PRIORITIES[i]) } + maxIdx = max(maxIdx, #slotSpells) + tinsert(slots,slotSpells) + end + + tinsert(slots, recall) + + local barFrame = bar:GetFrame() + + -- init bar secure environment + barFrame:SetAttribute("nMultiCastSlots",#slots) + barFrame:SetAttribute("baseActionID", (NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset() - 1)*NUM_ACTIONBAR_BUTTONS) + barFrame:SetAttribute("_onstate-multispellpage", _onstate_multispellpage) + barFrame:Execute(_bar_init) + + for i, p in ipairs(TOTEM_PRIORITIES) do + barFrame:SetAttribute("TOTEM_PRIORITY_"..i,p) + end + + -- create flyout container frame and close arrow + local flyout = bar._flyoutFrame + if not flyout then + flyout = CreateFrame("Frame", nil, barFrame, "SecureFrameTemplate") + bar._flyoutFrame = flyout + barFrame:SetFrameRef("flyout",flyout) + flyout.buttons = { } + flyout:Hide() + flyout:SetWidth(24) + flyout:SetHeight(1) + flyout:SetPoint("BOTTOM",barFrame,"TOP",0,0) + + local close = CreateFrame("Button", nil, flyout, "SecureFrameTemplate") + close:SetWidth(28) + close:SetHeight(12) + close:SetPoint("TOP") + close:SetNormalTexture(TOTEM_TEXTURE) + close:GetNormalTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_TCOORDS) ) + close:SetHighlightTexture(TOTEM_TEXTURE) + close:GetHighlightTexture():SetTexCoord( unpack(FLYOUT_DOWN_BUTTON_HL_TCOORDS) ) + barFrame:SetFrameRef("close",close) + barFrame:WrapScript(close, "OnClick", _closeFlyout) + end + + -- create flyout buttons + for i = #flyout.buttons + 1, maxIdx do + local b = CreateFrame("Button",nil,flyout,"SecureActionButtonTemplate") + b:SetWidth(24) + b:SetHeight(24) + local prev = flyout.buttons[i-1] + b:SetPoint("BOTTOM", prev or flyout, prev and "TOP" or "BOTTOM", 0, 3) -- TODO: better anchoring + b.icon = b:CreateTexture("BACKGROUND") + b.icon:SetAllPoints() + b.icon:Show() + b:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square") + b:GetHighlightTexture():SetBlendMode("ADD") + b:RegisterForClicks("AnyUp") + b:SetScript("OnShow",UpdateFlyoutIcon) + b:SetScript("OnEnter",ShowFlyoutTooltip) + b:SetScript("OnLeave",HideFlyoutTooltip) + b:SetAttribute("index",i) + b:Show() + barFrame:WrapScript(b, "OnClick", _flyout_child_preClick, _flyout_child_postClick) + flyout.buttons[i] = b + end + + for i, b in ipairs(flyout.buttons) do + barFrame:SetFrameRef("flyout-child",b) + barFrame:Execute([[ + tinsert(flyoutChildren,self:GetFrameRef("flyout-child")) + ]]) + end + + -- transfer the table of spell IDs into the secure environment + for i, spells in ipairs(slots) do + barFrame:SetAttribute("spell-slot", i) + for j, spell in ipairs(spells) do + barFrame:SetAttribute("spell-index", j) + barFrame:SetAttribute("spell-id", spell) + barFrame:Execute([[ + multiCastSpellList[self:GetAttribute("spell-slot")][self:GetAttribute("spell-index")] = self:GetAttribute("spell-id") + ]]) + end + end + + return #slots +end + diff -r caec78119a17 -r d0a41fc7b0d7 classes/classes.xml --- a/classes/classes.xml Sat Aug 08 00:04:04 2009 +0000 +++ b/classes/classes.xml Fri Aug 21 04:15:09 2009 +0000 @@ -11,5 +11,6 @@