From a572688294f07d1f569b30a79e7cacb552f9ad7d Mon Sep 17 00:00:00 2001 From: ck Date: Thu, 18 Jan 2024 23:36:05 -0600 Subject: [PATCH] Updates. --- src/AuraTable/AuraTable.lua | 2 +- src/Spell/Spell.lua | 192 +++++++++++++++++++++------------- src/Unit/Unit.lua | 199 ++++-------------------------------- src/_bastion.lua | 8 +- 4 files changed, 149 insertions(+), 252 deletions(-) diff --git a/src/AuraTable/AuraTable.lua b/src/AuraTable/AuraTable.lua index 26212f8..40683d8 100644 --- a/src/AuraTable/AuraTable.lua +++ b/src/AuraTable/AuraTable.lua @@ -330,7 +330,7 @@ end ---@param source "any" | Unit ---@return Aura function AuraTable:FindFrom(spell, source) - if type(source) == "string" or source == "any" then + if type(source) == "string" and source == "any" then return self:FindAny(spell) end diff --git a/src/Spell/Spell.lua b/src/Spell/Spell.lua index 3407afe..94249c3 100644 --- a/src/Spell/Spell.lua +++ b/src/Spell/Spell.lua @@ -1,43 +1,65 @@ ---@type Tinkr, Bastion local Tinkr, Bastion = ... +---@class Spell.Traits.Cast +---@field moving boolean +---@field dead boolean +---@field global boolean +---@field casting boolean +---@field channeling boolean +---@field override boolean + +---@class Spell.Traits.Target +---@field exists boolean +---@field player boolean + +---@class Spell.Traits +---@field cast Spell.Traits.Cast +---@field target Spell.Traits.Target + +---@class Spell.Traits.Cast.Params : Spell.Traits.Cast, { [string]?: boolean } +---@class Spell.Traits.Target.Params : Spell.Traits.Target, { [string]?: boolean } + +---@class Spell.Traits.Params +---@field cast? Spell.Traits.Cast.Params +---@field target? Spell.Traits.Target.Params + +---@class Spell.Aura +---@field spell Spell +---@field source? Unit +---@field target? Unit +---@field lastApplied number + -- Create a new Spell class ---@class Spell ----@field spellID number ----@field PostCastFunc fun(self:Spell) | false ----@field OnCastFunc fun(self:Spell) | false ----@field PreCastFunc fun(self:Spell) | false +---@field auras table ---@field CastableIfFunc false | fun(self:Spell):boolean +---@field damage number +---@field damageFormula false | fun(self:Spell):number ---@field lastCastAt number | false ---@field lastCastAttempt number | false ----@field target Unit | false ----@field damageFormula false | fun(self:Spell):number +---@field OnCastFunc fun(self:Spell) | false ---@field overrides { [spellId]: fun(self: Spell): Spell } ----@field auras { [spellId]: { spell: Spell, source?: Unit, target?: Unit, lastApplied: number } } +---@field PostCastFunc fun(self:Spell) | false +---@field PreCastFunc fun(self:Spell) | false +---@field release_at false +---@field spellID number +---@field target Unit | false +---@field traits Spell.Traits +---@field wasLooking boolean local Spell = { + auras = {}, CastableIfFunc = false, - PreCastFunc = false, - OnCastFunc = false, - PostCastFunc = false, - lastCastAttempt = false, - wasLooking = false, - lastCastAt = false, conditions = {}, - auras = {}, + damage = 0, + damageFormula = false, + lastCastAt = false, + lastCastAttempt = false, + OnCastFunc = false, overrides = {}, - traits = { - cast = { - moving = true, - dead = false, - global = false, - casting = false, - channeling = false, - }, - }, - target = false, + PostCastFunc = false, + PreCastFunc = false, release_at = false, - damageFormula = false, - damage = 0, } local usableExcludes = { @@ -60,24 +82,40 @@ end -- Equals ---@param other Spell ----@return boolean function Spell:__eq(other) return self:GetID() == other:GetID() end -- tostring ----@return string function Spell:__tostring() return "Bastion.__Spell(" .. self:GetID() .. ")" .. " - " .. self:GetName() end -- Constructor ---@param id number ----@return Spell function Spell:New(id) + ---@class Spell local self = setmetatable({}, Spell) - + self.auras = {} + self.conditions = {} + self.overrides = {} self.spellID = id + self.traits = { + cast = { + moving = true, + dead = false, + global = false, + casting = false, + channeling = false, + override = false, + }, + target = { + exists = true, + player = false, + } + } + self.target = false + self.wasLooking = false return self end @@ -87,7 +125,6 @@ function Spell:GetDescription() end -- Duplicator ----@return Spell function Spell:Fresh() return Spell:New(self:GetID()) end @@ -99,17 +136,8 @@ function Spell:GetID(ignoreOverride) return ignoreOverride and self.spellID or self:IsOverridden() and self:OverrideSpellID() or self.spellID end -function Spell:SetTraits(traits) - if traits.cast and type(traits.cast) == "table" then - for k, v in pairs(traits.cast) do - self.traits.cast[k] = v - end - end -end - -- Add post cast func ---@param func fun(self:Spell) ----@return Spell function Spell:PostCast(func) self.PostCastFunc = func return self @@ -188,7 +216,7 @@ end -- Cast the spell ---@param unit Unit ----@param condition? string|fun(self:Spell):boolean +---@param condition? string | fun(self:Spell):boolean ---@return boolean function Spell:Cast(unit, condition) if condition then @@ -212,7 +240,8 @@ function Spell:Cast(unit, condition) self.wasLooking = IsMouselooking() -- if unit:GetOMToken() contains 'nameplate' then we need to use Object wrapper to cast - local u = unit:GetOMToken() + + local u = unit and unit:GetOMToken() or self.traits.target.player and "none" or "none" if type(u) == "string" and string.find(u, "nameplate") then u = Object(u) end @@ -230,6 +259,7 @@ function Spell:Cast(unit, condition) if self:GetOnCastFunction() then self:GetOnCastFunction()(self) end + return true end @@ -237,16 +267,11 @@ end ---@param unit Unit ---@return boolean function Spell:ForceCast(unit) - -- Call pre cast function - -- if self:GetPreCastFunction() then - -- self:GetPreCastFunction()(self) - -- end - -- Check if the mouse was looking self.wasLooking = IsMouselooking() -- if unit:GetOMToken() contains 'nameplate' then we need to use Object wrapper to cast - local u = unit:GetOMToken() + local u = unit and unit:GetOMToken() or self.traits.target.player and "none" or "none" if type(u) == "string" and string.find(u, "nameplate") then u = Object(u) end @@ -255,16 +280,11 @@ function Spell:ForceCast(unit) CastSpellByName(self:GetName(), u) SpellCancelQueuedSpell() - Bastion:Debug("Casting", self) + Bastion:Debug("Force Casting", self) -- Set the last cast time self.lastCastAttempt = GetTime() - -- -- Call post cast function - -- if self:GetOnCastFunction() then - -- self:GetOnCastFunction()(self) - -- end - return true end @@ -300,7 +320,7 @@ end ---@param byId? boolean ---@return boolean, boolean function Spell:IsUsableSpell(byId) - return IsUsableSpell((byId ~= nil and byId) and self:GetID() or self:GetName()) + return IsUsableSpell(byId and self:GetID() or self:GetName()) end -- Check if the spell is usable @@ -315,37 +335,67 @@ end ---@param override? boolean ---@return boolean function Spell:IsKnownAndUsable(override) - return self:IsKnown(override) and not self:IsOnCooldown() and self:IsUsable(override and false or true) + return self:IsKnown(override) and not self:IsOnCooldown() and self:IsUsable(override ~= nil and false or true) +end + +---@param traits Spell.Traits.Params +function Spell:SetTraits(traits) + for _, trait in pairs({ "cast", "target" }) do + if type(traits[trait]) == "table" then + for k, _ in pairs(self.traits[trait]) do + if traits[trait][k] ~= nil then + self.traits[trait][k] = traits[trait][k] + end + end + end + end + return self end function Spell:EvaluateTraits() local player = Bastion.UnitManager["player"] - return ( - (self.traits.cast.dead or player:IsAlive()) and - (self.traits.cast.moving or not player:IsMoving()) and - (self.traits.cast.global or player:GetGCD() == 0) and - (self.traits.cast.casting or not player:IsCasting()) and - (self.traits.cast.channeling or not player:IsChanneling()) - ) + if not self.traits.cast.global and player:GetGCD() > 0 then + return false + end + + if not self.traits.cast.moving and player:IsMoving() then + return false + end + + if not self.traits.cast.dead and player:IsDead() then + return false + end + + if not self.traits.cast.casting and player:IsCasting() then + return false + end + + if not self.traits.cast.channeling and player:IsChanneling() then + return false + end + + if self.traits.target.exists and not self:TargetExists() then + return false + end + + return true end -- Check if the spell is castable ----@return boolean function Spell:Castable() if not self:EvaluateTraits() then - return true + return false end if self:GetCastableFunction() then - return self:GetCastableFunction()(self) + return self:GetCastableFunction()(self) and self:IsKnownAndUsable(self.traits.cast.override or nil) end - return self:IsKnownAndUsable() + return self:IsKnownAndUsable(self.traits.cast.override or nil) end -- Set a script to check if the spell is castable ---@param func fun(spell:Spell):boolean ----@return Spell function Spell:CastableIf(func) self.CastableIfFunc = func return self @@ -353,7 +403,6 @@ end -- Set a script to run before the spell has been cast ---@param func fun(spell:Spell) ----@return Spell function Spell:PreCast(func) self.PreCastFunc = func return self @@ -361,7 +410,6 @@ end -- Set a script to run after the spell has been cast ---@param func fun(spell:Spell) ----@return Spell function Spell:OnCast(func) self.OnCastFunc = func return self @@ -580,6 +628,10 @@ function Spell:GetTarget() return self.target end +function Spell:TargetExists() + return self:GetTarget() and self:GetTarget():Exists() +end + -- IsEnrageDispel ---@return boolean function Spell:IsEnrageDispel() diff --git a/src/Unit/Unit.lua b/src/Unit/Unit.lua index 55b7943..8c28b5b 100644 --- a/src/Unit/Unit.lua +++ b/src/Unit/Unit.lua @@ -268,7 +268,7 @@ function Unit:IsBoss() return false end ----@return UnitId +---@return UnitIds function Unit:GetOMToken() if not self.unit then return "none" @@ -379,183 +379,27 @@ local isClassicWow = select(4, GetBuildInfo()) < 40000 -- return UnitInMelee(self:GetOMToken(), unit:GetOMToken()) -- end --- 1048593 +local losFlag = bit.bor(0x1, 0x10) -local losBlacklist = { - [131863] = true, -- Raal the Gluttonous (WCM) -} - -local AttachmentPoisitions = { - MountMain = 0, - HandRight = 1, - HandLeft = 2, - ElbowRight = 3, - ElbowLeft = 4, - ShoulderRight = 5, - ShoulderLeft = 6, - KneeRight = 7, - KneeLeft = 8, - HipRight = 9, - HipLeft = 10, - Helm = 11, - Back = 12, - ShoulderFlapRight = 13, - ShoulderFlapLeft = 14, - ChestBloodFront = 15, - ChestBloodBack = 16, - Breath = 17, - PlayerName = 18, - Base = 19, - Head = 20, - SpellLeftHand = 21, - SpellRightHand = 22, - Special1 = 23, - Special2 = 24, - Special3 = 25, - SheathMainHand = 26, - SheathOffHand = 27, - SheathShield = 28, - PlayerNameMounted = 29, - LargeWeaponLeft = 30, - LargeWeaponRight = 31, - HipWeaponLeft = 32, - HipWeaponRight = 33, - Chest = 34, - HandArrow = 35, - Bullet = 36, - SpellHandOmni = 37, - SpellHandDirected = 38, - VehicleSeat1 = 39, - VehicleSeat2 = 40, - VehicleSeat3 = 41, - VehicleSeat4 = 42, - VehicleSeat5 = 43, - VehicleSeat6 = 44, - VehicleSeat7 = 45, - VehicleSeat8 = 46, - LeftFoot = 47, - RightFoot = 48, - ShieldNoGlove = 49, - SpinLow = 50, - AlteredShoulderR = 51, - AlteredShoulderL = 52, - BeltBuckle = 53, - SheathCrossbow = 54, - HeadTop = 55, - VirtualSpellDirected = 56, - Backpack = 57, - Unknown = 60, -} - ---[[ - M2Collision = 1, -- 0x1 - M2Render = 2, -- 0x2 - WMOCollision = 16, -- 0x10 - WMORender = 32, -- 0x20 - Terrain = 256, -- 0x100 - WaterWalkableLiquid = 65536, -- 0x10000 - Liquid = 131072, -- 0x20000 - WaterOrLiquid = 196608, -- 0x30000 - EntityCollision = 1048576, -- 0x100000 - Most = 1048849, -- 0x100201 - Unknown = 2097152, -- 0x200000 - All = 3211571, -- 0x310003 -]] - ---[[ - public enum IntersectFlags { - None, - DoodadCollision = 0x00000001, - DoodadRender = 0x00000002, - WmoCollision = 0x00000010, - WmoRender = 0x00000020, - WmoNoCamCollision = 0x00000040, - Terrain = 0x00000100, - IgnoreWmoDoodad = 0x00002000, - LiquidWaterWalkable = 0x00010000, - LiquidAll = 0x00020000, - Cull = 0x00080000, - EntityCollision = 0x00100000, - EntityRender = 0x00200000, - - Collision = DoodadCollision | WmoCollision | Terrain | EntityCollision, - LineOfSight = WmoCollision | EntityCollision -]] - ---[[ - M2Collision = 0x1 - M2Render = 0x2 - WMOCollision = 0x10 - WMORender = 0x20 - Terrain = 0x100 - WaterWalkableLiquid = 0x10000 - Liquid = 0x20000 - WaterOrLiquid = 0x30000, - EntityCollision = 0x100000 - Most = 0x100201, - Unknown = 0x200000, - All = 0x310003, -]] - -local attachmentOverride = { - [131863] = AttachmentPoisitions.Head, -- WCM Raal the Gluttonous -} - -function Unit:GetHitSphere() - --local srcX, srcY, srcZ = GetUnitAttachmentPosition(self:GetOMToken(), attachmentOverride[self:GetID()] or AttachmentPoisitions.PlayerName) - --local srcHeight = UnitIsMounted(self:GetOMToken()) and 3.081099 or 2.43808 - return Bastion.Vector3:New(GetUnitAttachmentPosition(self:GetOMToken(), - attachmentOverride[self:GetID()] or AttachmentPoisitions.PlayerName)) -end - -function Unit:GetLOSSourcePosition() - local src = self:GetPosition() - src.z = UnitIsMounted(self:GetOMToken()) and 3.081099 or 2.43808 - return src -end - -local losFlag = bit.bor(0x10) -- Check if the unit can see another unit ----@param targetUnit Unit ----@return boolean -function Unit:CanSee(targetUnit) - local npcId = targetUnit:GetID() - if npcId and losBlacklist[npcId] then - return true - end - - local src = self:GetLOSSourcePosition() - local dst = targetUnit:GetHitSphere() - - if (src.x == 0 and src.y == 0 and src.z == 0) or (dst.x == 0 and dst.y == 0 and dst.z == 0) then - return true - end - - local contactPoint = src + - (dst - src):directionOrZero() * math.min(targetUnit:GetDistance(self), self:GetCombatReach()) - - local x, y, z = TraceLine(src.x, src.y, src.z, contactPoint.x, contactPoint.y, contactPoint.z, losFlag) - if x ~= 0 or y ~= 0 or z ~= 0 then - return false - else - return true - end -end - ----@param destination Unit ----@return Vector3 -function Unit:GetHitSpherePointFor(destination) - local vThis = Bastion.Vector3:New(self:GetPosition().x, self:GetPosition().y, - self:GetPosition().z + ObjectHeight(self:GetOMToken())) - local vObj = Bastion.Vector3:New(destination:GetPosition().x, destination:GetPosition().y, - destination:GetPosition().z) - local contactPoint = vThis + - (vObj - vThis):directionOrZero() * math.min(destination:GetDistance(self), self:GetCombatReach()) - return contactPoint -end - ---@param unit Unit -function Unit:CanSee2(unit) +---@return boolean +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:GetOMToken()) local ah = ObjectHeight(self:GetOMToken()) local attx, atty, attz = GetUnitAttachmentPosition(unit:GetOMToken(), 34) @@ -1135,11 +979,8 @@ end ---@return number function Unit:GetGCD() local start, duration = GetSpellCooldown(61304) - if start == 0 then - return 0 - end - return duration - (GetTime() - start) + return start == 0 and 0 or duration - (GetTime() - start) end -- Get units max gcd time diff --git a/src/_bastion.lua b/src/_bastion.lua index 29fd481..5622ca4 100644 --- a/src/_bastion.lua +++ b/src/_bastion.lua @@ -186,6 +186,7 @@ Bastion.Globals.SpellName = {} Bastion.Globals.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", function() local args = { CombatLogGetCurrentEventInfo() } + ---@type string local subEvent = args[2] ---@type string local sourceGUID = args[4] @@ -196,10 +197,13 @@ Bastion.Globals.EventManager:RegisterWoWEvent("COMBAT_LOG_EVENT_UNFILTERED", fun ---@type string local spellName = args[13] - if not Bastion.Globals.SpellName[spellID] or Bastion.Globals.SpellName[spellID] ~= spellName then - Bastion.Globals.SpellName[spellID] = spellName + if subEvent:find("SPELL") == 1 or subEvent:find("RANGE") == 1 then + if (not Bastion.Globals.SpellName[spellID] or Bastion.Globals.SpellName[spellID] ~= spellName) then + Bastion.Globals.SpellName[spellID] = spellName + end end + -- if sourceGUID == pguid then -- local args = { CombatLogGetCurrentEventInfo() }