From 0937d619099495317d38478b523dd0b36743b970 Mon Sep 17 00:00:00 2001 From: "Johnny C. Lam" Date: Sun, 10 Nov 2013 00:31:29 +0000 Subject: [PATCH] Move state kept in OvaleState into the relevant modules. Each module now manages part of the state for the simulator. A module needs to define the following (possibly empty) methods: ResetState(state) ApplySpellStart(state, ...) ApplySpellToPlayer(state, ...) ApplySpellToTarget(state, ...) The module also needs to define a state prototype with additional methods that should be mixed into the state object maintained by OvaleState. Modules register/unregister their state for the simulator using: OvaleState:RegisterState(...) OvaleState:UnregisterState(...) This de-couples OvaleState from every module that tracks some piece of information in the game. git-svn-id: svn://svn.curseforge.net/wow/ovale/mainline/trunk@1149 d5049fe3-3747-40f7-a4b5-f36d6801af5f --- Ovale.toc | 8 +- OvaleAura.lua | 338 ++++++++++++++++++++++++++++++ OvaleBestAction.lua | 3 +- OvaleComboPoints.lua | 67 ++++++ OvaleFuture.lua | 67 +++++- OvaleOptions.lua | 3 +- OvalePower.lua | 122 ++++++++++- OvaleState.lua | 566 +++++++++++--------------------------------------- compiler.pl | 1 + 9 files changed, 726 insertions(+), 449 deletions(-) diff --git a/Ovale.toc b/Ovale.toc index 1d5196d..3e075e7 100644 --- a/Ovale.toc +++ b/Ovale.toc @@ -29,7 +29,6 @@ OvaleLatency.lua OvalePool.lua OvalePoolGC.lua OvalePoolRefCount.lua -OvalePower.lua OvaleQueue.lua OvaleSpellBook.lua OvaleStance.lua @@ -39,8 +38,11 @@ OvaleDamageTaken.lua OvalePaperDoll.lua OvaleScore.lua # +OvaleState.lua +# OvaleAura.lua OvaleComboPoints.lua +OvalePower.lua OvaleRecount.lua OvaleScripts.lua scripts\scripts.xml @@ -51,13 +53,11 @@ OvaleSwing.lua OvaleOptions.lua OvaleFuture.lua # -OvaleState.lua conditions\conditions.xml -# +OvaleCompile.lua OvaleIcone.lua OvaleIcone.xml # OvaleBestAction.lua -OvaleCompile.lua # OvaleFrame.lua diff --git a/OvaleAura.lua b/OvaleAura.lua index d62f90f..3877199 100644 --- a/OvaleAura.lua +++ b/OvaleAura.lua @@ -20,6 +20,7 @@ local OvaleData = Ovale.OvaleData local OvaleGUID = Ovale.OvaleGUID local OvalePaperDoll = Ovale.OvalePaperDoll local OvalePool = Ovale.OvalePool +local OvaleState = Ovale.OvaleState local ipairs = ipairs local pairs = pairs @@ -327,9 +328,11 @@ function OvaleAura:OnEnable() self:RegisterEvent("UNIT_AURA") self:RegisterMessage("Ovale_GroupChanged", RemoveAurasForMissingUnits) self:RegisterMessage("Ovale_InactiveUnit") + OvaleState:RegisterState(self, self.statePrototype) end function OvaleAura:OnDisable() + OvaleState:UnregisterState(self) self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") self:UnregisterEvent("PLAYER_ENTERING_WORLD") self:UnregisterEvent("UNIT_AURA") @@ -615,3 +618,338 @@ function OvaleAura:DebugListAura(unitId, filter) end end -- + +--[[---------------------------------------------------------------------------- + State machine for simulator. +--]]---------------------------------------------------------------------------- + +-- +OvaleAura.statePrototype = { + aura = nil, + serial = nil, +} +-- + +-- +-- Initialize the state. +function OvaleAura:InitializeState(state) + state.aura = {} + state.serial = 0 +end + +-- Reset the state to the current conditions. +function OvaleAura:ResetState(state) + state.serial = state.serial + 1 +end + +-- Apply the effects of the spell on the player's state, assuming the spellcast completes. +function OvaleAura:ApplySpellOnPlayer(state, spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) + -- If the spellcast has already ended, then the effects on the player have already occurred. + if endCast <= OvaleState.now then + return + end + + -- Apply the auras on the player. + local si = OvaleData.spellInfo[spellId] + if si and si.aura and si.aura.player then + state:ApplySpellAuras(spellId, startCast, endCast, OvaleGUID:GetGUID("player"), si.aura.player, spellcast) + end +end + +-- Apply the effects of the spell on the target's state when it lands on the target. +function OvaleAura:ApplySpellOnTarget(state, spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) + local si = OvaleData.spellInfo[spellId] + if si and si.aura and si.aura.target then + -- Apply the auras on the target. + state:ApplySpellAuras(spellId, startCast, endCast, targetGUID, si.aura.target, spellcast) + end +end +-- + +-- Mix-in methods for simulator state. +do + local statePrototype = OvaleAura.statePrototype + + -- Apply the auras caused by the given spell in the simulator. + function statePrototype:ApplySpellAuras(spellId, startCast, endCast, guid, auraList, spellcast) + local state = self + for filter, filterInfo in pairs(auraList) do + for auraId, spellData in pairs(filterInfo) do + local si = OvaleData.spellInfo[auraId] + -- An aura is treated as a periodic aura if it sets "tick" explicitly in SpellInfo. + local isDoT = (si and si.tick) + local duration = spellData + local stacks = spellData + + -- If aura is specified with a duration, then assume stacks == 1. + if type(duration) == "number" and duration > 0 then + stacks = 1 + end + -- Set the duration to the proper length if it's a DoT. + if si and si.duration then + duration = state:GetDuration(auraId) + end + + local start, ending, currentStacks, tick = state:GetAuraByGUID(guid, auraId, filter, true, target) + local newAura = state:NewAura(guid, auraId, filter) + newAura.mine = true + + --[[ + auraId=N, N > 0 N is duration, auraID is applied, add one stack + auraId=0 aura is removed + auraId=N, N < 0 N is number of stacks of aura removed + auraId=refresh auraId is refreshed, no change to stacks + --]] + if type(stacks) == "number" and stacks == 0 then + Ovale:Logf("Aura %d is completely removed", auraId) + newAura.stacks = 0 + newAura.start = start + newAura.ending = endCast + elseif ending and endCast <= ending then + -- Spellcast ends before the aura expires. + if stacks == "refresh" or stacks > 0 then + if stacks == "refresh" then + Ovale:Logf("Aura %d is refreshed", auraId) + newAura.stacks = currentStacks + else -- if stacks > 0 then + newAura.stacks = currentStacks + stacks + Ovale:Logf("Aura %d gains a stack to %d because of spell %d (ending was %s)", auraId, newAura.stacks, spellId, ending) + end + newAura.start = start + if isDoT and ending > newAura.start and tick and tick > 0 then + -- Add new duration after the next tick is complete. + local remainingTicks = floor((ending - endCast) / tick) + newAura.ending = (ending - tick * remainingTicks) + duration + newAura.tick = OvaleAura:GetTickLength(auraId) + -- Re-snapshot stats for the DoT. + -- XXX This is not quite right because it uses the current player stats instead of the simulator's state. + OvalePaperDoll:SnapshotStats(newAura, spellcast) + newAura.damageMultiplier = state:GetDamageMultiplier(auraId) + else + newAura.ending = endCast + duration + end + Ovale:Logf("Aura %d ending is now %f", auraId, newAura.ending) + elseif stacks < 0 then + newAura.stacks = currentStacks + stacks + newAura.start = start + newAura.ending = ending + Ovale:Logf("Aura %d loses %d stack(s) to %d because of spell %d", auraId, -1 * stacks, newAura.stacks, spellId) + if newAura.stacks <= 0 then + Ovale:Logf("Aura %d is completely removed", auraId) + newAura.stacks = 0 + newAura.ending = endCast + end + end + elseif type(stacks) == "number" and type(duration) == "number" and stacks > 0 and duration > 0 then + Ovale:Logf("New aura %d at %f on %s", auraId, endCast, guid) + newAura.stacks = stacks + newAura.start = endCast + newAura.ending = endCast + duration + if isDoT then + newAura.tick = OvaleAura:GetTickLength(auraId) + -- Snapshot stats for the DoT. + -- XXX This is not quite right because it uses the current player stats instead of the simulator's state. + OvalePaperDoll:SnapshotStats(newAura, spellcast) + newAura.damageMultiplier = state:GetDamageMultiplier(auraId) + end + end + end + end + end + + function statePrototype:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) + local state = self + local aura + if mine then + local auraTable = state.aura[guid] + if auraTable then + if filter then + local auraList = auraTable[filter] + if auraList then + if auraList[spellId] and auraList[spellId].serial == state.serial then + aura = auraList[spellId] + end + end + else + for auraFilter, auraList in pairs(auraTable) do + if auraList[spellId] and auraList[spellId].serial == state.serial then + aura = auraList[spellId] + filter = auraFilter + break + end + end + end + end + end + if aura then + if aura.stacks > 0 then + Ovale:Logf("Found %s aura %s on %s", filter, spellId, guid) + else + Ovale:Logf("Found %s aura %s on %s (removed)", filter, spellId, guid) + end + if auraFound then + for k, v in pairs(aura) do + auraFound[k] = v + end + end + return aura.start, aura.ending, aura.stacks, aura.gain + else + Ovale:Logf("Aura %s not found in state for %s", spellId, guid) + return OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) + end + end + + do + local aura = {} + local newAura = {} + + function statePrototype:GetAura(unitId, spellId, filter, mine, auraFound) + local state = self + local guid = OvaleGUID:GetGUID(unitId) + if OvaleData.buffSpellList[spellId] then + if auraFound then wipe(newAura) end + local newStart, newEnding, newStacks, newGain + for auraId in pairs(OvaleData.buffSpellList[spellId]) do + if auraFound then wipe(aura) end + local start, ending, stacks, gain = state:GetAuraByGUID(guid, auraId, filter, mine, unitId, aura) + if start and (not newStart or stacks > newStacks) then + newStart = start + newEnding = ending + newStacks = stacks + newGain = gain + if auraFound then + wipe(newAura) + for k, v in pairs(aura) do + newAura[k] = v + end + end + end + end + if auraFound then + for k, v in pairs(newAura) do + auraFound[k] = v + end + end + return newStart, newEnding, newStacks, newGain + else + return state:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) + end + end + end + + -- Look for an aura on any target, excluding the given GUID. + -- Returns the earliest start time, the latest ending time, and the number of auras seen. + function statePrototype:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID) + local state = self + local start, ending, count = OvaleAura:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID) + -- TODO: This is broken because it doesn't properly account for removed auras in the current frame. + for guid, auraTable in pairs(state.aura) do + if guid ~= excludingGUID then + for auraFilter, auraList in pairs(auraTable) do + if not filter or auraFilter == filter then + local aura = auraList[spellId] + if aura and aura.serial == state.serial then + if aura.start and (not start or aura.start < start) then + start = aura.start + end + if aura.ending and (not ending or aura.ending > ending) then + ending = aura.ending + end + count = count + 1 + end + end + end + end + end + return start, ending, count + end + + function statePrototype:NewAura(guid, spellId, filter) + local state = self + if not state.aura[guid] then + state.aura[guid] = {} + end + if not state.aura[guid][filter] then + state.aura[guid][filter] = {} + end + if not state.aura[guid][filter][spellId] then + state.aura[guid][filter][spellId] = {} + end + local aura = state.aura[guid][filter][spellId] + aura.serial = state.serial + aura.mine = true + aura.gain = OvaleState.currentTime + return aura + end + + function statePrototype:GetDamageMultiplier(spellId) + local state = self + local damageMultiplier = 1 + if spellId then + local si = OvaleData.spellInfo[spellId] + if si and si.damageAura then + local playerGUID = OvaleGUID:GetGUID("player") + for filter, auraList in pairs(si.damageAura) do + for auraSpellId, multiplier in pairs(auraList) do + local count = select(3, state:GetAuraByGUID(playerGUID, auraSpellId, filter, nil, "player")) + if count and count > 0 then + local auraSpellInfo = OvaleData.spellInfo[auraSpellId] + if auraSpellInfo.stacking and auraSpellInfo.stacking > 0 then + multiplier = 1 + (multiplier - 1) * count + end + damageMultiplier = damageMultiplier * multiplier + end + end + end + end + end + return damageMultiplier + end + + -- Returns the duration, tick length, and number of ticks of an aura. + function statePrototype:GetDuration(auraSpellId) + local state = self + local si + if type(auraSpellId) == "number" then + si = OvaleData.spellInfo[auraSpellId] + elseif OvaleData.buffSpellList[auraSpellId] then + for spellId in pairs(OvaleData.buffSpellList[auraSpellId]) do + si = OvaleData.spellInfo[spellId] + if si then + auraSpellId = spellId + break + end + end + end + if si and si.duration then + local OvaleComboPoints = Ovale.OvaleComboPoints + local OvalePower = Ovale.OvalePower + local duration = si.duration + local combo = state.combo or 0 + local holy = state.holy or 1 + if si.adddurationcp then + duration = duration + si.adddurationcp * combo + end + if si.adddurationholy then + duration = duration + si.adddurationholy * (holy - 1) + end + if si.tick then -- DoT + --DoT duration is tick * numTicks. + local tick = OvaleAura:GetTickLength(auraSpellId) + local numTicks = floor(duration / tick + 0.5) + duration = tick * numTicks + return duration, tick, numTicks + end + return duration + end + end + + -- Track a new Eclipse buff that starts at timestamp. + function statePrototype:AddEclipse(timestamp, spellId) + local state = self + local aura = state:NewAura(self_player_guid, spellId, "HELPFUL") + aura.start = timestamp + aura.ending = nil + aura.stacks = 1 + end +end diff --git a/OvaleBestAction.lua b/OvaleBestAction.lua index f5f2cde..b12ba04 100644 --- a/OvaleBestAction.lua +++ b/OvaleBestAction.lua @@ -17,6 +17,7 @@ local OvaleActionBar = Ovale.OvaleActionBar local OvaleCondition = Ovale.OvaleCondition local OvaleData = Ovale.OvaleData local OvaleEquipement = Ovale.OvaleEquipement +local OvaleFuture = Ovale.OvaleFuture local OvalePaperDoll = Ovale.OvalePaperDoll local OvalePool = Ovale.OvalePool local OvalePower = Ovale.OvalePower @@ -699,7 +700,7 @@ local OVALE_COMPUTE_VISITOR = -- function OvaleBestAction:StartNewAction() OvaleState:Reset() - OvaleState:ApplyActiveSpells() + OvaleFuture:ApplyInFlightSpells() self_serial = self_serial + 1 end diff --git a/OvaleComboPoints.lua b/OvaleComboPoints.lua index cabc92f..78e5b77 100644 --- a/OvaleComboPoints.lua +++ b/OvaleComboPoints.lua @@ -17,6 +17,7 @@ Ovale.OvaleComboPoints = OvaleComboPoints local OvaleData = Ovale.OvaleData local OvaleGUID = Ovale.OvaleGUID local OvalePaperDoll = Ovale.OvalePaperDoll +local OvaleState = Ovale.OvaleState local API_GetComboPoints = GetComboPoints local MAX_COMBO_POINTS = MAX_COMBO_POINTS @@ -35,11 +36,13 @@ function OvaleComboPoints:OnEnable() self:RegisterEvent("PLAYER_TARGET_CHANGED", "Refresh") self:RegisterEvent("UNIT_COMBO_POINTS") self:RegisterEvent("UNIT_TARGET", "UNIT_COMBO_POINTS") + OvaleState:RegisterState(self, self.statePrototype) end end function OvaleComboPoints:OnDisable() if OvalePaperDoll.class == "ROGUE" or OvalePaperDoll.class == "DRUID" then + OvaleState:UnregisterState(self) self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") self:UnregisterEvent("PLAYER_ENTERING_WORLD") self:UnregisterEvent("PLAYER_LOGIN") @@ -92,3 +95,67 @@ function OvaleComboPoints:Debug() Ovale:FormatPrint("Player has %d combo points on target %s.", self.combo, OvaleGUID:GetGUID("target")) end -- + +--[[---------------------------------------------------------------------------- + State machine for simulator. +--]]---------------------------------------------------------------------------- + +-- +OvaleComboPoints.statePrototype = { + combo = nil, +} +-- + +-- +-- Initialize the state. +function OvaleComboPoints:InitializeState(state) + state.combo = 0 +end + +-- Reset the state to the current conditions. +function OvaleComboPoints:ResetState(state) + state.combo = self.combo or 0 +end + +-- Apply the effects of the spell on the player's state, assuming the spellcast completes. +function OvaleComboPoints:ApplySpellOnPlayer(state, spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) + -- If the spellcast has already ended, then the effects on the player have already occurred. + if endCast <= OvaleState.now then + return + end + + local si = OvaleData.spellInfo[spellId] + if si and si.combo then + local cost = si.combo + local power = state.combo or 0 + --[[ + cost > 0 means that the spell generates combo points. + cost < 0 means that the spell costs combo points. + cost == 0 means that the spell uses all of the combo points (finisher). + --]] + if cost == 0 then + power = 0 + else + power = power + cost + end + --[[ + Add extra combo points generated by presence of a buff. + "buff_combo" is the spell ID of the buff that causes extra points to be generated or used. + "buff_combo_amount" is the number of extra points generated or used, defaulting to 1 + (one extra point generated). + --]] + if si.buff_combo and state:GetAura("player", si.buff_combo, nil, true) then + local buffAmount = si.buff_combo_amount or 1 + power = power + buffAmount + end + -- Clamp combo points to lower and upper limits. + if power < 0 then + power = 0 + end + if power > MAX_COMBO_POINTS then + power = MAX_COMBO_POINTS + end + state.combo = power + end +end +-- diff --git a/OvaleFuture.lua b/OvaleFuture.lua index d5c9e2c..490c059 100644 --- a/OvaleFuture.lua +++ b/OvaleFuture.lua @@ -23,6 +23,7 @@ local OvalePaperDoll = Ovale.OvalePaperDoll local OvalePool = Ovale.OvalePool local OvaleScore = Ovale.OvaleScore local OvaleSpellBook = Ovale.OvaleSpellBook +local OvaleState = Ovale.OvaleState local ipairs = ipairs local pairs = pairs @@ -249,9 +250,11 @@ function OvaleFuture:OnEnable() self:RegisterEvent("UNIT_SPELLCAST_START") self:RegisterMessage("Ovale_AuraAdded") self:RegisterMessage("Ovale_InactiveUnit") + OvaleState:RegisterState(self, self.statePrototype) end function OvaleFuture:OnDisable() + OvaleState:UnregisterState(self) self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") self:UnregisterEvent("PLAYER_ENTERING_WORLD") self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START") @@ -446,8 +449,10 @@ function OvaleFuture:COMBAT_LOG_EVENT_UNFILTERED(event, ...) end end --- Apply spells that are being cast or are in flight. -function OvaleFuture:ApplyInFlightSpells(now, ApplySpell) +-- Apply the effects of spells that are being cast or are in flight, allowing us to +-- ignore lag or missile travel time. +function OvaleFuture:ApplyInFlightSpells() + local now = OvaleState.now local index = 0 local spellcast, si while true do @@ -460,7 +465,7 @@ function OvaleFuture:ApplyInFlightSpells(now, ApplySpell) if not (si and si.toggle) then Ovale:Logf("now = %f, spellId = %d, endCast = %f", now, spellcast.spellId, spellcast.stop) if now - spellcast.stop < 5 then - ApplySpell(spellcast.spellId, spellcast.start, spellcast.stop, spellcast.stop, spellcast.nocd, spellcast.target, spellcast) + OvaleState:ApplySpell(spellcast.spellId, spellcast.start, spellcast.stop, spellcast.stop, spellcast.nocd, spellcast.target, spellcast) else tremove(self_activeSpellcast, index) self_pool:Release(spellcast) @@ -497,3 +502,59 @@ function OvaleFuture:Debug() end end -- + +--[[---------------------------------------------------------------------------- + State machine for simulator. +--]]---------------------------------------------------------------------------- + +-- +OvaleFuture.statePrototype = { + counter = nil, +} +-- + +-- +-- Initialize the state. +function OvaleFuture:InitializeState(state) + state.counter = {} +end + +-- Reset the state to the current conditions. +function OvaleFuture:ResetState(state) + for k, v in pairs(self.counter) do + state.counter[k] = self.counter[k] + end +end + +-- Apply the effects of the spell at the start of the spellcast. +function OvaleFuture:ApplySpellStart(state, spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) + -- If the spellcast has already started, then the effects have already occurred. + if startCast < OvaleState.now then + return + end + + local si = OvaleData.spellInfo[spellId] + if si then + -- Increment and reset spell counters. + if si.inccounter then + local id = si.inccounter + local value = state.counter[id] and state.counter[id] or 0 + state.counter[id] = value + 1 + end + if si.resetcounter then + local id = si.resetcounter + state.counter[id] = 0 + end + end +end +-- + +-- Mix-in methods for simulator state. +do + local statePrototype = OvaleFuture.statePrototype + + function statePrototype:GetCounterValue(id) + local state = self + return state.counter[id] and state.counter[id] or 0 + end +end \ No newline at end of file diff --git a/OvaleOptions.lua b/OvaleOptions.lua index 00fe530..35abca0 100644 --- a/OvaleOptions.lua +++ b/OvaleOptions.lua @@ -19,6 +19,7 @@ local L = Ovale.L local OvalePaperDoll = Ovale.OvalePaperDoll local OvaleScripts = Ovale.OvaleScripts local OvaleSpellBook = Ovale.OvaleSpellBook +local OvaleState = Ovale.OvaleState local strgmatch = string.gmatch local strgsub = string.gsub @@ -600,7 +601,7 @@ local self_options = name = "Power", type = "execute", func = function() - if Ovale.OvaleState then Ovale.OvaleState:DebugPower() end + OvaleState.state:DebugPower() end }, talent = diff --git a/OvalePower.lua b/OvalePower.lua index 5f4fba9..1b993cc 100644 --- a/OvalePower.lua +++ b/OvalePower.lua @@ -13,8 +13,13 @@ local OvalePower = Ovale:NewModule("OvalePower", "AceEvent-3.0") Ovale.OvalePower = OvalePower -- +local OvaleData = Ovale.OvaleData +local OvaleState = Ovale.OvaleState + local pairs = pairs +local select = select local API_GetPowerRegen = GetPowerRegen +local API_GetSpellInfo = GetSpellInfo local API_UnitPower = UnitPower local API_UnitPowerMax = UnitPowerMax local API_UnitPowerType = UnitPowerType @@ -94,9 +99,11 @@ function OvalePower:OnEnable() self:RegisterEvent("UNIT_RANGEDDAMAGE") self:RegisterEvent("UNIT_SPELL_HASTE", "UNIT_RANGEDDAMAGE") self:RegisterMessage("Ovale_StanceChanged", "EventHandler") + OvaleState:RegisterState(self, self.statePrototype) end function OvalePower:OnDisable() + OvaleState:UnregisterState(self) self:UnregisterEvent("ACTIVE_TALENT_GROUP_CHANGED") self:UnregisterEvent("PLAYER_ALIVE") self:UnregisterEvent("PLAYER_ENTERING_WORLD") @@ -188,4 +195,117 @@ function OvalePower:Debug() Ovale:FormatPrint("Active regen: %f", self.activeRegen) Ovale:FormatPrint("Inactive regen: %f", self.inactiveRegen) end --- \ No newline at end of file +-- + +--[[---------------------------------------------------------------------------- + State machine for simulator. +--]]---------------------------------------------------------------------------- + +-- +OvalePower.statePrototype = { + powerRate = nil, +} +-- + +-- +-- Initialize the state. +function OvalePower:InitializeState(state) + state.powerRate = {} +end + +-- Reset the state to the current conditions. +function OvalePower:ResetState(state) + -- Power levels for each resource. + for powerType in pairs(self.POWER_INFO) do + state[powerType] = self.power[powerType] or 0 + end + -- Clear power regeneration rates for each resource. + for powerType in pairs(self.POWER_INFO) do + state.powerRate[powerType] = 0 + end + -- Set power regeneration for current resource. + if Ovale.enCombat then + state.powerRate[self.powerType] = self.activeRegen + else + state.powerRate[self.powerType] = self.inactiveRegen + end +end + +-- Apply the effects of the spell on the player's state, assuming the spellcast completes. +function OvalePower:ApplySpellOnPlayer(state, spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) + -- If the spellcast has already ended, then the effects on the player have already occurred. + if endCast <= OvaleState.now then + return + end + + local si = OvaleData.spellInfo[spellId] + + -- Update power using information from GetSpellInfo() if there is no SpellInfo() for the spell's cost. + do + local cost, _, powerType = select(4, API_GetSpellInfo(spellId)) + if cost and powerType then + powerType = self.POWER_TYPE[powerType] + if not si or not si[powerType] then + state[powerType] = state[powerType] - cost + end + end + end + + if si then + -- Update power state except for eclipse energy. + for powerType, powerInfo in pairs(self.POWER_INFO) do + if powerType ~= "eclipse" then + local cost = si[powerType] + local power = state[powerType] or 0 + if cost then + --[[ + cost > 0 means that the spell costs resources. + cost < 0 means that the spell generates resources. + cost == 0 means that the spell uses all of the resources (zeroes it out). + --]] + if cost == 0 then + power = 0 + else + power = power - cost + end + --[[ + Add extra resource generated by presence of a buff. + "buff_" is the spell ID of the buff that causes extra resources to be generated or used. + "buff__amount" is the amount of extra resources generated or used, defaulting to -1 + (one extra resource generated). + --]] + local buffParam = "buff_" .. tostring(powerType) + local buffAmoumtParam = buffParam .. "_amount" + if si[buffParam] and state:GetAura("player", si[buffParam], nil, true) then + local buffAmount = si[buffAmountParam] or -1 + power = power - buffAmount + end + -- Clamp power to lower and upper limits. + local mini = powerInfo.mini or 0 + local maxi = powerInfo.maxi or self.maxPower[powerType] + if mini and power < mini then + power = mini + end + if maxi and power > maxi then + power = maxi + end + state[powerType] = power + end + end + end + end +end +-- + +-- Mix-in methods for simulator state. +do + local statePrototype = OvalePower.statePrototype + + -- Print out the levels of each power type in the current state. + function statePrototype:DebugPower() + local state = self + for powerType in pairs(OvalePower.POWER_INFO) do + Ovale:FormatPrint("%s = %d", powerType, state[powerType]) + end + end +end diff --git a/OvaleState.lua b/OvaleState.lua index a6857d7..a52b56e 100644 --- a/OvaleState.lua +++ b/OvaleState.lua @@ -15,34 +15,37 @@ local OvaleState = Ovale:NewModule("OvaleState") Ovale.OvaleState = OvaleState -- -local OvaleAura = Ovale.OvaleAura -local OvaleComboPoints = Ovale.OvaleComboPoints local OvaleData = Ovale.OvaleData -local OvaleFuture = Ovale.OvaleFuture local OvaleGUID = Ovale.OvaleGUID local OvalePaperDoll = Ovale.OvalePaperDoll -local OvalePower = Ovale.OvalePower +local OvaleQueue = Ovale.OvaleQueue local OvaleSpellBook = Ovale.OvaleSpellBook local OvaleStance = Ovale.OvaleStance local floor = math.floor local pairs = pairs local select = select +local tinsert = table.insert +local tremove = table.remove local tostring = tostring local type = type local wipe = table.wipe local API_GetEclipseDirection = GetEclipseDirection local API_GetRuneCooldown = GetRuneCooldown local API_GetRuneType = GetRuneType -local API_GetSpellInfo = GetSpellInfo local API_GetTime = GetTime local API_UnitHealth = UnitHealth local API_UnitHealthMax = UnitHealthMax -local MAX_COMBO_POINTS = MAX_COMBO_POINTS + +local self_statePrototype = {} +local self_stateModules = OvaleQueue:NewQueue("OvaleState_stateModules") local self_runes = {} local self_runesCD = {} +-- Whether the state of the simulator has been initialized. +local self_stateIsInitialized = false + -- Aura IDs for Eclipse buffs. local LUNAR_ECLIPSE = 48518 local SOLAR_ECLIPSE = 48517 @@ -52,73 +55,101 @@ local STARFALL = 48505 -- --the state in the current frame -OvaleState.state = {rune={}, cd = {}, counter={}} -OvaleState.aura = {} -OvaleState.serial = 0 -for i=1,6 do - OvaleState.state.rune[i] = {} -end +OvaleState.state = {} --The spell being cast OvaleState.currentSpellId = nil +OvaleState.now = nil OvaleState.maintenant = nil OvaleState.currentTime = nil OvaleState.attenteFinCast = nil OvaleState.startCast = nil OvaleState.endCast = nil OvaleState.gcd = 1.5 -OvaleState.powerRate = {} OvaleState.lastSpellId = nil -- -- -local function ApplySpell(spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) - local self = OvaleState - self:ApplySpell(spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) -end - --- Track a new Eclipse buff that starts at timestamp. -local function AddEclipse(timestamp, spellId) +-- XXX The way this function updates the rune state looks completely wrong. +local function AddRune(atTime, runeType, value) local self = OvaleState - local newAura = self:NewAura(OvaleGUID:GetGUID("player"), spellId, "HELPFUL") - newAura.start = timestamp - newAura.ending = nil - newAura.stacks = 1 + for i = 1, 6 do + local rune = self.state.rune[i] + if (rune.type == runeType or rune.type == 4) and rune.cd <= atTime then + rune.cd = atTIme + 10 + end + end end -- -- +function OvaleState:RegisterState(addon, statePrototype) + self_stateModules:Insert(addon) + self_statePrototype[addon] = statePrototype + + -- Mix-in addon's state prototype into OvaleState.state. + for k, v in pairs(statePrototype) do + self.state[k] = v + end +end + +function OvaleState:UnregisterState(addon) + stateModules = OvaleQueue:NewQueue("OvaleState_stateModules") + while self_stateModules:Size() > 0 do + local stateAddon = self_stateModules:Remove() + if stateAddon ~= addon then + stateModules:Insert(addon) + end + end + self_stateModules = stateModules + + -- Remove mix-in methods from addon's state prototype. + local statePrototype = self_statePrototype[addon] + for k in pairs(statePrototype) do + self.state[k] = nil + end + self_stateModules[addon] = nil +end + +function OvaleState:InvokeMethod(methodName, ...) + for _, addon in self_stateModules:Iterator() do + if addon[methodName] then + addon[methodName](addon, self.state, ...) + end + end +end + function OvaleState:StartNewFrame() - self.maintenant = API_GetTime() + if not self_stateIsInitialized then + self:InitializeState() + end + self.now = API_GetTime() + self.maintenant = self.now self.gcd = self:GetGCD() end -function OvaleState:UpdatePowerRates() - for powerType in pairs(OvalePower.POWER_INFO) do - self.powerRate[powerType] = 0 - end - -- Power regeneration for current power type. - if Ovale.enCombat then - self.powerRate[OvalePower.powerType] = OvalePower.activeRegen - else - self.powerRate[OvalePower.powerType] = OvalePower.inactiveRegen +function OvaleState:InitializeState() + self:InvokeMethod("InitializeState") + + self.state.rune = {} + for i = 1, 6 do + self.state.rune[i] = {} end + + -- Legacy fields + self.powerRate = self.state.powerRate + + self_stateIsInitialized = true end function OvaleState:Reset() self.lastSpellId = Ovale.lastSpellcast and Ovale.lastSpellcast.spellId - self.serial = self.serial + 1 self.currentTime = self.maintenant Ovale:Logf("Reset state with current time = %f", self.currentTime) self.currentSpellId = nil self.attenteFinCast = self.maintenant - -- Snapshot the current power and regeneration rates. - self.state.combo = OvaleComboPoints.combo - for powerType in pairs(OvalePower.POWER_INFO) do - self.state[powerType] = OvalePower.power[powerType] - end - self:UpdatePowerRates() - + self:InvokeMethod("ResetState") + if OvalePaperDoll.class == "DEATHKNIGHT" then for i=1,6 do self.state.rune[i].type = API_GetRuneType(i) @@ -140,16 +171,6 @@ function OvaleState:Reset() v.enable = 0 v.toggled = nil end - - for k,v in pairs(self.state.counter) do - self.state.counter[k] = OvaleFuture.counter[k] - end -end - --- Apply the effects of spells that are being cast or are in flight, allowing us to --- ignore lag or missile travel time. -function OvaleState:ApplyActiveSpells() - OvaleFuture:ApplyInFlightSpells(self.maintenant, ApplySpell) end --[[ @@ -200,30 +221,12 @@ end -- Apply the effects of the spell at the start of the spellcast. function OvaleState:ApplySpellStart(spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) - local si = OvaleData.spellInfo[spellId] - --[[ - If the spellcast has already started, then the effects have already occurred, - so only consider spells that are cast in the future in the simulator. - --]] - if startCast >= self.maintenant then - if si then - -- Increment and reset spell counters. - if si.inccounter then - local id = si.inccounter - local value = self.state.counter[id] and self.state.counter[id] or 0 - self.state.counter[id] = value + 1 - end - if si.resetcounter then - local id = si.resetcounter - self.state.counter[id] = 0 - end - end - end + self:InvokeMethod("ApplySpellStart", spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) end -- Apply the effects of the spell on the player's state, assuming the spellcast completes. function OvaleState:ApplySpellOnPlayer(spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) - local si = OvaleData.spellInfo[spellId] + self:InvokeMethod("ApplySpellOnPlayer", spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) --[[ If the spellcast has already ended, then the effects have already occurred, so only consider spells that have not yet finished casting in the simulator. @@ -234,21 +237,12 @@ function OvaleState:ApplySpellOnPlayer(spellId, startCast, endCast, nextCast, no -- Adjust the player's resources. self:ApplySpellCost(spellId, startCast, endCast) - - -- Apply the auras on the player. - if si and si.aura and si.aura.player then - self:ApplySpellAuras(spellId, startCast, endCast, OvaleGUID:GetGUID("player"), si.aura.player, spellcast) - end end end -- Apply the effects of the spell on the target's state when it lands on the target. function OvaleState:ApplySpellOnTarget(spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) - local si = OvaleData.spellInfo[spellId] - if si and si.aura and si.aura.target then - -- Apply the auras on the target. - self:ApplySpellAuras(spellId, startCast, endCast, targetGUID, si.aura.target, spellcast) - end + self:InvokeMethod("ApplySpellOnTarget", spellId, startCast, endCast, nextCast, nocd, targetGUID, spellcast) end -- Adjust a spell cooldown in the simulator. @@ -308,95 +302,8 @@ end -- Adjust the player's resources in the simulator from casting the given spell. function OvaleState:ApplySpellCost(spellId, startCast, endCast) local si = OvaleData.spellInfo[spellId] - local _, _, _, cost, _, powerType = API_GetSpellInfo(spellId) - - -- Update power using information from GetSpellInfo() if there is no user-defined SpellInfo() for the spell's cost. - if cost and powerType then - powerType = OvalePower.POWER_TYPE[powerType] - if not si or not si[powerType] then - self.state[powerType] = self.state[powerType] - cost - end - end if si then - -- Update power state, except for combo points, eclipse energy, and runes. - for powerType, powerInfo in pairs(OvalePower.POWER_INFO) do - if powerType ~= "eclipse" then - local cost = si[powerType] - if cost then - --[[ - cost > 0 means that the spell costs resources. - cost < 0 means that the spell generates resources. - cost == 0 means that the spell uses all of the resources (zeroes it out). - --]] - if cost == 0 then - self.state[powerType] = 0 - else - self.state[powerType] = self.state[powerType] - cost - end - --[[ - Add extra resource generated by presence of a buff. - "buff_" is the spell ID of the buff that causes extra resources to be generated or used. - "buff__amount" is the amount of extra resources generated or used, defaulting to -1 - (one extra resource generated). - --]] - local buffParam = "buff_" .. tostring(powerType) - local buffAmoumtParam = buffParam .. "_amount" - if si[buffParam] and self:GetAura("player", si[buffParam], nil, true) then - local buffAmount = si[buffAmountParam] or -1 - self.state[powerType] = self.state[powerType] - buffAmount - end - -- Clamp self.state[powerType] to lower and upper limits. - local mini = powerInfo.mini or 0 - local maxi = powerInfo.maxi or OvalePower.maxPower[powerType] - if mini and self.state[powerType] < mini then - self.state[powerType] = mini - end - if maxi and self.state[powerType] > maxi then - self.state[powerType] = maxi - end - end - end - end - - --[[ - Combo points: This resource is handled specially because it has different semantics - from other resources. In particular, it's a resource that's attached to the target - and not to the player. - --]] - if si.combo then - local combo = si.combo - --[[ - Combo points have the opposite meaning from other resources: - - combo > 0 means that the spell generates resources. - combo < 0 means that the spell costs resources. - combo == 0 means that the spell uses all of the combo points. - --]] - if combo == 0 then - self.state.combo = 0 - else - self.state.combo = self.state.combo + combo - end - --[[ - Add extra combo points generated by presence of a buff. - "buff_combo" is the spell ID of the buff that causes extra points to be generated or used. - "buff_combo_amount" is the number of extra points generated or used, defaulting to 1 - (one extra resource generated). - --]] - if si.buff_combo and self:GetAura("player", si.buff_combo, nil, true) then - local buffAmount = si.buff_combo_amount or 1 - self.state.combo = self.state.combo + buffAmount - end - -- Clamp self.state.combo to lower and upper limits. - if self.state.combo < 0 then - self.state.combo = 0 - end - if self.state.combo > MAX_COMBO_POINTS then - self.state.combo = MAX_COMBO_POINTS - end - end - -- Eclipse if si.eclipse then local energy = si.eclipse @@ -417,7 +324,7 @@ function OvaleState:ApplySpellCost(spellId, startCast, endCast) -- Clamp Eclipse energy to min/max values and note that an Eclipse state will be reached after the spellcast. if self.state.eclipse <= -100 then self.state.eclipse = -100 - AddEclipse(endCast, LUNAR_ECLIPSE) + self.state:AddEclipse(endCast, LUNAR_ECLIPSE) -- Reaching Lunar Eclipse resets the cooldown of Starfall. local cd = self:GetCD(STARFALL) if cd then @@ -427,118 +334,22 @@ function OvaleState:ApplySpellCost(spellId, startCast, endCast) end elseif self.state.eclipse >= 100 then self.state.eclipse = 100 - AddEclipse(endCast, SOLAR_ECLIPSE) + self.state:AddEclipse(endCast, SOLAR_ECLIPSE) end end -- Runes if si.blood and si.blood < 0 then - self:AddRune(startCast, 1, si.blood) + AddRune(startCast, 1, si.blood) end if si.unholy and si.unholy < 0 then - self:AddRune(startCast, 2, si.unholy) + AddRune(startCast, 2, si.unholy) end if si.frost and si.frost < 0 then - self:AddRune(startCast, 3, si.frost) + AddRune(startCast, 3, si.frost) end if si.death and si.death < 0 then - self:AddRune(startCast, 4, si.death) - end - end -end - --- XXX The way this function updates the rune state looks completely wrong. -function OvaleState:AddRune(atTime, runeType, value) - for i = 1, 6 do - local rune = self.state.rune[i] - if (rune.type == runeType or rune.type == 4) and rune.cd <= atTime then - rune.cd = atTime + 10 - end - end -end - --- Apply the auras caused by the given spell in the simulator. -function OvaleState:ApplySpellAuras(spellId, startCast, endCast, guid, auraList, spellcast) - for filter, filterInfo in pairs(auraList) do - for auraId, spellData in pairs(filterInfo) do - local si = OvaleData.spellInfo[auraId] - -- An aura is treated as a periodic aura if it sets "tick" explicitly in SpellInfo. - local isDoT = (si and si.tick) - local duration = spellData - local stacks = spellData - - -- If aura is specified with a duration, then assume stacks == 1. - if type(duration) == "number" and duration > 0 then - stacks = 1 - end - -- Set the duration to the proper length if it's a DoT. - if si and si.duration then - duration = self:GetDuration(auraId) - end - - local start, ending, currentStacks, tick = self:GetAuraByGUID(guid, auraId, filter, true, target) - local newAura = self:NewAura(guid, auraId, filter) - newAura.mine = true - - --[[ - auraId=N, N > 0 N is duration, auraID is applied, add one stack - auraId=0 aura is removed - auraId=N, N < 0 N is number of stacks of aura removed - auraId=refresh auraId is refreshed, no change to stacks - --]] - if type(stacks) == "number" and stacks == 0 then - Ovale:Logf("Aura %d is completely removed", auraId) - newAura.stacks = 0 - newAura.start = start - newAura.ending = endCast - elseif ending and endCast <= ending then - -- Spellcast ends before the aura expires. - if stacks == "refresh" or stacks > 0 then - if stacks == "refresh" then - Ovale:Logf("Aura %d is refreshed", auraId) - newAura.stacks = currentStacks - else -- if stacks > 0 then - newAura.stacks = currentStacks + stacks - Ovale:Logf("Aura %d gains a stack to %d because of spell %d (ending was %s)", auraId, newAura.stacks, spellId, ending) - end - newAura.start = start - if isDoT and ending > newAura.start and tick and tick > 0 then - -- Add new duration after the next tick is complete. - local remainingTicks = floor((ending - endCast) / tick) - newAura.ending = (ending - tick * remainingTicks) + duration - newAura.tick = OvaleAura:GetTickLength(auraId) - -- Re-snapshot stats for the DoT. - -- XXX This is not quite right because it uses the current player stats instead of the simulator's state. - OvalePaperDoll:SnapshotStats(newAura, spellcast) - newAura.damageMultiplier = self:GetDamageMultiplier(auraId) - else - newAura.ending = endCast + duration - end - Ovale:Logf("Aura %d ending is now %f", auraId, newAura.ending) - elseif stacks < 0 then - newAura.stacks = currentStacks + stacks - newAura.start = start - newAura.ending = ending - Ovale:Logf("Aura %d loses %d stack(s) to %d because of spell %d", auraId, -1 * stacks, newAura.stacks, spellId) - if newAura.stacks <= 0 then - Ovale:Logf("Aura %d is completely removed", auraId) - newAura.stacks = 0 - newAura.ending = endCast - end - end - elseif type(stacks) == "number" and type(duration) == "number" and stacks > 0 and duration > 0 then - Ovale:Logf("New aura %d at %f on %s", auraId, endCast, guid) - newAura.stacks = stacks - newAura.start = endCast - newAura.ending = endCast + duration - if isDoT then - newAura.tick = OvaleAura:GetTickLength(auraId) - -- Snapshot stats for the DoT. - -- XXX This is not quite right because it uses the current player stats instead of the simulator's state. - OvalePaperDoll:SnapshotStats(newAura, spellcast) - newAura.damageMultiplier = self:GetDamageMultiplier(auraId) - end - end + AddRune(startCast, 4, si.death) end end end @@ -634,147 +445,27 @@ function OvaleState:GetComputedSpellCD(spellId) end function OvaleState:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) - local aura - if mine then - local auraTable = self.aura[guid] - if auraTable then - if filter then - local auraList = auraTable[filter] - if auraList then - if auraList[spellId] and auraList[spellId].serial == self.serial then - aura = auraList[spellId] - end - end - else - for auraFilter, auraList in pairs(auraTable) do - if auraList[spellId] and auraList[spellId].serial == self.serial then - aura = auraList[spellId] - filter = auraFilter - break - end - end - end - end - end - if aura then - if aura.stacks > 0 then - Ovale:Logf("Found %s aura %s on %s", filter, spellId, guid) - else - Ovale:Logf("Found %s aura %s on %s (removed)", filter, spellId, guid) - end - if auraFound then - for k, v in pairs(aura) do - auraFound[k] = v - end - end - return aura.start, aura.ending, aura.stacks, aura.gain - else - Ovale:Logf("Aura %s not found in state for %s", spellId, guid) - return OvaleAura:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) - end + return self.state:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) end -do - local aura = {} - local newAura = {} - - function OvaleState:GetAura(unitId, spellId, filter, mine, auraFound) - local guid = OvaleGUID:GetGUID(unitId) - if OvaleData.buffSpellList[spellId] then - if auraFound then wipe(newAura) end - local newStart, newEnding, newStacks, newGain - for auraId in pairs(OvaleData.buffSpellList[spellId]) do - if auraFound then wipe(aura) end - local start, ending, stacks, gain = self:GetAuraByGUID(guid, auraId, filter, mine, unitId, aura) - if start and (not newStart or stacks > newStacks) then - newStart = start - newEnding = ending - newStacks = stacks - newGain = gain - if auraFound then - wipe(newAura) - for k, v in pairs(aura) do - newAura[k] = v - end - end - end - end - if auraFound then - for k, v in pairs(newAura) do - auraFound[k] = v - end - end - return newStart, newEnding, newStacks, newGain - else - return self:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) - end - end +function OvaleState:GetAura(unitId, spellId, filter, mine, auraFound) + return self.state:GetAura(unitId, spellId, filter, mine, auraFound) end --- Look for an aura on any target, excluding the given GUID. --- Returns the earliest start time, the latest ending time, and the number of auras seen. function OvaleState:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID) - local start, ending, count = OvaleAura:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID) - -- TODO: This is broken because it doesn't properly account for removed auras in the current frame. - for guid, auraTable in pairs(self.aura) do - if guid ~= excludingGUID then - for auraFilter, auraList in pairs(auraTable) do - if not filter or auraFilter == filter then - local aura = auraList[spellId] - if aura and aura.serial == self.serial then - if aura.start and (not start or aura.start < start) then - start = aura.start - end - if aura.ending and (not ending or aura.ending > ending) then - ending = aura.ending - end - count = count + 1 - end - end - end - end - end - return start, ending, count + return self.state:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID) end function OvaleState:NewAura(guid, spellId, filter) - if not self.aura[guid] then - self.aura[guid] = {} - end - if not self.aura[guid][filter] then - self.aura[guid][filter] = {} - end - if not self.aura[guid][filter][spellId] then - self.aura[guid][filter][spellId] = {} - end - local aura = self.aura[guid][filter][spellId] - aura.serial = self.serial - aura.mine = true - aura.gain = self.currentTime - return aura + return self.state:NewAura(guid, spellId, filter) end function OvaleState:GetDamageMultiplier(spellId) - local damageMultiplier = 1 - if spellId then - local si = OvaleData.spellInfo[spellId] - if si and si.damageAura then - local playerGUID = OvaleGUID:GetGUID("player") - for filter, auraList in pairs(si.damageAura) do - for auraSpellId, multiplier in pairs(auraList) do - local count = select(3, self:GetAuraByGUID(playerGUID, auraSpellId, filter, nil, "player")) - if count and count > 0 then - local auraSpellInfo = OvaleData.spellInfo[auraSpellId] - if auraSpellInfo.stacking and auraSpellInfo.stacking > 0 then - multiplier = 1 + (multiplier - 1) * count - end - damageMultiplier = damageMultiplier * multiplier - end - end - end - end - end - return damageMultiplier + return self.state:GetDamageMultiplier(spellId) +end + +function OvaleState:GetDuration(auraSpellId) + return self.state:GetDuration(auraSpellId) end -- Returns 1 if moving toward Solar or -1 if moving toward Lunar. @@ -861,45 +552,42 @@ function OvaleState:GetRunesCooldown(blood, frost, unholy, death, nodeath) return maxCD end --- Returns the duration, tick length, and number of ticks of an aura. -function OvaleState:GetDuration(auraSpellId) - local si - if type(auraSpellId) == "number" then - si = OvaleData.spellInfo[auraSpellId] - elseif OvaleData.buffSpellList[auraSpellId] then - for spellId in pairs(OvaleData.buffSpellList[auraSpellId]) do - si = OvaleData.spellInfo[spellId] - if si then - auraSpellId = spellId - break - end - end - end - if si and si.duration then - local duration = si.duration - local combo = self.state.combo or 0 - local holy = self.state.holy or 1 - if si.adddurationcp then - duration = duration + si.adddurationcp * combo - end - if si.adddurationholy then - duration = duration + si.adddurationholy * (holy - 1) - end - if si.tick then -- DoT - --DoT duration is tick * numTicks. - local tick = OvaleAura:GetTickLength(auraSpellId) - local numTicks = floor(duration / tick + 0.5) - duration = tick * numTicks - return duration, tick, numTicks - end - return duration - end +--[[------------------------------ + Legacy methods for transition. +--]]------------------------------ +function OvaleState:GetCounterValue(id) + return self.state:GetCounterValue(id) end --- Print out the levels of each power type in the current state. -function OvaleState:DebugPower() - for powerType in pairs(OvalePower.POWER_INFO) do - Ovale:FormatPrint("%s = %d", powerType, self.state[powerType]) - end +function OvaleState:GetCD(spellId) + return self.state:GetCD(spellId) +end + +function OvaleState:GetComputedSpellCD(spellId) + return self.state:GetSpellCooldown(spellId) +end + +function OvaleState:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) + return self.state:GetAuraByGUID(guid, spellId, filter, mine, unitId, auraFound) +end + +function OvaleState:GetAura(unitId, spellId, filter, mine, auraFound) + return self.state:GetAura(unitId, spellId, filter, mine, auraFound) +end + +function OvaleState:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID) + return self.state:GetAuraOnAnyTarget(spellId, filter, mine, excludingGUID) +end + +function OvaleState:NewAura(guid, spellId, filter) + return self.state:NewAura(guid, spellId, filter) +end + +function OvaleState:GetDamageMultiplier(spellId) + return self.state:GetDamageMultiplier(spellId) +end + +function OvaleState:GetDuration(auraSpellId) + return self.state:GetDuration(auraSpellId) end -- diff --git a/compiler.pl b/compiler.pl index 2399aee..6eb1c42 100644 --- a/compiler.pl +++ b/compiler.pl @@ -101,6 +101,7 @@ $sp{OvaleCondition}{ParseCondition} = true; $sp{OvaleCondition}{ParseRuneCondition} = true; $sp{OvaleCondition}{TestValue} = true; +$m{OvaleQueue}{NewQueue} = true; $sp{OvaleQueue}{Front} = true; $sp{OvaleQueue}{FrontToBackIterator} = true; $sp{OvaleQueue}{InsertBack} = true; -- 1.7.9.5