--[[-------------------------------------------------------------------- Ovale Spell Priority 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. --]]-------------------------------------------------------------------- -- This addon tracks the number of combo points by the player on the current target. local _, Ovale = ... local OvaleComboPoints = Ovale:NewModule("OvaleComboPoints", "AceEvent-3.0") Ovale.OvaleComboPoints = OvaleComboPoints --<private-static-properties> -- Profiling set-up. local Profiler = Ovale.Profiler local profiler = nil do local group = OvaleComboPoints:GetName() Profiler:RegisterProfilingGroup(group) profiler = Profiler:GetProfilingGroup(group) end -- Forward declarations for module dependencies. local OvaleAura = nil local OvaleData = nil local OvaleFuture = nil local OvaleGUID = nil local OvaleState = nil local API_GetComboPoints = GetComboPoints local API_UnitClass = UnitClass local MAX_COMBO_POINTS = MAX_COMBO_POINTS -- Player's class. local _, self_class = API_UnitClass("player") -- Table of functions to update spellcast information to register with OvaleFuture. local self_updateSpellcastInfo = {} --</private-static-properties> --<public-static-properties> OvaleComboPoints.combo = 0 --</public-static-properties> --<private-static-methods> -- Manage spellcast.combo information. local function SaveToSpellcast(spellcast) if spellcast.spellId then local si = OvaleData.spellInfo[spellcast.spellId] if si.combo == "finisher" then -- If a buff is present that removes the combo point cost of the spell, -- then treat it as a maximum combo-point finisher. if si.buff_combo_none then if OvaleAura:GetAura("player", si.buff_combo_none) then spellcast.combo = MAX_COMBO_POINTS end end local min_combo = si.min_combo or si.mincombo or 1 if OvaleComboPoints.combo >= min_combo then spellcast.combo = OvaleComboPoints.combo end end end end local function UpdateFromSpellcast(dest, spellcast) if spellcast.combo then dest.combo = spellcast.combo end end do self_updateSpellcastInfo.SaveToSpellcast = SaveToSpellcast self_updateSpellcastInfo.UpdateFromSpellcast = UpdateFromSpellcast end --</private-static-methods> --<public-static-methods> function OvaleComboPoints:OnInitialize() -- Resolve module dependencies. OvaleAura = Ovale.OvaleAura OvaleData = Ovale.OvaleData OvaleFuture = Ovale.OvaleFuture OvaleGUID = Ovale.OvaleGUID OvaleState = Ovale.OvaleState end function OvaleComboPoints:OnEnable() if self_class == "ROGUE" or self_class == "DRUID" then self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") self:RegisterEvent("PLAYER_ENTERING_WORLD", "Refresh") self:RegisterEvent("PLAYER_LOGIN", "Refresh") self:RegisterEvent("PLAYER_TARGET_CHANGED", "Refresh") self:RegisterEvent("UNIT_COMBO_POINTS") self:RegisterEvent("UNIT_TARGET", "UNIT_COMBO_POINTS") OvaleState:RegisterState(self, self.statePrototype) OvaleFuture:RegisterSpellcastInfo(self_updateSpellcastInfo) end end function OvaleComboPoints:OnDisable() if self_class == "ROGUE" or self_class == "DRUID" then OvaleState:UnregisterState(self) OvaleFuture:UnregisterSpellcastInfo(self_updateSpellcastInfo) self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") self:UnregisterEvent("PLAYER_ENTERING_WORLD") self:UnregisterEvent("PLAYER_LOGIN") self:UnregisterEvent("PLAYER_TARGET_CHANGED") self:UnregisterEvent("UNIT_COMBO_POINTS") self:UnregisterEvent("UNIT_TARGET") end end --[[ A rogue's Seal Fate or a druid's Primal Fury are passive abilities that grant an extra combo point when a combo-point generator critically strikes the target. Workaround the "combo point delay" after a generator critically strikes the target by catching the critical strike damage event and adding the given number of extra combo points. The delay MUST be less than the GCD. An ability that generates extra combo points after it critically strikes the target should have a "critcombo=N" parameter in its SpellInfo() description, where N is the number of extra combo points to add, e.g., critcombo=1. --]] function OvaleComboPoints:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, cleuEvent, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags, ...) local arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23 = ... if sourceGUID == OvaleGUID:GetGUID("player") and destGUID == OvaleGUID:GetGUID("target") then if cleuEvent == "SPELL_DAMAGE" then local spellId, critical = arg12, arg21 local si = OvaleData.spellInfo[spellId] if critical and si and si.critcombo then self.combo = self.combo + si.critcombo if self.combo > MAX_COMBO_POINTS then self.combo = MAX_COMBO_POINTS end end end end end function OvaleComboPoints:UNIT_COMBO_POINTS(event, ...) local unitId = ... if unitId == "player" then self:Refresh() end end function OvaleComboPoints:Refresh() profiler.Start("OvaleComboPoints_Refresh") self.combo = API_GetComboPoints("player") or 0 profiler.Stop("OvaleComboPoints_Refresh") end function OvaleComboPoints:Debug() Ovale:FormatPrint("Player has %d combo points on target %s.", self.combo, OvaleGUID:GetGUID("target")) end --</public-static-methods> --[[---------------------------------------------------------------------------- State machine for simulator. --]]---------------------------------------------------------------------------- --<public-static-properties> OvaleComboPoints.statePrototype = {} --</public-static-properties> --<private-static-properties> local statePrototype = OvaleComboPoints.statePrototype --</private-static-properties> --<state-properties> statePrototype.combo = nil --</state-properties> --<public-static-methods> -- Initialize the state. function OvaleComboPoints:InitializeState(state) state.combo = 0 end -- Reset the state to the current conditions. function OvaleComboPoints:ResetState(state) profiler.Start("OvaleComboPoints_ResetState") state.combo = self.combo or 0 profiler.Stop("OvaleComboPoints_ResetState") end -- Apply the effects of the spell on the player's state, assuming the spellcast completes. function OvaleComboPoints:ApplySpellAfterCast(state, spellId, targetGUID, startCast, endCast, nextCast, isChanneled, nocd, spellcast) profiler.Start("OvaleComboPoints_ApplySpellAfterCast") local si = OvaleData.spellInfo[spellId] if si and si.combo then local cost = state:ComboPointCost(spellId) local power = state.combo power = power - cost -- 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 profiler.Stop("OvaleComboPoints_ApplySpellAfterCast") end --</public-static-methods> --<state-methods> -- Return the number of combo points required to cast the given spell. statePrototype.ComboPointCost = function(state, spellId) profiler.Start("OvaleComboPoints_state_ComboPointCost") local spellCost = 0 local si = OvaleData.spellInfo[spellId] if si and si.combo then local cost = si.combo --[[ combo == 0 means the that spell uses no resources. combo > 0 means that the spell generates combo points. combo < 0 means that the spell costs combo points. combo == "finisher" means that the spell uses all of the combo points (zeroes it out). --]] if cost == "finisher" then -- This spell is a finisher so compute the cost based on the amount of resources consumed. cost = state.combo -- Clamp cost between values defined by min_combo and max_combo. local minCost = si.min_combo or si.mincombo or 1 local maxCost = si.max_combo if cost < minCost then cost = minCost end if maxCost and cost > maxCost then cost = maxCost end else --[[ Add extra combo points generated by presence of a buff. "buff_combo" is the spell ID of the buff that causes extra resources to be generated or used. "buff_combo_amount" is the amount of extra resources generated or used, defaulting to 1 (one extra combo point generated). --]] local buffExtra = si.buff_combo if buffExtra then local aura = state:GetAura("player", buffExtra, nil, true) if state:IsActiveAura(aura) then local buffAmount = si.buff_combo_amount or 1 cost = cost + buffAmount end end cost = -1 * cost end local buffNoCost = si.buff_combo_none if buffNoCost then -- "buff_combo_none" is the spell ID of the buff that makes casting the spell cost zero combo points. local aura = state:GetAura("player", buffNoCost) if state:IsActiveAura(aura) then cost = 0 end end spellCost = cost end profiler.Stop("OvaleComboPoints_state_ComboPointCost") return spellCost end --</state-methods>