diff --git a/ShadowedUnitFrames.lua b/ShadowedUnitFrames.lua index eddf687b..ac35053c 100755 --- a/ShadowedUnitFrames.lua +++ b/ShadowedUnitFrames.lua @@ -5,6 +5,9 @@ ShadowUF = select(2, ...) local L = ShadowUF.L + +local WoWWrath = (WOW_PROJECT_ID == WOW_PROJECT_WRATH_CLASSIC) + ShadowUF.dbRevision = 61 ShadowUF.dbRevisionClassic = 6 ShadowUF.playerUnit = "player" @@ -772,6 +775,12 @@ function ShadowUF:HideBlizzardFrames() -- We keep these in case someone is still using the default auras, otherwise it messes up vehicle stuff PlayerFrame:RegisterEvent("PLAYER_ENTERING_WORLD") + if WoWWrath then + PlayerFrame:RegisterEvent("UNIT_ENTERING_VEHICLE") + PlayerFrame:RegisterEvent("UNIT_ENTERED_VEHICLE") + PlayerFrame:RegisterEvent("UNIT_EXITING_VEHICLE") + PlayerFrame:RegisterEvent("UNIT_EXITED_VEHICLE") + end PlayerFrame:SetMovable(true) PlayerFrame:SetUserPlaced(true) PlayerFrame:SetDontSavePosition(true) diff --git a/ShadowedUnitFrames.xml b/ShadowedUnitFrames.xml index 9ce821a8..ec6af43d 100644 --- a/ShadowedUnitFrames.xml +++ b/ShadowedUnitFrames.xml @@ -1,4 +1,8 @@ diff --git a/modules/auraindicators.lua b/modules/auraindicators.lua index 6af6a0c0..b1e1499d 100755 --- a/modules/auraindicators.lua +++ b/modules/auraindicators.lua @@ -23,7 +23,7 @@ Indicators.auraConfig = setmetatable({}, { return tbl[index] end}) -local playerUnits = {player = true, pet = true} +local playerUnits = {player = true, vehicle = true, pet = true} local backdropTbl = {bgFile = "Interface\\Addons\\ShadowedUnitFrames\\mediabackdrop", edgeFile = "Interface\\Addons\\ShadowedUnitFrames\\media\\backdrop", tile = true, tileSize = 1, edgeSize = 1} function Indicators:OnEnable(frame) diff --git a/modules/auras.lua b/modules/auras.lua index 1f6c244d..5d2b31bc 100755 --- a/modules/auras.lua +++ b/modules/auras.lua @@ -1,5 +1,5 @@ local Auras = {} -local playerUnits = {player = true, pet = true} +local playerUnits = {player = true, vehicle = true, pet = true} local mainHand, offHand, tempEnchantScan = {time = 0}, {time = 0} local canCure = ShadowUF.Units.canCure ShadowUF:RegisterModule(Auras, "auras", ShadowUF.L["Auras"]) @@ -236,7 +236,7 @@ local function hideTooltip(self) end local function cancelAura(self, mouse) - if( mouse ~= "RightButton" or not UnitIsUnit(self.parent.unit, "player") or InCombatLockdown() or self.filter == "TEMP" ) then + if( mouse ~= "RightButton" or ( not UnitIsUnit(self.parent.unit, "player") and not UnitIsUnit(self.parent.unit, "vehicle") ) or InCombatLockdown() or self.filter == "TEMP" ) then return end @@ -465,6 +465,17 @@ end -- Unfortunately, temporary enchants have basically no support beyond hacks. So we will hack! tempEnchantScan = function(self, elapsed) + if( self.parent.unit == self.parent.vehicleUnit and self.lastTemporary > 0 ) then + mainHand.has = false + offHand.has = false + + self.temporaryEnchants = 0 + self.lastTemporary = 0 + + Auras:Update(self.parent) + return + end + timeElapsed = timeElapsed + elapsed if( timeElapsed < 0.50 ) then return end timeElapsed = timeElapsed - 0.50 diff --git a/modules/combopoints.lua b/modules/combopoints.lua index eb01a898..0f64799d 100755 --- a/modules/combopoints.lua +++ b/modules/combopoints.lua @@ -1,5 +1,7 @@ if( not ShadowUF.ComboPoints ) then return end +local WoWWrath = (WOW_PROJECT_ID == WOW_PROJECT_WRATH_CLASSIC) + local Combo = setmetatable({}, {__index = ShadowUF.ComboPoints}) ShadowUF:RegisterModule(Combo, "comboPoints", ShadowUF.L["Combo points"]) local cpConfig = {max = MAX_COMBO_POINTS, key = "comboPoints", colorKey = "COMBOPOINTS", powerType = Enum.PowerType.ComboPoints, eventType = "COMBO_POINTS", icon = "Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\combo"} @@ -30,11 +32,21 @@ function Combo:GetMaxPoints() end function Combo:GetPoints(unit) - return UnitPower("player", cpConfig.powerType) + -- For Malygos dragons, they also self cast their CP on themselves, which is why we check CP on ourself + if( WoWWrath and UnitHasVehicleUI("player") and UnitHasVehiclePlayerFrameUI("player") ) then + local points = GetComboPoints("vehicle", "target") + if( points == 0 ) then + points = GetComboPoints("vehicle", "vehicle") + end + + return points + else + return UnitPower("player", cpConfig.powerType) + end end function Combo:Update(frame, event, unit, powerType) - if( not event or ( unit == frame.unit or unit == "player" ) ) then + if( not event or ( unit == frame.unit or unit == frame.vehicleUnit or unit == "player" or unit == "vehicle" ) ) then ShadowUF.ComboPoints.Update(self, frame, event, unit, powerType) end end diff --git a/modules/druid.lua b/modules/druid.lua index f42aa868..51d0c199 100755 --- a/modules/druid.lua +++ b/modules/druid.lua @@ -22,7 +22,7 @@ function Druid:OnLayoutApplied(frame) end function Druid:PowerChanged(frame) - local visible = UnitPowerType(frame.unit) ~= Enum.PowerType.Mana + local visible = UnitPowerType(frame.unit) ~= Enum.PowerType.Mana and not frame.inVehicle local type = visible and "RegisterUnitEvent" or "UnregisterSingleEvent" frame[type](frame, "UNIT_POWER_FREQUENT", self, "Update") diff --git a/modules/health.lua b/modules/health.lua index 81c5ecf7..fccd24d9 100755 --- a/modules/health.lua +++ b/modules/health.lua @@ -91,6 +91,8 @@ function Health:UpdateColor(frame) return elseif( ShadowUF.db.profile.units[frame.unitType].healthBar.colorDispel and frame.healthBar.hasDebuff ) then color = DebuffTypeColor[frame.healthBar.hasDebuff] + elseif( frame.inVehicle ) then + color = ShadowUF.db.profile.classColors.VEHICLE elseif( not UnitPlayerControlled(unit) and UnitIsTapDenied(unit) and UnitCanAttack("player", unit) ) then color = ShadowUF.db.profile.healthColors.tapped elseif( not UnitPlayerOrPetInRaid(unit) and not UnitPlayerOrPetInParty(unit) and ( ( ( reactionType == "player" or reactionType == "both" ) and UnitIsPlayer(unit) and not UnitIsFriend(unit, "player") ) or ( ( reactionType == "npc" or reactionType == "both" ) and not UnitIsPlayer(unit) ) ) ) then diff --git a/modules/indicators.lua b/modules/indicators.lua index 4632f729..2e74aa8d 100755 --- a/modules/indicators.lua +++ b/modules/indicators.lua @@ -1,5 +1,7 @@ local Indicators = {list = {"status", "pvp", "leader", "resurrect", "masterLoot", "raidTarget", "ready", "role", "class", "phase", "happiness" }} +local WoWWrath = (WOW_PROJECT_ID == WOW_PROJECT_WRATH_CLASSIC) + ShadowUF:RegisterModule(Indicators, "indicators", ShadowUF.L["Indicators"]) function Indicators:UpdateClass(frame) @@ -131,6 +133,12 @@ local function combatMonitor(self, elapsed) end end +-- It looks like the combat check for players is a bit buggy when they are in a vehicle, so swap it to also check polling +function Indicators:CheckVehicle(frame) + frame.indicators.timeElapsed = 0 + frame.indicators:SetScript("OnUpdate", frame.inVehicle and combatMonitor or nil) +end + function Indicators:UpdateStatus(frame) if( not frame.indicators.status or not frame.indicators.status.enabled ) then return end @@ -260,6 +268,9 @@ function Indicators:OnEnable(frame) frame.indicators.parent = frame if( frame.unitType == "player" ) then + if WoWWrath then + frame:RegisterUpdateFunc(self, "CheckVehicle") + end frame:RegisterNormalEvent("PLAYER_REGEN_ENABLED", self, "UpdateStatus") frame:RegisterNormalEvent("PLAYER_REGEN_DISABLED", self, "UpdateStatus") frame:RegisterNormalEvent("PLAYER_UPDATE_RESTING", self, "UpdateStatus") diff --git a/modules/tags.lua b/modules/tags.lua index 1a84598d..0213115a 100755 --- a/modules/tags.lua +++ b/modules/tags.lua @@ -4,6 +4,8 @@ local L = ShadowUF.L ShadowUF.Tags = Tags +local WoWWrath = (WOW_PROJECT_ID == WOW_PROJECT_WRATH_CLASSIC) + -- Map the numeric index to the string local numerics = {} for id, color in pairs(PowerBarColor) do @@ -792,7 +794,18 @@ Tags.defaultTags = { return ShadowUF.L["Offline"] end end]], - ["cpoints"] = [[function(unit, unitOwner) + ["cpoints"] = WoWWrath and [[function(unit, unitOwner) + if( UnitHasVehicleUI("player") and UnitHasVehiclePlayerFrameUI("player") ) then + local points = GetComboPoints("vehicle") + if( points == 0 ) then + points = GetComboPoints("vehicle", "vehicle") + end + + return points + else + return UnitPower("player", Enum.PowerType.ComboPoints) + end + end]] or [[function(unit, unitOwner) return UnitPower("player", Enum.PowerType.ComboPoints) end]], ["sshards"] = [[function(unit, unitOwner) diff --git a/modules/totems.lua b/modules/totems.lua index 26d04e01..7b0f265e 100755 --- a/modules/totems.lua +++ b/modules/totems.lua @@ -2,6 +2,8 @@ local Totems = {} local totemColors = {} local MAX_TOTEMS = MAX_TOTEMS +local WoWWrath = (WOW_PROJECT_ID == WOW_PROJECT_WRATH_CLASSIC) + -- Death Knights untalented ghouls are guardians and are considered totems........... so set it up for them local playerClass = select(2, UnitClass("player")) ShadowUF:RegisterModule(Totems, "totemBar", ShadowUF.L["Totem bar"], true, "SHAMAN") @@ -44,6 +46,9 @@ function Totems:OnEnable(frame) end frame:RegisterNormalEvent("PLAYER_TOTEM_UPDATE", self, "Update") + if WoWWrath then + frame:RegisterUpdateFunc(self, "UpdateVisibility") + end frame:RegisterUpdateFunc(self, "Update") end @@ -107,7 +112,7 @@ local function totemMonitor(self, elapsed) self:SetScript("OnUpdate", nil) self.endTime = nil - if( MAX_TOTEMS == 1 ) then + if( not self.parent.inVehicle and MAX_TOTEMS == 1 ) then ShadowUF.Layout:SetBarVisibility(self.parent, "totemBar", false) end end @@ -117,6 +122,18 @@ local function totemMonitor(self, elapsed) end end +function Totems:UpdateVisibility(frame) + if( frame.totemBar.inVehicle ~= frame.inVehicle ) then + frame.totemBar.inVehicle = frame.inVehicle + + if( frame.inVehicle ) then + ShadowUF.Layout:SetBarVisibility(frame, "totemBar", false) + elseif( MAX_TOTEMS ~= 1 ) then + self:Update(frame) + end + end +end + function Totems:Update(frame) local totalActive = 0 for _, indicator in pairs(frame.totemBar.totems) do diff --git a/modules/units.lua b/modules/units.lua index 08b02bf9..2404683f 100755 --- a/modules/units.lua +++ b/modules/units.lua @@ -11,6 +11,8 @@ local unitFrames, headerFrames, frameList, unitEvents, childUnits, headerUnits, local remappedUnits = Units.remappedUnits local _G = getfenv(0) +local WoWWrath = (WOW_PROJECT_ID == WOW_PROJECT_WRATH_CLASSIC) + ShadowUF.Units = Units ShadowUF:RegisterModule(Units, "units") @@ -37,7 +39,7 @@ local function ReregisterUnitEvents(self) if( hasHandler ) then self:UnregisterEvent(event) - self:BlizzRegisterUnitEvent(event, self.unitOwner, nil) + self:BlizzRegisterUnitEvent(event, self.unitOwner, self.vehicleUnit) end end end @@ -52,7 +54,7 @@ local function RegisterNormalEvent(self, event, handler, func, unitOverride) end if( unitEvents[event] and not ShadowUF.fakeUnits[self.unitRealType] ) then - self:BlizzRegisterUnitEvent(event, unitOverride or self.unitOwner, nil) + self:BlizzRegisterUnitEvent(event, unitOverride or self.unitOwner, self.vehicleUnit) if unitOverride then self.unitEventOverrides = self.unitEventOverrides or {} self.unitEventOverrides[event] = unitOverride @@ -285,6 +287,62 @@ local function SetVisibility(self) end end +-- Vehicles do not always return their data right away, a pure OnUpdate check seems to be the most accurate unfortunately +local function checkVehicleData(self, elapsed) + self.timeElapsed = self.timeElapsed + elapsed + if( self.timeElapsed >= 0.50 ) then + self.timeElapsed = 0 + self.dataAttempts = self.dataAttempts + 1 + + -- Took too long to get vehicle data, or they are no longer in a vehicle + if( self.dataAttempts >= 6 or not UnitHasVehicleUI(self.unitOwner) or not UnitHasVehiclePlayerFrameUI(self.unitOwner) ) then + self.timeElapsed = nil + self.dataAttempts = nil + self:SetScript("OnUpdate", nil) + + self.inVehicle = false + self.unit = self.unitOwner + self:FullUpdate() + + -- Got data, stop checking and do a full frame update + elseif( UnitIsConnected(self.unit) or UnitHealthMax(self.unit) > 0 ) then + self.timeElapsed = nil + self.dataAttempts = nil + self:SetScript("OnUpdate", nil) + + self.unitGUID = UnitGUID(self.unit) + self:FullUpdate() + end + end +end + +-- Check if a unit entered a vehicle +function Units:CheckVehicleStatus(frame, event, unit) + if( event and frame.unitOwner ~= unit ) then return end + + -- Not in a vehicle yet, and they entered one that has a UI or they were in a vehicle but the GUID changed (vehicle -> vehicle) + if( ( not frame.inVehicle or frame.unitGUID ~= UnitGUID(frame.vehicleUnit) ) and UnitHasVehicleUI(frame.unitOwner) and UnitHasVehiclePlayerFrameUI(frame.unitOwner) and not ShadowUF.db.profile.units[frame.unitType].disableVehicle ) then + frame.inVehicle = true + frame.unit = frame.vehicleUnit + + if( not UnitIsConnected(frame.unit) or UnitHealthMax(frame.unit) == 0 ) then + frame.timeElapsed = 0 + frame.dataAttempts = 0 + frame:SetScript("OnUpdate", checkVehicleData) + else + frame.unitGUID = UnitGUID(frame.unit) + frame:FullUpdate() + end + + -- Was in a vehicle, no longer has a UI + elseif( frame.inVehicle and ( not UnitHasVehicleUI(frame.unitOwner) or not UnitHasVehiclePlayerFrameUI(frame.unitOwner) or ShadowUF.db.profile.units[frame.unitType].disableVehicle ) ) then + frame.inVehicle = false + frame.unit = frame.unitOwner + frame.unitGUID = UnitGUID(frame.unit) + frame:FullUpdate() + end +end + -- Handles checking for GUID changes for doing a full update, this fixes frames sometimes showing the wrong unit when they change function Units:CheckUnitStatus(frame) local guid = frame.unit and UnitGUID(frame.unit) @@ -310,8 +368,15 @@ end -- OnAttributeChanged won't do anything because the frame is already setup, however, the active unit is non-existant -- while the primary unit is. So if we see they're in a vehicle with this case, we force the full update to get the vehicle change function Units:CheckGroupedUnitStatus(frame) - frame.unitGUID = UnitGUID(frame.unit) - frame:FullUpdate() + if( frame.inVehicle and not UnitExists(frame.unit) and UnitExists(frame.unitOwner) ) then + frame.inVehicle = false + frame.unit = frame.unitOwner + frame.unitGUID = UnitGUID(frame.unit) + frame:FullUpdate() + else + frame.unitGUID = UnitGUID(frame.unit) + frame:FullUpdate() + end end -- More fun with sorting, due to sorting magic we have to check if we want to create stuff when the frame changes of partys too @@ -349,6 +414,7 @@ end -- unitType = Unitid minus numbers in it, used for configuration -- unitRealType = The actual unit type, if party is shown in raid this will be "party" while unitType is still "raid" -- unitOwner = Always the units owner even when unit changes due to vehicles +-- vehicleUnit = Unit to use when the unitOwner is in a vehicle OnAttributeChanged = function(self, name, unit) if( name ~= "unit" or not unit or unit == self.unitOwner ) then return end @@ -362,6 +428,8 @@ OnAttributeChanged = function(self, name, unit) self.unitRealType = string.gsub(unit, "([0-9]+)", "") self.unitType = self.unitUnmapped and string.gsub(self.unitUnmapped, "([0-9]+)", "") or self.unitType or self.unitRealType self.unitOwner = unit + self.vehicleUnit = self.unitOwner == "player" and "vehicle" or self.unitRealType == "party" and "partypet" .. self.unitID or self.unitRealType == "raid" and "raidpet" .. self.unitID or nil + self.inVehicle = nil -- Split everything into two maps, this is the simple parentUnit -> frame map -- This is for things like finding a party parent for party target/pet, the main map for doing full updates is @@ -396,6 +464,13 @@ OnAttributeChanged = function(self, name, unit) ClickCastFrames[self] = true end + -- Handles switching the internal unit variable to that of their vehicle + if( WoWWrath and ( self.unit == "player" or self.unitRealType == "party" or self.unitRealType == "raid" ) ) then + self:RegisterNormalEvent("UNIT_ENTERED_VEHICLE", Units, "CheckVehicleStatus") + self:RegisterNormalEvent("UNIT_EXITED_VEHICLE", Units, "CheckVehicleStatus") + self:RegisterUpdateFunc(Units, "CheckVehicleStatus") + end + -- Phase change, do a full update on it self:RegisterUnitEvent("UNIT_PHASE", self, "FullUpdate") @@ -405,6 +480,35 @@ OnAttributeChanged = function(self, name, unit) self:SetAttribute("unitRealOwner", self.unitRealOwner) self:RegisterNormalEvent("UNIT_PET", Units, "CheckPetUnitUpdated") + if WoWWrath then + if( self.unit == "pet" ) then + self:SetAttribute("disableVehicleSwap", ShadowUF.db.profile.units.player.disableVehicle) + else + self:SetAttribute("disableVehicleSwap", ShadowUF.db.profile.units.party.disableVehicle) + end + + -- Logged out in a vehicle + if( UnitHasVehicleUI(self.unitRealOwner) and UnitHasVehiclePlayerFrameUI(self.unitRealOwner) ) then + self:SetAttribute("unitIsVehicle", true) + end + + -- Hide any pet that became a vehicle, we detect this by the owner being untargetable but they have a pet out + stateMonitor:WrapScript(self, "OnAttributeChanged", [[ + if( name == "state-vehicleupdated" ) then + self:SetAttribute("unitIsVehicle", UnitHasVehicleUI(self:GetAttribute("unitRealOwner")) and value == "vehicle" and true or false) + elseif( name == "disablevehicleswap" or name == "state-unitexists" or name == "unitisvehicle" ) then + -- Unit does not exist, OR unit is a vehicle and vehicle swap is not disabled, hide frame + if( not self:GetAttribute("state-unitexists") or ( self:GetAttribute("unitIsVehicle") and not self:GetAttribute("disableVehicleSwap") ) ) then + self:Hide() + -- Unit exists, show it + else + self:Show() + end + end + ]]) + RegisterStateDriver(self, "vehicleupdated", string.format("[target=%s, nohelp, noharm] vehicle; pet", self.unitRealOwner, self.unit)) + end + -- Automatically do a full update on target change elseif( self.unit == "target" ) then self.isUnitVolatile = true @@ -418,6 +522,11 @@ OnAttributeChanged = function(self, name, unit) self:RegisterUnitEvent("UNIT_TARGETABLE_CHANGED", self, "FullUpdate") elseif( self.unit == "player" ) then + -- this should not get called in combat, but just in case make sure we are not actually in combat + if not InCombatLockdown() then + self:SetAttribute("toggleForVehicle", true) + end + -- Force a full update when the player is alive to prevent freezes when releasing in a zone that forces a ressurect (naxx/tk/etc) self:RegisterNormalEvent("PLAYER_ALIVE", self, "FullUpdate") @@ -491,6 +600,8 @@ local secureInitializeUnit = [[ self:SetWidth(header:GetAttribute("style-width")) self:SetScale(header:GetAttribute("style-scale")) + self:SetAttribute("toggleForVehicle", true) + self:SetAttribute("*type1", "target") self:SetAttribute("*type2", "togglemenu") self:SetAttribute("type2", "togglemenu") diff --git a/modules/xp.lua b/modules/xp.lua index f16c5071..207e4672 100755 --- a/modules/xp.lua +++ b/modules/xp.lua @@ -107,7 +107,7 @@ end function XP:UpdateXP(frame) -- At the level cap or XP is disabled, or the pet is actually a vehicle right now, swap to reputation bar (or hide it) - if( UnitLevel(frame.unitOwner) == MAX_PLAYER_LEVEL ) then + if( UnitLevel(frame.unitOwner) == MAX_PLAYER_LEVEL or ( frame.unitOwner == "pet" and UnitExists("vehicle") ) ) then frame.xpBar.xp:Hide() return end diff --git a/options/config.lua b/options/config.lua index 428613b8..9ebd7110 100755 --- a/options/config.lua +++ b/options/config.lua @@ -4,6 +4,8 @@ local playerClass = select(2, UnitClass("player")) local modifyUnits, globalConfig = {}, {} local L = ShadowUF.L +local WoWWrath = (WOW_PROJECT_ID == WOW_PROJECT_WRATH_CLASSIC) + ShadowUF.Config = Config --[[ @@ -2477,6 +2479,43 @@ local function loadUnitOptions() set = setUnit, get = getUnit, args = { + vehicle = WoWWrath and { + order = 1, + type = "group", + inline = true, + name = L["Vehicles"], + hidden = function(info) return info[2] ~= "player" and info[2] ~= "party" or not ShadowUF.db.profile.advanced end, + args = { + disable = { + order = 0, + type = "toggle", + name = L["Disable vehicle swap"], + desc = L["Disables the unit frame from turning into a vehicle when the player enters one."], + set = function(info, value) + setUnit(info, value) + local unit = info[2] + if( unit == "player" ) then + if( ShadowUF.Units.unitFrames.pet ) then + ShadowUF.Units.unitFrames.pet:SetAttribute("disableVehicleSwap", ShadowUF.db.profile.units[unit].disableVehicle) + end + + if( ShadowUF.Units.unitFrames.player ) then + ShadowUF.Units:CheckVehicleStatus(ShadowUF.Units.unitFrames.player) + end + elseif( unit == "party" ) then + for frame in pairs(ShadowUF.Units.unitFrames) do + if( frame.unitType == "partypet" ) then + frame:SetAttribute("disableVehicleSwap", ShadowUF.db.profile.units[unit].disableVehicle) + elseif( frame.unitType == "party" ) then + ShadowUF.Units:CheckVehicleStatus(frame) + end + end + end + end, + arg = "disableVehicle", + }, + }, + } or nil, portrait = { order = 2, type = "group",