--[[-------------------------------------------------------------------- Ovale Spell Priority Copyright (C) 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 player's stats as available on the in-game paper doll. local _, Ovale = ... local OvalePaperDoll = Ovale:NewModule("OvalePaperDoll", "AceEvent-3.0") Ovale.OvalePaperDoll = OvalePaperDoll --<private-static-properties> -- Profiling set-up. local Profiler = Ovale.Profiler local profiler = nil do local group = OvalePaperDoll:GetName() Profiler:RegisterProfilingGroup(group) profiler = Profiler:GetProfilingGroup(group) end local OvalePool = Ovale.OvalePoolRefCount -- Forward declarations for module dependencies. local OvaleEquipement = nil local OvaleStance = nil local OvaleState = nil local tonumber = tonumber local API_GetCombatRating = GetCombatRating local API_GetCritChance = GetCritChance local API_GetMastery = GetMastery local API_GetMasteryEffect = GetMasteryEffect local API_GetMeleeHaste = GetMeleeHaste local API_GetRangedCritChance = GetRangedCritChance local API_GetRangedHaste = GetRangedHaste local API_GetSpecialization = GetSpecialization local API_GetSpellBonusDamage = GetSpellBonusDamage local API_GetSpellBonusHealing = GetSpellBonusHealing local API_GetSpellCritChance = GetSpellCritChance local API_GetTime = GetTime local API_UnitAttackPower = UnitAttackPower local API_UnitAttackSpeed = UnitAttackSpeed local API_UnitClass = UnitClass local API_UnitDamage = UnitDamage local API_UnitLevel = UnitLevel local API_UnitRangedAttackPower = UnitRangedAttackPower local API_UnitSpellHaste = UnitSpellHaste local API_UnitStat = UnitStat local CR_CRIT_MELEE = CR_CRIT_MELEE local CR_HASTE_MELEE = CR_HASTE_MELEE -- Player's class. local _, self_class = API_UnitClass("player") -- Snapshot table pool. local self_pool = OvalePool("OvalePaperDoll_pool") -- Total number of snapshots taken. local self_snapshotCount = 0 local OVALE_PAPERDOLL_DEBUG = "paper_doll" local OVALE_SNAPSHOT_DEBUG = "snapshot" local OVALE_SPELLDAMAGE_SCHOOL = { DEATHKNIGHT = 4, -- Nature DRUID = 4, -- Nature HUNTER = 4, -- Nature MAGE = 5, -- Frost MONK = 4, -- Nature PALADIN = 2, -- Holy PRIEST = 2, -- Holy ROGUE = 4, -- Nature SHAMAN = 4, -- Nature WARLOCK = 6, -- Shadow WARRIOR = 4, -- Nature } local OVALE_HEALING_CLASS = { DRUID = true, MONK = true, PALADIN = true, PRIEST = true, SHAMAN = true, } local OVALE_SPECIALIZATION_NAME = { DEATHKNIGHT = { "blood", "frost", "unholy" }, DRUID = { "balance", "feral", "guardian", "restoration" }, HUNTER = { "beast_mastery", "marksmanship", "survival" }, MAGE = { "arcane", "fire", "frost" }, MONK = { "brewmaster", "mistweaver", "windwalker" }, PALADIN = { "holy", "protection", "retribution" }, PRIEST = { "discipline", "holy", "shadow" }, ROGUE = { "assassination", "combat", "subtlety" }, SHAMAN = { "elemental", "enhancement", "restoration" }, WARLOCK = { "affliction", "demonology", "destruction" }, WARRIOR = { "arms", "fury", "protection" }, } --</private-static-properties> --<public-static-properties> -- player's level OvalePaperDoll.level = API_UnitLevel("player") -- Player's current specialization. OvalePaperDoll.specialization = nil -- Most recent snapshot. OvalePaperDoll.snapshot = nil -- Maps field names to default value & descriptions for player's stats. OvalePaperDoll.SNAPSHOT_STATS = { -- primary stats agility = { default = 0, description = "agility" }, intellect = { default = 0, description = "intellect" }, spirit = { default = 0, description = "spirit" }, stamina = { default = 0, description = "stamina" }, strength = { default = 0, description = "strength" }, attackPower = { default = 0, description = "attack power" }, rangedAttackPower = { default = 0, description = "ranged attack power" }, -- percent increase of effect due to mastery masteryEffect = { default = 0, description = "mastery effect" }, -- percent increase to melee critical strike & haste meleeCrit = { default = 0, description = "melee critical strike chance" }, meleeHaste = { default = 0, description = "melee haste effect" }, -- percent increase to ranged critical strike & haste rangedCrit = { default = 0, description = "ranged critical strike chance" }, rangedHaste = { default = 0, description = "ranged haste effect" }, -- percent increase to spell critical strike & haste spellCrit = { default = 0, description = "spell critical strike chance" }, spellHaste = { default = 0, description = "spell haste effect" }, -- combat rating for mastery, critical strike & haste masteryRating = { default = 0, description = "mastery rating" }, critRating = { default = 0, description = "critical strike rating" }, hasteRating = { default = 0, description = "haste rating" }, -- spellpower spellBonusDamage = { default = 0, description = "spell bonus damage" }, spellBonusHealing = { default = 0, description = "spell bonus healing" }, -- normalized weapon damage of mainhand and offhand weapons mainHandWeaponDamage = { default = 0, description = "normalized weapon damage (mainhand)" }, offHandWeaponDamage = { default = 0, description = "normalized weapon damage (offhand)" }, baseDamageMultiplier = { default = 1, description = "base damage multiplier" }, } --</public-static-properties> --<private-static-methods> -- Return table for most recent snapshot to be updated through events. local function UpdateCurrentSnapshot() local self = OvalePaperDoll local now = API_GetTime() if self.snapshot.snapshotTime < now then Ovale:DebugPrintf(OVALE_SNAPSHOT_DEBUG, true, "New snapshot.") self_snapshotCount = self_snapshotCount + 1 local snapshot = self_pool:Get() -- Pre-populate snapshot with the most recent previously-captured stats. for k in pairs(self.SNAPSHOT_STATS) do snapshot[k] = self.snapshot[k] end snapshot.snapshotTime = now self_pool:Release(self.snapshot) self.snapshot = snapshot end return self.snapshot end --</private-static-methods> --<public-static-methods> function OvalePaperDoll:OnInitialize() -- Resolve module dependencies. OvaleEquipement = Ovale.OvaleEquipement OvaleStance = Ovale.OvaleStance OvaleState = Ovale.OvaleState -- Initialize latest snapshot table. if self.snapshot then self.snapshot:Release() end self.snapshot = self_pool:Get() for k, info in pairs(self.SNAPSHOT_STATS) do self.snapshot[k] = info.default end self.snapshot.snapshotTime = 0 end function OvalePaperDoll:OnEnable() self:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED", "UpdateStats") self:RegisterEvent("COMBAT_RATING_UPDATE") self:RegisterEvent("MASTERY_UPDATE") self:RegisterEvent("PLAYER_ALIVE", "UpdateStats") self:RegisterEvent("PLAYER_DAMAGE_DONE_MODS") self:RegisterEvent("PLAYER_ENTERING_WORLD", "UpdateStats") self:RegisterEvent("PLAYER_LEVEL_UP") self:RegisterEvent("PLAYER_REGEN_ENABLED") self:RegisterEvent("PLAYER_TALENT_UPDATE", "UpdateStats") self:RegisterEvent("SPELL_POWER_CHANGED") self:RegisterEvent("UNIT_ATTACK_POWER") self:RegisterEvent("UNIT_DAMAGE", "UpdateDamage") self:RegisterEvent("UNIT_LEVEL") self:RegisterEvent("UNIT_RANGEDDAMAGE") self:RegisterEvent("UNIT_RANGED_ATTACK_POWER") self:RegisterEvent("UNIT_SPELL_HASTE") self:RegisterEvent("UNIT_STATS") self:RegisterMessage("Ovale_EquipmentChanged", "UpdateDamage") self:RegisterMessage("Ovale_StanceChanged", "UpdateDamage") OvaleState:RegisterState(self, self.statePrototype) end function OvalePaperDoll:OnDisable() OvaleState:UnregisterState(self) self:UnregisterEvent("ACTIVE_TALENT_GROUP_CHANGED") self:UnregisterEvent("COMBAT_RATING_UPDATE") self:UnregisterEvent("MASTERY_UPDATE") self:UnregisterEvent("PLAYER_ALIVE") self:UnregisterEvent("PLAYER_DAMAGE_DONE_MODS") self:UnregisterEvent("PLAYER_ENTERING_WORLD") self:UnregisterEvent("PLAYER_LEVEL_UP") self:UnregisterEvent("PLAYER_REGEN_ENABLED") self:UnregisterEvent("PLAYER_TALENT_UPDATE") self:UnregisterEvent("SPELL_POWER_CHANGED") self:UnregisterEvent("UNIT_ATTACK_POWER") self:UnregisterEvent("UNIT_DAMAGE") self:UnregisterEvent("UNIT_LEVEL") self:UnregisterEvent("UNIT_RANGEDDAMAGE") self:UnregisterEvent("UNIT_RANGED_ATTACK_POWER") self:UnregisterEvent("UNIT_SPELL_HASTE") self:UnregisterEvent("UNIT_STATS") self:UnregisterMessage("Ovale_EquipmentChanged") self:UnregisterMessage("Ovale_StanceChanged") self_pool:Drain() end function OvalePaperDoll:COMBAT_RATING_UPDATE(event) profiler.Start("OvalePaperDoll_UpdateStats") local snapshot = UpdateCurrentSnapshot() snapshot.meleeCrit = API_GetCritChance() snapshot.rangedCrit = API_GetRangedCritChance() snapshot.spellCrit = API_GetSpellCritChance(OVALE_SPELLDAMAGE_SCHOOL[self_class]) snapshot.critRating = API_GetCombatRating(CR_CRIT_MELEE) snapshot.hasteRating = API_GetCombatRating(CR_HASTE_MELEE) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s", event) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %f%%", self.SNAPSHOT_STATS["meleeCrit"].description, snapshot.meleeCrit) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %f%%", self.SNAPSHOT_STATS["rangedCrit"].description, snapshot.rangedCrit) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %f%%", self.SNAPSHOT_STATS["spellCrit"].description, snapshot.spellCrit) profiler.Stop("OvalePaperDoll_UpdateStats") end function OvalePaperDoll:MASTERY_UPDATE(event) profiler.Start("OvalePaperDoll_UpdateStats") local snapshot = UpdateCurrentSnapshot() snapshot.masteryRating = API_GetMastery() if self.level < 80 then snapshot.masteryEffect = 0 else snapshot.masteryEffect = API_GetMasteryEffect() Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s: %s = %f%%", event, self.SNAPSHOT_STATS["masteryEffect"].description, snapshot.masteryEffect) end profiler.Stop("OvalePaperDoll_UpdateStats") end function OvalePaperDoll:PLAYER_LEVEL_UP(event, level, ...) profiler.Start("OvalePaperDoll_UpdateStats") self.level = tonumber(level) or API_UnitLevel("player") Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s: level = %d", event, self.level) profiler.Stop("OvalePaperDoll_UpdateStats") end function OvalePaperDoll:PLAYER_DAMAGE_DONE_MODS(event, unitId) profiler.Start("OvalePaperDoll_UpdateStats") local snapshot = UpdateCurrentSnapshot() snapshot.spellBonusHealing = API_GetSpellBonusHealing() Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s: %s = %d", event, self.SNAPSHOT_STATS["spellBonusHealing"].description, snapshot.spellBonusHealing) profiler.Stop("OvalePaperDoll_UpdateStats") end function OvalePaperDoll:PLAYER_REGEN_DISABLED(event) self_snapshotCount = 0 end function OvalePaperDoll:PLAYER_REGEN_ENABLED(event) profiler.Start("OvalePaperDoll_UpdateStats") local now = API_GetTime() if Ovale.enCombat and Ovale.combatStartTime then Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%d snapshots in %f seconds.", self_snapshotCount, now - Ovale.combatStartTime) end self_pool:Drain() profiler.Stop("OvalePaperDoll_UpdateStats") end function OvalePaperDoll:SPELL_POWER_CHANGED(event) profiler.Start("OvalePaperDoll_UpdateStats") local snapshot = UpdateCurrentSnapshot() snapshot.spellBonusDamage = API_GetSpellBonusDamage(OVALE_SPELLDAMAGE_SCHOOL[self_class]) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s: %s = %d", event, self.SNAPSHOT_STATS["spellBonusDamage"].description, snapshot.spellBonusDamage) profiler.Stop("OvalePaperDoll_UpdateStats") end function OvalePaperDoll:UNIT_ATTACK_POWER(event, unitId) if unitId == "player" then profiler.Start("OvalePaperDoll_UpdateStats") local snapshot = UpdateCurrentSnapshot() local base, posBuff, negBuff = API_UnitAttackPower(unitId) snapshot.attackPower = base + posBuff + negBuff Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s: %s = %d", event, self.SNAPSHOT_STATS["attackPower"].description, snapshot.attackPower) self:UpdateDamage(event) profiler.Stop("OvalePaperDoll_UpdateStats") end end function OvalePaperDoll:UNIT_LEVEL(event, unitId) if unitId == "player" then profiler.Start("OvalePaperDoll_UpdateStats") self.level = API_UnitLevel(unitId) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s: level = %d", event, self.level) profiler.Stop("OvalePaperDoll_UpdateStats") end end function OvalePaperDoll:UNIT_RANGEDDAMAGE(event, unitId) if unitId == "player" then profiler.Start("OvalePaperDoll_UpdateStats") local snapshot = UpdateCurrentSnapshot() snapshot.rangedHaste = API_GetRangedHaste() Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s: %s = %f%%", event, self.SNAPSHOT_STATS["rangedHaste"].description, snapshot.rangedHaste) profiler.Stop("OvalePaperDoll_UpdateStats") end end function OvalePaperDoll:UNIT_RANGED_ATTACK_POWER(event, unitId) if unitId == "player" then profiler.Start("OvalePaperDoll_UpdateStats") local base, posBuff, negBuff = API_UnitRangedAttackPower(unitId) local snapshot = UpdateCurrentSnapshot() snapshot.rangedAttackPower = base + posBuff + negBuff Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s: %s = %d", event, self.SNAPSHOT_STATS["rangedAttackPower"].description, snapshot.rangedAttackPower) profiler.Stop("OvalePaperDoll_UpdateStats") end end function OvalePaperDoll:UNIT_SPELL_HASTE(event, unitId) if unitId == "player" then profiler.Start("OvalePaperDoll_UpdateStats") local snapshot = UpdateCurrentSnapshot() snapshot.meleeHaste = API_GetMeleeHaste() snapshot.spellHaste = API_UnitSpellHaste(unitId) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s", event) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %f%%", self.SNAPSHOT_STATS["meleeHaste"].description, snapshot.meleeHaste) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %f%%", self.SNAPSHOT_STATS["spellHaste"].description, snapshot.spellHaste) self:UpdateDamage(event) profiler.Stop("OvalePaperDoll_UpdateStats") end end function OvalePaperDoll:UNIT_STATS(event, unitId) if unitId == "player" then profiler.Start("OvalePaperDoll_UpdateStats") local snapshot = UpdateCurrentSnapshot() snapshot.strength = API_UnitStat(unitId, 1) snapshot.agility = API_UnitStat(unitId, 2) snapshot.stamina = API_UnitStat(unitId, 3) snapshot.intellect = API_UnitStat(unitId, 4) snapshot.spirit = API_UnitStat(unitId, 5) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s", event) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %d", self.SNAPSHOT_STATS["agility"].description, snapshot.agility) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %d", self.SNAPSHOT_STATS["intellect"].description, snapshot.intellect) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %d", self.SNAPSHOT_STATS["spirit"].description, snapshot.spirit) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %d", self.SNAPSHOT_STATS["stamina"].description, snapshot.stamina) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %d", self.SNAPSHOT_STATS["strength"].description, snapshot.strength) self:COMBAT_RATING_UPDATE(event) profiler.Stop("OvalePaperDoll_UpdateStats") end end function OvalePaperDoll:UpdateDamage(event) profiler.Start("OvalePaperDoll_UpdateDamage") local minDamage, maxDamage, minOffHandDamage, maxOffHandDamage, _, _, damageMultiplier = API_UnitDamage("player") local mainHandAttackSpeed, offHandAttackSpeed = API_UnitAttackSpeed("player") local snapshot = UpdateCurrentSnapshot() snapshot.baseDamageMultiplier = damageMultiplier if self_class == "DRUID" and OvaleStance:IsStance("druid_cat_form") then -- Cat Form: 100% increased auto-attack damage. damageMultiplier = damageMultiplier * 2 elseif self_class == "MONK" and OvaleEquipement:HasOneHandedWeapon() then -- Way of the Monk: 40% increased auto-attack damage if dual-wielding. damageMultiplier = damageMultiplier * 1.4 end -- weaponDamage = (weaponDPS + attackPower / 14) * weaponSpeed -- normalizedWeaponDamage = (weaponDPS + attackPower / 14) * normalizedWeaponSpeed local avgDamage = (minDamage + maxDamage) / 2 / damageMultiplier local mainHandWeaponSpeed = mainHandAttackSpeed * self:GetMeleeHasteMultiplier() local normalizedMainHandWeaponSpeed = OvaleEquipement.mainHandWeaponSpeed or 0 if self_class == "DRUID" then if OvaleStance:IsStance("druid_cat_form") then normalizedMainHandWeaponSpeed = 1 elseif OvaleStance:IsStance("druid_bear_form") then normalizedMainHandWeaponSpeed = 2.5 end end snapshot.mainHandWeaponDamage = avgDamage / mainHandWeaponSpeed * normalizedMainHandWeaponSpeed --Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " MH weapon damage = ((%f + %f) / 2 / %f) / %f * %f", -- minDamage, maxDamage, damageMultiplier, mainHandWeaponSpeed, normalizedMainHandWeaponSpeed) if OvaleEquipement:HasOffHandWeapon() then local avgOffHandDamage = (minOffHandDamage + maxOffHandDamage) / 2 / damageMultiplier -- Sometimes, UnitAttackSpeed() doesn't return a value for OH attack speed, so approximate with MH one. offHandAttackSpeed = offHandAttackSpeed or mainHandAttackSpeed local offHandWeaponSpeed = offHandAttackSpeed * self:GetMeleeHasteMultiplier() local normalizedOffHandWeaponSpeed = OvaleEquipement.offHandWeaponSpeed or 0 if self_class == "DRUID" then if OvaleStance:IsStance("druid_cat_form") then normalizedOffHandWeaponSpeed = 1 elseif OvaleStance:IsStance("druid_bear_form") then normalizedOffHandWeaponSpeed = 2.5 end end snapshot.offHandWeaponDamage = avgOffHandDamage / offHandWeaponSpeed * normalizedOffHandWeaponSpeed --Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " OH weapon damage = ((%f + %f) / 2 / %f) / %f * %f", -- minOffHandDamage, maxOffHandDamage, damageMultiplier, offHandWeaponSpeed, normalizedOffHandWeaponSpeed) else snapshot.offHandWeaponDamage = 0 end Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, true, "%s", event) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %f", self.SNAPSHOT_STATS["baseDamageMultiplier"].description, snapshot.baseDamageMultiplier) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %f", self.SNAPSHOT_STATS["mainHandWeaponDamage"].description, snapshot.mainHandWeaponDamage) Ovale:DebugPrintf(OVALE_PAPERDOLL_DEBUG, " %s = %f", self.SNAPSHOT_STATS["offHandWeaponDamage"].description, snapshot.offHandWeaponDamage) profiler.Stop("OvalePaperDoll_UpdateDamage") end function OvalePaperDoll:UpdateSpecialization(event) profiler.Start("OvalePaperDoll_UpdateSpecialization") local newSpecialization = API_GetSpecialization() if self.specialization ~= newSpecialization then local oldSpecialization = self.specialization self.specialization = newSpecialization self:SendMessage("Ovale_SpecializationChanged", self:GetSpecialization(newSpecialization), self:GetSpecialization(oldSpecialization)) end profiler.Stop("OvalePaperDoll_UpdateSpecialization") end function OvalePaperDoll:UpdateStats(event) self:UpdateSpecialization(event) self:COMBAT_RATING_UPDATE(event) self:MASTERY_UPDATE(event) self:PLAYER_DAMAGE_DONE_MODS(event, "player") self:SPELL_POWER_CHANGED(event) self:UNIT_ATTACK_POWER(event, "player") self:UNIT_RANGEDDAMAGE(event, "player") self:UNIT_RANGED_ATTACK_POWER(event, "player") self:UNIT_SPELL_HASTE(event, "player") self:UNIT_STATS(event, "player") self:UpdateDamage(event) end function OvalePaperDoll:GetMasteryMultiplier(snapshot) snapshot = snapshot or self:CurrentSnapshot() return 1 + snapshot.masteryEffect / 100 end function OvalePaperDoll:GetMeleeHasteMultiplier(snapshot) snapshot = snapshot or self:CurrentSnapshot() return 1 + snapshot.meleeHaste / 100 end function OvalePaperDoll:GetRangedHasteMultiplier(snapshot) snapshot = snapshot or self:CurrentSnapshot() return 1 + snapshot.rangedHaste / 100 end function OvalePaperDoll:GetSpellHasteMultiplier(snapshot) snapshot = snapshot or self:CurrentSnapshot() return 1 + snapshot.spellHaste / 100 end -- Return the given specialization's name, or the current one if none is specified. function OvalePaperDoll:GetSpecialization(specialization) specialization = specialization or self.specialization return OVALE_SPECIALIZATION_NAME[self_class][specialization] end -- Return true if the current specialization matches the given name. function OvalePaperDoll:IsSpecialization(name) if name and self.specialization then if type(name) == "number" then return name == self.specialization else return name == OVALE_SPECIALIZATION_NAME[self_class][self.specialization] end end return false end -- Copy the current snapshot into the given snapshot table. function OvalePaperDoll:UpdateSnapshot(snapshot) profiler.Start("OvalePaperDoll:UpdateSnapshot") local snapshot = self:CurrentSnapshot() for k in pairs(self.SNAPSHOT_STATS) do snapshot[k] = self.snapshot[k] end profiler.Stop("OvalePaperDoll:UpdateSnapshot") return snapshot end -- Return a raw reference to the current snapshot. function OvalePaperDoll:CurrentSnapshot() local now = API_GetTime() if self.snapshot.snapshotTime < now then self:UpdateStats("CurrentSnapshot") end return self.snapshot end -- Get a new reference to a snapshot; if no snapshot is specified, use the current one. function OvalePaperDoll:GetSnapshot(snapshot) snapshot = snapshot or self:CurrentSnapshot() return self_pool:GetReference(snapshot) end -- Release a reference to the given snapshot. function OvalePaperDoll:ReleaseSnapshot(snapshot) return self_pool:ReleaseReference(snapshot) end function OvalePaperDoll:Debug(snapshot) snapshot = snapshot or self.snapshot self_pool:Debug() Ovale:FormatPrint("Total snapshots: %d", self_snapshotCount) Ovale:FormatPrint("Level: %d", self.level) Ovale:FormatPrint("Specialization: %s", self.specialization) Ovale:FormatPrint("Snapshot time: %f", snapshot.snapshotTime) Ovale:FormatPrint("%s: %d", self.SNAPSHOT_STATS["agility"].description, snapshot.agility) Ovale:FormatPrint("%s: %d", self.SNAPSHOT_STATS["intellect"].description, snapshot.intellect) Ovale:FormatPrint("%s: %d", self.SNAPSHOT_STATS["spirit"].description, snapshot.spirit) Ovale:FormatPrint("%s: %d", self.SNAPSHOT_STATS["stamina"].description, snapshot.stamina) Ovale:FormatPrint("%s: %d", self.SNAPSHOT_STATS["strength"].description, snapshot.strength) Ovale:FormatPrint("%s: %d", self.SNAPSHOT_STATS["attackPower"].description, snapshot.attackPower) Ovale:FormatPrint("%s: %d", self.SNAPSHOT_STATS["rangedAttackPower"].description, snapshot.rangedAttackPower) Ovale:FormatPrint("%s: %d", self.SNAPSHOT_STATS["spellBonusDamage"].description, snapshot.spellBonusDamage) Ovale:FormatPrint("%s: %d", self.SNAPSHOT_STATS["spellBonusHealing"].description, snapshot.spellBonusHealing) Ovale:FormatPrint("%s: %f%%", self.SNAPSHOT_STATS["spellCrit"].description, snapshot.spellCrit) Ovale:FormatPrint("%s: %f%%", self.SNAPSHOT_STATS["spellHaste"].description, snapshot.spellHaste) Ovale:FormatPrint("%s: %f%%", self.SNAPSHOT_STATS["meleeCrit"].description, snapshot.meleeCrit) Ovale:FormatPrint("%s: %f%%", self.SNAPSHOT_STATS["meleeHaste"].description, snapshot.meleeHaste) Ovale:FormatPrint("%s: %f%%", self.SNAPSHOT_STATS["rangedCrit"].description, snapshot.rangedCrit) Ovale:FormatPrint("%s: %f%%", self.SNAPSHOT_STATS["rangedHaste"].description, snapshot.rangedHaste) Ovale:FormatPrint("%s: %f%%", self.SNAPSHOT_STATS["masteryEffect"].description, snapshot.masteryEffect) Ovale:FormatPrint("%s: %f%%", self.SNAPSHOT_STATS["critRating"].description, snapshot.critRating) Ovale:FormatPrint("%s: %f%%", self.SNAPSHOT_STATS["hasteRating"].description, snapshot.hasteRating) Ovale:FormatPrint("%s: %f%%", self.SNAPSHOT_STATS["masteryRating"].description, snapshot.masteryRating) Ovale:FormatPrint("%s: %f", self.SNAPSHOT_STATS["baseDamageMultiplier"].description, snapshot.baseDamageMultiplier) Ovale:FormatPrint("%s: %f", self.SNAPSHOT_STATS["mainHandWeaponDamage"].description, snapshot.mainHandWeaponDamage) Ovale:FormatPrint("%s: %f", self.SNAPSHOT_STATS["offHandWeaponDamage"].description, snapshot.offHandWeaponDamage) end --</public-static-methods> --[[---------------------------------------------------------------------------- State machine for simulator. --]]---------------------------------------------------------------------------- --<public-static-properties> OvalePaperDoll.statePrototype = {} --</public-static-properties> --<private-static-properties> local statePrototype = OvalePaperDoll.statePrototype --</private-static-properties> --<state-properties> -- Player's class. statePrototype.class = nil -- Player's level. statePrototype.level = nil -- Player's chosen specialization/mastery. statePrototype.specialization = nil -- Player's current snapshot. statePrototype.snapshot = nil --</state-properties> --<public-static-methods> -- Initialize the state. function OvalePaperDoll:InitializeState(state) state.class = nil state.level = nil state.specialization = nil state.snapshot = nil end -- Reset the state to the current conditions. function OvalePaperDoll:ResetState(state) state.class = self_class state.level = self.level state.specialization = self.specialization local now = API_GetTime() if state.snapshot and state.snapshot.snapshotTime < now then self_pool:ReleaseReference(state.snapshot) state.snapshot = nil end state.snapshot = state.snapshot or self_pool:GetReference(self.snapshot) end -- Release state resources prior to removing from the simulator. function OvalePaperDoll:CleanState(state) self_pool:ReleaseReference(state.snapshot) end --</public-static-methods> --<state-methods> statePrototype.GetMasteryMultiplier = function(state, snapshot) snapshot = snapshot or state.snapshot return OvalePaperDoll:GetMasteryMultiplier(snapshot) end statePrototype.GetMeleeHasteMultiplier = function(state, snapshot) snapshot = snapshot or state.snapshot return OvalePaperDoll:GetMeleeHasteMultiplier(snapshot) end statePrototype.GetRangedHasteMultiplier = function(state, snapshot) snapshot = snapshot or state.snapshot return OvalePaperDoll:GetRangedHasteMultiplier(snapshot) end statePrototype.GetSpellHasteMultiplier = function(state, snapshot) snapshot = snapshot or state.snapshot return OvalePaperDoll:GetSpellHasteMultiplier(snapshot) end --</state-methods>