From 0c1d11c772d17bbe022a4f55bb6322ab4eb80b65 Mon Sep 17 00:00:00 2001 From: Emlembow <36314674+Emlembow@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:41:19 -0700 Subject: [PATCH] Auto-commit: changes committed --- BMHunter.lua | 400 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 312 insertions(+), 88 deletions(-) diff --git a/BMHunter.lua b/BMHunter.lua index f8d6245..3e258d1 100644 --- a/BMHunter.lua +++ b/BMHunter.lua @@ -1,158 +1,382 @@ +-- Talents: C0PAAAAAAAAAAAAAAAAAAAAAAAMmxGDsALjGaYDAAAAAADAAAAAAgZsNjxMjZYmxMMmZMzYMjZyMMmxMzMmZMDjhZGmlBjZG2A + local Tinkr, Bastion = ... -local BeastMasteryModule = Bastion.Module:New('BeastMasteryHunter') + +local BMHunterModule = Bastion.Module:New('BMHunter') local Player = Bastion.UnitManager:Get('player') -local Target = Bastion.UnitManager:Get('target') local Pet = Bastion.UnitManager:Get('pet') -local Focus = Bastion.UnitManager:Get('focus') + +-- Initialize SpellBook local SpellBook = Bastion.SpellBook:New() -- Spells -local KillCommand = SpellBook:GetSpell(34026) +local HuntersMark = SpellBook:GetSpell(257284) +local BestialWrath = SpellBook:GetSpell(19574) local BarbedShot = SpellBook:GetSpell(217200) +local DireBeast = SpellBook:GetSpell(120679) +local KillCommand = SpellBook:GetSpell(34026) +local BlackArrow = SpellBook:GetSpell(194599) +local KillShot = SpellBook:GetSpell(53351) +local CallOfTheWild = SpellBook:GetSpell(359844) +local Bloodshed = SpellBook:GetSpell(321530) local CobraShot = SpellBook:GetSpell(193455) +local ExplosiveShot = SpellBook:GetSpell(212431) local MultiShot = SpellBook:GetSpell(2643) -local BeastCleave = SpellBook:GetSpell(115939) -local AspectOfTheWild = SpellBook:GetSpell(193530) -local BestialWrath = SpellBook:GetSpell(19574) -local Bloodshed = SpellBook:GetSpell(321530) -local DireBeast = SpellBook:GetSpell(120679) -local Barrage = SpellBook:GetSpell(120360) +local AutoShot = SpellBook:GetSpell(75) +local CallPet = SpellBook:GetSpell(883) +local FeedPet = SpellBook:GetSpell(6991) local CounterShot = SpellBook:GetSpell(147362) -local Intimidation = SpellBook:GetSpell(19577) -local BindingShot = SpellBook:GetSpell(109248) -local FreezingTrap = SpellBook:GetSpell(187650) -local TarTrap = SpellBook:GetSpell(187698) +local MendPet = SpellBook:GetSpell(136) local Exhilaration = SpellBook:GetSpell(109304) -local FeignDeath = SpellBook:GetSpell(5384) -local TranquilizingShot = SpellBook:GetSpell(19801) +local SurvivalOfTheFittest = SpellBook:GetSpell(264735) --- Buffs +-- Buffs and Debuffs local FrenzyBuff = SpellBook:GetSpell(272790) local BeastCleaveBuff = SpellBook:GetSpell(268877) +local BestialWrathBuff = SpellBook:GetSpell(19574) + +-- Custom Units +local BestTarget = Bastion.UnitManager:CreateCustomUnit('besttarget', function() + local bestTarget = nil + local highestHealth = 0 + + Bastion.UnitManager:EnumEnemies(function(unit) + if unit:IsAffectingCombat() and unit:GetDistance(Player) <= 40 and Player:CanSee(unit) then + local health = unit:GetHealth() + if health > highestHealth then + highestHealth = health + bestTarget = unit + end + end + end) + + return bestTarget or Bastion.UnitManager:Get('target') +end) --- Create APLs +local InterruptTarget = Bastion.UnitManager:CreateCustomUnit('interrupttarget', function() + local target = nil + Bastion.UnitManager:EnumEnemies(function(unit) + if unit:IsAffectingCombat() and unit:GetDistance(Player) <= 40 and Player:CanSee(unit) + and unit:IsCasting() and unit:IsInterruptible() then + local castPercentage = GetCastPercentage(unit) + if castPercentage >= 30 and castPercentage <= 80 then + target = unit + return true + end + end + end) + return target or BestTarget +end) + +-- APLs local DefaultAPL = Bastion.APL:New('default') local CooldownAPL = Bastion.APL:New('cooldown') local AoEAPL = Bastion.APL:New('aoe') +local PetAPL = Bastion.APL:New('pet') +local InterruptAPL = Bastion.APL:New('interrupt') local DefensiveAPL = Bastion.APL:New('defensive') -local UtilityAPL = Bastion.APL:New('utility') +local BossAPL = Bastion.APL:New('boss') --- Utility APL -UtilityAPL:AddSpell( - CounterShot:CastableIf(function(self) - return self:IsKnownAndUsable() and (Target:IsCasting() and Target:IsInterruptible() or - (Focus:Exists() and Focus:IsCasting() and Focus:IsInterruptible())) - end):SetTarget(function() return Focus:Exists() and Focus:IsCasting() and Focus or Target end) +-- Helper Functions +local function GetBarbedShotCharges() + return BarbedShot:GetCharges() +end + +local function GetFrenzyStacks() + return Pet:GetAuras():FindMy(FrenzyBuff):GetCount() +end + +local function IsKillerCobraTalented() + -- Implement logic to check if Killer Cobra is talented + -- This is a placeholder and should be replaced with actual talent checking logic + return true +end + +local function IsVenomsBiteTalented() + -- Implement logic to check if Venom's Bite is talented + -- This is a placeholder and should be replaced with actual talent checking logic + return true +end + +local function ShouldUseMultiShot() + local beastCleaveBuff = Pet:GetAuras():FindMy(BeastCleaveBuff) + return Player:GetEnemies(8) >= 2 and (not beastCleaveBuff:IsUp() or beastCleaveBuff:GetRemainingTime() < 2) +end + +local lastFeedTime = 0 +local function ShouldFeedPet() + return GetTime() - lastFeedTime > 1800 -- 30 minutes +end + +local lastAutoAttackTime = 0 +local function IsAutoAttacking() + return GetTime() - lastAutoAttackTime < 2 +end + +local function GetCastPercentage(unit) + local spell, _, _, startTimeMS, endTimeMS = UnitCastingInfo(unit:GetOMToken()) + if not spell then + return 0 + end + local castTime = (endTimeMS - startTimeMS) / 1000 + local elapsed = (GetTime() * 1000 - startTimeMS) / 1000 + return elapsed / castTime * 100 +end + +local function ShouldInterrupt(unit) + local castPercentage = GetCastPercentage(unit) + local randomThreshold = math.random(30, 80) + return castPercentage >= randomThreshold +end + +-- Default APL +DefaultAPL:AddSpell( + AutoShot:CastableIf(function(self) + return BestTarget:Exists() and not IsAutoAttacking() and Player:CanSee(BestTarget) + end):SetTarget(BestTarget):OnCast(function() + lastAutoAttackTime = GetTime() + end) ) -UtilityAPL:AddSpell( - Intimidation:CastableIf(function(self) - return self:IsKnownAndUsable() and Target:IsCasting() and not Target:IsInterruptible() - end):SetTarget(Target) +DefaultAPL:AddSpell( + BarbedShot:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and (GetFrenzyStacks() < 3 or GetBarbedShotCharges() == 2) + end):SetTarget(BestTarget) ) -UtilityAPL:AddSpell( - BindingShot:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetEnemies(30) > 2 - end):SetTarget(Target) +DefaultAPL:AddSpell( + KillCommand:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(BestTarget) ) -UtilityAPL:AddSpell( - TarTrap:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetEnemies(40) > 2 - end):SetTarget(Target) +DefaultAPL:AddSpell( + DireBeast:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(BestTarget) ) -UtilityAPL:AddSpell( - TranquilizingShot:CastableIf(function(self) - return self:IsKnownAndUsable() and Target:GetAuras():HasAnyStealableAura() - end):SetTarget(Target) +DefaultAPL:AddSpell( + KillShot:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and BestTarget:GetHP() < 20 + end):SetTarget(BestTarget) ) --- Defensive APL -DefensiveAPL:AddSpell( - Exhilaration:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetHP() < 30 - end):SetTarget(Player) +DefaultAPL:AddSpell( + CobraShot:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and (Player:GetAuras():FindMy(BestialWrathBuff):IsUp() or Player:GetPower() > 70) + end):SetTarget(BestTarget) ) -DefensiveAPL:AddSpell( - FeignDeath:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetHP() < 15 - end):SetTarget(Player) +DefaultAPL:AddSpell( + ExplosiveShot:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and not Player:GetAuras():FindMy(BestialWrathBuff):IsUp() + end):SetTarget(BestTarget) ) -- Cooldown APL CooldownAPL:AddSpell( - AspectOfTheWild:CastableIf(function(self) - return self:IsKnownAndUsable() - end):SetTarget(Player) + HuntersMark:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and not BestTarget:GetAuras():FindMy(HuntersMark):IsUp() + end):SetTarget(BestTarget) ) CooldownAPL:AddSpell( BestialWrath:CastableIf(function(self) - return self:IsKnownAndUsable() + return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(Player) +) + +CooldownAPL:AddSpell( + BlackArrow:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(BestTarget) +) + +CooldownAPL:AddSpell( + CallOfTheWild:CastableIf(function(self) + return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() end):SetTarget(Player) ) CooldownAPL:AddSpell( Bloodshed:CastableIf(function(self) - return self:IsKnownAndUsable() - end):SetTarget(Target) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(BestTarget) ) -- AoE APL +AoEAPL:AddSpell( + BarbedShot:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and (GetFrenzyStacks() < 3 or GetBarbedShotCharges() == 2) + end):SetTarget(BestTarget) +) + +AoEAPL:AddSpell( + BlackArrow:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(BestTarget) +) + AoEAPL:AddSpell( MultiShot:CastableIf(function(self) - return self:IsKnownAndUsable() and (not Pet:GetAuras():FindMy(BeastCleaveBuff):IsUp() or - Pet:GetAuras():FindMy(BeastCleaveBuff):GetRemainingTime() < 2) - end):SetTarget(Target) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and ShouldUseMultiShot() + end):SetTarget(BestTarget) ) AoEAPL:AddSpell( - Barrage:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetEnemies(10) >= 3 - end):SetTarget(Target) + DireBeast:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(BestTarget) ) --- Default APL -DefaultAPL:AddSpell( - BarbedShot:CastableIf(function(self) - return self:IsKnownAndUsable() and - (Pet:GetAuras():FindMy(FrenzyBuff):GetRemainingTime() < 2 or self:GetCharges() == 2) - end):SetTarget(Target) +AoEAPL:AddSpell( + CallOfTheWild:CastableIf(function(self) + return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(Player) ) -DefaultAPL:AddSpell( +AoEAPL:AddSpell( + BestialWrath:CastableIf(function(self) + return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(Player) +) + +AoEAPL:AddSpell( KillCommand:CastableIf(function(self) - return self:IsKnownAndUsable() - end):SetTarget(Target) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(BestTarget) ) -DefaultAPL:AddSpell( - DireBeast:CastableIf(function(self) - return self:IsKnownAndUsable() - end):SetTarget(Target) +AoEAPL:AddSpell( + BarbedShot:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and GetBarbedShotCharges() > 0 + end):SetTarget(BestTarget) ) -DefaultAPL:AddSpell( +AoEAPL:AddSpell( + CobraShot:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:GetAuras():FindMy(BestialWrathBuff):IsUp() and IsKillerCobraTalented() + end):SetTarget(BestTarget) +) + +AoEAPL:AddSpell( + KillShot:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and IsVenomsBiteTalented() and BestTarget:GetHP() < 20 + end):SetTarget(BestTarget) +) + +AoEAPL:AddSpell( + ExplosiveShot:CastableIf(function(self) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(BestTarget) +) + +AoEAPL:AddSpell( CobraShot:CastableIf(function(self) - return self:IsKnownAndUsable() and Player:GetPower() > 70 and KillCommand:GetCooldownRemaining() > 2 - end):SetTarget(Target) + return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(BestTarget) +) + +-- Pet APL +PetAPL:AddSpell( + CallPet:CastableIf(function(self) + return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and not Pet:Exists() + end):SetTarget(Player) +) + +PetAPL:AddSpell( + FeedPet:CastableIf(function(self) + return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Pet:Exists() and ShouldFeedPet() + end):SetTarget(Pet):OnCast(function() + lastFeedTime = GetTime() + end) ) -BeastMasteryModule:Sync(function() - if not Player:IsAffectingCombat() then return end +PetAPL:AddSpell( + MendPet:CastableIf(function(self) + return Pet:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Pet:GetHP() < 90 and not Pet:GetAuras():FindMy(MendPet):IsUp() + end):SetTarget(Pet) +) + +-- Interrupt APL +InterruptAPL:AddSpell( + CounterShot:CastableIf(function(self) + if not BestTarget:Exists() or not self:IsKnownAndUsable() or Player:IsCastingOrChanneling() then + return false + end + + if BestTarget:IsCasting() and BestTarget:IsInterruptible() then + return ShouldInterrupt(BestTarget) + end + + return false + end):SetTarget(BestTarget) +) + +-- Defensive APL +DefensiveAPL:AddSpell( + Exhilaration:CastableIf(function(self) + return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:GetHP() < 80 + end):SetTarget(Player) +) + +DefensiveAPL:AddSpell( + SurvivalOfTheFittest:CastableIf(function(self) + return self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + and Player:GetHP() < 80 + end):SetTarget(Player) +) + +-- Boss APL +BossAPL:AddSpell( + CallOfTheWild:CastableIf(function(self) + return BestTarget:Exists() and BestTarget:IsBoss() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() + end):SetTarget(Player) +) + +-- Module Sync +BMHunterModule:Sync(function() + if Player:IsMounted() then + return + end - UtilityAPL:Execute() DefensiveAPL:Execute() - - if Player:GetEnemies(10) >= 3 then - AoEAPL:Execute() + DefensiveAPL:Execute() -- Add this line to check defensives + PetAPL:Execute() + + if Player:IsAffectingCombat() then + InterruptAPL:Execute() + local enemyCount = Player:GetEnemies(8) + if enemyCount >= 2 then + AoEAPL:Execute() + else + CooldownAPL:Execute() + DefaultAPL:Execute() + end end - - CooldownAPL:Execute() - DefaultAPL:Execute() end) -Bastion:Register(BeastMasteryModule) \ No newline at end of file +Bastion:Register(BMHunterModule) + +-- Event handler for auto-attack tracking +Bastion.Globals.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function() + local _, subEvent, _, sourceGUID, _, _, _, _, _, _, _, spellID = CombatLogGetCurrentEventInfo() + if sourceGUID == Player:GetGUID() and (subEvent == "SWING_DAMAGE" or subEvent == "SWING_MISSED") then + lastAutoAttackTime = GetTime() + end +end) \ No newline at end of file