From 9f77df0da4d4f22777957074c64c036268e4614e Mon Sep 17 00:00:00 2001 From: 4n0n <4n0n@tinkr.site> Date: Wed, 18 Jan 2023 04:16:50 -0600 Subject: [PATCH] Subtlety --- scripts/outlaw.lua | 65 ++++- scripts/subtlety.lua | 676 +++++++++++++++++++++++++++++++++++++++++++ src/Item/Item.lua | 6 +- src/Spell/Spell.lua | 16 + src/Unit/Unit.lua | 41 ++- 5 files changed, 795 insertions(+), 9 deletions(-) create mode 100644 scripts/subtlety.lua diff --git a/scripts/outlaw.lua b/scripts/outlaw.lua index 79d3f4a..2943c91 100644 --- a/scripts/outlaw.lua +++ b/scripts/outlaw.lua @@ -40,9 +40,12 @@ local AtrophicPosion = Bastion.SpellBook:GetSpell(381637) local Evasion = Bastion.SpellBook:GetSpell(5277) local TricksOfTheTrade = Bastion.SpellBook:GetSpell(57934) local CheapShot = Bastion.SpellBook:GetSpell(1833) +local BagOfTricks = Bastion.SpellBook:GetSpell(312411) +local AutoAttack = Bastion.SpellBook:GetSpell(6603) local IrideusFragment = Bastion.ItemBook:GetItem(193743) local Healthstone = Bastion.ItemBook:GetItem(5512) +local WindscarWhetstone = Bastion.ItemBook:GetItem(137486) local PurgeTarget = Bastion.UnitManager:CreateCustomUnit('purge', function(unit) local purge = nil @@ -133,6 +136,36 @@ local Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit) return tank end) +local Explosive = Bastion.UnitManager:CreateCustomUnit('explosive', function(unit) + local explosive = nil + + Bastion.UnitManager:EnumNameplates(function(unit) + if unit:IsDead() then + return false + end + + if not Player:CanSee(unit) then + return false + end + + if Player:GetDistance(unit) > 40 then + return false + end + + if Player:InMelee(unit) and unit:GetID() == 120651 and Player:IsFacing(unit) then + + explosive = unit + return true + end + end) + + if explosive == nil then + explosive = None + end + + return explosive +end) + local DefaultAPL = Bastion.APL:New('default') local AOEAPL = Bastion.APL:New('aoe') local SpecialAPL = Bastion.APL:New('special') @@ -145,11 +178,22 @@ SpecialAPL:AddSpell( end):SetTarget(KickTarget) ) +SpecialAPL:AddSpell( + SinisterStrike:CastableIf(function(self) + return Explosive:Exists() and not Player:IsCastingOrChanneling() + end):SetTarget(Explosive) +) + SpecialAPL:AddSpell( KidneyShot:CastableIf(function(self) return KickTarget:Exists() and Player:InMelee(KickTarget) and self:IsKnownAndUsable() and - not Player:IsCastingOrChanneling() and Player:GetComboPoints(KickTarget) <= 2 + not Player:IsCastingOrChanneling() and + (Player:GetComboPoints(Target) >= 5 or + ( + Player:GetComboPoints(Target) >= 4 and + (Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp()))) + end):SetTarget(KickTarget) ) @@ -232,6 +276,21 @@ SpecialAPL:AddItem( end):SetTarget(Player) ) +SpecialAPL:AddItem( + WindscarWhetstone:UsableIf(function(self) + return self:IsEquippedAndUsable() and + not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss()) + end):SetTarget(Player) +) + +SpecialAPL:AddSpell( + BagOfTricks:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() + end):SetTarget(Target) +) + -- Adrenaline Rush on cooldown. DefaultAPL:AddSpell( AdrenalineRush:CastableIf(function(self) @@ -341,7 +400,7 @@ DefaultAPL:AddSpell( -- Vanish followed by Ambush if you won't overcap combo points and wait until you have at least 50 energy. DefaultAPL:AddSpell( Vanish:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and + return Tank:Exists() and Target:Exists() and Player:InMelee(Target) and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetComboPoints(Target) <= 4 and @@ -500,7 +559,7 @@ AOEAPL:AddSpell( -- Vanish followed by Ambush if you won't overcap combo points and wait until you have at least 50 energy. AOEAPL:AddSpell( Vanish:CastableIf(function(self) - return Target:Exists() and Player:InMelee(Target) and + return Tank:Exists() and Target:Exists() and Player:InMelee(Target) and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and Player:GetComboPoints(Target) < 5 and diff --git a/scripts/subtlety.lua b/scripts/subtlety.lua new file mode 100644 index 0000000..bafd0f4 --- /dev/null +++ b/scripts/subtlety.lua @@ -0,0 +1,676 @@ +local Tinkr, Bastion = ... + +local SubModulue = Bastion.Module:New('sub') +local Evaluator = Tinkr.Util.Evaluator +local Player = Bastion.UnitManager:Get('player') +local None = Bastion.UnitManager:Get('none') +local Target = Bastion.UnitManager:Get('target') + +local RollTheBones = Bastion.SpellBook:GetSpell(315508) +local SliceAndDice = Bastion.SpellBook:GetSpell(315496) +local BetweenTheEyes = Bastion.SpellBook:GetSpell(315341) +local BladeRush = Bastion.SpellBook:GetSpell(271877) +local Vanish = Bastion.SpellBook:GetSpell(1856) +local Dispatch = Bastion.SpellBook:GetSpell(2098) +local Ambush = Bastion.SpellBook:GetSpell(8676) +local Stealth = Bastion.SpellBook:GetSpell(1784) +local PistolShot = Bastion.SpellBook:GetSpell(185763) +local Opportunity = Bastion.SpellBook:GetSpell(195627) +local SinisterStrike = Bastion.SpellBook:GetSpell(193315) +local GrandMelee = Bastion.SpellBook:GetSpell(193358) +local Broadside = Bastion.SpellBook:GetSpell(193356) +local TrueBearing = Bastion.SpellBook:GetSpell(193359) +local RuthlessPrecision = Bastion.SpellBook:GetSpell(193357) +local SkullAndCrossbones = Bastion.SpellBook:GetSpell(199603) +local BuriedTreasure = Bastion.SpellBook:GetSpell(199600) +local AdrenalineRush = Bastion.SpellBook:GetSpell(13750) +local ShadowDance = Bastion.SpellBook:GetSpell(185313) +local ShadowDanceAura = Bastion.SpellBook:GetSpell(185422) +local Audacity = Bastion.SpellBook:GetSpell(381845) +local Flagellation = Bastion.SpellBook:GetSpell(323654) +local Dreadblades = Bastion.SpellBook:GetSpell(343142) +local JollyRoger = Bastion.SpellBook:GetSpell(199603) +local BladeFlurry = Bastion.SpellBook:GetSpell(13877) +local Kick = Bastion.SpellBook:GetSpell(1766) +local MarkedForDeath = Bastion.SpellBook:GetSpell(137619) +local CrimsonVial = Bastion.SpellBook:GetSpell(185311) +local Shiv = Bastion.SpellBook:GetSpell(5938) +local KidneyShot = Bastion.SpellBook:GetSpell(408) +local InstantPoison = Bastion.SpellBook:GetSpell(315584) +local AtrophicPosion = Bastion.SpellBook:GetSpell(381637) +local Evasion = Bastion.SpellBook:GetSpell(5277) +local TricksOfTheTrade = Bastion.SpellBook:GetSpell(57934) +local CheapShot = Bastion.SpellBook:GetSpell(1833) +local BagOfTricks = Bastion.SpellBook:GetSpell(312411) +local AutoAttack = Bastion.SpellBook:GetSpell(6603) +local SymbolsOfDeath = Bastion.SpellBook:GetSpell(212283) +local ShadowBlades = Bastion.SpellBook:GetSpell(121471) +local ColdBlood = Bastion.SpellBook:GetSpell(382245) +local ShurikenTornado = Bastion.SpellBook:GetSpell(277925) +local ThistleTea = Bastion.SpellBook:GetSpell(381623) +local Gloomblade = Bastion.SpellBook:GetSpell(200758) +local Shadowstrike = Bastion.SpellBook:GetSpell(185438) +local Rupture = Bastion.SpellBook:GetSpell(1943) +local Eviscerate = Bastion.SpellBook:GetSpell(196819) +local NumbingPoison = Bastion.SpellBook:GetSpell(5761) +local ShurikenStorm = Bastion.SpellBook:GetSpell(197835) +local BlackPowder = Bastion.SpellBook:GetSpell(319175) +local SecretTechnique = Bastion.SpellBook:GetSpell(280719) +local DarkBrew = Bastion.SpellBook:GetSpell(310454) + +local IrideusFragment = Bastion.ItemBook:GetItem(193743) +local Healthstone = Bastion.ItemBook:GetItem(5512) +local WindscarWhetstone = Bastion.ItemBook:GetItem(137486) + +local PurgeTarget = Bastion.UnitManager:CreateCustomUnit('purge', function(unit) + local purge = nil + + Bastion.UnitManager:EnumNameplates(function(unit) + if unit:IsDead() then + return false + end + + if not Player:CanSee(unit) then + return false + end + + if Player:GetDistance(unit) > 40 then + return false + end + + if unit:GetAuras():HasAnyStealableAura() then + purge = unit + return true + end + end) + + if purge == nil then + purge = None + end + + return purge +end) + +local KickTarget = Bastion.UnitManager:CreateCustomUnit('kick', function(unit) + local purge = nil + + Bastion.UnitManager:EnumNameplates(function(unit) + if unit:IsDead() then + return false + end + + if not Player:CanSee(unit) then + return false + end + + if Player:GetDistance(unit) > 40 then + return false + end + + if Player:InMelee(unit) and unit:IsInterruptible(5) and Player:IsFacing(unit) then + purge = unit + return true + end + end) + + if purge == nil then + purge = None + end + + return purge +end) + +local Tank = Bastion.UnitManager:CreateCustomUnit('tank', function(unit) + local tank = nil + + Bastion.UnitManager:EnumFriends(function(unit) + if Player:GetDistance(unit) > 40 then + return false + end + + if not Player:CanSee(unit) then + return false + end + + if unit:IsDead() then + return false + end + + if unit:IsTank() then + tank = unit + return true + end + + return false + end) + + if tank == nil then + tank = None + end + + return tank +end) + +local RuptureTarget = Bastion.UnitManager:CreateCustomUnit('rupture', function() + local target = nil + + Bastion.UnitManager:EnumNameplates(function(unit) + if unit:IsDead() then + return false + end + + if not Player:CanSee(unit) then + return false + end + + if not Player:InMelee(unit) then + return false + end + + if not unit:IsAffectingCombat() then + return false + end + + if not Player:IsFacing(unit) then + return false + end + + if ( + not unit:GetAuras():FindMy(Rupture):IsUp() or + unit:GetAuras():FindMy(Rupture):GetRemainingTime() < 6 + ) + then + target = unit + return true + end + end) + + if target == nil then + target = None + end + + return target +end) + +local DefaultAPL = Bastion.APL:New('default') +local AOEAPL = Bastion.APL:New('aoe') +local SpecialAPL = Bastion.APL:New('special') +local RacialsAPL = Bastion.APL:New('racials') + +SpecialAPL:AddSpell( + Kick:CastableIf(function(self) + return KickTarget:Exists() and Player:InMelee(KickTarget) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() + end):SetTarget(KickTarget) +) + +SpecialAPL:AddSpell( + KidneyShot:CastableIf(function(self) + return KickTarget:Exists() and Player:InMelee(KickTarget) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Kick:GetTimeSinceLastCast() > 2 and + (Player:GetComboPoints(Target) >= 5 or + ( + Player:GetComboPoints(Target) >= 4 and + (Player:GetAuras():FindMy(Broadside):IsUp() or Player:GetAuras():FindMy(Opportunity):IsUp()))) + + end):SetTarget(KickTarget) +) + +SpecialAPL:AddSpell( + CheapShot:CastableIf(function(self) + return KickTarget:Exists() and Player:InMelee(KickTarget) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(Stealth):IsUp() + end):SetTarget(KickTarget) +) + +SpecialAPL:AddSpell( + Stealth:CastableIf(function(self) + return self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and not Player:IsAffectingCombat() and + not Player:GetAuras():FindMy(Stealth):IsUp() and not IsMounted() + end):SetTarget(Player) +) + +SpecialAPL:AddSpell( + CrimsonVial:CastableIf(function(self) + return self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetHealthPercent() < 70 + end):SetTarget(Player) +) + +SpecialAPL:AddSpell( + Shiv:CastableIf(function(self) + return PurgeTarget:Exists() and Player:InMelee(PurgeTarget) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and PurgeTarget:GetAuras():HasAnyStealableAura() + end):SetTarget(PurgeTarget) +) + +SpecialAPL:AddSpell( + InstantPoison:CastableIf(function(self) + return self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + not Player:GetAuras():FindMy(InstantPoison):IsUp() and not Player:IsMoving() + end):SetTarget(Player) +) + +SpecialAPL:AddSpell( + AtrophicPosion:CastableIf(function(self) + return self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + not Player:GetAuras():FindMy(AtrophicPosion):IsUp() and not Player:IsMoving() + end):SetTarget(Player) +) + +SpecialAPL:AddSpell( + NumbingPoison:CastableIf(function(self) + return self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + not Player:GetAuras():FindMy(NumbingPoison):IsUp() and not Player:IsMoving() + end):SetTarget(Player) +) + +SpecialAPL:AddItem( + Healthstone:UsableIf(function(self) + return self:IsEquippedAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetHealthPercent() < 40 + end):SetTarget(Player) +) + +SpecialAPL:AddSpell( + TricksOfTheTrade:CastableIf(function(self) + return Tank:Exists() and self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:IsTanking(Target) + end):SetTarget(Tank) +) + +SpecialAPL:AddSpell( + Evasion:CastableIf(function(self) + return self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetHealthPercent() < 40 + end):SetTarget(Player) +) + +SpecialAPL:AddItem( + IrideusFragment:UsableIf(function(self) + return self:IsEquippedAndUsable() and + not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss()) + end):SetTarget(Player) +) + +SpecialAPL:AddItem( + WindscarWhetstone:UsableIf(function(self) + return self:IsEquippedAndUsable() and + not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 2 or Target:IsBoss()) + end):SetTarget(Player) +) + +-- Use Shadowstrike during Shadow Dance. +SpecialAPL:AddSpell( + Shadowstrike:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and Vanish:GetTimeSinceLastCast() <= 3 + end):SetTarget(Target) +) + +RacialsAPL:AddSpell( + BagOfTricks:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() + end):SetTarget(Target) +) + +-- Use Symbols of Death on cooldown as much as possible. +DefaultAPL:AddSpell( + SymbolsOfDeath:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() + end):SetTarget(Player) +) + +-- Use Shadow Blades on cooldown. +DefaultAPL:AddSpell( + ShadowBlades:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() + end):SetTarget(Player) +) + +-- Use Cold Blood before a finishing move, ideally before Secret Technique. +DefaultAPL:AddSpell( + ColdBlood:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetComboPoints(Target) >= 5 and SecretTechnique:GetCooldownRemaining() <= 2 and + Player:GetAuras():FindMy(SliceAndDice):IsUp() and + Target:GetAuras():FindMy(Rupture):IsUp() + end):SetTarget(Player) +) + +-- Line up Shuriken Tornado with Symbols of Death. +DefaultAPL:AddSpell( + ShurikenTornado:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() + end):SetTarget(Player) +) + +-- Use Shadow Dance on cooldown as much as possible. +DefaultAPL:AddSpell( + ShadowDance:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() + end):SetTarget(Player) +) + +-- Use Thistle Tea when low on energy. +DefaultAPL:AddSpell( + ThistleTea:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetPowerDeficit() >= 100 and + ThistleTea:GetTimeSinceLastCast() >= 3 + end):SetTarget(Player) +) + +-- Use Finishing moves with 6 or more combo points (5 or more during Shadow Dance) with the following priority: +-- Cast Slice and Dice if it needs to be refreshed for maintenance or if it is not up. +DefaultAPL:AddSpell( + SliceAndDice:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + (Player:GetComboPoints(Target) >= 6 or + (Player:GetComboPoints(Target) >= 5 and + Player:GetAuras():FindMy(ShadowDanceAura):IsUp())) and + ( + not Player:GetAuras():FindMy(SliceAndDice):IsUp() or + Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() < 12 + ) + end):SetTarget(Player) +) + +-- Cast Rupture if it needs to be refreshed for maintenance or if it is not up. +DefaultAPL:AddSpell( + Rupture:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + (Player:GetComboPoints(Target) >= 6 or + (Player:GetComboPoints(Target) >= 5 and + Player:GetAuras():FindMy(ShadowDanceAura):IsUp())) and ( + not Target:GetAuras():FindMy(Rupture):IsUp() or + Target:GetAuras():FindMy(Rupture):GetRemainingTime() < 12 + ) + end):SetTarget(Target) +) + +-- Secret Technique - Best is to use it during Shadow Dance. +DefaultAPL:AddSpell( + SecretTechnique:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + (Player:GetComboPoints(Target) >= 6 or + (Player:GetComboPoints(Target) >= 5 and + Player:GetAuras():FindMy(ShadowDanceAura):IsUp())) + end):SetTarget(Target) +) + +-- Cast Eviscerate. +DefaultAPL:AddSpell( + Eviscerate:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + (Player:GetComboPoints(Target) >= 6 or + (Player:GetComboPoints(Target) >= 5 and + Player:GetAuras():FindMy(ShadowDanceAura):IsUp())) + end):SetTarget(Target) +) + +-- Vanish - Is a fairly weak cooldown. It is best to use on low combo points for a Shadowstrike cast. Use it after Secret Technique in Shadow Dance when playing with Danse Macabre. +DefaultAPL:AddSpell( + Vanish:CastableIf(function(self) + return Tank:Exists() and Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetComboPoints(Target) < 4 + end):SetTarget(Player) +) + +-- Use Combo Point builder with the following priority: +-- Use Gloomblade outside of Shadow Dance. +DefaultAPL:AddSpell( + Gloomblade:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() + end):SetTarget(Target) +) + +-- Use Shadowstrike during Shadow Dance. +DefaultAPL:AddSpell( + Shadowstrike:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetAuras():FindMy(ShadowDanceAura):IsUp() + end):SetTarget(Target) +) + +-- AOE + +-- Use Symbols of Death on cooldown as much as possible. +AOEAPL:AddSpell( + SymbolsOfDeath:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() + end):SetTarget(Player) +) + +-- Use Shadow Blades on cooldown. +AOEAPL:AddSpell( + ShadowBlades:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() + end):SetTarget(Player) +) + +-- Use Cold Blood before a finishing move. +AOEAPL:AddSpell( + ColdBlood:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetComboPoints(Target) >= 5 and SecretTechnique:GetCooldownRemaining() <= 2 and + Player:GetAuras():FindMy(SliceAndDice):IsUp() and + Target:GetAuras():FindMy(Rupture):IsUp() + end):SetTarget(Player) +) + +-- Line up Shuriken Tornado with Symbols of Death. +AOEAPL:AddSpell( + ShurikenTornado:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetAuras():FindMy(SymbolsOfDeath):IsUp() + end):SetTarget(Target) +) + +-- Use Shadow Dance on cooldown as much as possible. +AOEAPL:AddSpell( + ShadowDance:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() + end):SetTarget(Player) +) + +-- Use Thistle Tea with Shadow Dance. +AOEAPL:AddSpell( + ThistleTea:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and Player:GetPowerDeficit() >= 70 and + ThistleTea:GetTimeSinceLastCast() >= 3 + end):SetTarget(Player) +) + +-- Use Finishing moves with 5 or more combo points with the following priority: +-- Cast Slice and Dice if it needs to be refreshed for maintenance or if it is not up. +AOEAPL:AddSpell( + SliceAndDice:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + (Player:GetComboPoints(Target) >= 6 or + (Player:GetComboPoints(Target) >= 5 and + Player:GetAuras():FindMy(ShadowDanceAura):IsUp())) and + ( + not Player:GetAuras():FindMy(SliceAndDice):IsUp() or + Player:GetAuras():FindMy(SliceAndDice):GetRemainingTime() < 6 + ) + end):SetTarget(Target) +) + +-- Cast Rupture if it needs to be refreshed for maintenance or if it is not up. +AOEAPL:AddSpell( + Rupture:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + (Player:GetComboPoints(Target) >= 6 or + (Player:GetComboPoints(Target) >= 5 and + Player:GetAuras():FindMy(ShadowDanceAura):IsUp())) and ( + not Target:GetAuras():FindMy(Rupture):IsUp() or + Target:GetAuras():FindMy(Rupture):GetRemainingTime() < 12 + ) + end):SetTarget(Target) +) + +-- Cast Rupture on all targets. (scam??) +-- AOEAPL:AddSpell( +-- Rupture:CastableIf(function(self) +-- return RuptureTarget:Exists() and Player:InMelee(RuptureTarget) and +-- self:IsKnownAndUsable() and +-- not Player:IsCastingOrChanneling() and +-- (Player:GetComboPoints(RuptureTarget) >= 6 or +-- (Player:GetComboPoints(RuptureTarget) >= 5 and +-- Player:GetAuras():FindMy(ShadowDanceAura):IsUp())) and ( +-- not RuptureTarget:GetAuras():FindMy(Rupture):IsUp() or +-- RuptureTarget:GetAuras():FindMy(Rupture):GetRemainingTime() < 6 +-- ) +-- end):SetTarget(RuptureTarget) +-- ) + +AOEAPL:AddSpell( + SecretTechnique:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + (Player:GetComboPoints(Target) >= 6 or + (Player:GetComboPoints(Target) >= 5 and + Player:GetAuras():FindMy(ShadowDanceAura):IsUp())) + end):SetTarget(Target) +) + +-- Cast Black Powder with 3 or more targets, 2 or more when talented into Dark Brew. +AOEAPL:AddSpell( + BlackPowder:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + (Player:GetMeleeAttackers() >= 3 or + (Player:GetMeleeAttackers() >= 2 and + DarkBrew:IsKnown())) + end):SetTarget(Target) +) + +-- Cast Eviscerate. +AOEAPL:AddSpell( + Eviscerate:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetComboPoints(Target) >= 5 + end):SetTarget(Target) +) + +-- Vanish - Is a fairly weak cooldown. It is best to use on low combo points for a Shadowstrike cast. Use it after Secret Technique in Shadow Dance when playing with Danse Macabre. +AOEAPL:AddSpell( + Vanish:CastableIf(function(self) + return Tank:Exists() and Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetComboPoints(Target) < 4 + end):SetTarget(Player) +) + +-- Use Combo Point builder with the following priority: +-- Use Shuriken Storm on 2 targets outside of Shadow Dance. +AOEAPL:AddSpell( + ShurikenStorm:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetMeleeAttackers() >= 2 and + not Player:GetAuras():FindMy(ShadowDanceAura):IsUp() + end):SetTarget(Target) +) + +-- Use Shadowstrike on 2 and 3 targets during Shadow Dance or to proc Premeditation. +AOEAPL:AddSpell( + Shadowstrike:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetMeleeAttackers() >= 2 and + Player:GetAuras():FindMy(ShadowDanceAura):IsUp() + end):SetTarget(Target) +) + +-- Use Shuriken Storm +AOEAPL:AddSpell( + ShurikenStorm:CastableIf(function(self) + return Target:Exists() and Player:InMelee(Target) and + self:IsKnownAndUsable() and + not Player:IsCastingOrChanneling() and + Player:GetMeleeAttackers() >= 4 + end):SetTarget(Target) +) + + +SubModulue:Sync(function() + SpecialAPL:Execute() + if Player:GetMeleeAttackers() > 1 then + AOEAPL:Execute() + else + DefaultAPL:Execute() + end + RacialsAPL:Execute() +end) + +Bastion:Register(SubModulue) diff --git a/src/Item/Item.lua b/src/Item/Item.lua index 82139df..9da7492 100644 --- a/src/Item/Item.lua +++ b/src/Item/Item.lua @@ -60,7 +60,7 @@ end -- Get the Items cooldown function Item:GetCooldown() - return select(2, GetItemCooldown(self:GetID())) + return select(2, C_Container.GetItemCooldown(self:GetID())) end -- Return the Usable function @@ -80,7 +80,7 @@ end -- Get the Items cooldown remaining function Item:GetCooldownRemaining() - local start, duration = GetItemCooldown(self:GetID()) + local start, duration = C_Container.GetItemCooldown(self:GetID()) return start + duration - GetTime() end @@ -123,7 +123,7 @@ end -- Check if the Item is on cooldown function Item:IsOnCooldown() - return select(2, GetItemCooldown(self:GetID())) > 0 + return select(2, C_Container.GetItemCooldown(self:GetID())) > 0 end -- Check if the Item is usable diff --git a/src/Spell/Spell.lua b/src/Spell/Spell.lua index ae06614..609fff7 100644 --- a/src/Spell/Spell.lua +++ b/src/Spell/Spell.lua @@ -5,6 +5,7 @@ local Spell = { CastableIfFunc = false, PreCastFunc = false, OnCastFunc = false, + PostCastFunc = false, wasLooking = false, lastCastAt = 0, conditions = {}, @@ -44,6 +45,10 @@ function Spell:New(id) local unit, castGUID, spellID = ... if unit == "player" and spellID == self:GetID() then self.lastCastAt = GetTime() + + if self:GetPostCastFunction() then + self:GetPostCastFunction()(self) + end end end) @@ -55,6 +60,12 @@ function Spell:GetID() return self.spellID end +-- Add post cast func +function Spell:PostCast(func) + self.PostCastFunc = func + return self +end + -- Get the spells name function Spell:GetName() return GetSpellInfo(self:GetID()) @@ -129,6 +140,11 @@ function Spell:Cast(unit, condition) end end +-- Get post cast func +function Spell:GetPostCastFunction() + return self.PostCastFunc +end + -- Check if the spell is known function Spell:IsKnown() local isKnown = IsSpellKnown(self:GetID()) diff --git a/src/Unit/Unit.lua b/src/Unit/Unit.lua index 3b44b3a..5441b0c 100644 --- a/src/Unit/Unit.lua +++ b/src/Unit/Unit.lua @@ -233,9 +233,9 @@ end local isClassicWow = select(4, GetBuildInfo()) < 40000 -- Check if two units are in melee -function Unit:InMelee(unit) - return UnitInMelee(self.unit, unit.unit) -end +-- function Unit:InMelee(unit) +-- return UnitInMelee(self.unit, unit.unit) +-- end local losFlag = bit.bor(0x1, 0x10, 0x100000) @@ -425,4 +425,39 @@ function Unit:IsBehind(unit) return math.abs(angle) > 90 end +function Unit:GetMeleeBoost() + if IsPlayerSpell(196924) then + return 3 + end + return 0 +end + +-- Melee calculation +-- float fMaxDist = fmaxf((float)(*(float*)((uintptr_t)this + 0x1BF8) + 1.3333) + *(float*)((uintptr_t)target + 0x1BF8), 5.0); +-- fMaxDist = fMaxDist + 1.0; +-- Vector3 myPos = ((WoWGameObject*)this)->GetPosition(); +-- Vector3 targetPos = ((WoWGameObject*)target)->GetPosition(); +-- return ((myPos.x - targetPos.x) * (myPos.x - targetPos.x)) + ((myPos.y - targetPos.y) * (myPos.y - targetPos.y)) + ((myPos.z - targetPos.z) * (myPos.z - targetPos.z)) <= (float)(fMaxDist * fMaxDist); + +-- InMelee +function Unit:InMelee(unit) + local x, y, z = ObjectPosition(self.unit) + local x2, y2, z2 = ObjectPosition(unit.unit) + + if not x or not x2 then + return false + end + + local dist = math.sqrt((x - x2) ^ 2 + (y - y2) ^ 2 + (z - z2) ^ 2) + local maxDist = math.max((ObjectCombatReach(self.unit) + 1.3333) + ObjectCombatReach(unit.unit), 5.0) + maxDist = maxDist + 1.0 + self:GetMeleeBoost() + + return dist <= maxDist +end + +-- Get object id +function Unit:GetID() + return ObjectID(self.unit) +end + return Unit