-- Masks -- These look a little ugly but the idea is decent... lazyr.masks = {} -- klugy, but hey lazyr.masks.alreadyInsideInterruptExceptionCriteria = false function lazyr.masks.negWrapper(f, negate) return function() local r = f() return ((r and not negate) or (not r and negate)) end end -- returns a super mask. Returns true if any of the given masks are true (an "OR"). -- however if negate is true, then returns true only if ALL of then given masks are false ("AND") function lazyr.masks.maskGroup(masks, negate) return function() if (not negate) then for idx, mask in masks do if (mask()) then return true end end return false else for idx, mask in masks do if (mask()) then return false end end return true end end end function lazyr.masks.ComboPoints(cp, gtLtEq) cp = tonumber(cp) return function() if (not gtLtEq or gtLtEq == "") then return (GetComboPoints() >= cp) end if (gtLtEq == ">") then return (GetComboPoints() > cp) elseif (gtLtEq == "=") then return (GetComboPoints() == cp) else return (GetComboPoints() < cp) end end end function lazyr.masks.IsBeingGanked() return function() return lazyr.ganked end end function lazyr.masks.DebuffSpace() return function() if UnitExists("target") then for i=1,16 do s=UnitDebuff("target", i) if (not s) then return true end end end return false end end function lazyr.masks.IsImmune(action) return function() if (lazyr.perPlayerConf.Immunities[action] and lazyr.perPlayerConf.Immunities[action][UnitName("target")]) then if (lazyr.perPlayerConf.showReasonForTargetCCd) then lazyr.p("-ifTargetImmune: "..UnitName("target").." has immunity to "..action) end return true end return false end end function lazyr.masks.IsFlagRunner() return function() if (not lrLocale.BGWGTEXT0) then lazyr.p("Sorry, ifFlagRunner not supported for your locale.") return false end if (UnitName("target")==lazyr.flagHolder) and UnitExists("target") then return true else return false end end end function lazyr.masks.IsFlaggedPVP(unit) return function() if unit ~= "Target" then if UnitIsPVP("player") then return true else return false end else if (UnitIsPVP("target") and UnitIsEnemy("target","player") and UnitExists("target")) then return true else return false end end end end function lazyr.masks.IsDueling() return function() return lazyr.InDuel end end function lazyr.masks.IsBeingAttackedBy(num, gtLtEq) num = tonumber(num) return function() if (not gtLtEq or gtLtEq == "") then return (lazyr.numberOfAttackers >= num) end if (gtLtEq == ">") then return (lazyr.numberOfAttackers > num) elseif (gtLtEq == "=") then return (lazyr.numberOfAttackers == num) else return (lazyr.numberOfAttackers < num) end end end function lazyr.masks.IsTargetOfTarget() return function() return UnitIsUnit("player", "targettarget") end end function lazyr.masks.IsTargetOfTargetClass(class) return function() return (class == UnitClass("targettarget")) end end -- :-( function lazyr.masks.IsStealthed() local icon, name, active, castable = GetShapeshiftFormInfo(1) return (active == 1) end function lazyr.masks.IsStealthedMask() return function() return lazyr.masks.IsStealthed() end end function lazyr.masks.BehindAttackHasNotFailedRecently() return function() return ((GetTime() - lazyr.behindAttackLastFailedAt) >= .3) end end function lazyr.masks.BehindAttackFailedRecently() return function() return ((GetTime() - lazyr.behindAttackLastFailedAt) < .3) end end function lazyr.masks.InFrontAttackHasNotFailedRecently() return function() return ((GetTime() - lazyr.inFrontAttackLastFailedAt) >= .3) end end function lazyr.masks.InFrontAttackFailedRecently() return function() return ((GetTime() - lazyr.inFrontAttackLastFailedAt) < .3) end end function lazyr.masks.InCooldown(action) return function() local actionInfo = lazyr.ParseArg(action) if (not actionInfo) then return false end local action = actionInfo[1] local start, duration, enable = GetActionCooldown(action:GetSlot()); if ( (duration - (GetTime() - start)) > 1) then return true else return false end end end -- :-( function lazyr.masks.FindTalentPoints(icon) -- Okay, there is no event that gets fired when talents have changed, so -- normally we'd need to scan the talent tree every single time. -- Instead, for fun, we cache talent point lookups for 1 minute. Not sure -- how much this really helps performance, but hey. local cacheInfo = lazyr.talentCache[icon] if (cacheInfo) then local time = cacheInfo[1] local rank = cacheInfo[2] if (time and time > (GetTime() - 60)) then return rank end end rank = 0 for i = 1, GetNumTalentTabs() do for j = 1, GetNumTalents(i) do local name, thisIcon, _, _, rank, max = GetTalentInfo(i, j) if (thisIcon and string.find(thisIcon, icon)) then lazyr.talentCache[icon] = {GetTime(), rank} return rank end end end lazyr.talentCache[icon] = {GetTime(), 0} return 0 end -- :-( function lazyr.masks.CalculateBaseEviscDamage(cp) -- find eviscerate rank -- lookup damage cp using damage table local rank = lazyr.actions.eviscerate:GetRank() if (rank == 0) then return false end local eviscDamage = lazyr.eviscDamage[rank][cp] if (not eviscDamage) then lazyr.p("strange, damage lookup failed") return false end --origEviscDamage = eviscDamage -- adjust for Improved Eviscerate, if invested local ieAdjust = { 1.05, 1.1, 1.15 } local tpts = lazyr.masks.FindTalentPoints("Ability_Rogue_Eviscerate") if (tpts > 0) then eviscDamage = eviscDamage * ieAdjust[tpts] end -- adjust for Aggression, if invested local aggrAdjust = { 1.02, 1.04, 1.06 } local tpts = lazyr.masks.FindTalentPoints("Ability_Racial_Avatar") if (tpts > 0) then eviscDamage = eviscDamage * aggrAdjust[tpts] end return eviscDamage end -- :-( function lazyr.masks.CalculateObservedEviscDamage(cp) if (lazyr.perPlayerConf.useEviscTracking) then local observedDamage, observedCt = lazyr.et.GetEviscTrackingInfo(cp) if (observedCt > 0) then --lazyr.d("Calculate Evisc Dmg: Using the OBSERVED Evisc ("..cp.."cp) damage of: "..observedDamage) return observedDamage end end local dmg = lazyr.masks.CalculateBaseEviscDamage(cp) --lazyr.d("Calculate Evisc Dmg: Using the OPTIMAL Evisc ("..cp.."cp) damage of: "..dmg) return dmg end function lazyr.masks.IsEviscKillShot(assumeCBActive, goalPct) return function() local cp = GetComboPoints() if (cp == 0) then return false end local hp = lazyr.masks.GetUnitHealth("target") -- adjust hp for goalPct if (goalPct ~= 100) then hp = hp * (goalPct / 100) end local eviscDamage = lazyr.masks.CalculateObservedEviscDamage(cp) -- adjust for Cold Blood, if we're asked to, or if active if (assumeCBActive or lazyr.masks.HasBuffOrDebuff("player", "buff", lazyr.actions.coldBlood.texture, lrLocale.BUFF_TTS.coldBlood)) then -- Cold Blood guarantees a crit (if it hits) eviscDamage = eviscDamage * 2 end --lazyr.d("Adjusted evisc dmg: "..origEviscDamage.." vs "..eviscDamage) --lazyr.d("Avg evisc dmg with "..cp.." combo points is "..eviscDamage..", vs: "..hp) if (hp <= eviscDamage) then if (cp < 5) then lazyr.d("Early eviscerate! Kill shot!") end return true else return false end end end -- :-( -- supported unitIds: player, (enemy) target function lazyr.masks.GetUnitHealth(unitId, wantPct) if (unitId == "player") then if (wantPct) then return (UnitHealth(unitId) / UnitHealthMax(unitId)) * 100 else return UnitHealth(unitId) end elseif (unitId == "target") then if (wantPct) then return UnitHealth(unitId) else if (not MobHealth_GetTargetCurHP) then lazyr.p("MobInfo2 (or equivalent) not installed, can't determine target's HP.") -- return something huge return 1000000 end local hp = MobHealth_GetTargetCurHP() if (not hp or hp == 0) then -- no mob info, return something huge hp = 1000000 end return hp end end end -- :-( -- returns mana, energy, or rage function lazyr.masks.GetUnitMana(unitId, wantPct) -- mana is different than health, we get actual values for everything, even enemies if (wantPct) then return (UnitMana(unitId) / UnitManaMax(unitId)) * 100 else return UnitMana(unitId) end end function lazyr.masks.UnitPowerMask(unitId, gtLtEq, val, powerType, wantPct) return function() local compareVal = 0 if (powerType == "hp") then compareVal = lazyr.masks.GetUnitHealth(unitId, wantPct) elseif (powerType == "mana" or powerType == "energy") then compareVal = lazyr.masks.GetUnitMana(unitId, wantPct) end if (gtLtEq == ">") then return (compareVal > val) elseif (gtLtEq == "=") then return (compareVal == val) else return (compareVal < val) end end end -- :-( -- -- Checking buffs/debuffs is fun! -- We accept one or more of: -- - the buff/debuff texture -- - the Tooltip title -- - a line found inside the body of the tooltip. -- function lazyr.masks.HasBuffOrDebuff(unitId, buffOrDebuff, texture, ttTitle, ttBody) local candidates = {} local buffId = 1 while true do local thisTexture if (buffOrDebuff == "buff") then thisTexture = UnitBuff(unitId, buffId) else thisTexture = UnitDebuff(unitId, buffId) end if (not thisTexture) then break end if (not texture) then -- no texture criteria given, so just add to list of candidates candidates[buffId] = true elseif (string.find(thisTexture, texture)) then lazyr.d("HasBuffOrDebuff: found texture "..texture.." at buffId: "..buffId) candidates[buffId] = true else candidates[buffId] = false end buffId = buffId + 1 end if (ttTitle) then for buffId, isCandidate in ipairs(candidates) do if (isCandidate) then LazyRogue_Tooltip:ClearLines() if (buffOrDebuff == "buff") then LazyRogue_Tooltip:SetUnitBuff(unitId, buffId) else LazyRogue_Tooltip:SetUnitDebuff(unitId, buffId) end local thisTTTitle = LazyRogue_TooltipTextLeft1:GetText() if (thisTTTitle and string.find(thisTTTitle, "^"..ttTitle)) then lazyr.d("HasBuffOrDebuff: found ttTitle "..ttTitle.." at buffId: "..buffId) else lazyr.d("HasBuffOrDebuff: did NOT find ttTitle "..ttTitle.." at buffId: "..buffId) candidates[buffId] = false end end end end if (ttBody) then for buffId, isCandidate in ipairs(candidates) do if (isCandidate) then LazyRogue_Tooltip:ClearLines() if (buffOrDebuff == "buff") then LazyRogue_Tooltip:SetUnitBuff(unitId, buffId) else LazyRogue_Tooltip:SetUnitDebuff(unitId, buffId) end local ttNumlines = LazyRogue_Tooltip:NumLines() for i = 2, ttNumlines do local thisTTBody = getglobal("LazyRogue_TooltipTextLeft"..i):GetText() if (thisTTBody and string.find(thisTTBody, "^"..ttBody)) then lazyr.d("HasBuffOrDebuff: found ttBody "..ttBody.." at buffId: "..buffId) else lazyr.d("HasBuffOrDebuff: did NOT find ttBody "..ttBody.." at buffId: "..buffId) candidates[buffId] = false end end end end end for buffId, isCandidate in ipairs(candidates) do if (isCandidate) then return buffId end end return nil end function lazyr.masks.BuffOrDebuffMask(attack) return function() local unitId = "target" local buffOrDebuff = "debuff" local texture local ttTitle if (attack == "Adrenaline") then unitId = "player" buffOrDebuff = "buff" texture = lazyr.actions.adrenalineRush.texture ttTitle = lrLocale.BUFF_TTS.adrenalineRush elseif (attack == "Berserking") then unitId = "player" buffOrDebuff = "buff" texture = lazyr.actions.berserking.texture ttTitle = lrLocale.BUFF_TTS.berserking elseif (attack == "BladeFlurry") then unitId = "player" buffOrDebuff = "buff" texture = lazyr.actions.bladeFlurry.texture ttTitle = lrLocale.BUFF_TTS.bladeFlurry elseif (attack == "Blind") then texture = lazyr.actions.blind.texture ttTitle = lrLocale.BUFF_TTS.blind elseif (attack == "ColdBlood") then unitId = "player" buffOrDebuff = "buff" texture = lazyr.actions.coldBlood.texture ttTitle = lrLocale.BUFF_TTS.coldBlood elseif (attack == "Cs") then texture = lazyr.actions.cheapShot.texture ttTitle = lrLocale.BUFF_TTS.cheapShot elseif (attack == "Evasion") then unitId = "player" buffOrDebuff = "buff" texture = lazyr.actions.evasion.texture ttTitle = lrLocale.BUFF_TTS.evasion elseif (attack == "Expose") then texture = lazyr.actions.exposeArmor.texture ttTitle = lrLocale.BUFF_TTS.exposeArmor elseif (attack == "Garrote") then texture = lazyr.actions.garrote.texture ttTitle = lrLocale.BUFF_TTS.garrote elseif (attack == "Ghostly") then unitId = "player" buffOrDebuff = "buff" texture = lazyr.actions.ghostlyStrike.texture ttTitle = lrLocale.BUFF_TTS.ghostlyStrike elseif (attack == "Gouge") then texture = lazyr.actions.gouge.texture ttTitle = lrLocale.BUFF_TTS.gouge elseif (attack == "Hemo") then texture = lazyr.actions.hemorrhage.texture ttTitle = lrLocale.BUFF_TTS.hemorrhage elseif (attack == "Ks") then texture = lazyr.actions.kidneyShot.texture ttTitle = lrLocale.BUFF_TTS.kidneyShot elseif (attack == "RecentlyBandaged") then unitId = "player" texture = "INV_Misc_Bandage_08" ttTitle = lrLocale.BUFF_TTS.recentlyBandaged elseif (attack == "FirstAid") then unitId = "player" buffOrDebuff = "buff" texture = "Spell_Holy_Heal" ttTitle = lrLocale.BUFF_TTS.firstAid elseif (attack == "Remorseless") then unitId = "player" buffOrDebuff = "buff" texture = "Ability_FiegnDead" ttTitle = lrLocale.BUFF_TTS.remorseless elseif (attack == "Rupture") then texture = lazyr.actions.rupture.texture ttTitle = lrLocale.BUFF_TTS.rupture elseif (attack == "Sap") then texture = lazyr.actions.sap.texture ttTitle = lrLocale.BUFF_TTS.sap elseif (attack == "Snd") then unitId = "player" buffOrDebuff = "buff" texture = lazyr.actions.sliceNDice.texture ttTitle = lrLocale.BUFF_TTS.sliceNDice elseif (attack == "Stealth") then unitId = "player" buffOrDebuff = "buff" texture = lazyr.actions.stealth.texture ttTitle = lrLocale.BUFF_TTS.stealth elseif (attack == "Vanish") then unitId = "player" buffOrDebuff = "buff" texture = lazyr.actions.vanish.texture ttTitle = lrLocale.BUFF_TTS.vanish else lazyr.p("internal error, unknown attack: "..attack) return false end return lazyr.masks.HasBuffOrDebuff(unitId, buffOrDebuff, texture, ttTitle) end end function lazyr.masks.TargetClass(class) return function() return (class == UnitClass("target")) end end function lazyr.masks.TargetLevel(gtLtEq, val) return function() if (not UnitExists("target")) then return false end local tLevel = UnitLevel("target") if (tLevel == -1) then -- "??" -- means target is > 10 levels above the player. -- hmm, special case. we can still be smart here. -- if the criteria was greater than something, where something -- is at most your level + 10, then we can return true. -- otherwise we can't be sure. local pLevel = UnitLevel("player") if (gtLtEq == ">" and (val <= pLevel + 10)) then return true end return false end if (gtLtEq == ">") then return (tLevel > val) elseif (gtLtEq == "=") then return (tLevel == val) else return (tLevel < val) end end end function lazyr.masks.TargetMyLevel(gtLtEq, val) return function() if (not UnitExists("target")) then return false end local tLevel = tonumber(UnitLevel("target")) local pLevel = tonumber(UnitLevel("player")) local tmp=pLevel+val --not sure how to code this with the information availble --if (tLevel == -1) then -- "??" -- means target is > 10 levels above the player. -- hmm, special case. we can still be smart here. -- if the criteria was greater than something, where something -- is at most your level + 10, then we can return true. -- otherwise we can't be sure. -- if (gtLtEq == ">" and (tmp <= pLevel + 10)) then -- return true -- end -- return false -- end if (gtLtEq == ">") then lazyr.d("Search for target over lvl "..tmp) return (tmp < tLevel) elseif (gtLtEq == "=") then lazyr.d("Search for target equal to lvl "..tmp) return (tmp == tLevel) else lazyr.d("Search for target under lvl "..tmp) return (tmp > tLevel) end end end function lazyr.masks.TargetType(type) return function() return (type == UnitCreatureType("target")) end end function lazyr.masks.TargetNamed(nameRegex) return function() local tName = UnitName("target") if (tName and string.find(tName, nameRegex)) then return true end return false end end function lazyr.masks.TargetNPC() return function() return not UnitIsPlayer("target") end end function lazyr.masks.TargetHostile() return function() -- http://www.wowwiki.com/API_UnitReaction local reaction = UnitReaction("player", "target") if (not reaction) then -- dunno... return false end return (reaction <= 3) end end function lazyr.masks.TargetInCombat() return function() return UnitAffectingCombat("target") end end function lazyr.masks.TargetAlive() return function() if UnitName("target") then return (not UnitIsDead("target")) else return false end end end function lazyr.masks.TargetCCd() return function() for texture, ttInfo in lrLocale.CC_TTS do local ttTitle = ttInfo[1] local ttBody = ttInfo[2] if (lazyr.masks.HasBuffOrDebuff("target", "debuff", texture, ttTitle, ttBody)) then if (lazyr.perPlayerConf.showReasonForTargetCCd) then if (not ttTitle) then ttTitle = texture end lazyr.p("ifTargetCCd: target afflicted by "..ttTitle) end return true end end return false end end function lazyr.masks.IsMarked() return function() if (not lrLocale.HuntersMark_TTS) then lazyr.p("Sorry, ifHuntersMark not supported for your locale.") return false end for texture, ttTitle in lrLocale.HuntersMark_TTS do if (lazyr.masks.HasBuffOrDebuff("player", "debuff", texture, ttTitle)) then lazyr.d("player afflicted by Hunter's Mark") return true end end return false end end function lazyr.masks.IsPolymorphed() return function() if (not lrLocale.Polymorph_TTS) then lazyr.p("Sorry, ifPolymorphed not supported for your locale.") return false end for texture, ttTitle in lrLocale.Polymorph_TTS do if (lazyr.masks.HasBuffOrDebuff("player", "debuff", texture, ttTitle)) then lazyr.d("player afflicted by Polymorph") return true end end return false end end function lazyr.masks.IsBleeding() return function() if (not lrLocale.Bleed_TTS) then lazyr.p("Sorry, ifBleeding not supported for your locale.") return false end for texture, ttTitle in lrLocale.Bleed_TTS do if (lazyr.masks.HasBuffOrDebuff("player", "debuff", texture, ttTitle)) then if (lazyr.perPlayerConf.showReasonForTargetCCd) then if (not ttTitle) then ttTitle = texture end lazyr.p("ifBleeding: player afflicted by "..ttTitle) end return true end end return false end end function lazyr.masks.IsDotted() return function() if (not lrLocale.DOT_TTS) then lazyr.p("Sorry, ifDotted not supported for your locale.") return false end for idx, ttBody in lrLocale.DOT_TTS do if (lazyr.masks.HasBuffOrDebuff("player", "debuff", nil, nil, ttBody)) then if (lazyr.perPlayerConf.showReasonForTargetCCd) then lazyr.p("ifDotted: player afflicted by "..ttBody) end return true end end return false end end function lazyr.masks.IsFeared() return function() if (not lrLocale.FEAR_TTS) then lazyr.p("Sorry, ifFeared not supported for your locale.") return false end for idx, ttBody in lrLocale.FEAR_TTS do if (lazyr.masks.HasBuffOrDebuff("player", "debuff", nil, nil, ttBody)) then if (lazyr.perPlayerConf.showReasonForTargetCCd) then lazyr.p("ifFeared: player afflicted by "..ttBody) end return true end end return false end end function lazyr.masks.IsImmobile() return function() if (not lrLocale.IMMOBILE_TTS) then lazyr.p("Sorry, ifImmobile not supported for your locale.") return false end for idx, ttBody in lrLocale.IMMOBILE_TTS do if (lazyr.masks.HasBuffOrDebuff("player", "debuff", nil, nil, ttBody)) then if (lazyr.perPlayerConf.showReasonForTargetCCd) then lazyr.p("ifImmobile: player afflicted by "..ttBody) end return true end end return false end end function lazyr.masks.UnitStunned(unitId) return function() if (not lrLocale.STUNNED_TTS) then lazyr.p("Sorry, if[Target]Stunned not supported for your locale.") return false end for idx, ttBody in lrLocale.STUNNED_TTS do if (lazyr.masks.HasBuffOrDebuff(unitId, "debuff", nil, nil, ttBody)) then if (lazyr.perPlayerConf.showReasonForTargetCCd) then lazyr.p("ifStunned: played afflicted by "..ttBody) end return true end end return false end end function lazyr.masks.UnitSlowed(unitId) return function() if (not lrLocale.SLOWED_TTS) then lazyr.p("Sorry, if[Target]Slowed not supported for your locale.") return false end for idx, ttBody in lrLocale.SLOWED_TTS do if (lazyr.masks.HasBuffOrDebuff(unitId, "debuff", nil, nil, ttBody)) then if (lazyr.perPlayerConf.showReasonForTargetCCd) then lazyr.p("ifSlowed: player afflicted by "..ttBody) end return true end end return false end end function lazyr.masks.IsInstance(unitId) return function() if (not lrLocale.INSTANCES) then lazyr.p("Sorry, ifInstance not supported for your locale.") return false end zone = GetZoneText() for idx, instance in lrLocale.INSTANCES do if string.find(zone, instance) then return true end end return false end end function lazyr.masks.IsBattleground(unitId) return function() for i = 1, MAX_BATTLEFIELD_QUEUES do status, mapName, instanceID = GetBattlefieldStatus(i) if (status == "active") then lazyr.d("You're in batteground: "..mapName) return true end return false end end end function lazyr.masks.TargetIsCasting(nameRegex) return function() if (lazyr.interrupt.targetCasting and ((GetTime() - lazyr.interrupt.castingDetectedAt) <= 5)) then if (not nameRegex or nameRegex == "") then return true end if (string.find(lazyr.interrupt.targetCasting, nameRegex)) then return true end end return false end end -- if any of the exception criteria return true, we return FALSE function lazyr.masks.InterruptExceptionCriteria() return function() lazyr.masks.alreadyInsideInterruptExceptionCriteria = true local actionInfos = lazyr.ParseForm(lrConf.interruptExceptionCriteria) lazyr.masks.alreadyInsideInterruptExceptionCriteria = false for idx, actionInfo in actionInfos do local action = actionInfo[1] -- should be nil local masks = actionInfo[2] local areAllTrue = true if (masks) then for idx, mask in masks do if (not mask()) then areAllTrue = false break end end if (areAllTrue) then -- all criteria on this line returned true, so this mask returns false return false end end end return true end end function lazyr.masks.TargetElite() return function() return string.find(UnitClassification("target"), "elite") end end function lazyr.masks.TargetInMeleRange() return function() return CheckInteractDistance("target", 1) end end function lazyr.masks.TargetInBlindRange() return function() return CheckInteractDistance("target", 2) end end function lazyr.masks.PlayerInCombat() return function() return lazyr.isInCombat end end function lazyr.masks.PlayerInGroup() return function() return (GetNumPartyMembers() > 0) end end function lazyr.masks.PlayerInRaid() return function() return (GetNumRaidMembers() > 0) end end function lazyr.masks.PlayerInGroupOrRaid() return function() return ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0)) end end -- if you don't eviscerate now, will you have time for 2 ticks before the target dies? -- we determine the rate of damage, and estimate when the target will be dead -- then we look at the last tick, and add 4 seconds, and see if that's before he'll die. function lazyr.masks.IsLastChance() return function() -- MobInfo-2 required if (not MobHealth_GetTargetCurHP) then return false end if (GetComboPoints() == 0 or not UnitName("target") or UnitHealth("target") == 0) then return false end local n = lazyr.targetHealthHistory:GetN() -- we want at least a couple data points if (n < 3) then return false end local startTime = GetTime() -- m is the slope, or hp per second local m = lazyr.targetHealthHistory:ComputeSlope() if (not m) then return false end if (m >= 0) then lazyr.d("IsLastChance: m is positive? target healing?") return false end local currentHp = lazyr.masks.GetUnitHealth("target") local secondsTilDeath = math.abs(currentHp / m) -- now, we know when he'll die. -- look at the last tick, and add 4 seconds (and a 1/4s buffer), and see -- if that's before he'll die. -- Also consider the player's current energy: -- Maybe we won't need 2 ticks... to be really smart, we'd need to know what attack -- the player will use if he doesn't evisc right now... well, the maximum attack is -- backstab (60), but more likely a SS (40-45). -- Okay, for simplicity let's just assume the player will SS (40). local ticksNeeded = 2 local currentEnergy = lazyr.masks.GetUnitMana("player") if (currentEnergy >= 60) then ticksNeeded = 1 elseif (currentEnergy >= 80) then ticksNeeded = 0 end local whenTicks = lazyr.lastTickTime + (ticksNeeded * 2) local isLastChance if ((whenTicks + .25) > (GetTime() + secondsTilDeath)) then isLastChance = true else isLastChance = false end local msg = "IsLastChance: n: "..n.. ", m: "..math.abs(string.format("%.1f", m)).."hp/s, ".. " hp: "..currentHp.. ", DEAD IN ".. string.format("%.1f", secondsTilDeath).."s (".. string.format("%.1f", (GetTime() - startTime)).."s)" if (isLastChance) then msg = msg.." EVISCERATE NOW" end msg = msg.."." lazyr.d(msg) return isLastChance end end function lazyr.masks.IsEquipped(item) return function() local itemId local itemName if (string.find(item, '^%d')) then itemId = tonumber(item) else itemName = item end for slot = 0, 19 do local link = GetInventoryItemLink("player", slot) if (link) then local id, name = lazyr.IdAndNameFromLink(link) if (id) then if ((itemId and id == itemId)) then return true elseif (itemName) then if string.lower(name) == string.lower(itemName) then return true end end end end end return false end end function lazyr.masks.IsKeyDown(key) return function() if (key == "Ctrl") then return IsControlKeyDown() elseif (key == "Alt") then return IsAltKeyDown() elseif (key == "Shift") then return IsShiftKeyDown() end return false end end function lazyr.masks.Every(action, seconds) return function() if (GetTime() > (action.everyTimer + seconds))or action.everyTimer==nil then return true end return false end end function lazyr.masks.Timer(action, seconds) return function() if lazyr.actions[action] then if (GetTime() > (lazyr.actions[action].everyTimer + seconds)) then return true end elseif lazyr.forms[action] then if (GetTime() > (lazyr.setForm[action].everyTimer + seconds)) then return true end elseif lazyr.items[action] then if (GetTime() > (lazyr.item[action].everyTimer + seconds)) then return true end elseif lazyr.pseudoActions[action] then if (GetTime() > (lazyr.pseudoActions[action].everyTimer + seconds)) then return true end elseif lazyr.comboActions[action] then if (GetTime() > (lazyr.comboActions[action].everyTimer + seconds)) then return true end end return false end end -- :-( -- This code is good for a Rogue. It skips over some annoying exceptions that only -- Hunters and Druids face. Do not rip off this code unless you're writing a Rogue-only addon. function lazyr.masks.PlayerMountedIndex() local buffId = 0 local mountBuffIndex = nil while true do local buffIndex = GetPlayerBuff(buffId, "HELPFUL|PASSIVE") if (buffIndex < 0) then break end local texture = GetPlayerBuffTexture(buffIndex) local skip = false if (string.find(texture, "Ability_Mount_") or string.find(texture, "Spell_Nature_Swiftness") or string.find(texture, "INV_Misc_Foot_Kodo")) then -- Whoa, one exception though: Is it really a mount? (Spotted Frostsaber?) -- or just a Hunter in the party with Aspect of the Pack? if (string.find(texture, "Ability_Mount_WhiteTiger")) then lazyr.d("PlayerMountedIndex: Whoa, Ability_Mount_WhiteTiger is suspect, having to parse TT") LazyRogue_Tooltip:ClearLines() LazyRogue_Tooltip:SetPlayerBuff(buffIndex) local ttText = LazyRogue_TooltipTextLeft2:GetText() if (not string.find(ttText, "^"..lrLocale.MOUNTED_BUFF_TT)) then lazyr.d("PlayerMountedIndex: IGNORING: it's not really a mount: "..ttText) skip = true -- uggh, Lua really needs a continue function end end if (not skip) then lazyr.d("PlayerMountedIndex: OK, you're mounted: "..texture) mountBuffIndex = buffIndex break end end buffId = buffId + 1 end return mountBuffIndex end function lazyr.masks.PlayerMounted() return function() return lazyr.masks.PlayerMountedIndex() end end function lazyr.masks.InZone(nameRegex) return function() if (string.find(GetRealZoneText(), nameRegex)) then return true end return false end end function lazyr.masks.IsPoisoned(weapon) return function() bMh, tMh, cMh, bOh, tOh, cOh = GetWeaponEnchantInfo(); if (weapon == "MainHand" and bMh) then return true elseif (weapon == "OffHand" and bOh) then return true else return false end return false end end function lazyr.masks.IsGlobalCooldown() return function() if not lazyr.globalCooldownSlot then for slot = 1, 120 do if (not GetActionText(slot)) then -- ignore any Player macros :-) local text = GetActionTexture(slot) if (text and (string.find(text, "INV_Misc_Rune_01"))) then lazyr.globalCooldownSlot = slot break end end end if not lazyr.globalCooldownSlot then lazyr.p("Sorry -if[Not]GlobalCooldown function is not available to this char.") return false end local start, duration, enable = GetActionCooldown(lazyr.globalCooldownSlot) if (enable > 0) then return true else return false end else local start, duration, enable = GetActionCooldown(lazyr.globalCooldownSlot) if ( start > 0 and duration > 0 and enable > 0) then return true else return false end end end end function lazyr.masks.History(gtLtEq, val, action) return function() local historySize = table.getn(lazyr.actionHistory) if (gtLtEq == ">") then local i = val + 1 while true do if (not lazyr.actionHistory[i]) then return false end if (lazyr.actionHistory[i] == action) then return true end i = i + 1 end elseif (gtLtEq == "<") then local i = val - 1 while (i > 0) do if (lazyr.actionHistory[i] and lazyr.actionHistory[i] == action) then return true end i = i - 1 end return false else if (lazyr.actionHistory[val] and lazyr.actionHistory[val] == action) then return true end return false end end end function lazyr.ParseArg(arg) -- remove comments: # .... or // .... -- trim leading/trailing whitespace -- ignore blank lines arg = string.gsub(arg, "#.*", "") arg = string.gsub(arg, "//.*", "") arg = string.gsub(arg, "%-%-.*", "") arg = string.gsub(arg, "^%s+", "") arg = string.gsub(arg, "%s+$", "") if (arg == "") then return 0 end local bits = {} for bit in string.gfind(arg, "[^\-]+") do table.insert(bits, bit) end local action local masks = {} for idx, bit in bits do if (string.sub(bit, 1, 6) == "action") then if (not lazyr.re(bit, "^action=(.+)$")) then lazyr.p("Can't parse: "..bit) return nil end local thisAction = lazyr.match1 if (not lazyr.otherActions[thisAction]) then lazyr.otherActions[thisAction] = lazyr.Action:New(thisAction, thisAction) end action = lazyr.otherActions[thisAction] elseif (bit == "adrenaline") then action = lazyr.actions.adrenalineRush elseif (bit == "ambush") then action = lazyr.actions.ambush elseif (bit == "cbAmbush") then action = lazyr.comboActions.cbAmbush elseif (bit == "berserking") then action = lazyr.actions.berserking elseif (bit == "bladeFlurry" or bit == "bladeflurry") then action = lazyr.actions.bladeFlurry elseif (bit == "blind") then action = lazyr.actions.blind elseif (bit == "bs") then action = lazyr.actions.backstab table.insert(masks, lazyr.masks.BehindAttackHasNotFailedRecently()) elseif (bit == "cbEvisc" or bit == "cbevisc") then action = lazyr.comboActions.cbEvisc elseif (bit == "coldBlood" or bit == "coldblood") then action = lazyr.actions.coldBlood elseif (bit == "cs") then action = lazyr.actions.cheapShot elseif (bit == "dismount") then action = lazyr.pseudoActions.dismount elseif (bit == "evasion") then action = lazyr.actions.evasion elseif (bit == "evisc") then action = lazyr.actions.eviscerate elseif (bit == "expose") then action = lazyr.actions.exposeArmor elseif (bit == "feint") then action = lazyr.actions.feint table.insert(masks, lazyr.masks.PlayerInGroupOrRaid()) elseif (bit == "garrote") then action = lazyr.actions.garrote table.insert(masks, lazyr.masks.BehindAttackHasNotFailedRecently()) elseif (bit == "ghostly") then action = lazyr.actions.ghostlyStrike elseif (bit == "gouge") then action = lazyr.actions.gouge table.insert(masks, lazyr.masks.InFrontAttackHasNotFailedRecently()) elseif (bit == "hemo") then action = lazyr.actions.hemorrhage elseif (bit == "kick") then action = lazyr.actions.kick table.insert(masks, lazyr.masks.TargetInMeleRange()) elseif (bit == "ks") then action = lazyr.actions.kidneyShot elseif (bit == "ping") then action = lazyr.pseudoActions.ping elseif (bit == "premeditation") then action = lazyr.actions.premeditation elseif (bit == "preparation") then action = lazyr.actions.preparation elseif (bit == "pickPocket") then action = lazyr.actions.pickPocket elseif (bit == "riposte") then action = lazyr.actions.riposte elseif (bit == "rupture") then action = lazyr.actions.rupture elseif (bit == "sap") then action = lazyr.actions.sap elseif (bit == "snd") then action = lazyr.actions.sliceNDice elseif (bit == "sprint") then action = lazyr.actions.sprint elseif (bit == "ss") then action = lazyr.actions.sinisterStrike elseif (bit == "stealth") then action = lazyr.actions.stealth table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.BuffOrDebuffMask("Stealth"), true)) elseif (bit == "stop") then action = lazyr.pseudoActions.stop elseif (bit == "stopAll" or bit == "stopall") then action = lazyr.pseudoActions.stopAll elseif (bit == "tea") then action = lazyr.items.thistleTea elseif (bit == "perception") then action = lazyr.actions.humanRacial elseif (bit == "stoneForm") then action = lazyr.actions.dwarfRacial elseif (bit == "escapeArtist") then action = lazyr.actions.gnomeRacial elseif (bit == "bloodFury") then action = lazyr.actions.orcRacial elseif (bit == "warStomp") then action = lazyr.actions.taurenRacial elseif (bit == "forsaken") then action = lazyr.actions.undeadRacial elseif (bit == "throw") then action = lazyr.actions.throw elseif (bit == "bow") then action = lazyr.actions.bow elseif (bit == "gun") then action = lazyr.actions.gun elseif (bit == "crossbow") then action = lazyr.actions.crossbow elseif (bit == "cannibalize") then action = lazyr.actions.cannibalize elseif (bit == "targetAssist") then action = lazyr.pseudoActions.targetAssist elseif (bit == "targetNearest") then action = lazyr.pseudoActions.targetNearest elseif (bit == "autoAttack") then action = lazyr.pseudoActions.autoAttack elseif (string.sub(bit, 1, 11) == "applyPoison") then lazyr.d("applyPoison") if (not lazyr.re(bit, "^applyPoison(%a+)=(.+)$")) then lazyr.p("Can't parse: "..bit) return nil end if (lazyr.match1 ~="MainHand" and lazyr.match1 ~="OffHand") then lazyr.p("Only MainHand and OffHand available, but not"..lazyr.match1) return nil end local weaponName=lazyr.match1 local poisonName=lazyr.match2 local key = weaponName..":"..poisonName if (not lazyr.poisonsUse[key]) then lazyr.poisonsUse[key] = lazyr.applyPoison:New(poisonName, weaponName) end action = lazyr.poisonsUse[key] elseif (string.sub(bit, 1, 5) == "sayIn") then if (not lazyr.re(bit, "^sayIn(%a+)=(.+)$")) then lazyr.p("Can't parse: "..bit) return nil end if lazyr.match1 ~="Guild" and lazyr.match1 ~="Party" and lazyr.match1 ~="Raid" and lazyr.match1 ~="Say" and lazyr.match1 ~="Emote" and lazyr.match1 ~="RAID_WARNING" then lazyr.p("Unknown channel name: "..lazyr.match1) return nil end -- XXX: this will not work! these globals are set at parse time, but they -- might be changed before run time! lazyr.sayInChannel = lazyr.match1 lazyr.sayInMessage = lazyr.match2 action = lazyr.pseudoActions.sayIn elseif (string.sub(bit, 1, 8) == "setForm=") then if (not lazyr.re(bit, "^setForm=(.+)$")) then lazyr.p("Can't parse: "..bit) return nil end local form = lazyr.match1 if (not lazyr.forms[form]) then lazyr.forms[form] = lazyr.SetForm:New("form"..form, form) end action = lazyr.forms[form] elseif (string.sub(bit, 1, 14) == "equipMainHand=") then if (not lazyr.re(bit, "^equipMainHand=(.+)$")) then lazyr.p("Can't parse: "..bit) return nil end local item = lazyr.match1 local itemId local itemName if (string.find(item, '^%d')) then itemId = tonumber(item) itemName = "Item "..itemId else itemName = item end if (not lazyr.mainHandItems[item]) then lazyr.mainHandItems[item] = lazyr.EquipItem:New(item, itemName, itemId, 16) end action = lazyr.mainHandItems[item] elseif (string.sub(bit, 1, 13) == "equipOffHand=") then if (not lazyr.re(bit, "^equipOffHand=(.+)$")) then lazyr.p("Can't parse: "..bit) return nil end local item = lazyr.match1 local itemId local itemName if (string.find(item, '^%d')) then itemId = tonumber(item) itemName = "Item "..itemId else itemName = item end if (not lazyr.offHandItems[item]) then lazyr.offHandItems[item] = lazyr.EquipItem:New(item, itemName, itemId, 17) end action = lazyr.offHandItems[item] elseif (string.sub(bit, 1, 3) == "use") then if (not lazyr.re(bit, "^use(E?q?u?i?p?p?e?d?)=?(.+)$")) then lazyr.p("Can't parse: "..bit) return nil end local equippedOnly = (lazyr.match1 == "Equipped") local item = lazyr.match2 local itemId local itemName if (string.find(item, '^%d')) then itemId = tonumber(item) itemName = "Item "..itemId else itemName = item end local myItemSet if (equippedOnly) then myItemSet = lazyr.equippedItems else myItemSet = lazyr.items end if (not myItemSet[item]) then myItemSet[item] = lazyr.Item:New(item, itemName, itemId, equippedOnly) end action = myItemSet[item] elseif (bit == "vanish") then action = lazyr.actions.vanish elseif (lazyr.re(bit, "^if(N?o?t?)Equipped=(.+)$")) then local negate = lazyr.match1 == "Not" local item = lazyr.match2 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsEquipped(item), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetOfTargetClass=(.+)$")) then local negate = (lazyr.match1 == "Not") local subMasks = {} for class in string.gfind(lazyr.match2, "[^,]+") do table.insert(subMasks, lazyr.masks.IsTargetOfTargetClass(class)) end table.insert(masks, lazyr.masks.maskGroup(subMasks, negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Dueling$")) then local negate = lazyr.match1 == "Not" table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsDueling(), negate)) elseif (lazyr.re(bit, "^if(T?a?r?g?e?t?)FlaggedPVP$")) then local unit = lazyr.match1 table.insert(masks, lazyr.masks.IsFlaggedPVP(unit)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetOfTarget$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsTargetOfTarget(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Stealthed$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsStealthedMask(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)InCombat$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.PlayerInCombat(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)BehindAttackJustFailed$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.BehindAttackFailedRecently(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)InFrontAttackJustFailed$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.InFrontAttackFailedRecently(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)InGroup$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.PlayerInGroup(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)InRaid$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.PlayerInRaid(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)LastChance$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsLastChance(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Mounted$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.PlayerMounted(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Instance$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsInstance(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Battleground$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsBattleground(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Ganked$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsBeingGanked(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)FlagRunner$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsFlagRunner(), negate)) elseif (lazyr.re(bit, "^if(C?b?)KillShot=?(%d?%d?%d?)%%?$")) then local assumeCBActive = false local goalPct = 100 if (bit == "ifKillShot" and action ~= lazyr.actions.eviscerate) then lazyr.p("-ifKillShot only works with evisc") return nil elseif (bit == "^ifCbKillShot$" and action ~= lazyr.comboActions.cbEvisc and action ~= lazyr.actions.eviscerate) then lazyr.p("-ifCbKillShot only works with cbevisc or evisc") return nil end if (lazyr.match2 ~= "") then goalPct = tonumber(lazyr.match2) end table.insert(masks, lazyr.masks.IsEviscKillShot(assumeCBActive, goalPct)) elseif (lazyr.re(bit, "^if([<=>]?)(%d+)cp$") or lazyr.re(bit, "^([<=>]?)(%d+)cp$")) then local gtLtEq = lazyr.match1 local val = tonumber(lazyr.match2) table.insert(masks, lazyr.masks.ComboPoints(val, gtLtEq)) elseif (lazyr.re(bit, "^if([<=>]?)(%d+)attackers$")) then local gtLtEq = lazyr.match1 local val = tonumber(lazyr.match2) table.insert(masks, lazyr.masks.IsBeingAttackedBy(val, gtLtEq)) elseif (lazyr.re(bit, "^if(%a+)([<=>])(%d+)(%%?)(%a+)$") or lazyr.re(bit, "^(%a+)([<=>])(%d+)(%%?)(%a+)$")) then local unitId = string.lower(lazyr.match1) local gtLtEq = lazyr.match2 local val = tonumber(lazyr.match3) local wantPct = (lazyr.match4 == "%") local powerType = lazyr.match5 if (unitId ~= "player" and unitId ~= "target") then lazyr.p("UnitId must be Player or Target, "..unitId.." not supported.") return nil end if (powerType ~= "hp" and powerType ~= "mana" and powerType ~= "energy") then lazyr.p("Only hp and mana/energy are supported, not: "..powerType) return nil end table.insert(masks, lazyr.masks.UnitPowerMask(unitId, gtLtEq, val, powerType, wantPct)) elseif (lazyr.re(bit, "^if(N?o?t?)(%a-)(N?o?t?)Active$")) then -- Okay, this is a little messy, but it will fix up those -- N?o?t?s from capturing pieces of %a- they shouldn't. if (lazyr.match1 ~= "" and lazyr.match1 ~= "Not") then lazyr.match2 = lazyr.match1..lazyr.match2 end if (lazyr.match3 ~= "" and lazyr.match3 ~= "Not") then lazyr.match2 = lazyr.match2..lazyr.match3 end local attack = lazyr.match2 local negate = (lazyr.match1 == "Not" or lazyr.match3 == "Not") if (attack ~= "Adrenaline" and attack ~= "Berserking" and attack ~= "BladeFlurry" and attack ~= "Blind" and attack ~= "ColdBlood" and attack ~= "Cs" and attack ~= "Evasion" and attack ~= "Expose" and attack ~= "Garrote" and attack ~= "Ghostly" and attack ~= "Gouge" and attack ~= "FirstAid" and attack ~= "Hemo" and attack ~= "Ks" and attack ~= "RecentlyBandaged" and attack ~= "Remorseless" and attack ~= "Rupture" and attack ~= "Sap" and attack ~= "Snd" and attack ~= "Vanish") then lazyr.p("Only Adrenaline, Berserking, BladeFlurry, Blind, ColdBlood, Cs, Evasion, Expose, FirstAid (Bandage), Garrote, Ghostly, Gouge, Hemo, Ks, RecentlyBandaged, Remorseless, Rupture, Sap, Snd, and Vanish are supported, not: "..attack) return nil end table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.BuffOrDebuffMask(attack), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)GlobalCooldown$")) then local negate = (lazyr.match1 == "Not" ) table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsGlobalCooldown(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetClass=?(.+)$")) then local negate = (lazyr.match1 == "Not") local subMasks = {} for class in string.gfind(lazyr.match2, "[^,]+") do table.insert(subMasks, lazyr.masks.TargetClass(class)) end table.insert(masks, lazyr.masks.maskGroup(subMasks, negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetLevel([<=>])(%d+)$")) then local negate = (lazyr.match1 == "Not" ) local gtLtEq = lazyr.match2 local val = tonumber(lazyr.match3) table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetLevel(gtLtEq, val), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetMyLevel([<=>])(%a*)(%d+)$")) then local val = nil local negate = (lazyr.match1 == "Not" ) local gtLtEq = lazyr.match2 if lazyr.match3 == "plus" or lazyr.match3 == "" then val = tonumber(lazyr.match4) elseif lazyr.match3 == "minus" then val = tonumber(lazyr.match4*-1) else lazyr.d("unable to determine plus/minus sign") return nil end table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetMyLevel(gtLtEq, val), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetType=?(.+)$")) then local negate = (lazyr.match1 == "Not") local subMasks = {} for type in string.gfind(lazyr.match2, "[^,]+") do table.insert(subMasks, lazyr.masks.TargetType(type)) end table.insert(masks, lazyr.masks.maskGroup(subMasks, negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetNamed=(.+)$")) then local negate = (lazyr.match1 == "Not") local nameRegex = lazyr.match2 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetNamed(nameRegex), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetNPC$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetNPC(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetHostile$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetHostile(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetInCombat$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetInCombat(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetSlowed$")) then local negate = (lazyr.match1 == "Not" ) table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.UnitSlowed("target"), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Slowed$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.UnitSlowed("player"), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetStunned$")) then local negate = (lazyr.match1 == "Not" ) table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.UnitStunned("target"), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Stunned$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.UnitStunned("player"), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Feared$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsFeared(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Immobile$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsImmobile(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetAlive$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetAlive(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetCCd$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetCCd(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetIsCasting=?(.*)$")) then local negate = (lazyr.match1 == "Not") if (lazyr.match2 ~= "") then local subMasks = {} for nameRegex in string.gfind(lazyr.match2, "[^,]+") do table.insert(subMasks, lazyr.masks.TargetIsCasting(nameRegex)) end table.insert(masks, lazyr.masks.maskGroup(subMasks, negate)) else table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetIsCasting(), negate)) end -- XXX this is kinda strange, should rethink this. if (not negate and not lazyr.masks.alreadyInsideInterruptExceptionCriteria) then table.insert(masks, lazyr.masks.InterruptExceptionCriteria()) end elseif (lazyr.re(bit, "^if(N?o?t?)TargetElite$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetElite(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)(%a+)Down$")) then local negate = (lazyr.match1 == "Not") local key = lazyr.match2 if (key ~= "Ctrl" and key ~= "Alt" and key ~= "Shift") then lazyr.p("Only Ctrl, Alt, and Shift are supported, not: "..key) end table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsKeyDown(key), negate)) elseif (lazyr.re(bit, "^every(%d+)s$")) then if (action == nil) then lazyr.p("you must put the action before the -everyXXs") return nil end local val = tonumber(lazyr.match1) table.insert(masks, lazyr.masks.Every(action, val)) elseif (lazyr.re(bit, "^if(N?o?t?)Timer=(.+)>(.+)s$")) then if (lazyr.match2 == nil) or (lazyr.match3 == nil) then lazyr.p("syntax eg. -ifTimer=gouge>5s") return nil end local negate = (lazyr.match1 == "Not") local val = tonumber(lazyr.match3) table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.Timer(string.lower(lazyr.match2), val), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Zone=(.+)$")) then local negate = (lazyr.match1 == "Not") local nameRegex = lazyr.match2 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.InZone(nameRegex), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)History([<=>])(%d+)=(.+)$")) then local negate = (lazyr.match1 == "Not") local gtLtEq = lazyr.match2 local val = tonumber(lazyr.match3) local action = lazyr.match4 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.History(gtLtEq, val, action), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetInMeleeRange$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetInMeleRange(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetInBlindRange$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetInBlindRange(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)InCooldown=(.+)$")) then local negate = (lazyr.match1 == "Not") local action = lazyr.match2 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.InCooldown(action), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Dotted$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsDotted(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Bleeding$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsBleeding(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)HuntersMark$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsMarked(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)Polymorphed$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsPolymorphed(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)CanDebuff$")) then local negate = (lazyr.match1 == "Not") table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.DebuffSpace(), negate)) elseif (lazyr.re(bit, "^if(N?o?t?)TargetImmune=?(.*)$")) then local negate = (lazyr.match1 == "Not") if (lazyr.match2 ~= "") then local subMasks = {} for thisAction in string.gfind(lazyr.match2, "[^,]+") do table.insert(subMasks, lazyr.masks.IsImmune(thisAction)) end table.insert(masks, lazyr.masks.maskGroup(subMasks, negate)) else table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsImmune(lazyr.match2), negate)) end elseif (lazyr.re(bit, "^if(N?o?t?)Poisoned=(%a+)$")) then if (lazyr.match2 ~="MainHand" and lazyr.match2 ~="OffHand") then lazyr.p("Only MainHand and OffHand available, but not"..lazyr.match1) return nil end local negate = (lazyr.match1 == "Not") local targetW = lazyr.match2 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsPoisoned(targetW), negate)) else lazyr.d("ParseArg: parse failure: "..arg) return nil end end return {action, masks} end function lazyr.ParseForm(args) local startTime = GetTime() local actions = {} for idx, arg in args do local actionInfo = lazyr.ParseArg(arg) if (not actionInfo) then lazyr.p("Can't parse: "..arg) return nil elseif (actionInfo == 0) then -- was empty (comments?) just ignore this else table.insert(actions, actionInfo) end end --lazyr.d("ParseForm: time: "..string.format("%f", (GetTime() - startTime)).."s") return actions end function lazyr.FindForm(formName) if (not formName) then return nil end for thisFormName, actions in lrConf.forms do if (thisFormName == formName) then return actions end end return nil end -- speed optimization, skip parsing and regexes every time function lazyr.FindParsedForm(formName) if (not formName) then return nil end local startTime = GetTime() if (lazyr.parsedFormCache[formName] == nil) then local actions = lazyr.FindForm(formName) if (actions) then lazyr.parsedFormCache[formName] = lazyr.ParseForm(actions) end end --lazyr.d("FindParsedForm: time: "..string.format("%f", (GetTime() - startTime)).."s") return lazyr.parsedFormCache[formName] end function lazyr.ClearParsedForm(formName) lazyr.parsedFormCache[formName] = nil end function lazyr.Try(action, masks) if (masks) then for idx, mask in masks do if (not mask()) then return false end end end return action:Use() end function lazyr.TryActions(actions) local actionThatSucceeded = nil if (not UnitName("target") and lazyr.perPlayerConf.autoTarget) then TargetNearestEnemy() end if (actions) then for idx, actionInfo in actions do local action = actionInfo[1] local masks = actionInfo[2] if (lazyr.Try(action, masks)) then actionThatSucceeded = action break end end end if (not lazyr.mock and lazyr.perPlayerConf.initiateAutoAttack and not actionThatSucceeded and not lazyr.masks.IsStealthed()) then if (not lazyr.IsAutoAttacking()) then lazyr.d("Initiating auto-attack...") lazyr.StartAutoAttack() end end if (actionThatSucceeded) then return actionThatSucceeded.name else return nil end end