Add APL Traits

pull/2/head
4n0n 2 years ago
parent 1254134ac4
commit dfa7b56eff
  1. 98
      scripts/subtlety.lua
  2. 168
      src/APL/APL.lua
  3. 17
      src/Unit/Unit.lua
  4. 13
      src/_bastion.lua

@ -37,7 +37,7 @@ 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 Sanguine = Bastion.SpellBook:GetSpell(326509)
local Sanguine = Bastion.SpellBook:GetSpell(226512)
local AtrophicPosion = Bastion.SpellBook:GetSpell(381637)
local Evasion = Bastion.SpellBook:GetSpell(5277)
local TricksOfTheTrade = Bastion.SpellBook:GetSpell(57934)
@ -65,6 +65,7 @@ local IrideusFragment = Bastion.ItemBook:GetItem(193743)
local Healthstone = Bastion.ItemBook:GetItem(5512)
local WindscarWhetstone = Bastion.ItemBook:GetItem(137486)
local DarkMoonRime = Bastion.ItemBook:GetItem(198477)
local AlgetharsPuzzleBox = Bastion.ItemBook:GetItem(193701)
local RimeCards = {
One = Bastion.SpellBook:GetSpell(382844),
@ -191,6 +192,7 @@ local RuptureTarget = Bastion.UnitManager:CreateCustomUnit('rupture', function()
unit:GetAuras():FindMy(Rupture):GetRemainingTime() < 6
)
and unit:TimeToDie() > 12
and unit:GetCombatTime() > 4
then
target = unit
return true
@ -209,17 +211,25 @@ local AOEAPL = Bastion.APL:New('aoe')
local SpecialAPL = Bastion.APL:New('special')
local RacialsAPL = Bastion.APL:New('racials')
local Facing = function(t)
return Bastion.APLTrait:New(function()
return Player:IsFacing(t)
end)
end
SpecialAPL:AddSpell(
Kick:CastableIf(function(self)
return KickTarget:Exists() and Player:InMelee(KickTarget) and
return KickTarget:Exists() and self:IsInRange(KickTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
end):SetTarget(KickTarget)
):AddTraits(
Facing(KickTarget)
)
SpecialAPL:AddSpell(
KidneyShot:CastableIf(function(self)
return KickTarget:Exists() and Player:InMelee(KickTarget) and
return KickTarget:Exists() and self:IsInRange(KickTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Kick:GetTimeSinceLastCast() > 2 and
@ -234,9 +244,10 @@ SpecialAPL:AddSpell(
SpecialAPL:AddSpell(
CheapShot:CastableIf(function(self)
return KickTarget:Exists() and Player:InMelee(KickTarget) and
return KickTarget:Exists() and self:IsInRange(KickTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(Stealth):IsUp()
and not Target:GetAuras():Find(Sanguine):IsUp()
end):SetTarget(KickTarget)
)
@ -258,7 +269,7 @@ SpecialAPL:AddSpell(
SpecialAPL:AddSpell(
Shiv:CastableIf(function(self)
return PurgeTarget:Exists() and Player:InMelee(PurgeTarget) and
return PurgeTarget:Exists() and self:IsInRange(PurgeTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and PurgeTarget:GetAuras():HasAnyStealableAura()
end):SetTarget(PurgeTarget)
@ -326,6 +337,13 @@ SpecialAPL:AddItem(
end):SetTarget(Player)
)
SpecialAPL:AddItem(
AlgetharsPuzzleBox:UsableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and self:IsEquippedAndUsable() and
not Player:IsCastingOrChanneling() and (Player:GetMeleeAttackers() > 3 or Target:IsBoss())
end):SetTarget(Player)
)
SpecialAPL:AddItem(
DarkMoonRime:UsableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and self:IsEquippedAndUsable() and
@ -345,7 +363,7 @@ SpecialAPL:AddItem(
-- Use Shadowstrike during Shadow Dance.
SpecialAPL:AddSpell(
Shadowstrike:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
return Target:Exists() and self:IsInRange(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and Player:GetAuras():FindMy(Premeditation):IsUp() and
Player:GetEnemies(10) <= 3
@ -454,7 +472,7 @@ DefaultAPL:AddSpell(
-- 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
return Target:Exists() and self:IsInRange(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 6 or
@ -466,22 +484,24 @@ DefaultAPL:AddSpell(
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
return Target:Exists() and self:IsInRange(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 Target:GetAuras():FindMy(Rupture):IsUp()
(Player:GetComboPoints(Target) >= 5) and
Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and
(Player:GetAuras():FindMy(DanseMacabre):GetCount() >= 3 or
not DanseMacabre:IsKnown()) and
(not ColdBlood:IsKnown() or
ColdBlood:GetCooldownRemaining() > Player:GetAuras():FindMy(ShadowDanceAura):GetRemainingTime() - 2)
end):SetTarget(Target)
)
-- Cast Eviscerate.
-- Cast Eviscerate if it is available.
DefaultAPL:AddSpell(
Eviscerate:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
return Target:Exists() and self:IsInRange(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 6 or
@ -504,7 +524,7 @@ DefaultAPL:AddSpell(
-- Use Gloomblade outside of Shadow Dance.
DefaultAPL:AddSpell(
Gloomblade:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
return Target:Exists() and self:IsInRange(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
not Player:GetAuras():FindMy(ShadowDanceAura):IsUp()
@ -514,7 +534,7 @@ DefaultAPL:AddSpell(
-- Use Shadowstrike during Shadow Dance.
DefaultAPL:AddSpell(
Shadowstrike:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
return Target:Exists() and self:IsInRange(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetAuras():FindMy(ShadowDanceAura):IsUp()
@ -587,7 +607,7 @@ AOEAPL:AddSpell(
-- Use Thistle Tea with Shadow Dance.
AOEAPL:AddSpell(
ThistleTea:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
return Target:Exists() and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetPowerDeficit() >= 100 and
@ -614,7 +634,7 @@ AOEAPL:AddSpell(
-- 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
return Target:Exists() and self:IsInRange(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5) and (
@ -630,7 +650,7 @@ AOEAPL:AddSpell(
-- Cast Rupture on all targets. (scam??)
AOEAPL:AddSpell(
Rupture:CastableIf(function(self)
return RuptureTarget:Exists() and Player:InMelee(RuptureTarget) and
return RuptureTarget:Exists() and self:IsInRange(RuptureTarget) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(RuptureTarget) >= 6) and (
@ -641,22 +661,25 @@ AOEAPL:AddSpell(
end):SetTarget(RuptureTarget)
)
-- actions.finish+=/secret_technique,if=buff.shadow_dance.up&(buff.danse_macabre.stack>=3|!talent.danse_macabre)&(!talent.cold_blood|cooldown.cold_blood.remains>buff.shadow_dance.remains-2)
AOEAPL:AddSpell(
SecretTechnique:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
return Target:Exists() and self:IsInRange(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 Target:GetAuras():FindMy(Rupture):IsUp()
(Player:GetComboPoints(Target) >= 5) and
Player:GetAuras():FindMy(ShadowDanceAura):IsUp() and
(Player:GetAuras():FindMy(DanseMacabre):GetCount() >= 3 or
not DanseMacabre:IsKnown()) and
(not ColdBlood:IsKnown() or
ColdBlood:GetCooldownRemaining() > Player:GetAuras():FindMy(ShadowDanceAura):GetRemainingTime() - 2)
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
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
(Player:GetComboPoints(Target) >= 5) and
(Player:GetEnemies(10) >= 3 or
@ -668,7 +691,7 @@ AOEAPL:AddSpell(
-- Cast Eviscerate.
AOEAPL:AddSpell(
Eviscerate:CastableIf(function(self)
return Target:Exists() and Player:InMelee(Target) and
return Target:Exists() and self:IsInRange(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetComboPoints(Target) >= 5
@ -689,8 +712,7 @@ AOEAPL:AddSpell(
-- Use Shuriken Storm on 2 targets outside of Shadow Dance.
AOEAPL:AddSpell(
ShurikenStorm:CastableIf(function(self)
return Target:Exists() and Player:GetDistance(Target) <= 10 and
self:IsKnownAndUsable() and
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetEnemies(10) == 2 and
not Player:GetAuras():FindMy(ShadowDanceAura):IsUp()
@ -700,7 +722,7 @@ AOEAPL:AddSpell(
-- 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
return Target:Exists() and self:IsInRange(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetEnemies(10) >= 2 and Player:GetEnemies(10) <= 3 and
@ -708,15 +730,25 @@ AOEAPL:AddSpell(
end):SetTarget(Target)
)
-- Use Shuriken Storm
-- Use Shuriken Storm at > 2 targets.
AOEAPL:AddSpell(
ShurikenStorm:CastableIf(function(self)
return Target:Exists() and Player:GetDistance(Target) <= 10 and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling()
return self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetEnemies(10) > 2
end):SetTarget(Player)
)
-- Use gloomblade at <= 2 targets.
AOEAPL:AddSpell(
Gloomblade:CastableIf(function(self)
return Target:Exists() and self:IsInRange(Target) and
self:IsKnownAndUsable() and
not Player:IsCastingOrChanneling() and
Player:GetEnemies(10) <= 2
end):SetTarget(Target)
)
SubModulue:Sync(function()
SpecialAPL:Execute()
if Player:GetEnemies(10) >= 2 then

@ -1,3 +1,116 @@
-- Create an APL trait for the APL class
local APLTrait = {}
APLTrait.__index = APLTrait
-- Constructor
function APLTrait:New(cb)
local self = setmetatable({}, APLTrait)
self.cb = cb
self.lastcall = 0
return self
end
-- Evaulate the APL trait
function APLTrait:Evaluate()
if GetTime() - self.lastcall > 0.1 then
self.lastresult = self.cb()
self.lastcall = GetTime()
return self.lastresult
end
return self.lastresult
end
-- tostring
function APLTrait:__tostring()
return "Bastion.__APLTrait"
end
-- Create an APL actor for the APL class
local APLActor = {}
APLActor.__index = APLActor
-- Constructor
function APLActor:New(actor)
local self = setmetatable({}, APLActor)
self.actor = actor
self.traits = {}
return self
end
-- Add a trait to the APL actor
function APLActor:AddTraits(...)
for _, trait in ipairs({ ... }) do
table.insert(self.traits, trait)
end
return self
end
-- Get the actor
function APLActor:GetActor()
return self.actor
end
-- Evaulate the APL actor
function APLActor:Evaluate()
for _, trait in ipairs(self.traits) do
if not trait:Evaluate() then
return false
end
end
return true
end
-- Execute
function APLActor:Execute()
if self:GetActor().apl then
if self:GetActor().condition() then
-- print("Bastion: APL:Execute: Executing sub APL " .. self:GetActor().apl.name)
self:GetActor().apl:Execute()
end
end
if self:GetActor().spell then
if self:GetActor().condition then
-- print("Bastion: APL:Execute: Condition for spell " .. self:GetActor().spell:GetName())
self:GetActor().spell:CastableIf(self:GetActor().castableFunc):Cast(self:GetActor().target,
self:GetActor().condition)
end
-- print("Bastion: APL:Execute: No condition for spell " .. self:GetActor().spell:GetName())
self:GetActor().spell:CastableIf(self:GetActor().castableFunc):Cast(self:GetActor().target)
end
if self:GetActor().item then
if self:GetActor().condition then
-- print("Bastion: APL:Execute: Condition for spell " .. self:GetActor().spell:GetName())
self:GetActor().item:UsableIf(self:GetActor().usableFunc):Use(self:GetActor().target,
self:GetActor().condition)
end
-- print("Bastion: APL:Execute: No condition for spell " .. self:GetActor().spell:GetName())
self:GetActor().item:UsableIf(self:GetActor().usableFunc):Use(self:GetActor().target)
end
if self:GetActor().action then
-- print("Bastion: APL:Execute: Executing action " .. self:GetActor().action)
self:GetActor().cb(self)
end
end
-- has traits
function APLActor:HasTraits()
return #self.traits > 0
end
-- tostring
function APLActor:__tostring()
return "Bastion.__APLActor"
end
-- APL (Attack priority list) class
local APL = {}
@ -26,7 +139,9 @@ end
-- Add a manual action to the APL
function APL:AddAction(action, cb)
table.insert(self.apl, { action = action, cb = cb })
local actor = APLActor:New({ action = action, cb = cb })
table.insert(self.apl, actor)
return actor
end
-- Add a spell to the APL
@ -34,7 +149,11 @@ function APL:AddSpell(spell, condition)
local castableFunc = spell.CastableIfFunc
local target = spell:GetTarget()
table.insert(self.apl, { spell = spell, condition = condition, castableFunc = castableFunc, target = target })
local actor = APLActor:New({ spell = spell, condition = condition, castableFunc = castableFunc, target = target })
table.insert(self.apl, actor)
return actor
end
-- Add an item to the APL
@ -42,46 +161,27 @@ function APL:AddItem(item, condition)
local usableFunc = item.UsableIfFunc
local target = item:GetTarget()
table.insert(self.apl, { item = item, condition = condition, usableFunc = usableFunc, target = target })
local actor = APLActor:New({ item = item, condition = condition, usableFunc = usableFunc, target = target })
table.insert(self.apl, actor)
return actor
end
-- Add an APL to the APL (for sub APLs)
function APL:AddAPL(apl, condition)
table.insert(self.apl, { apl = apl, condition = condition })
local actor = APLActor:New({ apl = apl, condition = condition })
table.insert(self.apl, actor)
return actor
end
-- Execute the APL
function APL:Execute()
for _, actor in ipairs(self.apl) do
if actor.apl then
if actor.condition() then
-- print("Bastion: APL:Execute: Executing sub APL " .. actor.apl.name)
actor.apl:Execute()
end
end
if actor.spell then
if actor.condition then
-- print("Bastion: APL:Execute: Condition for spell " .. actor.spell:GetName())
actor.spell:CastableIf(actor.castableFunc):Cast(actor.target,
actor.condition)
end
-- print("Bastion: APL:Execute: No condition for spell " .. actor.spell:GetName())
actor.spell:CastableIf(actor.castableFunc):Cast(actor.target)
end
if actor.item then
if actor.condition then
-- print("Bastion: APL:Execute: Condition for spell " .. actor.spell:GetName())
actor.item:UsableIf(actor.usableFunc):Use(actor.target,
actor.condition)
end
-- print("Bastion: APL:Execute: No condition for spell " .. actor.spell:GetName())
actor.item:UsableIf(actor.usableFunc):Use(actor.target)
end
if actor.action then
-- print("Bastion: APL:Execute: Executing action " .. actor.action)
actor.cb(self)
if actor:HasTraits() and actor:Evaluate() then
actor:Execute()
else
actor:Execute()
end
end
end
@ -91,4 +191,4 @@ function APL:__tostring()
return "Bastion.__APL(" .. self.name .. ")"
end
return APL
return APL, APLActor, APLTrait

@ -325,7 +325,7 @@ function Unit:GetChannelOrCastPercentComplete()
local start = startTimeMS / 1000
local finish = endTimeMS / 1000
local current = GetTime()
print(((current - start) / (finish - start)) * 100)
return ((current - start) / (finish - start)) * 100
end
return 0
@ -603,4 +603,19 @@ function Unit:TimeToDie()
return timeto
end
-- Set combat time if affecting combat and return the difference between now and the last time
function Unit:GetCombatTime()
if self:IsAffectingCombat() then
self.last_combat_time = GetTime()
elseif not self:IsAffectingCombat() and self.last_combat_time then
self.last_combat_time = nil
end
if not self.last_combat_time then
return 0
end
return GetTime() - self.last_combat_time
end
return Unit

@ -6,25 +6,20 @@ local Bastion = {
Bastion.__index = Bastion
function Bastion.require(class)
if Bastion[class] then
return Bastion[class]
end
Bastion[class] = Tinkr:require("scripts/bastion/src/" .. class .. "/" .. class, Bastion)
return Bastion[class]
return Tinkr:require("scripts/bastion/src/" .. class .. "/" .. class, Bastion)
end
Bastion.ClassMagic = Bastion.require("ClassMagic")
Bastion.List = Bastion.require("List")
Bastion.NotificationsList, Bastion.Notification = Bastion.require("NotificationsList")
Bastion.Vector3 = Bastion.require("Vector3")
Bastion.Commmand = Bastion.require("Command")
Bastion.Command = Bastion.require("Command")
Bastion.Cache = Bastion.require("Cache")
Bastion.Cacheable = Bastion.require("Cacheable")
Bastion.Refreshable = Bastion.require("Refreshable")
Bastion.Unit = Bastion.require("Unit")
Bastion.Aura = Bastion.require("Aura")
Bastion.APL = Bastion.require("APL")
Bastion.APL, Bastion.APLActor, Bastion.APLTrait = Bastion.require("APL")
Bastion.Module = Bastion.require("Module")
Bastion.UnitManager = Bastion.require("UnitManager"):New()
Bastion.ObjectManager = Bastion.require("ObjectManager"):New()
@ -115,7 +110,7 @@ function Bastion:Debug(...)
print(str)
end
local Command = Bastion.Commmand:New('bastion')
local Command = Bastion.Command:New('bastion')
Command:Register('toggle', 'Toggle bastion on/off', function()
Bastion.Enabled = not Bastion.Enabled

Loading…
Cancel
Save