diff --git a/Condition.lua b/Condition.lua deleted file mode 100644 index e976bd0..0000000 --- a/Condition.lua +++ /dev/null @@ -1,1234 +0,0 @@ -local LBCT = LibStub("LibBabble-CreatureType-3.0"):GetLookupTable() -local LRC = LibStub("LibRangeCheck-2.0", true) -local runes = {} -local runesCD = {} - -local runeType = -{ - blood = 1, - unholy = 2, - frost = 3, - death = 4 -} - -local totemType = -{ - ghoul = 1, - fire = 1, - earth = 2, - water = 3, - air = 4 -} - -local fearSpellList = nil -local stunSpellList = nil -local incapacitateSpellList = nil -local rootSpellList = nil - -local function buildRootSpellList() - if (rootSpellList) then - return - end - rootSpellList = {} - for k, v in pairs(Ovale.buffSpellList.fear) do - rootSpellList[v] = true - end -end - -local function buildStunSpellList() - if (stunSpellList) then - return - end - stunSpellList = {} - for k, v in pairs(Ovale.buffSpellList.stun) do - stunListList[v] = true - end -end - -local function buildIncapacitateSpellList() - if (incapacitateSpellList) then - return - end - incapacitateSpellList = {} - for k, v in pairs(Ovale.buffSpellList.incapacitate) do - incapacitateSpellList[v] = true - end -end - -local function buildFearSpellList() - if (fearSpellList) then - return - end - fearSpellList = {} - for k, v in pairs(Ovale.buffSpellList.fear) do - fearSpellList[v] = true - end -end - -local function isDebuffInList(list) - local i=1; - while (true) do - local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId = UnitDebuff("player", i); - if (not name) then - break - end - if (list[spellId]) then - return true - end - i = i +1 - end - return false -end - -local function avecHate(temps, hate) - if not temps then - temps = 0 - end - if (not hate) then - return temps - elseif (hate == "spell") then - return temps/Ovale.spellHaste - elseif (hate == "melee") then - return temps/Ovale.meleeHaste - else - return temps - end -end - -local function compare(a, comparison, b) - if (comparison == "more") then - if (not b or (a~=nil and a>b)) then - return 0 - else - return nil - end - elseif comparison == "equal" then - if b == a then - return 0 - else - return nil - end - else - if (not a or (b~=nil and a<b)) then - return 0 - else - return nil - end - end -end - -local function testbool(a, condition) - if (condition == "yes" or not condition) then - if (a) then - return 0 - else - return nil - end - else - if (not a) then - return 0 - else - return nil - end - end -end - -local function getTarget(condition) - if (not condition) then - return "player" - else - return condition - end -end - -local function addTime(time1, duration) - if not time1 then - return nil - else - return time1 + duration - end -end - ---Return time2-time1 -local function diffTime(time1, time2) - if not time1 then - return 0 - end - if not time2 then - return nil - end - return time2 - time1 -end - -local function addOrSubTime(time1, operator, duration) - if operator == "more" then - return addTime(time1, -duration) - else - return addTime(time1, duration) - end -end - -local function nilstring(text) - if text == nil then - return "nil" - else - return text - end -end - --- Get the expiration time of a debuff --- that can be on any unit except the target --- Returns the first to expires, the last to expires --- Returns nil if the debuff is not present -local function getOtherAura(spellId, suppTime) - Ovale:EnableOtherAuras() - local otherAura = Ovale.otherAura[spellId] - if otherAura then - Ovale:Log("otherAura") - - local maxTime = 0 - local minTime = nil - suppTime = suppTime or 10 - for target,expireTime in pairs(otherAura) do - Ovale:Log("target "..target.. " "..expireTime) - if target~=UnitGUID("target") then - if Ovale.maintenant - suppTime > expireTime then - otherAura[target] = nil - else - if expireTime > maxTime then - maxTime = expireTime - end - if not minTime or diff<minTime then - minTime = diff - end - end - end - end - Ovale:Log("maxTime final "..maxTime) - return minTime, maxTime - end - return nil -end - -local function GetRune(condition) - local nombre = 0 - local nombreCD = 0 - local maxCD = nil - - for i=1,4 do - runes[i] = 0 - runesCD[i] = 0 - end - - local k=1 - while true do - local type = runeType[condition[k*2-1]] - if not type then - break - end - local howMany = condition[k*2] - runes[type] = runes[type] + howMany - k = k + 1 - end - - for i=1,6 do - local rune = Ovale.state.rune[i] - if rune then - if runes[rune.type] > 0 then - runes[rune.type] = runes[rune.type] - 1 - if rune.cd > runesCD[rune.type] then - runesCD[rune.type] = rune.cd - end - elseif rune.cd < runesCD[rune.type] then - runesCD[rune.type] = rune.cd - end - end - end - - if not condition.nodeath then - for i=1,6 do - local rune = Ovale.state.rune[i] - if rune and rune.type == 4 then - for j=1,3 do - if runes[j]>0 then - runes[j] = runes[j] - 1 - if rune.cd > runesCD[j] then - runesCD[j] = rune.cd - end - break - elseif rune.cd < runesCD[j] then - runesCD[j] = rune.cd - break - end - end - end - end - end - - for i=1,4 do - if runes[i]> 0 then - return nil - end - if not maxCD or runesCD[i]>maxCD then - maxCD = runesCD[i] - end - end - return maxCD -end - -local lastEnergyValue = nil -local lastEnergyTime - -local function GetManaAndRate(withBerserker) - local _,className = UnitClass("player") - local current = Ovale.state.mana - if current~=lastEnergyValue then - lastEnergyValue = current - lastEnergyTime = Ovale.currentTime - end - - local rate - - if className == "ROGUE" or (className == "DRUID" and GetShapeshiftForm(true) == 3) then - rate = 10 * Ovale.meleeHaste - if (className == "ROGUE") then - local rush = Ovale:GetAura("player", "HELPFUL", 13750) - if rush.stacks>0 then - rate = rate * 2 - end - elseif withBerserker then - local berserk = Ovale:GetAura("player", "HELPFUL", 50334) - if berserk.stacks>0 then - mana = mana/2 - end - end - elseif className == "HUNTER" then - rate = 4 * Ovale.meleeHaste - else - rate = 0 - end - - return lastEnergyValue, lastEnergyTime, rate -end - -local function GetManaTime(mana, withBerserker) - local lastEnergyValue, lastEnergyTime, rate = GetManaAndRate(withBerserker) - - if rate > 0 then - local limit = math.ceil((mana - lastEnergyValue) / rate + lastEnergyTime) - return limit - else - if Ovale.state.mana>=mana then - return Ovale.currentTime-1 - else - return nil - end - end -end - - --- Recherche un aura sur la cible et récupère sa durée et le nombre de stacks --- return start, ending, stacks -local function GetTargetAura(condition, filter, target) - if (not target) then - target=condition.target - if (not target) then - target="target" - end - end - local stacks = condition.stacks - if not stacks then - stacks = 1 - end - local spellId = condition[1] - - - local aura - if type(spellId) == "number" then - aura = Ovale:GetAura(target, filter, spellId) - elseif Ovale.buffSpellList[spellId] then - for k,v in pairs(Ovale.buffSpellList[spellId]) do - local newAura = Ovale:GetAura(target, filter, v) - if not aura or newAura.stacks>aura.stacks then - aura = newAura - end - end - elseif spellId == "Magic" or spellId == "Disease" or spellId=="Curse" or spellId=="Poison" then - aura = Ovale:GetAura(target, filter, spellId) - else - Ovale:Print("ERROR: unknown buff "..spellId) - Ovale.bug = true - return 0,0 - end - - if Ovale.trace then - Ovale:Print("GetTargetAura = start=".. nilstring(aura.start) .. " end="..nilstring(aura.ending).." stacks=" ..nilstring(aura.stacks).."/"..stacks) - end - - if (not condition.mine or (aura.mine and condition.mine==1) or (not aura.mine and condition.mine==0)) and aura.stacks>=stacks then - local ending - if condition.forceduration then - if Ovale.spellInfo[spellId] and Ovale.spellInfo[spellId].duration then - ending = aura.start + Ovale.spellInfo[spellId].duration - else - ending = aura.start + condition.forceduration - end - else - ending = aura.ending - end - return aura.start, ending - else - return 0,0 - end -end - -local lastSaved = {} -local savedHealth = {} -local targetGUID = {} -local lastSPD = {} - -local function getTargetDead(target) - local second = math.floor(Ovale.maintenant) - if targetGUID[target] ~=UnitGUID(target) then - lastSaved[target] = nil - targetGUID[target] = UnitGUID(target) - savedHealth[target] = {} - end - local newHealth = UnitHealth(target) - if newHealth then - Ovale:Log("newHealth = " .. newHealth) - end - if UnitHealthMax(target)==1 then - Ovale:Log("Dummy, return in the future") - return nil - end - if second~=lastSaved[target] and targetGUID[target] then - lastSaved[target] = second - local mod10 = second % 10 - local prevHealth = savedHealth[target][mod10] - savedHealth[target][mod10] = newHealth - if prevHealth and prevHealth>newHealth then - lastSPD[target] = 10/(prevHealth-newHealth) - if lastSPD[target] > 0 then - Ovale:Log("dps = " .. (1/lastSPD[target])) - end - end - end - if not lastSPD[target] or lastSPD[target]<=0 then - return nil - end - -- Rough estimation - local duration = newHealth * lastSPD[target] - if duration < 10000 then - return Ovale.maintenant + duration - else - return nil - end -end - -Ovale.conditions= -{ - -- Test if a white hit just occured - -- 1 : maximum time after a white hit - -- Not useful anymore. No widely used spell reset swing timer anyway - --[[AfterWhiteHit = function(condition) - local debut = OvaleSwing.starttime - local fin = OvaleSwing.duration + debut - local maintenant = GetTime() - if (maintenant-debut<condition[1]) then - return 0 - elseif (maintenant<fin-0.1) then - return fin-maintenant - else - return 0.1 - end - end,]] - -- Test how many armor set parts are equiped by the player - -- 1 : set number - -- 2 : "more" or "less" - -- 3 : limit - ArmorSetParts = function(condition) - local nombre = 0 - if OvaleEquipement.nombre[condition[1]] then - nombre = OvaleEquipement.nombre[condition[1]] - end - return compare(nombre, condition[2], condition[3]) - end, - attackPower = function(condition) - local base, posBuff, negBuff = UnitAttackPower("player") - return base + posBuff + negBuff, 0, 0 - end, - BuffDuration = function(condition) - --local name, rank, icon, count, debuffType, duration = UnitBuff("player", Ovale:GetSpellInfoOrNil(condition[1])) - --if not name then --- return nil - -- end - local start, ending = GetTargetAura(condition, "HELPFUL", getTarget(condition.target)) - return compare(diffTime(start, ending), condition[2], condition[3]) - end, - -- Test if a buff will expire on the player after a given time - -- 1 : buff spell id - -- 2 : expiration time - BuffExpires = function(condition) - local start, ending = GetTargetAura(condition, "HELPFUL", getTarget(condition.target)) - local timeBefore = avecHate(condition[2], condition.haste) - if Ovale.trace then - Ovale:Print("timeBefore = " .. nilstring(timeBefore)) - Ovale:Print("start = " .. nilstring(ending)) - end - return addTime(ending, -timeBefore) - end, - buffExpires = function(condition) - local start, ending = GetTargetAura(condition, "HELPFUL", getTarget(condition.target)) - if ending then - return ending - start, start, -1 - else - return nil - end - end, - -- Test if a time has elapsed since the last buff gain - -- 1 : buff spell id - -- 2 : time since the buff gain - BuffGain = function(condition) - local spellId = condition[1] - local target = getTarget(condition.target) - if spellId then - if not Ovale.buff[target][spellId] then - return 0 - end - local timeGain = Ovale.buff[target][spellId].gain - if not timeGain then - timeGain = 0 - end - - return timeGain + condition[2] - end - return 0 - end, - -- Test if a buff is active - -- 1 : the buff spell id - -- stacks : minimum number of stacks - BuffPresent = function(condition) - local start, ending = GetTargetAura(condition, "HELPFUL", getTarget(condition.target)) - local timeBefore = avecHate(condition[2], condition.haste) - return start, addTime(ending, -timeBefore) - end, - BuffStealable = function(condition) - local i = 1 - local stealable = false - local target = getTarget(condition.target) - while true do - local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable = UnitBuff(target, i) - if not name then - break - end - if isStealable then - stealable = true - break - end - i = i + 1 - end - return testbool(stealable, condition[1]) - end, - Casting = function(condition) - if Ovale.currentSpellId == condition[1] then - return Ovale.startCast, Ovale.endCast - else - return nil - end - end, - CastTime = function(condition) - local name, rank, icon, cost, isFunnel, powerType, castTime = Ovale:GetSpellInfoOrNil(condition[1]) - if Ovale.trace then - Ovale:Print("castTime/1000 = " .. (castTime/1000) .. " " .. condition[2] .. " " .. condition[3]) - end - return compare(castTime/1000, condition[2], condition[3]) - end, - castTime = function(condition) - local name, rank, icon, cost, isFunnel, powerType, castTime = Ovale:GetSpellInfoOrNil(condition[1]) - return castTime/1000, 0, 0 - end, - -- Test if a list of checkboxes is off - -- 1,... : the checkboxes names - CheckBoxOff = function(condition) - for k,v in pairs(condition) do - if (Ovale:IsChecked(v)) then - return nil - end - end - return 0 - end, - -- Test if a list of checkboxes is on - -- 1,... : the checkboxes names - CheckBoxOn = function(condition) - for k,v in pairs(condition) do - if (not Ovale:IsChecked(v)) then - return nil - end - end - return 0 - end, - Class = function(condition) - local loc, noloc = UnitClass(getTarget(condition.target)) - return testbool(noloc == condition[1], condition[2]) - end, - -- Test the target classification - -- 1 : normal, elite, or worldboss - Classification = function(condition) - local classification - local target = getTarget(condition.target) - if UnitLevel(target)==-1 then - classification = "worldboss" - else - classification = UnitClassification(target); - if (classification == "rareelite") then - classification = "elite" - elseif (classification == "rare") then - classification = "normal" - end - end - - if (condition[1]==classification) then - return 0 - else - return nil - end - end, - -- Test how many combo points a feral druid or a rogue has - -- 1 : "less" or "more" - -- 2 : the limit - ComboPoints = function(condition) - local points = Ovale.state.combo - return compare(points, condition[1], condition[2]) - end, - comboPoints = function(condition) - return Ovale.state.combo, 0, 0 - end, - Counter = function(condition) - return compare(Ovale:GetCounterValue(condition[1]), condition[2], condition[3]) - end, - counter = function(condition) - return Ovale:GetCounterValue(condition[1]), 0, 0 - end, - CreatureFamily = function(condition) - return testbool(UnitCreatureFamily(getTarget(condition.target)) == LBCT[condition[1]], condition[2]) - end, - CreatureType = function(condition) - for _,v in pairs(condition) do - if (UnitCreatureType(getTarget(condition.target)) == LBCT[v]) then - return 0 - end - end - return nil - end, - damage = function(condition) - local spellInfo = Ovale:GetSpellInfo(condition[1]) - if not spellInfo then - return nil - end - local ret = (spellInfo.base or 0) - if spellInfo.bonuscp then - ret = ret + (Ovale.state.combo * spellInfo.bonuscp) - end - if spellInfo.bonusholy then - ret = ret + (Ovale.state.holy * spellInfo.bonusholy) - end - if spellInfo.bonusap then - ret = ret + spellInfo.bonusap * UnitAttackPower("player") - end - if spellInfo.bonusapcp then - ret = ret + spellInfo.bonusapcp * UnitAttackPower("player") * Ovale.state.combo - end - if spellInfo.bonusapholy then - ret = ret + spellInfo.bonusapholy * UnitAttackPower("player") * Ovale.state.holy - end - if spellInfo.bonussp then - ret = ret + spellInfo.bonussp * GetSpellBonusDamage(2) - end - if spellInfo.bonusspholy then - ret = ret + spellInfo.bonusspholy * GetSpellBonusDamage(2) * Ovale.state.holy - end - return ret * Ovale.damageMultiplier, 0, 0 - end, - damageMultiplier = function(condition) - return self.damageMultiplier, 0, 0 - end, - DeadIn = function(condition) - local deadAt = getTargetDead(getTarget(condition.target)) - if condition[1] == "more" then - return 0, addTime(deadAt, -condition[2]) - else - return addTime(deadAt, -condition[2]), nil - end - end, - deadIn = function(condition) - return getTargetDead(getTarget(condition.target)), 0, -1 - end, - -- Test if a debuff will expire on the target after a given time, or if there is less than the - -- given number of stacks (if stackable) - -- 1 : buff spell id - -- 2 : expiration time - -- stacks : how many stacks - -- mine : 1 means that if the debuff is not ours, the debuff is ignored - DebuffExpires = function(condition) - local start, ending = GetTargetAura(condition, "HARMFUL", getTarget(condition.target)) - local tempsMax = avecHate(condition[2], condition.haste) - return addTime(ending, -tempsMax) - end, - debuffExpires = function(condition) - local start, ending = GetTargetAura(condition, "HARMFUL", getTarget(condition.target)) - if ending then - return ending - start, start, -1 - else - return nil - end - end, - DebuffPresent = function(condition) - local start, ending = GetTargetAura(condition, "HARMFUL", getTarget(condition.target)) - local timeBefore = avecHate(condition[2], condition.haste) - return start, addTime(ending, -timeBefore) - end, - debuffTick = function(condition) - local start, ending = GetTargetAura(condition, "HARMFUL", getTarget(condition.target)) - local si = Ovale.spellInfo[condition[1]] - if not si or not si.duration then - return nil - end - local ticks = floor(Ovale.spellHaste * (si.duration/(si.tick or 3)) + 0.5) - local tickLength = (ending - start) / ticks - local tickTime = start + tickLength - for i=1,ticks do - if Ovale.currentTime<=tickTime then - break - end - tickTime = tickTime + tickLength - end - return tickTime, 0, -1 - end, - Distance = function(condition) - if LRC then - local target = getTarget(condition.target) - local minRange, maxRange = LRC:GetRange(target) - if maxRange == nil or minRange == nil then - return nil - end - if condition[1] == "more" then - if condition[2]~=nil and maxRange>condition[2] then - return 0 - else - return nil - end - else - if condition[2]~=nil and minRange<condition[2] then - return 0 - else - return nil - end - end - end - end, - distance = function(condition) - if LRC then - return LRC:GetRange(getTarget(condition.target)) - else - return nil - end - end, - --Compare to eclipse power. <0 lunar, >0 solar - Eclipse = function(condition) - return compare(Ovale.state.eclipse, condition[1], condition[2]) - end, - eclipse = function(condition) - return Ovale.state.eclipse - end, - EffectiveMana = function(condition) - local limit = GetManaTime(condition[2], true) - if condition[1]=="more" then - return limit, nil - else - return 0,limit - end - end, - effectiveMana = function(condition) - return GetManaAndRate(true) - end, - EndCastTime = function(condition) - local name, rank, icon, cost, isFunnel, powerType, castTime = Ovale:GetSpellInfoOrNil(condition[1]) - local actionCooldownStart, actionCooldownDuration, actionEnable = Ovale:GetComputedSpellCD(condition[1]) - local startCast = actionCooldownStart + actionCooldownDuration - if startCast<Ovale.currentTime then - startCast = Ovale.currentTime - end - return startCast + castTime/1000 - end, - enemies = function(condition) - return Ovale:GetNumberOfEnemies(), 0, 0 - end, - Exists = function(condition) - return testbool(UnitExists(getTarget(condition.target)) == 1, condition[1]) - end, - Glyph = function(condition) - local present = false - for i = 1, GetNumGlyphSockets() do - local enabled, glypType, glyphTooltipIndex, glyphSpellID = GetGlyphSocketInfo(i) - if (glyphSpellID == condition[1]) then - present = true - break - end - end - return testbool(present, condition[2]) - end, - HasFullControl = function(condition) - return testbool(HasFullControl(), condition[1]) - end, - HasShield = function(condition) - local _,_,id = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("SecondaryHandSlot")) or "","(item:%d+:%d+:%d+:%d+)") - if (not id) then - return testbool(false, condition[1]) - end - - local _,_,_,_,_,_,_,_,itemLoc = GetItemInfo(id) - return testbool(itemLoc=="INVTYPE_SHIELD", condition[1]) - end, - HolyPower = function(condition) - return compare(Ovale.state.holy, condition[1], condition[2]) - end, - holyPower = function(condition) - return Ovale.state.holy, 0, 0 - end, - InCombat = function(condition) - return testbool(Ovale.enCombat, condition[1]) - end, - InRange = function(condition) - local spellName = GetSpellInfo(condition[1]) - return testbool(IsSpellInRange(spellName,getTarget(condition.target))==1,condition[2]) - end, - item = function(condition) - local itemId = element.params[1] - local actionCooldownStart, actionCooldownDuration, actionEnable = GetItemCooldown(itemId) - return actionCooldownDuration, actionCooldownStart, -1 - end, - ItemCount = function(condition) - if condition.charges == 1 then - return compare(GetItemCount(condition[1], false, true), condition[2], condition[3]) - else - return compare(GetItemCount(condition[1]), condition[2], condition[3]) - end - end, - itemCount = function(condition) - if condition.charges == 1 then - return GetItemCount(condition[1], false, true), 0, 0 - else - return GetItemCount(condition[1]), 0, 0 - end - end, - IsCasting = function(condition) - local casting - local target = getTarget(condition.target) - local spellId = condition.spell - if not spellId then - return testbool(UnitCastingInfo(target) or UnitChannelInfo(target), condition[1]) - elseif type(spellId) == "number" then - local spellName = GetSpellInfo(spellId) - return testbool(UnitCastingInfo(target)==spellName or UnitChannelInfo(target) == spellName, condition[1]) - elseif Ovale.buffSpellList[spellId] then - local castSpellName = UnitCastingInfo(target) or UnitChannelInfo(target) - local found = false - for k,v in pairs(Ovale.buffSpellList[spellId]) do - local spellName = GetSpellInfo(v) - if spellName == castSpellName then - found = true - break - end - end - return testbool(found, condition[1]) - elseif spellId == "harmful" then - local castSpellName = UnitCastingInfo(target) or UnitChannelInfo(target) - return testbool(castSpellName and IsHarmfulSpell(castSpellName), condition[1]) - elseif spellId == "helpful" then - local castSpellName = UnitCastingInfo(target) or UnitChannelInfo(target) - return testbool(castSpellName and IsHelpfulSpell(castSpellName), condition[1]) - end - end, - IsFeared = function(condition) - buildFearSpellList() - return testbool(not HasFullControl() and isDebuffInList(fearSpellList), condition[1]) - end, - IsFriend = function(condition) - return testbool(UnitIsFriend("player", getTarget(condition.target)), condition[1]) - end, - IsIncapacitated = function(condition) - buildIncapacitateSpellList() - return testbool(not HasFullControl() and isDebuffInList(incapacitateSpellList), condition[1]) - end, - IsInterruptible = function(condition) - local target = getTarget(condition.target) - local spell, rank, name, icon, start, ending, isTradeSkill, castID, protected = UnitCastingInfo(target) - if not spell then - spell, rank, name, icon, start, ending, isTradeSkill, protected = UnitChannelInfo(target) - end - return testbool(protected ~= nil and not protected, condition[1]) - end, - IsRooted = function(condition) - buildRootSpellList() - return testbool(isDebuffInList(rootSpellList), condition[1]) - end, - IsStunned = function(condition) - buildStunSpellList() - return testbool(not HasFullControl() and isDebuffInList(stunSpellList), condition[1]) - end, - LastSpellDamage = function(condition) - local spellId = condition[1] - if not Ovale.spellDamage[spellId] then - return nil - end - return compare(Ovale.spellDamage[spellId], condition[2], condition[3]) - end, - lastSpellDamage = function(condition) - return Ovale.spellDamage(condition[1]) - end, - lastSpellDamageMultiplier = function(condition) - return Ovale.lastSpellDM[condition[1]], 0, 0 - end, - lastSpellAttackPower = function(condition) - return Ovale.lastSpellAP[condition[1]], 0, 0 - end, - lastSpellSpellPower = function(condition) - return Ovale.lastSpellSP[condition[1]], 0, 0 - end, - LastSwing = function(condition) - local ret = OvaleSwing:GetLast(condition[1]) - if condition[2] and ret then - ret = ret + condition[2] - end - return 0, ret - end, - lastSwing = function(condition) - return Ovale.currentTime - OvaleSwing:GetLast(condition[1]), 0, 1 - end, - -- Compare with the player level - -- 1 : "less" or "more" - -- 2 : the limit - Level = function(condition) - return compare(UnitLevel(getTarget(condition.target)), condition[1], condition[2]) - end, - level = function(condition) - return UnitLevel(condition.target) - end, - Life = function(condition) - local target = getTarget(condition.target) - return compare(UnitHealth(target), condition[1], condition[2]) - end, - life = function(condition) - local target = getTarget(condition.target) - return UnitHealth(target), 0, 0 - end, - LifeMissing = function(condition) - local target = getTarget(condition.target) - return compare(UnitHealthMax(target)-UnitHealth(target), condition[1], condition[2]) - end, - lifeMissing = function(condition) - local target = getTarget(condition.target) - return UnitHealthMax(target)-UnitHealth(target), 0, 0 - end, - -- Test if the player life is bellow/above a given value in percent - -- 1 : "less" or "more" - -- 2 : the limit, in percent - LifePercent = function(condition) - local target = getTarget(condition.target) - if UnitHealthMax(target) == nil or UnitHealthMax(target) == 0 then - return nil - end - return compare(UnitHealth(target)/UnitHealthMax(target), condition[1], condition[2]/100) - end, - lifePercent = function(condition) - local target = getTarget(condition.target) - if UnitHealthMax(target) == nil or UnitHealthMax(target) == 0 then - return nil - end - return 100 * UnitHealth(target)/UnitHealthMax(target), 0, 0 - end, - -- Test if a list item is selected - -- 1 : the list name - -- 2 : the item name - List = function(condition) - if (condition[1]) then - if (Ovale:GetListValue(condition[1]) == condition[2]) then - return 0 - end - end - return nil - end, - -- Test if the player mana is above/bellow a given value - -- 1 : "less" or "more" - -- 2 : the mana/energy/rage... limit - Mana = function(condition) - local target = getTarget(condition.target) - if target == "player" then - local limit = GetManaTime(condition[2], false) - if condition[1]=="more" then - return limit, nil - else - return 0,limit - end - else - return compare(UnitPower(target), condition[1], condition[2]) - end - end, - mana = function(condition) - return GetManaAndRate(false) - end, - ManaPercent = function(condition) - local target = getTarget(condition.target) - if UnitPowerMax(target) == 0 then - return nil - end - return compare(UnitPower(target)/UnitPowerMax(target), condition[1], condition[2]/100) - end, - manaPercent = function(condition) - local target = getTarget(condition.target) - if UnitPowerMax(target) == 0 then - return nil - end - local value, t, rate = GetManaAndRate(false) - local conversion = 100/UnitPowerMax(target) - return value * conversion, t, rate * conversion - end, - MaxHealth = function(condition) - local target = getTarget(condition.target) - return compare(UnitMaxHealth(target), condition[1], condition[2]) - end, - maxHealth = function(condition) - return UnitMaxHealth(getTarget(condition.target)), 0, 0 - end, - maxMana = function(condition) - return UnitPowerMax(getTarget(condition.target)), 0, 0 - end, - NextSwing = function(condition) - local ret = OvaleSwing:GetNext(condition[1]) - if condition[2] and ret then - ret = ret - condition[2] - end - return ret - end, - nextSwing = function(condition) - return OvaleSwing:GetNext(condition[1]) - Ovale.currentTime, 0, -1 - end, - OtherDebuffExpires = function(condition) - local minTime, maxTime = getOtherAura(condition[1], condition[3]) - if minTime then - local timeBefore = condition[2] or 0 - return minTime - timeBefore, nil - end - return 0, nil - end, - OtherDebuffPresent = function(condition) - local minTime, maxTime = getOtherAura(condition[1], condition[3]) - if maxTime and maxTime>0 then - local timeBefore = condition[2] or 0 - return 0, addTime(maxTime, -timeBefore) - end - return nil - end, - OtherAuraExpires = OtherDebuffExpires, - OtherAuraPresent = OtherDebuffPresent, - otherAura = function(condition) - local minTime, maxTime = getOtherAura(condition[1]) - return 0, maxTime, -1 - end, - Present = function(condition) - local present = UnitExists(getTarget(condition.target)) and not UnitIsDead(getTarget(condition.target)) - return testbool(present, condition[1]) - end, - -- Test if any player pet is present (or not) - -- 1 : "yes" or "no" - PetPresent = function(condition) - local present = UnitExists("pet") and not UnitIsDead("pet") - return testbool(present, condition[1]) - end, - -- Test the target level difference with the player - -- 1 : "less" or "more" - -- 2 : [target level]-[player level] limit - RelativeLevel = function(condition) - local difference - local target = getTarget(condition.target) - if UnitLevel(target) == -1 then - difference = 3 - else - difference = UnitLevel(target) - UnitLevel("player") - end - - return compare(difference, condition[1], condition[2]) - end, - remainingCastTime = function(condition) - local name, nameSubtext, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible = UnitCastingInfo(getTarget(condition.target)) - if not endTime then - return nil - end - return 0, endTime/1000, -1 - end, - Runes = function(condition) - return GetRune(condition) - end, - runes = function(condition) - local ret = GetRune(condition) - if not ret then - return nil - end - if ret < Ovale.maintenant then - ret = Ovale.maintenant - end - return 0, ret, -1 - end, - SoulShards = function(condition) - return compare(Ovale.state.shard, condition[1], condition[2]) - end, - soulShards = function(condition) - return Ovale.state.shard - end, - Speed = function(condition) - return compare(GetUnitSpeed(getTarget(condition.target))*100/7, condition[1], condition[2]) - end, - speed = function(condition) - return GetUnitSpeed(getTarget(condition.target))*100/7 - end, - spell = function(condition) - local actionCooldownStart, actionCooldownDuration, actionEnable = Ovale:GetComputedSpellCD(condition[1]) - return actionCooldownDuration, actionCooldownStart, -1 - end, - spellPower = function(condition) - return GetSpellBonusDamage(2), 0, 0 - end, - -- Test if the player is in a given stance - -- 1 : the stance - Stance = function(condition) - if (GetShapeshiftForm(true) == condition[1]) then - return 0 - else - return nil - end - end, - Stealthed = function(condition) - return testbool(IsStealthed(), condition[1]) - end, - -- Test how many talent points has been spent in a talent - -- 1 : the talent identifier (use /script print(Ovale.talentNameToId["Talent name"]) to retreive) - -- 2 : "more" or "less" - -- 3 : the limit - TalentPoints = function(condition) - if (not Ovale.listeTalentsRemplie) then - Ovale:RemplirListeTalents() - return nil - end - return compare(Ovale.pointsTalent[condition[1]], condition[2], condition[3]) - end, - talentPoints = function(condition) - if (not Ovale.listeTalentsRemplie) then - Ovale:RemplirListeTalents() - return nil - end - return Ovale.pointsTalent[condition[1]], 0, 0 - end, - -- Test if the target's target is the player (or is not) - -- 1 : "yes" (it should be the player) or "no" - TargetIsPlayer = function(condition) - return testbool(UnitIsUnit("player",getTarget(condition.target).."target"), condition[1]) - end, - Threat = function(condition) - local isTanking, status, threatpct = UnitDetailedThreatSituation("player", getTarget(condition.target)) - return compare(threatpct, condition[1], condition[2]) - end, - threat = function(condition) - local isTanking, status, threatpct = UnitDetailedThreatSituation("player", getTarget(condition.target)) - return threatpct - end, - TimeInCombat = function(condition) - if not Ovale.combatStartTime then - return nil - elseif condition[1] == "more" then - return Ovale.combatStartTime + condition[2] - else - return 0, Ovale.combatStartTime + condition[2] - end - end, - timeInCombat = function(condition) - return Ovale.maintenant - Ovale.combatStartTime, Ovale.maintenant, 1 - end, - timeToDie = function(condition) - return 0, getTargetDead(getTarget(condition.target)), -1 - end, - timeWithHaste = function(condition) - return avecHate(condition[1], "spell"),0,0 - end, - TotemExpires = function(condition) - if type(condition[1]) ~= "number" then - condition[1] = totemType[condition[1]] - end - - local haveTotem, totemName, startTime, duration = GetTotemInfo(condition[1]) - if not startTime then - return 0 - end - if (condition.totem and Ovale:GetSpellInfoOrNil(condition.totem)~=totemName) then - return 0 - end - return addTime(startTime + duration, -(condition[2] or 0)) - end, - TotemPresent = function(condition) - if type(condition[1]) ~= "number" then - condition[1] = totemType[condition[1]] - end - - local haveTotem, totemName, startTime, duration = GetTotemInfo(condition[1]) - if not startTime then - return nil - end - if (condition.totem and Ovale:GetSpellInfoOrNil(condition.totem)~=totemName) then - return nil - end - return startTime, startTime + duration - end, - Tracking = function(condition) - local what = Ovale:GetSpellInfoOrNil(condition[1]) - local numTrackingTypes = GetNumTrackingTypes() - local present = false - for i=1,numTrackingTypes do - local name, texture, active = GetTrackingInfo(i) - if name == what then - present = (active == 1) - break - end - end - return testbool(present, condition[2]) - end, - WeaponEnchantExpires = function(condition) - local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo() - if (condition[1] == "mainhand") then - if (not hasMainHandEnchant) then - return 0 - end - mainHandExpiration = mainHandExpiration/1000 - if ((condition[2] or 0) >= mainHandExpiration) then - return 0 - else - return Ovale.maintenant + mainHandExpiration - condition[2] - end - else - if (not hasOffHandEnchant) then - return 0 - end - offHandExpiration = offHandExpiration/1000 - if ((condition[2] or 0) >= offHandExpiration) then - return 0 - else - return Ovale.maintenant + offHandExpiration - condition[2] - end - end - end, -} - -Ovale.conditions.health = Ovale.conditions.life -Ovale.conditions.Health = Ovale.conditions.Life -Ovale.conditions.healthPercent = Ovale.conditions.lifePercent -Ovale.conditions.HealthPercent = Ovale.conditions.LifePercent -Ovale.conditions.HealthMissing = Ovale.conditions.LifeMissing diff --git a/Locale-esES.lua b/Locale-esES.lua new file mode 100644 index 0000000..030c053 --- /dev/null +++ b/Locale-esES.lua @@ -0,0 +1,4 @@ +local L = LibStub:GetLibrary("AceLocale-3.0"):NewLocale("Ovale", "esES", false) +if not L then return end + +--@localization(locale="esES", format="lua_additive_table", same-key-is-true=true, handle-subnamespaces="concat")@ \ No newline at end of file diff --git a/Ovale.lua b/Ovale.lua index 4812bb2..5549ffc 100644 --- a/Ovale.lua +++ b/Ovale.lua @@ -1,26 +1,19 @@ -local L = LibStub("AceLocale-3.0"):GetLocale("Ovale") Ovale = LibStub("AceAddon-3.0"):NewAddon("Ovale", "AceEvent-3.0", "AceConsole-3.0") + +--<private-static-properties> +local L = LibStub("AceLocale-3.0"):GetLocale("Ovale") local Recount = Recount local Skada = Skada +--</private-static-properties> +--<public-static-properties> --Default scripts (see "defaut" directory) Ovale.defaut = {} --The table of check boxes definition Ovale.casesACocher = {} ---key: spell name / value: action icon id -Ovale.actionSort = {} ---key: talentId / value: points in this talent -Ovale.pointsTalent = {} ---key: talentId / value: talent name (not used) -Ovale.talentIdToName = {} -Ovale.spellList = {} ---key: talent name / value: talent id -Ovale.talentNameToId = {} --allows to do some initialization the first time the addon is enabled Ovale.firstInit = false ---allows to fill the player talent tables on first use -Ovale.listeTalentsRemplie = false --the frame with the icons Ovale.frame = nil --check boxes GUI items @@ -31,235 +24,21 @@ Ovale.dropDowns = {} Ovale.masterNodes = nil --set it if there was a bug, traces will be enabled on next frame Ovale.bug = false +Ovale.traced = false --trace next script function calls Ovale.trace=false --in combat? Ovale.enCombat = false ---current computed spell haste. "2" means 2 times faster -Ovale.spellHaste = 1 ---current computed melee haste TODO: why I don't use character sheet value anyway? -Ovale.meleeHaste = 1 ---current auras -Ovale.aura = { player = {}, target = {}} ---allow to track the current target -Ovale.targetGUID = nil ---spell info from the current script (by spellId) -Ovale.spellInfo = {} ---track when a buff was applied (used for the old eclipse mechanism, maybe this could be removed?) -Ovale.buff = {} ---player class -Ovale.className = nil ---the state in the current frame ---TODO: really, the simulator should be in its own class -Ovale.state = {rune={}, cd = {}, counter={}} ---spells that count for scoring -Ovale.scoreSpell = {} ---tracks debuffs on the units that are not the current target -Ovale.otherAura = {} --score in current combat Ovale.score = 0 --maximal theoric score in current combat Ovale.maxScore = 0 ---increased at each frame, allows to know if the aura was updated this frame ---TODO: aura should be tracked using combat log events or something like that ---and it should be in its own class -Ovale.serial = 0 ---spell counter (see Counter function) -Ovale.counter = {} ---the spells that the player has casted but that did not reach their target ---the result is computed by the simulator, allowing to ignore lag or missile travel time -Ovale.lastSpell = {} ---the damage of the last spell or dot (by id) -Ovale.spellDamage = {} ---the attack power of the last spell -Ovale.lastSpellAP = {} -Ovale.lastSpellSP = {} -Ovale.lastSpellDM = {} -Ovale.damageMultiplier = 1 -Ovale.numberOfEnemies = nil -Ovale.enemies = {} -Ovale.refreshNeeded = false +Ovale.refreshNeeded = {} Ovale.compileOnItems = false - --- List haste buff that does not appear in the character sheet and that are not raid wide buffs -Ovale.selfHasteBuff = -{ - [53657] = 9, -- Judgement of the pure - [49016] = 20 -- Unholy Frenzy -} - --- List temporary damage multiplier -Ovale.selfDamageBuff = -{ - [5217] = 1.15, -- Tiger's fury - [57933] = 1.15 -- Tricks of the trade -} - -Ovale.buffSpellList = -{ - fear = - { - 5782, -- Fear - 5484, -- Howl of terror - 5246, -- Intimidating Shout - 8122, -- Psychic scream - }, - root = - { - 23694, -- Improved Hamstring - 339, -- Entangling Roots - 122, -- Frost Nova - 47168, -- Improved Wing Clip - }, - incapacitate = - { - 6770, -- Sap - 12540, -- Gouge - 20066, -- Repentance - }, - stun = - { - 5211, -- Bash - 44415, -- Blackout - 6409, -- Cheap Shot - 22427, -- Concussion Blow - 853, -- Hammer of Justice - 408, -- Kidney Shot - 46968, -- Shockwave - }, - strengthagility= - { - 6673, -- Battle Shout - 8076, -- Strength of Earth - 57330, -- Horn of Winter - 93435 --Roar of Courage (Cat, Spirit Beast) - }, - stamina = - { - 21562, -- Fortitude TODO: vérifier - 469, -- Commanding Shout - 6307, -- Blood Pact - 90364 -- Qiraji Fortitude - }, - lowerarmor= - { - 58567, -- Sunder Armor (x3) - 8647, -- Expose Armor - 91565, -- Faerie Fire (x3) - 35387, --Corrosive Spit (x3 Serpent) - 50498 --Tear Armor (x3 Raptor) - }, - magicaldamagetaken= - { - 65142, -- Ebon Plague - 60433, -- Earth and Moon - 93068, -- Master Poisoner - 1490, -- Curse of the Elements - 85547, -- Jinx 1 - 86105, -- Jinx 2 - 34889, --Fire Breath (Dragonhawk) - 24844 --Lightning Breath (Wind serpent) - }, - magicalcrittaken= - { - 17800, -- Shadow and Flame - 22959 -- Critical Mass - }, - physicaldamagetaken= - { - 30069, -- Blood Frenzy (rank 1) - 30070, -- Blood Frenzy (rank 2) - 81327, -- Brittle Bones (rank 1) - 81328, -- Brittle Bones (rank 2) - 58684, -- Savage Combat (rank 1) - 58683, -- Savage Combat (rank 2) - 55749, -- Acid Spit (Worm) - 50518, -- Ravage (Ravager) - }, - lowerphysicaldamage= - { - 99, -- Demoralizing Roar - 702, -- Curse of Weakness - 1160, -- Demoralizing Shout - 26017, -- Vindication - 81130, -- Scarlet Fever - 50256, --Demoralizing Roar (Bear) - 24423, -- Demoralizing Screech (Carrion Bird) - }, - meleeslow= - { - 55095, --Icy Touch - 58179, --Infected Wounds rank 1 - 58180, --Infected Wounds rank 2 - 68055, --Judgments of the just - 6343, --Thunderclap - 8042, --Earth Shock - 54404, --Dust Cloud (Tallstrider) - 90315, -- Tailspin (Fox) - }, - castslow = - { - 1714, --Curse of Tongues - 58604, --Lava Breath (Core Hound) - 50274, --Spore Cloud (Sporebat) - 5761, --Mind-numbing Poison - 73975, --Necrotic Strike - 31589 --Slow - }, - bleed= - { - 33876, --Mangle cat - 33878, --Mangle bear - 46856, -- Trauma rank 1 - 46857, -- Trauma rank 2 - 16511, --Hemorrhage - 50271, --Tendon Rip (Hyena) - 35290 --Gore (Boar) - }, - heroism= - { - 2825, --Bloodlust - 32182, --Heroism - 80353, --Time warp - 90355 -- Ancient Hysteria (Core Hound) - }, - meleehaste = - { - 8515, -- Windfury - 55610, -- Improved Icy Talons - 53290 -- Hunting Party - }, - spellhaste = - { - 24907, -- Moonkin aura - 2895, -- Wrath of Air Totem - 49868 -- Mind Quickening - }, - enrage = - { - 49016, -- Unholy Frenzy - 18499, -- Berserker Rage - 12292, -- Death Wish - 12880, -- Enrage (rank 1) - 14201, -- Enrage (rank 2) - 14202, -- Enrage (rank 3) - 5229, -- Enrage (Bear) - 52610, -- Savage Roar (Cat) - 76691, -- Vengeance (All Tank Specs) - }, - criticalstrike = - { - 51740, -- Elemental Oath - 51698, -- Honor Among Thieves (rank 1) - 51700, -- Honor Among Thieves (rank 2) - 51701, -- Honor Among Thieves (rank 3) - 17007, -- Leader of the Pack - 29801, -- Rampage - 24604, -- Furious Howl (Wolf) - 90309, -- Terrifying Roar (Devilsaur) - } -} - +Ovale.combatStartTime = nil +Ovale.needCompile = false +Ovale.listes = {} +--</public-static-properties> --Key bindings BINDING_HEADER_OVALE = "Ovale" @@ -269,407 +48,9 @@ BINDING_NAME_OVALE_CHECKBOX2 = L["Inverser la boîte à cocher "].."(3)" BINDING_NAME_OVALE_CHECKBOX3 = L["Inverser la boîte à cocher "].."(4)" BINDING_NAME_OVALE_CHECKBOX4 = L["Inverser la boîte à cocher "].."(5)" ---GUI option -local options = -{ - type = "group", - args = - { - apparence = - { - name = L["Apparence"], - type = "group", - args = - { - combatUniquement = - { - order = 1, - type = "toggle", - name = L["En combat uniquement"], - get = function(info) - return Ovale.db.profile.apparence.enCombat - end, - set = function(info, v) - Ovale.db.profile.apparence.enCombat = v - Ovale:UpdateVisibility() - end, - width = "full" - }, - targetOnly = - { - order = 1.5, - type = "toggle", - name = L["Si cible uniquement"], - get = function(info) - return Ovale.db.profile.apparence.avecCible - end, - set = function(info, v) - Ovale.db.profile.apparence.avecCible = v - Ovale:UpdateVisibility() - end, - width = "full" - }, - iconScale = - { - order = 2, - type = "range", - name = L["Taille des icônes"], - desc = L["La taille des icônes"], - min = 0.1, max = 16, step = 0.1, - get = function(info) return Ovale.db.profile.apparence.iconScale end, - set = function(info,value) Ovale.db.profile.apparence.iconScale = value; Ovale:UpdateFrame() end - }, - secondIconScale = - { - order = 2.5, - type = "range", - name = L["Taille du second icône"], - min = 0.2, max = 1, step = 0.1, - get = function(info) return Ovale.db.profile.apparence.secondIconScale end, - set = function(info,value) Ovale.db.profile.apparence.secondIconScale = value; Ovale:UpdateFrame() end - }, - fontScale = - { - order = 3, - type = "range", - name = L["Taille des polices"], - desc = L["La taille des polices"], - min = 0.1, max = 2, step = 0.1, - get = function(info) return Ovale.db.profile.apparence.fontScale end, - set = function(info,value) Ovale.db.profile.apparence.fontScale = value; Ovale:UpdateFrame() end - }, - smallIconScale = - { - order = 4, - type = "range", - name = L["Taille des petites icônes"], - desc = L["La taille des petites icônes"], - min = 0.1, max = 16, step = 0.1, - get = function(info) return Ovale.db.profile.apparence.smallIconScale end, - set = function(info,value) Ovale.db.profile.apparence.smallIconScale = value; Ovale:UpdateFrame() end - }, - margin = - { - order = 5.5, - type = "range", - name = L["Marge entre deux icônes"], - min = -16, max = 64, step = 1, - get = function(info) return Ovale.db.profile.apparence.margin end, - set = function(info,value) Ovale.db.profile.apparence.margin = value; Ovale:UpdateFrame() end - }, - iconShiftX = - { - order = 5.6, - type = "range", - name = L["Décalage horizontal des options"], - min = -256, max = 256, step = 1, - get = function(info) return Ovale.db.profile.apparence.iconShiftX end, - set = function(info,value) Ovale.db.profile.apparence.iconShiftX = value; Ovale:UpdateFrame() end - }, - iconShiftY = - { - order = 5.7, - type = "range", - name = L["Décalage vertical des options"], - min = -256, max = 256, step = 1, - get = function(info) return Ovale.db.profile.apparence.iconShiftY end, - set = function(info,value) Ovale.db.profile.apparence.iconShiftY = value; Ovale:UpdateFrame() end - }, - raccourcis = - { - order = 6, - type = "toggle", - name = L["Raccourcis clavier"], - desc = L["Afficher les raccourcis clavier dans le coin inférieur gauche des icônes"], - get = function(info) return Ovale.db.profile.apparence.raccourcis end, - set = function(info, value) Ovale.db.profile.apparence.raccourcis = value end - }, - numeric = - { - order = 7, - type = "toggle", - name = L["Affichage numérique"], - desc = L["Affiche le temps de recharge sous forme numérique"], - get = function(info) return Ovale.db.profile.apparence.numeric end, - set = function(info, value) Ovale.db.profile.apparence.numeric = value end - }, - verrouille = - { - order = 8, - type = "toggle", - name = L["Verrouiller position"], - get = function(info) return Ovale.db.profile.apparence.verrouille end, - set = function(info, value) Ovale.db.profile.apparence.verrouille = value end - }, - vertical = - { - order = 9, - type = "toggle", - name = L["Vertical"], - get = function(info) return Ovale.db.profile.apparence.vertical end, - set = function(info, value) Ovale.db.profile.apparence.vertical = value; Ovale:UpdateFrame() end - }, - alpha = - { - order = 9.5, - type = "range", - name = L["Opacité des icônes"], - min = 0, max = 100, step = 5, - get = function(info) return Ovale.db.profile.apparence.alpha * 100 end, - set = function(info, value) Ovale.db.profile.apparence.alpha = value/100; Ovale.frame.frame:SetAlpha(value/100) end - }, - optionsAlpha = - { - order = 9.5, - type = "range", - name = L["Opacité des options"], - min = 0, max = 100, step = 5, - get = function(info) return Ovale.db.profile.apparence.optionsAlpha * 100 end, - set = function(info, value) Ovale.db.profile.apparence.optionsAlpha = value/100; Ovale.frame.content:SetAlpha(value/100) end - }, - predictif = - { - order = 10, - type = "toggle", - name = L["Prédictif"], - desc = L["Affiche les deux prochains sorts et pas uniquement le suivant"], - get = function(info) return Ovale.db.profile.apparence.predictif end, - set = function(info, value) Ovale.db.profile.apparence.predictif = value; Ovale:UpdateFrame() end - }, - moving = - { - order = 11, - type = "toggle", - name = L["Défilement"], - desc = L["Les icônes se déplacent"], - get = function(info) return Ovale.db.profile.apparence.moving end, - set = function(info, value) Ovale.db.profile.apparence.moving = value; Ovale:UpdateFrame() end - }, - hideEmpty = - { - order = 12, - type = "toggle", - name = L["Cacher bouton vide"], - get = function(info) return Ovale.db.profile.apparence.hideEmpty end, - set = function(info, value) Ovale.db.profile.apparence.hideEmpty = value; Ovale:UpdateFrame() end - }, - targetHostileOnly = - { - order = 13, - type = "toggle", - name = L["Cacher si cible amicale ou morte"], - get = function(info) return Ovale.db.profile.apparence.targetHostileOnly end, - set = function(info, value) Ovale.db.profile.apparence.targetHostileOnly = value; Ovale:UpdateFrame() end - }, - highlightIcon = - { - order = 14, - type = "toggle", - name = L["Illuminer l'icône"], - desc = L["Illuminer l'icône quand la technique doit être spammée"], - get = function(info) return Ovale.db.profile.apparence.highlightIcon end, - set = function(info, value) Ovale.db.profile.apparence.highlightIcon = value; Ovale:UpdateFrame() end - }, - clickThru = - { - order = 15, - type = "toggle", - name = L["Ignorer les clics souris"], - get = function(info) return Ovale.db.profile.apparence.clickThru end, - set = function(info, value) Ovale.db.profile.apparence.clickThru = value; Ovale:UpdateFrame() end - }, - latencyCorrection = - { - order = 16, - type = "toggle", - name = L["Correction de la latence"], - get = function(info) return Ovale.db.profile.apparence.latencyCorrection end, - set = function(info, value) Ovale.db.profile.apparence.latencyCorrection = value end - }, - hideVehicule = - { - order = 17, - type = "toggle", - name = L["Cacher dans les véhicules"], - get = function(info) return Ovale.db.profile.apparence.hideVehicule end, - set = function(info, value) Ovale.db.profile.apparence.hideVehicule = value end - }, - flashIcon = - { - order = 18, - type = "toggle", - name = L["Illuminer l'icône quand le temps de recharge est écoulé"], - get = function(info) return Ovale.db.profile.apparence.flashIcon end, - set = function(info, value) Ovale.db.profile.apparence.flashIcon = value; Ovale:UpdateFrame() end - }, - targetText = - { - order = 19, - type = "input", - name = L["Caractère de portée"], - desc = L["Ce caractère est affiché dans un coin de l'icône pour indiquer si la cible est à portée"], - get = function(info) return Ovale.db.profile.apparence.targetText end, - set = function(info, value) Ovale.db.profile.apparence.targetText = value; Ovale:UpdateFrame() end - } - } - }, - code = - { - name = L["Code"], - type = "group", - args = - { - code = - { - order = 1, - type = "input", - multiline = 15, - name = L["Code"], - get = function(info) - return string.gsub(Ovale.db.profile.code, "\t", " ") - end, - set = function(info,v) - Ovale.db.profile.code = v - Ovale.needCompile = true - end, - width = "full" - } - } - }, - actions = - { - name = "Actions", - type = "group", - args = - { - show = - { - order = -1, - type = "execute", - name = L["Afficher la fenêtre"], - guiHidden = true, - func = function() - Ovale.db.profile.display = true - Ovale:UpdateVisibility() - end - }, - hide = - { - order = -2, - type = "execute", - name = L["Cacher la fenêtre"], - guiHidden = true, - func = function() - Ovale.db.profile.display = false - Ovale.frame:Hide() - end - }, - config = - { - name = "Configuration", - type = "execute", - func = function() Ovale:AfficherConfig() end - }, - code = - { - name = "Code", - type = "execute", - func = function() Ovale:AfficherCode() end - }, - debug = - { - order = -3, - name = "Debug", - type = "execute", - func = function() - for i=1,10 do Ovale:Print(i.."="..UnitPower("player", i)) end - Ovale:Print(Ovale.state.eclipse) - end - }, - talent = - { - order = -4, - name = "List talent id", - type = "execute", - func = function() - for k,v in pairs(Ovale.talentNameToId) do - Ovale:Print(k.."="..v) - end - end - }, - targetbuff = - { - order = -5, - name = "List target buff and debuff spell id", - type = "execute", - func = function() - Ovale:DebugListAura("target", "HELPFUL") - Ovale:DebugListAura("target", "HARMFUL") - end - }, - buff = - { - order = -6, - name = "List player buff and debuff spell id", - type = "execute", - func = function() - Ovale:DebugListAura("player", "HELPFUL") - Ovale:DebugListAura("player", "HARMFUL") - end - }, - glyph = - { - order = -7, - name = "List player glyphs", - type = "execute", - func = function() - for i=1,GetNumGlyphs() do - local name, level, enabled, texture, spellId = GetGlyphInfo(i) - if spellId then Ovale:Print(name..": "..spellId.." ("..tostring(enabled)..")") end - end - end - }, - spell = - { - order = -8, - name = "List player spells", - type = "execute", - func = function() - local book=BOOKTYPE_SPELL - while true do - local i=1 - while true do - local skillType, spellId = GetSpellBookItemInfo(i, book) - if not spellId then - break - end - local spellName = GetSpellBookItemName(i, book) - Ovale:Print(spellName..": "..spellId) - i = i + 1 - end - if book == BOOKTYPE_SPELL then - book = BOOKTYPE_PET - else - break - end - end - end - } - } - } - } -} - -local function nilstring(text) - if text == nil then - return "nil" - else - return text - end -end - +--<public-static-methods> function Ovale:Debug() - self:Print(self:DebugNode(self.masterNodes[1])) + self:Print(OvaleCompile:DebugNode(self.masterNodes[1])) end function Ovale:DebugListAura(target, filter) @@ -684,94 +65,28 @@ function Ovale:DebugListAura(target, filter) end end -function Ovale:OnInitialize() - self.AceConfig = LibStub("AceConfig-3.0"); - self.AceConfigDialog = LibStub("AceConfigDialog-3.0"); -end - -function Ovale:GetOtherAura(spellId) - if not self.otherAura[spellId] then - self.otherAura[spellId] = {} - end - return self.otherAura[spellId] -end - -function Ovale:WithHaste(temps, hate) - if not temps then - temps = 0 - end - if (not hate) then - return temps - elseif (hate == "spell") then - return temps/self.spellHaste - elseif (hate == "melee") then - return temps/self.meleeHaste - else - return temps - end -end - function Ovale:CompileAll() - if self.db.profile.code then - self.masterNodes = self:Compile(self.db.profile.code) - self.refreshNeeded = true + if OvaleOptions:GetProfile().code then + self.masterNodes = OvaleCompile:Compile(OvaleOptions:GetProfile().code) + self.refreshNeeded.player = true self:UpdateFrame() self.needCompile = false end end -function Ovale:HandleProfileChanges() - if self.firstInit then - if (self.db.profile.code) then - self.needCompile = true - end - end -end function Ovale:FirstInit() - self:RemplirActionIndexes() - self:RemplirListeTalents() - self:FillSpellList() - - local playerClass, englishClass = UnitClass("player") - self.className = englishClass - if self.className == "DEATHKNIGHT" then - for i=1,6 do - self.state.rune[i] = {} - end - end - self.playerGuid = UnitGUID("player") - - self:ChargerDefaut() - - self.frame = LibStub("AceGUI-3.0"):Create("OvaleFrame") - - self.frame:SetPoint("TOPLEFT",UIParent,"BOTTOMLEFT",self.db.profile.left,self.db.profile.top) - self.firstInit = true - - - options.args.profile = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db) - self.AceConfig:RegisterOptionsTable("Ovale", options.args.code) - self.AceConfig:RegisterOptionsTable("Ovale Actions", options.args.actions, "Ovale") - self.AceConfig:RegisterOptionsTable("Ovale Profile", options.args.profile) - self.AceConfig:RegisterOptionsTable("Ovale Apparence", options.args.apparence) - self.AceConfigDialog:AddToBlizOptions("Ovale", "Ovale") - self.AceConfigDialog:AddToBlizOptions("Ovale Profile", "Profile", "Ovale") - self.AceConfigDialog:AddToBlizOptions("Ovale Apparence", "Apparence", "Ovale") + OvaleData:FirstInit() - self.db.RegisterCallback( self, "OnNewProfile", "HandleProfileChanges" ) - self.db.RegisterCallback( self, "OnProfileReset", "HandleProfileChanges" ) - self.db.RegisterCallback( self, "OnProfileChanged", "HandleProfileChanges" ) - self.db.RegisterCallback( self, "OnProfileCopied", "HandleProfileChanges" ) + self.frame = LibStub("AceGUI-3.0"):Create("OvaleFrame") + local profile = OvaleOptions:GetProfile() - if self.db.profile.code then - self.needCompile = true - end + self.frame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", profile.left, profile.top) self:UpdateFrame() - if not Ovale.db.profile.display then + if not profile.display then self.frame:Hide() end end @@ -785,198 +100,32 @@ function Ovale:OnEnable() RegisterAddonMessagePrefix("Ovale") self:RegisterEvent("PLAYER_REGEN_ENABLED"); self:RegisterEvent("PLAYER_REGEN_DISABLED"); - self:RegisterEvent("SPELLS_CHANGED") - self:RegisterEvent("PLAYER_TALENT_UPDATE") - self:RegisterEvent("CHARACTER_POINTS_CHANGED") - self:RegisterEvent("ACTIONBAR_SLOT_CHANGED"); - self:RegisterEvent("UPDATE_BINDINGS"); - self:RegisterEvent("UNIT_AURA"); - self:RegisterEvent("ACTIONBAR_PAGE_CHANGED") - self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED") - self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED") - self:RegisterEvent("UNIT_SPELLCAST_START") - self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START") - self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP") self:RegisterEvent("PLAYER_TARGET_CHANGED") - self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") self:RegisterEvent("CHAT_MSG_ADDON") self:RegisterEvent("GLYPH_UPDATED") self:RegisterEvent("GLYPH_ADDED") self:RegisterEvent("UNIT_INVENTORY_CHANGED") - - self:UNIT_AURA("","player") - + self:UpdateVisibility() end function Ovale:OnDisable() -- Called when the addon is disabled - self:UnregisterEvent("UNIT_INVENTORY_CHANGED") - self:UnregisterEvent("ACTIONBAR_PAGE_CHANGED") - self:UnregisterEvent("PLAYER_REGEN_ENABLED") + self:UnregisterEvent("PLAYER_REGEN_ENABLED") self:UnregisterEvent("PLAYER_REGEN_DISABLED") - self:UnregisterEvent("PLAYER_TALENT_UPDATE") - self:UnregisterEvent("ACTIONBAR_SLOT_CHANGED") - self:UnregisterEvent("SPELLS_CHANGED") - self:UnregisterEvent("CHARACTER_POINTS_CHANGED") - self:UnregisterEvent("UPDATE_BINDINGS") - self:UnregisterEvent("UNIT_AURA") - self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START") - self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_STOP") - self:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED") - self:UnregisterEvent("UNIT_SPELLCAST_START") self:UnregisterEvent("PLAYER_TARGET_CHANGED") - self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") self:UnregisterEvent("CHAT_MSG_ADDON") self:UnregisterEvent("GLYPH_UPDATED") - self:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED") + self:UnregisterEvent("GLYPH_ADDED") + self:UnregisterEvent("UNIT_INVENTORY_CHANGED") self.frame:Hide() end -function Ovale:ACTIONBAR_SLOT_CHANGED(event, slot, unknown) - if (slot == 0) then - self:RemplirActionIndexes() - elseif (slot) then - -- on reçoit aussi si c'est une macro avec mouseover à chaque fois que la souris passe sur une cible! - self:RemplirActionIndex(tonumber(slot)) - end -end - -function Ovale:ACTIONBAR_PAGE_CHANGED() - -- self:RemplirActionIndexes() -end - -function Ovale:CHARACTER_POINTS_CHANGED() - self:RemplirListeTalents() --- self:Print("CHARACTER_POINTS_CHANGED") -end - -function Ovale:PLAYER_TALENT_UPDATE() - self:RemplirListeTalents() --- self:Print("PLAYER_TALENT_UPDATE") -end - ---The user learnt a new spell -function Ovale:SPELLS_CHANGED() - -- self:RemplirActionIndexes() - -- self:RemplirListeTalents() - self:FillSpellList() - self.needCompile = true -end - function Ovale:UNIT_INVENTORY_CHANGED() if self.compileOnItems then self.needCompile = true else - self.refreshNeeded = true - end -end - ---Called when the user changed his key bindings -function Ovale:UPDATE_BINDINGS() - self:RemplirActionIndexes() -end - ---Called for each combat log event -function Ovale:COMBAT_LOG_EVENT_UNFILTERED(event, ...) - local time, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags = select(1, ...) - - if sourceGUID == self.playerGuid then - -- self:Print("event="..event.." source="..nilstring(sourceName).." destName="..nilstring(destName).." " ..GetTime()) - - if string.find(event, "SPELL_PERIODIC_DAMAGE")==1 or string.find(event, "SPELL_DAMAGE")==1 then - local spellId, spellName, spellSchool, amount = select(12, ...) - self.spellDamage[spellId] = amount - end - - --Called when a missile reached or missed its target - --Update lastSpell accordingly - --Do not use SPELL_CAST_SUCCESS because it is sent when the missile has not reached the target - - if - string.find(event, "SPELL_AURA_APPLIED")==1 - or string.find(event, "SPELL_AURA_REFRESH")==1 - or string.find(event, "SPELL_DAMAGE")==1 - or string.find(event, "SPELL_MISSED") == 1 - or string.find(event, "SPELL_CAST_SUCCESS") == 1 - or string.find(event, "SPELL_CAST_FAILED") == 1 then - local spellId, spellName = select(12, ...) - for i,v in ipairs(self.lastSpell) do - if (v.spellId == spellId or v.auraSpellId == spellId) and v.allowRemove then - if not v.channeled and (v.removeOnSuccess or - string.find(event, "SPELL_CAST_SUCCESS") ~= 1) then - table.remove(self.lastSpell, i) - self.refreshNeeded = true - --self:Print("LOG_EVENT on supprime "..spellId.." a "..GetTime()) - end - --self:Print(UnitDebuff("target", "Etreinte de l'ombre")) - break - end - end - end - if self.otherAurasEnabled then - --Track debuffs on units that are not the current target - if string.find(event, "SPELL_AURA_") == 1 then - local spellId, spellName, spellSchool, auraType = select(12, ...) - -- auraType == "DEBUFF" and - if self.spellInfo[spellId] and self.spellInfo[spellId].duration then - local otherDebuff = self:GetOtherAura(spellId) - if event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_REFRESH" then - otherDebuff[destGUID] = Ovale.maintenant + self:WithHaste(self.spellInfo[spellId].duration, self.spellInfo[spellId].durationhaste) - self.refreshNeeded = true - -- self:Print("ajout de "..spellName.." à "..destGUID) - elseif event == "SPELL_AURA_REMOVED" then - otherDebuff[destGUID] = nil - self.refreshNeeded = true - -- self:Print("suppression de "..spellName.." de "..destGUID) - end - end - end - end - --if string.find(event, "SWING")==1 then - -- self:Print(select(1, ...)) - --end - end - - if self.numberOfEnemies then - if event == "UNIT_DIED" then - for k,v in pairs(self.enemies) do - if k==destGUID then - self.enemies[v] = nil - self.numberOfEnemies = self.numberOfEnemies - 1 - self.refreshNeeded = true - --self:Print("enemy die") - end - end - elseif sourceFlags and not self.enemies[sourceGUID] and bit.band(sourceFlags, COMBATLOG_OBJECT_REACTION_HOSTILE)>0 - and bit.band(sourceFlags, COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) > 0 and - destFlags and bit.band(destFlags, COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) == 0 then - self.enemies[sourceGUID] = true - --self:Print("new ennemy source=".. sourceName) - self.numberOfEnemies = self.numberOfEnemies + 1 - self.refreshNeeded = true - elseif destGUID and not self.enemies[destGUID] and bit.band(destFlags, COMBATLOG_OBJECT_REACTION_HOSTILE)>0 - and bit.band(destFlags, COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) > 0 and - sourceFlags and bit.band(sourceFlags, COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) == 0 then - self.enemies[destGUID] = true - --self:Print("new ennemy dest=".. destName) - self.numberOfEnemies = self.numberOfEnemies + 1 - self.refreshNeeded = true - end - end - - if self.otherAurasEnabled then - if event == "UNIT_DIED" then - --Remove any dead unit from otherAura - for k,v in pairs(self.otherAura) do - for j,w in pairs(v) do - if j==destGUID then - v[j] = nil - self.refreshNeeded = true - end - end - end - end + self.refreshNeeded.player = true end end @@ -984,84 +133,10 @@ end --Used to update the visibility e.g. if the user chose --to hide Ovale if a friendly unit is targeted function Ovale:PLAYER_TARGET_CHANGED() - self.refreshNeeded = true + self.refreshNeeded.target = true self:UpdateVisibility() end ---Called when a new aura is added to an unit ---At this time it is not used to keep the aura list (may be used in the future for optimization) ---It is only used to update haste -function Ovale:UNIT_AURA(event, unit) - if unit == "player" or unit == "pet" then - local hateBase = GetCombatRatingBonus(18) - local hateCommune=0; - local hateSorts = 0; - local hateCaC = 0; - local hateHero = 0 - local hateClasse = 0 - local damageMultiplier = 1 - local i=1; - - if not self.buff[unit] then - self.buff[unit] = {} - end - - local buff = self.buff[unit] - - while true do - local name, rank, iconTexture, count, debuffType, duration, expirationTime, source, stealable, consolidate, spellId = UnitBuff(unit, i); - if (not name) then - break - end - if (not buff[spellId]) then - buff[spellId] = {} - end - buff[spellId].icon = iconTexture - buff[spellId].count = count - buff[spellId].duration = duration - buff[spellId].expirationTime = expirationTime - buff[spellId].source = source - if (not buff[spellId].present) then - buff[spellId].gain = Ovale.maintenant - end - buff[spellId].lastSeen = Ovale.maintenant - buff[spellId].present = true - - if unit == "player" then - if self.buffSpellList.spellhaste[spellId] then - hateSorts = 5 - elseif self.buffSpellList.meleehaste[spellId] then - hateCaC = 10 - elseif self.buffSpellList.heroism[spellId] then - hateHero = 30 - elseif self.selfHasteBuff[spellId] then - hateClasse = self.selfHasteBuff[spellId] - end - if self.selfDamageBuff[spellId] then - damageMultiplier = damageMultiplier * self.selfDamageBuff[spellId] - end - end - i = i + 1; - end - - for k,v in pairs(buff) do - if (v.lastSeen ~= Ovale.maintenant) then - v.present = false - end - end - - if unit == "player" then - self.spellHaste = 1 + (hateBase + hateCommune + hateSorts + hateHero + hateClasse)/100 - self.meleeHaste = 1 + (hateBase + hateCommune + hateCaC + hateHero + hateClasse)/100 - self.damageMultiplier = damageMultiplier - end - - self.refreshNeeded = true --- self.rangedHaste = hateBase + hateCommune + hateHero + hateClasse -- TODO ajouter le bidule du chasseur en spé bête --- print("spellHaste = "..self.spellHaste) - end -end - --Called when a glyph has been added --The script needs to be compiled function Ovale:GLYPH_ADDED(event) @@ -1074,184 +149,6 @@ function Ovale:GLYPH_UPDATED(event) self.needCompile = true end -function Ovale:GetNumberOfEnemies() - if not self.numberOfEnemies then - self.numberOfEnemies = 0 - end - return self.numberOfEnemies -end - -function Ovale:RemoveSpellFromList(spellId, lineId) - for i,v in ipairs(self.lastSpell) do - if v.lineId == lineId then - table.remove(self.lastSpell, i) - --self:Print("RemoveSpellFromList on supprime "..spellId) - break - end - end - self.refreshNeeded = true -end - ---Called if the player interrupted early his cast ---The spell is removed from the lastSpell table -function Ovale:UNIT_SPELLCAST_INTERRUPTED(event, unit, name, rank, lineId, spellId) - if unit == "player" then - --self:Print("UNIT_SPELLCAST_INTERRUPTED "..event.." name="..name.." lineId="..lineId.." spellId="..spellId.. " time="..GetTime()) - self:RemoveSpellFromList(spellId, lineId) - end -end - -function Ovale:UNIT_SPELLCAST_SUCCEEDED(event, unit, name, rank, lineId, spellId) - if unit == "player" then - --self:Print("UNIT_SPELLCAST_SUCCEEDED "..event.." name="..name.." lineId="..lineId.." spellId="..spellId.. " time="..GetTime()) - for i,v in ipairs(self.lastSpell) do - if v.lineId == lineId then - --Already added in UNIT_SPELLCAST_START - v.allowRemove = true - return - end - end - if not UnitChannelInfo("player") then - --A UNIT_SPELLCAST_SUCCEEDED is received when channeling a spell, with a different lineId! - local now = GetTime() - self:AddSpellToList(spellId, lineId, now, now, false, true) - end - end -end - -function Ovale:SendScoreToDamageMeter(name, guid, scored, scoreMax) - if Recount then - local source = Recount.db2.combatants[name] - if source then - Recount:AddAmount(source,"Ovale",scored) - Recount:AddAmount(source,"OvaleMax",scoreMax) - end - end - if Skada then - if not guid or not Skada.current or not Skada.total then return end - local player = Skada:get_player(Skada.current, guid, nil) - if not player then return end - if not player.ovale then player.ovale = 0 end - if not player.ovaleMax then player.ovaleMax = 0 end - player.ovale = player.ovale + scored - player.ovaleMax = player.ovaleMax + scoreMax - player = Skada:get_player(Skada.total, guid, nil) - player.ovale = player.ovale + scored - player.ovaleMax = player.ovaleMax + scoreMax - end -end - -function Ovale:AddSpellToList(spellId, lineId, startTime, endTime, channeled, allowRemove) - local newSpell = {} - newSpell.spellId = spellId - newSpell.lineId = lineId - newSpell.start = startTime - newSpell.stop = endTime - newSpell.channeled = channeled - newSpell.allowRemove = allowRemove - - self.lastSpellAP[spellId] = UnitAttackPower("player") - self.lastSpellSP[spellId] = GetSpellBonusDamage(2) - self.lastSpellDM[spellId] = self.damageMultiplier - self.lastSpell[#self.lastSpell+1] = newSpell - --self:Print("on ajoute "..spellId..": ".. newSpell.start.." to "..newSpell.stop.." ("..self.maintenant..")" ..#self.lastSpell) - - if self.spellInfo[spellId] then - local si = self.spellInfo[spellId] - - if si.aura then - for target, targetInfo in pairs(si.aura) do - for filter, filterInfo in pairs(targetInfo) do - for auraSpellId, spellData in pairs(filterInfo) do - if spellData and spellData ~= "refresh" and spellData > 0 then - newSpell.auraSpellId = auraSpellId - if target == "player" then - newSpell.removeOnSuccess = true - end - break - end - end - end - end - end - - --self:Print("spellInfo found") - if si and si.buffnocd and UnitBuff("player", GetSpellInfo(si.buffnocd)) then - newSpell.nocd = true - else - newSpell.nocd = false - end - --Increase or reset the counter that is used by the Counter function - if si.resetcounter then - self.counter[si.resetcounter] = 0 - --self:Print("reset counter "..si.resetcounter) - end - if si.inccounter then - local cname = si.inccounter - if not self.counter[cname] then - self.counter[cname] = 0 - end - self.counter[cname] = self.counter[cname] + 1 - --self:Print("inc counter "..cname.." to "..self.counter[cname]) - end - else - newSpell.removeOnSuccess = true - end - - if self.enCombat then - --self:Print(tostring(self.scoreSpell[spellId])) - if (not self.spellInfo[spellId] or not self.spellInfo[spellId].toggle) and self.scoreSpell[spellId] then - --Compute the player score - local scored = self.frame:GetScore(spellId) - --self:Print("Scored "..scored) - if scored~=nil then - self.score = self.score + scored - self.maxScore = self.maxScore + 1 - self:SendScoreToDamageMeter(UnitName("player"), UnitGUID("player"), scored, 1) - end - end - end - self.refreshNeeded = true -end - -function Ovale:GetCounterValue(id) - if self.state.counter[id] then - return self.state.counter[id] - elseif self.counter[id] then - return self.counter[id] - else - return 0 - end -end - -function Ovale:UNIT_SPELLCAST_CHANNEL_START(event, unit, name, rank, lineId, spellId) - if unit=="player" then - --self:Print("UNIT_SPELLCAST_CHANNEL_START "..event.." name="..name.." lineId="..lineId.." spellId="..spellId) - local _,_,_,_,startTime, endTime = UnitChannelInfo("player") - --self:Print("startTime = " ..startTime.." endTime = "..endTime) - self:AddSpellToList(spellId, lineId, startTime/1000, endTime/1000, true, false) - end -end - -function Ovale:UNIT_SPELLCAST_CHANNEL_STOP(event, unit, name, rank, lineId, spellId) - if unit == "player" then - --self:Print("UNIT_SPELLCAST_CHANNEL_STOP "..event.." name="..name.." lineId="..lineId.." spellId="..spellId) - self:RemoveSpellFromList(spellId, lineId) - end -end - ---Called when a spell started its cast -function Ovale:UNIT_SPELLCAST_START(event, unit, name, rank, lineId, spellId) - --self:Print("UNIT_SPELLCAST_START "..event.." name="..name.." lineId="..lineId.." spellId="..spellId) - if unit=="player" then - local _,_,_,_,startTime,endTime = UnitCastingInfo("player") - --local spell, rank, icon, cost, isFunnel, powerType, castTime, minRange, maxRange = GetSpellInfo(spellId) - --local startTime = GetTime() - --self:AddSpellToList(spellId, lineId, startTime, startTime + castTime/1000) - self:AddSpellToList(spellId, lineId, startTime/1000, endTime/1000, false, false) - end -end - function Ovale:CHAT_MSG_ADDON(event, prefix, msg, type, author) if prefix ~= "Ovale" then return end if type ~= "RAID" and type~= "PARTY" then return end @@ -1275,127 +172,29 @@ function Ovale:PLAYER_REGEN_DISABLED() self.enCombat = true self.score = 0 self.maxScore = 0 - self.combatStartTime = self.maintenant - if self.numberOfEnemies then - self.numberOfEnemies = 0 - self.enemies = {} - end + self.combatStartTime = OvaleState.maintenant self:UpdateVisibility() end -function Ovale:ChercherShortcut(id) --- ACTIONBUTTON1..12 => principale (1..12, 13..24, 73..108) --- MULTIACTIONBAR1BUTTON1..12 => bas gauche (61..72) --- MULTIACTIONBAR2BUTTON1..12 => bas droite (49..60) --- MULTIACTIONBAR3BUTTON1..12 => haut droit (25..36) --- MULTIACTIONBAR4BUTTON1..12 => haut gauche (37..48) - local name; - if (id<=24 or id>72) then - name = "ACTIONBUTTON"..(((id-1)%12)+1); - elseif (id<=36) then - name = "MULTIACTIONBAR3BUTTON"..(id-24); - elseif (id<=48) then - name = "MULTIACTIONBAR4BUTTON"..(id-36); - elseif (id<=60) then - name = "MULTIACTIONBAR2BUTTON"..(id-48); - else - name = "MULTIACTIONBAR1BUTTON"..(id-60); - end - local key = GetBindingKey(name); ---[[ if (not key) then - DEFAULT_CHAT_FRAME:AddMessage(id.."=>"..name.." introuvable") - else - DEFAULT_CHAT_FRAME:AddMessage(id.."=>"..name.."="..key) - end]] - return key; -end - -function Ovale:GetSpellInfoOrNil(spell) - if (spell) then - return GetSpellInfo(spell) - else - return nil - end -end - -function Ovale:RemplirActionIndex(i) - self.shortCut[i] = self:ChercherShortcut(i) - local actionText = GetActionText(i) - if actionText then - self.actionMacro[actionText] = i - else - local type, spellId = GetActionInfo(i); - if (type=="spell") then - self.actionSort[spellId] = i - elseif (type =="item") then - self.actionObjet[spellId] = i - end - end -end - -function Ovale:RemplirActionIndexes() - self.actionSort = {} - self.actionMacro = {} - self.actionObjet = {} - self.shortCut = {} - for i=1,120 do - self:RemplirActionIndex(i) - end -end - -function Ovale:FillSpellList() - self.spellList = {} - local book=BOOKTYPE_SPELL - while true do - local i=1 - while true do - local skillType, spellId = GetSpellBookItemInfo(i, book) - if not spellId then - break - end - if skillType~="FUTURESPELL" then - local spellName = GetSpellBookItemName(i, book) - self.spellList[spellId] = spellName - end - i = i + 1 - end - if book==BOOKTYPE_SPELL then - book = BOOKTYPE_PET - else - break - end - end -end - -function Ovale:RemplirListeTalents() - local numTabs = GetNumTalentTabs(); - for t=1, numTabs do - local numTalents = GetNumTalents(t); - for i=1, numTalents do - local nameTalent, icon, tier, column, currRank, maxRank = GetTalentInfo(t,i); - local link = GetTalentLink(t,i) - if link then - local a, b, talentId = string.find(link, "talent:(%d+)"); - talentId = tonumber(talentId) - self.talentIdToName[talentId] = nameTalent - self.talentNameToId[nameTalent] = talentId - self.pointsTalent[talentId] = currRank - self.listeTalentsRemplie = true - self.needCompile = true - end +function Ovale:SendScoreToDamageMeter(name, guid, scored, scoreMax) + if Recount then + local source = Recount.db2.combatants[name] + if source then + Recount:AddAmount(source,"Ovale",scored) + Recount:AddAmount(source,"OvaleMax",scoreMax) end end -end - -function Ovale:AddRune(time, type, value) - if value<0 then - for i=1,6 do - if (self.state.rune[i].type == type or self.state.rune[i].type==4)and self.state.rune[i].cd<=time then - self.state.rune[i].cd = time + 10 - end - end - else - + if Skada then + if not guid or not Skada.current or not Skada.total then return end + local player = Skada:get_player(Skada.current, guid, nil) + if not player then return end + if not player.ovale then player.ovale = 0 end + if not player.ovaleMax then player.ovaleMax = 0 end + player.ovale = player.ovale + scored + player.ovaleMax = player.ovaleMax + scoreMax + player = Skada:get_player(Skada.total, guid, nil) + player.ovale = player.ovale + scored + player.ovaleMax = player.ovaleMax + scoreMax end end @@ -1405,1066 +204,6 @@ function Ovale:Log(text) end end -function Ovale:GetAura(target, filter, spellId, forceduration) - if not self.aura[target] then - self.aura[target] = {} - end - if not self.aura[target][filter] then - self.aura[target][filter] = {} - end - if not self.aura[target][filter][spellId] then - self.aura[target][filter][spellId] = {} - end - local myAura = self.aura[target][filter][spellId] - if myAura.serial == Ovale.serial then - return myAura - end - - myAura.mine = false - myAura.start = nil - myAura.ending = nil - myAura.stacks = 0 - myAura.serial = Ovale.serial - - local i = 1 - - while (true) do - local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, thisSpellId = UnitAura(target, i, filter); - if not name then - break - end - if (unitCaster=="player" or not myAura.mine) and (spellId == thisSpellId or spellId == debuffType) then - myAura.mine = (unitCaster == "player") - myAura.start = expirationTime - duration - - if expirationTime>0 then - myAura.ending = expirationTime - else - myAura.ending = nil - end - if count and count>0 then - myAura.stacks = count - else - myAura.stacks = 1 - end - if myAura.mine then - break - end - end - i = i + 1; - end - return myAura -end - -function Ovale:GetCD(spellId) - if not spellId then - return nil - end - - if self.spellInfo[spellId] and self.spellInfo[spellId].cd then - local cdname - if self.spellInfo[spellId].sharedcd then - cdname = self.spellInfo[spellId].sharedcd - else - cdname = spellId - end - if not self.state.cd[cdname] then - self.state.cd[cdname] = {} - end - return self.state.cd[cdname] - else - return nil - end -end - -function Ovale:AddEclipse(endCast, spellId) - local newAura = self:GetAura("player", "HELPFUL", spellId) - newAura.start = endCast + 0.5 - newAura.stacks = 1 - newAura.ending = nil -end - --- Cast a spell in the simulator --- spellId : the spell id --- startCast : temps du cast --- endCast : fin du cast --- nextCast : temps auquel le prochain sort peut être lancé (>=endCast, avec le GCD) --- nocd : le sort ne déclenche pas son cooldown -function Ovale:AddSpellToStack(spellId, startCast, endCast, nextCast, nocd) - if not spellId then - return - end - - local newSpellInfo = self.spellInfo[spellId] - - --On enregistre les infos sur le sort en cours - self.attenteFinCast = nextCast - self.currentSpellId = spellId - self.startCast = startCast - self.endCast = endCast - --Temps actuel de la simulation : un peu après le dernier cast (ou maintenant si dans le passé) - if startCast>=self.maintenant then - self.currentTime = startCast+0.1 - else - self.currentTime = self.maintenant - end - - if Ovale.trace then - Ovale:Print("add spell "..spellId.." at "..startCast.." currentTime = "..self.currentTime.. " nextCast="..self.attenteFinCast .. " endCast="..endCast) - end - - --Effet du sort au moment du début du cast - --(donc si cast déjà commencé, on n'en tient pas compte) - if startCast >= self.maintenant then - if newSpellInfo then - if newSpellInfo.inccounter then - local id = newSpellInfo.inccounter - self.state.counter[id] = self:GetCounterValue(id) + 1 - end - - if newSpellInfo.resetcounter then - self.state.counter[newSpellInfo.resetcounter] = 0 - end - end - end - - --Effet du sort au moment où il est lancé - --(donc si il est déjà lancé, on n'en tient pas compte) - if endCast >= self.maintenant then - --Mana - local _, _, _, cost = GetSpellInfo(spellId) - if cost then - self.state.mana = self.state.mana - cost - end - - if newSpellInfo then - - if newSpellInfo.mana then - self.state.mana = self.state.mana - newSpellInfo.mana - end - - --Points de combo - if newSpellInfo.combo then - self.state.combo = self.state.combo + newSpellInfo.combo - if self.state.combo<0 then - self.state.combo = 0 - end - end - --Runes - if newSpellInfo.frost then - self:AddRune(startCast, 3, newSpellInfo.frost) - end - if newSpellInfo.death then - self:AddRune(startCast, 4, newSpellInfo.death) - end - if newSpellInfo.blood then - self:AddRune(startCast, 1, newSpellInfo.blood) - end - if newSpellInfo.unholy then - self:AddRune(startCast, 2, newSpellInfo.unholy) - end - if newSpellInfo.holy then - self.state.holy = self.state.holy + newSpellInfo.holy - if self.state.holy < 0 then - self.state.holy = 0 - elseif self.state.holy > 3 then - self.state.holy = 3 - end - end - if newSpellInfo.shard then - self.state.shard = self.state.shard + newSpellInfo.shard - if self.state.shard < 0 then - self.state.shard = 0 - elseif self.state.shard > 3 then - self.state.shard = 3 - end - end - end - end - - -- Effets du sort au moment où il atteint sa cible - if newSpellInfo then - -- Cooldown du sort - local cd = self:GetCD(spellId) - if cd then - cd.start = startCast - cd.duration = newSpellInfo.cd - --Pas de cooldown - if nocd then - cd.duration = 0 - end - --On vérifie si le buff "buffnocd" est présent, auquel cas le CD du sort n'est pas déclenché - if newSpellInfo.buffnocd and not nocd then - local buffAura = self:GetAura("player", "HELPFUL", newSpellInfo.buffnocd) - if self.traceAura then - if buffAura then - self:Print("buffAura stacks = "..buffAura.stacks.." start="..nilstring(buffAura.start).." ending = "..nilstring(buffAura.ending)) - self:Print("startCast = "..startCast) - else - self:Print("buffAura = nil") - end - self.traceAura = false - end - if buffAura and buffAura.stacks>0 and buffAura.start and buffAura.start<=startCast and (not buffAura.ending or buffAura.ending>startCast) then - cd.duration = 0 - end - end - if newSpellInfo.targetlifenocd and not nocd then - if UnitHealth("target")/UnitHealthMax("target")*100<newSpellInfo.targetlifenocd then - cd.duration = 0 - end - end - cd.enable = 1 - if newSpellInfo.toggle then - cd.toggled = 1 - end - end - - if newSpellInfo.eclipse then - self.state.eclipse = self.state.eclipse + newSpellInfo.eclipse - if self.state.eclipse < -100 then - self.state.eclipse = -100 - self:AddEclipse(endCast, 48518) - elseif self.state.eclipse > 100 then - self.state.eclipse = 100 - self:AddEclipse(endCast, 48517) - end - end - if newSpellInfo.starsurge then - local buffAura = self:GetAura("player", "HELPFUL", 48517) --Solar - if buffAura.stacks>0 then - self:Log("starsurge with solar buff = " .. (- newSpellInfo.starsurge)) - self.state.eclipse = self.state.eclipse - newSpellInfo.starsurge - else - buffAura = self:GetAura("player", "HELPFUL", 48518) --Lunar - if buffAura.stacks>0 then - self:Log("starsurge with lunar buff = " .. newSpellInfo.starsurge) - self.state.eclipse = self.state.eclipse + newSpellInfo.starsurge - elseif self.state.eclipse < 0 then - self:Log("starsurge with eclipse < 0 = " .. (- newSpellInfo.starsurge)) - self.state.eclipse = self.state.eclipse - newSpellInfo.starsurge - else - self:Log("starsurge with eclipse > 0 = " .. newSpellInfo.starsurge) - self.state.eclipse = self.state.eclipse + newSpellInfo.starsurge - end - end - if self.state.eclipse < -100 then - self.state.eclipse = -100 - self:AddEclipse(endCast, 48518) - elseif self.state.eclipse > 100 then - self.state.eclipse = 100 - self:AddEclipse(endCast, 48517) - end - end - - --Auras causés par le sort - if newSpellInfo.aura then - for target, targetInfo in pairs(newSpellInfo.aura) do - for filter, filterInfo in pairs(targetInfo) do - for auraSpellId, spellData in pairs(filterInfo) do - local newAura = self:GetAura(target, filter, auraSpellId) - newAura.mine = true - local duration = spellData - local stacks = duration - --Optionnellement, on va regarder la durée du buff - if auraSpellId and self.spellInfo[auraSpellId] and self.spellInfo[auraSpellId].duration then - duration = self.spellInfo[auraSpellId].duration - elseif stacks~="refresh" and stacks > 0 then - stacks = 1 - end - if stacks=="refresh" then - if newAura.ending then - newAura.ending = endCast + duration - end - elseif stacks<0 and newAura.ending then - --Buff are immediatly removed when the cast ended, do not need to do it again - if filter~="HELPFUL" or target~="player" or endCast>=Ovale.maintenant then - newAura.stacks = newAura.stacks + stacks - if Ovale.trace then - self:Print("removing one stack of "..auraSpellId.." because of ".. spellId.." to ".. newAura.stacks) - end - --Plus de stacks, on supprime l'aura - if newAura.stacks<=0 then - self:Log("Aura is completly removed") - newAura.stacks = 0 - newAura.ending = 0 - end - end - elseif newAura.ending and newAura.ending >= endCast then - newAura.ending = endCast + duration - newAura.stacks = newAura.stacks + stacks - else - newAura.start = endCast - newAura.ending = endCast + duration - newAura.stacks = stacks - end - if Ovale.trace then - if auraSpellId then - self:Print(spellId.." adding "..stacks.." aura "..auraSpellId.." to "..target.." "..filter.." "..newAura.start..","..newAura.ending) - else - self:Print("adding nil aura") - end - end - end - end - end - end - end -end - -function Ovale:InitAllActions() - self.maintenant = GetTime(); - self.gcd = self:GetGCD() -end - -function Ovale:InitCalculerMeilleureAction() - self.serial = self.serial + 1 - self.currentTime = Ovale.maintenant - self.currentSpellId = nil - self.attenteFinCast = Ovale.maintenant - self.state.combo = GetComboPoints("player") - self.state.mana = UnitPower("player") - self.state.shard = UnitPower("player", 7) - self.state.eclipse = UnitPower("player", 8) - self.state.holy = UnitPower("player", 9) - if self.className == "DEATHKNIGHT" then - for i=1,6 do - self.state.rune[i].type = GetRuneType(i) - local start, duration, runeReady = GetRuneCooldown(i) - if runeReady then - self.state.rune[i].cd = start - else - self.state.rune[i].cd = duration + start - if self.state.rune[i].cd<0 then - self.state.rune[i].cd = 0 - end - end - end - end - for k,v in pairs(self.state.cd) do - v.start = nil - v.duration = nil - v.enable = 0 - v.toggled = nil - end - - for k,v in pairs(self.state.counter) do - self.state.counter[k] = self.counter[k] - end - - for i,v in ipairs(self.lastSpell) do - if not self.spellInfo[v.spellId] or not self.spellInfo[v.spellId].toggle then - --[[local spell, rank, displayName, icon, startTime, endTime, isTradeSkill = UnitCastingInfo("player") - if spell and spell == v.name and startTime/1000 - v.start < 0.5 and v.stop~=endTime/1000 then - print("ancien = "..v.stop) - v.stop = endTime/1000 - print("changement de v.stop en "..v.stop.." "..v.start) - end]] - self:Log("self.maintenant = " ..self.maintenant.." spellId="..v.spellId.." v.stop="..v.stop) - if self.maintenant - v.stop < 5 then - self:AddSpellToStack(v.spellId, v.start, v.stop, v.stop, v.nocd) - else - --self:Print("Removing obsolete "..v.spellId) - table.remove(self.lastSpell, i) - end - end - end -end - -local function printTime(temps) - if (temps == nil) then - Ovale:Print("> nil") - else - Ovale:Print("> "..temps) - end -end - -function Ovale:GetGCD(spellId) - if spellId and self.spellInfo[spellId] then - if self.spellInfo[spellId].haste == "spell" then - local cd = self.spellInfo[spellId].gcd - if not cd then - cd = 1.5 - end - cd = cd / self.spellHaste - if (cd<1) then - cd = 1 - end - return cd - elseif self.spellInfo[spellId].gcd then - return self.spellInfo[spellId].gcd - end - end - - -- Default value - if self.className == "ROGUE" or (self.className == "DRUID" and GetShapeshiftForm(true) == 3) then - return 1.0 - elseif self.className == "MAGE" or self.className == "WARLOCK" or self.className == "PRIEST" or - (self.className == "DRUID" and GetShapeshiftForm(true) ~= 1) then - local cd = 1.5 / self.spellHaste - if (cd<1) then - cd = 1 - end - return cd - else - return 1.5 - end -end - ---Compute the spell Cooldown -function Ovale:GetComputedSpellCD(spellId) - local actionCooldownStart, actionCooldownDuration, actionEnable - local cd = self:GetCD(spellId) - if cd and cd.start then - actionCooldownStart = cd.start - actionCooldownDuration = cd.duration - actionEnable = cd.enable - else - actionCooldownStart, actionCooldownDuration, actionEnable = GetSpellCooldown(spellId) - -- Les chevaliers de la mort ont des infos fausses sur le CD quand ils n'ont plus les runes - -- On force à 1,5s ou 1s en présence impie - if self.className=="DEATHKNIGHT" and actionCooldownDuration==10 and - (not self.spellInfo[spellId] or self.spellInfo[spellId].cd~=10) then - local impie = GetSpellInfo(48265) - if impie and UnitBuff("player", impie) then - actionCooldownDuration=1 - else - actionCooldownDuration=1.5 - end - end - if self.spellInfo[spellId] and self.spellInfo[spellId].forcecd then - actionCooldownStart, actionCooldownDuration = GetSpellCooldown(self.spellInfo[spellId].forcecd) - end - end - return actionCooldownStart, actionCooldownDuration, actionEnable -end - -function Ovale:GetActionInfo(element) - if not element then - return nil - end - - local spellId = element.params[1] - local action - local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, - actionUsable, actionShortcut, actionIsCurrent, actionEnable - - local target = element.params.target - if (not target) then - target = "target" - end - - if (element.func == "Spell" ) then - if not self.spellList[spellId] and not self.actionSort[spellId] then - self:Log("Spell "..spellId.." not learnt") - return nil - end - - --Get spell info - action = self.actionSort[spellId] - actionCooldownStart, actionCooldownDuration, actionEnable = self:GetComputedSpellCD(spellId) - - --if (not action or not GetActionTexture(action)) then - spellName = self.spellList[spellId] - if not spellName then - spellName = GetSpellInfo(spellId) - end - actionTexture = GetSpellTexture(spellId) - actionInRange = IsSpellInRange(spellName, target) - actionUsable = IsUsableSpell(spellId) - actionShortcut = nil - --end - elseif (element.func=="Macro") then - action = self.actionMacro[element.params[1]] - if action then - actionTexture = GetActionTexture(action) - actionInRange = IsActionInRange(action, target) - actionCooldownStart, actionCooldownDuration, actionEnable = GetActionCooldown(action) - actionUsable = IsUsableAction(action) - actionShortcut = self.shortCut[action] - actionIsCurrent = IsCurrentAction(action) - else - Ovale:Log("Unknown macro "..element.params[1]) - end - elseif (element.func=="Item") then - local itemId - if (type(element.params[1]) == "number") then - itemId = element.params[1] - else - local _,_,id = string.find(GetInventoryItemLink("player",GetInventorySlotInfo(element.params[1])) or "","item:(%d+):%d+:%d+:%d+") - if not id then - return nil - end - itemId = tonumber(id) - end - - if (Ovale.trace) then - self:Print("Item "..nilstring(itemId)) - end - - local spellName = GetItemSpell(itemId) - actionUsable = (spellName~=nil) - - action = self.actionObjet[itemId] - --if (not action or not GetActionTexture(action)) then - actionTexture = GetItemIcon(itemId) - actionInRange = IsItemInRange(itemId, target) - actionCooldownStart, actionCooldownDuration, actionEnable = GetItemCooldown(itemId) - actionShortcut = nil - actionIsCurrent = nil - --end - elseif element.func=="Texture" then - actionTexture = "Interface\\Icons\\"..element.params[1] - actionCooldownStart = Ovale.maintenant - actionCooldownDuration = 0 - actionEnable = 1 - actionUsable = true - end - - if action then - if actionUsable == nil then - actionUsable = IsUsableAction(action) - end - actionShortcut = self.shortCut[action] - actionIsCurrent = IsCurrentAction(action) - end - - local cd = self:GetCD(spellId) - if cd and cd.toggle then - actionIsCurrent = 1 - end - - return actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, - actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellId, target, element.params.nored -end - -local function subTime(time1, duration) - if not time1 then - return nil - else - return time1 - duration - end -end - -local function addTime(time1, duration) - if not time1 then - return nil - else - return time1 + duration - end -end - -local function isBeforeEqual(time1, time2) - return time1 and (not time2 or time1<=time2) -end - -local function isBefore(time1, time2) - return time1 and (not time2 or time1<time2) -end - -local function isAfterEqual(time1, time2) - return not time1 or (time2 and time1>=time2) -end - -local function isAfter(time1, time2) - return not time1 or (time2 and time1>time2) -end - -function Ovale:CalculerMeilleureAction(element) - if (self.bug and not self.trace) then - return nil - end - - if (not element) then - return nil - end - - --TODO: créer un objet par type au lieu de ce if else if tout moche - if (element.type=="function")then - if (element.func == "Spell" or element.func=="Macro" or element.func=="Item" or element.func=="Texture") then - local action - local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, - actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellId = self:GetActionInfo(element) - - if not actionTexture then - if (Ovale.trace) then - self:Print("Action "..element.params[1].." not found") - end - return nil - end - if element.params.usable==1 and not actionUsable then - if (Ovale.trace) then - self:Print("Action "..element.params[1].." not usable") - end - return nil - end - if spellId and self.spellInfo[spellId] and self.spellInfo[spellId].casttime then - element.castTime = self.spellInfo[spellId].casttime - elseif spellId then - local spell, rank, icon, cost, isFunnel, powerType, castTime = GetSpellInfo(spellId) - if castTime then - element.castTime = castTime/1000 - else - element.castTime = nil - end - else - element.castTime = 0 - end - --TODO: not useful anymore? - if (spellId and self.spellInfo[spellId] and self.spellInfo[spellId].toggle and actionIsCurrent) then - if (Ovale.trace) then - self:Print("Action "..element.params[1].." is current action") - end - return nil - end - if actionEnable and actionEnable>0 then - local restant - if (not actionCooldownDuration or actionCooldownStart==0) then - restant = self.currentTime - else - restant = actionCooldownDuration + actionCooldownStart - end - self:Log("restant = "..restant.." attenteFinCast="..nilstring(self.attenteFinCast)) - if restant<self.attenteFinCast then - if -- spellName==self.currentSpellName or - not self.spellInfo[self.currentSpellId] or - not self.spellInfo[self.currentSpellId].canStopChannelling then - restant = self.attenteFinCast - else - --TODO: pas exact, parce que si ce sort est reporté de par exemple 0,5s par un debuff - --ça tombera entre deux ticks - local ticks = floor(self.spellHaste * self.spellInfo[self.currentSpellId].canStopChannelling + 0.5) - local tickLength = (self.attenteFinCast - self.startCast) / ticks - local tickTime = self.startCast + tickLength - if (Ovale.trace) then - self:Print(spellName.." restant = " .. restant) - self:Print("ticks = "..ticks.." tickLength="..tickLength.." tickTime="..tickTime) - end - for i=1,ticks do - if restant<=tickTime then - restant = tickTime - break - end - tickTime = tickTime + tickLength - end - if (Ovale.trace) then - self:Print(spellId.." restant = " .. restant) - end - end - end - if (Ovale.trace) then - self:Print("Action "..element.params[1].." remains "..restant) - end - local retourPriorite = element.params.priority - if (not retourPriorite) then - retourPriorite = 3 - end - return restant, nil, retourPriorite, element - else - if (Ovale.trace) then - self:Print("Action "..element.params[1].." not enabled") - end - end - else - local classe = Ovale.conditions[element.func] - if (not classe) then - self.bug = true - self:Print("Function "..element.func.." not found") - return nil - end - local start, ending, rate = classe(element.params) - - if (Ovale.trace) then - local parameterList = element.func.."(" - for k,v in pairs(element.params) do - parameterList = parameterList..k.."="..v.."," - end - self:Print("Function "..parameterList..") returned "..nilstring(start)..","..nilstring(ending)..","..nilstring(rate)) - end - - if rate then - if not element.result then - element.result = { type = "value" } - end - local result = element.result - result.value = start - result.origin = ending - result.rate = rate - return 0, nil, 3, result - else - return start, ending - end - end - elseif element.type == "time" then - return element.value - elseif element.type == "value" then - Ovale:Log("value " .. element.value) - return 0, nil, 3, element - elseif element.type == "after" then - local timeA = Ovale:CalculerMeilleureAction(element.time) - local startA, endA = Ovale:CalculerMeilleureAction(element.a) - return addTime(startA, timeA), addTime(endA, timeA) - elseif (element.type == "before") then - if (Ovale.trace) then - --self:Print(nilstring(element.time).."s before ["..element.nodeId.."]") - end - local timeA = Ovale:CalculerMeilleureAction(element.time) - local startA, endA = Ovale:CalculerMeilleureAction(element.a) - return addTime(startA, -timeA), addTime(endA, -timeA) - elseif (element.type == "between") then - self:Log("between") - local tempsA = Ovale:CalculerMeilleureAction(element.a) - local tempsB = Ovale:CalculerMeilleureAction(element.b) - if tempsB==nil and tempsA==nil then - Ovale:Log("diff returns 0 because the two nodes are nil") - return 0 - end - - if tempsA==nil or tempsB==nil then - if Ovale.trace then Ovale:Print(element.type.." return nil") end - return nil - end - local diff - if tempsA>tempsB then - diff = tempsA - tempsB - else - diff = tempsB - tempsA - end - Ovale:Log("diff returns "..diff) - return diff - elseif element.type == "fromuntil" then - self:Log("fromuntil") - local tempsA = Ovale:CalculerMeilleureAction(element.a) - if (tempsA==nil) then - if Ovale.trace then Ovale:Print(element.type.." return nil") end - return nil - end - local tempsB = Ovale:CalculerMeilleureAction(element.b) - if (tempsB==nil) then - if Ovale.trace then Ovale:Print(element.type.." return nil") end - return nil - end - Ovale:Log("fromuntil returns "..(tempsB - tempsA)) - return tempsB - tempsA - elseif element.type == "compare" then - self:Log("compare "..element.comparison) - local tempsA = Ovale:CalculerMeilleureAction(element.a) - local timeB = Ovale:CalculerMeilleureAction(element.time) - self:Log(nilstring(tempsA).." "..element.comparison.." "..nilstring(timeB)) - if element.comparison == "more" and (not tempsA or tempsA>timeB) then - if Ovale.trace then Ovale:Print(element.type.." return 0") end - return 0 - elseif element.comparison == "less" and tempsA and tempsA<timeB then - if Ovale.trace then Ovale:Print(element.type.." return 0") end - return 0 - elseif element.comparison == "at most" and tempsA and tempsA<=timeB then - if Ovale.trace then Ovale:Print(element.type.." return 0") end - return 0 - elseif element.comparison == "at least" and (not tempsA or tempsA>=timeB) then - if Ovale.trace then Ovale:Print(element.type.." return 0") end - return 0 - end - return nil - elseif element.type == "and" or element.type == "if" then - if (Ovale.trace) then - self:Print(element.type.." ["..element.nodeId.."]") - end - local startA, endA = Ovale:CalculerMeilleureAction(element.a) - if (startA==nil) then - if Ovale.trace then Ovale:Print(element.type.." return nil ["..element.nodeId.."]") end - return nil - end - if startA == endA then - if Ovale.trace then Ovale:Print(element.type.." return startA=endA ["..element.nodeId.."]") end - return nil - end - local startB, endB, prioriteB, elementB = Ovale:CalculerMeilleureAction(element.b) - if isAfter(startB, endA) or isAfter(startA, endB) then - if Ovale.trace then Ovale:Print(element.type.." return nil ["..element.nodeId.."]") end - return nil - end - if isBefore(startB, startA) then - startB = startA - end - if isAfter(endB, endA) then - endB = endA - end - if Ovale.trace then - Ovale:Print(element.type.." return "..nilstring(startB)..","..nilstring(endB).." ["..element.nodeId.."]") - end - return startB, endB, prioriteB, elementB - elseif element.type == "unless" then - if Ovale.trace then - self:Print(element.type) - end - local startA, endA = Ovale:CalculerMeilleureAction(element.a) - local startB, endB, prioriteB, elementB = Ovale:CalculerMeilleureAction(element.b) - - if isBeforeEqual(startA, startB) and isAfterEqual(endA, endB) then - if Ovale.trace then Ovale:Print(element.type.." return nil") end - return nil - end - - if isAfterEqual(startA, startB) and isBefore(endA, endB) then - if Ovale.trace then Ovale:Print(element.type.." return "..nilstring(endA)..","..nilstring(endB)) end - return endA, endB, prioriteB, elementB - end - - if isAfter(startA, startB) and isBefore(startA, endB) then - endB = startA - end - - if isAfter(endA, startB) and isBefore(endA, endB) then - startB = endA - end - - if Ovale.trace then Ovale:Print(element.type.." return "..nilstring(startB)..","..nilstring(endB)) end - return startB, endB, prioriteB, elementB - elseif (element.type == "or") then - if (Ovale.trace) then - self:Print(element.type) - end - - local startA, endA = Ovale:CalculerMeilleureAction(element.a) - local startB, endB = Ovale:CalculerMeilleureAction(element.b) - if isBefore(endA,self.currentTime) then - return startB,endB - elseif isBefore(endB,self.currentTime) then - return startA,endA - end - - if isBefore(endA,startB) then - return startA,endA - elseif isBefore(endB,startA) then - return startB,endB - end - - if isBefore(startA, startB) then - startB = startA - end - if isAfter(endA, endB) then - endB = endA - end - return startB, endB - elseif element.type == "operator" then - local startA, endA, prioA, elementA = self:CalculerMeilleureAction(element.a) - local startB, endB, prioB, elementB = self:CalculerMeilleureAction(element.b) - if not elementA or not elementB then - self:Log("operator " .. element.operator .. ": elementA or elementB is nil") - return nil - end - local a = elementA.value - local b = elementA.origin - local c = elementA.rate - local x = elementB.value - local y = elementB.origin - local z = elementB.rate - - if not a or not x or not b or not y then - self:Log("operator " .. element.operator .. ": a or x is nil") - return nil - end - - self:Log(a.."+(t-"..b..")*"..c.. element.operator..x.."+(t-"..y..")*"..z) - - local l, m, n - - if element.operator == "*" then - if c == 0 then - l = a*x - m = y - n = a*z - elseif z == 0 then - l = x*a; m = b; n = x*c - else - self:Print("ERROR: at least one value must be constant when multiplying") - self.bug = true - end - elseif element.operator == "+" then - if c+z == 0 then - l = a+x; m = 0; n = 0 - else - l = a+x; m = (b*c+y*z)/(c+z); n = c+z - end - elseif element.operator == '-' then - if c-z == 0 then - l = a-x; m = 0; n = 0 - else - l = a-x; m = (b*c-y*z)/(c-z); n = c-z - end - elseif element.operator == '/' then - if z == 0 then - l = a/x; m = b; n = c/x - else - self:Print("ERROR: second operator of / must be constant") - self.bug = true - end - elseif element.operator == '<' then - -- a + (t-b)*c = x + (t-y)*z - -- (t-b)*c - (t-y)*z = x - a - -- t*c - b*c - t*z + y*z = x - a - -- t*(c-z) = x - a + b*c + y*z - -- t = (x-a + b*c + y*z)/(c-z) - if c == z then - if a-b*c < x-y*z then - return 0 - else - return nil - end - else - local t = (x-a + b*c + y*z)/(c-z) - if c > z then - return 0, t - else - return t, nil - end - end - elseif element.operator == '>' then - if c == z then - self:Log("> with c==z") - if a-b*c > x-y*z then - self:Log("a>x") - return 0 - else - return nil - end - else - local t = (x-a + b*c + y*z)/(c-z) - if c < z then - return 0, t - else - return t, nil - end - end - end - if not element.result then - element.result = { type = "value" } - end - local result = element.result - result.value = l - result.origin = m - result.rate = n - self:Log("result = " .. l .." + "..m.."*"..n) - return startA, endA, 3, result - elseif element.type == "lua" then - local ret = loadstring(element.lua)() - self:Log("lua "..nilstring(ret)) - if not element.result then - element.result = { type = "value" } - end - local result = element.result - result.value = ret - result.origin = 0 - result.rate = 0 - return 0, nil, 3, result - elseif (element.type == "group") then - local meilleurTempsFils - local bestEnd - local meilleurePrioriteFils - local bestElement - local bestCastTime - - if (Ovale.trace) then - self:Print(element.type.." ["..element.nodeId.."]") - end - - if #element.nodes == 1 then - return Ovale:CalculerMeilleureAction(element.nodes[1]) - end - - for k, v in ipairs(element.nodes) do - local newStart, newEnd, priorite, nouveauElement = Ovale:CalculerMeilleureAction(v) - if newStart~=nil and newStart<Ovale.currentTime then - newStart = Ovale.currentTime - end - - - if newStart and (not newEnd or newStart<=newEnd) then - local remplacer - - local newCastTime - if nouveauElement then - newCastTime = nouveauElement.castTime - end - if not newCastTime or newCastTime < self.gcd then - newCastTime = self.gcd - end - - if (not meilleurTempsFils) then - remplacer = true - else - -- temps maximum entre le nouveau sort et le précédent - local maxEcart - if (priorite and not meilleurePrioriteFils) then - self.bug = true - self:Print("Internal error: meilleurePrioriteFils=nil and priorite="..priorite) - return nil - end - if (priorite and priorite > meilleurePrioriteFils) then - -- Si le nouveau sort est plus prioritaire que le précédent, on le lance - -- si caster le sort actuel repousse le nouveau sort - maxEcart = bestCastTime*0.75 - elseif (priorite and priorite < meilleurePrioriteFils) then - -- A l'inverse, si il est moins prioritaire que le précédent, on ne le lance - -- que si caster le nouveau sort ne repousse pas le meilleur - maxEcart = -newCastTime*0.75 - else - maxEcart = -0.01 - end - if (newStart-meilleurTempsFils < maxEcart) then - remplacer = true - end - end - if (remplacer) then - meilleurTempsFils = newStart - meilleurePrioriteFils = priorite - bestElement = nouveauElement - bestEnd = newEnd - bestCastTime = newCastTime - end - end - end - - if (meilleurTempsFils) then - if (Ovale.trace) then - if bestElement then - self:Print("group best action "..bestElement.params[1].." remains "..meilleurTempsFils..","..nilstring(bestEnd).." ["..element.nodeId.."]") - else - self:Print("group no best action returns "..meilleurTempsFils..","..nilstring(bestEnd).." ["..element.nodeId.."]") - end - end - return meilleurTempsFils, bestEnd, meilleurePrioriteFils, bestElement - else - if (Ovale.trace) then self:Print("group return nil") end - return nil - end - end - if (Ovale.trace) then self:Print("unknown element "..element.type..", return nil") end - return nil -end - -function Ovale:ChargerDefaut() - local localizedClass, englishClass = UnitClass("player") - - self.db = LibStub("AceDB-3.0"):New("OvaleDB", - { - profile = - { - display = true, - code = Ovale.defaut[englishClass], - left = 500, - top = 500, - check = {}, - list = {}, - apparence = {enCombat=false, iconScale = 2, secondIconScale = 1, margin = 4, fontScale = 0.5, iconShiftX = 0, iconShiftY = 0, - smallIconScale=1, raccourcis=true, numeric=false, avecCible = false, - verrouille = false, vertical = false, predictif=false, highlightIcon = true, clickThru = false, - latencyCorrection=true, hideVehicule=false, flashIcon=true, targetText = "●", alpha = 1, - optionsAlpha = 1, updateInterval=0.1} - } - }) -end - function Ovale:AfficherConfig() self.AceConfigDialog:SetDefaultSize("Ovale Apparence", 500, 550) self.AceConfigDialog:Open("Ovale Apparence", configFrame) @@ -2476,14 +215,14 @@ function Ovale:AfficherCode() end local function OnCheckBoxValueChanged(widget) - Ovale.db.profile.check[widget.userdata.k] = widget:GetValue() + OvaleOptions:GetProfile().check[widget.userdata.k] = widget:GetValue() if Ovale.casesACocher[widget.userdata.k].compile then Ovale.needCompile = true end end local function OnDropDownValueChanged(widget) - Ovale.db.profile.list[widget.userdata.k] = widget.value + OvaleOptions:GetProfile().list[widget.userdata.k] = widget.value if Ovale.listes[widget.userdata.k].compile then Ovale.needCompile = true end @@ -2494,26 +233,26 @@ function Ovale:ToggleOptions() end function Ovale:UpdateVisibility() - if not Ovale.db.profile.display then + if not OvaleOptions:GetProfile().display then self.frame:Hide() return end self.frame:Show() - if Ovale.db.profile.apparence.hideVehicule and UnitInVehicle("player") then + if OvaleOptions:GetApparence().hideVehicule and UnitInVehicle("player") then self.frame:Hide() end - if Ovale.db.profile.apparence.avecCible and not UnitExists("target") then + if OvaleOptions:GetApparence().avecCible and not UnitExists("target") then self.frame:Hide() end - if Ovale.db.profile.apparence.enCombat and not Ovale.enCombat then + if OvaleOptions:GetApparence().enCombat and not Ovale.enCombat then self.frame:Hide() end - if Ovale.db.profile.apparence.targetHostileOnly and (UnitIsDead("target") or not UnitCanAttack("player", "target")) then + if OvaleOptions:GetApparence().targetHostileOnly and (UnitIsDead("target") or not UnitCanAttack("player", "target")) then self.frame:Hide() end end @@ -2527,15 +266,17 @@ function Ovale:UpdateFrame() self.checkBoxes = {} + local profile = OvaleOptions:GetProfile() + for k,checkBox in pairs(self.casesACocher) do self.checkBoxes[k] = LibStub("AceGUI-3.0"):Create("CheckBox"); self.frame:AddChild(self.checkBoxes[k]) self.checkBoxes[k]:SetLabel(checkBox.text) - if self.db.profile.check[k]==nil then - self.db.profile.check[k] = checkBox.checked + if profile.check[k]==nil then + profile.check[k] = checkBox.checked end - if (self.db.profile.check[k]) then - self.checkBoxes[k]:SetValue(self.db.profile.check[k]); + if (profile.check[k]) then + self.checkBoxes[k]:SetValue(profile.check[k]); end self.checkBoxes[k].userdata.k = k self.checkBoxes[k]:SetCallback("OnValueChanged",OnCheckBoxValueChanged) @@ -2547,11 +288,11 @@ function Ovale:UpdateFrame() for k,list in pairs(self.listes) do self.dropDowns[k] = LibStub("AceGUI-3.0"):Create("Dropdown"); self.dropDowns[k]:SetList(list.items) - if not self.db.profile.list[k] then - self.db.profile.list[k] = list.default + if not profile.list[k] then + profile.list[k] = list.default end - if (self.db.profile.list[k]) then - self.dropDowns[k]:SetValue(self.db.profile.list[k]); + if (profile.list[k]) then + self.dropDowns[k]:SetValue(profile.list[k]); end self.dropDowns[k].userdata.k = k self.dropDowns[k]:SetCallback("OnValueChanged",OnDropDownValueChanged) @@ -2568,29 +309,11 @@ function Ovale:GetListValue(v) return self.dropDowns[v] and self.dropDowns[v].value end -function Ovale:GetSpellInfo(spellId) - if (not self.spellInfo[spellId]) then - self.spellInfo[spellId] = { aura = {player = {}, target = {}} } - end - return self.spellInfo[spellId] -end - -function Ovale:ResetSpellInfo() - self.spellInfo = {} -end - -function Ovale:EnableOtherAuras() - if self.otherAurasEnabled then - return - end - self.otherAurasEnabled = true -end - function Ovale:SetCheckBox(v,on) for k,checkBox in pairs(self.casesACocher) do if v==0 then self.checkBoxes[k]:SetValue(on) - self.db.profile.check[k] = on + OvaleOptions:GetProfile().check[k] = on break end v = v - 1 @@ -2601,9 +324,10 @@ function Ovale:ToggleCheckBox(v) for k,checkBox in pairs(self.casesACocher) do if v==0 then self.checkBoxes[k]:SetValue(not self.checkBoxes[k]:GetValue()) - self.db.profile.check[k] = self.checkBoxes[k]:GetValue() + OvaleOptions:GetProfile().check[k] = self.checkBoxes[k]:GetValue() break end v = v - 1 end -end \ No newline at end of file +end +--</public-static-methods> diff --git a/Ovale.toc b/Ovale.toc index afe973f..fa5ec41 100644 --- a/Ovale.toc +++ b/Ovale.toc @@ -3,7 +3,7 @@ ## Notes: Show the icon of the next spell to cast ## Notes-frFR: Affiche l'icône du prochain sort à lancer ## Author: Sidoine -## Version: 4.3.11 +## Version: 4.3.12 ## OptionalDeps: Ace3, Masque, Recount, Skada, LibBabble-CreatureType-3.0, LibRangeCheck-2.0 ## SavedVariables: OvaleDB ## SavedVariablesPerCharacter: OvaleDBPC @@ -15,6 +15,7 @@ embeds.xml Locale-frFR.lua Locale-deDE.lua Locale-enUS.lua +Locale-esES.lua Locale-itIT.lua Locale-koKR.lua Locale-ptBR.lua @@ -22,14 +23,24 @@ Locale-ruRU.lua Locale-zhCN.lua Locale-zhTW.lua Ovale.lua -Condition.lua +OvaleActionBar.lua +OvaleAura.lua +OvaleBestAction.lua +OvaleCompile.lua +OvaleCondition.lua +OvaleData.lua OvaleEquipement.lua +OvaleEnemies.lua +OvaleFrame.lua +OvaleFuture.lua +OvaleGUID.lua OvaleIcone.lua OvaleIcone.xml -OvaleFrame.lua -OvaleCompile.lua +OvaleOptions.lua OvaleRecount.lua OvaleSkada.lua +OvaleSpellDamage.lua +OvaleState.lua OvaleSwing.lua defaut\Chaman.lua defaut\Chasseur.lua diff --git a/OvaleActionBar.lua b/OvaleActionBar.lua new file mode 100644 index 0000000..8bd29da --- /dev/null +++ b/OvaleActionBar.lua @@ -0,0 +1,108 @@ +-- Keep data about the player action bars (key bindings mostly) +OvaleActionBar = LibStub("AceAddon-3.0"):NewAddon("OvaleActionBar", "AceEvent-3.0") + +--<public-static-properties> +--key: spell name / value: action icon id +OvaleActionBar.actionSort = {} +OvaleActionBar.actionMacro = {} +OvaleActionBar.actionObjet = {} +OvaleActionBar.shortCut = {} +--</public-static-properties> + +--<public-static-methods> +function OvaleActionBar:OnEnable() + self:RegisterEvent("ACTIONBAR_SLOT_CHANGED") + self:RegisterEvent("UPDATE_BINDINGS") + self:FillActionIndexes() +end + +function OvaleActionBar:OnDisable() + self:UnregisterEvent("ACTIONBAR_SLOT_CHANGED") + self:UnregisterEvent("UPDATE_BINDINGS") +end + +function OvaleActionBar:ACTIONBAR_SLOT_CHANGED(event, slot, unknown) + if (slot == 0) then + self:FillActionIndexes() + elseif (slot) then + -- on reoit aussi si c'est une macro avec mouseover chaque fois que la souris passe sur une cible! + self:FillActionIndex(tonumber(slot)) + end +end + +--Called when the user changed his key bindings +function OvaleActionBar:UPDATE_BINDINGS() + self:FillActionIndexes() +end + +function OvaleActionBar:FillActionIndexes() + self.actionSort = {} + self.actionMacro = {} + self.actionObjet = {} + self.shortCut = {} + for i=1,120 do + self:FillActionIndex(i) + end +end + +function OvaleActionBar:FillActionIndex(i) + self.shortCut[i] = self:FindKeyBinding(i) + local actionText = GetActionText(i) + if actionText then + self.actionMacro[actionText] = i + else + local type, spellId = GetActionInfo(i); + if (type=="spell") then + self.actionSort[spellId] = i + elseif (type =="item") then + self.actionObjet[spellId] = i + end + end +end + +function OvaleActionBar:FindKeyBinding(id) +-- ACTIONBUTTON1..12 => principale (1..12, 13..24, 73..108) +-- MULTIACTIONBAR1BUTTON1..12 => bas gauche (61..72) +-- MULTIACTIONBAR2BUTTON1..12 => bas droite (49..60) +-- MULTIACTIONBAR3BUTTON1..12 => haut droit (25..36) +-- MULTIACTIONBAR4BUTTON1..12 => haut gauche (37..48) + local name; + if (id<=24 or id>72) then + name = "ACTIONBUTTON"..(((id-1)%12)+1); + elseif (id<=36) then + name = "MULTIACTIONBAR3BUTTON"..(id-24); + elseif (id<=48) then + name = "MULTIACTIONBAR4BUTTON"..(id-36); + elseif (id<=60) then + name = "MULTIACTIONBAR2BUTTON"..(id-48); + else + name = "MULTIACTIONBAR1BUTTON"..(id-60); + end + local key = GetBindingKey(name); +--[[ if (not key) then + DEFAULT_CHAT_FRAME:AddMessage(id.."=>"..name.." introuvable") + else + DEFAULT_CHAT_FRAME:AddMessage(id.."=>"..name.."="..key) + end]] + return key; +end + +-- Get the action id that match a spell id +function OvaleActionBar:GetForSpell(spellId) + return self.actionSort[spellId] +end + +-- Get the action id that match a macro id +function OvaleActionBar:GetForMacro(macroId) + return self.actionMacro[macroId] +end + +-- Get the action id that match an item id +function OvaleActionBar:GetForItem(itemId) + return self.actionObjet[itemId] +end + +function OvaleActionBar:GetBinding(actionId) + return self.shortCut[actionId] +end +--</public-static-methods> diff --git a/OvaleAura.lua b/OvaleAura.lua new file mode 100644 index 0000000..ae0f3d4 --- /dev/null +++ b/OvaleAura.lua @@ -0,0 +1,269 @@ +-- This addon keep the list of all the aura for all the units +-- Fore each aura, it saves the state of the player when it was refreshed + +OvaleAura = LibStub("AceAddon-3.0"):NewAddon("OvaleAura", "AceEvent-3.0") + +--<public-static-properties> +OvaleAura.aura = {} +OvaleAura.serial = 0 +OvaleAura.spellHaste = 1 +OvaleAura.meleeHaste = 1 +OvaleAura.damageMultiplier = 1 +OvaleAura.playerGUID = nil +--</public-static-properties> + +-- Events +--<public-static-methods> +function OvaleAura:OnEnable() + self.playerGUID = UnitGUID("player") + self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") +end + +function OvaleAura:OnDisable() + self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") +end + +function OvaleAura:COMBAT_LOG_EVENT_UNFILTERED(event, ...) + local time, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags = select(1, ...) + + if string.find(event, "SPELL_AURA_") == 1 then + local spellId, spellName, spellSchool, auraType = select(12, ...) + + local unitId = OvaleGUID:GetUnitId(destGUID) + + if unitId then + self:UpdateAuras(unitId, destGUID) + end + + if sourceGUID == self.playerGUID and (event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_REFRESH" or event == "SPELL_AURA_APPLIED_DOSE") then + local aura = self:GetAuraByGUID(destGUID, spellId, true) + if aura then + aura.spellHaste = self.spellHaste + end + end + end + + if event == "UNIT_DIED" then + self.aura[destGUID] = nil + local unitId = OvaleGUID:GetUnitId(destGUID) + if unitId then + Ovale.refreshNeeded[unitId] = true + end + end +end + +function OvaleAura:AddAura(unitGUID, spellId, unitCaster, icon, count, debuffType, duration, expirationTime, isStealable, name) + local auraList = self.aura[unitGUID] + + if not auraList[spellId] then + auraList[spellId] = {} + end + + local mine = (unitCaster == "player") + local aura + if mine then + if not auraList[spellId].mine then + auraList[spellId].mine = { gain = OvaleState.maintenant } + end + aura = auraList[spellId].mine + else + if not auraList[spellId].other then + auraList[spellId].other = { gain = OvaleState.maintenant } + end + aura = auraList[spellId].other + end + + aura.serial = self.serial + + if count == 0 then + count = 1 + end + + if not aura.ending or aura.ending < expirationTime or aura.stacks < count then + aura.icon = icon + aura.stacks = count + aura.debuffType = debuffType + if duration > 0 then + aura.duration = duration + aura.ending = expirationTime + else + aura.duration = nil + aura.ending = nil + end + aura.start = expirationTime - duration + aura.stealable = isStealable + aura.mine = mine + aura.source = unitCaster + aura.name = name + end +end + +-- Private methods +function OvaleAura:UpdateAuras(unitId, unitGUID) + self.serial = self.serial + 1 + + local hateBase + local hateCommune + local hateSorts + local hateCaC + local hateHero + local hateClasse + local damageMultiplier + + if unitId == "player" then + hateBase = GetCombatRatingBonus(18) + hateCommune = 0 + hateSorts = 0 + hateCaC = 0 + hateHero = 0 + hateClasse = 0 + damageMultiplier = 1 + end + + if not unitGUID then + unitGUID = UnitGUID(unitId) + end + + if not self.aura[unitGUID] then + self.aura[unitGUID] = {} + end + + local i = 1 + + local mode = "HELPFUL" + while (true) do + local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId = UnitAura(unitId, i, mode) + if not name then + if mode == "HELPFUL" then + mode = "HARMFUL" + i = 1 + else + break + end + else + self:AddAura(unitGUID, spellId, unitCaster, icon, count, debuffType, duration, expirationTime, isStealable, name) + if debuffType then + -- TODO: not very clean + -- should be computed by OvaleState:GetAura + self:AddAura(unitGUID, debuffType, unitCaster, icon, count, debuffType, duration, expirationTime, isStealable, name) + end + + if unitId == "player" then + if OvaleData.buffSpellList.spellhaste[spellId] then + hateSorts = 5 + elseif OvaleData.buffSpellList.meleehaste[spellId] then + hateCaC = 10 + elseif OvaleData.buffSpellList.heroism[spellId] then + hateHero = 30 + elseif OvaleData.selfHasteBuff[spellId] then + hateClasse = OvaleData.selfHasteBuff[spellId] + end + if OvaleData.selfDamageBuff[spellId] then + damageMultiplier = damageMultiplier * OvaleData.selfDamageBuff[spellId] + end + end + i = i + 1 + end + end + + local auraList = self.aura[unitGUID] + --Removes expired aura + for spellId,whoseTable in pairs(auraList) do + for whose,aura in pairs(whoseTable) do + if aura.serial ~= self.serial then + -- Ovale:Print("Removing "..aura.name.." from "..whose .. " self.serial = " ..self.serial .. " aura.serial = " ..aura.serial) + whoseTable[whose] = nil + end + end + if not next(whoseTable) then + --Ovale:Print("Removing "..spellId) + auraList[spellId] = nil + end + end + + --Clear unit if all aura have been deleted + if not next(auraList) then + self.aura[unitGUID] = nil + end + + --Update player haste + if unitId == "player" then + self.spellHaste = 1 + (hateBase + hateCommune + hateSorts + hateHero + hateClasse)/100 + self.meleeHaste = 1 + (hateBase + hateCommune + hateCaC + hateHero + hateClasse)/100 + self.damageMultiplier = damageMultiplier + end + + Ovale.refreshNeeded[unitId] = true +end + +-- Public methods +function OvaleAura:GetAuraByGUID(guid, spellId, mine, unitId) + if not guid then + return nil + end + local auraTable = self.aura[guid] + if not auraTable then + if not unitId then + unitId = OvaleGUID:GetUnitId(guid) + end + if not unitId then + return nil + end + self:UpdateAuras(unitId, guid) + auraTable = self.aura[guid] + if not auraTable then + -- no aura on target + return nil + end + end + local aura = auraTable[spellId] + if not aura then return nil end + if mine or mine == 1 then + return aura.mine + elseif aura.other then + return aura.other + else + return aura.mine + end +end + +function OvaleAura:GetAura(unitId, spellId, mine) + return self:GetAuraByGUID(UnitGUID(unitId), spellId, mine, unitId) +end + +-- Look for the last of my aura on any targt that will expires. +-- Returns its expiration time +function OvaleAura:GetExpirationTimeOnAnyTarget(spellId) + local ending = nil + local starting = nil + + for unitId,auraTable in pairs(self.aura) do + if auraTable[spellId] then + local aura = auraTable[spellId].mine + if aura then + local newEnding = aura.ending + local newStarting = aura.start + if newStarting and (not staring or newStarting < starting) then + starting = newStarting + end + if newEnding and (not ending or newEnding > ending) then + ending = newEnding + end + end + end + end + return starting, ending +end + +function OvaleAura:Debug() + Ovale:Print("------") + for guid,auraTable in pairs(self.aura) do + Ovale:Print("***"..guid) + for spellId,whoseTable in pairs(auraTable) do + for whose,aura in pairs(whoseTable) do + Ovale:Print(guid.." "..whose.." "..spellId .. " "..aura.name .. " stacks ="..aura.stacks) + end + end + end +end +--</public-static-methods> diff --git a/OvaleBestAction.lua b/OvaleBestAction.lua new file mode 100644 index 0000000..cccbe52 --- /dev/null +++ b/OvaleBestAction.lua @@ -0,0 +1,616 @@ +OvaleBestAction = {} + +--<private-static-methods> +local function nilstring(text) + if text == nil then + return "nil" + else + return text + end +end + +local function printTime(temps) + if (temps == nil) then + Ovale:Print("> nil") + else + Ovale:Print("> "..temps) + end +end + +local function addTime(time1, duration) + if not time1 then + return nil + else + return time1 + duration + end +end + +local function isBeforeEqual(time1, time2) + return time1 and (not time2 or time1<=time2) +end + +local function isBefore(time1, time2) + return time1 and (not time2 or time1<time2) +end + +local function isAfterEqual(time1, time2) + return not time1 or (time2 and time1>=time2) +end + +local function isAfter(time1, time2) + return not time1 or (time2 and time1>time2) +end +--</private-static-methods> + +--<public-static-methods> +function OvaleBestAction:StartNewAction() + OvaleState:Reset() + OvaleFuture:Apply() +end + +function OvaleBestAction:GetActionInfo(element) + if not element then + return nil + end + + local spellId = element.params[1] + local action + local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, + actionUsable, actionShortcut, actionIsCurrent, actionEnable + + local target = element.params.target + if (not target) then + target = OvaleCondition.defaultTarget + end + + if (element.func == "Spell" ) then + action = OvaleActionBar:GetForSpell(spellId) + if not OvaleData.spellList[spellId] and not action then + Ovale:Log("Spell "..spellId.." not learnt") + return nil + end + + actionCooldownStart, actionCooldownDuration, actionEnable = OvaleData:GetComputedSpellCD(spellId) + + spellName = OvaleData.spellList[spellId] + if not spellName then + spellName = GetSpellInfo(spellId) + end + actionTexture = GetSpellTexture(spellId) + actionInRange = IsSpellInRange(spellName, target) + actionUsable = IsUsableSpell(spellId) + actionShortcut = nil + elseif (element.func=="Macro") then + action = OvaleActionBar:GetForMacro(element.params[1]) + if action then + actionTexture = GetActionTexture(action) + actionInRange = IsActionInRange(action, target) + actionCooldownStart, actionCooldownDuration, actionEnable = GetActionCooldown(action) + actionUsable = IsUsableAction(action) + actionShortcut = OvaleActionBar:GetBinding(action) + actionIsCurrent = IsCurrentAction(action) + else + Ovale:Log("Unknown macro "..element.params[1]) + end + elseif (element.func=="Item") then + local itemId + if (type(element.params[1]) == "number") then + itemId = element.params[1] + else + local _,_,id = string.find(GetInventoryItemLink("player",GetInventorySlotInfo(element.params[1])) or "","item:(%d+):%d+:%d+:%d+") + if not id then + return nil + end + itemId = tonumber(id) + end + + if (Ovale.trace) then + Ovale:Print("Item "..nilstring(itemId)) + end + + local spellName = GetItemSpell(itemId) + actionUsable = (spellName~=nil) + + action = OvaleActionBar:GetForItem(itemId) + actionTexture = GetItemIcon(itemId) + actionInRange = IsItemInRange(itemId, target) + actionCooldownStart, actionCooldownDuration, actionEnable = GetItemCooldown(itemId) + actionShortcut = nil + actionIsCurrent = nil + elseif element.func=="Texture" then + actionTexture = "Interface\\Icons\\"..element.params[1] + actionCooldownStart = OvaleState.maintenant + actionCooldownDuration = 0 + actionEnable = 1 + actionUsable = true + end + + if action then + if actionUsable == nil then + actionUsable = IsUsableAction(action) + end + actionShortcut = OvaleActionBar:GetBinding(action) + actionIsCurrent = IsCurrentAction(action) + end + + local cd = OvaleState:GetCD(spellId) + if cd and cd.toggle then + actionIsCurrent = 1 + end + + return actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, + actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellId, target, element.params.nored +end + +function OvaleBestAction:Compute(element) + if (Ovale.bug and not Ovale.trace) then + return nil + end + + if (not element) then + return nil + end + + --TODO: crer un objet par type au lieu de ce if else if tout moche + if (element.type=="function")then + if (element.func == "Spell" or element.func=="Macro" or element.func=="Item" or element.func=="Texture") then + local action + local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, + actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellId = self:GetActionInfo(element) + + if not actionTexture then + if (Ovale.trace) then + Ovale:Print("Action "..element.params[1].." not found") + end + return nil + end + if element.params.usable==1 and not actionUsable then + if (Ovale.trace) then + Ovale:Print("Action "..element.params[1].." not usable") + end + return nil + end + if spellId and OvaleData.spellInfo[spellId] and OvaleData.spellInfo[spellId].casttime then + element.castTime = OvaleData.spellInfo[spellId].casttime + elseif spellId then + local spell, rank, icon, cost, isFunnel, powerType, castTime = GetSpellInfo(spellId) + if castTime then + element.castTime = castTime/1000 + else + element.castTime = nil + end + else + element.castTime = 0 + end + --TODO: not useful anymore? + if (spellId and OvaleData.spellInfo[spellId] and OvaleData.spellInfo[spellId].toggle and actionIsCurrent) then + if (Ovale.trace) then + Ovale:Print("Action "..element.params[1].." is current action") + end + return nil + end + if actionEnable and actionEnable>0 then + local restant + if (not actionCooldownDuration or actionCooldownStart==0) then + restant = OvaleState.currentTime + else + restant = actionCooldownDuration + actionCooldownStart + end + Ovale:Log("restant = "..restant.." attenteFinCast="..nilstring(OvaleState.attenteFinCast)) + if restant<OvaleState.attenteFinCast then + if not OvaleData.spellInfo[OvaleState.currentSpellId] or + not OvaleData.spellInfo[OvaleState.currentSpellId].canStopChannelling then + restant = OvaleState.attenteFinCast + else + --TODO: pas exact, parce que si ce sort est report de par exemple 0,5s par un debuff + --a tombera entre deux ticks + local ticks = floor(OvaleAura.spellHaste * OvaleData.spellInfo[OvaleState.currentSpellId].canStopChannelling + 0.5) + local tickLength = (OvaleState.attenteFinCast - OvaleState.startCast) / ticks + local tickTime = OvaleState.startCast + tickLength + if (Ovale.trace) then + Ovale:Print(spellName.." restant = " .. restant) + Ovale:Print("ticks = "..ticks.." tickLength="..tickLength.." tickTime="..tickTime) + end + for i=1,ticks do + if restant<=tickTime then + restant = tickTime + break + end + tickTime = tickTime + tickLength + end + if (Ovale.trace) then + Ovale:Print(spellId.." restant = " .. restant) + end + end + end + if (Ovale.trace) then + Ovale:Print("Action "..element.params[1].." remains "..restant) + end + local retourPriorite = element.params.priority + if (not retourPriorite) then + retourPriorite = 3 + end + return restant, nil, retourPriorite, element + else + if (Ovale.trace) then + Ovale:Print("Action "..element.params[1].." not enabled") + end + end + else + local classe = OvaleCondition.conditions[element.func] + if (not classe) then + Ovale.bug = true + Ovale:Print("Function "..element.func.." not found") + return nil + end + local start, ending, rate = classe(element.params) + + if (Ovale.trace) then + local parameterList = element.func.."(" + for k,v in pairs(element.params) do + parameterList = parameterList..k.."="..v.."," + end + Ovale:Print("Function "..parameterList..") returned "..nilstring(start)..","..nilstring(ending)..","..nilstring(rate)) + end + + if rate then + if not element.result then + element.result = { type = "value" } + end + local result = element.result + result.value = start + result.origin = ending + result.rate = rate + return 0, nil, 3, result + else + return start, ending + end + end + elseif element.type == "time" then + return element.value + elseif element.type == "value" then + Ovale:Log("value " .. element.value) + return 0, nil, 3, element + elseif element.type == "after" then + local timeA = self:Compute(element.time) + local startA, endA = self:Compute(element.a) + return addTime(startA, timeA), addTime(endA, timeA) + elseif (element.type == "before") then + if (Ovale.trace) then + --Ovale:Print(nilstring(element.time).."s before ["..element.nodeId.."]") + end + local timeA = self:Compute(element.time) + local startA, endA = self:Compute(element.a) + return addTime(startA, -timeA), addTime(endA, -timeA) + elseif (element.type == "between") then + Ovale:Log("between") + local tempsA = self:Compute(element.a) + local tempsB = self:Compute(element.b) + if tempsB==nil and tempsA==nil then + Ovale:Log("diff returns 0 because the two nodes are nil") + return 0 + end + + if tempsA==nil or tempsB==nil then + if Ovale.trace then Ovale:Print(element.type.." return nil") end + return nil + end + local diff + if tempsA>tempsB then + diff = tempsA - tempsB + else + diff = tempsB - tempsA + end + Ovale:Log("diff returns "..diff) + return diff + elseif element.type == "fromuntil" then + Ovale:Log("fromuntil") + local tempsA = self:Compute(element.a) + if (tempsA==nil) then + if Ovale.trace then Ovale:Print(element.type.." return nil") end + return nil + end + local tempsB = self:Compute(element.b) + if (tempsB==nil) then + if Ovale.trace then Ovale:Print(element.type.." return nil") end + return nil + end + Ovale:Log("fromuntil returns "..(tempsB - tempsA)) + return tempsB - tempsA + elseif element.type == "compare" then + Ovale:Log("compare "..element.comparison) + local tempsA = self:Compute(element.a) + local timeB = self:Compute(element.time) + Ovale:Log(nilstring(tempsA).." "..element.comparison.." "..nilstring(timeB)) + if element.comparison == "more" and (not tempsA or tempsA>timeB) then + if Ovale.trace then Ovale:Print(element.type.." return 0") end + return 0 + elseif element.comparison == "less" and tempsA and tempsA<timeB then + if Ovale.trace then Ovale:Print(element.type.." return 0") end + return 0 + elseif element.comparison == "at most" and tempsA and tempsA<=timeB then + if Ovale.trace then Ovale:Print(element.type.." return 0") end + return 0 + elseif element.comparison == "at least" and (not tempsA or tempsA>=timeB) then + if Ovale.trace then Ovale:Print(element.type.." return 0") end + return 0 + end + return nil + elseif element.type == "and" or element.type == "if" then + if (Ovale.trace) then + Ovale:Print(element.type.." ["..element.nodeId.."]") + end + local startA, endA = self:Compute(element.a) + if (startA==nil) then + if Ovale.trace then Ovale:Print(element.type.." return nil ["..element.nodeId.."]") end + return nil + end + if startA == endA then + if Ovale.trace then Ovale:Print(element.type.." return startA=endA ["..element.nodeId.."]") end + return nil + end + local startB, endB, prioriteB, elementB = self:Compute(element.b) + if isAfter(startB, endA) or isAfter(startA, endB) then + if Ovale.trace then Ovale:Print(element.type.." return nil ["..element.nodeId.."]") end + return nil + end + if isBefore(startB, startA) then + startB = startA + end + if isAfter(endB, endA) then + endB = endA + end + if Ovale.trace then + Ovale:Print(element.type.." return "..nilstring(startB)..","..nilstring(endB).." ["..element.nodeId.."]") + end + return startB, endB, prioriteB, elementB + elseif element.type == "unless" then + if Ovale.trace then + Ovale:Print(element.type) + end + local startA, endA = self:Compute(element.a) + local startB, endB, prioriteB, elementB = self:Compute(element.b) + + if isBeforeEqual(startA, startB) and isAfterEqual(endA, endB) then + if Ovale.trace then Ovale:Print(element.type.." return nil") end + return nil + end + + if isAfterEqual(startA, startB) and isBefore(endA, endB) then + if Ovale.trace then Ovale:Print(element.type.." return "..nilstring(endA)..","..nilstring(endB)) end + return endA, endB, prioriteB, elementB + end + + if isAfter(startA, startB) and isBefore(startA, endB) then + endB = startA + end + + if isAfter(endA, startB) and isBefore(endA, endB) then + startB = endA + end + + if Ovale.trace then Ovale:Print(element.type.." return "..nilstring(startB)..","..nilstring(endB)) end + return startB, endB, prioriteB, elementB + elseif (element.type == "or") then + if (Ovale.trace) then + Ovale:Print(element.type) + end + + local startA, endA = self:Compute(element.a) + local startB, endB = self:Compute(element.b) + if isBefore(endA,OvaleState.currentTime) then + return startB,endB + elseif isBefore(endB,OvaleState.currentTime) then + return startA,endA + end + + if isBefore(endA,startB) then + return startA,endA + elseif isBefore(endB,startA) then + return startB,endB + end + + if isBefore(startA, startB) then + startB = startA + end + if isAfter(endA, endB) then + endB = endA + end + return startB, endB + elseif element.type == "operator" then + local startA, endA, prioA, elementA = self:Compute(element.a) + local startB, endB, prioB, elementB = self:Compute(element.b) + if not elementA or not elementB then + Ovale:Log("operator " .. element.operator .. ": elementA or elementB is nil") + return nil + end + local a = elementA.value + local b = elementA.origin + local c = elementA.rate + local x = elementB.value + local y = elementB.origin + local z = elementB.rate + + if not a or not x or not b or not y then + Ovale:Log("operator " .. element.operator .. ": a or x is nil") + return nil + end + + Ovale:Log(a.."+(t-"..b..")*"..c.. element.operator..x.."+(t-"..y..")*"..z) + + local l, m, n + + if element.operator == "*" then + if c == 0 then + l = a*x + m = y + n = a*z + elseif z == 0 then + l = x*a; m = b; n = x*c + else + Ovale:Print("ERROR: at least one value must be constant when multiplying") + Ovale.bug = true + end + elseif element.operator == "+" then + if c+z == 0 then + l = a+x; m = 0; n = 0 + else + l = a+x; m = (b*c+y*z)/(c+z); n = c+z + end + elseif element.operator == '-' then + if c-z == 0 then + l = a-x; m = 0; n = 0 + else + l = a-x; m = (b*c-y*z)/(c-z); n = c-z + end + elseif element.operator == '/' then + if z == 0 then + l = a/x; m = b; n = c/x + else + Ovale:Print("ERROR: second operator of / must be constant") + Ovale.bug = true + end + elseif element.operator == '<' then + -- a + (t-b)*c = x + (t-y)*z + -- (t-b)*c - (t-y)*z = x - a + -- t*c - b*c - t*z + y*z = x - a + -- t*(c-z) = x - a + b*c + y*z + -- t = (x-a + b*c + y*z)/(c-z) + if c == z then + if a-b*c < x-y*z then + return 0 + else + return nil + end + else + local t = (x-a + b*c + y*z)/(c-z) + if c > z then + return 0, t + else + return t, nil + end + end + elseif element.operator == '>' then + if c == z then + Ovale:Log("> with c==z") + if a-b*c > x-y*z then + Ovale:Log("a>x") + return 0 + else + return nil + end + else + local t = (x-a + b*c + y*z)/(c-z) + if c < z then + return 0, t + else + return t, nil + end + end + end + if not element.result then + element.result = { type = "value" } + end + local result = element.result + result.value = l + result.origin = m + result.rate = n + Ovale:Log("result = " .. l .." + "..m.."*"..n) + return startA, endA, 3, result + elseif element.type == "lua" then + local ret = loadstring(element.lua)() + Ovale:Log("lua "..nilstring(ret)) + if not element.result then + element.result = { type = "value" } + end + local result = element.result + result.value = ret + result.origin = 0 + result.rate = 0 + return 0, nil, 3, result + elseif (element.type == "group") then + local meilleurTempsFils + local bestEnd + local meilleurePrioriteFils + local bestElement + local bestCastTime + + if (Ovale.trace) then + Ovale:Print(element.type.." ["..element.nodeId.."]") + end + + if #element.nodes == 1 then + return self:Compute(element.nodes[1]) + end + + for k, v in ipairs(element.nodes) do + local newStart, newEnd, priorite, nouveauElement = self:Compute(v) + if newStart~=nil and newStart<OvaleState.currentTime then + newStart = OvaleState.currentTime + end + + + if newStart and (not newEnd or newStart<=newEnd) then + local remplacer + + local newCastTime + if nouveauElement then + newCastTime = nouveauElement.castTime + end + if not newCastTime or newCastTime < OvaleState.gcd then + newCastTime = OvaleState.gcd + end + + if (not meilleurTempsFils) then + remplacer = true + else + -- temps maximum entre le nouveau sort et le prcdent + local maxEcart + if (priorite and not meilleurePrioriteFils) then + Ovale.bug = true + Ovale:Print("Internal error: meilleurePrioriteFils=nil and priorite="..priorite) + return nil + end + if (priorite and priorite > meilleurePrioriteFils) then + -- Si le nouveau sort est plus prioritaire que le prcdent, on le lance + -- si caster le sort actuel repousse le nouveau sort + maxEcart = bestCastTime*0.75 + elseif (priorite and priorite < meilleurePrioriteFils) then + -- A l'inverse, si il est moins prioritaire que le prcdent, on ne le lance + -- que si caster le nouveau sort ne repousse pas le meilleur + maxEcart = -newCastTime*0.75 + else + maxEcart = -0.01 + end + if (newStart-meilleurTempsFils < maxEcart) then + remplacer = true + end + end + if (remplacer) then + meilleurTempsFils = newStart + meilleurePrioriteFils = priorite + bestElement = nouveauElement + bestEnd = newEnd + bestCastTime = newCastTime + end + end + end + + if (meilleurTempsFils) then + if (Ovale.trace) then + if bestElement then + Ovale:Print("group best action "..bestElement.params[1].." remains "..meilleurTempsFils..","..nilstring(bestEnd).." ["..element.nodeId.."]") + else + Ovale:Print("group no best action returns "..meilleurTempsFils..","..nilstring(bestEnd).." ["..element.nodeId.."]") + end + end + return meilleurTempsFils, bestEnd, meilleurePrioriteFils, bestElement + else + if (Ovale.trace) then Ovale:Print("group return nil") end + return nil + end + end + if (Ovale.trace) then Ovale:Print("unknown element "..element.type..", return nil") end + return nil +end +--</public-static-methods> diff --git a/OvaleCompile.lua b/OvaleCompile.lua index 68eaa4d..afc00ec 100644 --- a/OvaleCompile.lua +++ b/OvaleCompile.lua @@ -1,9 +1,14 @@ local L = LibStub("AceLocale-3.0"):GetLocale("Ovale") +OvaleCompile = {} + +--<private-static-properties> local node={} local defines = {} local customFunctions = {} +--</private-static-properties> +--<private-static-methods> local function AddNode(newNode) node[#node+1] = newNode newNode.nodeId = #node @@ -48,12 +53,12 @@ local function HasGlyph(spellId) end local function HasTalent(talentId) - if not Ovale.listeTalentsRemplie then - Ovale:RemplirListeTalents() + if not OvaleData.listeTalentsRemplie then + OvaleData:RemplirListeTalents() end - if Ovale.listeTalentsRemplie then - if Ovale.pointsTalent[talentId]~=nil then - return Ovale.pointsTalent[talentId]>0 + if OvaleData.listeTalentsRemplie then + if OvaleData.pointsTalent[talentId]~=nil then + return OvaleData.pointsTalent[talentId]>0 else Ovale:Print("Unknown talent "..talentId) return false @@ -79,7 +84,7 @@ local function TestConditions(paramList) Ovale.casesACocher[cb] = {} end Ovale.casesACocher[cb].compile = true - if not Ovale.db.profile.check[cb] then + if not OvaleOptions:GetProfile().check[cb] then return false end end @@ -89,7 +94,7 @@ local function TestConditions(paramList) Ovale.casesACocher[cb] = {} end Ovale.casesACocher[cb].compile = true - if Ovale.db.profile.check[cb] then + if OvaleOptions:GetProfile().check[cb] then return false end end @@ -100,7 +105,7 @@ local function TestConditions(paramList) Ovale.listes[list] = { items = {}} end Ovale.listes[list].compile = true - if Ovale.db.profile.list[list] ~= key then + if OvaleOptions:GetProfile().list[list] ~= key then return false end end @@ -155,7 +160,7 @@ local function ParseSpellAddDebuff(params) local spellId = paramList[1] if spellId then paramList[1] = nil - Ovale:GetSpellInfo(spellId).aura.player.HARMFUL = paramList + OvaleData:GetSpellInfo(spellId).aura.player.HARMFUL = paramList end return "" end @@ -165,7 +170,7 @@ local function ParseSpellAddBuff(params) local spellId = paramList[1] if spellId then paramList[1] = nil - Ovale:GetSpellInfo(spellId).aura.player.HELPFUL = paramList + OvaleData:GetSpellInfo(spellId).aura.player.HELPFUL = paramList end return "" end @@ -175,7 +180,7 @@ local function ParseSpellAddTargetDebuff(params) local spellId = paramList[1] if spellId then paramList[1] = nil - Ovale:GetSpellInfo(spellId).aura.target.HARMFUL = paramList + OvaleData:GetSpellInfo(spellId).aura.target.HARMFUL = paramList end return "" end @@ -188,7 +193,7 @@ local function ParseSpellInfo(params) if not TestConditions(paramList) then return "" end - local spellInfo = Ovale:GetSpellInfo(spellId) + local spellInfo = OvaleData:GetSpellInfo(spellId) for k,v in pairs(paramList) do if k == "addduration" then spellInfo.duration = spellInfo.duration + v @@ -207,7 +212,7 @@ local function ParseScoreSpells(params) local spellId = tonumber(v) if spellId then --Ovale:Print("Add spell to score "..spellId) - Ovale.scoreSpell[spellId] = true + OvaleData.scoreSpell[spellId] = true else Ovale:Print("unknown spell "..v) end @@ -215,10 +220,10 @@ local function ParseScoreSpells(params) end local function ParseSpellList(name, params) - Ovale.buffSpellList[name] = {} + OvaleData.buffSpellList[name] = {} local i = 1 for v in string.gmatch(params, "(%d+)") do - Ovale.buffSpellList[name][i] = tonumber(v) + OvaleData.buffSpellList[name][i] = tonumber(v) i = i + 1 end end @@ -418,21 +423,10 @@ local function ParseAddIcon(params, text) return masterNode end -function Ovale:CompileInputs(text) - self.casesACocher = {} - self.listes = {} - self.defaultListes = {} - self.defaultCheck = {} - - text = string.gsub(text, "AddListItem%s*%(%s*(%w+)%s+(%w+)%s+\"(.-)\"%s*(.-)%s*%)", ParseAddListItem) - text = string.gsub(text, "AddCheckBox%s*%(%s*(%w+)%s+\"(.-)\"%s*(.-)%s*%)", ParseAddCheckBox) - return text -end - local function ParseCanStopChannelling(text) local spellId = tonumber(text) if spellId then - Ovale:GetSpellInfo(spellId).canStopChannelling = true + OvaleData:GetSpellInfo(spellId).canStopChannelling = true else Ovale:Print("CanStopChannelling with unknown spell "..spellId) end @@ -440,7 +434,7 @@ local function ParseCanStopChannelling(text) end local function ParseSpellName(text) - local spell = Ovale:GetSpellInfoOrNil(text) + local spell = OvaleData:GetSpellInfoOrNil(text) if (spell) then return '"'..spell..'"' else @@ -452,10 +446,21 @@ end local function ParseL(text) return '"'..L[text]..'"' end +--</private-static-methods> -function Ovale:Compile(text) - self.compileOnItems = false - self.bug = false +--<public-static-methods> +function OvaleCompile:CompileInputs(text) + Ovale.casesACocher = {} + Ovale.listes = {} + + text = string.gsub(text, "AddListItem%s*%(%s*(%w+)%s+(%w+)%s+\"(.-)\"%s*(.-)%s*%)", ParseAddListItem) + text = string.gsub(text, "AddCheckBox%s*%(%s*(%w+)%s+\"(.-)\"%s*(.-)%s*%)", ParseAddCheckBox) + return text +end + +function OvaleCompile:Compile(text) + Ovale.compileOnItems = false + Ovale.bug = false node = {} defines = {} @@ -476,7 +481,7 @@ function Ovale:Compile(text) text = string.gsub(text, "L%s*%(%s*(%w+)%s*%)", ParseL) -- Options diverses - Ovale:ResetSpellInfo() + OvaleData:ResetSpellInfo() text = string.gsub(text, "CanStopChannelling%s*%(%s*(%w+)%s*%)", ParseCanStopChannelling) text = string.gsub(text, "SpellAddBuff%s*%((.-)%)", ParseSpellAddBuff) text = string.gsub(text, "SpellAddDebuff%s*%((.-)%)", ParseSpellAddDebuff) @@ -511,7 +516,7 @@ function Ovale:Compile(text) return masterNodes end -function Ovale:DebugNode(node) +function OvaleCompile:DebugNode(node) local text if (not node) then return "#nil" @@ -557,4 +562,5 @@ function Ovale:DebugNode(node) end return text -end \ No newline at end of file +end +--</public-static-methods> diff --git a/OvaleCondition.lua b/OvaleCondition.lua new file mode 100644 index 0000000..3c4cd50 --- /dev/null +++ b/OvaleCondition.lua @@ -0,0 +1,1175 @@ +OvaleCondition = {} + +--<private-static-properties> + +local LBCT = LibStub("LibBabble-CreatureType-3.0"):GetLookupTable() +local LRC = LibStub("LibRangeCheck-2.0", true) +local runes = {} +local runesCD = {} + +local runeType = +{ + blood = 1, + unholy = 2, + frost = 3, + death = 4 +} + +local totemType = +{ + ghoul = 1, + fire = 1, + earth = 2, + water = 3, + air = 4 +} + +local lastSaved = {} +local savedHealth = {} +local targetGUID = {} +local lastSPD = {} + +--</private-static-properties> + +--<private-static-methods> +local function isDebuffInList(list) + local i=1; + while (true) do + local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellId = UnitDebuff("player", i); + if (not name) then + break + end + if (list[spellId]) then + return true + end + i = i +1 + end + return false +end + +local function avecHate(temps, hate) + if not temps then + temps = 0 + end + if (not hate) then + return temps + elseif (hate == "spell") then + return temps/OvaleAura.spellHaste + elseif (hate == "melee") then + return temps/OvaleAura.meleeHaste + else + return temps + end +end + +local function compare(a, comparison, b) + if (comparison == "more") then + if (not b or (a~=nil and a>b)) then + return 0 + else + return nil + end + elseif comparison == "equal" then + if b == a then + return 0 + else + return nil + end + else + if (not a or (b~=nil and a<b)) then + return 0 + else + return nil + end + end +end + +local function testbool(a, condition) + if (condition == "yes" or not condition) then + if (a) then + return 0 + else + return nil + end + else + if (not a) then + return 0 + else + return nil + end + end +end + +local function getTarget(condition) + if (not condition) then + return "player" + elseif condition == "target" then + return OvaleCondition.defaultTarget + else + return condition + end +end + +local function addTime(time1, duration) + if not time1 then + return nil + else + return time1 + duration + end +end + +--Return time2-time1 +local function diffTime(time1, time2) + if not time1 then + return 0 + end + if not time2 then + return nil + end + return time2 - time1 +end + +local function addOrSubTime(time1, operator, duration) + if operator == "more" then + return addTime(time1, -duration) + else + return addTime(time1, duration) + end +end + +local function nilstring(text) + if text == nil then + return "nil" + else + return text + end +end + +-- Get the expiration time of a debuff +-- that can be on any unit except the target +-- Returns the first to expires, the last to expires +-- Returns nil if the debuff is not present +local function getOtherAura(spellId, suppTime) + return OvaleState:GetExpirationTimeOnAnyTarget(spellId) +end + +local function GetRune(condition) + local nombre = 0 + local nombreCD = 0 + local maxCD = nil + + for i=1,4 do + runes[i] = 0 + runesCD[i] = 0 + end + + local k=1 + while true do + local type = runeType[condition[k*2-1]] + if not type then + break + end + local howMany = condition[k*2] + runes[type] = runes[type] + howMany + k = k + 1 + end + + for i=1,6 do + local rune = OvaleState.state.rune[i] + if rune then + if runes[rune.type] > 0 then + runes[rune.type] = runes[rune.type] - 1 + if rune.cd > runesCD[rune.type] then + runesCD[rune.type] = rune.cd + end + elseif rune.cd < runesCD[rune.type] then + runesCD[rune.type] = rune.cd + end + end + end + + if not condition.nodeath then + for i=1,6 do + local rune = OvaleState.state.rune[i] + if rune and rune.type == 4 then + for j=1,3 do + if runes[j]>0 then + runes[j] = runes[j] - 1 + if rune.cd > runesCD[j] then + runesCD[j] = rune.cd + end + break + elseif rune.cd < runesCD[j] then + runesCD[j] = rune.cd + break + end + end + end + end + end + + for i=1,4 do + if runes[i]> 0 then + return nil + end + if not maxCD or runesCD[i]>maxCD then + maxCD = runesCD[i] + end + end + return maxCD +end + +local lastEnergyValue = nil +local lastEnergyTime + +local function GetManaAndRate(withBerserker) + local _,className = UnitClass("player") + local current = OvaleState.state.mana + if current~=lastEnergyValue then + lastEnergyValue = current + lastEnergyTime = OvaleState.currentTime + end + + local rate + + if className == "ROGUE" or (className == "DRUID" and GetShapeshiftForm(true) == 3) then + rate = 10 * OvaleAura.meleeHaste + if (className == "ROGUE") then + local rush = OvaleState:GetAura("player", 13750) + if rush and rush.stacks>0 then + rate = rate * 2 + end + elseif withBerserker then + local berserk = OvaleState:GetAura("player", 50334) + if berserk and berserk.stacks>0 then + mana = mana/2 + end + end + elseif className == "HUNTER" then + rate = 4 * OvaleAura.meleeHaste + else + rate = 0 + end + + return lastEnergyValue, lastEnergyTime, rate +end + +local function GetManaTime(mana, withBerserker) + local lastEnergyValue, lastEnergyTime, rate = GetManaAndRate(withBerserker) + + if rate > 0 then + local limit = math.ceil((mana - lastEnergyValue) / rate + lastEnergyTime) + return limit + else + if OvaleState.state.mana>=mana then + return OvaleState.currentTime-1 + else + return nil + end + end +end + + +-- Recherche un aura sur la cible et récupère sa durée et le nombre de stacks +-- return start, ending, stacks +local function GetTargetAura(condition, filter, target) + if (not target) then + target=condition.target + if (not target) then + target="target" + end + end + local stacks = condition.stacks + if not stacks then + stacks = 1 + end + local spellId = condition[1] + + local mine = (condition.mine == 1) + + local aura + if type(spellId) == "number" then + aura = OvaleState:GetAura(target, spellId, mine) + elseif OvaleData.buffSpellList[spellId] then + for k,v in pairs(OvaleData.buffSpellList[spellId]) do + local newAura = OvaleState:GetAura(target, v, mine) + if newAura and (not aura or newAura.stacks>aura.stacks) then + aura = newAura + end + end + elseif spellId == "Magic" or spellId == "Disease" or spellId=="Curse" or spellId=="Poison" then + aura = OvaleState:GetAura(target, spellId, mine) + else + Ovale:Print("ERROR: unknown buff "..spellId) + Ovale.bug = true + return 0,0 + end + + if not aura then + return 0,0 + end + + if Ovale.trace then + Ovale:Print("GetTargetAura = start=".. nilstring(aura.start) .. " end="..nilstring(aura.ending).." stacks=" ..nilstring(aura.stacks).."/"..stacks) + end + + if (not condition.mine or (aura.mine and condition.mine==1) or (not aura.mine and condition.mine==0)) and aura.stacks>=stacks then + local ending + if condition.forceduration then + if OvaleData.spellInfo[spellId] and OvaleData.spellInfo[spellId].duration then + ending = aura.start + OvaleData.spellInfo[spellId].duration + else + ending = aura.start + condition.forceduration + end + else + ending = aura.ending + end + return aura.start, ending + else + return 0,0 + end +end + +local function getTargetDead(target) + local second = math.floor(OvaleState.maintenant) + if targetGUID[target] ~=UnitGUID(target) then + lastSaved[target] = nil + targetGUID[target] = UnitGUID(target) + savedHealth[target] = {} + end + local newHealth = UnitHealth(target) + if newHealth then + Ovale:Log("newHealth = " .. newHealth) + end + if UnitHealthMax(target)==1 then + Ovale:Log("Dummy, return in the future") + return nil + end + if second~=lastSaved[target] and targetGUID[target] then + lastSaved[target] = second + local mod10 = second % 10 + local prevHealth = savedHealth[target][mod10] + savedHealth[target][mod10] = newHealth + if prevHealth and prevHealth>newHealth then + lastSPD[target] = 10/(prevHealth-newHealth) + if lastSPD[target] > 0 then + Ovale:Log("dps = " .. (1/lastSPD[target])) + end + end + end + if not lastSPD[target] or lastSPD[target]<=0 then + return nil + end + -- Rough estimation + local duration = newHealth * lastSPD[target] + if duration < 10000 then + return OvaleState.maintenant + duration + else + return nil + end +end +--</private-static-methods> + +--<public-static-properties> +OvaleCondition.conditions= +{ + -- Test if a white hit just occured + -- 1 : maximum time after a white hit + -- Not useful anymore. No widely used spell reset swing timer anyway + --[[AfterWhiteHit = function(condition) + local debut = OvaleSwing.starttime + local fin = OvaleSwing.duration + debut + local maintenant = GetTime() + if (maintenant-debut<condition[1]) then + return 0 + elseif (maintenant<fin-0.1) then + return fin-maintenant + else + return 0.1 + end + end,]] + -- Test how many armor set parts are equiped by the player + -- 1 : set number + -- 2 : "more" or "less" + -- 3 : limit + ArmorSetParts = function(condition) + local nombre = 0 + if OvaleEquipement.nombre[condition[1]] then + nombre = OvaleEquipement.nombre[condition[1]] + end + return compare(nombre, condition[2], condition[3]) + end, + attackPower = function(condition) + local base, posBuff, negBuff = UnitAttackPower("player") + return base + posBuff + negBuff, 0, 0 + end, + BuffDuration = function(condition) + --local name, rank, icon, count, debuffType, duration = UnitBuff("player", OvaleData:GetSpellInfoOrNil(condition[1])) + --if not name then +-- return nil + -- end + local start, ending = GetTargetAura(condition, "HELPFUL", getTarget(condition.target)) + return compare(diffTime(start, ending), condition[2], condition[3]) + end, + -- Test if a buff will expire on the player after a given time + -- 1 : buff spell id + -- 2 : expiration time + BuffExpires = function(condition) + local start, ending = GetTargetAura(condition, "HELPFUL", getTarget(condition.target)) + local timeBefore = avecHate(condition[2], condition.haste) + if Ovale.trace then + Ovale:Print("timeBefore = " .. nilstring(timeBefore)) + Ovale:Print("start = " .. nilstring(ending)) + end + return addTime(ending, -timeBefore) + end, + buffExpires = function(condition) + local start, ending = GetTargetAura(condition, "HELPFUL", getTarget(condition.target)) + if ending then + return ending - start, start, -1 + else + return nil + end + end, + -- Test if a time has elapsed since the last buff gain + -- 1 : buff spell id + -- 2 : time since the buff gain + BuffGain = function(condition) + local spellId = condition[1] + local target = getTarget(condition.target) + if spellId then + local aura = OvaleState:GetAura(target,spellId) + if not aura then + return 0 + end + local timeGain = aura.gain + if not timeGain then + timeGain = 0 + end + + return timeGain + condition[2] + end + return 0 + end, + -- Test if a buff is active + -- 1 : the buff spell id + -- stacks : minimum number of stacks + BuffPresent = function(condition) + local start, ending = GetTargetAura(condition, "HELPFUL", getTarget(condition.target)) + local timeBefore = avecHate(condition[2], condition.haste) + return start, addTime(ending, -timeBefore) + end, + BuffStealable = function(condition) + local i = 1 + local stealable = false + local target = getTarget(condition.target) + while true do + local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable = UnitBuff(target, i) + if not name then + break + end + if isStealable then + stealable = true + break + end + i = i + 1 + end + return testbool(stealable, condition[1]) + end, + Casting = function(condition) + if OvaleState.currentSpellId == condition[1] then + return OvaleState.startCast, OvaleState.endCast + else + return nil + end + end, + CastTime = function(condition) + local name, rank, icon, cost, isFunnel, powerType, castTime = OvaleData:GetSpellInfoOrNil(condition[1]) + if Ovale.trace then + Ovale:Print("castTime/1000 = " .. (castTime/1000) .. " " .. condition[2] .. " " .. condition[3]) + end + return compare(castTime/1000, condition[2], condition[3]) + end, + castTime = function(condition) + local name, rank, icon, cost, isFunnel, powerType, castTime = OvaleData:GetSpellInfoOrNil(condition[1]) + return castTime/1000, 0, 0 + end, + -- Test if a list of checkboxes is off + -- 1,... : the checkboxes names + CheckBoxOff = function(condition) + for k,v in pairs(condition) do + if (Ovale:IsChecked(v)) then + return nil + end + end + return 0 + end, + -- Test if a list of checkboxes is on + -- 1,... : the checkboxes names + CheckBoxOn = function(condition) + for k,v in pairs(condition) do + if (not Ovale:IsChecked(v)) then + return nil + end + end + return 0 + end, + Class = function(condition) + local loc, noloc = UnitClass(getTarget(condition.target)) + return testbool(noloc == condition[1], condition[2]) + end, + -- Test the target classification + -- 1 : normal, elite, or worldboss + Classification = function(condition) + local classification + local target = getTarget(condition.target) + if UnitLevel(target)==-1 then + classification = "worldboss" + else + classification = UnitClassification(target); + if (classification == "rareelite") then + classification = "elite" + elseif (classification == "rare") then + classification = "normal" + end + end + + if (condition[1]==classification) then + return 0 + else + return nil + end + end, + -- Test how many combo points a feral druid or a rogue has + -- 1 : "less" or "more" + -- 2 : the limit + ComboPoints = function(condition) + local points = OvaleState.state.combo + return compare(points, condition[1], condition[2]) + end, + comboPoints = function(condition) + return OvaleState.state.combo, 0, 0 + end, + Counter = function(condition) + return compare(OvaleState:GetCounterValue(condition[1]), condition[2], condition[3]) + end, + counter = function(condition) + return OvaleState:GetCounterValue(condition[1]), 0, 0 + end, + CreatureFamily = function(condition) + return testbool(UnitCreatureFamily(getTarget(condition.target)) == LBCT[condition[1]], condition[2]) + end, + CreatureType = function(condition) + for _,v in pairs(condition) do + if (UnitCreatureType(getTarget(condition.target)) == LBCT[v]) then + return 0 + end + end + return nil + end, + damage = function(condition) + local spellInfo = OvaleData:GetSpellInfo(condition[1]) + if not spellInfo then + return nil + end + local ret = (spellInfo.base or 0) + if spellInfo.bonuscp then + ret = ret + (OvaleState.state.combo * spellInfo.bonuscp) + end + if spellInfo.bonusholy then + ret = ret + (OvaleState.state.holy * spellInfo.bonusholy) + end + if spellInfo.bonusap then + ret = ret + spellInfo.bonusap * UnitAttackPower("player") + end + if spellInfo.bonusapcp then + ret = ret + spellInfo.bonusapcp * UnitAttackPower("player") * OvaleState.state.combo + end + if spellInfo.bonusapholy then + ret = ret + spellInfo.bonusapholy * UnitAttackPower("player") * OvaleState.state.holy + end + if spellInfo.bonussp then + ret = ret + spellInfo.bonussp * GetSpellBonusDamage(2) + end + if spellInfo.bonusspholy then + ret = ret + spellInfo.bonusspholy * GetSpellBonusDamage(2) * OvaleState.state.holy + end + return ret * OvaleAura.damageMultiplier, 0, 0 + end, + damageMultiplier = function(condition) + return OvaleAura.damageMultiplier, 0, 0 + end, + DeadIn = function(condition) + local deadAt = getTargetDead(getTarget(condition.target)) + if condition[1] == "more" then + return 0, addTime(deadAt, -condition[2]) + else + return addTime(deadAt, -condition[2]), nil + end + end, + deadIn = function(condition) + return getTargetDead(getTarget(condition.target)), 0, -1 + end, + -- Test if a debuff will expire on the target after a given time, or if there is less than the + -- given number of stacks (if stackable) + -- 1 : buff spell id + -- 2 : expiration time + -- stacks : how many stacks + -- mine : 1 means that if the debuff is not ours, the debuff is ignored + DebuffExpires = function(condition) + local start, ending = GetTargetAura(condition, "HARMFUL", getTarget(condition.target)) + local tempsMax = avecHate(condition[2], condition.haste) + return addTime(ending, -tempsMax) + end, + debuffExpires = function(condition) + local start, ending = GetTargetAura(condition, "HARMFUL", getTarget(condition.target)) + if ending then + return ending - start, start, -1 + else + return nil + end + end, + DebuffPresent = function(condition) + local start, ending = GetTargetAura(condition, "HARMFUL", getTarget(condition.target)) + local timeBefore = avecHate(condition[2], condition.haste) + return start, addTime(ending, -timeBefore) + end, + Distance = function(condition) + if LRC then + local target = getTarget(condition.target) + local minRange, maxRange = LRC:GetRange(target) + if maxRange == nil or minRange == nil then + return nil + end + if condition[1] == "more" then + if condition[2]~=nil and maxRange>condition[2] then + return 0 + else + return nil + end + else + if condition[2]~=nil and minRange<condition[2] then + return 0 + else + return nil + end + end + end + end, + distance = function(condition) + if LRC then + return LRC:GetRange(getTarget(condition.target)) + else + return nil + end + end, + --Compare to eclipse power. <0 lunar, >0 solar + Eclipse = function(condition) + return compare(OvaleState.state.eclipse, condition[1], condition[2]) + end, + eclipse = function(condition) + return OvaleState.state.eclipse + end, + EffectiveMana = function(condition) + local limit = GetManaTime(condition[2], true) + if condition[1]=="more" then + return limit, nil + else + return 0,limit + end + end, + effectiveMana = function(condition) + return GetManaAndRate(true) + end, + EndCastTime = function(condition) + local name, rank, icon, cost, isFunnel, powerType, castTime = OvaleData:GetSpellInfoOrNil(condition[1]) + local actionCooldownStart, actionCooldownDuration, actionEnable = OvaleData:GetComputedSpellCD(condition[1]) + local startCast = actionCooldownStart + actionCooldownDuration + if startCast<OvaleState.currentTime then + startCast = OvaleState.currentTime + end + return startCast + castTime/1000 + end, + enemies = function(condition) + return OvaleEnemies:GetNumberOfEnemies(), 0, 0 + end, + Exists = function(condition) + return testbool(UnitExists(getTarget(condition.target)) == 1, condition[1]) + end, + Glyph = function(condition) + local present = false + for i = 1, GetNumGlyphSockets() do + local enabled, glypType, glyphTooltipIndex, glyphSpellID = GetGlyphSocketInfo(i) + if (glyphSpellID == condition[1]) then + present = true + break + end + end + return testbool(present, condition[2]) + end, + HasFullControl = function(condition) + return testbool(HasFullControl(), condition[1]) + end, + HasShield = function(condition) + local _,_,id = string.find(GetInventoryItemLink("player",GetInventorySlotInfo("SecondaryHandSlot")) or "","(item:%d+:%d+:%d+:%d+)") + if (not id) then + return testbool(false, condition[1]) + end + + local _,_,_,_,_,_,_,_,itemLoc = GetItemInfo(id) + return testbool(itemLoc=="INVTYPE_SHIELD", condition[1]) + end, + HolyPower = function(condition) + return compare(OvaleState.state.holy, condition[1], condition[2]) + end, + holyPower = function(condition) + return OvaleState.state.holy, 0, 0 + end, + InCombat = function(condition) + return testbool(Ovale.enCombat, condition[1]) + end, + InRange = function(condition) + local spellName = GetSpellInfo(condition[1]) + return testbool(IsSpellInRange(spellName,getTarget(condition.target))==1,condition[2]) + end, + item = function(condition) + local itemId = element.params[1] + local actionCooldownStart, actionCooldownDuration, actionEnable = GetItemCooldown(itemId) + return actionCooldownDuration, actionCooldownStart, -1 + end, + ItemCount = function(condition) + if condition.charges == 1 then + return compare(GetItemCount(condition[1], false, true), condition[2], condition[3]) + else + return compare(GetItemCount(condition[1]), condition[2], condition[3]) + end + end, + itemCount = function(condition) + if condition.charges == 1 then + return GetItemCount(condition[1], false, true), 0, 0 + else + return GetItemCount(condition[1]), 0, 0 + end + end, + IsCasting = function(condition) + local casting + local target = getTarget(condition.target) + local spellId = condition.spell + if not spellId then + return testbool(UnitCastingInfo(target) or UnitChannelInfo(target), condition[1]) + elseif type(spellId) == "number" then + local spellName = GetSpellInfo(spellId) + return testbool(UnitCastingInfo(target)==spellName or UnitChannelInfo(target) == spellName, condition[1]) + elseif OvaleData.buffSpellList[spellId] then + local castSpellName = UnitCastingInfo(target) or UnitChannelInfo(target) + local found = false + for k,v in pairs(OvaleData.buffSpellList[spellId]) do + local spellName = GetSpellInfo(v) + if spellName == castSpellName then + found = true + break + end + end + return testbool(found, condition[1]) + elseif spellId == "harmful" then + local castSpellName = UnitCastingInfo(target) or UnitChannelInfo(target) + return testbool(castSpellName and IsHarmfulSpell(castSpellName), condition[1]) + elseif spellId == "helpful" then + local castSpellName = UnitCastingInfo(target) or UnitChannelInfo(target) + return testbool(castSpellName and IsHelpfulSpell(castSpellName), condition[1]) + end + end, + IsFeared = function(condition) + local fearSpellList = OvaleData:GetFearSpellList() + return testbool(not HasFullControl() and isDebuffInList(fearSpellList), condition[1]) + end, + IsFriend = function(condition) + return testbool(UnitIsFriend("player", getTarget(condition.target)), condition[1]) + end, + IsIncapacitated = function(condition) + local incapacitateSpellList = OvaleData:GetIncapacitateSpellList() + return testbool(not HasFullControl() and isDebuffInList(incapacitateSpellList), condition[1]) + end, + IsInterruptible = function(condition) + local target = getTarget(condition.target) + local spell, rank, name, icon, start, ending, isTradeSkill, castID, protected = UnitCastingInfo(target) + if not spell then + spell, rank, name, icon, start, ending, isTradeSkill, protected = UnitChannelInfo(target) + end + return testbool(protected ~= nil and not protected, condition[1]) + end, + IsRooted = function(condition) + local rootSpellList = OvaleData:GetRootSpellList() + return testbool(isDebuffInList(rootSpellList), condition[1]) + end, + IsStunned = function(condition) + local stunSpellList = OvaleData:GetStunSpellList() + return testbool(not HasFullControl() and isDebuffInList(stunSpellList), condition[1]) + end, + LastSpellDamage = function(condition) + local spellId = condition[1] + if not OvaleSpellDamage:Get(spellId) then + return nil + end + return compare(OvaleSpellDamage:Get(spellId), condition[2], condition[3]) + end, + lastSpellDamage = function(condition) + return OvaleSpellDamage:Get(condition[1]) + end, + lastSpellDamageMultiplier = function(condition) + return OvaleFuture.lastSpellDM[condition[1]], 0, 0 + end, + lastSpellAttackPower = function(condition) + return OvaleFuture.lastSpellAP[condition[1]], 0, 0 + end, + lastSpellSpellPower = function(condition) + return OvaleFuture.lastSpellSP[condition[1]], 0, 0 + end, + LastSwing = function(condition) + local ret = OvaleSwing:GetLast(condition[1]) + if condition[2] and ret then + ret = ret + condition[2] + end + return 0, ret + end, + lastSwing = function(condition) + return OvaleState.currentTime - OvaleSwing:GetLast(condition[1]), 0, 1 + end, + -- Compare with the player level + -- 1 : "less" or "more" + -- 2 : the limit + Level = function(condition) + return compare(UnitLevel(getTarget(condition.target)), condition[1], condition[2]) + end, + level = function(condition) + return UnitLevel(condition.target) + end, + Life = function(condition) + local target = getTarget(condition.target) + return compare(UnitHealth(target), condition[1], condition[2]) + end, + life = function(condition) + local target = getTarget(condition.target) + return UnitHealth(target), 0, 0 + end, + LifeMissing = function(condition) + local target = getTarget(condition.target) + return compare(UnitHealthMax(target)-UnitHealth(target), condition[1], condition[2]) + end, + lifeMissing = function(condition) + local target = getTarget(condition.target) + return UnitHealthMax(target)-UnitHealth(target), 0, 0 + end, + -- Test if the player life is bellow/above a given value in percent + -- 1 : "less" or "more" + -- 2 : the limit, in percent + LifePercent = function(condition) + local target = getTarget(condition.target) + if UnitHealthMax(target) == nil or UnitHealthMax(target) == 0 then + return nil + end + return compare(UnitHealth(target)/UnitHealthMax(target), condition[1], condition[2]/100) + end, + lifePercent = function(condition) + local target = getTarget(condition.target) + if UnitHealthMax(target) == nil or UnitHealthMax(target) == 0 then + return nil + end + return 100 * UnitHealth(target)/UnitHealthMax(target), 0, 0 + end, + -- Test if a list item is selected + -- 1 : the list name + -- 2 : the item name + List = function(condition) + if (condition[1]) then + if (Ovale:GetListValue(condition[1]) == condition[2]) then + return 0 + end + end + return nil + end, + -- Test if the player mana is above/bellow a given value + -- 1 : "less" or "more" + -- 2 : the mana/energy/rage... limit + Mana = function(condition) + local target = getTarget(condition.target) + if target == "player" then + local limit = GetManaTime(condition[2], false) + if condition[1]=="more" then + return limit, nil + else + return 0,limit + end + else + return compare(UnitPower(target), condition[1], condition[2]) + end + end, + mana = function(condition) + return GetManaAndRate(false) + end, + ManaPercent = function(condition) + local target = getTarget(condition.target) + if UnitPowerMax(target) == 0 then + return nil + end + return compare(UnitPower(target)/UnitPowerMax(target), condition[1], condition[2]/100) + end, + manaPercent = function(condition) + local target = getTarget(condition.target) + if UnitPowerMax(target) == 0 then + return nil + end + local value, t, rate = GetManaAndRate(false) + local conversion = 100/UnitPowerMax(target) + return value * conversion, t, rate * conversion + end, + MaxHealth = function(condition) + local target = getTarget(condition.target) + return compare(UnitMaxHealth(target), condition[1], condition[2]) + end, + maxHealth = function(condition) + return UnitMaxHealth(getTarget(condition.target)), 0, 0 + end, + maxMana = function(condition) + return UnitPowerMax(getTarget(condition.target)), 0, 0 + end, + NextSwing = function(condition) + local ret = OvaleSwing:GetNext(condition[1]) + if condition[2] and ret then + ret = ret - condition[2] + end + return ret + end, + nextSwing = function(condition) + return OvaleSwing:GetNext(condition[1]) - OvaleState.currentTime, 0, -1 + end, + nextTick = function(condition) + local start, ending = GetTargetAura(condition, "HARMFUL", getTarget(condition.target)) + local si = OvaleData.spellInfo[condition[1]] + if not si or not si.duration then + return nil + end + local ticks = floor(OvaleAura.spellHaste * (si.duration/(si.tick or 3)) + 0.5) + local tickLength = (ending - start) / ticks + local tickTime = start + tickLength + for i=1,ticks do + if OvaleState.currentTime<=tickTime then + break + end + tickTime = tickTime + tickLength + end + return tickTime, 0, -1 + end, + OtherDebuffExpires = function(condition) + local minTime, maxTime = getOtherAura(condition[1], condition[3]) + if minTime then + local timeBefore = condition[2] or 0 + return minTime - timeBefore, nil + end + return 0, nil + end, + OtherDebuffPresent = function(condition) + local minTime, maxTime = getOtherAura(condition[1], condition[3]) + if maxTime and maxTime>0 then + local timeBefore = condition[2] or 0 + return 0, addTime(maxTime, -timeBefore) + end + return nil + end, + OtherAuraExpires = OtherDebuffExpires, + OtherAuraPresent = OtherDebuffPresent, + otherAura = function(condition) + local minTime, maxTime = getOtherAura(condition[1]) + return 0, maxTime, -1 + end, + Present = function(condition) + local present = UnitExists(getTarget(condition.target)) and not UnitIsDead(getTarget(condition.target)) + return testbool(present, condition[1]) + end, + -- Test if any player pet is present (or not) + -- 1 : "yes" or "no" + PetPresent = function(condition) + local present = UnitExists("pet") and not UnitIsDead("pet") + return testbool(present, condition[1]) + end, + -- Test the target level difference with the player + -- 1 : "less" or "more" + -- 2 : [target level]-[player level] limit + RelativeLevel = function(condition) + local difference + local target = getTarget(condition.target) + if UnitLevel(target) == -1 then + difference = 3 + else + difference = UnitLevel(target) - UnitLevel("player") + end + + return compare(difference, condition[1], condition[2]) + end, + remainingCastTime = function(condition) + local name, nameSubtext, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible = UnitCastingInfo(getTarget(condition.target)) + if not endTime then + return nil + end + return 0, endTime/1000, -1 + end, + Runes = function(condition) + return GetRune(condition) + end, + runes = function(condition) + local ret = GetRune(condition) + if not ret then + return nil + end + if ret < OvaleState.maintenant then + ret = OvaleState.maintenant + end + return 0, ret, -1 + end, + SoulShards = function(condition) + return compare(OvaleState.state.shard, condition[1], condition[2]) + end, + soulShards = function(condition) + return OvaleState.state.shard + end, + Speed = function(condition) + return compare(GetUnitSpeed(getTarget(condition.target))*100/7, condition[1], condition[2]) + end, + speed = function(condition) + return GetUnitSpeed(getTarget(condition.target))*100/7 + end, + spell = function(condition) + local actionCooldownStart, actionCooldownDuration, actionEnable = OvaleData:GetComputedSpellCD(condition[1]) + return actionCooldownDuration, actionCooldownStart, -1 + end, + spellPower = function(condition) + return GetSpellBonusDamage(2), 0, 0 + end, + -- Test if the player is in a given stance + -- 1 : the stance + Stance = function(condition) + if (GetShapeshiftForm(true) == condition[1]) then + return 0 + else + return nil + end + end, + Stealthed = function(condition) + return testbool(IsStealthed(), condition[1]) + end, + -- Test how many talent points has been spent in a talent + -- 1 : the talent identifier (use /script print(OvaleData.talentNameToId["Talent name"]) to retreive) + -- 2 : "more" or "less" + -- 3 : the limit + TalentPoints = function(condition) + return compare(OvaleData:GetTalentPoints(condition[1]), condition[2], condition[3]) + end, + talentPoints = function(condition) + return OvaleData:GetTalentPoints(condition[1]), 0, 0 + end, + -- Test if the target's target is the player (or is not) + -- 1 : "yes" (it should be the player) or "no" + TargetIsPlayer = function(condition) + return testbool(UnitIsUnit("player",getTarget(condition.target).."target"), condition[1]) + end, + Threat = function(condition) + local isTanking, status, threatpct = UnitDetailedThreatSituation("player", getTarget(condition.target)) + return compare(threatpct, condition[1], condition[2]) + end, + threat = function(condition) + local isTanking, status, threatpct = UnitDetailedThreatSituation("player", getTarget(condition.target)) + return threatpct + end, + TimeInCombat = function(condition) + if not Ovale.combatStartTime then + return nil + elseif condition[1] == "more" then + return Ovale.combatStartTime + condition[2] + else + return 0, Ovale.combatStartTime + condition[2] + end + end, + timeInCombat = function(condition) + return OvaleState.maintenant - Ovale.combatStartTime, OvaleState.maintenant, 1 + end, + timeToDie = function(condition) + return 0, getTargetDead(getTarget(condition.target)), -1 + end, + timeWithHaste = function(condition) + return avecHate(condition[1], "spell"),0,0 + end, + TotemExpires = function(condition) + if type(condition[1]) ~= "number" then + condition[1] = totemType[condition[1]] + end + + local haveTotem, totemName, startTime, duration = GetTotemInfo(condition[1]) + if not startTime then + return 0 + end + if (condition.totem and OvaleData:GetSpellInfoOrNil(condition.totem)~=totemName) then + return 0 + end + return addTime(startTime + duration, -(condition[2] or 0)) + end, + TotemPresent = function(condition) + if type(condition[1]) ~= "number" then + condition[1] = totemType[condition[1]] + end + + local haveTotem, totemName, startTime, duration = GetTotemInfo(condition[1]) + if not startTime then + return nil + end + if (condition.totem and OvaleData:GetSpellInfoOrNil(condition.totem)~=totemName) then + return nil + end + return startTime, startTime + duration + end, + Tracking = function(condition) + local what = OvaleData:GetSpellInfoOrNil(condition[1]) + local numTrackingTypes = GetNumTrackingTypes() + local present = false + for i=1,numTrackingTypes do + local name, texture, active = GetTrackingInfo(i) + if name == what then + present = (active == 1) + break + end + end + return testbool(present, condition[2]) + end, + WeaponEnchantExpires = function(condition) + local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo() + if (condition[1] == "mainhand") then + if (not hasMainHandEnchant) then + return 0 + end + mainHandExpiration = mainHandExpiration/1000 + if ((condition[2] or 0) >= mainHandExpiration) then + return 0 + else + return OvaleState.maintenant + mainHandExpiration - condition[2] + end + else + if (not hasOffHandEnchant) then + return 0 + end + offHandExpiration = offHandExpiration/1000 + if ((condition[2] or 0) >= offHandExpiration) then + return 0 + else + return OvaleState.maintenant + offHandExpiration - condition[2] + end + end + end, +} + +OvaleCondition.conditions.health = OvaleCondition.conditions.life +OvaleCondition.conditions.Health = OvaleCondition.conditions.Life +OvaleCondition.conditions.healthPercent = OvaleCondition.conditions.lifePercent +OvaleCondition.conditions.HealthPercent = OvaleCondition.conditions.LifePercent +OvaleCondition.conditions.HealthMissing = OvaleCondition.conditions.LifeMissing +OvaleCondition.defaultTarget = "target" + +--</public-static-properties> diff --git a/OvaleData.lua b/OvaleData.lua new file mode 100644 index 0000000..65ec761 --- /dev/null +++ b/OvaleData.lua @@ -0,0 +1,427 @@ +OvaleData = LibStub("AceAddon-3.0"):NewAddon("OvaleData", "AceEvent-3.0") + +--<public-static-properties> +OvaleData.spellList = {} +OvaleData.firstInit = false +OvaleData.className = nil +OvaleData.spellInfo = {} +--allows to fill the player talent tables on first use +OvaleData.listeTalentsRemplie = false +--key: talentId / value: points in this talent +OvaleData.pointsTalent = {} +--key: talentId / value: talent name (not used) +OvaleData.talentIdToName = {} +--key: talent name / value: talent id +OvaleData.talentNameToId = {} +--spell info from the current script (by spellId) +OvaleData.spellInfo = {} +--spells that count for scoring +OvaleData.scoreSpell = {} + +-- List haste buff that does not appear in the character sheet and that are not raid wide buffs +OvaleData.selfHasteBuff = +{ + [53657] = 9, -- Judgement of the pure + [49016] = 20 -- Unholy Frenzy +} + +-- List temporary damage multiplier +OvaleData.selfDamageBuff = +{ + [5217] = 1.15, -- Tiger's fury + [57933] = 1.15 -- Tricks of the trade +} + +OvaleData.buffSpellList = +{ + fear = + { + 5782, -- Fear + 5484, -- Howl of terror + 5246, -- Intimidating Shout + 8122, -- Psychic scream + }, + root = + { + 23694, -- Improved Hamstring + 339, -- Entangling Roots + 122, -- Frost Nova + 47168, -- Improved Wing Clip + }, + incapacitate = + { + 6770, -- Sap + 12540, -- Gouge + 20066, -- Repentance + }, + stun = + { + 5211, -- Bash + 44415, -- Blackout + 6409, -- Cheap Shot + 22427, -- Concussion Blow + 853, -- Hammer of Justice + 408, -- Kidney Shot + 46968, -- Shockwave + }, + strengthagility= + { + 6673, -- Battle Shout + 8076, -- Strength of Earth + 57330, -- Horn of Winter + 93435 --Roar of Courage (Cat, Spirit Beast) + }, + stamina = + { + 21562, -- Fortitude TODO: vérifier + 469, -- Commanding Shout + 6307, -- Blood Pact + 90364 -- Qiraji Fortitude + }, + lowerarmor= + { + 58567, -- Sunder Armor (x3) + 8647, -- Expose Armor + 91565, -- Faerie Fire (x3) + 35387, --Corrosive Spit (x3 Serpent) + 50498 --Tear Armor (x3 Raptor) + }, + magicaldamagetaken= + { + 65142, -- Ebon Plague + 60433, -- Earth and Moon + 93068, -- Master Poisoner + 1490, -- Curse of the Elements + 85547, -- Jinx 1 + 86105, -- Jinx 2 + 34889, --Fire Breath (Dragonhawk) + 24844 --Lightning Breath (Wind serpent) + }, + magicalcrittaken= + { + 17800, -- Shadow and Flame + 22959 -- Critical Mass + }, + physicaldamagetaken= + { + 30069, -- Blood Frenzy (rank 1) + 30070, -- Blood Frenzy (rank 2) + 81327, -- Brittle Bones (rank 1) + 81328, -- Brittle Bones (rank 2) + 58684, -- Savage Combat (rank 1) + 58683, -- Savage Combat (rank 2) + 55749, -- Acid Spit (Worm) + 50518, -- Ravage (Ravager) + }, + lowerphysicaldamage= + { + 99, -- Demoralizing Roar + 702, -- Curse of Weakness + 1160, -- Demoralizing Shout + 26017, -- Vindication + 81130, -- Scarlet Fever + 50256, --Demoralizing Roar (Bear) + 24423, -- Demoralizing Screech (Carrion Bird) + }, + meleeslow= + { + 55095, --Icy Touch + 58179, --Infected Wounds rank 1 + 58180, --Infected Wounds rank 2 + 68055, --Judgments of the just + 6343, --Thunderclap + 8042, --Earth Shock + 54404, --Dust Cloud (Tallstrider) + 90315, -- Tailspin (Fox) + }, + castslow = + { + 1714, --Curse of Tongues + 58604, --Lava Breath (Core Hound) + 50274, --Spore Cloud (Sporebat) + 5761, --Mind-numbing Poison + 73975, --Necrotic Strike + 31589 --Slow + }, + bleed= + { + 33876, --Mangle cat + 33878, --Mangle bear + 46856, -- Trauma rank 1 + 46857, -- Trauma rank 2 + 16511, --Hemorrhage + 50271, --Tendon Rip (Hyena) + 35290 --Gore (Boar) + }, + heroism= + { + 2825, --Bloodlust + 32182, --Heroism + 80353, --Time warp + 90355 -- Ancient Hysteria (Core Hound) + }, + meleehaste = + { + 8515, -- Windfury + 55610, -- Improved Icy Talons + 53290 -- Hunting Party + }, + spellhaste = + { + 24907, -- Moonkin aura + 2895, -- Wrath of Air Totem + 49868 -- Mind Quickening + }, + enrage = + { + 49016, -- Unholy Frenzy + 18499, -- Berserker Rage + 12292, -- Death Wish + 12880, -- Enrage (rank 1) + 14201, -- Enrage (rank 2) + 14202, -- Enrage (rank 3) + 5229, -- Enrage (Bear) + 52610, -- Savage Roar (Cat) + 76691, -- Vengeance (All Tank Specs) + }, + criticalstrike = + { + 51740, -- Elemental Oath + 51698, -- Honor Among Thieves (rank 1) + 51700, -- Honor Among Thieves (rank 2) + 51701, -- Honor Among Thieves (rank 3) + 17007, -- Leader of the Pack + 29801, -- Rampage + 24604, -- Furious Howl (Wolf) + 90309, -- Terrifying Roar (Devilsaur) + } +} +--</public-static-properties> + +--<private-static-properties> +local fearSpellList = nil +local stunSpellList = nil +local incapacitateSpellList = nil +local rootSpellList = nil +--</private-static-properties> + +--<public-static-methods> +function OvaleData:OnEnable() + self:FirstInit() + self:RegisterEvent("PLAYER_TALENT_UPDATE") + self:RegisterEvent("CHARACTER_POINTS_CHANGED") + self:RegisterEvent("SPELLS_CHANGED") +end + +function OvaleData:OnDisable() + self:UnregisterEvent("SPELLS_CHANGED") + self:UnregisterEvent("PLAYER_TALENT_UPDATE") + self:UnregisterEvent("CHARACTER_POINTS_CHANGED") +end + +function OvaleData:CHARACTER_POINTS_CHANGED() + self:RemplirListeTalents() +-- Ovale:Print("CHARACTER_POINTS_CHANGED") +end + +function OvaleData:PLAYER_TALENT_UPDATE() + self:RemplirListeTalents() +-- Ovale:Print("PLAYER_TALENT_UPDATE") +end + +--The user learnt a new spell +function OvaleData:SPELLS_CHANGED() + self:FillSpellList() + Ovale.needCompile = true +end + +function OvaleData:GetRootSpellList() + if rootSpellList then + return rootSpellList + end + rootSpellList = {} + for k, v in pairs(self.buffSpellList.fear) do + rootSpellList[v] = true + end + return rootSpellList +end + +function OvaleData:GetStunSpellList() + if stunSpellList then + return stunSpellList + end + stunSpellList = {} + for k, v in pairs(self.buffSpellList.stun) do + stunListList[v] = true + end + return stunSpellList +end + +function OvaleData:GetIncapacitateSpellList() + if incapacitateSpellList then + return incapacitateSpellList + end + incapacitateSpellList = {} + for k, v in pairs(self.buffSpellList.incapacitate) do + incapacitateSpellList[v] = true + end + return incapacitateSpellList +end + +function OvaleData:GetFearSpellList() + if fearSpellList then + return fearSpellList + end + fearSpellList = {} + for k, v in pairs(self.buffSpellList.fear) do + fearSpellList[v] = true + end + return fearSpellList +end + + +function OvaleData:GetSpellInfoOrNil(spell) + if (spell) then + return GetSpellInfo(spell) + else + return nil + end +end + +function OvaleData:FillSpellList() + self.spellList = {} + local book=BOOKTYPE_SPELL + while true do + local i=1 + while true do + local skillType, spellId = GetSpellBookItemInfo(i, book) + if not spellId then + break + end + if skillType~="FUTURESPELL" then + local spellName = GetSpellBookItemName(i, book) + self.spellList[spellId] = spellName + end + i = i + 1 + end + if book==BOOKTYPE_SPELL then + book = BOOKTYPE_PET + else + break + end + end +end + +function OvaleData:RemplirListeTalents() + local numTabs = GetNumTalentTabs(); + for t=1, numTabs do + local numTalents = GetNumTalents(t); + for i=1, numTalents do + local nameTalent, icon, tier, column, currRank, maxRank = GetTalentInfo(t,i); + local link = GetTalentLink(t,i) + if link then + local a, b, talentId = string.find(link, "talent:(%d+)"); + talentId = tonumber(talentId) + self.talentIdToName[talentId] = nameTalent + self.talentNameToId[nameTalent] = talentId + self.pointsTalent[talentId] = currRank + self.listeTalentsRemplie = true + Ovale.needCompile = true + end + end + end +end + +function OvaleData:FirstInit() + if self.firstInit then + return + end + + self.firstInit = true + + local playerClass, englishClass = UnitClass("player") + self.className = englishClass + + self:RemplirListeTalents() + self:FillSpellList() +end + +function OvaleData:GetTalentPoints(talentId) + if not self.listeTalentsRemplie then + self:RemplirListeTalents() + end + return self.pointsTalent[talentId] +end + +function OvaleData:GetSpellInfo(spellId) + if (not self.spellInfo[spellId]) then + self.spellInfo[spellId] = { aura = {player = {}, target = {}} } + end + return self.spellInfo[spellId] +end + +function OvaleData:ResetSpellInfo() + self.spellInfo = {} +end + +function OvaleData:GetGCD(spellId) + if spellId and self.spellInfo[spellId] then + if self.spellInfo[spellId].haste == "spell" then + local cd = self.spellInfo[spellId].gcd + if not cd then + cd = 1.5 + end + cd = cd / OvaleAura.spellHaste + if (cd<1) then + cd = 1 + end + return cd + elseif self.spellInfo[spellId].gcd then + return self.spellInfo[spellId].gcd + end + end + + -- Default value + if self.className == "ROGUE" or (self.className == "DRUID" and GetShapeshiftForm(true) == 3) then + return 1.0 + elseif self.className == "MAGE" or self.className == "WARLOCK" or self.className == "PRIEST" or + (self.className == "DRUID" and GetShapeshiftForm(true) ~= 1) then + local cd = 1.5 / OvaleAura.spellHaste + if (cd<1) then + cd = 1 + end + return cd + else + return 1.5 + end +end + + +--Compute the spell Cooldown +function OvaleData:GetComputedSpellCD(spellId) + local actionCooldownStart, actionCooldownDuration, actionEnable + local cd = OvaleState:GetCD(spellId) + if cd and cd.start then + actionCooldownStart = cd.start + actionCooldownDuration = cd.duration + actionEnable = cd.enable + else + actionCooldownStart, actionCooldownDuration, actionEnable = GetSpellCooldown(spellId) + -- Les chevaliers de la mort ont des infos fausses sur le CD quand ils n'ont plus les runes + -- On force à 1,5s ou 1s en présence impie + if self.className=="DEATHKNIGHT" and actionCooldownDuration==10 and + (not self.spellInfo[spellId] or self.spellInfo[spellId].cd~=10) then + local impie = GetSpellInfo(48265) + if impie and UnitBuff("player", impie) then + actionCooldownDuration=1 + else + actionCooldownDuration=1.5 + end + end + if self.spellInfo[spellId] and self.spellInfo[spellId].forcecd then + actionCooldownStart, actionCooldownDuration = GetSpellCooldown(self.spellInfo[spellId].forcecd) + end + end + return actionCooldownStart, actionCooldownDuration, actionEnable +end +--</public-static-methods> diff --git a/OvaleEnemies.lua b/OvaleEnemies.lua new file mode 100644 index 0000000..322f346 --- /dev/null +++ b/OvaleEnemies.lua @@ -0,0 +1,65 @@ +-- Gather information about ennemies + +OvaleEnemies = LibStub("AceAddon-3.0"):NewAddon("OvaleEnemies", "AceEvent-3.0") + +--<public-static-properties> +OvaleEnemies.numberOfEnemies = 0 +OvaleEnemies.enemies = {} +--</public-static-properties> + +--<public-static-methods> +-- Events +function OvaleEnemies:OnEnable() + self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + self:RegisterEvent("PLAYER_REGEN_DISABLED") +end + +function OvaleEnemies:OnDisable() + self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + self:UnregisterEvent("PLAYER_REGEN_DISABLED") +end + +function OvaleEnemies:COMBAT_LOG_EVENT_UNFILTERED(event, ...) + local time, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags = select(1, ...) + + if event == "UNIT_DIED" then + for k,v in pairs(self.enemies) do + if k==destGUID then + self.enemies[v] = nil + self.numberOfEnemies = self.numberOfEnemies - 1 + Ovale.refreshNeeded["player"] = true + --Ovale:Print("enemy die") + end + end + elseif sourceFlags and not self.enemies[sourceGUID] and bit.band(sourceFlags, COMBATLOG_OBJECT_REACTION_HOSTILE)>0 + and bit.band(sourceFlags, COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) > 0 and + destFlags and bit.band(destFlags, COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) == 0 then + self.enemies[sourceGUID] = true + --Ovale:Print("new ennemy source=".. sourceName) + self.numberOfEnemies = self.numberOfEnemies + 1 + Ovale.refreshNeeded["player"] = true + elseif destGUID and not self.enemies[destGUID] and bit.band(destFlags, COMBATLOG_OBJECT_REACTION_HOSTILE)>0 + and bit.band(destFlags, COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) > 0 and + sourceFlags and bit.band(sourceFlags, COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) == 0 then + self.enemies[destGUID] = true + --Ovale:Print("new ennemy dest=".. destName) + self.numberOfEnemies = self.numberOfEnemies + 1 + Ovale.refreshNeeded["player"] = true + end +end + +function OvaleEnemies:PLAYER_REGEN_DISABLED() + if self.numberOfEnemies then + self.numberOfEnemies = 0 + self.enemies = {} + end +end + +function OvaleEnemies:GetNumberOfEnemies() + if not self.numberOfEnemies then + self.numberOfEnemies = 0 + end + return self.numberOfEnemies +end +--</public-static-methods> + diff --git a/OvaleEquipement.lua b/OvaleEquipement.lua index 5da7bed..7eead27 100644 --- a/OvaleEquipement.lua +++ b/OvaleEquipement.lua @@ -1,6 +1,10 @@ OvaleEquipement = LibStub("AceAddon-3.0"):NewAddon("OvaleEquipement", "AceEvent-3.0") +--<public-static-properties> OvaleEquipement.nombre = {} +--</public-static-properties> + +--<public-static-methods> function OvaleEquipement:OnEnable() self:RegisterEvent("UNIT_INVENTORY_CHANGED") @@ -265,4 +269,7 @@ end function OvaleEquipement:PLAYER_ENTERING_WORLD(event) self:Refresh() -end \ No newline at end of file +end + +--</public-static-methods> + diff --git a/OvaleFrame.lua b/OvaleFrame.lua index 6e45dff..e4f0121 100644 --- a/OvaleFrame.lua +++ b/OvaleFrame.lua @@ -1,60 +1,56 @@ -local AceGUI = LibStub("AceGUI-3.0") -local Masque = LibStub("Masque", true) - -local GetTime = GetTime - ----------------- --- Main Frame -- ----------------- ---[[ - Events : - OnClose - -]] +--inherits Frame do +--<private-static-properties> + local AceGUI = LibStub("AceGUI-3.0") + local Masque = LibStub("Masque", true) + local GetTime = GetTime + local Type = "OvaleFrame" local Version = 7 +--</private-static-properties> - local function frameOnClose(this) - this.obj:Fire("OnClose") +--<public-methods> + local function frameOnClose(self) + self.obj:Fire("OnClose") end - local function closeOnClick(this) - this.obj:Hide() + local function closeOnClick(self) + self.obj:Hide() end - local function frameOnMouseDown(this) - if (not Ovale.db.profile.apparence.verrouille) then - this:StartMoving() + local function frameOnMouseDown(self) + if (not OvaleOptions:GetApparence().verrouille) then + self:StartMoving() AceGUI:ClearFocus() end end - local function ToggleOptions(this) - if (this.content:IsShown()) then - this.content:Hide() + local function ToggleOptions(self) + if (self.content:IsShown()) then + self.content:Hide() else - this.content:Show() + self.content:Show() end end - local function frameOnMouseUp(this) - this:StopMovingOrSizing() + local function frameOnMouseUp(self) + self:StopMovingOrSizing() + local profile = OvaleOptions:GetProfile() - if (Ovale.db.profile.left~=this:GetLeft() or Ovale.db.profile.top ~=this:GetTop()) then - Ovale.db.profile.left = this:GetLeft() - Ovale.db.profile.top = this:GetTop() + if (profile.left~=self:GetLeft() or profile.top ~=self:GetTop()) then + profile.left = self:GetLeft() + profile.top = self:GetTop() end end - local function frameOnEnter(this) - if (not Ovale.db.profile.apparence.verrouille) then - this.obj.barre:Show() - end + local function frameOnEnter(self) + if (not OvaleOptions:GetApparence().verrouille) then + self.obj.barre:Show() + end end - local function frameOnLeave(this) - this.obj.barre:Hide() + local function frameOnLeave(self) + self.obj.barre:Hide() end @@ -113,7 +109,7 @@ do -- print("sort "..spellId.." parfait") return 1 else - local lag = Ovale.maintenant - action.waitStart + local lag = OvaleState.maintenant - action.waitStart if lag>5 then -- print("sort "..spellId.." ignoré (>5s)") return nil @@ -135,8 +131,8 @@ do end local function OnUpdate(self) - if not Ovale.listeTalentsRemplie then - Ovale:RemplirListeTalents() + if not OvaleData.listeTalentsRemplie then + OvaleData:RemplirListeTalents() end if Ovale.needCompile then Ovale:CompileAll() @@ -144,110 +140,121 @@ do end local now = GetTime() - - if not Ovale.refreshNeeded and self.lastUpdate and now < self.lastUpdate + Ovale.db.profile.apparence.updateInterval then + local forceRefresh = not self.lastUpdate or (now > self.lastUpdate + OvaleOptions:GetApparence().updateInterval) + + if not next(Ovale.refreshNeeded) and not forceRefresh then return end - Ovale.refreshNeeded = false self.lastUpdate = now - Ovale:InitAllActions() + OvaleState:StartNewFrame() for k,node in pairs(Ovale.masterNodes) do - if Ovale.trace then - Ovale:Print("****Master Node "..k) - end - Ovale:InitCalculerMeilleureAction() - local start, ending, priorite, element = Ovale:CalculerMeilleureAction(node) - if start then - Ovale:Log("CalculerMeilleureAction start = "..start) - end - local action = self.actions[k] - if element and element.type == "value" then - local actionTexture - if node.params.texture then - actionTexture = GetSpellTexture(node.params.texture) - end - local value - if element.value and element.origin and element.rate then - value = element.value + (Ovale.maintenant - element.origin) * element.rate + local target = node.params.target or "target" + OvaleCondition.defaultTarget = target + + if forceRefresh or Ovale.refreshNeeded[target] or Ovale.refreshNeeded["player"] or Ovale.refreshNeeded["pet"] then + if Ovale.trace then + Ovale:Print("****Master Node "..k) end - action.icons[1]:SetValue(value, actionTexture) - if #action.icons > 1 then - action.icons[2]:Update(element, nil) + OvaleBestAction:StartNewAction() + local start, ending, priorite, element = OvaleBestAction:Compute(node) + if start then + Ovale:Log("Compute start = "..start) end - else - local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, - actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellId, actionTarget, noRed = Ovale:GetActionInfo(element) - if noRed then - start = actionCooldownStart + actionCooldownDuration - if start < Ovale.currentTime then - start = Ovale.currentTime + local action = self.actions[k] + if element and element.type == "value" then + local actionTexture + if node.params.texture then + actionTexture = GetSpellTexture(node.params.texture) end - end - - -- Dans le cas de canStopChannelling, on risque de demander d'interrompre le channelling courant, ce qui est stupide - if start and Ovale.currentSpellId and Ovale.attenteFinCast and spellId == Ovale.currentSpellId and start<Ovale.attenteFinCast then - start = Ovale.attenteFinCast - end - - if (node.params.nocd and start~=nil and Ovale.maintenant<start-node.params.nocd) then - action.icons[1]:Update(element, nil) - else - action.icons[1]:Update(element, start, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, - actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellId, actionTarget) - end - - action.spellId = spellId - - if start == Ovale.maintenant and actionUsable then - if not action.waitStart then - action.waitStart = Ovale.maintenant + local value + if element.value and element.origin and element.rate then + value = element.value + (OvaleState.maintenant - element.origin) * element.rate + end + action.icons[1]:SetValue(value, actionTexture) + if #action.icons > 1 then + action.icons[2]:Update(element, nil) end else - action.waitStart = nil - end - - if Ovale.db.profile.apparence.moving and action.icons[1].debutAction and action.icons[1].finAction then - local top=1-(Ovale.maintenant - action.icons[1].debutAction)/(action.icons[1].finAction-action.icons[1].debutAction) - if top<0 then - top = 0 - elseif top>1 then - top = 1 + local actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, + actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellId, actionTarget, noRed = OvaleBestAction:GetActionInfo(element) + if noRed then + start = actionCooldownStart + actionCooldownDuration + if start < OvaleState.currentTime then + start = OvaleState.currentTime + end end - action.icons[1]:SetPoint("TOPLEFT",self.frame,"TOPLEFT",(action.left + top*action.dx)/action.scale,(action.top - top*action.dy)/action.scale) - if action.icons[2] then - action.icons[2]:SetPoint("TOPLEFT",self.frame,"TOPLEFT",(action.left + (top+1)*action.dx)/action.scale,(action.top - (top+1)*action.dy)/action.scale) + + -- Dans le cas de canStopChannelling, on risque de demander d'interrompre le channelling courant, ce qui est stupide + if start and OvaleState.currentSpellId and OvaleState.attenteFinCast and spellId == OvaleState.currentSpellId and start<OvaleState.attenteFinCast then + start = OvaleState.attenteFinCast end - end - - if (node.params.size ~= "small" and not node.params.nocd and Ovale.db.profile.apparence.predictif) then - if start then - local castTime=0 - if spellId then - local _, _, _, _, _, _, _castTime = GetSpellInfo(spellId) - if _castTime and _castTime>0 then - castTime = _castTime/1000 - end + + if (node.params.nocd and start~=nil and OvaleState.maintenant<start-node.params.nocd) then + action.icons[1]:Update(element, nil) + else + action.icons[1]:Update(element, start, actionTexture, actionInRange, actionCooldownStart, actionCooldownDuration, + actionUsable, actionShortcut, actionIsCurrent, actionEnable, spellId, actionTarget) + end + + action.spellId = spellId + + if start == OvaleState.maintenant and actionUsable then + if not action.waitStart then + action.waitStart = OvaleState.maintenant end - local gcd = Ovale:GetGCD(spellId) - local nextCast - if (castTime>gcd) then - nextCast = start + castTime + else + action.waitStart = nil + end + + if OvaleOptions:GetApparence().moving and action.icons[1].debutAction and action.icons[1].finAction then + local top=1-(OvaleState.maintenant - action.icons[1].debutAction)/(action.icons[1].finAction-action.icons[1].debutAction) + if top<0 then + top = 0 + elseif top>1 then + top = 1 + end + action.icons[1]:SetPoint("TOPLEFT",self.frame,"TOPLEFT",(action.left + top*action.dx)/action.scale,(action.top - top*action.dy)/action.scale) + if action.icons[2] then + action.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 OvaleOptions:GetApparence().predictif) then + if start then + local castTime=0 + if spellId then + local _, _, _, _, _, _, _castTime = GetSpellInfo(spellId) + if _castTime and _castTime>0 then + castTime = _castTime/1000 + end + end + local gcd = OvaleData:GetGCD(spellId) + local nextCast + if (castTime>gcd) then + nextCast = start + castTime + else + nextCast = start + gcd + end + if Ovale.trace then + Ovale:Print("****Second icon " .. start) + end + local spellTarget = element.params.target + if spellTarget == "target" or not spellTarget then + spellTarget = target + end + OvaleState:AddSpellToStack(spellId, start, start + castTime, nextCast, false, UnitGUID(spellTarget)) + start, ending, priorite, element = OvaleBestAction:Compute(node) + action.icons[2]:Update(element, start, OvaleBestAction:GetActionInfo(element)) else - nextCast = start + gcd - end - if Ovale.trace then - Ovale:Print("****Second icon " .. start) + action.icons[2]:Update(element, nil) end - Ovale:AddSpellToStack(spellId, start, start + castTime, nextCast) - start, ending, priorite, element = Ovale:CalculerMeilleureAction(node) - action.icons[2]:Update(element, start, Ovale:GetActionInfo(element)) - else - action.icons[2]:Update(element, nil) end end end end + + Ovale.refreshNeeded = {} if (not Ovale.bug) then Ovale.traced = false @@ -270,7 +277,7 @@ do end end - self.frame:EnableMouse(not Ovale.db.profile.apparence.clickThru) + self.frame:EnableMouse(not OvaleOptions:GetApparence().clickThru) local left = 0 local maxHeight = 0 @@ -283,7 +290,7 @@ do local BARRE = 8 - local margin = Ovale.db.profile.apparence.margin + local margin = OvaleOptions:GetApparence().margin for k,node in pairs(Ovale.masterNodes) do if not self.actions[k] then @@ -294,27 +301,27 @@ do local width, height, newScale local nbIcons if (node.params.size == "small") then - newScale = Ovale.db.profile.apparence.smallIconScale + newScale = OvaleOptions:GetApparence().smallIconScale width = newScale * 36 + margin height = newScale * 36 + margin nbIcons = 1 else - newScale = Ovale.db.profile.apparence.iconScale + newScale = OvaleOptions:GetApparence().iconScale width =newScale * 36 + margin height = newScale * 36 + margin - if Ovale.db.profile.apparence.predictif and node.params.type ~= "value" then + if OvaleOptions:GetApparence().predictif and node.params.type ~= "value" then nbIcons = 2 else nbIcons = 1 end end - if (top + height > Ovale.db.profile.apparence.iconScale * 36 + margin) then + if (top + height > OvaleOptions:GetApparence().iconScale * 36 + margin) then top = 0 left = maxWidth end action.scale = newScale - if (Ovale.db.profile.apparence.vertical) then + if (OvaleOptions:GetApparence().vertical) then action.left = top action.top = -left-BARRE-margin action.dx = width @@ -333,15 +340,15 @@ do local icon = action.icons[l] local scale = action.scale if l> 1 then - scale = scale * Ovale.db.profile.apparence.secondIconScale + scale = scale * OvaleOptions:GetApparence().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(Ovale.db.profile.apparence.fontScale) + icon:SetFontScale(OvaleOptions:GetApparence().fontScale) icon:SetParams(node.params) icon:SetHelp(node.params.help) - icon:SetRangeIndicator(Ovale.db.profile.apparence.targetText) - icon:EnableMouse(not Ovale.db.profile.apparence.clickThru) + icon:SetRangeIndicator(OvaleOptions:GetApparence().targetText) + icon:EnableMouse(not OvaleOptions:GetApparence().clickThru) icon.cdShown = (l == 1) if Masque then self.skinGroup:AddButton(icon) @@ -360,18 +367,18 @@ do end end - if (Ovale.db.profile.apparence.vertical) then + if (OvaleOptions:GetApparence().vertical) then self.barre:SetWidth(maxHeight - margin) self.barre:SetHeight(BARRE) - self.frame:SetWidth(maxHeight + Ovale.db.profile.apparence.iconShiftY) - self.frame:SetHeight(maxWidth+BARRE+margin + Ovale.db.profile.apparence.iconShiftX) - self.content:SetPoint("TOPLEFT",self.frame,"TOPLEFT",maxHeight + Ovale.db.profile.apparence.iconShiftX,Ovale.db.profile.apparence.iconShiftY) + self.frame:SetWidth(maxHeight + OvaleOptions:GetApparence().iconShiftY) + self.frame:SetHeight(maxWidth+BARRE+margin + OvaleOptions:GetApparence().iconShiftX) + self.content:SetPoint("TOPLEFT",self.frame,"TOPLEFT",maxHeight + OvaleOptions:GetApparence().iconShiftX,OvaleOptions:GetApparence().iconShiftY) else self.barre:SetWidth(maxWidth - margin) self.barre:SetHeight(BARRE) - self.frame:SetWidth(maxWidth) -- + Ovale.db.profile.apparence.iconShiftX - self.frame:SetHeight(maxHeight+BARRE+margin) -- + Ovale.db.profile.apparence.iconShiftY - self.content:SetPoint("TOPLEFT",self.frame,"TOPLEFT",maxWidth + Ovale.db.profile.apparence.iconShiftX,Ovale.db.profile.apparence.iconShiftY) + self.frame:SetWidth(maxWidth) -- + OvaleOptions:GetApparence().iconShiftX + self.frame:SetHeight(maxHeight+BARRE+margin) -- + OvaleOptions:GetApparence().iconShiftY + self.content:SetPoint("TOPLEFT",self.frame,"TOPLEFT",maxWidth + OvaleOptions:GetApparence().iconShiftX,OvaleOptions:GetApparence().iconShiftY) end end @@ -379,7 +386,6 @@ do local frame = CreateFrame("Frame",nil,UIParent) local self = {} - self.type = "Frame" self.Hide = Hide self.Show = Show @@ -392,17 +398,29 @@ do self.ToggleOptions = ToggleOptions self.OnUpdate = OnUpdate self.GetScore = GetScore - + +--<public-properties> + self.type = "Frame" self.localstatus = {} self.actions = {} - - self.frame = frame + self.updateFrame = CreateFrame("Frame") + self.barre = self.frame:CreateTexture(); + self.content = CreateFrame("Frame",nil,frame) + if Masque then + self.skinGroup = Masque:Group("Ovale") + end + self.lastUpdate = nil + --Cheating with frame object which has an obj property + --TODO: Frame Class + self.obj = nil +--</public-properties> + frame.obj = self frame:SetWidth(100) frame:SetHeight(100) frame:SetPoint("CENTER",UIParent,"CENTER",0,0) - if not Ovale.db.profile.apparence.clickThru then + if not OvaleOptions:GetApparence().clickThru then frame:EnableMouse() end frame:SetMovable(true) @@ -413,34 +431,29 @@ do frame:SetScript("OnLeave", frameOnLeave) -- frame:SetScript("OnUpdate", frameOnUpdate) frame:SetScript("OnHide",frameOnClose) - frame:SetAlpha(Ovale.db.profile.apparence.alpha) + frame:SetAlpha(OvaleOptions:GetApparence().alpha) - self.updateFrame = CreateFrame("Frame") self.updateFrame:SetScript("OnUpdate", frameOnUpdate) self.updateFrame.obj = self - self.barre = self.frame:CreateTexture(); self.barre:SetTexture(0,0.8,0) self.barre:SetPoint("TOPLEFT",0,0) self.barre:Hide() --Container Support - local content = CreateFrame("Frame",nil,frame) - self.content = content + local content = self.content content.obj = self content:SetWidth(200) content:SetHeight(100) content:Hide() - content:SetAlpha(Ovale.db.profile.apparence.optionsAlpha) + content:SetAlpha(OvaleOptions:GetApparence().optionsAlpha) AceGUI:RegisterAsContainer(self) - if Masque then - self.skinGroup = Masque:Group("Ovale") - end return self end +--</public-methods> AceGUI:RegisterWidgetType(Type,Constructor,Version) end diff --git a/OvaleFuture.lua b/OvaleFuture.lua new file mode 100644 index 0000000..362c7bc --- /dev/null +++ b/OvaleFuture.lua @@ -0,0 +1,306 @@ +-- The travelling missiles or spells that have been cast but whose effects were not still not applied + +OvaleFuture = LibStub("AceAddon-3.0"):NewAddon("OvaleFuture", "AceEvent-3.0") + +--<public-static-properties> +--spell counter (see Counter function) +OvaleFuture.counter = {} +--the spells that the player has casted but that did not reach their target +--the result is computed by the simulator, allowing to ignore lag or missile travel time +OvaleFuture.lastSpell = {} +--the attack power of the last spell +OvaleFuture.lastSpellAP = {} +OvaleFuture.lastSpellSP = {} +OvaleFuture.lastSpellDM = {} +OvaleFuture.playerGUID = nil +OvaleFuture.nextSpellTarget = nil +OvaleFuture.nextSpellLineID = nil +--</public-static-properties> + +-- Events +--<public-static-methods> +function OvaleFuture:OnEnable() + self.playerGUID = UnitGUID("player") + self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED") + self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED") + self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + self:RegisterEvent("UNIT_SPELLCAST_START") + self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START") + self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP") + self:RegisterEvent("UNIT_SPELLCAST_SENT") +end + +function OvaleFuture:OnDisable() + self:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED") + self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + self:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED") + self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START") + self:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_STOP") + self:UnregisterEvent("UNIT_SPELLCAST_START") + self:UnregisterEvent("UNIT_SPELLCAST_SENT") +end + + +function OvaleFuture:UNIT_SPELLCAST_CHANNEL_START(event, unit, name, rank, lineId, spellId) + if unit=="player" then + --Ovale:Print("UNIT_SPELLCAST_CHANNEL_START "..event.." name="..name.." lineId="..lineId.." spellId="..spellId .. " " .. GetTime()) + local _,_,_,_,startTime, endTime = UnitChannelInfo("player") + --Ovale:Print("startTime = " ..startTime.." endTime = "..endTime) + self:AddSpellToList(spellId, lineId, startTime/1000, endTime/1000, true, false) + end +end + +function OvaleFuture:UNIT_SPELLCAST_CHANNEL_STOP(event, unit, name, rank, lineId, spellId) + if unit == "player" then + --Ovale:Print("UNIT_SPELLCAST_CHANNEL_STOP "..event.." name="..name.." lineId="..lineId.." spellId="..spellId) + self:RemoveSpellFromList(spellId, lineId) + end +end + +--Called when a spell started its cast +function OvaleFuture:UNIT_SPELLCAST_START(event, unit, name, rank, lineId, spellId) + --Ovale:Print("UNIT_SPELLCAST_START "..event.." name="..name.." lineId="..lineId.." spellId="..spellId .. " time=" .. GetTime()) + if unit=="player" then + local _,_,_,_,startTime,endTime = UnitCastingInfo("player") + --local spell, rank, icon, cost, isFunnel, powerType, castTime, minRange, maxRange = GetSpellInfo(spellId) + --local startTime = GetTime() + --self:AddSpellToList(spellId, lineId, startTime, startTime + castTime/1000) + self:AddSpellToList(spellId, lineId, startTime/1000, endTime/1000, false, false) + end +end + +--Called if the player interrupted early his cast +--The spell is removed from the lastSpell table +function OvaleFuture:UNIT_SPELLCAST_INTERRUPTED(event, unit, name, rank, lineId, spellId) + if unit == "player" then + --Ovale:Print("UNIT_SPELLCAST_INTERRUPTED "..event.." name="..name.." lineId="..lineId.." spellId="..spellId.. " time="..GetTime()) + self:RemoveSpellFromList(spellId, lineId) + end +end + +function OvaleFuture:UNIT_SPELLCAST_SENT(event, unit, spell, rank, target, lineId) + if unit == "player" then + local targetGUID = OvaleGUID.nameToGUID[target] + self.nextSpellTarget = targetGUID + self.nextSpellLineID = lineId + --Ovale:Print(target) + for i,v in ipairs(self.lastSpell) do + if v.lineId == lineId then + v.target = targetGUID + end + end + end +end + +function OvaleFuture:UNIT_SPELLCAST_SUCCEEDED(event, unit, name, rank, lineId, spellId) + if unit == "player" then + --Ovale:Print("UNIT_SPELLCAST_SUCCEEDED "..event.." name="..name.." lineId="..lineId.." spellId="..spellId.. " time="..GetTime()) + for i,v in ipairs(self.lastSpell) do + if v.lineId == lineId then + --Already added in UNIT_SPELLCAST_START + v.allowRemove = true + return + end + end + if not UnitChannelInfo("player") then + --A UNIT_SPELLCAST_SUCCEEDED is received when channeling a spell, with a different lineId! + local now = GetTime() + self:AddSpellToList(spellId, lineId, now, now, false, true) + end + end +end + +function OvaleFuture:COMBAT_LOG_EVENT_UNFILTERED(event, ...) + local time, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags = select(1, ...) + + --[[ + Sequence of events: + - casting a spell that damages + SPELL_CAST_START + SPELL_DAMAGE + - casting a spell that misses + SPELL_CAST_START + SPELL_MISSED + - casting a spell then interrupting it + SPELL_CAST_START + SPELL_CAST_FAILED + - casting an instant damaging spell + SPELL_CAST_SUCCESS + SPELL_DAMAGE + - chanelling a damaging spell + SPELL_CAST_SUCCESS + SPELL_AURA_APPLIED + SPELL_PERIODIC_DAMAGE + SPELL_PERIODIC_DAMAGE + SPELL_PERIODIC_DAMAGE + (interruption does not generate an event) + - refreshing a buff + SPELL_AURA_REFRESH + SPELL_CAST_SUCCESS + - removing a buff + SPELL_AURA_REMOVED + - casting a buff + SPELL_AURA_APPLIED + SPELL_CAST_SUCCESS + -casting a DOT that misses + SPELL_CAST_SUCCESS + SPELL_MISSED + - casting a DOT that damages + SPELL_CAST_SUCESS + SPELL_AURA_APPLIED + SPELL_PERIODIC_DAMAGE + SPELL_PERIODIC_DAMAGE]] + + if sourceGUID == self.playerGUID then + --Called when a missile reached or missed its target + --Update lastSpell accordingly + --Do not use SPELL_CAST_SUCCESS because it is sent when the missile has not reached the target + + --Ovale:Print("SPELL_CAST_START " .. GetTime()) + --if string.find(event, "SPELL") == 1 then + -- local spellId, spellName = select(12, ...) + -- Ovale:Print(event .. " " ..spellName .. " " ..GetTime()) + --end + -- local spellId, spellName = select(12, ...) + -- for i,v in ipairs(self.lastSpell) do + + -- end + --end + + if + string.find(event, "SPELL_AURA_APPLIED")==1 + or string.find(event, "SPELL_AURA_REFRESH")==1 + or string.find(event, "SPELL_DAMAGE")==1 + or string.find(event, "SPELL_MISSED") == 1 + or string.find(event, "SPELL_CAST_SUCCESS") == 1 + or string.find(event, "SPELL_CAST_FAILED") == 1 then + local spellId, spellName = select(12, ...) + for i,v in ipairs(self.lastSpell) do + if (v.spellId == spellId or v.auraSpellId == spellId) and v.allowRemove then + if not v.channeled and (v.removeOnSuccess or + string.find(event, "SPELL_CAST_SUCCESS") ~= 1) then + table.remove(self.lastSpell, i) + Ovale.refreshNeeded["player"] = true + --Ovale:Print("LOG_EVENT on supprime "..spellId.." a "..GetTime()) + end + --Ovale:Print(UnitDebuff("target", "Etreinte de l'ombre")) + break + end + end + end + end + +end + +function OvaleFuture:AddSpellToList(spellId, lineId, startTime, endTime, channeled, allowRemove) + local newSpell = {} + newSpell.spellId = spellId + newSpell.lineId = lineId + newSpell.start = startTime + newSpell.stop = endTime + newSpell.channeled = channeled + newSpell.allowRemove = allowRemove + --TODO unable to know what is the real target + if lineId == self.nextSpellLineID and self.nextSpellTarget then + newSpell.target = self.nextSpellTarget + else + newSpell.target = UnitGUID("target") + end + + self.lastSpellAP[spellId] = UnitAttackPower("player") + self.lastSpellSP[spellId] = GetSpellBonusDamage(2) + self.lastSpellDM[spellId] = OvaleAura.damageMultiplier + self.lastSpell[#self.lastSpell+1] = newSpell + --Ovale:Print("on ajoute "..spellId..": ".. newSpell.start.." to "..newSpell.stop.." ("..OvaleState.maintenant..")" ..#self.lastSpell .. " " ..newSpell.target) + + if OvaleData.spellInfo[spellId] then + local si = OvaleData.spellInfo[spellId] + + if si.aura then + for target, targetInfo in pairs(si.aura) do + for filter, filterInfo in pairs(targetInfo) do + for auraSpellId, spellData in pairs(filterInfo) do + if spellData and spellData ~= "refresh" and spellData > 0 then + newSpell.auraSpellId = auraSpellId + if target == "player" then + newSpell.removeOnSuccess = true + end + break + end + end + end + end + end + + --Ovale:Print("spellInfo found") + if si and si.buffnocd and UnitBuff("player", GetSpellInfo(si.buffnocd)) then + newSpell.nocd = true + else + newSpell.nocd = false + end + --Increase or reset the counter that is used by the Counter function + if si.resetcounter then + self.counter[si.resetcounter] = 0 + --Ovale:Print("reset counter "..si.resetcounter) + end + if si.inccounter then + local cname = si.inccounter + if not self.counter[cname] then + self.counter[cname] = 0 + end + self.counter[cname] = self.counter[cname] + 1 + --Ovale:Print("inc counter "..cname.." to "..self.counter[cname]) + end + else + newSpell.removeOnSuccess = true + end + + if Ovale.enCombat then + --Ovale:Print(tostring(OvaleData.scoreSpell[spellId])) + if (not OvaleData.spellInfo[spellId] or not OvaleData.spellInfo[spellId].toggle) and OvaleData.scoreSpell[spellId] then + --Compute the player score + local scored = Ovale.frame:GetScore(spellId) + --Ovale:Print("Scored "..scored) + if scored~=nil then + Ovale.score = Ovale.score + scored + Ovale.maxScore = Ovale.maxScore + 1 + Ovale:SendScoreToDamageMeter(UnitName("player"), OvaleAura.playerGUID, scored, 1) + end + end + end + Ovale.refreshNeeded["player"] = true +end + + +function OvaleFuture:RemoveSpellFromList(spellId, lineId) + for i,v in ipairs(self.lastSpell) do + if v.lineId == lineId then + table.remove(self.lastSpell, i) + --Ovale:Print("RemoveSpellFromList on supprime "..spellId) + break + end + end + Ovale.refreshNeeded["player"] = true +end + +-- Apply the effects of travelling spells +function OvaleFuture:Apply() + for i,v in ipairs(self.lastSpell) do + if not OvaleData.spellInfo[v.spellId] or not OvaleData.spellInfo[v.spellId].toggle then + --[[local spell, rank, displayName, icon, startTime, endTime, isTradeSkill = UnitCastingInfo("player") + if spell and spell == v.name and startTime/1000 - v.start < 0.5 and v.stop~=endTime/1000 then + print("ancien = "..v.stop) + v.stop = endTime/1000 + print("changement de v.stop en "..v.stop.." "..v.start) + end]] + Ovale:Log("OvaleState.maintenant = " ..OvaleState.maintenant.." spellId="..v.spellId.." v.stop="..v.stop) + if OvaleState.maintenant - v.stop < 5 then + OvaleState:AddSpellToStack(v.spellId, v.start, v.stop, v.stop, v.nocd, v.target) + else + --Ovale:Print("Removing obsolete "..v.spellId) + table.remove(self.lastSpell, i) + end + end + end +end +--</public-static-methods> diff --git a/OvaleGUID.lua b/OvaleGUID.lua new file mode 100644 index 0000000..9cfb869 --- /dev/null +++ b/OvaleGUID.lua @@ -0,0 +1,134 @@ +-- This addon translates a GUID to a target name +-- Usage: OvaleGUID:GetUnitId(guid) + +OvaleGUID = LibStub("AceAddon-3.0"):NewAddon("OvaleGUID", "AceEvent-3.0", "AceConsole-3.0") + +--<public-static-properties> +OvaleGUID.unitId = {} +OvaleGUID.guid = {} +OvaleGUID.player = nil +OvaleGUID.nameToGUID = {} +OvaleGUID.nameToUnit = {} +--</public-static-properties> + +--<public-static-methods> +function OvaleGUID:OnEnable() + self:Update("player") + self:RegisterEvent("PLAYER_LOGIN") + self:RegisterEvent("UNIT_TARGET") + self:RegisterEvent("PARTY_MEMBERS_CHANGED") + self:RegisterEvent("RAID_ROSTER_UPDATE") + self:RegisterEvent("UNIT_PET") + self:RegisterEvent("ARENA_OPPONENT_UPDATE") + self:RegisterEvent("PLAYER_FOCUS_CHANGED") + self:RegisterEvent("UPDATE_MOUSEOVER_UNIT") + self:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT") +end + +function OvaleGUID:OnDisable() + self:UnregisterEvent("PLAYER_LOGIN") + self:UnregisterEvent("UNIT_TARGET") + self:UnregisterEvent("PARTY_MEMBERS_CHANGED") + self:UnregisterEvent("RAID_ROSTER_UPDATE") + self:UnregisterEvent("UNIT_PET") + self:UnregisterEvent("ARENA_OPPONENT_UPDATE") + self:UnregisterEvent("PLAYER_FOCUS_CHANGED") + self:UnregisterEvent("UPDATE_MOUSEOVER_UNIT") + self:UnregisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT") +end + +function OvaleGUID:Update(unitId) + local guid = UnitGUID(unitId) + local previousGuid = self.guid[unitId] + if unitId == "player" then + self.player = guid + end + if previousGuid ~= guid then + if previousGuid then + self.unitId[previousGuid][unitId] = nil + if not next(self.unitId[previousGuid]) then + self.unitId[previousGuid] = nil + end + end + self.guid[unitId] = guid + if guid then + if not self.unitId[guid] then + self.unitId[guid] = {} + end + -- Ovale:Print("GUID "..guid.." is ".. unitId) + self.unitId[guid][unitId] = true + end + local name = UnitName(unitId) + if name and (not self.nameToGUID[name] or unitId == "target" + or self.nameToUnit[name] == "mouseover") then + self.nameToGUID[name] = guid + self.nameToUnit[name] = unitId + end + end +end + +function OvaleGUID:GetUnitId(guid) + local unitIdTable = self.unitId[guid] + if not unitIdTable then return nil end + return next(unitIdTable) +end + +function OvaleGUID:UpdateWithTarget(unitId) + self:Update(unitId) + self:Update(unitId.."target") +end + +function OvaleGUID:PLAYER_LOGIN(event) + self:Update("player") +end + +function OvaleGUID:UNIT_TARGET(event, unitId) + self:Update(unitId .. "target") +end + +function OvaleGUID:PARTY_MEMBERS_CHANGED(event) + for i=1, GetNumPartyMembers() do + self:UpdateWithTarget("party"..i) + self:UpdateWithTarget("partypet"..i) + end +end + +function OvaleGUID:RAID_ROSTER_UPDATE(event) + for i=1, GetNumRaidMembers() do + self:UpdateWithTarget("raid"..i) + self:UpdateWithTarget("raidpet"..i) + end +end + +function OvaleGUID:UNIT_PET(event, unitId) + if string.find(unitId, "party") == 0 then + local petId = "partypet" .. string.sub(unitId, 6) + self:UpdateWithTarget(petId) + elseif string.find(unitId, "raid") == 0 then + local petId = "raidpet" .. string.sub(unitId, 5) + self:UpdateWithTarget(petId) + elseif unitId == "player" then + self:UpdateWithTarget("pet") + end +end + +function OvaleGUID:ARENA_OPPONENT_UPDATE(event) + for i=1, 5 do + self:UpdateWithTarget("arena"..i) + end +end + +function OvaleGUID:PLAYER_FOCUS_CHANGED(event) + self:UpdateWithTarget("focus") +end + +function OvaleGUID:UPDATE_MOUSEOVER_UNIT(event) + self:UpdateWithTarget("mouseover") +end + +function OvaleGUID:INSTANCE_ENCOUNTER_ENGAGE_UNIT(event) + for i=1, 4 do + self:UpdateWithTarget("boss"..i) + end +end +--</public-static-methods> diff --git a/OvaleIcone.lua b/OvaleIcone.lua index b92c677..af9b493 100644 --- a/OvaleIcone.lua +++ b/OvaleIcone.lua @@ -1,5 +1,8 @@ local L = LibStub("AceLocale-3.0"):GetLocale("Ovale") +--inherits ActionButtonTemplate + +--<public-methods> local function SetValue(self, value, actionTexture) self.icone:Show() self.icone:SetTexture(actionTexture); @@ -29,15 +32,15 @@ local function Update(self, element, minAttente, actionTexture, actionInRange, a if (minAttente~=nil and actionTexture) then if (actionTexture~=self.actionCourante or self.ancienneAttente==nil or - (minAttente~=Ovale.maintenant and minAttente>self.ancienneAttente+0.01) or + (minAttente~=OvaleState.maintenant and minAttente>self.ancienneAttente+0.01) or (minAttente < self.finAction-0.01)) then if (actionTexture~=self.actionCourante or self.ancienneAttente==nil or - (minAttente~=Ovale.maintenant and minAttente>self.ancienneAttente+0.01)) then - self.debutAction = Ovale.maintenant + (minAttente~=OvaleState.maintenant and minAttente>self.ancienneAttente+0.01)) then + self.debutAction = OvaleState.maintenant end self.actionCourante = actionTexture self.finAction = minAttente - if (minAttente == Ovale.maintenant) then + if (minAttente == OvaleState.maintenant) then self.cd:Hide() else self.lastSound = nil @@ -48,7 +51,7 @@ local function Update(self, element, minAttente, actionTexture, actionInRange, a end end - if not Ovale.db.profile.apparence.flashIcon and minAttente<=Ovale.maintenant then + if not OvaleOptions:GetApparence().flashIcon and minAttente<=OvaleState.maintenant then self.cd:Hide() end @@ -65,21 +68,21 @@ local function Update(self, element, minAttente, actionTexture, actionInRange, a end local red - if (minAttente > actionCooldownStart + actionCooldownDuration + 0.01 and minAttente > Ovale.maintenant - and minAttente>Ovale.attenteFinCast) then + if (minAttente > actionCooldownStart + actionCooldownDuration + 0.01 and minAttente > OvaleState.maintenant + and minAttente>OvaleState.attenteFinCast) then self.icone:SetVertexColor(0.75,0.2,0.2) red = true else self.icone:SetVertexColor(1,1,1) end - --if (minAttente==Ovale.maintenant) then + --if (minAttente==OvaleState.maintenant) then --self.cd:Hide() --end if element.params.sound and not self.lastSound then local delay = element.params.soundtime or 0.5 - if Ovale.maintenant>=minAttente - delay then + if OvaleState.maintenant>=minAttente - delay then self.lastSound = element.params.sound -- print("Play" .. self.lastSound) PlaySoundFile(self.lastSound) @@ -87,10 +90,10 @@ local function Update(self, element, minAttente, actionTexture, actionInRange, a end -- La latence - if minAttente>Ovale.maintenant and Ovale.db.profile.apparence.highlightIcon and not red then + if minAttente>OvaleState.maintenant and OvaleOptions:GetApparence().highlightIcon and not red then local lag = 0.6 local newShouldClick - if minAttente<Ovale.maintenant + lag then + if minAttente<OvaleState.maintenant + lag then newShouldClick = true else newShouldClick = false @@ -109,15 +112,15 @@ local function Update(self, element, minAttente, actionTexture, actionInRange, a end -- Le temps restant - if ((Ovale.db.profile.apparence.numeric or self.params.text == "always") and minAttente > Ovale.maintenant) then - self.remains:SetText(string.format("%.1f", minAttente - Ovale.maintenant)) + if ((OvaleOptions:GetApparence().numeric or self.params.text == "always") and minAttente > OvaleState.maintenant) then + self.remains:SetText(string.format("%.1f", minAttente - OvaleState.maintenant)) self.remains:Show() else self.remains:Hide() end -- Le raccourcis clavier - if (Ovale.db.profile.apparence.raccourcis) then + if (OvaleOptions:GetApparence().raccourcis) then self.shortcut:Show() self.shortcut:SetText(actionShortcut) else @@ -148,7 +151,7 @@ local function Update(self, element, minAttente, actionTexture, actionInRange, a self.shortcut:Hide() self.remains:Hide() self.focusText:Hide() - if Ovale.db.profile.apparence.hideEmpty then + if OvaleOptions:GetApparence().hideEmpty then self:Hide() else self:Show() @@ -177,6 +180,11 @@ local function SetFontScale(self, scale) self.aPortee:SetFont(self.fontName, self.fontHeight * self.fontScale, self.fontFlags) end +local function SetRangeIndicator(self, text) + self.aPortee:SetText(text) +end +--</public-methods> + function OvaleIcone_OnClick(self) Ovale:ToggleOptions() self:SetChecked(0) @@ -204,26 +212,36 @@ function OvaleIcone_OnLeave(self) end end -local function SetRangeIndicator(self, text) - self.aPortee:SetText(text) -end - function OvaleIcone_OnLoad(self) local name = self:GetName() + +--<public-properties> self.icone = _G[name.."Icon"] self.shortcut = _G[name.."HotKey"] self.remains = _G[name.."Name"] self.aPortee = _G[name.."Count"] - self.aPortee:SetText(Ovale.db.profile.apparence.targetText) + self.aPortee:SetText(OvaleOptions:GetApparence().targetText) self.cd = _G[name.."Cooldown"] self.normalTexture = _G[name.."NormalTexture"] - local fontName, fontHeight, fontFlags = self.shortcut:GetFont() self.fontName = fontName self.fontHeight = fontHeight self.fontFlags = fontFlags - self.focusText = self:CreateFontString(nil, "OVERLAY"); + self.cdShown = true + self.shouldClick = false + self.help = nil + self.spellId = nil + self.fontScale = nil + self.lastSound = nil + self.ancienneAttente = nil + self.finAction = nil + self.debutAction = nil + self.actionCourante = nil + self.params = nil +--</public-properties> + + self.focusText:SetFontObject("GameFontNormal"); self.focusText:SetAllPoints(self); self.focusText:SetTextColor(1,1,1); @@ -237,8 +255,7 @@ function OvaleIcone_OnLoad(self) self.SetFontScale = SetFontScale self.SetRangeIndicator = SetRangeIndicator self.SetValue = SetValue - self.cdShown = true - if Ovale.db.profile.clickThru then + if OvaleOptions:GetProfile().clickThru then self:EnableMouse(false) end end diff --git a/OvaleIcone.xml b/OvaleIcone.xml index 06177d3..044555b 100644 --- a/OvaleIcone.xml +++ b/OvaleIcone.xml @@ -2,7 +2,7 @@ <CheckButton name="OvaleIcone" virtual="true" inherits="ActionButtonTemplate"> <Scripts> - <OnLoad>OvaleIcone_OnLoad(self);</OnLoad> + <OnLoad>OvaleIcone_OnLoad(self)</OnLoad> <OnClick>OvaleIcone_OnClick(self)</OnClick> <OnEnter>OvaleIcone_OnEnter(self)</OnEnter> <OnLeave>OvaleIcone_OnLeave(self)</OnLeave> diff --git a/OvaleOptions.lua b/OvaleOptions.lua new file mode 100644 index 0000000..08525d8 --- /dev/null +++ b/OvaleOptions.lua @@ -0,0 +1,481 @@ +-- Ovale options and UI + +OvaleOptions = LibStub("AceAddon-3.0"):NewAddon("OvaleOptions", "AceEvent-3.0", "AceConsole-3.0") + +--<public-static-properties> +OvaleOptions.firstInit = false +OvaleOptions.db = nil +--</public-static-properties> + +--<private-static-properties> +local AceConfig = LibStub("AceConfig-3.0"); +local AceConfigDialog = LibStub("AceConfigDialog-3.0"); +local L = LibStub("AceLocale-3.0"):GetLocale("Ovale") + +--GUI option +local options = +{ + type = "group", + args = + { + apparence = + { + name = L["Apparence"], + type = "group", + args = + { + combatUniquement = + { + order = 1, + type = "toggle", + name = L["En combat uniquement"], + get = function(info) + return OvaleOptions.db.profile.apparence.enCombat + end, + set = function(info, v) + OvaleOptions.db.profile.apparence.enCombat = v + Ovale:UpdateVisibility() + end, + width = "full" + }, + targetOnly = + { + order = 1.5, + type = "toggle", + name = L["Si cible uniquement"], + get = function(info) + return OvaleOptions.db.profile.apparence.avecCible + end, + set = function(info, v) + OvaleOptions.db.profile.apparence.avecCible = v + Ovale:UpdateVisibility() + end, + width = "full" + }, + iconScale = + { + order = 2, + type = "range", + name = L["Taille des icônes"], + desc = L["La taille des icônes"], + min = 0.1, max = 16, step = 0.1, + get = function(info) return OvaleOptions.db.profile.apparence.iconScale end, + set = function(info,value) OvaleOptions.db.profile.apparence.iconScale = value; Ovale:UpdateFrame() end + }, + secondIconScale = + { + order = 2.5, + type = "range", + name = L["Taille du second icône"], + min = 0.2, max = 1, step = 0.1, + get = function(info) return OvaleOptions.db.profile.apparence.secondIconScale end, + set = function(info,value) OvaleOptions.db.profile.apparence.secondIconScale = value; Ovale:UpdateFrame() end + }, + fontScale = + { + order = 3, + type = "range", + name = L["Taille des polices"], + desc = L["La taille des polices"], + min = 0.1, max = 2, step = 0.1, + get = function(info) return OvaleOptions.db.profile.apparence.fontScale end, + set = function(info,value) OvaleOptions.db.profile.apparence.fontScale = value; Ovale:UpdateFrame() end + }, + smallIconScale = + { + order = 4, + type = "range", + name = L["Taille des petites icônes"], + desc = L["La taille des petites icônes"], + min = 0.1, max = 16, step = 0.1, + get = function(info) return OvaleOptions.db.profile.apparence.smallIconScale end, + set = function(info,value) OvaleOptions.db.profile.apparence.smallIconScale = value; Ovale:UpdateFrame() end + }, + margin = + { + order = 5.5, + type = "range", + name = L["Marge entre deux icônes"], + min = -16, max = 64, step = 1, + get = function(info) return OvaleOptions.db.profile.apparence.margin end, + set = function(info,value) OvaleOptions.db.profile.apparence.margin = value; Ovale:UpdateFrame() end + }, + iconShiftX = + { + order = 5.6, + type = "range", + name = L["Décalage horizontal des options"], + min = -256, max = 256, step = 1, + get = function(info) return OvaleOptions.db.profile.apparence.iconShiftX end, + set = function(info,value) OvaleOptions.db.profile.apparence.iconShiftX = value; Ovale:UpdateFrame() end + }, + iconShiftY = + { + order = 5.7, + type = "range", + name = L["Décalage vertical des options"], + min = -256, max = 256, step = 1, + get = function(info) return OvaleOptions.db.profile.apparence.iconShiftY end, + set = function(info,value) OvaleOptions.db.profile.apparence.iconShiftY = value; Ovale:UpdateFrame() end + }, + raccourcis = + { + order = 6, + type = "toggle", + name = L["Raccourcis clavier"], + desc = L["Afficher les raccourcis clavier dans le coin inférieur gauche des icônes"], + get = function(info) return OvaleOptions.db.profile.apparence.raccourcis end, + set = function(info, value) OvaleOptions.db.profile.apparence.raccourcis = value end + }, + numeric = + { + order = 7, + type = "toggle", + name = L["Affichage numérique"], + desc = L["Affiche le temps de recharge sous forme numérique"], + get = function(info) return OvaleOptions.db.profile.apparence.numeric end, + set = function(info, value) OvaleOptions.db.profile.apparence.numeric = value end + }, + verrouille = + { + order = 8, + type = "toggle", + name = L["Verrouiller position"], + get = function(info) return OvaleOptions.db.profile.apparence.verrouille end, + set = function(info, value) OvaleOptions.db.profile.apparence.verrouille = value end + }, + vertical = + { + order = 9, + type = "toggle", + name = L["Vertical"], + get = function(info) return OvaleOptions.db.profile.apparence.vertical end, + set = function(info, value) OvaleOptions.db.profile.apparence.vertical = value; Ovale:UpdateFrame() end + }, + alpha = + { + order = 9.5, + type = "range", + name = L["Opacité des icônes"], + min = 0, max = 100, step = 5, + get = function(info) return OvaleOptions.db.profile.apparence.alpha * 100 end, + set = function(info, value) OvaleOptions.db.profile.apparence.alpha = value/100; Ovale.frame.frame:SetAlpha(value/100) end + }, + optionsAlpha = + { + order = 9.5, + type = "range", + name = L["Opacité des options"], + min = 0, max = 100, step = 5, + get = function(info) return OvaleOptions.db.profile.apparence.optionsAlpha * 100 end, + set = function(info, value) OvaleOptions.db.profile.apparence.optionsAlpha = value/100; Ovale.frame.content:SetAlpha(value/100) end + }, + predictif = + { + order = 10, + type = "toggle", + name = L["Prédictif"], + desc = L["Affiche les deux prochains sorts et pas uniquement le suivant"], + get = function(info) return OvaleOptions.db.profile.apparence.predictif end, + set = function(info, value) OvaleOptions.db.profile.apparence.predictif = value; Ovale:UpdateFrame() end + }, + moving = + { + order = 11, + type = "toggle", + name = L["Défilement"], + desc = L["Les icônes se déplacent"], + get = function(info) return OvaleOptions.db.profile.apparence.moving end, + set = function(info, value) OvaleOptions.db.profile.apparence.moving = value; Ovale:UpdateFrame() end + }, + hideEmpty = + { + order = 12, + type = "toggle", + name = L["Cacher bouton vide"], + get = function(info) return OvaleOptions.db.profile.apparence.hideEmpty end, + set = function(info, value) OvaleOptions.db.profile.apparence.hideEmpty = value; Ovale:UpdateFrame() end + }, + targetHostileOnly = + { + order = 13, + type = "toggle", + name = L["Cacher si cible amicale ou morte"], + get = function(info) return OvaleOptions.db.profile.apparence.targetHostileOnly end, + set = function(info, value) OvaleOptions.db.profile.apparence.targetHostileOnly = value; Ovale:UpdateFrame() end + }, + highlightIcon = + { + order = 14, + type = "toggle", + name = L["Illuminer l'icône"], + desc = L["Illuminer l'icône quand la technique doit être spammée"], + get = function(info) return OvaleOptions.db.profile.apparence.highlightIcon end, + set = function(info, value) OvaleOptions.db.profile.apparence.highlightIcon = value; Ovale:UpdateFrame() end + }, + clickThru = + { + order = 15, + type = "toggle", + name = L["Ignorer les clics souris"], + get = function(info) return OvaleOptions.db.profile.apparence.clickThru end, + set = function(info, value) OvaleOptions.db.profile.apparence.clickThru = value; Ovale:UpdateFrame() end + }, + latencyCorrection = + { + order = 16, + type = "toggle", + name = L["Correction de la latence"], + get = function(info) return OvaleOptions.db.profile.apparence.latencyCorrection end, + set = function(info, value) OvaleOptions.db.profile.apparence.latencyCorrection = value end + }, + hideVehicule = + { + order = 17, + type = "toggle", + name = L["Cacher dans les véhicules"], + get = function(info) return OvaleOptions.db.profile.apparence.hideVehicule end, + set = function(info, value) OvaleOptions.db.profile.apparence.hideVehicule = value end + }, + flashIcon = + { + order = 18, + type = "toggle", + name = L["Illuminer l'icône quand le temps de recharge est écoulé"], + get = function(info) return OvaleOptions.db.profile.apparence.flashIcon end, + set = function(info, value) OvaleOptions.db.profile.apparence.flashIcon = value; Ovale:UpdateFrame() end + }, + targetText = + { + order = 19, + type = "input", + name = L["Caractère de portée"], + desc = L["Ce caractère est affiché dans un coin de l'icône pour indiquer si la cible est à portée"], + get = function(info) return OvaleOptions.db.profile.apparence.targetText end, + set = function(info, value) OvaleOptions.db.profile.apparence.targetText = value; Ovale:UpdateFrame() end + } + } + }, + code = + { + name = L["Code"], + type = "group", + args = + { + code = + { + order = 1, + type = "input", + multiline = 15, + name = L["Code"], + get = function(info) + return string.gsub(OvaleOptions.db.profile.code, "\t", " ") + end, + set = function(info,v) + OvaleOptions.db.profile.code = v + Ovale.needCompile = true + end, + width = "full" + } + } + }, + actions = + { + name = "Actions", + type = "group", + args = + { + show = + { + order = -1, + type = "execute", + name = L["Afficher la fenêtre"], + guiHidden = true, + func = function() + OvaleOptions.db.profile.display = true + Ovale:UpdateVisibility() + end + }, + hide = + { + order = -2, + type = "execute", + name = L["Cacher la fenêtre"], + guiHidden = true, + func = function() + OvaleOptions.db.profile.display = false + Ovale.frame:Hide() + end + }, + config = + { + name = "Configuration", + type = "execute", + func = function() Ovale:AfficherConfig() end + }, + code = + { + name = "Code", + type = "execute", + func = function() Ovale:AfficherCode() end + }, + debug = + { + order = -3, + name = "Debug", + type = "execute", + func = function() + for i=1,10 do Ovale:Print(i.."="..UnitPower("player", i)) end + Ovale:Print(OvaleState.state.eclipse) + end + }, + talent = + { + order = -4, + name = "List talent id", + type = "execute", + func = function() + for k,v in pairs(OvaleData.talentNameToId) do + Ovale:Print(k.."="..v) + end + end + }, + targetbuff = + { + order = -5, + name = "List target buff and debuff spell id", + type = "execute", + func = function() + Ovale:DebugListAura("target", "HELPFUL") + Ovale:DebugListAura("target", "HARMFUL") + end + }, + buff = + { + order = -6, + name = "List player buff and debuff spell id", + type = "execute", + func = function() + Ovale:DebugListAura("player", "HELPFUL") + Ovale:DebugListAura("player", "HARMFUL") + end + }, + glyph = + { + order = -7, + name = "List player glyphs", + type = "execute", + func = function() + for i=1,GetNumGlyphs() do + local name, level, enabled, texture, spellId = GetGlyphInfo(i) + if spellId then Ovale:Print(name..": "..spellId.." ("..tostring(enabled)..")") end + end + end + }, + spell = + { + order = -8, + name = "List player spells", + type = "execute", + func = function() + local book=BOOKTYPE_SPELL + while true do + local i=1 + while true do + local skillType, spellId = GetSpellBookItemInfo(i, book) + if not spellId then + break + end + local spellName = GetSpellBookItemName(i, book) + Ovale:Print(spellName..": "..spellId) + i = i + 1 + end + if book == BOOKTYPE_SPELL then + book = BOOKTYPE_PET + else + break + end + end + end + } + } + } + } +} +--</private-static-properties> + +--<public-static-methods> +function OvaleOptions:OnInitialize() + +end + +function OvaleOptions:FirstInit() + if self.firstInit then + return + end + + self.firstInit = true + + local localizedClass, englishClass = UnitClass("player") + self.db = LibStub("AceDB-3.0"):New("OvaleDB", + { + profile = + { + display = true, + code = Ovale.defaut[englishClass], + left = 500, + top = 500, + check = {}, + list = {}, + apparence = {enCombat=false, iconScale = 2, secondIconScale = 1, margin = 4, fontScale = 0.5, iconShiftX = 0, iconShiftY = 0, + smallIconScale=1, raccourcis=true, numeric=false, avecCible = false, + verrouille = false, vertical = false, predictif=false, highlightIcon = true, clickThru = false, + latencyCorrection=true, hideVehicule=false, flashIcon=true, targetText = "●", alpha = 1, + optionsAlpha = 1, updateInterval=0.1} + } + }) + + options.args.profile = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db) + AceConfig:RegisterOptionsTable("Ovale", options.args.code) + AceConfig:RegisterOptionsTable("Ovale Actions", options.args.actions, "Ovale") + AceConfig:RegisterOptionsTable("Ovale Profile", options.args.profile) + AceConfig:RegisterOptionsTable("Ovale Apparence", options.args.apparence) + + AceConfigDialog:AddToBlizOptions("Ovale", "Ovale") + AceConfigDialog:AddToBlizOptions("Ovale Profile", "Profile", "Ovale") + AceConfigDialog:AddToBlizOptions("Ovale Apparence", "Apparence", "Ovale") + + self.db.RegisterCallback( self, "OnNewProfile", "HandleProfileChanges" ) + self.db.RegisterCallback( self, "OnProfileReset", "HandleProfileChanges" ) + self.db.RegisterCallback( self, "OnProfileChanged", "HandleProfileChanges" ) + self.db.RegisterCallback( self, "OnProfileCopied", "HandleProfileChanges" ) + + if self.db.profile.code then + Ovale.needCompile = true + end +end + +function OvaleOptions:HandleProfileChanges() + if self.firstInit then + if (self.db.profile.code) then + Ovale.needCompile = true + end + end +end + +function OvaleOptions:OnEnable() + self:FirstInit() + +end + +function OvaleOptions:GetApparence() + self:FirstInit() + return self.db.profile.apparence +end + +function OvaleOptions:GetProfile() + self:FirstInit() + return self.db.profile +end + +--</public-static-methods> diff --git a/OvaleSpellDamage.lua b/OvaleSpellDamage.lua new file mode 100644 index 0000000..6dea01a --- /dev/null +++ b/OvaleSpellDamage.lua @@ -0,0 +1,35 @@ +-- Add-on that registers how many damage made the last spell cast by the player + +OvaleSpellDamage = LibStub("AceAddon-3.0"):NewAddon("OvaleSpellDamage", "AceEvent-3.0") + +--<public-static-properties> +OvaleSpellDamage.value = {} +OvaleSpellDamage.playerGUID = nil +--</public-static-properties> + +-- Events +--<public-static-methods> +function OvaleSpellDamage:OnEnable() + self.playerGUID = UnitGUID("player") + self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") +end + +function OvaleSpellDamage:OnDisable() + self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") +end + +function OvaleSpellDamage:COMBAT_LOG_EVENT_UNFILTERED(event, ...) + local time, event, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags = select(1, ...) + + if sourceGUID == self.playerGUID then + if string.find(event, "SPELL_PERIODIC_DAMAGE")==1 or string.find(event, "SPELL_DAMAGE")==1 then + local spellId, spellName, spellSchool, amount = select(12, ...) + self.value[spellId] = amount + end + end +end + +function OvaleSpellDamage:Get(spellId) + return self.value[spellId] +end +--</public-static-methods> diff --git a/OvaleState.lua b/OvaleState.lua new file mode 100644 index 0000000..854c943 --- /dev/null +++ b/OvaleState.lua @@ -0,0 +1,404 @@ +-- Keep the current state in the simulation + +OvaleState = {} + +--<public-static-properties> +--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 +--The spell being cast +OvaleState.currentSpellId = nil +--Allows to debug auras +OvaleState.traceAura = false +OvaleState.maintenant = nil +OvaleState.currentTime = nil +OvaleState.attenteFinCast = nil +OvaleState.startCast = nil +OvaleState.endCast = nil +OvaleState.gcd = 1.5 +--</public-static-properties> + +--<private-static-properties> +local UnitGUID = UnitGUID +--</private-static-properties> + +--<private-static-methods> +local function nilstring(text) + if text == nil then + return "nil" + else + return text + end +end +--</private-static-methods> + +--<public-static-methods> +function OvaleState:StartNewFrame() + self.maintenant = GetTime() + self.gcd = OvaleData:GetGCD() +end + +function OvaleState:Reset() + self.serial = self.serial + 1 + self.currentTime = self.maintenant + self.currentSpellId = nil + self.attenteFinCast = self.maintenant + self.state.combo = GetComboPoints("player") + self.state.mana = UnitPower("player") + self.state.shard = UnitPower("player", 7) + self.state.eclipse = UnitPower("player", 8) + self.state.holy = UnitPower("player", 9) + if OvaleData.className == "DEATHKNIGHT" then + for i=1,6 do + self.state.rune[i].type = GetRuneType(i) + local start, duration, runeReady = GetRuneCooldown(i) + if runeReady then + self.state.rune[i].cd = start + else + self.state.rune[i].cd = duration + start + if self.state.rune[i].cd<0 then + self.state.rune[i].cd = 0 + end + end + end + end + for k,v in pairs(self.state.cd) do + v.start = nil + v.duration = nil + 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 + +-- Cast a spell in the simulator +-- spellId : the spell id +-- startCast : temps du cast +-- endCast : fin du cast +-- nextCast : temps auquel le prochain sort peut tre lanc (>=endCast, avec le GCD) +-- nocd : le sort ne dclenche pas son cooldown +function OvaleState:AddSpellToStack(spellId, startCast, endCast, nextCast, nocd, targetGUID) + if not spellId or not targetGUID then + return + end + + local newSpellInfo = OvaleData.spellInfo[spellId] + + --On enregistre les infos sur le sort en cours + self.attenteFinCast = nextCast + self.currentSpellId = spellId + self.startCast = startCast + self.endCast = endCast + --Temps actuel de la simulation : un peu aprs le dernier cast (ou maintenant si dans le pass) + if startCast>=self.maintenant then + self.currentTime = startCast+0.1 + else + self.currentTime = self.maintenant + end + + if Ovale.trace then + Ovale:Print("add spell "..spellId.." at "..startCast.." currentTime = "..self.currentTime.. " nextCast="..self.attenteFinCast .. " endCast="..endCast) + end + + --Effet du sort au moment du dbut du cast + --(donc si cast dj commenc, on n'en tient pas compte) + if startCast >= self.maintenant then + if newSpellInfo then + if newSpellInfo.inccounter then + local id = newSpellInfo.inccounter + self.state.counter[id] = self:GetCounterValue(id) + 1 + end + + if newSpellInfo.resetcounter then + self.state.counter[newSpellInfo.resetcounter] = 0 + end + end + end + + --Effet du sort au moment o il est lanc + --(donc si il est dj lanc, on n'en tient pas compte) + if endCast >= self.maintenant then + --Mana + local _, _, _, cost = GetSpellInfo(spellId) + if cost then + self.state.mana = self.state.mana - cost + end + + if newSpellInfo then + + if newSpellInfo.mana then + self.state.mana = self.state.mana - newSpellInfo.mana + end + + --Points de combo + if newSpellInfo.combo then + self.state.combo = self.state.combo + newSpellInfo.combo + if self.state.combo<0 then + self.state.combo = 0 + end + end + --Runes + if newSpellInfo.frost then + self:AddRune(startCast, 3, newSpellInfo.frost) + end + if newSpellInfo.death then + self:AddRune(startCast, 4, newSpellInfo.death) + end + if newSpellInfo.blood then + self:AddRune(startCast, 1, newSpellInfo.blood) + end + if newSpellInfo.unholy then + self:AddRune(startCast, 2, newSpellInfo.unholy) + end + if newSpellInfo.holy then + self.state.holy = self.state.holy + newSpellInfo.holy + if self.state.holy < 0 then + self.state.holy = 0 + elseif self.state.holy > 3 then + self.state.holy = 3 + end + end + if newSpellInfo.shard then + self.state.shard = self.state.shard + newSpellInfo.shard + if self.state.shard < 0 then + self.state.shard = 0 + elseif self.state.shard > 3 then + self.state.shard = 3 + end + end + end + end + + -- Effets du sort au moment o il atteint sa cible + if newSpellInfo then + -- Cooldown du sort + local cd = self:GetCD(spellId) + if cd then + cd.start = startCast + cd.duration = newSpellInfo.cd + --Pas de cooldown + if nocd then + cd.duration = 0 + end + --On vrifie si le buff "buffnocd" est prsent, auquel cas le CD du sort n'est pas dclench + if newSpellInfo.buffnocd and not nocd then + local buffAura = self:GetAura("player", newSpellInfo.buffnocd) + if self.traceAura then + if buffAura then + Ovale:Print("buffAura stacks = "..buffAura.stacks.." start="..nilstring(buffAura.start).." ending = "..nilstring(buffAura.ending)) + Ovale:Print("startCast = "..startCast) + else + Ovale:Print("buffAura = nil") + end + self.traceAura = false + end + if buffAura and buffAura.stacks>0 and buffAura.start and buffAura.start<=startCast and (not buffAura.ending or buffAura.ending>startCast) then + cd.duration = 0 + end + end + if newSpellInfo.targetlifenocd and not nocd then + --TODO + if UnitHealth("target")/UnitHealthMax("target")*100<newSpellInfo.targetlifenocd then + cd.duration = 0 + end + end + cd.enable = 1 + if newSpellInfo.toggle then + cd.toggled = 1 + end + end + + if newSpellInfo.eclipse then + self.state.eclipse = self.state.eclipse + newSpellInfo.eclipse + if self.state.eclipse < -100 then + self.state.eclipse = -100 + self:AddEclipse(endCast, 48518) + elseif self.state.eclipse > 100 then + self.state.eclipse = 100 + self:AddEclipse(endCast, 48517) + end + end + if newSpellInfo.starsurge then + local buffAura = self:GetAura("player", 48517) --Solar + if buffAura and buffAura.stacks>0 then + Ovale:Log("starsurge with solar buff = " .. (- newSpellInfo.starsurge)) + self.state.eclipse = self.state.eclipse - newSpellInfo.starsurge + else + buffAura = self:GetAura("player", 48518) --Lunar + if buffAura and buffAura.stacks>0 then + Ovale:Log("starsurge with lunar buff = " .. newSpellInfo.starsurge) + self.state.eclipse = self.state.eclipse + newSpellInfo.starsurge + elseif self.state.eclipse < 0 then + Ovale:Log("starsurge with eclipse < 0 = " .. (- newSpellInfo.starsurge)) + self.state.eclipse = self.state.eclipse - newSpellInfo.starsurge + else + Ovale:Log("starsurge with eclipse > 0 = " .. newSpellInfo.starsurge) + self.state.eclipse = self.state.eclipse + newSpellInfo.starsurge + end + end + if self.state.eclipse < -100 then + self.state.eclipse = -100 + self:AddEclipse(endCast, 48518) + elseif self.state.eclipse > 100 then + self.state.eclipse = 100 + self:AddEclipse(endCast, 48517) + end + end + + --Auras causs par le sort + if newSpellInfo.aura then + for target, targetInfo in pairs(newSpellInfo.aura) do + for filter, filterInfo in pairs(targetInfo) do + for auraSpellId, spellData in pairs(filterInfo) do + local newAura + if target == "target" then + newAura = self:NewAura(targetGUID, auraSpellId) + else + newAura = self:NewAura(UnitGUID(target), auraSpellId) + end + newAura.mine = true + local duration = spellData + local stacks = duration + --Optionnellement, on va regarder la dure du buff + if auraSpellId and OvaleData.spellInfo[auraSpellId] and OvaleData.spellInfo[auraSpellId].duration then + duration = OvaleData.spellInfo[auraSpellId].duration + elseif stacks~="refresh" and stacks > 0 then + stacks = 1 + end + if stacks=="refresh" then + if newAura.ending then + newAura.ending = endCast + duration + end + elseif stacks<0 and newAura.ending then + --Buff are immediatly removed when the cast ended, do not need to do it again + if filter~="HELPFUL" or target~="player" or endCast>=self.maintenant then + newAura.stacks = newAura.stacks + stacks + if Ovale.trace then + Ovale:Print("removing one stack of "..auraSpellId.." because of ".. spellId.." to ".. newAura.stacks) + end + --Plus de stacks, on supprime l'aura + if newAura.stacks<=0 then + Ovale:Log("Aura is completly removed") + newAura.stacks = 0 + newAura.ending = 0 + end + end + elseif newAura.ending and newAura.ending >= endCast then + newAura.ending = endCast + duration + newAura.stacks = newAura.stacks + stacks + else + newAura.start = endCast + newAura.ending = endCast + duration + newAura.stacks = stacks + end + if Ovale.trace then + if auraSpellId then + Ovale:Print(spellId.." adding "..stacks.." aura "..auraSpellId.." to "..target.." "..filter.." "..newAura.start..","..newAura.ending) + else + Ovale:Print("adding nil aura") + end + end + end + end + end + end + end +end + +function OvaleState:AddRune(time, type, value) + if value<0 then + for i=1,6 do + if (self.state.rune[i].type == type or self.state.rune[i].type==4)and self.state.rune[i].cd<=time then + self.state.rune[i].cd = time + 10 + end + end + else + + end +end + +function OvaleState:GetCounterValue(id) + if self.state.counter[id] then + return self.state.counter[id] + else + return 0 + end +end + +function OvaleState:GetCD(spellId) + if not spellId then + return nil + end + + if OvaleData.spellInfo[spellId] and OvaleData.spellInfo[spellId].cd then + local cdname + if OvaleData.spellInfo[spellId].sharedcd then + cdname = OvaleData.spellInfo[spellId].sharedcd + else + cdname = spellId + end + if not self.state.cd[cdname] then + self.state.cd[cdname] = {} + end + return self.state.cd[cdname] + else + return nil + end +end + +function OvaleState:AddEclipse(endCast, spellId) + local newAura = self:NewAura(OvaleGUID.player, spellId) + newAura.start = endCast + 0.5 + newAura.stacks = 1 + newAura.ending = nil +end + +function OvaleState:GetAura(target, spellId, mine) + local guid = UnitGUID(target) + + if self.aura[guid] and self.aura[guid][spellId] and self.aura[guid][spellId].serial == self.serial then + return self.aura[guid][spellId] + else + return OvaleAura:GetAuraByGUID(guid, spellId, mine, target) + end +end + +function OvaleState:GetExpirationTimeOnAnyTarget(spellId) + local starting, ending = OvaleAura:GetExpirationTimeOnAnyTarget(spellId) + for unitId,auraTable in pairs(self.aura) do + local aura = auraTable[spellId] + if aura and aura.serial == self.serial then + local newEnding = aura.ending + local newStarting = aura.start + if newStarting and (not staring or newStarting < starting) then + starting = newStarting + end + if newEnding and (not ending or newEnding > ending) then + ending = newEnding + end + end + end + return starting, ending +end + +function OvaleState:NewAura(guid, spellId) + if not self.aura[guid] then + self.aura[guid] = {} + end + if not self.aura[guid][spellId] then + self.aura[guid][spellId] = {} + end + local myAura = self.aura[guid][spellId] + myAura.serial = self.serial + myAura.mine = true + myAura.gain = self.currentTime + return myAura +end +--</public-static-methods> diff --git a/OvaleSwing.lua b/OvaleSwing.lua index c372d67..37b410a 100644 --- a/OvaleSwing.lua +++ b/OvaleSwing.lua @@ -18,6 +18,22 @@ Modifed for Ovale ]] +OvaleSwing = LibStub("AceAddon-3.0"):NewAddon("OvaleSwing", "AceEvent-3.0") + +--<public-static-properties> +OvaleSwing.ohNext = nil +OvaleSwing.dual = false +OvaleSwing.starttime = nil +OvaleSwing.duration = nil +OvaleSwing.ohStartTime = nil +OvaleSwing.ohDuration = nil +OvaleSwing.delay = nil +OvaleSwing.startdelay = nil +OvaleSwing.swingmode = nil + +--</public-static-properties> + +--<private-static-properties> local autoshotname = GetSpellInfo(75) local resetspells = { } @@ -31,11 +47,10 @@ local _, playerclass = UnitClass('player') local unpack = unpack local math_abs = math.abs local GetTime = GetTime - -OvaleSwing = LibStub("AceAddon-3.0"):NewAddon("OvaleSwing", "AceEvent-3.0") - local BOOKTYPE_SPELL = BOOKTYPE_SPELL +--</private-static-properties> +--<public-static-methods> function OvaleSwing:OnEnable() self.ohNext = false -- fired when autoattack is enabled/disabled. @@ -86,7 +101,7 @@ end function OvaleSwing:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, eventName, srcGUID, srcName, srcFlags, dstName, dstGUID, dstFlags, ...) if srcName == UnitName("player") then if eventName == "SWING_DAMAGE" or eventName == "SWING_MISSED" then - self:MeleeSwing(Ovale.maintenant) + self:MeleeSwing(OvaleState.maintenant) end end end @@ -108,7 +123,7 @@ end function OvaleSwing:UNIT_SPELLCAST_SUCCEEDED(event, unit, spell) if unit == "player" then if resetspells[spell] then - self:MeleeSwing(Ovale.maintenant) + self:MeleeSwing(OvaleState.maintenant) end if delayspells[spell] and self.startdelay then self.delay = GetTime() - self.startdelay @@ -203,3 +218,4 @@ function OvaleSwing:GetNext(which) end end end +--</public-static-methods> diff --git a/compiler.pl b/compiler.pl new file mode 100644 index 0000000..2cfce11 --- /dev/null +++ b/compiler.pl @@ -0,0 +1,228 @@ +=c +--<private-static-properties> +--</private-static-properties> + +--<private-static-methods> +--</private-static-methods> + +--<public-static-properties> +--</public-static-properties> + +--<public-static-methods> +--</public-static-methods> + +--<public-methods> +--</public-methods> + +--<public-properties> +--</public-properties> +=cut + +$p{Skada}{current} = true; +$p{Skada}{total} = true; +$m{Skada}{NewModule} = true; +$m{Skada}{RemoveMode} = true; +$m{Skada}{get_player} = true; +$m{Skada}{AddMode} = true; + +$p{Recount}{db} = true; +$p{Recount}{db2} = true; +$m{Recount}{AddModeTooltip} = true; +$m{Recount}{AddAmount} = true; +$m{Recount}{AddSortedTooltipData} = true; + +$m{AceGUI}{RegisterWidgetType} = true; +$m{AceGUI}{RegisterAsContainer} = true; +$m{AceGUI}{ClearFocus} = true; + +$m{DEFAULT_CHAT_FRAME}{AddMessage} = true; + +$m{LRC}{GetRange} = true; + +$m{AceConfigDialog}{Open} = true; +$m{AceConfigDialog}{AddToBlizOptions} = true; +$m{AceConfigDialog}{SetDefaultSize} = true; + +$m{Masque}{Group} = true; + +$m{AceConfig}{RegisterOptionsTable} = true; + +$m{GameTooltip}{SetText} = true; +$m{GameTooltip}{ClearLines} = true; +$m{GameTooltip}{SetOwner} = true; +$m{GameTooltip}{AddDoubleLine} = true; +$m{GameTooltip}{Show} = true; +$m{GameTooltip}{Hide} = true; +$m{GameTooltip}{AddLine} = true; + +opendir(DIR, "."); +while (defined($r = readdir(DIR))) +{ + if ($r =~ m/(Ovale.*)\.lua$/) + { + my $class = $1; + open(F, "<", $r); + undef $/; + my $content = <F>; + close(F); + + my %psp = {}; + my %psm = {}; + my %pp = {}; + my %pm = {}; + + if ($content =~ m/--inherits (\w+)/) + { + if ($1 eq 'ActionButtonTemplate') + { + $m{$class}{Show} = true; + $m{$class}{Hide} = true; + $m{$class}{SetChecked} = true; + $m{$class}{CreateFontString} = true; + $m{$class}{RegisterForClicks} = true; + $m{$class}{EnableMouse} = true; + $m{$class}{GetName} = true; + } + if ($1 eq 'Frame') + { + $m{$class}{StartMoving} = true; + $m{$class}{StopMovingOrSizing} = true; + $m{$class}{GetLeft} = true; + $m{$class}{GetTop} = true; + } + } + + if ($content =~ m/$class\s*=\s*LibStub/) + { + $pm{'RegisterEvent'} = true; + $pm{'UnregisterEvent'} = true; + $m{$class}{Print} = true; + } + + if ($content =~ m/<private-static-properties>(.*)<\/private-static-properties>/s) + { + my $psp = $1; + while ($psp =~ m/local (\w+)\s*=/g) + { + $psp{$1} = true; + } + } + + if ($content =~ m/<private-static-methods>(.*)<\/private-static-methods>/s) + { + my $psm = $1; + while ($psm =~ m/local function (\w+)\s*=/g) + { + $psm{$1} = true; + } + } + + if ($content =~ m/<public-static-properties>(.*)<\/public-static-properties>/s) + { + my $sp = $1; + while ($sp =~ m/${class}\.(\w+)\s*=/g) + { + $sp{$class}{$1} = true; + } + } + + if ($content =~ m/<public-static-methods>(.*)<\/public-static-methods>/s) + { + my $sm = $1; + while ($sm =~ m/function\s+$class:(\w+)\s*\(/g) + { + $sm{$class}{$1} = true; + delete $m{$class}{$1} + } + } + + if ($content =~ m/<public-methods>(.*)<\/public-methods>/s) + { + my $m = $1; + while ($m =~ m/local function (\w+)\(self/g) + { + $m{$class}{$1} = true; + delete $sm{$class}{$1} + } + } + + if ($content =~ m/<public-properties>(.*)<\/public-properties>/s) + { + my $p = $1; + while ($p =~ m/self\.(\w+)/g) + { + $p{$class}{$1} = true; + } + } + + while ($content =~ m/\b([A-Z]\w+)\.(\w+)/g) + { + unless ($sp{$1}{$2} or $p{$1}{$2}) + { + $sp{$1}{$2} = $class; + } + } + + while ($content =~ m/\b([A-Z]\w+)\:(\w+)/g) + { + unless ($sm{$1}{$2} or $m{$1}{$2}) + { + $sm{$1}{$2} = $class; + } + } + + while ($content =~ m/self\.([a-z]\w*)/g) + { + #if ($class eq 'OvaleSwing') + #{ + # print $1," ",$sp{$class}{$1}," ",$pp{$1}, " ", $p{$class}{$1},"\n"; + #} + unless ($sp{$class}{$1} eq true or $pp{$1} eq true or $p{$class}{$1} eq true) + { + print "La classe $class ne contient pas la proprit $1\n"; + } + } + + while ($content =~ m/self\:(\w+)/g) + { + unless ($sm{$class}{$1} eq true or $pm{$1} eq true or $m{$class}{$1} eq true) + { + print "La classe $class ne contient pas la mthode $1\n"; + } + } + } +} + +for my $class (keys %sm) +{ + for my $method (keys %{$sm{$class}}) + { + unless ($sm{$class}{$method} eq true) + { + print "public static $class:$method $sm{$class}{$method}\n"; + } + } +} + +for my $class (keys %m) +{ + for my $method (keys %{$m{$class}}) + { + unless ($m{$class}{$method} eq true) + { + print "public $class:$method $m{$class}{$method}\n"; + } + } +} + +for my $class (keys %sp) +{ + for my $prop (keys %{$sp{$class}}) + { + unless ($sp{$class}{$prop} eq true) + { + print "public static $class.$prop $sp{$class}{$prop}\n"; + } + } +} + diff --git a/defaut/Pretre.lua b/defaut/Pretre.lua index 1f8f513..f3742b9 100644 --- a/defaut/Pretre.lua +++ b/defaut/Pretre.lua @@ -120,10 +120,10 @@ AddIcon help=mana mastery=3 } # Add Focus Target Monitor for Multi Dotting -AddIcon mastery=3 +AddIcon mastery=3 target=focus { - if TargetDebuffExpires(SHADOWWORDPAIN 1.5 mine=1 target=focus ) and TargetDeadIn(more 10) Spell(SHADOWWORDPAIN target=focus) - if TargetDebuffExpires(VAMPIRICTOUCH 3 mine=1 haste=spell target=focus) and TargetDeadIn(more 8) Spell(VAMPIRICTOUCH target=focus) + if TargetDebuffExpires(SHADOWWORDPAIN 1.5 mine=1) and TargetDeadIn(more 10) Spell(SHADOWWORDPAIN) + if TargetDebuffExpires(VAMPIRICTOUCH 3 mine=1 haste=spell) and TargetDeadIn(more 8) Spell(VAMPIRICTOUCH) } ]]