vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 -- Masks
2  
3 -- These look a little ugly but the idea is decent...
4 lazyr.masks = {}
5  
6 -- klugy, but hey
7 lazyr.masks.alreadyInsideInterruptExceptionCriteria = false
8  
9 function lazyr.masks.negWrapper(f, negate)
10 return function()
11 local r = f()
12 return ((r and not negate) or (not r and negate))
13 end
14 end
15  
16 -- returns a super mask. Returns true if any of the given masks are true (an "OR").
17 -- however if negate is true, then returns true only if ALL of then given masks are false ("AND")
18 function lazyr.masks.maskGroup(masks, negate)
19 return function()
20 if (not negate) then
21 for idx, mask in masks do
22 if (mask()) then
23 return true
24 end
25 end
26 return false
27 else
28 for idx, mask in masks do
29 if (mask()) then
30 return false
31 end
32 end
33 return true
34 end
35 end
36 end
37  
38  
39 function lazyr.masks.ComboPoints(cp, gtLtEq)
40 cp = tonumber(cp)
41 return function()
42 if (not gtLtEq or gtLtEq == "") then
43 return (GetComboPoints() >= cp)
44 end
45 if (gtLtEq == ">") then
46 return (GetComboPoints() > cp)
47 elseif (gtLtEq == "=") then
48 return (GetComboPoints() == cp)
49 else
50 return (GetComboPoints() < cp)
51 end
52 end
53 end
54  
55 function lazyr.masks.IsBeingGanked()
56 return function()
57 return lazyr.ganked
58 end
59 end
60  
61 function lazyr.masks.DebuffSpace()
62 return function()
63 if UnitExists("target") then
64 for i=1,16 do
65 s=UnitDebuff("target", i)
66 if (not s) then
67 return true
68 end
69 end
70 end
71 return false
72 end
73 end
74  
75 function lazyr.masks.IsImmune(action)
76 return function()
77 if (lazyr.perPlayerConf.Immunities[action] and lazyr.perPlayerConf.Immunities[action][UnitName("target")]) then
78 if (lazyr.perPlayerConf.showReasonForTargetCCd) then
79 lazyr.p("-ifTargetImmune: "..UnitName("target").." has immunity to "..action)
80 end
81 return true
82 end
83 return false
84 end
85 end
86  
87  
88 function lazyr.masks.IsFlagRunner()
89 return function()
90 if (not lrLocale.BGWGTEXT0) then
91 lazyr.p("Sorry, ifFlagRunner not supported for your locale.")
92 return false
93 end
94 if (UnitName("target")==lazyr.flagHolder) and UnitExists("target") then
95 return true
96 else
97 return false
98 end
99 end
100 end
101  
102 function lazyr.masks.IsFlaggedPVP(unit)
103 return function()
104 if unit ~= "Target" then
105 if UnitIsPVP("player") then
106 return true
107 else
108 return false
109 end
110 else
111 if (UnitIsPVP("target") and UnitIsEnemy("target","player") and UnitExists("target")) then
112 return true
113 else
114 return false
115 end
116 end
117 end
118 end
119  
120 function lazyr.masks.IsDueling()
121 return function()
122 return lazyr.InDuel
123 end
124 end
125  
126  
127 function lazyr.masks.IsBeingAttackedBy(num, gtLtEq)
128 num = tonumber(num)
129 return function()
130 if (not gtLtEq or gtLtEq == "") then
131 return (lazyr.numberOfAttackers >= num)
132 end
133 if (gtLtEq == ">") then
134 return (lazyr.numberOfAttackers > num)
135 elseif (gtLtEq == "=") then
136 return (lazyr.numberOfAttackers == num)
137 else
138 return (lazyr.numberOfAttackers < num)
139 end
140 end
141 end
142  
143 function lazyr.masks.IsTargetOfTarget()
144 return function()
145 return UnitIsUnit("player", "targettarget")
146 end
147 end
148  
149 function lazyr.masks.IsTargetOfTargetClass(class)
150 return function()
151 return (class == UnitClass("targettarget"))
152 end
153 end
154  
155  
156 -- :-(
157 function lazyr.masks.IsStealthed()
158 local icon, name, active, castable = GetShapeshiftFormInfo(1)
159 return (active == 1)
160 end
161  
162 function lazyr.masks.IsStealthedMask()
163 return function()
164 return lazyr.masks.IsStealthed()
165 end
166 end
167  
168 function lazyr.masks.BehindAttackHasNotFailedRecently()
169 return function()
170 return ((GetTime() - lazyr.behindAttackLastFailedAt) >= .3)
171 end
172 end
173  
174 function lazyr.masks.BehindAttackFailedRecently()
175 return function()
176 return ((GetTime() - lazyr.behindAttackLastFailedAt) < .3)
177 end
178 end
179  
180 function lazyr.masks.InFrontAttackHasNotFailedRecently()
181 return function()
182 return ((GetTime() - lazyr.inFrontAttackLastFailedAt) >= .3)
183 end
184 end
185  
186 function lazyr.masks.InFrontAttackFailedRecently()
187 return function()
188 return ((GetTime() - lazyr.inFrontAttackLastFailedAt) < .3)
189 end
190 end
191  
192 function lazyr.masks.InCooldown(action)
193 return function()
194 local actionInfo = lazyr.ParseArg(action)
195 if (not actionInfo) then
196 return false
197 end
198 local action = actionInfo[1]
199 local start, duration, enable = GetActionCooldown(action:GetSlot());
200 if ( (duration - (GetTime() - start)) > 1) then
201 return true
202 else
203 return false
204 end
205 end
206 end
207  
208 -- :-(
209 function lazyr.masks.FindTalentPoints(icon)
210 -- Okay, there is no event that gets fired when talents have changed, so
211 -- normally we'd need to scan the talent tree every single time.
212 -- Instead, for fun, we cache talent point lookups for 1 minute. Not sure
213 -- how much this really helps performance, but hey.
214  
215 local cacheInfo = lazyr.talentCache[icon]
216 if (cacheInfo) then
217 local time = cacheInfo[1]
218 local rank = cacheInfo[2]
219 if (time and time > (GetTime() - 60)) then
220 return rank
221 end
222 end
223  
224 rank = 0
225 for i = 1, GetNumTalentTabs() do
226 for j = 1, GetNumTalents(i) do
227 local name, thisIcon, _, _, rank, max = GetTalentInfo(i, j)
228 if (thisIcon and string.find(thisIcon, icon)) then
229 lazyr.talentCache[icon] = {GetTime(), rank}
230 return rank
231 end
232 end
233 end
234  
235 lazyr.talentCache[icon] = {GetTime(), 0}
236 return 0
237 end
238  
239 -- :-(
240 function lazyr.masks.CalculateBaseEviscDamage(cp)
241 -- find eviscerate rank
242 -- lookup damage cp using damage table
243 local rank = lazyr.actions.eviscerate:GetRank()
244 if (rank == 0) then
245 return false
246 end
247 local eviscDamage = lazyr.eviscDamage[rank][cp]
248 if (not eviscDamage) then
249 lazyr.p("strange, damage lookup failed")
250 return false
251 end
252 --origEviscDamage = eviscDamage
253  
254 -- adjust for Improved Eviscerate, if invested
255 local ieAdjust = { 1.05, 1.1, 1.15 }
256 local tpts = lazyr.masks.FindTalentPoints("Ability_Rogue_Eviscerate")
257 if (tpts > 0) then
258 eviscDamage = eviscDamage * ieAdjust[tpts]
259 end
260  
261 -- adjust for Aggression, if invested
262 local aggrAdjust = { 1.02, 1.04, 1.06 }
263 local tpts = lazyr.masks.FindTalentPoints("Ability_Racial_Avatar")
264 if (tpts > 0) then
265 eviscDamage = eviscDamage * aggrAdjust[tpts]
266 end
267  
268 return eviscDamage
269 end
270  
271 -- :-(
272 function lazyr.masks.CalculateObservedEviscDamage(cp)
273 if (lazyr.perPlayerConf.useEviscTracking) then
274 local observedDamage, observedCt = lazyr.et.GetEviscTrackingInfo(cp)
275 if (observedCt > 0) then
276 --lazyr.d("Calculate Evisc Dmg: Using the OBSERVED Evisc ("..cp.."cp) damage of: "..observedDamage)
277 return observedDamage
278 end
279 end
280  
281 local dmg = lazyr.masks.CalculateBaseEviscDamage(cp)
282 --lazyr.d("Calculate Evisc Dmg: Using the OPTIMAL Evisc ("..cp.."cp) damage of: "..dmg)
283 return dmg
284 end
285  
286 function lazyr.masks.IsEviscKillShot(assumeCBActive, goalPct)
287 return function()
288 local cp = GetComboPoints()
289 if (cp == 0) then
290 return false
291 end
292  
293 local hp = lazyr.masks.GetUnitHealth("target")
294 -- adjust hp for goalPct
295 if (goalPct ~= 100) then
296 hp = hp * (goalPct / 100)
297 end
298  
299 local eviscDamage = lazyr.masks.CalculateObservedEviscDamage(cp)
300  
301 -- adjust for Cold Blood, if we're asked to, or if active
302 if (assumeCBActive or lazyr.masks.HasBuffOrDebuff("player", "buff",
303 lazyr.actions.coldBlood.texture,
304 lrLocale.BUFF_TTS.coldBlood)) then
305 -- Cold Blood guarantees a crit (if it hits)
306 eviscDamage = eviscDamage * 2
307 end
308  
309 --lazyr.d("Adjusted evisc dmg: "..origEviscDamage.." vs "..eviscDamage)
310 --lazyr.d("Avg evisc dmg with "..cp.." combo points is "..eviscDamage..", vs: "..hp)
311 if (hp <= eviscDamage) then
312 if (cp < 5) then
313 lazyr.d("Early eviscerate! Kill shot!")
314 end
315 return true
316 else
317 return false
318 end
319 end
320 end
321  
322 -- :-(
323 -- supported unitIds: player, (enemy) target
324 function lazyr.masks.GetUnitHealth(unitId, wantPct)
325 if (unitId == "player") then
326 if (wantPct) then
327 return (UnitHealth(unitId) / UnitHealthMax(unitId)) * 100
328 else
329 return UnitHealth(unitId)
330 end
331 elseif (unitId == "target") then
332 if (wantPct) then
333 return UnitHealth(unitId)
334 else
335 if (not MobHealth_GetTargetCurHP) then
336 lazyr.p("MobInfo2 (or equivalent) not installed, can't determine target's HP.")
337 -- return something huge
338 return 1000000
339 end
340 local hp = MobHealth_GetTargetCurHP()
341 if (not hp or hp == 0) then
342 -- no mob info, return something huge
343 hp = 1000000
344 end
345 return hp
346 end
347 end
348 end
349  
350 -- :-(
351 -- returns mana, energy, or rage
352 function lazyr.masks.GetUnitMana(unitId, wantPct)
353 -- mana is different than health, we get actual values for everything, even enemies
354 if (wantPct) then
355 return (UnitMana(unitId) / UnitManaMax(unitId)) * 100
356 else
357 return UnitMana(unitId)
358 end
359 end
360  
361 function lazyr.masks.UnitPowerMask(unitId, gtLtEq, val, powerType, wantPct)
362 return function()
363 local compareVal = 0
364  
365 if (powerType == "hp") then
366 compareVal = lazyr.masks.GetUnitHealth(unitId, wantPct)
367 elseif (powerType == "mana" or powerType == "energy") then
368 compareVal = lazyr.masks.GetUnitMana(unitId, wantPct)
369 end
370  
371 if (gtLtEq == ">") then
372 return (compareVal > val)
373 elseif (gtLtEq == "=") then
374 return (compareVal == val)
375 else
376 return (compareVal < val)
377 end
378 end
379 end
380  
381  
382  
383 -- :-(
384 --
385 -- Checking buffs/debuffs is fun!
386 -- We accept one or more of:
387 -- - the buff/debuff texture
388 -- - the Tooltip title
389 -- - a line found inside the body of the tooltip.
390 --
391 function lazyr.masks.HasBuffOrDebuff(unitId, buffOrDebuff, texture, ttTitle, ttBody)
392 local candidates = {}
393 local buffId = 1
394 while true do
395 local thisTexture
396 if (buffOrDebuff == "buff") then
397 thisTexture = UnitBuff(unitId, buffId)
398 else
399 thisTexture = UnitDebuff(unitId, buffId)
400 end
401 if (not thisTexture) then
402 break
403 end
404  
405 if (not texture) then
406 -- no texture criteria given, so just add to list of candidates
407 candidates[buffId] = true
408  
409 elseif (string.find(thisTexture, texture)) then
410 lazyr.d("HasBuffOrDebuff: found texture "..texture.." at buffId: "..buffId)
411 candidates[buffId] = true
412  
413 else
414 candidates[buffId] = false
415 end
416 buffId = buffId + 1
417 end
418  
419 if (ttTitle) then
420 for buffId, isCandidate in ipairs(candidates) do
421 if (isCandidate) then
422 LazyRogue_Tooltip:ClearLines()
423 if (buffOrDebuff == "buff") then
424 LazyRogue_Tooltip:SetUnitBuff(unitId, buffId)
425 else
426 LazyRogue_Tooltip:SetUnitDebuff(unitId, buffId)
427 end
428 local thisTTTitle = LazyRogue_TooltipTextLeft1:GetText()
429 if (thisTTTitle and string.find(thisTTTitle, "^"..ttTitle)) then
430 lazyr.d("HasBuffOrDebuff: found ttTitle "..ttTitle.." at buffId: "..buffId)
431 else
432 lazyr.d("HasBuffOrDebuff: did NOT find ttTitle "..ttTitle.." at buffId: "..buffId)
433 candidates[buffId] = false
434 end
435 end
436 end
437 end
438  
439 if (ttBody) then
440 for buffId, isCandidate in ipairs(candidates) do
441 if (isCandidate) then
442 LazyRogue_Tooltip:ClearLines()
443 if (buffOrDebuff == "buff") then
444 LazyRogue_Tooltip:SetUnitBuff(unitId, buffId)
445 else
446 LazyRogue_Tooltip:SetUnitDebuff(unitId, buffId)
447 end
448 local ttNumlines = LazyRogue_Tooltip:NumLines()
449 for i = 2, ttNumlines do
450 local thisTTBody = getglobal("LazyRogue_TooltipTextLeft"..i):GetText()
451 if (thisTTBody and string.find(thisTTBody, "^"..ttBody)) then
452 lazyr.d("HasBuffOrDebuff: found ttBody "..ttBody.." at buffId: "..buffId)
453 else
454 lazyr.d("HasBuffOrDebuff: did NOT find ttBody "..ttBody.." at buffId: "..buffId)
455 candidates[buffId] = false
456 end
457 end
458 end
459 end
460 end
461  
462 for buffId, isCandidate in ipairs(candidates) do
463 if (isCandidate) then
464 return buffId
465 end
466 end
467  
468 return nil
469 end
470  
471  
472 function lazyr.masks.BuffOrDebuffMask(attack)
473 return function()
474 local unitId = "target"
475 local buffOrDebuff = "debuff"
476 local texture
477 local ttTitle
478 if (attack == "Adrenaline") then
479 unitId = "player"
480 buffOrDebuff = "buff"
481 texture = lazyr.actions.adrenalineRush.texture
482 ttTitle = lrLocale.BUFF_TTS.adrenalineRush
483 elseif (attack == "Berserking") then
484 unitId = "player"
485 buffOrDebuff = "buff"
486 texture = lazyr.actions.berserking.texture
487 ttTitle = lrLocale.BUFF_TTS.berserking
488 elseif (attack == "BladeFlurry") then
489 unitId = "player"
490 buffOrDebuff = "buff"
491 texture = lazyr.actions.bladeFlurry.texture
492 ttTitle = lrLocale.BUFF_TTS.bladeFlurry
493 elseif (attack == "Blind") then
494 texture = lazyr.actions.blind.texture
495 ttTitle = lrLocale.BUFF_TTS.blind
496 elseif (attack == "ColdBlood") then
497 unitId = "player"
498 buffOrDebuff = "buff"
499 texture = lazyr.actions.coldBlood.texture
500 ttTitle = lrLocale.BUFF_TTS.coldBlood
501 elseif (attack == "Cs") then
502 texture = lazyr.actions.cheapShot.texture
503 ttTitle = lrLocale.BUFF_TTS.cheapShot
504 elseif (attack == "Evasion") then
505 unitId = "player"
506 buffOrDebuff = "buff"
507 texture = lazyr.actions.evasion.texture
508 ttTitle = lrLocale.BUFF_TTS.evasion
509 elseif (attack == "Expose") then
510 texture = lazyr.actions.exposeArmor.texture
511 ttTitle = lrLocale.BUFF_TTS.exposeArmor
512 elseif (attack == "Garrote") then
513 texture = lazyr.actions.garrote.texture
514 ttTitle = lrLocale.BUFF_TTS.garrote
515 elseif (attack == "Ghostly") then
516 unitId = "player"
517 buffOrDebuff = "buff"
518 texture = lazyr.actions.ghostlyStrike.texture
519 ttTitle = lrLocale.BUFF_TTS.ghostlyStrike
520 elseif (attack == "Gouge") then
521 texture = lazyr.actions.gouge.texture
522 ttTitle = lrLocale.BUFF_TTS.gouge
523 elseif (attack == "Hemo") then
524 texture = lazyr.actions.hemorrhage.texture
525 ttTitle = lrLocale.BUFF_TTS.hemorrhage
526 elseif (attack == "Ks") then
527 texture = lazyr.actions.kidneyShot.texture
528 ttTitle = lrLocale.BUFF_TTS.kidneyShot
529 elseif (attack == "RecentlyBandaged") then
530 unitId = "player"
531 texture = "INV_Misc_Bandage_08"
532 ttTitle = lrLocale.BUFF_TTS.recentlyBandaged
533 elseif (attack == "FirstAid") then
534 unitId = "player"
535 buffOrDebuff = "buff"
536 texture = "Spell_Holy_Heal"
537 ttTitle = lrLocale.BUFF_TTS.firstAid
538 elseif (attack == "Remorseless") then
539 unitId = "player"
540 buffOrDebuff = "buff"
541 texture = "Ability_FiegnDead"
542 ttTitle = lrLocale.BUFF_TTS.remorseless
543 elseif (attack == "Rupture") then
544 texture = lazyr.actions.rupture.texture
545 ttTitle = lrLocale.BUFF_TTS.rupture
546 elseif (attack == "Sap") then
547 texture = lazyr.actions.sap.texture
548 ttTitle = lrLocale.BUFF_TTS.sap
549 elseif (attack == "Snd") then
550 unitId = "player"
551 buffOrDebuff = "buff"
552 texture = lazyr.actions.sliceNDice.texture
553 ttTitle = lrLocale.BUFF_TTS.sliceNDice
554 elseif (attack == "Stealth") then
555 unitId = "player"
556 buffOrDebuff = "buff"
557 texture = lazyr.actions.stealth.texture
558 ttTitle = lrLocale.BUFF_TTS.stealth
559 elseif (attack == "Vanish") then
560 unitId = "player"
561 buffOrDebuff = "buff"
562 texture = lazyr.actions.vanish.texture
563 ttTitle = lrLocale.BUFF_TTS.vanish
564 else
565 lazyr.p("internal error, unknown attack: "..attack)
566 return false
567 end
568  
569 return lazyr.masks.HasBuffOrDebuff(unitId, buffOrDebuff, texture, ttTitle)
570 end
571 end
572  
573 function lazyr.masks.TargetClass(class)
574 return function()
575 return (class == UnitClass("target"))
576 end
577 end
578  
579 function lazyr.masks.TargetLevel(gtLtEq, val)
580 return function()
581 if (not UnitExists("target")) then
582 return false
583 end
584 local tLevel = UnitLevel("target")
585 if (tLevel == -1) then
586 -- "??"
587 -- means target is > 10 levels above the player.
588 -- hmm, special case. we can still be smart here.
589 -- if the criteria was greater than something, where something
590 -- is at most your level + 10, then we can return true.
591 -- otherwise we can't be sure.
592 local pLevel = UnitLevel("player")
593 if (gtLtEq == ">" and (val <= pLevel + 10)) then
594 return true
595 end
596 return false
597 end
598  
599 if (gtLtEq == ">") then
600 return (tLevel > val)
601 elseif (gtLtEq == "=") then
602 return (tLevel == val)
603 else
604 return (tLevel < val)
605 end
606 end
607 end
608  
609 function lazyr.masks.TargetMyLevel(gtLtEq, val)
610 return function()
611 if (not UnitExists("target")) then
612 return false
613 end
614 local tLevel = tonumber(UnitLevel("target"))
615 local pLevel = tonumber(UnitLevel("player"))
616 local tmp=pLevel+val
617 --not sure how to code this with the information availble
618 --if (tLevel == -1) then
619 -- "??"
620 -- means target is > 10 levels above the player.
621 -- hmm, special case. we can still be smart here.
622 -- if the criteria was greater than something, where something
623 -- is at most your level + 10, then we can return true.
624 -- otherwise we can't be sure.
625 -- if (gtLtEq == ">" and (tmp <= pLevel + 10)) then
626 -- return true
627 -- end
628 -- return false
629 -- end
630 if (gtLtEq == ">") then
631 lazyr.d("Search for target over lvl "..tmp)
632 return (tmp < tLevel)
633 elseif (gtLtEq == "=") then
634 lazyr.d("Search for target equal to lvl "..tmp)
635 return (tmp == tLevel)
636 else
637 lazyr.d("Search for target under lvl "..tmp)
638 return (tmp > tLevel)
639 end
640 end
641 end
642  
643 function lazyr.masks.TargetType(type)
644 return function()
645 return (type == UnitCreatureType("target"))
646 end
647 end
648  
649 function lazyr.masks.TargetNamed(nameRegex)
650 return function()
651 local tName = UnitName("target")
652 if (tName and string.find(tName, nameRegex)) then
653 return true
654 end
655 return false
656 end
657 end
658  
659 function lazyr.masks.TargetNPC()
660 return function()
661 return not UnitIsPlayer("target")
662 end
663 end
664  
665 function lazyr.masks.TargetHostile()
666 return function()
667 -- http://www.wowwiki.com/API_UnitReaction
668 local reaction = UnitReaction("player", "target")
669 if (not reaction) then
670 -- dunno...
671 return false
672 end
673 return (reaction <= 3)
674 end
675 end
676  
677 function lazyr.masks.TargetInCombat()
678 return function()
679 return UnitAffectingCombat("target")
680 end
681 end
682  
683 function lazyr.masks.TargetAlive()
684 return function()
685 if UnitName("target") then
686 return (not UnitIsDead("target"))
687 else
688 return false
689 end
690 end
691 end
692  
693 function lazyr.masks.TargetCCd()
694 return function()
695 for texture, ttInfo in lrLocale.CC_TTS do
696 local ttTitle = ttInfo[1]
697 local ttBody = ttInfo[2]
698 if (lazyr.masks.HasBuffOrDebuff("target", "debuff", texture, ttTitle, ttBody)) then
699 if (lazyr.perPlayerConf.showReasonForTargetCCd) then
700 if (not ttTitle) then
701 ttTitle = texture
702 end
703 lazyr.p("ifTargetCCd: target afflicted by "..ttTitle)
704 end
705 return true
706 end
707 end
708 return false
709 end
710 end
711  
712 function lazyr.masks.IsMarked()
713 return function()
714 if (not lrLocale.HuntersMark_TTS) then
715 lazyr.p("Sorry, ifHuntersMark not supported for your locale.")
716 return false
717 end
718 for texture, ttTitle in lrLocale.HuntersMark_TTS do
719 if (lazyr.masks.HasBuffOrDebuff("player", "debuff", texture, ttTitle)) then
720 lazyr.d("player afflicted by Hunter's Mark")
721 return true
722 end
723 end
724 return false
725 end
726 end
727  
728 function lazyr.masks.IsPolymorphed()
729 return function()
730 if (not lrLocale.Polymorph_TTS) then
731 lazyr.p("Sorry, ifPolymorphed not supported for your locale.")
732 return false
733 end
734 for texture, ttTitle in lrLocale.Polymorph_TTS do
735 if (lazyr.masks.HasBuffOrDebuff("player", "debuff", texture, ttTitle)) then
736 lazyr.d("player afflicted by Polymorph")
737 return true
738 end
739 end
740 return false
741 end
742 end
743  
744  
745 function lazyr.masks.IsBleeding()
746 return function()
747 if (not lrLocale.Bleed_TTS) then
748 lazyr.p("Sorry, ifBleeding not supported for your locale.")
749 return false
750 end
751 for texture, ttTitle in lrLocale.Bleed_TTS do
752 if (lazyr.masks.HasBuffOrDebuff("player", "debuff", texture, ttTitle)) then
753 if (lazyr.perPlayerConf.showReasonForTargetCCd) then
754 if (not ttTitle) then
755 ttTitle = texture
756 end
757 lazyr.p("ifBleeding: player afflicted by "..ttTitle)
758 end
759 return true
760 end
761 end
762 return false
763 end
764 end
765  
766 function lazyr.masks.IsDotted()
767 return function()
768 if (not lrLocale.DOT_TTS) then
769 lazyr.p("Sorry, ifDotted not supported for your locale.")
770 return false
771 end
772 for idx, ttBody in lrLocale.DOT_TTS do
773 if (lazyr.masks.HasBuffOrDebuff("player", "debuff", nil, nil, ttBody)) then
774 if (lazyr.perPlayerConf.showReasonForTargetCCd) then
775 lazyr.p("ifDotted: player afflicted by "..ttBody)
776 end
777 return true
778 end
779 end
780 return false
781 end
782 end
783  
784 function lazyr.masks.IsFeared()
785 return function()
786 if (not lrLocale.FEAR_TTS) then
787 lazyr.p("Sorry, ifFeared not supported for your locale.")
788 return false
789 end
790 for idx, ttBody in lrLocale.FEAR_TTS do
791 if (lazyr.masks.HasBuffOrDebuff("player", "debuff", nil, nil, ttBody)) then
792 if (lazyr.perPlayerConf.showReasonForTargetCCd) then
793 lazyr.p("ifFeared: player afflicted by "..ttBody)
794 end
795 return true
796 end
797 end
798 return false
799 end
800 end
801  
802 function lazyr.masks.IsImmobile()
803 return function()
804 if (not lrLocale.IMMOBILE_TTS) then
805 lazyr.p("Sorry, ifImmobile not supported for your locale.")
806 return false
807 end
808 for idx, ttBody in lrLocale.IMMOBILE_TTS do
809 if (lazyr.masks.HasBuffOrDebuff("player", "debuff", nil, nil, ttBody)) then
810 if (lazyr.perPlayerConf.showReasonForTargetCCd) then
811 lazyr.p("ifImmobile: player afflicted by "..ttBody)
812 end
813 return true
814 end
815 end
816 return false
817 end
818 end
819  
820 function lazyr.masks.UnitStunned(unitId)
821 return function()
822 if (not lrLocale.STUNNED_TTS) then
823 lazyr.p("Sorry, if[Target]Stunned not supported for your locale.")
824 return false
825 end
826 for idx, ttBody in lrLocale.STUNNED_TTS do
827 if (lazyr.masks.HasBuffOrDebuff(unitId, "debuff", nil, nil, ttBody)) then
828 if (lazyr.perPlayerConf.showReasonForTargetCCd) then
829 lazyr.p("ifStunned: played afflicted by "..ttBody)
830 end
831 return true
832 end
833 end
834 return false
835 end
836 end
837  
838 function lazyr.masks.UnitSlowed(unitId)
839 return function()
840 if (not lrLocale.SLOWED_TTS) then
841 lazyr.p("Sorry, if[Target]Slowed not supported for your locale.")
842 return false
843 end
844 for idx, ttBody in lrLocale.SLOWED_TTS do
845 if (lazyr.masks.HasBuffOrDebuff(unitId, "debuff", nil, nil, ttBody)) then
846 if (lazyr.perPlayerConf.showReasonForTargetCCd) then
847 lazyr.p("ifSlowed: player afflicted by "..ttBody)
848 end
849 return true
850 end
851 end
852 return false
853 end
854 end
855  
856 function lazyr.masks.IsInstance(unitId)
857 return function()
858 if (not lrLocale.INSTANCES) then
859 lazyr.p("Sorry, ifInstance not supported for your locale.")
860 return false
861 end
862 zone = GetZoneText()
863 for idx, instance in lrLocale.INSTANCES do
864 if string.find(zone, instance) then
865 return true
866 end
867 end
868 return false
869 end
870 end
871 function lazyr.masks.IsBattleground(unitId)
872 return function()
873 for i = 1, MAX_BATTLEFIELD_QUEUES do
874 status, mapName, instanceID = GetBattlefieldStatus(i)
875 if (status == "active") then
876 lazyr.d("You're in batteground: "..mapName)
877 return true
878 end
879  
880 return false
881 end
882 end
883 end
884  
885 function lazyr.masks.TargetIsCasting(nameRegex)
886 return function()
887 if (lazyr.interrupt.targetCasting and ((GetTime() - lazyr.interrupt.castingDetectedAt) <= 5)) then
888 if (not nameRegex or nameRegex == "") then
889 return true
890 end
891 if (string.find(lazyr.interrupt.targetCasting, nameRegex)) then
892 return true
893 end
894 end
895 return false
896 end
897 end
898  
899 -- if any of the exception criteria return true, we return FALSE
900 function lazyr.masks.InterruptExceptionCriteria()
901 return function()
902 lazyr.masks.alreadyInsideInterruptExceptionCriteria = true
903 local actionInfos = lazyr.ParseForm(lrConf.interruptExceptionCriteria)
904 lazyr.masks.alreadyInsideInterruptExceptionCriteria = false
905  
906 for idx, actionInfo in actionInfos do
907 local action = actionInfo[1] -- should be nil
908 local masks = actionInfo[2]
909 local areAllTrue = true
910 if (masks) then
911 for idx, mask in masks do
912 if (not mask()) then
913 areAllTrue = false
914 break
915 end
916 end
917 if (areAllTrue) then
918 -- all criteria on this line returned true, so this mask returns false
919 return false
920 end
921 end
922 end
923  
924 return true
925 end
926 end
927  
928 function lazyr.masks.TargetElite()
929 return function()
930 return string.find(UnitClassification("target"), "elite")
931 end
932 end
933  
934 function lazyr.masks.TargetInMeleRange()
935 return function()
936 return CheckInteractDistance("target", 1)
937 end
938 end
939  
940 function lazyr.masks.TargetInBlindRange()
941 return function()
942 return CheckInteractDistance("target", 2)
943 end
944 end
945  
946 function lazyr.masks.PlayerInCombat()
947 return function()
948 return lazyr.isInCombat
949 end
950 end
951  
952 function lazyr.masks.PlayerInGroup()
953 return function()
954 return (GetNumPartyMembers() > 0)
955 end
956 end
957  
958 function lazyr.masks.PlayerInRaid()
959 return function()
960 return (GetNumRaidMembers() > 0)
961 end
962 end
963  
964 function lazyr.masks.PlayerInGroupOrRaid()
965 return function()
966 return ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0))
967 end
968 end
969  
970  
971 -- if you don't eviscerate now, will you have time for 2 ticks before the target dies?
972 -- we determine the rate of damage, and estimate when the target will be dead
973 -- then we look at the last tick, and add 4 seconds, and see if that's before he'll die.
974 function lazyr.masks.IsLastChance()
975 return function()
976 -- MobInfo-2 required
977 if (not MobHealth_GetTargetCurHP) then
978 return false
979 end
980 if (GetComboPoints() == 0 or not UnitName("target") or UnitHealth("target") == 0) then
981 return false
982 end
983  
984 local n = lazyr.targetHealthHistory:GetN()
985 -- we want at least a couple data points
986 if (n < 3) then
987 return false
988 end
989  
990 local startTime = GetTime()
991  
992 -- m is the slope, or hp per second
993 local m = lazyr.targetHealthHistory:ComputeSlope()
994 if (not m) then
995 return false
996 end
997 if (m >= 0) then
998 lazyr.d("IsLastChance: m is positive? target healing?")
999 return false
1000 end
1001 local currentHp = lazyr.masks.GetUnitHealth("target")
1002 local secondsTilDeath = math.abs(currentHp / m)
1003  
1004 -- now, we know when he'll die.
1005 -- look at the last tick, and add 4 seconds (and a 1/4s buffer), and see
1006 -- if that's before he'll die.
1007 -- Also consider the player's current energy:
1008 -- Maybe we won't need 2 ticks... to be really smart, we'd need to know what attack
1009 -- the player will use if he doesn't evisc right now... well, the maximum attack is
1010 -- backstab (60), but more likely a SS (40-45).
1011 -- Okay, for simplicity let's just assume the player will SS (40).
1012 local ticksNeeded = 2
1013 local currentEnergy = lazyr.masks.GetUnitMana("player")
1014 if (currentEnergy >= 60) then
1015 ticksNeeded = 1
1016 elseif (currentEnergy >= 80) then
1017 ticksNeeded = 0
1018 end
1019 local whenTicks = lazyr.lastTickTime + (ticksNeeded * 2)
1020  
1021 local isLastChance
1022 if ((whenTicks + .25) > (GetTime() + secondsTilDeath)) then
1023 isLastChance = true
1024 else
1025 isLastChance = false
1026 end
1027  
1028 local msg = "IsLastChance: n: "..n..
1029 ", m: "..math.abs(string.format("%.1f", m)).."hp/s, "..
1030 " hp: "..currentHp.. ", DEAD IN "..
1031 string.format("%.1f", secondsTilDeath).."s ("..
1032 string.format("%.1f", (GetTime() - startTime)).."s)"
1033 if (isLastChance) then
1034 msg = msg.." EVISCERATE NOW"
1035 end
1036 msg = msg.."."
1037 lazyr.d(msg)
1038  
1039 return isLastChance
1040 end
1041 end
1042  
1043 function lazyr.masks.IsEquipped(item)
1044 return function()
1045 local itemId
1046 local itemName
1047 if (string.find(item, '^%d')) then
1048 itemId = tonumber(item)
1049 else
1050 itemName = item
1051 end
1052 for slot = 0, 19 do
1053 local link = GetInventoryItemLink("player", slot)
1054 if (link) then
1055 local id, name = lazyr.IdAndNameFromLink(link)
1056 if (id) then
1057 if ((itemId and id == itemId)) then
1058 return true
1059 elseif (itemName) then
1060 if string.lower(name) == string.lower(itemName) then
1061 return true
1062 end
1063 end
1064 end
1065 end
1066 end
1067 return false
1068 end
1069 end
1070  
1071 function lazyr.masks.IsKeyDown(key)
1072 return function()
1073 if (key == "Ctrl") then
1074 return IsControlKeyDown()
1075 elseif (key == "Alt") then
1076 return IsAltKeyDown()
1077 elseif (key == "Shift") then
1078 return IsShiftKeyDown()
1079 end
1080 return false
1081 end
1082 end
1083  
1084 function lazyr.masks.Every(action, seconds)
1085 return function()
1086 if (GetTime() > (action.everyTimer + seconds))or action.everyTimer==nil then
1087 return true
1088 end
1089 return false
1090 end
1091 end
1092  
1093 function lazyr.masks.Timer(action, seconds)
1094 return function()
1095 if lazyr.actions[action] then
1096 if (GetTime() > (lazyr.actions[action].everyTimer + seconds)) then
1097 return true
1098 end
1099 elseif lazyr.forms[action] then
1100 if (GetTime() > (lazyr.setForm[action].everyTimer + seconds)) then
1101 return true
1102 end
1103 elseif lazyr.items[action] then
1104 if (GetTime() > (lazyr.item[action].everyTimer + seconds)) then
1105 return true
1106 end
1107 elseif lazyr.pseudoActions[action] then
1108 if (GetTime() > (lazyr.pseudoActions[action].everyTimer + seconds)) then
1109 return true
1110 end
1111 elseif lazyr.comboActions[action] then
1112 if (GetTime() > (lazyr.comboActions[action].everyTimer + seconds)) then
1113 return true
1114 end
1115 end
1116 return false
1117 end
1118 end
1119  
1120 -- :-(
1121 -- This code is good for a Rogue. It skips over some annoying exceptions that only
1122 -- Hunters and Druids face. Do not rip off this code unless you're writing a Rogue-only addon.
1123 function lazyr.masks.PlayerMountedIndex()
1124 local buffId = 0
1125 local mountBuffIndex = nil
1126 while true do
1127 local buffIndex = GetPlayerBuff(buffId, "HELPFUL|PASSIVE")
1128 if (buffIndex < 0) then
1129 break
1130 end
1131  
1132 local texture = GetPlayerBuffTexture(buffIndex)
1133  
1134 local skip = false
1135  
1136 if (string.find(texture, "Ability_Mount_") or
1137 string.find(texture, "Spell_Nature_Swiftness") or
1138 string.find(texture, "INV_Misc_Foot_Kodo")) then
1139  
1140 -- Whoa, one exception though: Is it really a mount? (Spotted Frostsaber?)
1141 -- or just a Hunter in the party with Aspect of the Pack?
1142 if (string.find(texture, "Ability_Mount_WhiteTiger")) then
1143 lazyr.d("PlayerMountedIndex: Whoa, Ability_Mount_WhiteTiger is suspect, having to parse TT")
1144 LazyRogue_Tooltip:ClearLines()
1145 LazyRogue_Tooltip:SetPlayerBuff(buffIndex)
1146 local ttText = LazyRogue_TooltipTextLeft2:GetText()
1147 if (not string.find(ttText, "^"..lrLocale.MOUNTED_BUFF_TT)) then
1148 lazyr.d("PlayerMountedIndex: IGNORING: it's not really a mount: "..ttText)
1149 skip = true -- uggh, Lua really needs a continue function
1150 end
1151 end
1152  
1153 if (not skip) then
1154 lazyr.d("PlayerMountedIndex: OK, you're mounted: "..texture)
1155 mountBuffIndex = buffIndex
1156 break
1157 end
1158 end
1159  
1160 buffId = buffId + 1
1161 end
1162  
1163 return mountBuffIndex
1164 end
1165  
1166  
1167 function lazyr.masks.PlayerMounted()
1168 return function()
1169 return lazyr.masks.PlayerMountedIndex()
1170 end
1171 end
1172  
1173  
1174 function lazyr.masks.InZone(nameRegex)
1175 return function()
1176 if (string.find(GetRealZoneText(), nameRegex)) then
1177 return true
1178 end
1179 return false
1180 end
1181 end
1182  
1183 function lazyr.masks.IsPoisoned(weapon)
1184 return function()
1185 bMh, tMh, cMh, bOh, tOh, cOh = GetWeaponEnchantInfo();
1186 if (weapon == "MainHand" and bMh) then
1187 return true
1188 elseif (weapon == "OffHand" and bOh) then
1189 return true
1190 else
1191 return false
1192 end
1193 return false
1194 end
1195 end
1196  
1197 function lazyr.masks.IsGlobalCooldown()
1198 return function()
1199 if not lazyr.globalCooldownSlot then
1200 for slot = 1, 120 do
1201 if (not GetActionText(slot)) then -- ignore any Player macros :-)
1202 local text = GetActionTexture(slot)
1203 if (text and (string.find(text, "INV_Misc_Rune_01"))) then
1204 lazyr.globalCooldownSlot = slot
1205 break
1206 end
1207 end
1208 end
1209 if not lazyr.globalCooldownSlot then
1210 lazyr.p("Sorry -if[Not]GlobalCooldown function is not available to this char.")
1211 return false
1212 end
1213 local start, duration, enable = GetActionCooldown(lazyr.globalCooldownSlot)
1214 if (enable > 0) then
1215 return true
1216 else
1217 return false
1218 end
1219  
1220  
1221  
1222 else
1223 local start, duration, enable = GetActionCooldown(lazyr.globalCooldownSlot)
1224 if ( start > 0 and duration > 0 and enable > 0) then
1225 return true
1226 else
1227 return false
1228 end
1229 end
1230 end
1231 end
1232  
1233 function lazyr.masks.History(gtLtEq, val, action)
1234 return function()
1235 local historySize = table.getn(lazyr.actionHistory)
1236 if (gtLtEq == ">") then
1237 local i = val + 1
1238 while true do
1239 if (not lazyr.actionHistory[i]) then
1240 return false
1241 end
1242 if (lazyr.actionHistory[i] == action) then
1243 return true
1244 end
1245 i = i + 1
1246 end
1247 elseif (gtLtEq == "<") then
1248 local i = val - 1
1249 while (i > 0) do
1250 if (lazyr.actionHistory[i] and lazyr.actionHistory[i] == action) then
1251 return true
1252 end
1253 i = i - 1
1254 end
1255 return false
1256 else
1257 if (lazyr.actionHistory[val] and lazyr.actionHistory[val] == action) then
1258 return true
1259 end
1260 return false
1261 end
1262 end
1263 end
1264  
1265  
1266  
1267  
1268 function lazyr.ParseArg(arg)
1269 -- remove comments: # .... or // ....
1270 -- trim leading/trailing whitespace
1271 -- ignore blank lines
1272 arg = string.gsub(arg, "#.*", "")
1273 arg = string.gsub(arg, "//.*", "")
1274 arg = string.gsub(arg, "%-%-.*", "")
1275 arg = string.gsub(arg, "^%s+", "")
1276 arg = string.gsub(arg, "%s+$", "")
1277 if (arg == "") then
1278 return 0
1279 end
1280  
1281 local bits = {}
1282 for bit in string.gfind(arg, "[^\-]+") do
1283 table.insert(bits, bit)
1284 end
1285  
1286 local action
1287 local masks = {}
1288 for idx, bit in bits do
1289 if (string.sub(bit, 1, 6) == "action") then
1290 if (not lazyr.re(bit, "^action=(.+)$")) then
1291 lazyr.p("Can't parse: "..bit)
1292 return nil
1293 end
1294 local thisAction = lazyr.match1
1295 if (not lazyr.otherActions[thisAction]) then
1296 lazyr.otherActions[thisAction] = lazyr.Action:New(thisAction, thisAction)
1297 end
1298 action = lazyr.otherActions[thisAction]
1299 elseif (bit == "adrenaline") then
1300 action = lazyr.actions.adrenalineRush
1301 elseif (bit == "ambush") then
1302 action = lazyr.actions.ambush
1303 elseif (bit == "cbAmbush") then
1304 action = lazyr.comboActions.cbAmbush
1305 elseif (bit == "berserking") then
1306 action = lazyr.actions.berserking
1307 elseif (bit == "bladeFlurry" or bit == "bladeflurry") then
1308 action = lazyr.actions.bladeFlurry
1309 elseif (bit == "blind") then
1310 action = lazyr.actions.blind
1311 elseif (bit == "bs") then
1312 action = lazyr.actions.backstab
1313 table.insert(masks, lazyr.masks.BehindAttackHasNotFailedRecently())
1314 elseif (bit == "cbEvisc" or bit == "cbevisc") then
1315 action = lazyr.comboActions.cbEvisc
1316 elseif (bit == "coldBlood" or bit == "coldblood") then
1317 action = lazyr.actions.coldBlood
1318 elseif (bit == "cs") then
1319 action = lazyr.actions.cheapShot
1320 elseif (bit == "dismount") then
1321 action = lazyr.pseudoActions.dismount
1322 elseif (bit == "evasion") then
1323 action = lazyr.actions.evasion
1324 elseif (bit == "evisc") then
1325 action = lazyr.actions.eviscerate
1326 elseif (bit == "expose") then
1327 action = lazyr.actions.exposeArmor
1328 elseif (bit == "feint") then
1329 action = lazyr.actions.feint
1330 table.insert(masks, lazyr.masks.PlayerInGroupOrRaid())
1331 elseif (bit == "garrote") then
1332 action = lazyr.actions.garrote
1333 table.insert(masks, lazyr.masks.BehindAttackHasNotFailedRecently())
1334 elseif (bit == "ghostly") then
1335 action = lazyr.actions.ghostlyStrike
1336 elseif (bit == "gouge") then
1337 action = lazyr.actions.gouge
1338 table.insert(masks, lazyr.masks.InFrontAttackHasNotFailedRecently())
1339 elseif (bit == "hemo") then
1340 action = lazyr.actions.hemorrhage
1341 elseif (bit == "kick") then
1342 action = lazyr.actions.kick
1343 table.insert(masks, lazyr.masks.TargetInMeleRange())
1344 elseif (bit == "ks") then
1345 action = lazyr.actions.kidneyShot
1346 elseif (bit == "ping") then
1347 action = lazyr.pseudoActions.ping
1348 elseif (bit == "premeditation") then
1349 action = lazyr.actions.premeditation
1350 elseif (bit == "preparation") then
1351 action = lazyr.actions.preparation
1352 elseif (bit == "pickPocket") then
1353 action = lazyr.actions.pickPocket
1354 elseif (bit == "riposte") then
1355 action = lazyr.actions.riposte
1356 elseif (bit == "rupture") then
1357 action = lazyr.actions.rupture
1358 elseif (bit == "sap") then
1359 action = lazyr.actions.sap
1360 elseif (bit == "snd") then
1361 action = lazyr.actions.sliceNDice
1362 elseif (bit == "sprint") then
1363 action = lazyr.actions.sprint
1364 elseif (bit == "ss") then
1365 action = lazyr.actions.sinisterStrike
1366 elseif (bit == "stealth") then
1367 action = lazyr.actions.stealth
1368 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.BuffOrDebuffMask("Stealth"), true))
1369 elseif (bit == "stop") then
1370 action = lazyr.pseudoActions.stop
1371 elseif (bit == "stopAll" or bit == "stopall") then
1372 action = lazyr.pseudoActions.stopAll
1373 elseif (bit == "tea") then
1374 action = lazyr.items.thistleTea
1375 elseif (bit == "perception") then
1376 action = lazyr.actions.humanRacial
1377 elseif (bit == "stoneForm") then
1378 action = lazyr.actions.dwarfRacial
1379 elseif (bit == "escapeArtist") then
1380 action = lazyr.actions.gnomeRacial
1381 elseif (bit == "bloodFury") then
1382 action = lazyr.actions.orcRacial
1383 elseif (bit == "warStomp") then
1384 action = lazyr.actions.taurenRacial
1385 elseif (bit == "forsaken") then
1386 action = lazyr.actions.undeadRacial
1387 elseif (bit == "throw") then
1388 action = lazyr.actions.throw
1389 elseif (bit == "bow") then
1390 action = lazyr.actions.bow
1391 elseif (bit == "gun") then
1392 action = lazyr.actions.gun
1393 elseif (bit == "crossbow") then
1394 action = lazyr.actions.crossbow
1395 elseif (bit == "cannibalize") then
1396 action = lazyr.actions.cannibalize
1397 elseif (bit == "targetAssist") then
1398 action = lazyr.pseudoActions.targetAssist
1399 elseif (bit == "targetNearest") then
1400 action = lazyr.pseudoActions.targetNearest
1401 elseif (bit == "autoAttack") then
1402 action = lazyr.pseudoActions.autoAttack
1403 elseif (string.sub(bit, 1, 11) == "applyPoison") then
1404 lazyr.d("applyPoison")
1405 if (not lazyr.re(bit, "^applyPoison(%a+)=(.+)$")) then
1406 lazyr.p("Can't parse: "..bit)
1407 return nil
1408 end
1409 if (lazyr.match1 ~="MainHand" and lazyr.match1 ~="OffHand") then
1410 lazyr.p("Only MainHand and OffHand available, but not"..lazyr.match1)
1411 return nil
1412 end
1413 local weaponName=lazyr.match1
1414 local poisonName=lazyr.match2
1415 local key = weaponName..":"..poisonName
1416 if (not lazyr.poisonsUse[key]) then
1417 lazyr.poisonsUse[key] = lazyr.applyPoison:New(poisonName, weaponName)
1418 end
1419 action = lazyr.poisonsUse[key]
1420  
1421 elseif (string.sub(bit, 1, 5) == "sayIn") then
1422 if (not lazyr.re(bit, "^sayIn(%a+)=(.+)$")) then
1423 lazyr.p("Can't parse: "..bit)
1424 return nil
1425 end
1426 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
1427 lazyr.p("Unknown channel name: "..lazyr.match1)
1428 return nil
1429 end
1430 -- XXX: this will not work! these globals are set at parse time, but they
1431 -- might be changed before run time!
1432 lazyr.sayInChannel = lazyr.match1
1433 lazyr.sayInMessage = lazyr.match2
1434  
1435 action = lazyr.pseudoActions.sayIn
1436  
1437 elseif (string.sub(bit, 1, 8) == "setForm=") then
1438 if (not lazyr.re(bit, "^setForm=(.+)$")) then
1439 lazyr.p("Can't parse: "..bit)
1440 return nil
1441 end
1442 local form = lazyr.match1
1443 if (not lazyr.forms[form]) then
1444 lazyr.forms[form] = lazyr.SetForm:New("form"..form, form)
1445 end
1446 action = lazyr.forms[form]
1447  
1448 elseif (string.sub(bit, 1, 14) == "equipMainHand=") then
1449 if (not lazyr.re(bit, "^equipMainHand=(.+)$")) then
1450 lazyr.p("Can't parse: "..bit)
1451 return nil
1452 end
1453 local item = lazyr.match1
1454 local itemId
1455 local itemName
1456 if (string.find(item, '^%d')) then
1457 itemId = tonumber(item)
1458 itemName = "Item "..itemId
1459 else
1460 itemName = item
1461 end
1462 if (not lazyr.mainHandItems[item]) then
1463 lazyr.mainHandItems[item] = lazyr.EquipItem:New(item, itemName, itemId, 16)
1464 end
1465 action = lazyr.mainHandItems[item]
1466  
1467 elseif (string.sub(bit, 1, 13) == "equipOffHand=") then
1468 if (not lazyr.re(bit, "^equipOffHand=(.+)$")) then
1469 lazyr.p("Can't parse: "..bit)
1470 return nil
1471 end
1472 local item = lazyr.match1
1473 local itemId
1474 local itemName
1475 if (string.find(item, '^%d')) then
1476 itemId = tonumber(item)
1477 itemName = "Item "..itemId
1478 else
1479 itemName = item
1480 end
1481 if (not lazyr.offHandItems[item]) then
1482 lazyr.offHandItems[item] = lazyr.EquipItem:New(item, itemName, itemId, 17)
1483 end
1484 action = lazyr.offHandItems[item]
1485  
1486 elseif (string.sub(bit, 1, 3) == "use") then
1487 if (not lazyr.re(bit, "^use(E?q?u?i?p?p?e?d?)=?(.+)$")) then
1488 lazyr.p("Can't parse: "..bit)
1489 return nil
1490 end
1491 local equippedOnly = (lazyr.match1 == "Equipped")
1492 local item = lazyr.match2
1493 local itemId
1494 local itemName
1495 if (string.find(item, '^%d')) then
1496 itemId = tonumber(item)
1497 itemName = "Item "..itemId
1498 else
1499 itemName = item
1500 end
1501 local myItemSet
1502 if (equippedOnly) then
1503 myItemSet = lazyr.equippedItems
1504 else
1505 myItemSet = lazyr.items
1506 end
1507 if (not myItemSet[item]) then
1508 myItemSet[item] = lazyr.Item:New(item, itemName, itemId, equippedOnly)
1509 end
1510 action = myItemSet[item]
1511  
1512 elseif (bit == "vanish") then
1513 action = lazyr.actions.vanish
1514  
1515 elseif (lazyr.re(bit, "^if(N?o?t?)Equipped=(.+)$")) then
1516 local negate = lazyr.match1 == "Not"
1517 local item = lazyr.match2
1518 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsEquipped(item), negate))
1519  
1520 elseif (lazyr.re(bit, "^if(N?o?t?)TargetOfTargetClass=(.+)$")) then
1521 local negate = (lazyr.match1 == "Not")
1522  
1523 local subMasks = {}
1524 for class in string.gfind(lazyr.match2, "[^,]+") do
1525 table.insert(subMasks, lazyr.masks.IsTargetOfTargetClass(class))
1526 end
1527  
1528 table.insert(masks, lazyr.masks.maskGroup(subMasks, negate))
1529  
1530 elseif (lazyr.re(bit, "^if(N?o?t?)Dueling$")) then
1531 local negate = lazyr.match1 == "Not"
1532 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsDueling(), negate))
1533  
1534 elseif (lazyr.re(bit, "^if(T?a?r?g?e?t?)FlaggedPVP$")) then
1535 local unit = lazyr.match1
1536 table.insert(masks, lazyr.masks.IsFlaggedPVP(unit))
1537  
1538 elseif (lazyr.re(bit, "^if(N?o?t?)TargetOfTarget$")) then
1539 local negate = (lazyr.match1 == "Not")
1540 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsTargetOfTarget(), negate))
1541  
1542 elseif (lazyr.re(bit, "^if(N?o?t?)Stealthed$")) then
1543 local negate = (lazyr.match1 == "Not")
1544 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsStealthedMask(), negate))
1545  
1546 elseif (lazyr.re(bit, "^if(N?o?t?)InCombat$")) then
1547 local negate = (lazyr.match1 == "Not")
1548 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.PlayerInCombat(), negate))
1549  
1550 elseif (lazyr.re(bit, "^if(N?o?t?)BehindAttackJustFailed$")) then
1551 local negate = (lazyr.match1 == "Not")
1552 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.BehindAttackFailedRecently(), negate))
1553  
1554 elseif (lazyr.re(bit, "^if(N?o?t?)InFrontAttackJustFailed$")) then
1555 local negate = (lazyr.match1 == "Not")
1556 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.InFrontAttackFailedRecently(), negate))
1557  
1558 elseif (lazyr.re(bit, "^if(N?o?t?)InGroup$")) then
1559 local negate = (lazyr.match1 == "Not")
1560 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.PlayerInGroup(), negate))
1561  
1562 elseif (lazyr.re(bit, "^if(N?o?t?)InRaid$")) then
1563 local negate = (lazyr.match1 == "Not")
1564 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.PlayerInRaid(), negate))
1565  
1566 elseif (lazyr.re(bit, "^if(N?o?t?)LastChance$")) then
1567 local negate = (lazyr.match1 == "Not")
1568 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsLastChance(), negate))
1569  
1570 elseif (lazyr.re(bit, "^if(N?o?t?)Mounted$")) then
1571 local negate = (lazyr.match1 == "Not")
1572 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.PlayerMounted(), negate))
1573  
1574 elseif (lazyr.re(bit, "^if(N?o?t?)Instance$")) then
1575 local negate = (lazyr.match1 == "Not")
1576 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsInstance(), negate))
1577  
1578 elseif (lazyr.re(bit, "^if(N?o?t?)Battleground$")) then
1579 local negate = (lazyr.match1 == "Not")
1580 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsBattleground(), negate))
1581  
1582 elseif (lazyr.re(bit, "^if(N?o?t?)Ganked$")) then
1583 local negate = (lazyr.match1 == "Not")
1584 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsBeingGanked(), negate))
1585  
1586 elseif (lazyr.re(bit, "^if(N?o?t?)FlagRunner$")) then
1587 local negate = (lazyr.match1 == "Not")
1588 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsFlagRunner(), negate))
1589  
1590 elseif (lazyr.re(bit, "^if(C?b?)KillShot=?(%d?%d?%d?)%%?$")) then
1591 local assumeCBActive = false
1592 local goalPct = 100
1593 if (bit == "ifKillShot" and action ~= lazyr.actions.eviscerate) then
1594 lazyr.p("-ifKillShot only works with evisc")
1595 return nil
1596 elseif (bit == "^ifCbKillShot$" and action ~= lazyr.comboActions.cbEvisc and
1597 action ~= lazyr.actions.eviscerate) then
1598 lazyr.p("-ifCbKillShot only works with cbevisc or evisc")
1599 return nil
1600 end
1601 if (lazyr.match2 ~= "") then
1602 goalPct = tonumber(lazyr.match2)
1603 end
1604 table.insert(masks, lazyr.masks.IsEviscKillShot(assumeCBActive, goalPct))
1605  
1606 elseif (lazyr.re(bit, "^if([<=>]?)(%d+)cp$") or lazyr.re(bit, "^([<=>]?)(%d+)cp$")) then
1607 local gtLtEq = lazyr.match1
1608 local val = tonumber(lazyr.match2)
1609 table.insert(masks, lazyr.masks.ComboPoints(val, gtLtEq))
1610  
1611 elseif (lazyr.re(bit, "^if([<=>]?)(%d+)attackers$")) then
1612 local gtLtEq = lazyr.match1
1613 local val = tonumber(lazyr.match2)
1614 table.insert(masks, lazyr.masks.IsBeingAttackedBy(val, gtLtEq))
1615  
1616 elseif (lazyr.re(bit, "^if(%a+)([<=>])(%d+)(%%?)(%a+)$") or
1617 lazyr.re(bit, "^(%a+)([<=>])(%d+)(%%?)(%a+)$")) then
1618 local unitId = string.lower(lazyr.match1)
1619 local gtLtEq = lazyr.match2
1620 local val = tonumber(lazyr.match3)
1621 local wantPct = (lazyr.match4 == "%")
1622 local powerType = lazyr.match5
1623  
1624 if (unitId ~= "player" and unitId ~= "target") then
1625 lazyr.p("UnitId must be Player or Target, "..unitId.." not supported.")
1626 return nil
1627 end
1628 if (powerType ~= "hp" and powerType ~= "mana" and powerType ~= "energy") then
1629 lazyr.p("Only hp and mana/energy are supported, not: "..powerType)
1630 return nil
1631 end
1632  
1633 table.insert(masks, lazyr.masks.UnitPowerMask(unitId, gtLtEq, val, powerType, wantPct))
1634  
1635 elseif (lazyr.re(bit, "^if(N?o?t?)(%a-)(N?o?t?)Active$")) then
1636 -- Okay, this is a little messy, but it will fix up those
1637 -- N?o?t?s from capturing pieces of %a- they shouldn't.
1638 if (lazyr.match1 ~= "" and lazyr.match1 ~= "Not") then
1639 lazyr.match2 = lazyr.match1..lazyr.match2
1640 end
1641 if (lazyr.match3 ~= "" and lazyr.match3 ~= "Not") then
1642 lazyr.match2 = lazyr.match2..lazyr.match3
1643 end
1644 local attack = lazyr.match2
1645 local negate = (lazyr.match1 == "Not" or lazyr.match3 == "Not")
1646  
1647 if (attack ~= "Adrenaline" and attack ~= "Berserking"
1648 and attack ~= "BladeFlurry" and attack ~= "Blind" and attack ~= "ColdBlood"
1649 and attack ~= "Cs" and attack ~= "Evasion"
1650 and attack ~= "Expose" and attack ~= "Garrote" and attack ~= "Ghostly"
1651 and attack ~= "Gouge" and attack ~= "FirstAid"
1652 and attack ~= "Hemo" and attack ~= "Ks"
1653 and attack ~= "RecentlyBandaged" and attack ~= "Remorseless"
1654 and attack ~= "Rupture" and attack ~= "Sap" and attack ~= "Snd"
1655 and attack ~= "Vanish") then
1656 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)
1657 return nil
1658 end
1659  
1660 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.BuffOrDebuffMask(attack), negate))
1661  
1662 elseif (lazyr.re(bit, "^if(N?o?t?)GlobalCooldown$")) then
1663 local negate = (lazyr.match1 == "Not" )
1664 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsGlobalCooldown(), negate))
1665  
1666 elseif (lazyr.re(bit, "^if(N?o?t?)TargetClass=?(.+)$")) then
1667 local negate = (lazyr.match1 == "Not")
1668 local subMasks = {}
1669 for class in string.gfind(lazyr.match2, "[^,]+") do
1670 table.insert(subMasks, lazyr.masks.TargetClass(class))
1671 end
1672 table.insert(masks, lazyr.masks.maskGroup(subMasks, negate))
1673  
1674 elseif (lazyr.re(bit, "^if(N?o?t?)TargetLevel([<=>])(%d+)$")) then
1675 local negate = (lazyr.match1 == "Not" )
1676 local gtLtEq = lazyr.match2
1677 local val = tonumber(lazyr.match3)
1678 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetLevel(gtLtEq, val), negate))
1679  
1680  
1681 elseif (lazyr.re(bit, "^if(N?o?t?)TargetMyLevel([<=>])(%a*)(%d+)$")) then
1682 local val = nil
1683 local negate = (lazyr.match1 == "Not" )
1684 local gtLtEq = lazyr.match2
1685 if lazyr.match3 == "plus" or lazyr.match3 == "" then
1686 val = tonumber(lazyr.match4)
1687 elseif lazyr.match3 == "minus" then
1688 val = tonumber(lazyr.match4*-1)
1689 else
1690 lazyr.d("unable to determine plus/minus sign")
1691 return nil
1692 end
1693 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetMyLevel(gtLtEq, val), negate))
1694  
1695 elseif (lazyr.re(bit, "^if(N?o?t?)TargetType=?(.+)$")) then
1696 local negate = (lazyr.match1 == "Not")
1697 local subMasks = {}
1698 for type in string.gfind(lazyr.match2, "[^,]+") do
1699 table.insert(subMasks, lazyr.masks.TargetType(type))
1700 end
1701 table.insert(masks, lazyr.masks.maskGroup(subMasks, negate))
1702  
1703 elseif (lazyr.re(bit, "^if(N?o?t?)TargetNamed=(.+)$")) then
1704 local negate = (lazyr.match1 == "Not")
1705 local nameRegex = lazyr.match2
1706 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetNamed(nameRegex), negate))
1707  
1708 elseif (lazyr.re(bit, "^if(N?o?t?)TargetNPC$")) then
1709 local negate = (lazyr.match1 == "Not")
1710 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetNPC(), negate))
1711  
1712 elseif (lazyr.re(bit, "^if(N?o?t?)TargetHostile$")) then
1713 local negate = (lazyr.match1 == "Not")
1714 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetHostile(), negate))
1715  
1716 elseif (lazyr.re(bit, "^if(N?o?t?)TargetInCombat$")) then
1717 local negate = (lazyr.match1 == "Not")
1718 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetInCombat(), negate))
1719  
1720 elseif (lazyr.re(bit, "^if(N?o?t?)TargetSlowed$")) then
1721 local negate = (lazyr.match1 == "Not" )
1722 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.UnitSlowed("target"), negate))
1723  
1724 elseif (lazyr.re(bit, "^if(N?o?t?)Slowed$")) then
1725 local negate = (lazyr.match1 == "Not")
1726 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.UnitSlowed("player"), negate))
1727  
1728 elseif (lazyr.re(bit, "^if(N?o?t?)TargetStunned$")) then
1729 local negate = (lazyr.match1 == "Not" )
1730 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.UnitStunned("target"), negate))
1731  
1732 elseif (lazyr.re(bit, "^if(N?o?t?)Stunned$")) then
1733 local negate = (lazyr.match1 == "Not")
1734 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.UnitStunned("player"), negate))
1735  
1736 elseif (lazyr.re(bit, "^if(N?o?t?)Feared$")) then
1737 local negate = (lazyr.match1 == "Not")
1738 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsFeared(), negate))
1739  
1740 elseif (lazyr.re(bit, "^if(N?o?t?)Immobile$")) then
1741 local negate = (lazyr.match1 == "Not")
1742 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsImmobile(), negate))
1743  
1744 elseif (lazyr.re(bit, "^if(N?o?t?)TargetAlive$")) then
1745 local negate = (lazyr.match1 == "Not")
1746 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetAlive(), negate))
1747  
1748 elseif (lazyr.re(bit, "^if(N?o?t?)TargetCCd$")) then
1749 local negate = (lazyr.match1 == "Not")
1750 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetCCd(), negate))
1751  
1752 elseif (lazyr.re(bit, "^if(N?o?t?)TargetIsCasting=?(.*)$")) then
1753 local negate = (lazyr.match1 == "Not")
1754 if (lazyr.match2 ~= "") then
1755 local subMasks = {}
1756 for nameRegex in string.gfind(lazyr.match2, "[^,]+") do
1757 table.insert(subMasks, lazyr.masks.TargetIsCasting(nameRegex))
1758 end
1759 table.insert(masks, lazyr.masks.maskGroup(subMasks, negate))
1760 else
1761 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetIsCasting(), negate))
1762 end
1763 -- XXX this is kinda strange, should rethink this.
1764 if (not negate and not lazyr.masks.alreadyInsideInterruptExceptionCriteria) then
1765 table.insert(masks, lazyr.masks.InterruptExceptionCriteria())
1766 end
1767  
1768 elseif (lazyr.re(bit, "^if(N?o?t?)TargetElite$")) then
1769 local negate = (lazyr.match1 == "Not")
1770 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetElite(), negate))
1771  
1772 elseif (lazyr.re(bit, "^if(N?o?t?)(%a+)Down$")) then
1773 local negate = (lazyr.match1 == "Not")
1774 local key = lazyr.match2
1775 if (key ~= "Ctrl" and key ~= "Alt" and key ~= "Shift") then
1776 lazyr.p("Only Ctrl, Alt, and Shift are supported, not: "..key)
1777 end
1778 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsKeyDown(key), negate))
1779  
1780 elseif (lazyr.re(bit, "^every(%d+)s$")) then
1781 if (action == nil) then
1782 lazyr.p("you must put the action before the -everyXXs")
1783 return nil
1784 end
1785 local val = tonumber(lazyr.match1)
1786 table.insert(masks, lazyr.masks.Every(action, val))
1787  
1788 elseif (lazyr.re(bit, "^if(N?o?t?)Timer=(.+)>(.+)s$")) then
1789 if (lazyr.match2 == nil) or (lazyr.match3 == nil) then
1790 lazyr.p("syntax eg. -ifTimer=gouge>5s")
1791 return nil
1792 end
1793 local negate = (lazyr.match1 == "Not")
1794 local val = tonumber(lazyr.match3)
1795 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.Timer(string.lower(lazyr.match2), val), negate))
1796  
1797 elseif (lazyr.re(bit, "^if(N?o?t?)Zone=(.+)$")) then
1798 local negate = (lazyr.match1 == "Not")
1799 local nameRegex = lazyr.match2
1800 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.InZone(nameRegex), negate))
1801  
1802 elseif (lazyr.re(bit, "^if(N?o?t?)History([<=>])(%d+)=(.+)$")) then
1803 local negate = (lazyr.match1 == "Not")
1804 local gtLtEq = lazyr.match2
1805 local val = tonumber(lazyr.match3)
1806 local action = lazyr.match4
1807 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.History(gtLtEq, val, action), negate))
1808  
1809 elseif (lazyr.re(bit, "^if(N?o?t?)TargetInMeleeRange$")) then
1810 local negate = (lazyr.match1 == "Not")
1811 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetInMeleRange(), negate))
1812  
1813 elseif (lazyr.re(bit, "^if(N?o?t?)TargetInBlindRange$")) then
1814 local negate = (lazyr.match1 == "Not")
1815 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.TargetInBlindRange(), negate))
1816  
1817 elseif (lazyr.re(bit, "^if(N?o?t?)InCooldown=(.+)$")) then
1818 local negate = (lazyr.match1 == "Not")
1819 local action = lazyr.match2
1820 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.InCooldown(action), negate))
1821  
1822 elseif (lazyr.re(bit, "^if(N?o?t?)Dotted$")) then
1823 local negate = (lazyr.match1 == "Not")
1824 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsDotted(), negate))
1825  
1826 elseif (lazyr.re(bit, "^if(N?o?t?)Bleeding$")) then
1827 local negate = (lazyr.match1 == "Not")
1828 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsBleeding(), negate))
1829  
1830 elseif (lazyr.re(bit, "^if(N?o?t?)HuntersMark$")) then
1831 local negate = (lazyr.match1 == "Not")
1832 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsMarked(), negate))
1833  
1834 elseif (lazyr.re(bit, "^if(N?o?t?)Polymorphed$")) then
1835 local negate = (lazyr.match1 == "Not")
1836 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsPolymorphed(), negate))
1837  
1838 elseif (lazyr.re(bit, "^if(N?o?t?)CanDebuff$")) then
1839 local negate = (lazyr.match1 == "Not")
1840 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.DebuffSpace(), negate))
1841  
1842 elseif (lazyr.re(bit, "^if(N?o?t?)TargetImmune=?(.*)$")) then
1843 local negate = (lazyr.match1 == "Not")
1844 if (lazyr.match2 ~= "") then
1845 local subMasks = {}
1846 for thisAction in string.gfind(lazyr.match2, "[^,]+") do
1847 table.insert(subMasks, lazyr.masks.IsImmune(thisAction))
1848 end
1849 table.insert(masks, lazyr.masks.maskGroup(subMasks, negate))
1850 else
1851 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsImmune(lazyr.match2), negate))
1852 end
1853  
1854 elseif (lazyr.re(bit, "^if(N?o?t?)Poisoned=(%a+)$")) then
1855 if (lazyr.match2 ~="MainHand" and lazyr.match2 ~="OffHand") then
1856 lazyr.p("Only MainHand and OffHand available, but not"..lazyr.match1)
1857 return nil
1858 end
1859 local negate = (lazyr.match1 == "Not")
1860 local targetW = lazyr.match2
1861 table.insert(masks, lazyr.masks.negWrapper(lazyr.masks.IsPoisoned(targetW), negate))
1862  
1863 else
1864 lazyr.d("ParseArg: parse failure: "..arg)
1865 return nil
1866 end
1867 end
1868  
1869 return {action, masks}
1870 end
1871  
1872 function lazyr.ParseForm(args)
1873 local startTime = GetTime()
1874 local actions = {}
1875 for idx, arg in args do
1876 local actionInfo = lazyr.ParseArg(arg)
1877 if (not actionInfo) then
1878 lazyr.p("Can't parse: "..arg)
1879 return nil
1880 elseif (actionInfo == 0) then
1881 -- was empty (comments?) just ignore this
1882 else
1883 table.insert(actions, actionInfo)
1884 end
1885 end
1886 --lazyr.d("ParseForm: time: "..string.format("%f", (GetTime() - startTime)).."s")
1887 return actions
1888 end
1889  
1890 function lazyr.FindForm(formName)
1891 if (not formName) then
1892 return nil
1893 end
1894 for thisFormName, actions in lrConf.forms do
1895 if (thisFormName == formName) then
1896 return actions
1897 end
1898 end
1899 return nil
1900 end
1901  
1902 -- speed optimization, skip parsing and regexes every time
1903 function lazyr.FindParsedForm(formName)
1904 if (not formName) then
1905 return nil
1906 end
1907 local startTime = GetTime()
1908 if (lazyr.parsedFormCache[formName] == nil) then
1909 local actions = lazyr.FindForm(formName)
1910 if (actions) then
1911 lazyr.parsedFormCache[formName] = lazyr.ParseForm(actions)
1912 end
1913 end
1914 --lazyr.d("FindParsedForm: time: "..string.format("%f", (GetTime() - startTime)).."s")
1915 return lazyr.parsedFormCache[formName]
1916 end
1917  
1918 function lazyr.ClearParsedForm(formName)
1919 lazyr.parsedFormCache[formName] = nil
1920 end
1921  
1922 function lazyr.Try(action, masks)
1923 if (masks) then
1924 for idx, mask in masks do
1925 if (not mask()) then
1926 return false
1927 end
1928 end
1929 end
1930 return action:Use()
1931 end
1932  
1933 function lazyr.TryActions(actions)
1934 local actionThatSucceeded = nil
1935  
1936 if (not UnitName("target") and lazyr.perPlayerConf.autoTarget) then
1937 TargetNearestEnemy()
1938 end
1939  
1940 if (actions) then
1941 for idx, actionInfo in actions do
1942 local action = actionInfo[1]
1943 local masks = actionInfo[2]
1944 if (lazyr.Try(action, masks)) then
1945 actionThatSucceeded = action
1946 break
1947 end
1948 end
1949 end
1950  
1951 if (not lazyr.mock
1952 and lazyr.perPlayerConf.initiateAutoAttack
1953 and not actionThatSucceeded
1954 and not lazyr.masks.IsStealthed()) then
1955  
1956 if (not lazyr.IsAutoAttacking()) then
1957 lazyr.d("Initiating auto-attack...")
1958 lazyr.StartAutoAttack()
1959 end
1960 end
1961  
1962 if (actionThatSucceeded) then
1963 return actionThatSucceeded.name
1964 else
1965 return nil
1966 end
1967 end
1968  
1969