--[[-------------------------------------------------------------------- Ovale Spell Priority Copyright (C) 2009, 2010, 2011, 2012 Sidoine Copyright (C) 2012, 2013, 2014 Johnny C. Lam This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License in the LICENSE file accompanying this program. --]]-------------------------------------------------------------------- local addonName, Ovale = ... -- do -- local AceGUI = LibStub("AceGUI-3.0") local Masque = LibStub("Masque", true) local OvaleBestAction = Ovale.OvaleBestAction local OvaleCompile = Ovale.OvaleCompile local OvaleCondition = Ovale.OvaleCondition local OvaleCooldown = Ovale.OvaleCooldown local OvaleGUID = Ovale.OvaleGUID local OvaleOptions = Ovale.OvaleOptions local OvaleState = Ovale.OvaleState local OvaleTimeSpan = Ovale.OvaleTimeSpan local Type = addonName .. "Frame" local Version = 7 local pairs = pairs local tostring = tostring local wipe = table.wipe local API_CreateFrame = CreateFrame local API_GetSpellInfo = GetSpellInfo local API_GetSpellTexture = GetSpellTexture local API_GetTime = GetTime local API_RegisterStateDriver = RegisterStateDriver local NextTime = OvaleTimeSpan.NextTime -- -- local function frameOnClose(self) self.obj:Fire("OnClose") end local function closeOnClick(self) self.obj:Hide() end local function frameOnMouseDown(self) if (not OvaleOptions:GetProfile().apparence.verrouille) then self:StartMoving() AceGUI:ClearFocus() end end local function ToggleOptions(self) if (self.content:IsShown()) then self.content:Hide() else self.content:Show() end end local function frameOnMouseUp(self) self:StopMovingOrSizing() local profile = OvaleOptions:GetProfile() if (profile.left~=self:GetLeft() or profile.top ~=self:GetTop()) then profile.left = self:GetLeft() profile.top = self:GetTop() end end local function frameOnEnter(self) if (not OvaleOptions:GetProfile().apparence.verrouille) then self.obj.barre:Show() end end local function frameOnLeave(self) self.obj.barre:Hide() end local function frameOnUpdate(self) self.obj:OnUpdate() end local function Hide(self) self.frame:Hide() end local function Show(self) self.frame:Show() end local function OnAcquire(self) self.frame:SetParent(UIParent) end local function OnRelease(self) end local function OnWidthSet(self, width) local content = self.content local contentwidth = width - 34 if contentwidth < 0 then contentwidth = 0 end content:SetWidth(contentwidth) content.width = contentwidth end local function OnHeightSet(self, height) local content = self.content local contentheight = height - 57 if contentheight < 0 then contentheight = 0 end content:SetHeight(contentheight) content.height = contentheight end local function OnLayoutFinished(self, width, height) if (not width) then width = self.content:GetWidth() end self.content:SetWidth(width) self.content:SetHeight(height+50) end local function GetScore(self, spellId) for k,action in pairs(self.actions) do if action.spellId == spellId then if not action.waitStart then -- print("sort "..spellId.." parfait") return 1 else local now = API_GetTime() local lag = now - action.waitStart if lag>5 then -- print("sort "..spellId.." ignoré (>5s)") return nil elseif lag>1.5 then -- print("sort "..spellId.." trop lent !") return 0 elseif lag>0 then -- print("sort "..spellId.." un peu lent "..lag) return 1-lag/1.5 else -- print("sort "..spellId.." juste bon") return 1 end end end end -- print("sort "..spellId.." incorrect") return 0 end local function OnUpdate(self) -- Update current time. local now = API_GetTime() local profile = OvaleOptions:GetProfile() -- Force a refresh if we've exceeded the minimum update interval since the last refresh. local forceRefresh = not self.lastUpdate or (now > self.lastUpdate + profile.apparence.updateInterval) -- Refresh the icons if we're forcing a refresh or if one of the units the script is tracking needs a refresh. local refresh = forceRefresh or next(Ovale.refreshNeeded) if not refresh then return end OvaleCompile:EvaluateScript() local iconNodes = OvaleCompile:GetIconNodes() if not iconNodes then return end self.lastUpdate = now local state = OvaleState.state state:Initialize() for k, node in ipairs(iconNodes) do -- Set the true target of "target" references in the icon's body. if node.params and node.params.target then OvaleCondition.defaultTarget = node.params.target else OvaleCondition.defaultTarget = "target" end if refresh then Ovale:Logf("+++ Icon %d", k) OvaleBestAction:StartNewAction(state) local timeSpan, _, element = OvaleBestAction:Compute(node.child[1], state) local start = NextTime(timeSpan, state.currentTime) if start then Ovale:Logf("Compute start = %f", start) end local action = self.actions[k] local icons = action.secure and action.secureIcons or action.icons if element and element.type == "value" then local actionTexture if node.params and node.params.texture then actionTexture = API_GetSpellTexture(node.params.texture) end local value if element.value and element.origin and element.rate then value = element.value + (now - element.origin) * element.rate end icons[1]:SetValue(value, actionTexture) if #icons > 1 then icons[2]:Update(element, nil) end else local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, actionUsable, actionShortcut, actionIsCurrent, actionEnable, actionType, actionId, actionTarget = OvaleBestAction:GetActionInfo(element, state) -- Use the start time of the best action instead of the intersection of its start time -- with any conditions used to determine the best action. if element and element.params and element.params.nored == 1 then start = actionCooldownStart + actionCooldownDuration if start < state.currentTime then start = state.currentTime end end -- Dans le cas de canStopChannelling, on risque de demander d'interrompre le channelling courant, ce qui est stupide if start and state.currentSpellId and state.nextCast and actionType == "spell" and actionId == state.currentSpellId and start < state.nextCast then start = state.nextCast end if start and node.params.nocd and now < start - node.params.nocd then icons[1]:Update(element, nil) else icons[1]:Update(element, start, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, actionUsable, actionShortcut, actionIsCurrent, actionEnable, actionType, actionId, actionTarget) end -- TODO: Scoring should allow for other actions besides spells. if actionType == "spell" then action.spellId = actionId else action.spellId = nil end if start and start <= now and actionUsable then action.waitStart = action.waitStart or now else action.waitStart = nil end if profile.apparence.moving and icons[1].cooldownStart and icons[1].cooldownEnd then local top=1-(now - icons[1].cooldownStart)/(icons[1].cooldownEnd-icons[1].cooldownStart) if top<0 then top = 0 elseif top>1 then top = 1 end icons[1]:SetPoint("TOPLEFT",self.frame,"TOPLEFT",(action.left + top*action.dx)/action.scale,(action.top - top*action.dy)/action.scale) if icons[2] then icons[2]:SetPoint("TOPLEFT",self.frame,"TOPLEFT",(action.left + (top+1)*action.dx)/action.scale,(action.top - (top+1)*action.dy)/action.scale) end end if (node.params.size ~= "small" and not node.params.nocd and profile.apparence.predictif) then if start then Ovale:Logf("****Second icon %f", start) local spellTarget if element then spellTarget = element.params.target end if not spellTarget or spellTarget == "target" then spellTarget = OvaleCondition.defaultTarget end state:ApplySpell(spellId, OvaleGUID:GetGUID(spellTarget)) timeSpan, _, element = OvaleBestAction:Compute(node.child[1], state) start = NextTime(timeSpan, state.currentTime) icons[2]:Update(element, start, OvaleBestAction:GetActionInfo(element, state)) else icons[2]:Update(element, nil) end end end end end wipe(Ovale.refreshNeeded) Ovale:UpdateTrace() Ovale:PrintOneTimeMessages() end local function UpdateIcons(self) for k, action in pairs(self.actions) do for i, icon in pairs(action.icons) do icon:Hide() end for i, icon in pairs(action.secureIcons) do icon:Hide() end end local profile = OvaleOptions:GetProfile() self.frame:EnableMouse(not profile.apparence.clickThru) local left = 0 local maxHeight = 0 local maxWidth = 0 local top = 0 local iconNodes = OvaleCompile:GetIconNodes() if not iconNodes then return end local BARRE = 8 local margin = profile.apparence.margin for k, node in ipairs(iconNodes) do if not self.actions[k] then self.actions[k] = {icons={}, secureIcons={}} end local action = self.actions[k] local width, height, newScale local nbIcons if (node.params.size == "small") then newScale = profile.apparence.smallIconScale width = newScale * 36 + margin height = newScale * 36 + margin nbIcons = 1 else newScale = profile.apparence.iconScale width =newScale * 36 + margin height = newScale * 36 + margin if profile.apparence.predictif and node.params.type ~= "value" then nbIcons = 2 else nbIcons = 1 end end if (top + height > profile.apparence.iconScale * 36 + margin) then top = 0 left = maxWidth end action.scale = newScale if (profile.apparence.vertical) then action.left = top action.top = -left-BARRE-margin action.dx = width action.dy = 0 else action.left = left action.top = -top-BARRE-margin action.dx = 0 action.dy = height end action.secure = node.secure for l=1,nbIcons do local icon if not node.secure then if not action.icons[l] then action.icons[l] = API_CreateFrame("CheckButton", "Icon"..k.."n"..l, self.frame, addonName .. "IconTemplate"); end icon = action.icons[l] else if not action.secureIcons[l] then action.secureIcons[l] = API_CreateFrame("CheckButton", "SecureIcon"..k.."n"..l, self.frame, "Secure" .. addonName .. "IconTemplate"); end icon = action.secureIcons[l] end local scale = action.scale if l> 1 then scale = scale * profile.apparence.secondIconScale end icon:SetPoint("TOPLEFT",self.frame,"TOPLEFT",(action.left + (l-1)*action.dx)/scale,(action.top - (l-1)*action.dy)/scale) icon:SetScale(scale) icon:SetFontScale(profile.apparence.fontScale) icon:SetParams(node.params) icon:SetHelp(node.params.help) icon:SetRangeIndicator(profile.apparence.targetText) icon:EnableMouse(not profile.apparence.clickThru) icon.cdShown = (l == 1) if Masque then self.skinGroup:AddButton(icon) end if l==1 then icon:Show(); end end top = top + height if (top> maxHeight) then maxHeight = top end if (left + width > maxWidth) then maxWidth = left + width end end if (profile.apparence.vertical) then self.barre:SetWidth(maxHeight - margin) self.barre:SetHeight(BARRE) self.frame:SetWidth(maxHeight + profile.apparence.iconShiftY) self.frame:SetHeight(maxWidth+BARRE+margin + profile.apparence.iconShiftX) self.content:SetPoint("TOPLEFT", self.frame, "TOPLEFT", maxHeight + profile.apparence.iconShiftX, profile.apparence.iconShiftY) else self.barre:SetWidth(maxWidth - margin) self.barre:SetHeight(BARRE) self.frame:SetWidth(maxWidth) -- + profile.apparence.iconShiftX self.frame:SetHeight(maxHeight+BARRE+margin) -- + profile.apparence.iconShiftY self.content:SetPoint("TOPLEFT", self.frame, "TOPLEFT", maxWidth + profile.apparence.iconShiftX, profile.apparence.iconShiftY) end end local function Constructor() -- Create parent frame for Ovale that auto-hides/shows based on whether the Pet Battle UI is active. local hider = API_CreateFrame("Frame", addonName .. "PetBattleFrameHider", UIParent, "SecureHandlerStateTemplate") hider:SetAllPoints(true) API_RegisterStateDriver(hider, "visibility", "[petbattle] hide; show") local frame = API_CreateFrame("Frame", nil, hider) local self = {} local profile = OvaleOptions:GetProfile() self.Hide = Hide self.Show = Show self.OnRelease = OnRelease self.OnAcquire = OnAcquire self.ApplyStatus = ApplyStatus self.LayoutFinished = OnLayoutFinished self.UpdateIcons = UpdateIcons self.OnSkinChanged = OnSkinChanged self.ToggleOptions = ToggleOptions self.OnUpdate = OnUpdate self.GetScore = GetScore -- self.type = "Frame" self.localstatus = {} self.actions = {} self.frame = frame self.hider = hider self.updateFrame = API_CreateFrame("Frame") self.barre = self.frame:CreateTexture(); self.content = API_CreateFrame("Frame",nil,frame) if Masque then self.skinGroup = Masque:Group(addonName) end self.lastUpdate = nil --Cheating with frame object which has an obj property --TODO: Frame Class self.obj = nil -- frame.obj = self frame:SetWidth(100) frame:SetHeight(100) frame:SetPoint("CENTER",UIParent,"CENTER",0,0) if not profile.apparence.clickThru then frame:EnableMouse() end frame:SetMovable(true) frame:SetFrameStrata("MEDIUM") frame:SetScript("OnMouseDown", frameOnMouseDown) frame:SetScript("OnMouseUp", frameOnMouseUp) frame:SetScript("OnEnter", frameOnEnter) frame:SetScript("OnLeave", frameOnLeave) -- frame:SetScript("OnUpdate", frameOnUpdate) frame:SetScript("OnHide",frameOnClose) frame:SetAlpha(profile.apparence.alpha) self.updateFrame:SetScript("OnUpdate", frameOnUpdate) self.updateFrame.obj = self self.barre:SetTexture(0,0.8,0) self.barre:SetPoint("TOPLEFT",0,0) self.barre:Hide() --Container Support local content = self.content content.obj = self content:SetWidth(200) content:SetHeight(100) content:Hide() content:SetAlpha(profile.apparence.optionsAlpha) AceGUI:RegisterAsContainer(self) return self end -- AceGUI:RegisterWidgetType(Type,Constructor,Version) end