parent
4ff584abe2
commit
0c1d11c772
@ -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 self:IsKnownAndUsable() and Player:GetPower() > 70 and KillCommand:GetCooldownRemaining() > 2 |
||||
end):SetTarget(Target) |
||||
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:GetAuras():FindMy(BestialWrathBuff):IsUp() and IsKillerCobraTalented() |
||||
end):SetTarget(BestTarget) |
||||
) |
||||
|
||||
BeastMasteryModule:Sync(function() |
||||
if not Player:IsAffectingCombat() then return end |
||||
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) |
||||
) |
||||
|
||||
UtilityAPL:Execute() |
||||
DefensiveAPL:Execute() |
||||
AoEAPL:AddSpell( |
||||
ExplosiveShot:CastableIf(function(self) |
||||
return BestTarget:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
end):SetTarget(BestTarget) |
||||
) |
||||
|
||||
if Player:GetEnemies(10) >= 3 then |
||||
AoEAPL:Execute() |
||||
AoEAPL:AddSpell( |
||||
CobraShot:CastableIf(function(self) |
||||
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) |
||||
) |
||||
|
||||
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 |
||||
|
||||
DefensiveAPL: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 |
||||
end) |
||||
|
||||
Bastion:Register(BeastMasteryModule) |
||||
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) |
Loading…
Reference in new issue