forked from Bastion/Bastion
commit
764655ea51
@ -0,0 +1,3 @@ |
||||
## Ignore mac files |
||||
.DS_Store |
||||
DS_Store |
@ -0,0 +1,2 @@ |
||||
# bastion |
||||
Bastion is a heavily cached World of Warcraft scripting platform |
@ -0,0 +1,436 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
local RestoModule = Bastion.Module:New('resto_druid') |
||||
|
||||
local Player = Bastion.UnitManager:Get('player') |
||||
local None = Bastion.UnitManager:Get('none') |
||||
local Target = Bastion.UnitManager:Get('target') |
||||
|
||||
local AnomalyDetectionMarkI = Bastion.SpellBook:GetSpell(382499) |
||||
local AutoAttack = Bastion.SpellBook:GetSpell(6603) |
||||
local MechanismBypass = Bastion.SpellBook:GetSpell(382501) |
||||
local OverloadElementalDeposit = Bastion.SpellBook:GetSpell(388213) |
||||
local ReviveBattlePets = Bastion.SpellBook:GetSpell(125439) |
||||
local WarStomp = Bastion.SpellBook:GetSpell(20549) |
||||
local ArmorSkills = Bastion.SpellBook:GetSpell(76275) |
||||
local Brawn = Bastion.SpellBook:GetSpell(154743) |
||||
local Cultivation = Bastion.SpellBook:GetSpell(20552) |
||||
local Endurance = Bastion.SpellBook:GetSpell(20550) |
||||
local Languages = Bastion.SpellBook:GetSpell(79746) |
||||
local MasterRiding = Bastion.SpellBook:GetSpell(90265) |
||||
local NatureResistance = Bastion.SpellBook:GetSpell(20551) |
||||
local WeaponSkills = Bastion.SpellBook:GetSpell(76300) |
||||
local ActivateEmpowerment = Bastion.SpellBook:GetSpell(357857) |
||||
local BlessingofOhnara = Bastion.SpellBook:GetSpell(384522) |
||||
local BronzeTimelock = Bastion.SpellBook:GetSpell(374990) |
||||
local ChampionAbility = Bastion.SpellBook:GetSpell(356550) |
||||
local CenarionWard = Bastion.SpellBook:GetSpell(102351) |
||||
local CombatAlly = Bastion.SpellBook:GetSpell(211390) |
||||
local ConstructAbility = Bastion.SpellBook:GetSpell(347013) |
||||
local CovenantAbility = Bastion.SpellBook:GetSpell(313347) |
||||
local GarrisonAbility = Bastion.SpellBook:GetSpell(161691) |
||||
local HeartEssence = Bastion.SpellBook:GetSpell(296208) |
||||
local HuntingCompanion = Bastion.SpellBook:GetSpell(376280) |
||||
local SanityRestorationOrb = Bastion.SpellBook:GetSpell(314955) |
||||
local SignatureAbility = Bastion.SpellBook:GetSpell(326526) |
||||
local SkywardAscent = Bastion.SpellBook:GetSpell(372610) |
||||
local SummonPocopoc = Bastion.SpellBook:GetSpell(360078) |
||||
local SurgeForward = Bastion.SpellBook:GetSpell(372608) |
||||
local Throw = Bastion.SpellBook:GetSpell(385265) |
||||
local VenthyrAbility = Bastion.SpellBook:GetSpell(315594) |
||||
local WartimeAbility = Bastion.SpellBook:GetSpell(264739) |
||||
local WhirlingSurge = Bastion.SpellBook:GetSpell(361584) |
||||
local PocopocZoneAbilitySkill = Bastion.SpellBook:GetSpell(363942) |
||||
local DragonridingBasics = Bastion.SpellBook:GetSpell(376777) |
||||
local LiftOff = Bastion.SpellBook:GetSpell(383363) |
||||
local ThrilloftheSkies = Bastion.SpellBook:GetSpell(383366) |
||||
local Vigor = Bastion.SpellBook:GetSpell(383359) |
||||
local WindsoftheIsles = Bastion.SpellBook:GetSpell(373586) |
||||
local Barkskin = Bastion.SpellBook:GetSpell(22812) |
||||
local BearForm = Bastion.SpellBook:GetSpell(5487) |
||||
local CatForm = Bastion.SpellBook:GetSpell(768) |
||||
local Cyclone = Bastion.SpellBook:GetSpell(33786) |
||||
local EntanglingRoots = Bastion.SpellBook:GetSpell(339) |
||||
local FerociousBite = Bastion.SpellBook:GetSpell(22568) |
||||
local FrenziedRegeneration = Bastion.SpellBook:GetSpell(22842) |
||||
local Growl = Bastion.SpellBook:GetSpell(6795) |
||||
local Innervate = Bastion.SpellBook:GetSpell(29166) |
||||
local Mangle = Bastion.SpellBook:GetSpell(33917) |
||||
local MarkoftheWild = Bastion.SpellBook:GetSpell(1126) |
||||
local Moonfire = Bastion.SpellBook:GetSpell(8921) |
||||
local MoonfireAura = Bastion.SpellBook:GetSpell(164812) |
||||
local Prowl = Bastion.SpellBook:GetSpell(5215) |
||||
local Rebirth = Bastion.SpellBook:GetSpell(20484) |
||||
local Regrowth = Bastion.SpellBook:GetSpell(8936) |
||||
local Rejuvenation = Bastion.SpellBook:GetSpell(774) |
||||
local RejuvenationAura = Bastion.SpellBook:GetSpell(25299) |
||||
local Revive = Bastion.SpellBook:GetSpell(50769) |
||||
local Rip = Bastion.SpellBook:GetSpell(1079) |
||||
local Shred = Bastion.SpellBook:GetSpell(5221) |
||||
local Soothe = Bastion.SpellBook:GetSpell(2908) |
||||
local StampedingRoar = Bastion.SpellBook:GetSpell(106898) |
||||
local Sunfire = Bastion.SpellBook:GetSpell(93402) |
||||
local SunfireAura = Bastion.SpellBook:GetSpell(164815) |
||||
local Swiftmend = Bastion.SpellBook:GetSpell(18562) |
||||
local TeleportMoonglade = Bastion.SpellBook:GetSpell(18960) |
||||
local Thrash = Bastion.SpellBook:GetSpell(106832) |
||||
local TigerDash = Bastion.SpellBook:GetSpell(252216) |
||||
local TravelForm = Bastion.SpellBook:GetSpell(783) |
||||
local UrsolsVortex = Bastion.SpellBook:GetSpell(102793) |
||||
local WildGrowth = Bastion.SpellBook:GetSpell(48438) |
||||
local Wrath = Bastion.SpellBook:GetSpell(5176) |
||||
local AquaticForm = Bastion.SpellBook:GetSpell(276012) |
||||
local FlightForm = Bastion.SpellBook:GetSpell(276029) |
||||
local TigerDash = Bastion.SpellBook:GetSpell(252216) |
||||
local Efflorescence = Bastion.SpellBook:GetSpell(145205) |
||||
local IncarnationTreeofLife = Bastion.SpellBook:GetSpell(33891) |
||||
local Ironbark = Bastion.SpellBook:GetSpell(102342) |
||||
local Lifebloom = Bastion.SpellBook:GetSpell(33763) |
||||
local LifebloomAura = Bastion.SpellBook:GetSpell(188550) |
||||
local NaturesCure = Bastion.SpellBook:GetSpell(88423) |
||||
local NaturesSwiftness = Bastion.SpellBook:GetSpell(132158) |
||||
local Revitalize = Bastion.SpellBook:GetSpell(212040) |
||||
local Tranquility = Bastion.SpellBook:GetSpell(740) |
||||
local MasteryHarmony = Bastion.SpellBook:GetSpell(77495) |
||||
local Moonfire = Bastion.SpellBook:GetSpell(8921) |
||||
local Wrath = Bastion.SpellBook:GetSpell(5176) |
||||
local BearForm = Bastion.SpellBook:GetSpell(5487) |
||||
local AdaptiveSwarm = Bastion.SpellBook:GetSpell(391888) |
||||
local AdaptiveSwarmBuff = Bastion.SpellBook:GetSpell(391891) |
||||
local ClearCasting = Bastion.SpellBook:GetSpell(16870) |
||||
local ConvokeTheSpirits = Bastion.SpellBook:GetSpell(391528) |
||||
local Flourish = Bastion.SpellBook:GetSpell(197721) |
||||
local SoulOfTheForest = Bastion.SpellBook:GetSpell(114108) |
||||
local Bursting = Bastion.SpellBook:GetSpell(240443) |
||||
local Rake = Bastion.SpellBook:GetSpell(1822) |
||||
local RakeAura = Bastion.SpellBook:GetSpell(155722) |
||||
local Starsurge = Bastion.SpellBook:GetSpell(197626) |
||||
local NaturesVigil = Bastion.SpellBook:GetSpell(124974) |
||||
local SpringBlossoms = Bastion.SpellBook:GetSpell(207386) |
||||
|
||||
local Lowest = Bastion.UnitManager:CreateCustomUnit('lowest', function(unit) |
||||
local lowest = nil |
||||
local lowestHP = math.huge |
||||
|
||||
Bastion.UnitManager:EnumFriends(function(unit) |
||||
if unit:IsDead() then |
||||
return false |
||||
end |
||||
|
||||
if Player:GetDistance(unit) > 40 then |
||||
return false |
||||
end |
||||
|
||||
if not Player:CanSee(unit) then |
||||
return false |
||||
end |
||||
|
||||
local hp = unit:GetHP() |
||||
if hp < lowestHP then |
||||
lowest = unit |
||||
lowestHP = hp |
||||
end |
||||
end) |
||||
|
||||
if not lowest then |
||||
lowest = Player |
||||
end |
||||
|
||||
return lowest |
||||
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 = Player |
||||
end |
||||
|
||||
return tank |
||||
end) |
||||
|
||||
local RejuvUnit = Bastion.UnitManager:CreateCustomUnit('rejuv', function(unit) |
||||
local lowest = nil |
||||
local lowestHP = math.huge |
||||
|
||||
Bastion.UnitManager:EnumFriends(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 not unit:IsDead() and Player:CanSee(unit) and not unit:GetAuras():FindMy(Rejuvenation):IsUp() then |
||||
|
||||
local hp = unit:GetHP() |
||||
if hp < lowestHP then |
||||
lowest = unit |
||||
lowestHP = hp |
||||
end |
||||
end |
||||
|
||||
end) |
||||
|
||||
|
||||
if lowest == nil then |
||||
lowest = Player |
||||
end |
||||
|
||||
return lowest |
||||
end) |
||||
|
||||
local SwiftmendUnit = Bastion.UnitManager:CreateCustomUnit('swiftmend', function(unit) |
||||
local lowest = nil |
||||
local lowestHP = math.huge |
||||
|
||||
Bastion.UnitManager:EnumFriends(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:CanSee(unit) and ( |
||||
(unit:GetAuras():FindMy(Regrowth):IsUp()) |
||||
or |
||||
( |
||||
unit:GetAuras():FindMy(Rejuvenation):IsUp() and |
||||
not unit:GetAuras():FindMy(WildGrowth):IsUp()) |
||||
) |
||||
) then |
||||
|
||||
local hp = unit:GetHP() |
||||
if hp < lowestHP then |
||||
lowest = unit |
||||
lowestHP = hp |
||||
end |
||||
end |
||||
|
||||
end) |
||||
|
||||
|
||||
if lowest == nil then |
||||
lowest = Player |
||||
end |
||||
|
||||
return lowest |
||||
end) |
||||
|
||||
local RestoCommands = Bastion.Command:New('resto') |
||||
|
||||
local PLACE_EFFLO = false |
||||
|
||||
RestoCommands:Register('efflo', 'Request the engine to place an Efflorescence', function() |
||||
PLACE_EFFLO = true |
||||
Bastion:Print('Efflorescence will be placed on next cast') |
||||
end) |
||||
|
||||
local DefaultAPL = Bastion.APL:New('default') |
||||
local DamageAPL = Bastion.APL:New('damage') |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Efflorescence:CastableIf(function(self) |
||||
return PLACE_EFFLO and Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
end):SetTarget(None):OnCast(function(self) |
||||
local loc = Bastion.UnitManager:FindFriendsCentroid(10, 40) |
||||
PLACE_EFFLO = false |
||||
self:Click(loc) |
||||
end) |
||||
) |
||||
|
||||
DefaultAPL:AddAction( |
||||
'cat_form_shift', |
||||
function() |
||||
if IsShiftKeyDown() and not Player:GetAuras():FindMy(CatForm):IsUp() and not Player:IsCastingOrChanneling() then |
||||
CatForm:Cast(Player) |
||||
elseif not IsShiftKeyDown() and Player:GetAuras():FindMy(CatForm):IsUp() then |
||||
CancelShapeshiftForm() |
||||
end |
||||
end |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
NaturesSwiftness:CastableIf(function(self) |
||||
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Lowest) and |
||||
(Lowest:GetHP() < 75 or (Player:GetPartyHPAround(40, 65) >= 2 or Player:GetPartyHPAround(40, 70)) |
||||
) |
||||
end):SetTarget(Lowest) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
ConvokeTheSpirits:CastableIf(function(self) |
||||
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and |
||||
self:IsInRange(Player) and (Player:GetPartyHPAround(40, 65) >= 2 or Player:GetPartyHPAround(40, 70) >= 3) |
||||
end):SetTarget(Player) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Flourish:CastableIf(function(self) |
||||
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() and |
||||
self:IsInRange(Player) and (Player:GetPartyHPAround(40, 65) >= 2 or Player:GetPartyHPAround(40, 70) >= 3) and |
||||
(not ConvokeTheSpirits:IsKnownAndUsable() and ConvokeTheSpirits:GetTimeSinceLastCast() > 7) and |
||||
WildGrowth:GetTimeSinceLastCast() <= 4 |
||||
end):SetTarget(Player) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
AdaptiveSwarm:CastableIf(function(self) |
||||
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Lowest) |
||||
end):SetTarget(Lowest) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Swiftmend:CastableIf(function(self) |
||||
return SwiftmendUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(SwiftmendUnit) and |
||||
( |
||||
SwiftmendUnit:GetHP() <= 85 or |
||||
( |
||||
Lowest:GetPartyHPAround(30, 90) >= 3 or Lowest:GetPartyHPAround(30, 85) >= 2 |
||||
) |
||||
) |
||||
end):SetTarget(SwiftmendUnit) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
WildGrowth:CastableIf(function(self) |
||||
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Lowest) and |
||||
( |
||||
( |
||||
Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and |
||||
( |
||||
Player:GetAuras():FindMy(SoulOfTheForest):GetRemainingTime() <= 5 or |
||||
Lowest:GetPartyHPAround(30, 90) >= 2)) or |
||||
(Lowest:GetPartyHPAround(30, 90) >= 3 or Lowest:GetPartyHPAround(30, 85) >= 2)) and not Player:IsMoving() |
||||
end):SetTarget(Lowest) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Regrowth:CastableIf(function(self) |
||||
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Lowest) and Lowest:GetHP() < 75 and |
||||
( |
||||
NaturesSwiftness:GetTimeSinceLastCast() < 2 or Player:GetAuras():FindMy(NaturesSwiftness):IsUp() or |
||||
NaturesSwiftness:IsKnownAndUsable()) and not Player:IsMoving() |
||||
end):SetTarget(Lowest) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Regrowth:CastableIf(function(self) |
||||
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Lowest) and |
||||
(Lowest:GetHP() < 70 or (Lowest:GetHP() <= 85 and Player:GetAuras():FindMy(ClearCasting):IsUp())) and |
||||
not Player:GetAuras():FindMy(Regrowth):IsUp() and not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() and |
||||
not Player:IsMoving() |
||||
end):SetTarget(Lowest) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
CenarionWard:CastableIf(function(self) |
||||
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Lowest) and Lowest:GetHP() <= 90 |
||||
end):SetTarget(Lowest) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Ironbark:CastableIf(function(self) |
||||
return Lowest:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Lowest) and Lowest:GetHP() <= 70 and not Lowest:GetAuras():FindMy(CenarionWard):IsUp() |
||||
end):SetTarget(Lowest) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Lifebloom:CastableIf(function(self) |
||||
return Player:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and not Player:GetAuras():FindMy(LifebloomAura):IsUp() and Player:IsAffectingCombat() |
||||
end):SetTarget(Player) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Lifebloom:CastableIf(function(self) |
||||
return Tank:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and not Tank:GetAuras():FindMy(LifebloomAura):IsUp() and Tank:IsAffectingCombat() |
||||
end):SetTarget(Tank) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Rejuvenation:CastableIf(function(self) |
||||
return RejuvUnit:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(RejuvUnit) and RejuvUnit:GetHP() <= 94 and |
||||
not Player:GetAuras():FindMy(SoulOfTheForest):IsUp() |
||||
end):SetTarget(RejuvUnit) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Sunfire:CastableIf(function(self) |
||||
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Target) and not Target:GetAuras():FindMy(SunfireAura):IsUp() |
||||
end):SetTarget(Target) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Moonfire:CastableIf(function(self) |
||||
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Target) and not Target:GetAuras():FindMy(MoonfireAura):IsUp() |
||||
end):SetTarget(Target) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Starsurge:CastableIf(function(self) |
||||
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Target) |
||||
end):SetTarget(Target) |
||||
) |
||||
|
||||
DefaultAPL:AddSpell( |
||||
Wrath:CastableIf(function(self) |
||||
return Target:Exists() and self:IsKnownAndUsable() and not Player:IsCastingOrChanneling() |
||||
and Player:CanSee(Target) and not Player:IsMoving() |
||||
end):SetTarget(Target) |
||||
) |
||||
|
||||
RestoModule:Sync(function() |
||||
if IsShiftKeyDown() and Player:GetAuras():FindMy(CatForm):IsUp() then |
||||
return DamageAPL:Execute() |
||||
end |
||||
DefaultAPL:Execute() |
||||
end) |
||||
|
||||
Bastion:Register(RestoModule) |
@ -0,0 +1,76 @@ |
||||
-- APL (Attack priority list) class |
||||
|
||||
local APL = {} |
||||
APL.__index = APL |
||||
|
||||
-- Constructor |
||||
function APL:New(name) |
||||
local self = setmetatable({}, APL) |
||||
|
||||
self.apl = {} |
||||
self.variables = {} |
||||
self.name = name |
||||
|
||||
return self |
||||
end |
||||
|
||||
-- Add a variable to the APL |
||||
function APL:SetVariable(name, value) |
||||
self.variables[name] = value |
||||
end |
||||
|
||||
-- Get and evaluate a variable |
||||
function APL:GetVariable(name) |
||||
return self.variables[name] |
||||
end |
||||
|
||||
-- Add a manual action to the APL |
||||
function APL:AddAction(action, cb) |
||||
table.insert(self.apl, { action = action, cb = cb }) |
||||
end |
||||
|
||||
-- Add a spell to the APL |
||||
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 }) |
||||
end |
||||
|
||||
-- Add an APL to the APL (for sub APLs) |
||||
function APL:AddAPL(apl, condition) |
||||
table.insert(self.apl, { apl = apl, condition = condition }) |
||||
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.action then |
||||
-- print("Bastion: APL:Execute: Executing action " .. actor.action) |
||||
actor.cb(self) |
||||
end |
||||
end |
||||
end |
||||
|
||||
-- tostring |
||||
function APL:__tostring() |
||||
return "Bastion.__APL(" .. self.name .. ")" |
||||
end |
||||
|
||||
return APL |
@ -0,0 +1,245 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
-- Create a new Aura class |
||||
local Aura = {} |
||||
|
||||
function Aura:__index(k) |
||||
local response = Bastion.ClassMagic:Resolve(Aura, k) |
||||
|
||||
if response == nil then |
||||
response = rawget(self, k) |
||||
end |
||||
|
||||
if response == nil then |
||||
error("Aura:__index: " .. k .. " does not exist") |
||||
end |
||||
|
||||
return response |
||||
end |
||||
|
||||
function Aura:__tostring() |
||||
return "Bastion.__Aura(" .. self:GetSpell():GetID() .. ")" .. " - " .. (self:GetName() or "''") |
||||
end |
||||
|
||||
-- Constructor |
||||
function Aura:New(unit, index, type) |
||||
if unit == nil then |
||||
local self = setmetatable({}, Aura) |
||||
self.aura = { |
||||
name = nil, |
||||
icon = nil, |
||||
count = 0, |
||||
dispelType = nil, |
||||
duration = 0, |
||||
expirationTime = 0, |
||||
source = nil, |
||||
isStealable = false, |
||||
nameplateShowPersonal = false, |
||||
spellId = 0, |
||||
canApplyAura = false, |
||||
isBossDebuff = false, |
||||
castByPlayer = false, |
||||
nameplateShowAll = false, |
||||
timeMod = 0, |
||||
|
||||
index = nil, |
||||
type = nil, |
||||
|
||||
} |
||||
return self |
||||
end |
||||
|
||||
local name, icon, count, dispelType, duration, expirationTime, source, isStealable, nameplateShowPersonal, |
||||
spellId, canApplyAura, isBossDebuff, castByPlayer, nameplateShowAll, timeMod = UnitAura(unit.unit, index, type) |
||||
|
||||
local self = setmetatable({}, Aura) |
||||
self.aura = { |
||||
name = name, |
||||
icon = icon, |
||||
count = count, |
||||
dispelType = dispelType, |
||||
duration = duration, |
||||
expirationTime = expirationTime, |
||||
source = source, |
||||
isStealable = isStealable, |
||||
nameplateShowPersonal = nameplateShowPersonal, |
||||
spellId = spellId, |
||||
canApplyAura = canApplyAura, |
||||
isBossDebuff = isBossDebuff, |
||||
castByPlayer = castByPlayer, |
||||
nameplateShowAll = nameplateShowAll, |
||||
timeMod = timeMod, |
||||
|
||||
index = index, |
||||
type = type, |
||||
} |
||||
return self |
||||
end |
||||
|
||||
function Aura:CreateFromUnitAuraInfo(unitAuraInfo) |
||||
local self = setmetatable({}, Aura) |
||||
self.aura = { |
||||
name = unitAuraInfo.name, |
||||
icon = unitAuraInfo.icon, |
||||
count = unitAuraInfo.applications, |
||||
dispelType = unitAuraInfo.dispelName, |
||||
duration = unitAuraInfo.duration, |
||||
expirationTime = unitAuraInfo.expirationTime, |
||||
source = unitAuraInfo.sourceUnit, |
||||
isStealable = unitAuraInfo.isStealable, |
||||
nameplateShowPersonal = unitAuraInfo.nameplateShowPersonal, |
||||
spellId = unitAuraInfo.spellId, |
||||
canApplyAura = unitAuraInfo.canApplyAura, |
||||
isBossDebuff = unitAuraInfo.isBossAura, |
||||
castByPlayer = unitAuraInfo.isFromPlayerOrPlayerPet, |
||||
nameplateShowAll = unitAuraInfo.nameplateShowAll, |
||||
timeMod = unitAuraInfo.timeMod, |
||||
|
||||
index = nil, |
||||
type = unitAuraInfo.isHarmful and "HARMFUL" or "HELPFUL", |
||||
} |
||||
return self |
||||
end |
||||
|
||||
-- Check if the aura is valid |
||||
function Aura:IsValid() |
||||
return self.aura.name ~= nil |
||||
end |
||||
|
||||
-- Check if the aura is up |
||||
function Aura:IsUp() |
||||
return self:IsValid() and (self:GetDuration() == 0 or self:GetRemainingTime() > 0) |
||||
end |
||||
|
||||
-- Get the auras index |
||||
function Aura:GetIndex() |
||||
return self.aura.index |
||||
end |
||||
|
||||
-- Get the auras type |
||||
function Aura:GetType() |
||||
return self.aura.type |
||||
end |
||||
|
||||
-- Get the auras name |
||||
function Aura:GetName() |
||||
return self.aura.name |
||||
end |
||||
|
||||
-- Get the auras icon |
||||
function Aura:GetIcon() |
||||
return self.aura.icon |
||||
end |
||||
|
||||
-- Get the auras count |
||||
function Aura:GetCount() |
||||
return self.aura.count |
||||
end |
||||
|
||||
-- Get the auras dispel type |
||||
function Aura:GetDispelType() |
||||
return self.aura.dispelType |
||||
end |
||||
|
||||
-- Get the auras duration |
||||
function Aura:GetDuration() |
||||
return self.aura.duration |
||||
end |
||||
|
||||
-- Get the auras remaining time |
||||
function Aura:GetRemainingTime() |
||||
local remainingTime = self.aura.expirationTime - GetTime() |
||||
|
||||
if remainingTime < 0 then |
||||
remainingTime = 0 |
||||
end |
||||
|
||||
return remainingTime |
||||
end |
||||
|
||||
-- Get the auras expiration time |
||||
function Aura:GetExpirationTime() |
||||
return self.aura.expirationTime |
||||
end |
||||
|
||||
-- Get the auras source |
||||
function Aura:GetSource() |
||||
return Bastion.UnitManager[self.aura.source] |
||||
end |
||||
|
||||
-- Get the auras stealable status |
||||
function Aura:GetIsStealable() |
||||
return self.aura.isStealable |
||||
end |
||||
|
||||
-- Get the auras nameplate show personal status |
||||
function Aura:GetNameplateShowPersonal() |
||||
return self.aura.nameplateShowPersonal |
||||
end |
||||
|
||||
-- Get the auras spell id |
||||
function Aura:GetSpell() |
||||
return Bastion.Spell:New(self.aura.spellId) |
||||
end |
||||
|
||||
-- Get the auras can apply aura status |
||||
function Aura:GetCanApplyAura() |
||||
return self.aura.canApplyAura |
||||
end |
||||
|
||||
-- Get the auras is boss debuff status |
||||
function Aura:GetIsBossDebuff() |
||||
return self.aura.isBossDebuff |
||||
end |
||||
|
||||
-- Get the auras cast by player status |
||||
function Aura:GetCastByPlayer() |
||||
return self.aura.castByPlayer |
||||
end |
||||
|
||||
-- Get the auras nameplate show all status |
||||
function Aura:GetNameplateShowAll() |
||||
return self.aura.nameplateShowAll |
||||
end |
||||
|
||||
-- Get the auras time mod |
||||
function Aura:GetTimeMod() |
||||
return self.aura.timeMod |
||||
end |
||||
|
||||
-- Check if the aura is a buff |
||||
function Aura:IsBuff() |
||||
return self.aura.type == "HELPFUL" |
||||
end |
||||
|
||||
-- Check if the aura is a debuff |
||||
function Aura:IsDebuff() |
||||
return self.aura.type == "HARMFUL" |
||||
end |
||||
|
||||
-- Check if the aura is dispelable by a spell |
||||
function Aura:IsDispelableBySpell(spell) |
||||
if self:GetDispelType() == nil then |
||||
return false |
||||
end |
||||
|
||||
if self:GetDispelType() == 'Magic' and spell:IsMagicDispel() then |
||||
return true |
||||
end |
||||
|
||||
if self:GetDispelType() == 'Curse' and spell:IsCurseDispel() then |
||||
return true |
||||
end |
||||
|
||||
if self:GetDispelType() == 'Poison' and spell:IsPoisonDispel() then |
||||
return true |
||||
end |
||||
|
||||
if self:GetDispelType() == 'Disease' and spell:IsDiseaseDispel() then |
||||
return true |
||||
end |
||||
|
||||
return false |
||||
end |
||||
|
||||
return Aura |
@ -0,0 +1,229 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
-- Create a new AuraTable class |
||||
local AuraTable = {} |
||||
AuraTable.__index = AuraTable |
||||
|
||||
-- Constructor |
||||
function AuraTable:New(unit) |
||||
local self = setmetatable({}, AuraTable) |
||||
|
||||
self.unit = unit |
||||
self.buffs = {} |
||||
self.debuffs = {} |
||||
self.auras = {} |
||||
|
||||
-- Our player is usually the most important unit, so we cache the auras for it |
||||
self.playerAppliedBuffs = {} |
||||
self.playerAppliedDebuffs = {} |
||||
self.playerAuras = {} |
||||
self.guid = unit:GetGUID() |
||||
|
||||
Bastion.EventManager:RegisterWoWEvent('UNIT_AURA', function(unit, auras) |
||||
local u = Bastion.UnitManager[unit] |
||||
|
||||
if not self.unit:IsUnit(unit) then |
||||
return |
||||
end |
||||
|
||||
local addedAuras = auras.addedAuras |
||||
|
||||
if #addedAuras > 0 then |
||||
for i = 1, #addedAuras do |
||||
local aura = Bastion.Aura:CreateFromUnitAuraInfo(addedAuras[i]) |
||||
if aura:IsBuff() then |
||||
if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then |
||||
if not self.playerAppliedBuffs[aura:GetSpell():GetID()] then |
||||
self.playerAppliedBuffs[aura:GetSpell():GetID()] = {} |
||||
end |
||||
table.insert(self.playerAppliedBuffs[aura:GetSpell():GetID()], aura) |
||||
else |
||||
if not self.buffs[aura:GetSpell():GetID()] then |
||||
self.buffs[aura:GetSpell():GetID()] = {} |
||||
end |
||||
table.insert(self.buffs[aura:GetSpell():GetID()], aura) |
||||
end |
||||
else |
||||
if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then |
||||
if not self.playerAppliedDebuffs[aura:GetSpell():GetID()] then |
||||
self.playerAppliedDebuffs[aura:GetSpell():GetID()] = {} |
||||
end |
||||
table.insert(self.playerAppliedDebuffs[aura:GetSpell():GetID()], aura) |
||||
else |
||||
if not self.debuffs[aura:GetSpell():GetID()] then |
||||
self.debuffs[aura:GetSpell():GetID()] = {} |
||||
end |
||||
table.insert(self.debuffs[aura:GetSpell():GetID()], aura) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end) |
||||
|
||||
return self |
||||
end |
||||
|
||||
-- Get a units buffs |
||||
function AuraTable:GetUnitBuffs() |
||||
for i = 1, 40 do |
||||
local aura = Bastion.Aura:New(self.unit, i, 'HELPFUL') |
||||
if aura:IsValid() then |
||||
if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then |
||||
if not self.playerAppliedBuffs[aura:GetSpell():GetID()] then |
||||
self.playerAppliedBuffs[aura:GetSpell():GetID()] = {} |
||||
end |
||||
table.insert(self.playerAppliedBuffs[aura:GetSpell():GetID()], aura) |
||||
else |
||||
if not self.buffs[aura:GetSpell():GetID()] then |
||||
self.buffs[aura:GetSpell():GetID()] = {} |
||||
end |
||||
table.insert(self.buffs[aura:GetSpell():GetID()], aura) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
-- Get a units debuffs |
||||
function AuraTable:GetUnitDebuffs() |
||||
for i = 1, 40 do |
||||
local aura = Bastion.Aura:New(self.unit, i, 'HARMFUL') |
||||
if aura:IsValid() then |
||||
if aura:GetSource():Exists() and aura:GetSource():IsUnit(Bastion.UnitManager['player']) then |
||||
if not self.playerAppliedDebuffs[aura:GetSpell():GetID()] then |
||||
self.playerAppliedDebuffs[aura:GetSpell():GetID()] = {} |
||||
end |
||||
table.insert(self.playerAppliedDebuffs[aura:GetSpell():GetID()], aura) |
||||
else |
||||
if not self.debuffs[aura:GetSpell():GetID()] then |
||||
self.debuffs[aura:GetSpell():GetID()] = {} |
||||
end |
||||
table.insert(self.debuffs[aura:GetSpell():GetID()], aura) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
local function merge(t1, t2) |
||||
for k, v in pairs(t2) do |
||||
if type(v) == "table" then |
||||
if type(t1[k] or false) == "table" then |
||||
merge(t1[k] or {}, t2[k] or {}) |
||||
else |
||||
t1[k] = v |
||||
end |
||||
else |
||||
t1[k] = v |
||||
end |
||||
end |
||||
return t1 |
||||
end |
||||
|
||||
-- Update auras |
||||
function AuraTable:Update() |
||||
self:Clear() |
||||
self.lastUpdate = GetTime() |
||||
|
||||
self:GetUnitBuffs() |
||||
self:GetUnitDebuffs() |
||||
self.auras = merge(self.buffs, self.debuffs) |
||||
self.playerAuras = merge(self.playerAppliedBuffs, self.playerAppliedDebuffs) |
||||
end |
||||
|
||||
-- Get a units auras |
||||
function AuraTable:GetUnitAuras() |
||||
-- For token units, we need to check if the GUID has changed |
||||
if self.unit:GetGUID() ~= self.guid then |
||||
self.guid = self.unit:GetGUID() |
||||
self:Update() |
||||
return self.auras |
||||
end |
||||
|
||||
-- Cache the auras for the unit so we don't have to query the API every time we want to check if the unit has a specific aura or not |
||||
-- If it's less than .4 seconds since the last time we queried the API, return the cached auras |
||||
if self.lastUpdate and GetTime() - self.lastUpdate < 0.5 then |
||||
return self.auras |
||||
end |
||||
|
||||
self:Update() |
||||
return self.auras |
||||
end |
||||
|
||||
-- Get a units auras |
||||
function AuraTable:GetMyUnitAuras() |
||||
-- For token units, we need to check if the GUID has changed |
||||
if self.unit:GetGUID() ~= self.guid then |
||||
self.guid = self.unit:GetGUID() |
||||
self:Update() |
||||
return self.playerAuras |
||||
end |
||||
|
||||
-- Cache the auras for the unit so we don't have to query the API every time we want to check if the unit has a specific aura or not |
||||
-- If it's less than .4 seconds since the last time we queried the API, return the cached auras |
||||
if self.lastUpdate and GetTime() - self.lastUpdate < 0.5 then |
||||
return self.playerAuras |
||||
end |
||||
|
||||
self:Update() |
||||
return self.playerAuras |
||||
end |
||||
|
||||
-- Clear the aura table |
||||
function AuraTable:Clear() |
||||
self.buffs = {} |
||||
self.debuffs = {} |
||||
self.auras = {} |
||||
self.playerAppliedBuffs = {} |
||||
self.playerAppliedDebuffs = {} |
||||
self.playerAuras = {} |
||||
end |
||||
|
||||
-- Check if the unit has a specific aura |
||||
function AuraTable:Find(spell) |
||||
local auras = self:GetUnitAuras() |
||||
local aura = auras[spell:GetID()] |
||||
|
||||
if aura then |
||||
return aura[1] |
||||
end |
||||
|
||||
return Bastion.Aura:New() |
||||
end |
||||
|
||||
function AuraTable:FindMy(spell) |
||||
local auras = self:GetMyUnitAuras() |
||||
local aura = auras[spell:GetID()] |
||||
|
||||
if aura then |
||||
return aura[1] |
||||
end |
||||
|
||||
return Bastion.Aura:New() |
||||
end |
||||
|
||||
-- Has any stealable aura |
||||
function AuraTable:HasAnyStealableAura() |
||||
for _, auras in pairs(self:GetUnitAuras()) do |
||||
for _, aura in pairs(auras) do |
||||
if aura:GetIsStealable() then |
||||
return true |
||||
end |
||||
end |
||||
end |
||||
|
||||
return false |
||||
end |
||||
|
||||
-- Has any dispelable aura |
||||
function AuraTable:HasAnyDispelableAura(spell) |
||||
for _, auras in pairs(self:GetUnitAuras()) do |
||||
for _, aura in pairs(auras) do |
||||
if aura:IsDebuff() and aura:IsDispelableBySpell(spell) then |
||||
return true |
||||
end |
||||
end |
||||
end |
||||
|
||||
return false |
||||
end |
||||
|
||||
return AuraTable |
@ -0,0 +1,46 @@ |
||||
local Cache = {} |
||||
Cache.__index = Cache |
||||
|
||||
-- Constructor |
||||
function Cache:New() |
||||
local self = setmetatable({}, Cache) |
||||
self.cache = {} |
||||
return self |
||||
end |
||||
|
||||
function Cache:Set(key, value, duration) |
||||
self.cache = self.cache or {} |
||||
self.cache[key] = { |
||||
value = value, |
||||
duration = duration, |
||||
time = GetTime() |
||||
} |
||||
end |
||||
|
||||
function Cache:Get(key) |
||||
self.cache = self.cache or {} |
||||
local cache = self.cache[key] |
||||
if cache and cache.time + cache.duration > GetTime() then |
||||
return cache.value |
||||
end |
||||
|
||||
-- It's old or doesn't exist, so remove it |
||||
self.cache[key] = nil |
||||
|
||||
return nil |
||||
end |
||||
|
||||
function Cache:IsCached(key) |
||||
self.cache = self.cache or {} |
||||
local cache = self.cache[key] |
||||
if cache and cache.time + cache.duration > GetTime() then |
||||
return true |
||||
end |
||||
|
||||
-- It's old or doesn't exist, so remove it |
||||
self.cache[key] = nil |
||||
|
||||
return false |
||||
end |
||||
|
||||
return Cache |
@ -0,0 +1,68 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
-- Define a Cacheable class |
||||
local Cacheable = { |
||||
cache = nil, |
||||
callback = nil, |
||||
value = nil |
||||
} |
||||
|
||||
-- On index check the cache to be valid and return the value or reconstruct the value and return it |
||||
function Cacheable:__index(k) |
||||
if Cacheable[k] then |
||||
return Cacheable[k] |
||||
end |
||||
|
||||
if self.cache == nil then |
||||
error("Cacheable:__index: " .. k .. " does not exist") |
||||
end |
||||
|
||||
if not self.cache:IsCached('self') then |
||||
self.value = self.callback() |
||||
self.cache:Set('self', self.value, 0.5) |
||||
end |
||||
|
||||
return self.value[k] |
||||
end |
||||
|
||||
-- When the object is accessed return the value |
||||
function Cacheable:__tostring() |
||||
return "Bastion.__Cacheable(" .. tostring(self.value) .. ")" |
||||
end |
||||
|
||||
-- Create |
||||
function Cacheable:New(value, cb) |
||||
local self = setmetatable({}, Cacheable) |
||||
|
||||
self.cache = Bastion.Cache:New() |
||||
self.value = value |
||||
self.callback = cb |
||||
|
||||
self.cache:Set('self', self.value, 0.5) |
||||
|
||||
return self |
||||
end |
||||
|
||||
-- Try to update the value |
||||
function Cacheable:TryUpdate() |
||||
if self.cache:IsCached("value") then |
||||
self.value = self.callback() |
||||
end |
||||
end |
||||
|
||||
-- Update the value |
||||
function Cacheable:Update() |
||||
self.value = self.callback() |
||||
end |
||||
|
||||
-- Set a new value |
||||
function Cacheable:Set(value) |
||||
self.value = value |
||||
end |
||||
|
||||
-- Set a new callback |
||||
function Cacheable:SetCallback(cb) |
||||
self.callback = cb |
||||
end |
||||
|
||||
return Cacheable |
@ -0,0 +1,51 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
-- Create a new Class class |
||||
local Class = {} |
||||
|
||||
function Class:__index(k) |
||||
local response = Bastion.ClassMagic:Resolve(Class, k) |
||||
|
||||
if response == nil then |
||||
response = rawget(self, k) |
||||
end |
||||
|
||||
if response == nil then |
||||
error("Class:__index: " .. k .. " does not exist") |
||||
end |
||||
|
||||
return response |
||||
end |
||||
|
||||
-- Constructor |
||||
function Class:New(locale, name, id) |
||||
local self = setmetatable({}, Class) |
||||
self.class = { |
||||
locale = locale, |
||||
name = name, |
||||
id = id |
||||
} |
||||
return self |
||||
end |
||||
|
||||
-- Get the classes locale |
||||
function Class:GetLocale() |
||||
return self.class.locale |
||||
end |
||||
|
||||
-- Get the classes name |
||||
function Class:GetName() |
||||
return self.class.name |
||||
end |
||||
|
||||
-- Get the classes id |
||||
function Class:GetID() |
||||
return self.class.id |
||||
end |
||||
|
||||
-- Return the classes color |
||||
function Class:GetColor() |
||||
return C_ClassColor.GetClassColor(self.class.name) |
||||
end |
||||
|
||||
return Class |
@ -0,0 +1,49 @@ |
||||
local ClassMagic = {} |
||||
ClassMagic.__index = ClassMagic |
||||
|
||||
function ClassMagic:Resolve(Class, key) |
||||
if Class[key] or Class[key] == false then |
||||
return Class[key] |
||||
end |
||||
|
||||
if Class['Get' .. key:sub(1, 1):upper() .. key:sub(2)] then |
||||
local func = Class['Get' .. key:sub(1, 1):upper() .. key:sub(2)] |
||||
|
||||
-- Call the function and return the result if there's more than one return value return it as a table |
||||
local result = { func(self) } |
||||
if #result > 1 then |
||||
return result |
||||
end |
||||
|
||||
return result[1] |
||||
end |
||||
|
||||
|
||||
if Class['Get' .. key:upper()] then |
||||
local func = Class['Get' .. key:upper()] |
||||
|
||||
-- Call the function and return the result if there's more than one return value return it as a table |
||||
local result = { func(self) } |
||||
if #result > 1 then |
||||
return result |
||||
end |
||||
|
||||
return result[1] |
||||
end |
||||
|
||||
if Class['Is' .. key:upper()] then |
||||
local func = Class['Is' .. key:upper()] |
||||
|
||||
-- Call the function and return the result if there's more than one return value return it as a table |
||||
local result = { func(self) } |
||||
if #result > 1 then |
||||
return result |
||||
end |
||||
|
||||
return result[1] |
||||
end |
||||
|
||||
return Class[key] |
||||
end |
||||
|
||||
return ClassMagic |
@ -0,0 +1,60 @@ |
||||
-- Create a wow command handler class |
||||
|
||||
local Command = {} |
||||
Command.__index = Command |
||||
|
||||
function Command:__tostring() |
||||
return "Command(" .. self.command .. ")" |
||||
end |
||||
|
||||
function Command:New(prefix) |
||||
local self = setmetatable({}, Command) |
||||
|
||||
self.prefix = prefix |
||||
self.commands = {} |
||||
|
||||
_G['SLASH_' .. prefix:upper() .. '1'] = "/" .. prefix |
||||
SlashCmdList[prefix:upper()] = function(msg, editbox) |
||||
self:OnCommand(msg) |
||||
end |
||||
|
||||
return self |
||||
end |
||||
|
||||
function Command:Register(command, helpmsg, cb) |
||||
self.commands[command] = { |
||||
helpmsg = helpmsg, |
||||
cb = cb |
||||
} |
||||
end |
||||
|
||||
function Command:Parse(msg) |
||||
local args = {} |
||||
for arg in msg:gmatch("%S+") do |
||||
table.insert(args, arg) |
||||
end |
||||
|
||||
return args |
||||
end |
||||
|
||||
function Command:OnCommand(msg) |
||||
local args = self:Parse(msg) |
||||
|
||||
if #args == 0 then |
||||
self:PrintHelp() |
||||
return |
||||
end |
||||
|
||||
local runner = self.commands[args[1]] |
||||
if runner then |
||||
runner.cb(args) |
||||
end |
||||
end |
||||
|
||||
function Command:PrintHelp() |
||||
for k, v in pairs(self.commands) do |
||||
print('/' .. self.prefix .. ' ' .. k .. " - " .. v.helpmsg) |
||||
end |
||||
end |
||||
|
||||
return Command |
@ -0,0 +1,60 @@ |
||||
-- Create an EventManager class |
||||
|
||||
local EventManager = { |
||||
events = {}, |
||||
eventHandlers = {}, |
||||
wowEventHandlers = {}, |
||||
frame = nil |
||||
} |
||||
|
||||
EventManager.__index = EventManager |
||||
|
||||
-- Constructor |
||||
function EventManager:New() |
||||
local self = setmetatable({}, EventManager) |
||||
self.events = {} |
||||
self.eventHandlers = {} |
||||
self.wowEventHandlers = {} |
||||
|
||||
-- Frame for wow events |
||||
self.frame = CreateFrame("Frame") |
||||
|
||||
self.frame:SetScript('OnEvent', function(f, event, ...) |
||||
if self.wowEventHandlers[event] then |
||||
for _, callback in ipairs(self.wowEventHandlers[event]) do |
||||
callback(...) |
||||
end |
||||
end |
||||
end) |
||||
|
||||
|
||||
return self |
||||
end |
||||
|
||||
-- Register an event |
||||
function EventManager:RegisterEvent(event, handler) |
||||
if not self.events[event] then |
||||
self.events[event] = {} |
||||
end |
||||
table.insert(self.events[event], handler) |
||||
end |
||||
|
||||
-- Register a wow event |
||||
function EventManager:RegisterWoWEvent(event, handler) |
||||
if not self.wowEventHandlers[event] then |
||||
self.wowEventHandlers[event] = {} |
||||
self.frame:RegisterEvent(event) |
||||
end |
||||
table.insert(self.wowEventHandlers[event], handler) |
||||
end |
||||
|
||||
-- Trigger an event |
||||
function EventManager:TriggerEvent(event, ...) |
||||
if self.events[event] then |
||||
for _, handler in pairs(self.events[event]) do |
||||
handler(...) |
||||
end |
||||
end |
||||
end |
||||
|
||||
return EventManager |
@ -0,0 +1,343 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
-- Create a new Item class |
||||
local Item = { |
||||
UsableIfFunc = false, |
||||
PreUseFunc = false, |
||||
OnUseFunc = false, |
||||
wasLooking = false, |
||||
lastUseAt = 0, |
||||
conditions = {}, |
||||
target = false, |
||||
} |
||||
|
||||
local usableExcludes = { |
||||
[18562] = true, |
||||
} |
||||
|
||||
function Item:__index(k) |
||||
local response = Bastion.ClassMagic:Resolve(Item, k) |
||||
|
||||
if response == nil then |
||||
response = rawget(self, k) |
||||
end |
||||
|
||||
if response == nil then |
||||
error("Item:__index: " .. k .. " does not exist") |
||||
end |
||||
|
||||
return response |
||||
end |
||||
|
||||
-- tostring |
||||
function Item:__tostring() |
||||
return "Bastion.__Item(" .. self:GetID() .. ")" .. " - " .. self:GetName() |
||||
end |
||||
|
||||
-- Constructor |
||||
function Item:New(id) |
||||
local self = setmetatable({}, Item) |
||||
|
||||
self.ItemID = id |
||||
|
||||
return self |
||||
end |
||||
|
||||
-- Get the Items id |
||||
function Item:GetID() |
||||
return self.ItemID |
||||
end |
||||
|
||||
-- Get the Items name |
||||
function Item:GetName() |
||||
return GetItemInfo(self:GetID()) |
||||
end |
||||
|
||||
-- Get the Items icon |
||||
function Item:GetIcon() |
||||
return select(3, GetItemInfo(self:GetID())) |
||||
end |
||||
|
||||
-- Get the Items cooldown |
||||
function Item:GetCooldown() |
||||
return select(2, GetItemCooldown(self:GetID())) |
||||
end |
||||
|
||||
-- Return the Usable function |
||||
function Item:GetUsableFunction() |
||||
return self.UsableIfFunc |
||||
end |
||||
|
||||
-- Return the preUse function |
||||
function Item:GetPreUseFunction() |
||||
return self.PreUseFunc |
||||
end |
||||
|
||||
-- Get the on Use func |
||||
function Item:GetOnUseFunction() |
||||
return self.OnUseFunc |
||||
end |
||||
|
||||
-- Get the Items cooldown remaining |
||||
function Item:GetCooldownRemaining() |
||||
local start, duration = GetItemCooldown(self:GetID()) |
||||
return start + duration - GetTime() |
||||
end |
||||
|
||||
-- Use the Item |
||||
function Item:Use(unit, condition) |
||||
if condition and not self:EvaluateCondition(condition) then |
||||
return false |
||||
end |
||||
|
||||
if not self:Usable() then |
||||
return false |
||||
end |
||||
|
||||
-- Call pre Use function |
||||
if self:GetPreUseFunction() then |
||||
self:GetPreUseFunction()(self) |
||||
end |
||||
|
||||
-- Check if the mouse was looking |
||||
self.wasLooking = IsMouselooking() |
||||
|
||||
-- Use the Item |
||||
UseItemByName(self:GetName(), unit.unit) |
||||
|
||||
Bastion:Debug("Using", self) |
||||
|
||||
-- Set the last Use time |
||||
self.lastUseAt = GetTime() |
||||
|
||||
-- Call post Use function |
||||
if self:GetOnUseFunction() then |
||||
self:GetOnUseFunction()(self) |
||||
end |
||||
end |
||||
|
||||
-- Check if the Item is known |
||||
function Item:IsEquipped() |
||||
return IsEquippedItem(self:GetID()) |
||||
end |
||||
|
||||
-- Check if the Item is on cooldown |
||||
function Item:IsOnCooldown() |
||||
return select(2, GetItemCooldown(self:GetID())) > 0 |
||||
end |
||||
|
||||
-- Check if the Item is usable |
||||
function Item:IsUsable() |
||||
local usable, noMana = IsUsableItem(self:GetID()) |
||||
return usable or usableExcludes[self:GetID()] |
||||
end |
||||
|
||||
-- Check if the Item is Usable |
||||
function Item:IsEquippedAndUsable() |
||||
return (self:IsEquippable() and self:IsEquipped()) or (not self:IsEquippable() and self:IsUsable()) |
||||
end |
||||
|
||||
-- Is equippable |
||||
function Item:IsEquippable() |
||||
return IsEquippableItem(self:GetID()) |
||||
end |
||||
|
||||
-- Check if the Item is Usable |
||||
function Item:Usable() |
||||
if self:GetUsableFunction() then |
||||
return self:GetUsableFunction()(self) |
||||
end |
||||
|
||||
return self:IsKnownAndUsable() |
||||
end |
||||
|
||||
-- Set a script to check if the Item is Usable |
||||
function Item:UsableIf(func) |
||||
self.UsableIfFunc = func |
||||
return self |
||||
end |
||||
|
||||
-- Set a script to run before the Item has been Use |
||||
function Item:PreUse(func) |
||||
self.PreUseFunc = func |
||||
return self |
||||
end |
||||
|
||||
-- Set a script to run after the Item has been Use |
||||
function Item:OnUse(func) |
||||
self.OnUseFunc = func |
||||
return self |
||||
end |
||||
|
||||
-- Get was looking |
||||
function Item:GetWasLooking() |
||||
return self.wasLooking |
||||
end |
||||
|
||||
-- Click the Item |
||||
function Item:Click(x, y, z) |
||||
if type(x) == 'table' then |
||||
x, y, z = x.x, x.y, x.z |
||||
end |
||||
if IsItemPending() == 64 then |
||||
MouselookStop() |
||||
Click(x, y, z) |
||||
if self:GetWasLooking() then |
||||
MouselookStart() |
||||
end |
||||
return true |
||||
end |
||||
return false |
||||
end |
||||
|
||||
-- Check if the Item is Usable and Use it |
||||
function Item:Call(unit) |
||||
if self:Usable() then |
||||
self:Use(unit) |
||||
return true |
||||
end |
||||
return false |
||||
end |
||||
|
||||
-- Check if the Item is in range of the unit |
||||
function Item:IsInRange(unit) |
||||
local name, rank, icon, UseTime, Itemmin, Itemmax, ItemID = GetItemInfo(self:GetID()) |
||||
|
||||
local them = Object(unit.unit) |
||||
|
||||
local tx, ty, tz = ObjectPosition(unit.unit) |
||||
local px, py, pz = ObjectPosition('player') |
||||
|
||||
if not them then |
||||
return false |
||||
end |
||||
|
||||
if tx == 0 and ty == 0 and tz == 0 then |
||||
return true |
||||
end |
||||
|
||||
local combatReach = ObjectCombatReach("player") |
||||
local themCombatReach = ObjectCombatReach(unit.unit) |
||||
|
||||
if Bastion.UnitManager['player']:InMelee(unit) and Itemmin == 0 then |
||||
return true |
||||
end |
||||
|
||||
local distance = FastDistance(px, py, pz, tx, ty, tz) |
||||
|
||||
if Itemmax |
||||
and distance >= Itemmin |
||||
and distance <= combatReach + themCombatReach + Itemmax |
||||
then |
||||
return true |
||||
end |
||||
|
||||
return false |
||||
end |
||||
|
||||
-- Get the last use time |
||||
function Item:GetLastUseTime() |
||||
return self.lastUseAt |
||||
end |
||||
|
||||
-- Get time since last use |
||||
function Item:GetTimeSinceLastUse() |
||||
if not self:GetLastUseTime() then |
||||
return math.huge |
||||
end |
||||
return GetTime() - self:GetLastUseTime() |
||||
end |
||||
|
||||
-- Get the Items charges |
||||
function Item:GetCharges() |
||||
return GetItemCharges(self:GetID()) |
||||
end |
||||
|
||||
-- Get the Items charges remaining |
||||
function Item:GetChargesRemaining() |
||||
local charges, maxCharges, start, duration = GetItemCharges(self:GetID()) |
||||
return charges |
||||
end |
||||
|
||||
-- Create a condition for the Item |
||||
function Item:Condition(name, func) |
||||
self.conditions[name] = { |
||||
func = func |
||||
} |
||||
return self |
||||
end |
||||
|
||||
-- Get a condition for the Item |
||||
function Item:GetCondition(name) |
||||
local condition = self.conditions[name] |
||||
if condition then |
||||
return condition |
||||
end |
||||
|
||||
return nil |
||||
end |
||||
|
||||
-- Evaluate a condition for the Item |
||||
function Item:EvaluateCondition(name) |
||||
local condition = self:GetCondition(name) |
||||
if condition then |
||||
return condition.func(self) |
||||
end |
||||
|
||||
return false |
||||
end |
||||
|
||||
-- Check if the Item has a condition |
||||
function Item:HasCondition(name) |
||||
local condition = self:GetCondition(name) |
||||
if condition then |
||||
return true |
||||
end |
||||
|
||||
return false |
||||
end |
||||
|
||||
-- Set the Items target |
||||
function Item:SetTarget(unit) |
||||
self.target = unit |
||||
return self |
||||
end |
||||
|
||||
-- Get the Items target |
||||
function Item:GetTarget() |
||||
return self.target |
||||
end |
||||
|
||||
-- IsMagicDispel |
||||
function Item:IsMagicDispel() |
||||
return ({ |
||||
[88423] = true |
||||
})[self:GetID()] |
||||
end |
||||
|
||||
-- IsCurseDispel |
||||
function Item:IsCurseDispel() |
||||
return ({ |
||||
[88423] = true |
||||
})[self:GetID()] |
||||
end |
||||
|
||||
-- IsPoisonDispel |
||||
function Item:IsPoisonDispel() |
||||
return ({ |
||||
[88423] = true |
||||
})[self:GetID()] |
||||
end |
||||
|
||||
-- IsDiseaseDispel |
||||
function Item:IsDiseaseDispel() |
||||
return ({ |
||||
|
||||
})[self:GetID()] |
||||
end |
||||
|
||||
function Item:IsItem(Item) |
||||
return self:GetID() == Item:GetID() |
||||
end |
||||
|
||||
return Item |
@ -0,0 +1,23 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
-- Create a new ItemBook class |
||||
local ItemBook = {} |
||||
ItemBook.__index = ItemBook |
||||
|
||||
-- Constructor |
||||
function ItemBook:New() |
||||
local self = setmetatable({}, ItemBook) |
||||
self.items = {} |
||||
return self |
||||
end |
||||
|
||||
-- Get a spell from the ItemBook |
||||
function ItemBook:GetItem(id) |
||||
if self.items[id] == nil then |
||||
self.items[id] = Bastion.Item:New(id) |
||||
end |
||||
|
||||
return self.items[id] |
||||
end |
||||
|
||||
return ItemBook |
@ -0,0 +1,65 @@ |
||||
-- Create a module class for a bastion module |
||||
|
||||
local Module = {} |
||||
Module.__index = Module |
||||
|
||||
-- __tostring |
||||
function Module:__tostring() |
||||
return "Bastion.__Module(" .. self.name .. ")" |
||||
end |
||||
|
||||
function Module:New(name) |
||||
local module = {} |
||||
setmetatable(module, Module) |
||||
|
||||
module.name = name |
||||
module.enabled = false |
||||
module.synced = {} |
||||
|
||||
return module |
||||
end |
||||
|
||||
-- Enable the module |
||||
function Module:Enable() |
||||
self.enabled = true |
||||
end |
||||
|
||||
-- Disable the module |
||||
function Module:Disable() |
||||
self.enabled = false |
||||
end |
||||
|
||||
-- Toggle the module |
||||
function Module:Toggle() |
||||
if self.enabled then |
||||
self:Disable() |
||||
else |
||||
self:Enable() |
||||
end |
||||
end |
||||
|
||||
-- Add a function to the sync list |
||||
function Module:Sync(func) |
||||
table.insert(self.synced, func) |
||||
end |
||||
|
||||
-- Remove a function from the sync list |
||||
function Module:Unsync(func) |
||||
for i = 1, #self.synced do |
||||
if self.synced[i] == func then |
||||
table.remove(self.synced, i) |
||||
return |
||||
end |
||||
end |
||||
end |
||||
|
||||
-- Sync |
||||
function Module:Tick() |
||||
if self.enabled then |
||||
for i = 1, #self.synced do |
||||
self.synced[i]() |
||||
end |
||||
end |
||||
end |
||||
|
||||
return Module |
@ -0,0 +1,340 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
-- Create a new Spell class |
||||
local Spell = { |
||||
CastableIfFunc = false, |
||||
PreCastFunc = false, |
||||
OnCastFunc = false, |
||||
wasLooking = false, |
||||
lastCastAt = 0, |
||||
conditions = {}, |
||||
target = false, |
||||
} |
||||
|
||||
local usableExcludes = { |
||||
[18562] = true, |
||||
} |
||||
|
||||
function Spell:__index(k) |
||||
local response = Bastion.ClassMagic:Resolve(Spell, k) |
||||
|
||||
if response == nil then |
||||
response = rawget(self, k) |
||||
end |
||||
|
||||
if response == nil then |
||||
error("Spell:__index: " .. k .. " does not exist") |
||||
end |
||||
|
||||
return response |
||||
end |
||||
|
||||
-- tostring |
||||
function Spell:__tostring() |
||||
return "Bastion.__Spell(" .. self:GetID() .. ")" .. " - " .. self:GetName() |
||||
end |
||||
|
||||
-- Constructor |
||||
function Spell:New(id) |
||||
local self = setmetatable({}, Spell) |
||||
|
||||
self.spellID = id |
||||
|
||||
return self |
||||
end |
||||
|
||||
-- Get the spells id |
||||
function Spell:GetID() |
||||
return self.spellID |
||||
end |
||||
|
||||
-- Get the spells name |
||||
function Spell:GetName() |
||||
return GetSpellInfo(self:GetID()) |
||||
end |
||||
|
||||
-- Get the spells icon |
||||
function Spell:GetIcon() |
||||
return select(3, GetSpellInfo(self:GetID())) |
||||
end |
||||
|
||||
-- Get the spells cooldown |
||||
function Spell:GetCooldown() |
||||
return select(2, GetSpellCooldown(self:GetID())) |
||||
end |
||||
|
||||
-- Return the castable function |
||||
function Spell:GetCastableFunction() |
||||
return self.CastableIfFunc |
||||
end |
||||
|
||||
-- Return the precast function |
||||
function Spell:GetPreCastFunction() |
||||
return self.PreCastFunc |
||||
end |
||||
|
||||
-- Get the on cast func |
||||
function Spell:GetOnCastFunction() |
||||
return self.OnCastFunc |
||||
end |
||||
|
||||
-- Get the spells cooldown remaining |
||||
function Spell:GetCooldownRemaining() |
||||
local start, duration = GetSpellCooldown(self:GetID()) |
||||
return start + duration - GetTime() |
||||
end |
||||
|
||||
-- Cast the spell |
||||
function Spell:Cast(unit, condition) |
||||
if condition and not self:EvaluateCondition(condition) then |
||||
return false |
||||
end |
||||
|
||||
if not self:Castable() then |
||||
return false |
||||
end |
||||
|
||||
-- Call pre cast function |
||||
if self:GetPreCastFunction() then |
||||
self:GetPreCastFunction()(self) |
||||
end |
||||
|
||||
-- Check if the mouse was looking |
||||
self.wasLooking = IsMouselooking() |
||||
|
||||
-- Cast the spell |
||||
CastSpellByName(self:GetName(), unit.unit) |
||||
|
||||
Bastion:Debug("Casting", self) |
||||
|
||||
-- Set the last cast time |
||||
self.lastCastAt = GetTime() |
||||
|
||||
-- Call post cast function |
||||
if self:GetOnCastFunction() then |
||||
self:GetOnCastFunction()(self) |
||||
end |
||||
end |
||||
|
||||
-- Check if the spell is known |
||||
function Spell:IsKnown() |
||||
local isKnown = IsSpellKnown(self:GetID()) |
||||
local isPlayerSpell = IsPlayerSpell(self:GetID()) |
||||
return isKnown or isPlayerSpell |
||||
end |
||||
|
||||
-- Check if the spell is on cooldown |
||||
function Spell:IsOnCooldown() |
||||
return select(2, GetSpellCooldown(self:GetID())) > 0 |
||||
end |
||||
|
||||
-- Check if the spell is usable |
||||
function Spell:IsUsable() |
||||
local usable, noMana = IsUsableSpell(self:GetID()) |
||||
return usable or usableExcludes[self:GetID()] |
||||
end |
||||
|
||||
-- Check if the spell is castable |
||||
function Spell:IsKnownAndUsable() |
||||
return self:IsKnown() and not self:IsOnCooldown() and self:IsUsable() |
||||
end |
||||
|
||||
-- Check if the spell is castable |
||||
function Spell:Castable() |
||||
if self:GetCastableFunction() then |
||||
return self:GetCastableFunction()(self) |
||||
end |
||||
|
||||
return self:IsKnownAndUsable() |
||||
end |
||||
|
||||
-- Set a script to check if the spell is castable |
||||
function Spell:CastableIf(func) |
||||
self.CastableIfFunc = func |
||||
return self |
||||
end |
||||
|
||||
-- Set a script to run before the spell has been cast |
||||
function Spell:PreCast(func) |
||||
self.PreCastFunc = func |
||||
return self |
||||
end |
||||
|
||||
-- Set a script to run after the spell has been cast |
||||
function Spell:OnCast(func) |
||||
self.OnCastFunc = func |
||||
return self |
||||
end |
||||
|
||||
-- Get was looking |
||||
function Spell:GetWasLooking() |
||||
return self.wasLooking |
||||
end |
||||
|
||||
-- Click the spell |
||||
function Spell:Click(x, y, z) |
||||
if type(x) == 'table' then |
||||
x, y, z = x.x, x.y, x.z |
||||
end |
||||
if IsSpellPending() == 64 then |
||||
MouselookStop() |
||||
Click(x, y, z) |
||||
if self:GetWasLooking() then |
||||
MouselookStart() |
||||
end |
||||
return true |
||||
end |
||||
return false |
||||
end |
||||
|
||||
-- Check if the spell is castable and cast it |
||||
function Spell:Call(unit) |
||||
if self:Castable() then |
||||
self:Cast(unit) |
||||
return true |
||||
end |
||||
return false |
||||
end |
||||
|
||||
-- Check if the spell is in range of the unit |
||||
function Spell:IsInRange(unit) |
||||
local name, rank, icon, castTime, spellmin, spellmax, spellID = GetSpellInfo(self:GetID()) |
||||
|
||||
local them = Object(unit.unit) |
||||
|
||||
local tx, ty, tz = ObjectPosition(unit.unit) |
||||
local px, py, pz = ObjectPosition('player') |
||||
|
||||
if not them then |
||||
return false |
||||
end |
||||
|
||||
if tx == 0 and ty == 0 and tz == 0 then |
||||
return true |
||||
end |
||||
|
||||
local combatReach = ObjectCombatReach("player") |
||||
local themCombatReach = ObjectCombatReach(unit.unit) |
||||
|
||||
if Bastion.UnitManager['player']:InMelee(unit) and spellmin == 0 then |
||||
return true |
||||
end |
||||
|
||||
local distance = FastDistance(px, py, pz, tx, ty, tz) |
||||
|
||||
if spellmax |
||||
and distance >= spellmin |
||||
and distance <= combatReach + themCombatReach + spellmax |
||||
then |
||||
return true |
||||
end |
||||
|
||||
return false |
||||
end |
||||
|
||||
-- Get the last cast time |
||||
function Spell:GetLastCastTime() |
||||
return self.lastCastAt |
||||
end |
||||
|
||||
-- Get time since last cast |
||||
function Spell:GetTimeSinceLastCast() |
||||
if not self:GetLastCastTime() then |
||||
return math.huge |
||||
end |
||||
return GetTime() - self:GetLastCastTime() |
||||
end |
||||
|
||||
-- Get the spells charges |
||||
function Spell:GetCharges() |
||||
return GetSpellCharges(self:GetID()) |
||||
end |
||||
|
||||
-- Get the spells charges remaining |
||||
function Spell:GetChargesRemaining() |
||||
local charges, maxCharges, start, duration = GetSpellCharges(self:GetID()) |
||||
return charges |
||||
end |
||||
|
||||
-- Create a condition for the spell |
||||
function Spell:Condition(name, func) |
||||
self.conditions[name] = { |
||||
func = func |
||||
} |
||||
return self |
||||
end |
||||
|
||||
-- Get a condition for the spell |
||||
function Spell:GetCondition(name) |
||||
local condition = self.conditions[name] |
||||
if condition then |
||||
return condition |
||||
end |
||||
|
||||
return nil |
||||
end |
||||
|
||||
-- Evaluate a condition for the spell |
||||
function Spell:EvaluateCondition(name) |
||||
local condition = self:GetCondition(name) |
||||
if condition then |
||||
return condition.func(self) |
||||
end |
||||
|
||||
return false |
||||
end |
||||
|
||||
-- Check if the spell has a condition |
||||
function Spell:HasCondition(name) |
||||
local condition = self:GetCondition(name) |
||||
if condition then |
||||
return true |
||||
end |
||||
|
||||
return false |
||||
end |
||||
|
||||
-- Set the spells target |
||||
function Spell:SetTarget(unit) |
||||
self.target = unit |
||||
return self |
||||
end |
||||
|
||||
-- Get the spells target |
||||
function Spell:GetTarget() |
||||
return self.target |
||||
end |
||||
|
||||
-- IsMagicDispel |
||||
function Spell:IsMagicDispel() |
||||
return ({ |
||||
[88423] = true |
||||
})[self:GetID()] |
||||
end |
||||
|
||||
-- IsCurseDispel |
||||
function Spell:IsCurseDispel() |
||||
return ({ |
||||
[88423] = true |
||||
})[self:GetID()] |
||||
end |
||||
|
||||
-- IsPoisonDispel |
||||
function Spell:IsPoisonDispel() |
||||
return ({ |
||||
[88423] = true |
||||
})[self:GetID()] |
||||
end |
||||
|
||||
-- IsDiseaseDispel |
||||
function Spell:IsDiseaseDispel() |
||||
return ({ |
||||
|
||||
})[self:GetID()] |
||||
end |
||||
|
||||
function Spell:IsSpell(spell) |
||||
return self:GetID() == spell:GetID() |
||||
end |
||||
|
||||
return Spell |
@ -0,0 +1,23 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
-- Create a new SpellBook class |
||||
local SpellBook = {} |
||||
SpellBook.__index = SpellBook |
||||
|
||||
-- Constructor |
||||
function SpellBook:New() |
||||
local self = setmetatable({}, SpellBook) |
||||
self.spells = {} |
||||
return self |
||||
end |
||||
|
||||
-- Get a spell from the spellbook |
||||
function SpellBook:GetSpell(id) |
||||
if self.spells[id] == nil then |
||||
self.spells[id] = Bastion.Spell:New(id) |
||||
end |
||||
|
||||
return self.spells[id] |
||||
end |
||||
|
||||
return SpellBook |
@ -0,0 +1,41 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
-- Create a new Timer class |
||||
local Timer = { |
||||
startTime = nil, |
||||
resetAfterCombat = false, |
||||
} |
||||
Timer.__index = Timer |
||||
|
||||
-- Constructor |
||||
function Timer:New(type) |
||||
local self = setmetatable({}, Timer) |
||||
self.startTime = nil |
||||
self.type = type |
||||
return self |
||||
end |
||||
|
||||
-- Start the timer |
||||
function Timer:Start() |
||||
self.startTime = GetTime() |
||||
end |
||||
|
||||
-- Get the time since the timer was started |
||||
function Timer:GetTime() |
||||
if not self:IsRunning() then |
||||
return 0 |
||||
end |
||||
return GetTime() - self.startTime |
||||
end |
||||
|
||||
-- Check if the timer is running |
||||
function Timer:IsRunning() |
||||
return self.startTime ~= nil |
||||
end |
||||
|
||||
-- Reset the timer |
||||
function Timer:Reset() |
||||
self.startTime = nil |
||||
end |
||||
|
||||
return Timer |
@ -0,0 +1,368 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
-- Create a new Unit class |
||||
local Unit = { |
||||
cache = nil, |
||||
aura_table = nil, |
||||
unit = nil |
||||
} |
||||
|
||||
function Unit:__index(k) |
||||
local response = Bastion.ClassMagic:Resolve(Unit, k) |
||||
|
||||
if response == nil then |
||||
response = rawget(self, k) |
||||
end |
||||
|
||||
if response == nil then |
||||
error("Unit:__index: " .. k .. " does not exist") |
||||
end |
||||
|
||||
return response |
||||
end |
||||
|
||||
-- tostring |
||||
function Unit:__tostring() |
||||
return "Bastion.__Unit(" .. self.unit .. ")" .. " - " .. (self:GetName() or '') |
||||
end |
||||
|
||||
-- Constructor |
||||
function Unit:New(unit) |
||||
local self = setmetatable({}, Unit) |
||||
self.unit = unit |
||||
self.cache = Bastion.Cache:New() |
||||
self.aura_table = Bastion.AuraTable:New(self) |
||||
return self |
||||
end |
||||
|
||||
-- Check if the unit is valid |
||||
function Unit:IsValid() |
||||
return self.unit ~= nil and self:Exists() |
||||
end |
||||
|
||||
-- Check if the unit exists |
||||
function Unit:Exists() |
||||
return UnitExists(self.unit) |
||||
end |
||||
|
||||
-- Get the units token |
||||
function Unit:Token() |
||||
return self.unit |
||||
end |
||||
|
||||
-- Get the units name |
||||
function Unit:GetName() |
||||
return UnitName(self.unit) |
||||
end |
||||
|
||||
-- Get the units GUID |
||||
function Unit:GetGUID() |
||||
return ObjectGUID(self.unit) |
||||
end |
||||
|
||||
-- Get the units health |
||||
function Unit:GetHealth() |
||||
return UnitHealth(self.unit) |
||||
end |
||||
|
||||
-- Get the units max health |
||||
function Unit:GetMaxHealth() |
||||
return UnitHealthMax(self.unit) |
||||
end |
||||
|
||||
-- Get the units health percentage |
||||
function Unit:GetHP() |
||||
return self:GetHealth() / self:GetMaxHealth() * 100 |
||||
end |
||||
|
||||
function Unit:GetHealthPercent() |
||||
return self:GetHP() |
||||
end |
||||
|
||||
-- Get the units power type |
||||
function Unit:GetPowerType() |
||||
return UnitPowerType(self.unit) |
||||
end |
||||
|
||||
-- Get the units power |
||||
function Unit:GetPower(powerType) |
||||
local powerType = powerType or self:GetPowerType() |
||||
return UnitPower(self.unit, powerType) |
||||
end |
||||
|
||||
-- Get the units max power |
||||
function Unit:GetMaxPower(powerType) |
||||
local powerType = powerType or self:GetPowerType() |
||||
return UnitPowerMax(self.unit, powerType) |
||||
end |
||||
|
||||
-- Get the units power percentage |
||||
function Unit:GetPP(powerType) |
||||
local powerType = powerType or self:GetPowerType() |
||||
return self:GetPower(powerType) / self:GetMaxPower(powerType) * 100 |
||||
end |
||||
|
||||
-- Get the units power deficit |
||||
function Unit:GetPowerDeficit(powerType) |
||||
local powerType = powerType or self:GetPowerType() |
||||
return self:GetMaxPower(powerType) - self:GetPower(powerType) |
||||
end |
||||
|
||||
-- Get the units position |
||||
function Unit:GetPosition() |
||||
local x, y, z = ObjectPosition(self.unit) |
||||
return Bastion.Vector3:New(x, y, z) |
||||
end |
||||
|
||||
-- Get the units distance from another unit |
||||
function Unit:GetDistance(unit) |
||||
local pself = self:GetPosition() |
||||
local punit = unit:GetPosition() |
||||
|
||||
return pself:Distance(punit) |
||||
end |
||||
|
||||
-- Is the unit dead |
||||
function Unit:IsDead() |
||||
return UnitIsDeadOrGhost(self.unit) |
||||
end |
||||
|
||||
-- Is the unit alive |
||||
function Unit:IsAlive() |
||||
return not UnitIsDeadOrGhost(self.unit) |
||||
end |
||||
|
||||
-- Is the unit a pet |
||||
function Unit:IsPet() |
||||
return UnitIsUnit(self.unit, "pet") |
||||
end |
||||
|
||||
-- Is the unit a friendly unit |
||||
function Unit:IsFriendly() |
||||
return UnitIsFriend("player", self.unit) |
||||
end |
||||
|
||||
-- Is the unit a hostile unit |
||||
function Unit:IsHostile() |
||||
return UnitIsEnemy("player", self.unit) |
||||
end |
||||
|
||||
-- Is the unit a boss |
||||
function Unit:IsBoss() |
||||
return UnitClassification(self.unit) == "worldboss" |
||||
end |
||||
|
||||
-- Is the unit a target |
||||
function Unit:IsTarget() |
||||
return UnitIsUnit(self.unit, "target") |
||||
end |
||||
|
||||
-- Is the unit a focus |
||||
function Unit:IsFocus() |
||||
return UnitIsUnit(self.unit, "focus") |
||||
end |
||||
|
||||
-- Is the unit a mouseover |
||||
function Unit:IsMouseover() |
||||
return UnitIsUnit(self.unit, "mouseover") |
||||
end |
||||
|
||||
-- Is the unit a tank |
||||
function Unit:IsTank() |
||||
return UnitGroupRolesAssigned(self.unit) == "TANK" |
||||
end |
||||
|
||||
-- Is the unit a healer |
||||
function Unit:IsHealer() |
||||
return UnitGroupRolesAssigned(self.unit) == "HEALER" |
||||
end |
||||
|
||||
-- Is the unit a damage dealer |
||||
function Unit:IsDamage() |
||||
return UnitGroupRolesAssigned(self.unit) == "DAMAGER" |
||||
end |
||||
|
||||
-- Is the unit a player |
||||
function Unit:IsPlayer() |
||||
return UnitIsPlayer(self.unit) |
||||
end |
||||
|
||||
-- Is the unit a player controlled unit |
||||
function Unit:IsPCU() |
||||
return UnitPlayerControlled(self.unit) |
||||
end |
||||
|
||||
-- Get if the unit is affecting combat |
||||
function Unit:IsAffectingCombat() |
||||
return UnitAffectingCombat(self.unit) |
||||
end |
||||
|
||||
-- Get the units class id |
||||
function Unit:GetClass() |
||||
local locale, class, classID = UnitClass(self.unit) |
||||
return Bastion.Class:New(locale, class, classID) |
||||
end |
||||
|
||||
-- Get the units auras |
||||
function Unit:GetAuras() |
||||
return self.aura_table |
||||
end |
||||
|
||||
-- Get the raw unit |
||||
function Unit:GetRawUnit() |
||||
return self.unit |
||||
end |
||||
|
||||
local isClassicWow = select(4, GetBuildInfo()) < 40000 |
||||
|
||||
-- Check if two units are in melee |
||||
function Unit:InMelee(unit) |
||||
local combatReach = ObjectCombatReach(self.unit) |
||||
local themCombatReach = ObjectCombatReach(unit.unit) |
||||
|
||||
if not combatReach or not themCombatReach then |
||||
return false |
||||
end |
||||
|
||||
return self:GetDistance(unit) |
||||
< math.max(combatReach + 1.3333 + themCombatReach, 5) |
||||
end |
||||
|
||||
local losFlag = bit.bor(0x1, 0x10, 0x100000) |
||||
|
||||
-- Check if the unit can see another unit |
||||
function Unit:CanSee(unit) |
||||
-- mechagon smoke cloud |
||||
-- local mechagonID = 2097 |
||||
-- local smokecloud = 298602 |
||||
|
||||
-- local name, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceID, instanceGroupSize, LfgDungeonID = |
||||
-- GetInstanceInfo() |
||||
|
||||
-- otherUnit = otherUnit and otherUnit or "player" |
||||
-- if instanceID == 2097 then |
||||
-- if (self:debuff(smokecloud, unit) and not self:debuff(smokecloud, otherUnit)) |
||||
-- or (self:debuff(smokecloud, otherUnit) and not self:debuff(smokecloud, unit)) |
||||
-- then |
||||
-- return false |
||||
-- end |
||||
-- end |
||||
local ax, ay, az = ObjectPosition(self.unit) |
||||
local ah = ObjectHeight(self.unit) |
||||
local attx, atty, attz = GetUnitAttachmentPosition(unit.unit, 34) |
||||
|
||||
if (ax == 0 and ay == 0 and az == 0) or (attx == 0 and atty == 0 and attz == 0) then |
||||
return true |
||||
end |
||||
|
||||
if not attx or not ax then |
||||
return true |
||||
end |
||||
|
||||
local x, y, z = TraceLine(ax, ay, az + ah, attx, atty, attz, losFlag) |
||||
if x ~= 0 or y ~= 0 or z ~= 0 then |
||||
return false |
||||
else |
||||
return true |
||||
end |
||||
end |
||||
|
||||
-- Check if the unit is casting a spell |
||||
function Unit:IsCasting() |
||||
return UnitCastingInfo(self.unit) ~= nil |
||||
end |
||||
|
||||
-- Check if the unit is channeling a spell |
||||
function Unit:IsChanneling() |
||||
return UnitChannelInfo(self.unit) ~= nil |
||||
end |
||||
|
||||
-- Check if the unit is casting or channeling a spell |
||||
function Unit:IsCastingOrChanneling() |
||||
return self:IsCasting() or self:IsChanneling() |
||||
end |
||||
|
||||
-- Check if the unit can attack the target |
||||
function Unit:CanAttack(unit) |
||||
return UnitCanAttack(self.unit, unit.unit) |
||||
end |
||||
|
||||
-- Check if unit is interruptible |
||||
function Unit:IsInterruptible(percent) |
||||
local percent = percent or math.random(2, 5) |
||||
|
||||
local name, text, texture, startTimeMS, endTimeMS, isTradeSkill, castID, notInterruptible, spellId = UnitCastingInfo(self |
||||
.unit) |
||||
|
||||
if not name then |
||||
name, text, texture, startTimeMS, endTimeMS, isTradeSkill, notInterruptible, spellId = UnitChannelInfo(self.unit) |
||||
end |
||||
|
||||
if name and startTimeMS and endTimeMS and not notInterruptible then |
||||
local castTimeRemaining = endTimeMS / 1000 - GetTime() |
||||
local castTimeTotal = (endTimeMS - startTimeMS) / 1000 |
||||
if castTimeTotal > 0 and castTimeRemaining / castTimeTotal * 100 >= percent then |
||||
return true |
||||
end |
||||
end |
||||
return false |
||||
end |
||||
|
||||
-- Get the number of enemies in a given range of the unit and cache the result for .5 seconds |
||||
function Unit:GetEnemies(range) |
||||
|
||||
local enemies = self.cache:Get("enemies_" .. range) |
||||
if enemies then |
||||
return enemies |
||||
end |
||||
|
||||
local count = 0 |
||||
local objs = Objects() |
||||
local numobjs = #objs |
||||
|
||||
for i = 1, numobjs do |
||||
local object = objs[i] |
||||
-- unit types 5,6,7 |
||||
if ObjectType(object) == 5 or ObjectType(object) == 6 then |
||||
local unit = Unit:New(object) |
||||
if Bastion.UnitManager['player']:CanAttack(unit) and unit:IsAffectingCombat() and unit:IsAlive() and |
||||
unit:CanSee(self) |
||||
and |
||||
self:GetDistance(unit) <= range then |
||||
count = count + 1 |
||||
end |
||||
end |
||||
end |
||||
|
||||
self.cache:Set("enemies_" .. range, count, .5) |
||||
return count |
||||
end |
||||
|
||||
function Unit:GetPartyHPAround(distance, percent) |
||||
local count = 0 |
||||
|
||||
Bastion.UnitManager:EnumFriends(function(unit) |
||||
if not self:IsUnit(unit) and unit:GetDistance(self) <= distance and unit:IsAlive() and self:CanSee(unit) and |
||||
unit:GetHP() <= percent then |
||||
count = count + 1 |
||||
end |
||||
end) |
||||
|
||||
return count |
||||
end |
||||
|
||||
-- Is moving |
||||
function Unit:IsMoving() |
||||
return GetUnitSpeed(self.unit) > 0 |
||||
end |
||||
|
||||
function Unit:GetComboPoints(unit) |
||||
return GetComboPoints(self.unit, unit.unit) |
||||
end |
||||
|
||||
-- IsUnit |
||||
function Unit:IsUnit(unit) |
||||
return UnitIsUnit(self.unit, unit.unit) |
||||
end |
||||
|
||||
return Unit |
@ -0,0 +1,275 @@ |
||||
local Tinkr, Bastion = ... |
||||
|
||||
local Unit = Bastion.Unit |
||||
|
||||
local prefixes = { |
||||
'^player', |
||||
'^pet', |
||||
'^vehicle', |
||||
'^target', |
||||
'^focus', |
||||
'^mouseover', |
||||
'^none', |
||||
'^npc', |
||||
'^party[1-4]', |
||||
'^raid[1-4]?[0-9]', |
||||
'^boss[1-5]', |
||||
'^arena[1-5]' |
||||
} |
||||
|
||||
-- Validate a unit is a valid token |
||||
local function Validate(token) |
||||
local start, index |
||||
local length, offset = string.len(token), 0 |
||||
for i = 1, #prefixes do |
||||
start, index = string.find(token, prefixes[i]) |
||||
if start then |
||||
offset = index + 1 |
||||
if offset > length then |
||||
return true |
||||
else |
||||
while true do |
||||
start, index = string.find(token, 'target', offset, true) |
||||
if start then |
||||
offset = index + 1 |
||||
if offset > length then |
||||
return true |
||||
end |
||||
else |
||||
return false |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
return false |
||||
end |
||||
|
||||
-- Create a new UnitManager class |
||||
local UnitManager = { |
||||
units = {}, |
||||
customUnits = {}, |
||||
cache = {} |
||||
} |
||||
|
||||
function UnitManager:__index(k) |
||||
if UnitManager[k] then |
||||
return UnitManager[k] |
||||
end |
||||
|
||||
local k = k or 'none' |
||||
|
||||
-- if custom unit exists, return it it's cache expired return a new one |
||||
if self.customUnits[k] then |
||||
if not self.cache:IsCached(k) then |
||||
self.customUnits[k].unit:Update() |
||||
self.cache:Set(k, self.customUnits[k].unit, 0.5) |
||||
end |
||||
|
||||
|
||||
return self.customUnits[k].unit |
||||
end |
||||
|
||||
-- if not Validate(k) then |
||||
-- error("UnitManager:Get - Invalid token: " .. k) |
||||
-- end |
||||
|
||||
if self.units[k] == nil then |
||||
self.units[k] = Unit:New(k) |
||||
end |
||||
|
||||
return self.units[k] |
||||
end |
||||
|
||||
-- Constructor |
||||
function UnitManager:New() |
||||
local self = setmetatable({}, UnitManager) |
||||
self.units = {} |
||||
self.customUnits = {} |
||||
self.cache = Bastion.Cache:New() |
||||
return self |
||||
end |
||||
|
||||
function UnitManager:Validate(token) |
||||
return Validate(token) |
||||
end |
||||
|
||||
-- Get or create a unit |
||||
function UnitManager:Get(token) |
||||
-- if not Validate(token) then |
||||
-- error("UnitManager:Get - Invalid token: " .. token) |
||||
-- end |
||||
|
||||
if self.units[token] == nil then |
||||
self.units[token] = Unit:New(token) |
||||
end |
||||
|
||||
return self.units[token] |
||||
end |
||||
|
||||
-- Create a custom unit and cache it for .5 seconds |
||||
function UnitManager:CreateCustomUnit(token, cb) |
||||
local unit = cb() |
||||
local cachedUnit = Bastion.Cacheable:New(unit, cb) |
||||
|
||||
if unit == nil then |
||||
error("UnitManager:CreateCustomUnit - Invalid unit: " .. token) |
||||
end |
||||
|
||||
if self.customUnits[token] == nil then |
||||
self.customUnits[token] = { |
||||
unit = cachedUnit, |
||||
cb = cb |
||||
} |
||||
end |
||||
|
||||
self.cache:Set(token, cachedUnit, 0.5) |
||||
|
||||
return cachedUnit |
||||
end |
||||
|
||||
-- Enum Friends (party/raid members) |
||||
function UnitManager:EnumFriends(cb) |
||||
local isRaid = IsInRaid() |
||||
local n = GetNumGroupMembers() |
||||
|
||||
if cb(self:Get('player')) then |
||||
return |
||||
end |
||||
|
||||
if isRaid then |
||||
for i = 1, n do |
||||
local unit = self:Get('raid' .. i) |
||||
if unit:IsValid() then |
||||
if cb(unit) then |
||||
break |
||||
end |
||||
end |
||||
end |
||||
else |
||||
for i = 1, n do |
||||
local unit = self:Get('party' .. i) |
||||
if unit:IsValid() then |
||||
if cb(unit) then |
||||
break |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
-- Enum Enemies (object manager) |
||||
function UnitManager:EnumEnemies(cb) |
||||
local objs = Objects() |
||||
for i = 1, #objs do |
||||
local obj = objs[i] |
||||
if ObjectType(obj) == 5 or ObjectType(obj) == 6 then |
||||
local unit = Unit:New(obj) |
||||
if unit:IsHostile() and unit:IsAffectingCombat() and unit:IsAlive() and unit:CanSee(self) |
||||
then |
||||
cb(unit) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
-- Enum Units (object manager) |
||||
function UnitManager:EnumUnits(cb) |
||||
local objs = Objects() |
||||
for i = 1, #objs do |
||||
local obj = objs[i] |
||||
if ObjectType(obj) == 5 or ObjectType(obj) == 6 then |
||||
local unit = Unit:New(obj) |
||||
cb(unit) |
||||
end |
||||
end |
||||
end |
||||
|
||||
-- Get the number of friends with a buff (party/raid members) |
||||
function UnitManager:GetNumFriendsWithBuff(spell) |
||||
local count = 0 |
||||
self:EnumFriends(function(unit) |
||||
if unit:GetAuras():FindMy(spell):IsUp() then |
||||
count = count + 1 |
||||
end |
||||
end) |
||||
return count |
||||
end |
||||
|
||||
-- Get the number of friends alive (party/raid members) |
||||
function UnitManager:GetNumFriendsAlive() |
||||
local count = 0 |
||||
self:EnumFriends(function(unit) |
||||
if unit:IsAlive() then |
||||
count = count + 1 |
||||
end |
||||
end) |
||||
return count |
||||
end |
||||
|
||||
-- Get the friend with the most friends within a given radius (party/raid members) |
||||
-- Return unit, friends |
||||
function UnitManager:GetFriendWithMostFriends(radius) |
||||
local unit = nil |
||||
local count = 0 |
||||
local friends = {} |
||||
self:EnumFriends(function(u) |
||||
if u:IsAlive() then |
||||
local c = 0 |
||||
self:EnumFriends(function(other) |
||||
if other:IsAlive() and u:GetDistance(other) <= radius then |
||||
c = c + 1 |
||||
end |
||||
end) |
||||
if c > count then |
||||
unit = u |
||||
count = c |
||||
friends = {} |
||||
self:EnumFriends(function(other) |
||||
if other:IsAlive() and u:GetDistance(other) <= radius then |
||||
table.insert(friends, other) |
||||
end |
||||
end) |
||||
end |
||||
end |
||||
end) |
||||
return unit, friends |
||||
end |
||||
|
||||
-- Find the centroid of the most dense area of friends (party/raid members) of a given radius within a given range |
||||
function UnitManager:FindFriendsCentroid(radius, range) |
||||
local unit, friends = self:GetFriendWithMostFriends(radius) |
||||
if unit == nil then |
||||
return nil |
||||
end |
||||
|
||||
local centroid = Bastion.Vector3:New(0, 0, 0) |
||||
local zstart = -math.huge |
||||
for i = 1, #friends do |
||||
local p = friends[i]:GetPosition() |
||||
centroid = centroid + p |
||||
zstart = p.z > zstart and p.z or zstart |
||||
end |
||||
|
||||
centroid = centroid / #friends |
||||
|
||||
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 |
@ -0,0 +1,240 @@ |
||||
-- Create a Vector3 class |
||||
|
||||
local Vector3 = {} |
||||
Vector3.__index = Vector3 |
||||
|
||||
function Vector3:__tostring() |
||||
return "Vector3(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ")" |
||||
end |
||||
|
||||
function Vector3:__add(other) |
||||
return Vector3:New(self.x + other.x, self.y + other.y, self.z + other.z) |
||||
end |
||||
|
||||
function Vector3:__sub(other) |
||||
if type(other) == "number" then |
||||
return Vector3:New(self.x - other, self.y - other, self.z - other) |
||||
end |
||||
return Vector3:New(self.x - other.x, self.y - other.y, self.z - other.z) |
||||
end |
||||
|
||||
function Vector3:__mul(other) |
||||
return Vector3:New(self.x * other, self.y * other, self.z * other) |
||||
end |
||||
|
||||
function Vector3:__div(other) |
||||
return Vector3:New(self.x / other, self.y / other, self.z / other) |
||||
end |
||||
|
||||
function Vector3:__eq(other) |
||||
return self.x == other.x and self.y == other.y and self.z == other.z |
||||
end |
||||
|
||||
function Vector3:__lt(other) |
||||
return self.x < other.x and self.y < other.y and self.z < other.z |
||||
end |
||||
|
||||
function Vector3:__le(other) |
||||
return self.x <= other.x and self.y <= other.y and self.z <= other.z |
||||
end |
||||
|
||||
function Vector3:__unm() |
||||
return Vector3:New(-self.x, -self.y, -self.z) |
||||
end |
||||
|
||||
function Vector3:__len() |
||||
return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) |
||||
end |
||||
|
||||
function Vector3:__index(k) |
||||
if Vector3[k] then |
||||
return Vector3[k] |
||||
end |
||||
|
||||
if k == "length" then |
||||
return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) |
||||
end |
||||
|
||||
if k == "normalized" then |
||||
local length = math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) |
||||
return Vector3:New(self.x / length, self.y / length, self.z / length) |
||||
end |
||||
|
||||
if k == "magnitude" then |
||||
return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) |
||||
end |
||||
|
||||
if k == "sqrMagnitude" then |
||||
return self.x * self.x + self.y * self.y + self.z * self.z |
||||
end |
||||
|
||||
if k == "zero" then |
||||
return Vector3:New(0, 0, 0) |
||||
end |
||||
|
||||
if k == "one" then |
||||
return Vector3:New(1, 1, 1) |
||||
end |
||||
|
||||
if k == "up" then |
||||
return Vector3:New(0, 1, 0) |
||||
end |
||||
|
||||
if k == "down" then |
||||
return Vector3:New(0, -1, 0) |
||||
end |
||||
|
||||
if k == "left" then |
||||
return Vector3:New(-1, 0, 0) |
||||
end |
||||
|
||||
if k == "right" then |
||||
return Vector3:New(1, 0, 0) |
||||
end |
||||
|
||||
if k == "forward" then |
||||
return Vector3:New(0, 0, 1) |
||||
end |
||||
|
||||
if k == "back" then |
||||
return Vector3:New(0, 0, -1) |
||||
end |
||||
|
||||
if k == "positiveInfinity" then |
||||
return Vector3:New(math.huge, math.huge, math.huge) |
||||
end |
||||
|
||||
if k == "negativeInfinity" then |
||||
return Vector3:New(-math.huge, -math.huge, -math.huge) |
||||
end |
||||
|
||||
if k == "nan" then |
||||
return Vector3:New(0 / 0, 0 / 0, 0 / 0) |
||||
end |
||||
|
||||
if k == "epsilon" then |
||||
return 1.401298E-45 |
||||
end |
||||
|
||||
if k == "maxValue" then |
||||
return 3.402823E+38 |
||||
end |
||||
|
||||
if k == "minValue" then |
||||
return -3.402823E+38 |
||||
end |
||||
|
||||
if k == "x" then |
||||
return self[1] |
||||
end |
||||
|
||||
if k == "y" then |
||||
return self[2] |
||||
end |
||||
|
||||
if k == "z" then |
||||
return self[3] |
||||
end |
||||
|
||||
return nil |
||||
end |
||||
|
||||
function Vector3:__newindex(k, v) |
||||
if k == "x" then |
||||
self[1] = v |
||||
elseif k == "y" then |
||||
self[2] = v |
||||
elseif k == "z" then |
||||
self[3] = v |
||||
else |
||||
rawset(self, k, v) |
||||
end |
||||
end |
||||
|
||||
function Vector3:New(x, y, z) |
||||
if x == false then |
||||
return Vector3:New(0, 0, 0) |
||||
end |
||||
|
||||
local self = setmetatable({ x, y, z }, Vector3) |
||||
return self |
||||
end |
||||
|
||||
function Vector3:Dot(rhs) |
||||
return self.x * rhs.x + self.y * rhs.y + self.z * rhs.z |
||||
end |
||||
|
||||
function Vector3:Cross(rhs) |
||||
return Vector3:New(self.y * rhs.z - self.z * rhs.y, self.z * rhs.x - self.x * rhs.z, self.x * rhs.y - self.y * rhs.x) |
||||
end |
||||
|
||||
function Vector3:Distance(b) |
||||
return FastDistance(self.x, self.y, self.z, b.x, b.y, b.z) |
||||
end |
||||
|
||||
function Vector3:Angle(to) |
||||
return math.acos(self:Dot(to) / |
||||
( |
||||
math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) * |
||||
math.sqrt(to.x * to.x + to.y * to.y + to.z * to.z))) |
||||
end |
||||
|
||||
function Vector3:ClampMagnitude(maxLength) |
||||
if self:Dot(self) > maxLength * maxLength then |
||||
return self.normalized * maxLength |
||||
end |
||||
|
||||
return self |
||||
end |
||||
|
||||
-- Implement a clamp function |
||||
local function clamp(x, min, max) |
||||
return x < min and min or (x > max and max or x) |
||||
end |
||||
|
||||
function Vector3:Lerp(b, t) |
||||
t = clamp(t, 0, 1) |
||||
return Vector3:New(self.x + (b.x - self.x) * t, self.y + (b.y - self.y) * t, self.z + (b.z - self.z) * t) |
||||
end |
||||
|
||||
function Vector3:MoveTowards(target, maxDistanceDelta) |
||||
local toVector = target - self |
||||
local distance = toVector.magnitude |
||||
if distance <= maxDistanceDelta or distance == 0 then |
||||
return target |
||||
end |
||||
|
||||
return self + toVector / distance * maxDistanceDelta |
||||
end |
||||
|
||||
function Vector3:Scale(b) |
||||
return Vector3:New(self.x * b.x, self.y * b.y, self.z * b.z) |
||||
end |
||||
|
||||
function Vector3:Project(onNormal) |
||||
local num = onNormal:Dot(onNormal) |
||||
if num < 1.401298E-45 then |
||||
return Vector3:New(0, 0, 0) |
||||
end |
||||
|
||||
return onNormal * self:Dot(onNormal) / num |
||||
end |
||||
|
||||
function Vector3:ProjectOnPlane(planeNormal) |
||||
return self - self:Project(planeNormal) |
||||
end |
||||
|
||||
function Vector3:Reflect(inNormal) |
||||
return -2 * inNormal:Dot(self) * inNormal + self |
||||
end |
||||
|
||||
function Vector3:Normalize() |
||||
local num = self:Dot(self) |
||||
if num > 1E-05 then |
||||
return self / math.sqrt(num) |
||||
end |
||||
|
||||
return Vector3:New(0, 0, 0) |
||||
end |
||||
|
||||
return Vector3 |
@ -0,0 +1,152 @@ |
||||
local Tinkr = ... |
||||
|
||||
local Bastion = { |
||||
DebugMode = true |
||||
} |
||||
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] |
||||
end |
||||
|
||||
Bastion.ClassMagic = Bastion.require("ClassMagic") |
||||
Bastion.Vector3 = Bastion.require("Vector3") |
||||
Bastion.Commmand = Bastion.require("Command") |
||||
Bastion.Cache = Bastion.require("Cache") |
||||
Bastion.Cacheable = Bastion.require("Cacheable") |
||||
Bastion.Unit = Bastion.require("Unit") |
||||
Bastion.Aura = Bastion.require("Aura") |
||||
Bastion.APL = Bastion.require("APL") |
||||
Bastion.Module = Bastion.require("Module") |
||||
Bastion.UnitManager = Bastion.require("UnitManager"):New() |
||||
Bastion.EventManager = Bastion.require("EventManager"):New() |
||||
Bastion.Spell = Bastion.require("Spell") |
||||
Bastion.Item = Bastion.require("Item") |
||||
Bastion.SpellBook = Bastion.require("SpellBook"):New() |
||||
Bastion.ItemBook = Bastion.require("ItemBook"):New() |
||||
Bastion.AuraTable = Bastion.require("AuraTable") |
||||
Bastion.Class = Bastion.require("Class") |
||||
Bastion.Timer = Bastion.require("Timer") |
||||
Bastion.CombatTimer = Bastion.Timer:New('combat') |
||||
|
||||
Bastion.modules = {} |
||||
Bastion.Enabled = false |
||||
|
||||
Bastion.Ticker = C_Timer.NewTicker(0.1, function() |
||||
if not Bastion.CombatTimer:IsRunning() and UnitAffectingCombat("player") then |
||||
Bastion.CombatTimer:Start() |
||||
elseif Bastion.CombatTimer:IsRunning() and not UnitAffectingCombat("player") then |
||||
Bastion.CombatTimer:Reset() |
||||
end |
||||
|
||||
if Bastion.Enabled then |
||||
for i = 1, #Bastion.modules do |
||||
Bastion.modules[i]:Tick() |
||||
end |
||||
end |
||||
end) |
||||
|
||||
function Bastion:Register(module) |
||||
table.insert(Bastion.modules, module) |
||||
Bastion:Print("Registered", module) |
||||
end |
||||
|
||||
-- Find a module by name |
||||
function Bastion:FindModule(name) |
||||
for i = 1, #Bastion.modules do |
||||
if Bastion.modules[i].name == name then |
||||
return Bastion.modules[i] |
||||
end |
||||
end |
||||
|
||||
return nil |
||||
end |
||||
|
||||
function Bastion:Print(...) |
||||
local args = { ... } |
||||
local str = "|cFFDF362D[Bastion]|r |cFFFFFFFF" |
||||
for i = 1, #args do |
||||
str = str .. tostring(args[i]) .. " " |
||||
end |
||||
print(str) |
||||
end |
||||
|
||||
function Bastion:Debug(...) |
||||
if not Bastion.DebugMode then |
||||
return |
||||
end |
||||
local args = { ... } |
||||
local str = "|cFFDF6520[Bastion]|r |cFFFFFFFF" |
||||
for i = 1, #args do |
||||
str = str .. tostring(args[i]) .. " " |
||||
end |
||||
print(str) |
||||
end |
||||
|
||||
local Command = Bastion.Commmand:New('bastion') |
||||
|
||||
Command:Register('toggle', 'Toggle bastion on/off', function() |
||||
Bastion.Enabled = not Bastion.Enabled |
||||
if Bastion.Enabled then |
||||
Bastion:Print("Enabled") |
||||
else |
||||
Bastion:Print("Disabled") |
||||
end |
||||
end) |
||||
|
||||
Command:Register('debug', 'Toggle debug mode on/off', function() |
||||
Bastion.DebugMode = not Bastion.DebugMode |
||||
if Bastion.DebugMode then |
||||
Bastion:Print("Debug mode enabled") |
||||
else |
||||
Bastion:Print("Debug mode disabled") |
||||
end |
||||
end) |
||||
|
||||
Command:Register('dumpspells', 'Dump spells to a file', function() |
||||
local i = 1 |
||||
local rand = math.random(100000, 999999) |
||||
while true do |
||||
local spellName, spellSubName = GetSpellBookItemName(i, BOOKTYPE_SPELL) |
||||
if not spellName then |
||||
do break end |
||||
end |
||||
|
||||
-- use spellName and spellSubName here |
||||
local spellID = select(7, GetSpellInfo(spellName)) |
||||
|
||||
if spellID then |
||||
WriteFile('bastion-' .. UnitClass('player') .. '-' .. rand .. '.lua', |
||||
"local " .. spellName .. " = Bastion.SpellBook:GetSpell(" .. spellID .. ")", true) |
||||
end |
||||
i = i + 1 |
||||
end |
||||
end) |
||||
|
||||
Command:Register('module', 'Toggle a module on/off', function(args) |
||||
local module = Bastion:FindModule(args[2]) |
||||
if module then |
||||
module:Toggle() |
||||
if module.enabled then |
||||
Bastion:Print("Enabled", module.name) |
||||
else |
||||
Bastion:Print("Disabled", module.name) |
||||
end |
||||
else |
||||
Bastion:Print("Module not found") |
||||
end |
||||
end) |
||||
|
||||
local files = ListFiles("scripts/bastion/scripts") |
||||
|
||||
for i = 1, #files do |
||||
local file = files[i] |
||||
if file:sub(-4) == ".lua" or file:sub(-5) == '.luac' then |
||||
Tinkr:require("scripts/bastion/scripts/" .. file:sub(1, -5), Bastion) |
||||
end |
||||
end |
Loading…
Reference in new issue