From 33ca6a07076651aa481fb9376871cd118c360721 Mon Sep 17 00:00:00 2001 From: Ryan Crockett Date: Fri, 17 Mar 2023 08:28:26 -0400 Subject: [PATCH] basic frost --- {scripts => references}/brewmaster.lua | 0 {scripts => references}/mistweaver.lua | 0 {scripts => references}/windwalker.lua | 0 scripts/arcane.lua | 54 ++++++++ scripts/fire.lua | 54 ++++++++ scripts/frost.lua | 137 +++++++++++++++++++++ scripts/shared/get-ranged-target-count.lua | 25 ++++ src/ObjectManager/ObjectManager.lua | 1 - src/Spell/Spell.lua | 33 +++++ src/UnitManager/UnitManager.lua | 71 +++++++++++ src/_bastion.lua | 16 ++- 11 files changed, 387 insertions(+), 4 deletions(-) rename {scripts => references}/brewmaster.lua (100%) rename {scripts => references}/mistweaver.lua (100%) rename {scripts => references}/windwalker.lua (100%) create mode 100644 scripts/arcane.lua create mode 100644 scripts/fire.lua create mode 100644 scripts/frost.lua create mode 100644 scripts/shared/get-ranged-target-count.lua diff --git a/scripts/brewmaster.lua b/references/brewmaster.lua similarity index 100% rename from scripts/brewmaster.lua rename to references/brewmaster.lua diff --git a/scripts/mistweaver.lua b/references/mistweaver.lua similarity index 100% rename from scripts/mistweaver.lua rename to references/mistweaver.lua diff --git a/scripts/windwalker.lua b/references/windwalker.lua similarity index 100% rename from scripts/windwalker.lua rename to references/windwalker.lua diff --git a/scripts/arcane.lua b/scripts/arcane.lua new file mode 100644 index 0000000..abafe13 --- /dev/null +++ b/scripts/arcane.lua @@ -0,0 +1,54 @@ +local +Tinkr, +---@type Bastion +Bastion = ... + +local ArcaneModule = Bastion.Module:New('arcane') +local Player = Bastion.UnitManager:Get('player') +local Target = Bastion.UnitManager:Get('target') +local None = Bastion.UnitManager:Get('none') +local AutoAttack = Bastion.SpellBook:GetSpell(6603) + +local CDsEnabled = false + +local Command = Bastion.Command:New('arcane') + +Command:Register('cooldowns', 'Toggle Arcane CDs', function() + CDsEnabled = not CDsEnabled + Bastion:Print('Arcane Cooldowns ' .. (CDsEnabled and 'enabled' or 'disabled')) +end) + +---@return boolean +local function CombatRotation() + return false +end + + +---@return boolean +local function OutOfCombatRotation() + return false +end + + +local isRunning = false + +ArcaneModule:Sync(function() + if not isRunning then + Bastion:Print('Arcane Started') + isRunning = true + end + + if not Player:IsAlive() or Player:IsMounted() then + return false + end + + if Player:IsAffectingCombat() or IsCurrentSpell(AutoAttack:GetID()) then + -- Combat Rotation + return CombatRotation() + else + -- Out Of Combat Rotation + return OutOfCombatRotation() + end +end) + +Bastion:Register(ArcaneModule) \ No newline at end of file diff --git a/scripts/fire.lua b/scripts/fire.lua new file mode 100644 index 0000000..ec360d5 --- /dev/null +++ b/scripts/fire.lua @@ -0,0 +1,54 @@ +local +Tinkr, +---@type Bastion +Bastion = ... + +local FireModule = Bastion.Module:New('fire') +local Player = Bastion.UnitManager:Get('player') +local Target = Bastion.UnitManager:Get('target') +local None = Bastion.UnitManager:Get('none') +local AutoAttack = Bastion.SpellBook:GetSpell(6603) + +local CDsEnabled = false + +local Command = Bastion.Command:New('fire') + +Command:Register('cooldowns', 'Toggle Fire CDs', function() + CDsEnabled = not CDsEnabled + Bastion:Print('Fire Cooldowns ' .. (CDsEnabled and 'enabled' or 'disabled')) +end) + +---@return boolean +local function CombatRotation() + return false +end + + +---@return boolean +local function OutOfCombatRotation() + return false +end + + +local isRunning = false + +FireModule:Sync(function() + if not isRunning then + Bastion:Print('Fire Started') + isRunning = true + end + + if not Player:IsAlive() or Player:IsMounted() then + return false + end + + if Player:IsAffectingCombat() or IsCurrentSpell(AutoAttack:GetID()) then + -- Combat Rotation + return CombatRotation() + else + -- Out Of Combat Rotation + return OutOfCombatRotation() + end +end) + +Bastion:Register(FireModule) \ No newline at end of file diff --git a/scripts/frost.lua b/scripts/frost.lua new file mode 100644 index 0000000..e5a972b --- /dev/null +++ b/scripts/frost.lua @@ -0,0 +1,137 @@ +local +Tinkr, +---@type Bastion +Bastion = ... + +local FrostModule = Bastion.Module:New('frost') +local Player = Bastion.UnitManager:Get('player') +local Target = Bastion.UnitManager:Get('target') +local None = Bastion.UnitManager:Get('none') +local AutoAttack = Bastion.SpellBook:GetSpell(6603) +local Frostbolt = Bastion.SpellBook:GetSpell(116) +local IceLance = Bastion.SpellBook:GetSpell(30455) +local Flurry = Bastion.SpellBook:GetSpell(44614) +local BrainFreeze = Bastion.SpellBook:GetSpell(190446) +local FingersOfFrost = Bastion.SpellBook:GetSpell(44544) +local WintersChill = Bastion.SpellBook:GetSpell(228358) +local FrostNova = Bastion.SpellBook:GetSpell(122) +local IceNova = Bastion.SpellBook:GetSpell(157997) + +local CDsEnabled = false + +local Command = Bastion.Command:New('frost') + +Command:Register('cooldowns', 'Toggle Frost CDs', function() + CDsEnabled = not CDsEnabled + Bastion:Print('Frost Cooldowns ' .. (CDsEnabled and 'enabled' or 'disabled')) +end) + +---@type GetRangedTargetCount +local GetRangedTargetCount = Tinkr:require("scripts/bastion/scripts/shared/get-ranged-target-count", Bastion) + +---@param unit Unit +local function isUnitFrozen(unit) + if not unit:Exists() then return false end + + if unit:GetAuras():FindMy(IceNova):IsUp() or unit:GetAuras():FindMy(FrostNova):IsUp() or unit:GetAuras():FindMy(WintersChill):IsUp() then + return true + end + + return false +end + +local IceLanceTarget = Bastion.UnitManager:CreateCustomUnit('icelance', function() + if not IceLance:IsKnownAndUsable() then return None end + + local icelance_target = nil + + Bastion.UnitManager:EnumEnemies(function(unit) + if unit:IsDead() then + return false + end + + if not Player:CanSee(unit) then + return false + end + + if not IceLance:IsInRange(unit) then + return false + end + + if not Player:IsFacing(unit) then + return false + end + + if IceLance:IsInFlightToUnit(unit) then + return false + end + + if isUnitFrozen(unit) then + icelance_target = unit + return true + end + + return false + end) + + if icelance_target == nil then + icelance_target = None + end + + return icelance_target +end) + +---@return boolean +local function CombatRotation() + if IceLance:IsKnownAndUsable() and IceLanceTarget:Exists() then + return IceLance:Cast(IceLanceTarget) + end + + if Target:Exists() and Player:CanSee(Target) and IceLance:IsKnownAndUsable() and IceLance:IsInRange(Target) and (isUnitFrozen(Target) or Player:GetAuras():FindMy(FingersOfFrost):IsUp()) then + return IceLance:Cast(Target) + end + + if Target:Exists() and Player:CanSee(Target) and Flurry:IsKnownAndUsable() and Player:GetAuras():FindMy(BrainFreeze):IsUp() then + local CastingSpell = Player:GetCastingOrChannelingSpell() + + if Player:IsMoving() or (CastingSpell ~= nil and CastingSpell:GetID() == Frostbolt:GetID()) then + return Flurry:Cast(Target) + end + end + + if Target:Exists() and Player:CanSee(Target) and not Player:IsMoving() and Frostbolt:IsKnownAndUsable() and Frostbolt:IsInRange(Target) then + return Frostbolt:Cast(Target) + end + + return false +end + + +---@return boolean +local function OutOfCombatRotation() + return false +end + + +local isRunning = false + +FrostModule:Sync(function() + if not isRunning then + Bastion:Print('Frost Started') + isRunning = true + end + + if not Player:IsAlive() or Player:IsMounted() then + return false + end + + if Player:IsAffectingCombat() or IsCurrentSpell(AutoAttack:GetID()) then + -- Combat Rotation + return CombatRotation() + else + -- Out Of Combat Rotation + return OutOfCombatRotation() + end +end) + +Bastion:Register(FrostModule) \ No newline at end of file diff --git a/scripts/shared/get-ranged-target-count.lua b/scripts/shared/get-ranged-target-count.lua new file mode 100644 index 0000000..d02cb09 --- /dev/null +++ b/scripts/shared/get-ranged-target-count.lua @@ -0,0 +1,25 @@ +local +Tinkr, +---@type Bastion +Bastion = ... + +local Player = Bastion.UnitManager:Get('player') + +---@alias GetRangedTargetCount fun(range: number): number + +---@type GetRangedTargetCount +local function GetRangedTargetCount(range) + local count = 0 + + Bastion.UnitManager:EnumEnemies(function(unit) + if not unit:IsDead() and unit:IsAffectingCombat() and Player:CanSee(unit) and Player:GetDistance(unit) <= range and Player:IsFacing(unit) then + count = count + 1 + return false + end + return false + end) + + return count +end + +return GetRangedTargetCount \ No newline at end of file diff --git a/src/ObjectManager/ObjectManager.lua b/src/ObjectManager/ObjectManager.lua index 1aaca3d..897e26c 100644 --- a/src/ObjectManager/ObjectManager.lua +++ b/src/ObjectManager/ObjectManager.lua @@ -88,7 +88,6 @@ function ObjectManager:Refresh() self.friends:push(unit) elseif unit:IsEnemy() then self.enemies:push(unit) - if unit:InCombatOdds() > 80 then self.activeEnemies:push(unit) end diff --git a/src/Spell/Spell.lua b/src/Spell/Spell.lua index 35d2d4f..5a39455 100644 --- a/src/Spell/Spell.lua +++ b/src/Spell/Spell.lua @@ -508,4 +508,37 @@ function Spell:IsSpell(spell) return self:GetID() == spell:GetID() end +---@alias Missile table<{ spellId: number, target: string, source: number, my: number, mx: number, mz: number, px: number, py: number, pz: number, uy: number, ux: number, uz: number, hx: number, hy: number, hz: number, iy: number, ix: number, iz: number, px: number, py: number, pz: number }> + +-- IsInFlight +---@return Missile | nil +function Spell:Missile() + local inFlight = nil + + local missiles = Missiles() + + for i, missile in ipairs(missiles) do + if missile.spellId == self:GetID() then + inFlight = missile + end + end + + return inFlight +end + +---@param unit Unit +---@return boolean +function Spell:IsInFlightToUnit(unit) + local missile = self:Missile() + local isInFlight = false + + if missile then + if tostring(missile.target) == tostring(unit:GetGUID()) then + isInFlight = true + end + end + + return isInFlight +end + return Spell diff --git a/src/UnitManager/UnitManager.lua b/src/UnitManager/UnitManager.lua index 059fd92..6c53278 100644 --- a/src/UnitManager/UnitManager.lua +++ b/src/UnitManager/UnitManager.lua @@ -310,4 +310,75 @@ function UnitManager:FindFriendsCentroid(radius, range) return centroid end +-- Get the enemy with the most enemies within a given radius +---@param radius number +---@return Unit +---@return table +function UnitManager:GetEnemyWithMostEnemies(radius) + local unit = nil + local count = 0 + local enemies = {} + self:EnumEnemies(function(u) + if u:IsAlive() then + local c = 0 + self:EnumEnemies(function(other) + if other:IsAlive() and u:GetDistance(other) <= radius then + c = c + 1 + end + end) + if c > count then + unit = u + count = c + enemies = {} + self:EnumEnemies(function(other) + if other:IsAlive() and u:GetDistance(other) <= radius then + table.insert(enemies, other) + end + end) + end + end + end) + return unit, enemies +end + +-- Find the centroid of the most dense area of friends (party/raid members) of a given radius within a given range +---@param radius number +---@param range number +---@return Vector3 | nil +function UnitManager:FindEnemiesCentroid(radius, range) + local unit, enemies = self:GetEnemyWithMostEnemies(radius) + if unit == nil then + return nil + end + + local centroid = Bastion.Vector3:New(0, 0, 0) + local zstart = -math.huge + for i = 1, #enemies do + local p = enemies[i]:GetPosition() + centroid = centroid + p + zstart = p.z > zstart and p.z or zstart + end + + centroid = centroid / #enemies + + if unit:GetPosition():Distance(centroid) > range then + return unit:GetPosition() + end + + local _, _, z = TraceLine( + centroid.x, + centroid.y, + centroid.z + 5, + centroid.x, + centroid.y, + centroid.z - 5, + 0x100151 + ) + + centroid.z = z + 0.01 + + return centroid +end + return UnitManager + diff --git a/src/_bastion.lua b/src/_bastion.lua index b55074f..eba5608 100644 --- a/src/_bastion.lua +++ b/src/_bastion.lua @@ -10,6 +10,8 @@ function Bastion.require(class) return Tinkr:require("scripts/bastion/src/" .. class .. "/" .. class, Bastion) end + + ---@type ClassMagic Bastion.ClassMagic = Bastion.require("ClassMagic") ---@type List @@ -244,7 +246,15 @@ Command:Register('pause', 'Pause a module for X seconds', function (args) end) -if UnitClass('player') == 'Monk' and GetSpecialization() == 1 then - Tinkr:require("scripts/bastion/scripts/brewmaster", Bastion) - Eval('RunMacroText("/bastion module brewmaster")', 'bastion') +if UnitClass('player') == 'Mage' then + if GetSpecialization() == 1 then + Tinkr:require("scripts/bastion/scripts/arcane", Bastion) + Eval('RunMacroText("/bastion module arcane")', 'bastion') + elseif GetSpecialization() == 2 then + Tinkr:require("scripts/bastion/scripts/fire", Bastion) + Eval('RunMacroText("/bastion module fire")', 'bastion') + elseif GetSpecialization() == 3 then + Tinkr:require("scripts/bastion/scripts/frost", Bastion) + Eval('RunMacroText("/bastion module frost")', 'bastion') + end end