local _, addon = ... local MsgAlertContainer = addon.MsgAlertContainer; local TransitionAPI = addon.TransitionAPI; local SlotButtonOverlayUtil = addon.SlotButtonOverlayUtil; local Narci = Narci; Narci.refreshCombatRatings = true; local SLOT_TABLE = {}; Narci.slotTable = SLOT_TABLE; local STAT_STABLE = {}; local SHORT_STAT_TABLE = {}; local L = Narci.L; local VIGNETTE_ALPHA = 0.5; local IS_OPENED = false; --Addon was opened by clicking local MOG_MODE = false; local SHOW_MISSING_ENCHANT_ALERT = true; local NarciAPI = NarciAPI; local GetItemEnchantID = NarciAPI.GetItemEnchantID; local GetItemEnchantText = NarciAPI.GetEnchantTextByItemLink; local EnchantInfo = Narci.EnchantData; --Bridge/GearBonus.lua local PlayLetteboxAnimation = NarciAPI_LetterboxAnimation; local SmartFontType = NarciAPI.SmartFontType; local IsItemSocketable = NarciAPI.IsItemSocketable; local SetBorderTexture = NarciAPI.SetBorderTexture; local GetBorderArtByItemID = NarciAPI.GetBorderArtByItemID; local GetVerticalRunicLetters = NarciAPI.GetVerticalRunicLetters; local FadeFrame = NarciFadeUI.Fade; local inOutSine = addon.EasingFunctions.inOutSine local linear = addon.EasingFunctions.linear; local outSine = addon.EasingFunctions.outSine; local GetToolbarButtonByButtonType = addon.GetToolbarButtonByButtonType; local TransmogDataProvider = addon.TransmogDataProvider; --local GetCorruptedItemAffix = NarciAPI_GetCorruptedItemAffix; local Narci_AlertFrame_Autohide = Narci_AlertFrame_Autohide; local C_Item = C_Item; local GetItemInfo = GetItemInfo; local C_LegendaryCrafting = C_LegendaryCrafting; local C_TransmogCollection = C_TransmogCollection; local After = C_Timer.After; local ItemLocation = ItemLocation; local IsPlayerInAlteredForm = TransitionAPI.IsPlayerInAlteredForm; local InCombatLockdown = InCombatLockdown; local GetItemInfoInstant = GetItemInfoInstant; local GetInventoryItemTexture = GetInventoryItemTexture; local GetCameraZoom = GetCameraZoom; local floor = math.floor; local max = math.max; local UIParent = _G.UIParent; local Toolbar = NarciScreenshotToolbar; local EquipmentFlyoutFrame; local ItemLevelFrame; local RadarChart; local ItemTooltip; local MiniButton = Narci_MinimapButton; local NarciThemeUtil = NarciThemeUtil; hooksecurefunc("StaticPopup_Show", function(name) if name == "EXPERIMENTAL_CVAR_WARNING" then StaticPopup_Hide(name); end end) local EL = CreateFrame("Frame"); --Event Listener EL:Hide(); EL.EVENTS_DYNAMIC = {"PLAYER_TARGET_CHANGED", "COMBAT_RATING_UPDATE", "PLAYER_MOUNT_DISPLAY_CHANGED", "PLAYER_STARTED_MOVING", "PLAYER_REGEN_DISABLED", "UNIT_MAXPOWER", "PLAYER_STARTED_TURNING", "PLAYER_STOPPED_TURNING", "BAG_UPDATE_COOLDOWN", "UNIT_STATS", "BAG_UPDATE", "PLAYER_EQUIPMENT_CHANGED", "AZERITE_ESSENCE_ACTIVATED", }; EL.EVENTS_UNIT = {"UNIT_DAMAGE", "UNIT_ATTACK_SPEED", "UNIT_MAXHEALTH", "UNIT_AURA", "UNIT_INVENTORY_CHANGED"}; --[[ local TakenOutFrames = { [2] = AzeriteEmpoweredItemUI, -- [3] = ItemSocketingFrame, -- [4] = ArtifactFrame, -- } local function TakeOutFromUIParent(frame, frameStrata, state) local effectiveScale = UIParent:GetEffectiveScale(); frameStrata = frameStrata or "MEDIUM"; if frame then if state then frame:SetParent(nil); frame:SetFrameStrata(frameStrata); frame:SetScale(effectiveScale); else frame:SetScale(1); frame:SetParent(UIParent); frame:SetFrameStrata(frameStrata); end end end --]] --take out frames from UIParent, so they will still be visible when UI is hidden local function TakeOutFrames(state) local frameNames = { "AzeriteEmpoweredItemUI", "AzeriteEssenceUI", "ItemSocketingFrame", }; local frame; if state then local scale = UIParent:GetEffectiveScale(); for _, frameName in pairs(frameNames) do frame = _G[frameName]; if frame then frame:SetParent(nil); frame:SetScale(scale); end end else for _, frameName in pairs(frameNames) do frame = _G[frameName]; if frame then frame:SetParent(UIParent); frame:SetScale(1); end end end end local DefaultTooltip; local ShowDelayedTooltip = NarciAPI_ShowDelayedTooltip; function Narci_ShowButtonTooltip(self) DefaultTooltip:HideTooltip(); DefaultTooltip:SetOwner(self, "ANCHOR_NONE"); if not self.tooltipHeadline then return end DefaultTooltip:SetPoint("BOTTOM", self, "TOP", 0, 2); DefaultTooltip:SetText(self.tooltipHeadline); if self.tooltipLine1 then DefaultTooltip:AddLine(self.tooltipLine1, 1, 1, 1, true); end if self.tooltipSpecial then DefaultTooltip:AddLine(" "); DefaultTooltip:AddLine(self.tooltipSpecial, 0.25, 0.78, 0.92, true); end DefaultTooltip:Show(); DefaultTooltip:FadeIn(); --ShowDelayedTooltip("BOTTOM", self, "TOP", 0, 2); end function Narci:HideButtonTooltip() --ShowDelayedTooltip(false); DefaultTooltip:HideTooltip(); ItemTooltip:HideTooltip(); --DefaultTooltip:SetFrameStrata("TOOLTIP"); end -------------------------------- local UIPA = CreateFrame("Frame"); --UIParentAlphaAnimation UIPA:Hide() UIPA.t = 0; UIPA.totalTime = 0; UIPA.frame = UIParent; UIPA:SetScript("OnShow", function(self) self.startAlpha = self.frame:GetAlpha(); end); UIPA:SetScript("OnUpdate", function(self, elapsed) self.t = self.t + elapsed self.totalTime = self.totalTime + elapsed; if self.t < 0.08 then --Limit update frequency to mitigate the impact on FPS return; else self.t = 0; end local alpha = linear(self.totalTime, self.startAlpha, self.endAlpha, 0.5); if self.totalTime >= 0.5 then alpha = self.endAlpha; self:Hide(); end self.frame:SetAlpha(alpha); end); UIPA:SetScript("OnHide", function(self) self.t = 0; self.totalTime = 0; end); -------------------------------- -----------CVar Backup---------- -------------------------------- local ConsoleExec = ConsoleExec; local GetCVar = (C_CVar and C_CVar.GetCVar) or GetCVar; local SetCVar = (C_CVar and C_CVar.SetCVar) or SetCVar; ConsoleExec("pitchlimit 88"); local CVarTemp = {}; function CVarTemp:BackUp() self.zoomLevel = GetCameraZoom(); self.dynamicPitch = tonumber(GetCVar("test_cameraDynamicPitch")); self.shoulderOffset = GetCVar("test_cameraOverShoulder"); self.cameraViewBlendStyle = GetCVar("cameraViewBlendStyle"); end function CVarTemp:BackUpDynamicCam() self.DynmicCamShoulderOffsetZoomUpperBound = DynamicCam.db.profile.shoulderOffsetZoom.lowerBound; --New DynamicCam.db.profile.shoulderOffsetZoom.lowerBound = 0; end function CVarTemp:RestoreDynamicCam() DynamicCam.db.profile.shoulderOffsetZoom.lowerBound = self.DynmicCamShoulderOffsetZoomUpperBound; end local function GetKeepActionCam() return CVarTemp.isDynamicCamLoaded or (not CVarTemp.cameraSafeMode) end CVarTemp.shoulderOffset = tonumber(GetCVar("test_cameraOverShoulder")); CVarTemp.dynamicPitch = tonumber(GetCVar("test_cameraDynamicPitch")); --No CVar directly shows the current state of ActionCam. Check this CVar for the moment. 1~On 2~Off CVarTemp.zoomLevel = 2; local ZoomFactor = {}; ZoomFactor.Time = 1.5; --1.5 outSine --ZoomFactor.Amplifier = 0.65; --0.65 ZoomFactor.toSpeedBasic = 0.004; --yawmovespeed 180 ZoomFactor.fromSpeedBasic = 1.05; --yawmovespeed 180 ZoomFactor.toSpeed = 0.005; --yawmovespeed 180 ZoomFactor.fromSpeed = 1.0; --yawmovespeed 180 outSine 1.4 ZoomFactor.SpeedFactor = 180 / tonumber(GetCVar("cameraYawMoveSpeed") or 180); ZoomFactor.Goal = 2.5; --2.5 with dynamic pitch local MOG_MODE_OFFSET = 0; local ZoomValuebyRaceID = { --[raceID] = {ZoomValue Bust, factor1, factor2, ZoomValue for XmogMode}, [0] = {[2] = {2.1, 0.361, -0.1654, 4},}, --Default Value [1] = {[2] = {2.1, 0.3283, -0.02, 4}, --1 Human √ [3] = {2.0, 0.38, 0.0311, 3.6}}, [2] = {[2] = {2.4, 0.2667, -0.1233, 5.2}, --2 Orc √ [3] = {2.1, 0.3045, -0.0483, 5}}, [3] = {[2] = {2.0, 0.2667, -0.0267, 3.6}, --3 Dwarf √ [3] = {1.8, 0.3533, -0.02, 3.6}}, [4] = {[2] = {2.1, 0.30, -0.0404, 5}, --4 NE √ [3] = {2.1, 0.329, 0.025, 4.6}}, [5] = {[2] = {2.1, 0.3537, -0.15, 4.2}, --5 UD √ [3] = {2.0, 0.3447, 0.03, 3.6}}, [6] = {[2] = {4.5, 0.2027, -0.18, 5.5}, --6 Tauren Male √ [3] = {3.0, 0.2427, -0.1867, 5.5}}, [7] = {[2] = {2.1, 0.329, 0.0517, 3.2}, --7 Gnome √ [3] = {2.1, 0.329, -0.012, 3.1}}, [8] = {[2] = {2.1, 0.2787, 0.04, 5.2}, --8 Troll √ [3] = {2.1, 0.355, -0.1317, 5}}, [9] = {[2] = {2.1, 0.2787, 0.04, 4.2}, --9 Goblin √ [3] = {2.1, 0.3144, -0.054, 4}}, [10] = {[2] = {2.1, 0.361, -0.1654, 4}, --10 BloodElf Male √ [3] = {2.1, 0.3177, 0.0683, 3.8}}, [11] = {[2] = {2.4, 0.248, -0.02, 5.5}, --11 Goat Male √ [3] = {2.1, 0.3177, 0, 5}}, [24] = {[2] = {2.5, 0.2233, -0.04, 5.2}, --24 Pandaren Male √ [3] = {2.5, 0.2433, 0.04, 5.2}}, [27] = {[2] = {2.1, 0.3067, -0.02, 5.2}, --27 Nightborne √ [3] = {2.1, 0.3347, -0.0563, 4.7}}, [28] = {[2] = {3.5, 0.2027, -0.18, 5.5}, --28 Tauren Male √ [3] = {2.3, 0.2293, 0.0067, 5.5}}, [29] = {[2] = {2.1, 0.3556, -0.1038, 4.5}, --24 VE √ [3] = {2.1, 0.3353, -0.02, 3.8}}, [31] = {[2] = {2.3, 0.2387, -0.04, 5.5}, --32 Zandalari √ [3] = {2.1, 0.2733, -0.1243, 5.5}}, [32] = {[2] = {2.3, 0.2387, 0.04, 5.2}, --32 Kul'Tiran √ [3] = {2.1, 0.312, -0.02, 4.7}}, [35] = {[2] = {2.1, 0.31, -0.03, 3.1}, --35 Vulpera √ [3] = {2.1, 0.31, -0.03, 3.1}}, ["Wolf"] = {[2] = {2.6, 0.2266, -0.02, 5}, --22 Worgen Wolf form √ [3] = {2.1, 0.2613, -0.0133, 4.7}}, ["Druid"] = {[1] = {3.71, 0.2027, -0.02, 5}, --Cat [5] = {4.8, 0.1707, -0.04, 5}, --Bear [31] = {4.61, 0.1947, -0.02, 5}, --Moonkin [4] = {4.61, 0.1307, -0.04, 5}, --Swim [27] = {4.61, 0.1067, -0.02, 5}, --Fly Swift [29] = {4.61, 0.1067, -0.02, 5}, --Fly [3] = {4.91, 0.184, -0.02, 5}, --Travel Form [36] = {4.2, 0.1707, -0.04, 5}, --Treant [2] = {5.4, 0.1707, -0.04, 5}, --Tree of Life }, ["Mounted"] = {[2] = {8, 1.2495, -4, 5.5}, [3] = {8, 1.2495, -4, 5.5}}, [52] = {[2] = {2.1, 0.361, -0.1654, 4}, --Dracthyr Visage (Male elf) [3] = {2.0, 0.38, 0.0311, 3.6}}, --Dracthyr Visage (Female human) ["Dracthyr"] = {[2] = {2.6, 0.1704, 0.0749, 5}, --Dracthyr Dragon Form [3] = {2.6, 0.1704, 0.0749, 5}}, --1 Human 32 Kultiran --2 Orc --3 Dwarf --4 Night Elf --5 Undead --6 Tauren --7 Gnome --8 Troll --9 Goblin --10 Blood Elf --11 Draenei --/run NarciScreenshotToolbar:ShowUI("Blizzard") }; local _, _, PLAYER_RACE_ID = UnitRace("player") local PLAYER_GENDER_ID = UnitSex("player") local _, _, PLAYER_CLASS_ID = UnitClass("player"); local CAM_DISTANCE_INDEX = 1; local ZOOM_IN_VALUE = ZoomValuebyRaceID[0][1]; local ZOOM_IN_VALUE_MOG = 3.8; local SHOULDER_FACTOR_1 = ZoomValuebyRaceID[0][2][2]; local SHOULDER_FACTOR_2 = ZoomValuebyRaceID[0][2][3]; local CameraMover = {}; local CameraUtil = {}; function CameraUtil:UpdateParametersDefault() local raceKey; if IsMounted() then raceKey = "Mounted"; else raceKey = self:GetRaceKey(); end ZOOM_IN_VALUE = ZoomValuebyRaceID[raceKey][PLAYER_GENDER_ID][CAM_DISTANCE_INDEX]; SHOULDER_FACTOR_1 = ZoomValuebyRaceID[raceKey][PLAYER_GENDER_ID][2]; SHOULDER_FACTOR_2 = ZoomValuebyRaceID[raceKey][PLAYER_GENDER_ID][3]; ZOOM_IN_VALUE_MOG = ZoomValuebyRaceID[raceKey][PLAYER_GENDER_ID][4]; end CameraUtil.UpdateParameters = CameraUtil.UpdateParametersDefault; function CameraUtil:GetRaceKey() return PLAYER_RACE_ID end function CameraUtil:GetRaceKey_Worgen() local raceKey; local inAlternateForm = IsPlayerInAlteredForm(); if inAlternateForm then --Human raceKey = 1; else raceKey = "Wolf"; end return raceKey end function CameraUtil:GetRaceKey_Dracthyr() local raceKey; local inAlternateForm = IsPlayerInAlteredForm(); if inAlternateForm then --Visage raceKey = 52; else raceKey = "Dracthyr"; end return raceKey end function CameraUtil:UpdateParameters_Druid() local formID = GetShapeshiftFormID(); if formID then if formID == 31 then local _, glyphID = GetCurrentGlyphNameForSpell(24858); --Moonkin form with Glyph of Stars use regular configuration if glyphID and glyphID == 114301 then self:UpdateParametersDefault(); return end end local raceKey = "Druid"; ZOOM_IN_VALUE = ZoomValuebyRaceID[raceKey][formID][CAM_DISTANCE_INDEX]; SHOULDER_FACTOR_1 = ZoomValuebyRaceID[raceKey][formID][2]; SHOULDER_FACTOR_2 = ZoomValuebyRaceID[raceKey][formID][3]; ZOOM_IN_VALUE_MOG = ZoomValuebyRaceID[raceKey][formID][4]; else self:UpdateParametersDefault(); end end do if PLAYER_RACE_ID == 25 or PLAYER_RACE_ID == 26 then --Pandaren A|H PLAYER_RACE_ID = 24; elseif PLAYER_RACE_ID == 30 then --Lightforged PLAYER_RACE_ID = 11; elseif PLAYER_RACE_ID == 36 then --Mag'har Orc PLAYER_RACE_ID = 2; elseif PLAYER_RACE_ID == 34 then --DarkIron PLAYER_RACE_ID = 3; elseif PLAYER_RACE_ID == 37 then --Mechagnome PLAYER_RACE_ID = 7; elseif PLAYER_RACE_ID == 22 then CameraUtil.GetRaceKey = CameraUtil.GetRaceKey_Worgen; elseif PLAYER_RACE_ID == 52 or PLAYER_RACE_ID == 70 then PLAYER_RACE_ID = 52; --Dracthyr Horde -> Alliance CameraUtil.GetRaceKey = CameraUtil.GetRaceKey_Dracthyr; end local _, _, playerClassID = UnitClass("player"); if playerClassID == 11 then CameraUtil.UpdateParameters = CameraUtil.UpdateParameters_Druid; table.insert(EL.EVENTS_DYNAMIC, "UPDATE_SHAPESHIFT_FORM"); end end for raceKey, data in pairs(ZoomValuebyRaceID) do local id = tonumber(raceKey); if id and id > 1 and id ~= PLAYER_RACE_ID then ZoomValuebyRaceID[raceKey] = nil; end end function CameraUtil:OnPlayerFormChanged(pauseDuration) if not self.frame then self.frame = CreateFrame("Frame"); self.frame:SetScript("OnUpdate", function(f, elapsed) f.t = f.t + elapsed; if f.t > 0 then f:Hide(); self:UpdateParameters(); CameraMover:OnCameraChanged(); end end); end if not self.pauseUpdate then --self.pauseUpdate = true; pauseDuration = pauseDuration or 0; self.frame.t = -pauseDuration; self.frame:Show(); end end local function GetShoulderOffsetByZoom(zoom) return zoom * SHOULDER_FACTOR_1 + SHOULDER_FACTOR_2 + MOG_MODE_OFFSET end local SmoothShoulder = CreateFrame("Frame"); SmoothShoulder.t = 0; SmoothShoulder.duration = 1; SmoothShoulder.zoom = 0; SmoothShoulder:Hide(); SmoothShoulder:SetScript("OnShow", function(self) self.fromPoint = GetCVar("test_cameraOverShoulder"); end); local function SmoothShoulder_OnUpdate_ToValue(self, elapsed) self.t = self.t + elapsed; local value = outSine(self.t, self.fromPoint, self.toPoint, self.duration); if self.t >= self.duration then value = self.toPoint; self:Hide(); end SetCVar("test_cameraOverShoulder", value); end local function SmoothShoulder_OnUpdate_ByZoom(self, elapsed) local zoom = GetCameraZoom(); if zoom ~= self.zoom then local value = GetShoulderOffsetByZoom(zoom); if value < 0 then value = 0; end SetCVar("test_cameraOverShoulder", value); else self:Hide(); end end SmoothShoulder:SetScript("OnHide", function(self) self.t = 0; end); local function SmoothShoulderCVar(toPoint, clampToZero) if not toPoint then return end if clampToZero then if toPoint < 0 then toPoint = 0; end end SmoothShoulder:SetScript("OnUpdate", SmoothShoulder_OnUpdate_ToValue); SmoothShoulder.t = 0; SmoothShoulder.toPoint = toPoint; SmoothShoulder.fromPoint = GetCVar("test_cameraOverShoulder"); SmoothShoulder:Show(); end local function SmoothShoulder_OnUpdate_UntilStable(self, elapsed) self.t = self.t + elapsed; if self.t >= 0.1 then local zoom = GetCameraZoom(); if zoom ~= self.zoom then self.zoom = zoom; self.t = 0; else local value = GetShoulderOffsetByZoom(zoom); if value < 0 then value = 0; end SmoothShoulderCVar(value, true); end end end local UpdateShoulderCVar = {}; UpdateShoulderCVar.steps = 0; function UpdateShoulderCVar:Start(increment) SmoothShoulder:SetScript("OnUpdate", SmoothShoulder_OnUpdate_UntilStable); SmoothShoulder.t = 0; SmoothShoulder:Show(); end local DURATION_TRANSLATION = 0.8; function Narci_LeftLineAnimFrame_OnUpdate(self, elapsed) local toX = self.toX; local t = self.TimeSinceLastUpdate + elapsed; self.TimeSinceLastUpdate = t; local offsetX = outSine(t, toX - 120, toX , DURATION_TRANSLATION); --outSine if t >= DURATION_TRANSLATION then offsetX = toX; self:Hide(); end if not self.frame then self.frame = self:GetParent(); end self.frame:SetPoint(self.anchorPoint, offsetX, 0); end function Narci_RightLineAnimFrame_OnUpdate(self, elapsed) local toX = self.toX; local t = self.TimeSinceLastUpdate + elapsed; self.TimeSinceLastUpdate = t; local offsetX = outSine(t, self.fromX, toX, DURATION_TRANSLATION); if t >= DURATION_TRANSLATION then offsetX = toX; self:Hide(); end if not self.frame then self.frame = self:GetParent(); end self.frame:SetPoint(self.anchorPoint, offsetX, 0); end --Views local ViewProfile = { isEnabled = true, }; function ViewProfile:Disable() self.isEnabled = false; --print("Dynamic Cam Enabled") end function ViewProfile:SaveView(index) if self.isEnabled then SaveView(index); end end function ViewProfile:ResetView(index) if self.isEnabled then ResetView(index); end end Narci.CameraMover = CameraMover; function CameraMover:ZoomIn(toPoint) local goal = toPoint or ZoomFactor.Goal; ZoomFactor.Current = GetCameraZoom(); if ZoomFactor.Current >= goal then CameraZoomIn(ZoomFactor.Current - goal); else CameraZoomOut(-ZoomFactor.Current + goal); end end function CameraMover:OnCameraChanged() if not self.pauseUpdate then self.pauseUpdate = true; After(0.0, function() --self:ZoomIn(ZOOM_IN_VALUE); local zoom = GetCameraZoom(); if zoom < ZOOM_IN_VALUE then self:ZoomIn(ZOOM_IN_VALUE); else CameraZoomIn(0); end self.pauseUpdate = nil; end); end end function CameraMover:SetBlend(enable) local divisor; if enable then --Smooth DURATION_TRANSLATION = 0.8; divisor = 20; else --Instant DURATION_TRANSLATION = 0.4; divisor = 80; end for k, slot in pairs(STAT_STABLE) do local delay = (slot:GetID())/divisor; if slot.animIn then slot.animIn.A2:SetStartDelay(delay); end end for k, slot in pairs(SHORT_STAT_TABLE) do local delay = (slot:GetID())/divisor; slot.animIn.A2:SetStartDelay(delay); end RadarChart.animIn.A2:SetStartDelay(9/divisor); self.blend = enable; end CameraMover.smoothYaw = NarciAPI_CreateAnimationFrame(1.5); CameraMover.smoothYaw.MoveView = MoveViewRightStart; CameraMover.smoothYaw:SetScript("OnUpdate", function(frame, elapsed) frame.total = frame.total + elapsed; local factor = ZoomFactor; local speed = inOutSine(frame.total, factor.fromSpeed, factor.toSpeed, 1.5); --inOutSine frame.MoveView(speed); if frame.total >= 1.5 then if not IsPlayerMoving() then frame.MoveView(factor.toSpeed); else MoveViewRightStop(); end frame:Hide(); end end); CameraMover.smoothPitch = NarciAPI_CreateAnimationFrame(1.5); CameraMover.smoothPitch:SetScript("OnUpdate", function(frame, elapsed) frame.total = frame.total + elapsed --local x = frame.total; --local EndDistance = ZoomFactor.Goal; local PL = tostring(outSine(frame.total, 88, 1, frame.duration)); --outSine ConsoleExec( "pitchlimit "..PL) if frame.total >= frame.duration then ConsoleExec( "pitchlimit 1"); After(0, function() ConsoleExec( "pitchlimit 88"); end) frame:Hide(); end end); function CameraMover:InstantZoomIn() SetCVar("cameraViewBlendStyle", 2); SetView(4); ConsoleExec( "pitchlimit 1"); After(0, function() ConsoleExec( "pitchlimit 88"); end) local zoom = ZOOM_IN_VALUE or GetCameraZoom(); local shoulderOffset = GetShoulderOffsetByZoom(zoom); SetCVar("test_cameraOverShoulder", shoulderOffset); --CameraZoomIn(0.0) --Smooth self:ZoomIn(ZOOM_IN_VALUE); self:ShowFrame(); SetUIVisibility(false); if not IsPlayerMoving() and NarcissusDB.CameraOrbit then MoveViewRightStart(ZoomFactor.toSpeed); end end function CameraMover:HideUI() if UIParent:IsShown() then UIPA.endAlpha = 0; UIPA:Show(); end After(0.5, function() SetUIVisibility(false); --Same as pressing Alt + Z After(0.3, function() UIParent:SetAlpha(1); end) end) end function CameraMover:Enter() SetCVar("test_cameraDynamicPitch", 1); if self.blend then if NarcissusDB.CameraOrbit and not IsPlayerMoving() then if NarcissusDB.CameraOrbit then self.smoothYaw:Show(); end SetView(2); end if not IsFlying("player") then self.smoothPitch:Show(); end After(0.1, function() self:ZoomIn(ZOOM_IN_VALUE); After(0.7, function() self:ShowFrame(); end) end) self:HideUI(); else if not self.hasInitialized then if NarcissusDB.CameraOrbit then self.smoothYaw:Show(); end SetView(2); self.smoothPitch:Show(); After(0.1, function() self:ZoomIn(ZOOM_IN_VALUE); After(0.7, function() self:ShowFrame(); end) end) After(1, function() if not IsMounted() then self.hasInitialized = true; SaveView(1); end end) self:HideUI(); else self:InstantZoomIn(); end end end function CameraMover:Pitch() self.smoothPitch:Show(); end function CameraMover:MakeActive() --Reserved for DynamicCam users end function CameraMover:MakeInactive() --Reserved for DynamicCam users end function CameraMover:UpdateMovementMethodForDynamicCam() if not self.handler then self.handler = CreateFrame("Frame"); end local f = self.handler; f:Hide(); f.t = 0; f:SetScript("OnUpdate", function(_, elapsed) f.t = f.t + elapsed; if f.t >= 0.2 then f.currentZoom = GetCameraZoom(); if f.currentZoom ~= f.lastZoom then f.lastZoom = f.currentZoom; UpdateShoulderCVar:Start(); end end end); function self:MakeActive() f.lastZoom = -1; f:Show(); end function self:MakeInactive() f:Hide(); end end ------------------------------ ------------------------------ local function ExitFunc() IS_OPENED = false; MOG_MODE_OFFSET = 0; EL:Hide(); CameraMover:MakeInactive(); MoveViewRightStop(); if not GetKeepActionCam() then --(not CVarTemp.isDynamicCamLoaded and CVarTemp.dynamicPitch == 0) or not Narci.keepActionCam SetCVar("test_cameraDynamicPitch", 0); --Note: "test_cameraDynamicPitch" may cause camera to jitter while reseting the player's view SmoothShoulderCVar(0); After(1, function() ConsoleExec( "actioncam off" ); MoveViewRightStop(); end) else --Restore the acioncam state SmoothShoulderCVar(CVarTemp.shoulderOffset); SetCVar("test_cameraDynamicPitch", CVarTemp.dynamicPitch); After(1, function() MoveViewRightStop(); end) end ConsoleExec("pitchlimit 88"); FadeFrame(Narci_Vignette, 0.5, 0); if Narci_Attribute:IsVisible() then Narci_Attribute.animOut:Play(); end UIParent:SetAlpha(0); After(0.1, function() UIPA.startAlpha = 0; UIPA.endAlpha = 1; UIPA:Show(); SetUIVisibility(true); --UIFrameFadeIn(UIParent, 0.5, 0, 1); --cause frame rate drop Minimap:Show(); local cameraSmoothStyle = GetCVar("cameraSmoothStyle"); if tonumber(cameraSmoothStyle) == 0 and ViewProfile.isEnabled then --workaround for auto-following SetView(5); else SetView(2); CameraMover:ZoomIn(CVarTemp.zoomLevel); end SetCVar("cameraViewBlendStyle", CVarTemp.cameraViewBlendStyle); end); Narci.isActive = false; Narci.isAFK = false; DefaultTooltip:HideTooltip(); MsgAlertContainer:Hide(); UIErrorsFrame:Clear(); Narci_ModelContainer:HideAndClearModel(); Narci_ModelSettings:Hide(); Narci_XmogNameFrame:Hide(); NarciSettingsFrame:CloseUI(); MOG_MODE = false; end --[[ local function SetDate() local CalendarTime = C_Calendar.GetDate(); local hour = CalendarTime.hour; local minute = CalendarTime.minute; if minute < 10 then minute = "0"..tostring(minute) end Narci_Vignette.Time:SetText(hour..":"..minute) local zoneText = GetMinimapZoneText() Narci_Vignette.Location:SetText(zoneText) end --]] function Narci:EmergencyStop() print("Camera has been reset."); UIParent:SetAlpha(1); MoveViewRightStop(); MoveViewLeftStop(); ViewProfile:ResetView(5); ConsoleExec( "pitchlimit 88"); CVarTemp.shoulderOffset = 0; SetCVar("test_cameraOverShoulder", 0); SetCVar("cameraViewBlendStyle", 1); ConsoleExec( "actioncam off" ); CameraMover:MakeInactive(); Narci_ModelContainer:HideAndClearModel(); Narci_ModelSettings:Hide(); Narci_Character:Hide(); Narci_Attribute:Hide(); Narci_Vignette:Hide(); IS_OPENED = false; MOG_MODE_OFFSET = 0; EL:Hide(); end ---------------End of derivation--------------- ---Get Transmog Appearance--- --[[ ==sourceInfo== sourceType TRANSMOG_SOURCE_1 = "Boss Drop"; invType TRANSMOG_SOURCE_2 = "Quest"; visualID TRANSMOG_SOURCE_3 = "Vendor"; isCollected TRANSMOG_SOURCE_4 = "World Drop"; sourceID TRANSMOG_SOURCE_5 = "Achievement"; isHideVisual TRANSMOG_SOURCE_6 = "Profession"; itemID itemModID Normal 0, Heroic 1, Mythic 3, LFG 4 categoryID name quality --]] local xmogTable = { {1, INVTYPE_HEAD}, {3, INVTYPE_SHOULDER}, {15, INVTYPE_CLOAK}, {5, INVTYPE_CHEST}, {4, INVTYPE_BODY}, {19, INVTYPE_TABARD}, {9, INVTYPE_WRIST}, --Left **slotID for TABARD is 19 {10, INVTYPE_HAND}, {6, INVTYPE_WAIST}, {7, INVTYPE_LEGS}, {8, INVTYPE_FEET}, --Right {16, INVTYPE_WEAPONMAINHAND}, {17, INVTYPE_WEAPONOFFHAND}, --Weapon }; --[[ local function ShareHyperLink() --Send transmog hyperlink to chat local delay = 0; --Keep message in order print(MYMOG_GRADIENT) for i=1, #xmogTable do local index = xmogTable[i][1] if SLOT_TABLE[index] and SLOT_TABLE[index].hyperlink then After(delay, function() SendChatMessage(xmogTable[i][2]..": "..SLOT_TABLE[index].hyperlink, "GUILD") end) delay = delay + 0.1; end end end --]] local GetInventoryItemCooldown = GetInventoryItemCooldown; local function SetItemSocketingFramePosition(self) --Let ItemSocketingFrame appear on the side of the slot if ItemSocketingFrame then if self.GemSlot:IsShown() then ItemSocketingFrame:Show() else ItemSocketingFrame:Hide() return; end ItemSocketingFrame:ClearAllPoints(); if self.isRight then ItemSocketingFrame:SetPoint("TOPRIGHT", self, "TOPLEFT", 4, 0); else ItemSocketingFrame:SetPoint("TOPLEFT", self, "TOPRIGHT", -4, 0); end DefaultTooltip:HideTooltip(); end end local IsItemEnchantable = { [11] = true, [12] = true, [16] = true, [17] = true, [5] = true, [8] = true, [9] = true, [10] = true, [15] = true, }; local function DisplayRuneSlot(equipmentSlot, slotID, itemQuality, itemLink) --! RuneSlot.Background is disabled if not equipmentSlot.RuneSlot then return; elseif (itemQuality == 0) or (not itemLink) then equipmentSlot.RuneSlot:Hide(); return; end if IsItemEnchantable[slotID] then equipmentSlot.RuneSlot:Show(); else equipmentSlot.RuneSlot:Hide(); return; end local enchantID = GetItemEnchantID(itemLink); if enchantID ~= 0 then equipmentSlot.RuneSlot.RuneLetter:Show(); if EnchantInfo[enchantID] then equipmentSlot.RuneSlot.RuneLetter:SetText( GetVerticalRunicLetters( EnchantInfo[enchantID][1] ) ); equipmentSlot.RuneSlot.spellID = EnchantInfo[enchantID][3] end else equipmentSlot.RuneSlot.spellID = nil; equipmentSlot.RuneSlot.RuneLetter:Hide(); end end function Narci_RuneButton_OnEnter(self) local spellID = self.spellID; if (not spellID) then return; end DefaultTooltip:SetOwner(self, "ANCHOR_NONE"); if self:GetParent().isRight then DefaultTooltip:SetPoint("TOPRIGHT", self, "TOPLEFT", 8, 8); else DefaultTooltip:SetPoint("TOPLEFT", self, "TOPRIGHT", 0, 8); end DefaultTooltip:SetSpellByID(spellID); DefaultTooltip:Show(); DefaultTooltip:FadeIn(); end --------------------------------------------------- local USE_DELAY = true; local function AssignDelay(id, forced) if USE_DELAY or forced then local time = 0; if id == 1 then time = 1; elseif id == 2 then time = 2; elseif id == 3 then time = 3; elseif id == 15 then --back time = 4; elseif id == 5 then time = 5; elseif id == 9 then time = 6; elseif id == 16 then time = 7; elseif id == 17 then time = 8; elseif id == 4 then --shirt time = 9; elseif id == 10 then time = 10; elseif id == 6 then time = 11; elseif id == 7 then time = 12; elseif id == 8 then time = 13; elseif id == 11 then time = 14; elseif id == 12 then time = 15; elseif id == 13 then time = 16; elseif id == 14 then time = 17; elseif id == 19 then time = 18; end time = time/20; return time; else return 0; end; end local function GetTraitsIcon(itemLocation) if not itemLocation then return; end local TierInfos = C_AzeriteEmpoweredItem.GetAllTierInfo(itemLocation); if not TierInfos then return; end local powerIDs, icon, _; local isRightSpec = true; local traitIcons = {}; local specIndex = GetSpecialization() or 1; local specID = GetSpecializationInfo(specIndex); local MAX_TIERS = 5; for i = 1, MAX_TIERS do if (not TierInfos[i]) or (not TierInfos[i].azeritePowerIDs) then return traitIcons; end powerIDs = TierInfos[i].azeritePowerIDs; for k, powerID in pairs(powerIDs) do if C_AzeriteEmpoweredItem.IsPowerSelected(itemLocation, powerID) then local PowerInfo = C_AzeriteEmpoweredItem.GetPowerInfo(powerID) isRightSpec = isRightSpec and C_AzeriteEmpoweredItem.IsPowerAvailableForSpec(powerID, specID); _, _, icon = GetSpellInfo(PowerInfo and PowerInfo.spellID); traitIcons[i] = icon; break; else traitIcons[i] = ""; end end end return traitIcons, isRightSpec; end local function GetRuneForgeLegoIcon(itemLocation) local componentInfo = C_LegendaryCrafting.GetRuneforgeLegendaryComponentInfo(itemLocation); if componentInfo and componentInfo.powerID then local powerInfo = C_LegendaryCrafting.GetRuneforgePowerInfo(componentInfo.powerID); return powerInfo and powerInfo.iconFileID end end local GetSlotVisualID = NarciAPI.GetSlotVisualID; local GetGemBorderTexture = NarciAPI.GetGemBorderTexture; local GetItemQualityColor = NarciAPI.GetItemQualityColor; local QueueFrame = NarciAPI.CreateProcessor(nil, 0.5); ----------------------------------------------------------------------- NarciItemButtonSharedMixin = {}; function NarciItemButtonSharedMixin:RegisterErrorEvent() self:RegisterEvent("UI_ERROR_MESSAGE"); end function NarciItemButtonSharedMixin:UnregisterErrorEvent() self:UnregisterEvent("UI_ERROR_MESSAGE"); end function NarciItemButtonSharedMixin:OnErrorMessage(...) self:UnregisterErrorEvent(); local _, msg = ... Narci_AlertFrame_Autohide:AddMessage(msg, true); end function NarciItemButtonSharedMixin:AnchorAlertFrame() self:RegisterErrorEvent(); Narci_AlertFrame_Autohide:SetAnchor(self, -12, true); end function NarciItemButtonSharedMixin:PlayGamePadAnimation() if self.gamepad then self.Icon.ScaleUp:Play(); self.IconMask.ScaleUp:Play(); self.Border.ScaleUp:Play(); self.Border.BorderMask.ScaleUp:Play(); end end function NarciItemButtonSharedMixin:ResetAnimation() if self.gamepad then self.Icon.ScaleUp:Stop(); self.Border.ScaleUp:Stop(); self.Border.BorderMask.ScaleUp:Stop(); self.IconMask.ScaleUp:Stop(); self.Icon:SetScale(1); self.Border:SetScale(1); self.IconMask:SetScale(1); self.Border.BorderMask:SetScale(1); if self.gamepadOverlay then self.gamepadOverlay:Hide(); self.gamepadOverlay = nil; end end end function NarciItemButtonSharedMixin:SetBorderTexture(border, texKey) SetBorderTexture(border, texKey, 2); end function NarciItemButtonSharedMixin:ShowAlphaChannel() self.Icon:SetColorTexture(1, 1, 1); self.Border:SetColorTexture(1, 1, 1); self.Border.textureKey = -1; end ----------------------------------------------------------------------- local ValidForTempEnchant = { [16] = true, [17] = true, [5] = true, }; local function GetFormattedSourceText(sourceInfo) local sourceType = sourceInfo.sourceType; local itemQuality = sourceInfo.quality or 1; local hex = NarciAPI.GetItemQualityHexColor(itemQuality); local difficulty; local bonusID; local colorizedText, plainText, hyperlink; if sourceType == 1 then --TRANSMOG_SOURCE_BOSS_DROP = 1 local drops = C_TransmogCollection.GetAppearanceSourceDrops(sourceInfo.sourceID); if drops and drops[1] then colorizedText = drops[1].encounter.." ".."|cFFFFD100"..drops[1].instance.."|r"; plainText = drops[1].encounter.." "..drops[1].instance; if sourceInfo.itemModID == 0 then difficulty = PLAYER_DIFFICULTY1; bonusID = 3561; hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."1"..":1476:|h|r"; elseif sourceInfo.itemModID == 1 then difficulty = PLAYER_DIFFICULTY2; bonusID = 3562; hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."2"..":1476:|h|r"; elseif sourceInfo.itemModID == 3 then difficulty = PLAYER_DIFFICULTY6; bonusID = 3563; hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."3"..":1476:|h|r"; elseif sourceInfo.itemModID == 4 then difficulty = PLAYER_DIFFICULTY3; bonusID = 3564; hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."4"..":1476:|h|r"; end if difficulty then colorizedText = colorizedText.." |CFFf8e694"..difficulty.."|r"; plainText = plainText.." "..difficulty; end else local sourceText = _G["TRANSMOG_SOURCE_1"]; --Boss Drop colorizedText = sourceText; plainText = sourceText; end else if sourceType == 2 then --quest colorizedText = TRANSMOG_SOURCE_2; if sourceInfo.itemModID == 3 then hyperlink= "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:512".."6"..":1562:|h|r"; bonusID = 5126; elseif sourceInfo.itemModID == 2 then hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:512".."5"..":1562:|h|r"; bonusID = 5125; elseif sourceInfo.itemModID == 1 then hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:512".."4"..":1562:|h|r"; bonusID = 5124; end elseif sourceType == 3 then --vendor colorizedText = TRANSMOG_SOURCE_3; elseif sourceType == 4 then --world drop colorizedText = TRANSMOG_SOURCE_4; elseif sourceType == 5 then --achievement colorizedText = TRANSMOG_SOURCE_5; elseif sourceType == 6 then --profession colorizedText = TRANSMOG_SOURCE_6; else if itemQuality == 6 then colorizedText = ITEM_QUALITY6_DESC; elseif itemQuality == 5 then colorizedText = ITEM_QUALITY5_DESC; end end plainText = colorizedText; end if not hyperlink then hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID..":|h|r"; end return colorizedText, plainText, hyperlink; end NarciEquipmentSlotMixin = CreateFromMixins{NarciItemButtonSharedMixin}; function NarciEquipmentSlotMixin:SetTransmogSourceID(appliedSourceID, secondarySourceID) self.sourceID = appliedSourceID; if appliedSourceID and appliedSourceID > 0 then self.Icon:SetDesaturated(false); self.Name:Show(); self.ItemLevel:Show(); self.GradientBackground:Show(); else self.Icon:SetDesaturated(true); self.Name:SetText(nil); self.ItemLevel:SetText(nil); self.GradientBackground:Hide(); self:SetBorderTexture(self.Border, 0); if self.slotID == 2 then self:DisplayDirectionMark(false); end return end local itemName, itemIcon, itemQuality, subText; local sourceInfo = C_TransmogCollection.GetSourceInfo(appliedSourceID); itemName = sourceInfo and sourceInfo.name; if not itemName or itemName == "" then QueueFrame:Add(self, self.Refresh); return end self.itemID = sourceInfo.itemID; self.itemModID = sourceInfo.itemModID; itemQuality = sourceInfo.quality or 1; itemIcon = C_TransmogCollection.GetSourceIcon(appliedSourceID); subText = TransmogDataProvider:GetSpecialItemSourceText(appliedSourceID, self.itemID, self.itemModID); if subText then self.sourcePlainText = NarciAPI.RemoveColorString(subText); _, _, self.hyperlink = GetFormattedSourceText(sourceInfo); else subText, self.sourcePlainText, self.hyperlink = GetFormattedSourceText(sourceInfo); end if self.hyperlink then _, self.hyperlink = GetItemInfo(self.hyperlink); --original hyperlink cannot be printed (workaround) end local bonusID; if itemQuality == 6 then if self.slotID == 16 then bonusID = (sourceInfo.itemModID or 0); --Artifact use itemModID "7V0" + modID - 1 else bonusID = 0; end end self.bonusID = bonusID; local bR, bG, bB = GetItemQualityColor(itemQuality); local borderTexKey = itemQuality; self:SetBorderTexture(self.Border, borderTexKey); if self:IsVisible() then if itemIcon then self.IconOverlay:SetTexture(itemIcon); self.Icon.anim:Play(); end self.ItemLevel.anim1:SetScript("OnFinished", function(f) self.ItemLevel:SetText(subText); self.ItemLevel.anim2:Play(); f:SetScript("OnFinished", nil); end) self.Name.anim1:SetScript("OnFinished", function(f) self.Name:SetText(itemName); self.Name:SetTextColor(bR, bG, bB); self.Name.anim2:Play(); f:SetScript("OnFinished", nil); After(0, function() self:UpdateGradientSize(); end) end) self.ItemLevel.anim1:Play(); self.Name.anim1:Play(); else self.ItemLevel:SetText(subText); self.Name:SetText(itemName); self.Name:SetTextColor(bR, bG, bB); if itemIcon then self.Icon:SetTexture(itemIcon); end self:UpdateGradientSize(); end if self.slotID == 3 then --shoulder if secondarySourceID and secondarySourceID > 0 then self:DisplayDirectionMark(true, itemQuality); SLOT_TABLE[2]:SetTransmogSourceID(secondarySourceID, secondarySourceID); else self:DisplayDirectionMark(false); end elseif self.slotID == 2 then self:DisplayDirectionMark(appliedSourceID, itemQuality); end end function NarciEquipmentSlotMixin:Refresh(forceRefresh) local _; local slotID = self.slotID; local itemLocation = ItemLocation:CreateFromEquipmentSlot(slotID); --print(slotName..slotID) --local texture = CharacterHeadSlot.popoutButton.icon:GetTexture() local itemLink; local itemIcon, itemName, itemQuality, effectiveLvl, gemName, gemLink, gemID; local borderTexKey; local isAzeriteEmpoweredItem = false; --3 Pieces **likely to be changed in patch 8.2 local isAzeriteItem = false; --Heart of Azeroth --local isCorruptedItem = false; local bR, bG, bB; --Item Name Color if C_Item.DoesItemExist(itemLocation) then if MOG_MODE then self:UntrackCooldown(); self:UntrackTempEnchant(); self:ClearOverlay(); self:HideVFX(); self.itemLink = nil; self.isSlotHidden = false; --Undress an item from player model self.RuneSlot:Hide(); self.GradientBackground:Show(); local appliedSourceID, appliedVisualID, hasSecondaryAppearance = GetSlotVisualID(slotID); self.sourceID = appliedSourceID; if appliedVisualID > 0 then local sourceInfo = C_TransmogCollection.GetSourceInfo(appliedSourceID); itemName = sourceInfo and sourceInfo.name; if not itemName or itemName == "" then QueueFrame:Add(self, self.Refresh); return end self.itemID = sourceInfo.itemID; itemQuality = sourceInfo.quality; self.itemModID = sourceInfo.itemModID; itemIcon = C_TransmogCollection.GetSourceIcon(appliedSourceID); effectiveLvl = TransmogDataProvider:GetSpecialItemSourceText(appliedSourceID, self.itemID, self.itemModID); if effectiveLvl then self.sourcePlainText = NarciAPI.RemoveColorString(effectiveLvl); _, _, self.hyperlink = GetFormattedSourceText(sourceInfo); else effectiveLvl, self.sourcePlainText, self.hyperlink = GetFormattedSourceText(sourceInfo); end if self.hyperlink then _, self.hyperlink = GetItemInfo(self.hyperlink); --original hyperlink cannot be printed (workaround) end local bonusID; if itemQuality == 6 then if slotID == 16 then bonusID = (sourceInfo.itemModID or 0); --Artifact use itemModID "7V0" + modID - 1 else bonusID = 0; end end self.bonusID = bonusID; if effectiveLvl == nil then effectiveLvl = TransmogDataProvider:GetSpecialItemSourceText(appliedSourceID, self.itemID, self.itemModID) or " "; end else --irrelevant slot itemName = " "; itemQuality = 0; itemIcon = GetInventoryItemTexture("player", slotID); self.Icon:SetDesaturated(true); self.Name:Hide(); self.ItemLevel:Hide(); self.GradientBackground:Hide(); self.bonusID = nil; end self:DisplayDirectionMark(hasSecondaryAppearance, itemQuality); else self:TrackCooldown(); self:DisplayDirectionMark(false); self.Icon:SetDesaturated(false) self.Name:Show(); self.ItemLevel:Show(); self.GradientBackground:Show(); self.sourceID = nil; self.hyperlink = nil; self.sourcePlainText = nil; --[[ local current, maximum = GetInventoryItemDurability(slotID); if current and maximum then self.durability = (current / maximum); end --]] itemLink = C_Item.GetItemLink(itemLocation); if ValidForTempEnchant[slotID] then local hasTempEnchant = NarciTempEnchantIndicatorController:InitFromSlotButton(self); if hasTempEnchant ~= self.hasTempEnchant then self.hasTempEnchant = hasTempEnchant; else if itemLink == self.itemLink then return end end else if itemLink == self.itemLink then return end end self.itemLink = itemLink; local itemVFX, hideItemIcon; local itemID = GetItemInfoInstant(itemLink); borderTexKey, itemVFX, bR, bG, bB, hideItemIcon = GetBorderArtByItemID(itemID); itemIcon = ((not hideItemIcon) and GetInventoryItemTexture("player", slotID)) or nil; itemName = C_Item.GetItemName(itemLocation); itemQuality = C_Item.GetItemQuality(itemLocation); effectiveLvl = C_Item.GetCurrentItemLevel(itemLocation); self.ItemLevelCenter.ItemLevel:SetText(effectiveLvl); --Debug --if effectiveLvl and effectiveLvl > 1 then -- NarciDebug:CalculateAverage(effectiveLvl); --end if not hideItemIcon then if slotID == 13 or slotID == 14 then if itemID == 167555 then --Pocket-Sized Computation Device gemName, gemLink = IsItemSocketable(itemLink, 2); else gemName, gemLink = IsItemSocketable(itemLink); end else gemName, gemLink = IsItemSocketable(itemLink); end end self.GemSlot.ItemLevel = effectiveLvl; self.gemLink = gemLink; --Later used in OnEnter func in NarciSocketing.lua if slotID == 2 then isAzeriteItem = C_AzeriteItem.IsAzeriteItem(itemLocation); self.isAzeriteItem = isAzeriteItem; if isAzeriteItem then itemVFX = "Heart"; end elseif slotID == 1 or slotID == 3 or slotID == 5 then isAzeriteEmpoweredItem = C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItem(itemLocation); else --isCorruptedItem = IsCorruptedItem(itemLink); end if slotID == 15 then --Backslot if itemID == 169223 then --Ashjra'kamas, Shroud of Resolve Legendary Cloak local rank, corruptionResistance = NarciAPI.GetItemRankText(itemLink, "ITEM_MOD_CORRUPTION_RESISTANCE"); effectiveLvl = effectiveLvl.." "..rank.." |cFFFFD100"..corruptionResistance.."|r"; borderTexKey = "BlackDragon"; itemVFX = "DragonFire"; end end if slotID ~= 13 and slotID ~= 14 then local isRuneforgeLegendary = C_LegendaryCrafting.IsRuneforgeLegendary(itemLocation); if isRuneforgeLegendary then itemVFX = "Runeforge"; borderTexKey = "Runeforge"; itemIcon = GetRuneForgeLegoIcon(itemLocation) or itemIcon; end end local enchantText, isEnchanted = GetItemEnchantText(itemLink, true, self.isRight); --enchantText (effect texts) may not be available yet if enchantText then if self.isRight then effectiveLvl = enchantText.." "..effectiveLvl; else effectiveLvl = effectiveLvl.." "..enchantText; end self:ClearOverlay(); elseif not isEnchanted then if SHOW_MISSING_ENCHANT_ALERT and SlotButtonOverlayUtil:IsSlotValidForEnchant(slotID, itemID) then SlotButtonOverlayUtil:ShowEnchantAlert(self, slotID, itemID); if self.isRight then effectiveLvl = effectiveLvl .. " ".. L["Missing Enchant"]; else effectiveLvl = L["Missing Enchant"].." "..effectiveLvl; end end end --Enchant Frame-- if itemQuality then --and not isRuneforgeLegendary DisplayRuneSlot(self, slotID, itemQuality, itemLink); end --Item Visual Effects if itemVFX then self:ShowVFX(itemVFX); else self:HideVFX(); end end if not itemName or itemName == "" then QueueFrame:Add(self, self.Refresh); return end else self:UntrackCooldown(); self:UntrackTempEnchant(); self:ClearOverlay(); self:HideVFX(); self:DisplayDirectionMark(false); self.GradientBackground:Hide(); self.Icon:SetDesaturated(false); self.ItemLevelCenter.ItemLevel:SetText(""); self.itemID = nil; self.bonusID = nil; self.itemLink = nil; self.gemLink = nil; itemQuality = 0; itemIcon = self.emptyTexture; itemName = " " ; effectiveLvl = ""; DisplayRuneSlot(self, slotID, 0); end self.itemQuality = itemQuality; if itemQuality and not bR then --itemQuality sometimes return nil. This is a temporary solution bR, bG, bB = GetItemQualityColor(itemQuality); if not borderTexKey then borderTexKey = itemQuality; end end bR = bR or 1; bG = bG or 1; bB = bB or 1; if isAzeriteEmpoweredItem then borderTexKey = "Azerite"; if not MOG_MODE then local icons, isRightSpec = GetTraitsIcon(itemLocation); for i = 1, #icons do effectiveLvl = effectiveLvl.." |T"..icons[i]..":12:12:0:0:64:64:4:60:4:60|t"; end end end if isAzeriteItem then local heartLevel = C_AzeriteItem.GetPowerLevel(itemLocation); local xp_Current, xp_Needed = C_AzeriteItem.GetAzeriteItemXPInfo(itemLocation); local GetEssenceInfo = C_AzeriteEssence.GetEssenceInfo; local GetMilestoneEssence = C_AzeriteEssence.GetMilestoneEssence; if not C_AzeriteItem.IsAzeriteItemAtMaxLevel() then heartLevel = heartLevel .. " |CFFf8e694" .. floor((xp_Current/xp_Needed)*100 + 0.5) .. "%"; end effectiveLvl = effectiveLvl.." |cFFFFD100"..heartLevel; local EssenceID = GetMilestoneEssence(115); if EssenceID then borderTexKey = "Heart"; local EssenceInfo = GetEssenceInfo(EssenceID); bR, bG, bB = GetItemQualityColor(EssenceInfo.rank + 1); itemName = EssenceInfo.name; itemIcon = EssenceInfo.icon; end for i = 116, 119 do --116, 117, 119 3 minor slots if i ~= 118 then EssenceID = GetMilestoneEssence(i); if EssenceID then local icon = GetEssenceInfo(EssenceID).icon; effectiveLvl = effectiveLvl.." |T"..icon..":12:12:0:0:64:64:4:60:4:60|t"; end end end end --[[ if isCorruptedItem then borderTexKey = "NZoth"; if not MOG_MODE then local corruption = GetItemStats(itemLink)["ITEM_MOD_CORRUPTION"]; if corruption then local Affix = GetCorruptedItemAffix(itemLink); if Affix then if self.isRight then effectiveLvl = Affix.." |cff946dd1"..corruption.."|r "..effectiveLvl; else effectiveLvl = effectiveLvl.." "..Affix.." |cff946dd1"..corruption.."|r"; end else if self.isRight then effectiveLvl = "|cff946dd1"..corruption.."|r "..effectiveLvl; else effectiveLvl = effectiveLvl.." |cff946dd1"..corruption.."|r"; end end end itemQuality = "NZoth"; end end --]] --Gem Slot-- if gemName ~= nil then local gemBorder, gemIcon, itemSubClassID; --regular gems if gemLink then gemID, _, _, _, gemIcon, _, itemSubClassID = GetItemInfoInstant(gemLink); gemBorder = GetGemBorderTexture(itemSubClassID, gemID); else gemBorder = GetGemBorderTexture(nil); end self.GemSlot.GemBorder:SetTexture(gemBorder); self.GemSlot.GemIcon:SetTexture(gemIcon); self.GemSlot.GemIcon:Show(); self.GemSlot.sockedGemItemID = gemID; if self:IsVisible() then self.GemSlot:FadeIn(); else self.GemSlot:ShowSlot(); end else if self:IsVisible() then self.GemSlot:FadeOut(); else self.GemSlot:HideSlot(); end self.GemSlot.sockedGemItemID = nil; end --if slotID == 13 then itemName = "The Lion\'s Roar"; end --Antumbra, Shadow of the Cosmos -------------------------------------------------- if self:IsVisible() then self:SetBorderTexture(self.Border, borderTexKey); if itemIcon then self.IconOverlay:SetTexture(itemIcon); self.Icon.anim:Play(); end self.ItemLevel.anim1:SetScript("OnFinished", function(f) self.ItemLevel:SetText(effectiveLvl); self.ItemLevel.anim2:Play(); f:SetScript("OnFinished", nil); end) self.Name.anim1:SetScript("OnFinished", function(f) self.Name:SetText(itemName); self.Name:SetTextColor(bR, bG, bB); self.Name.anim2:Play(); f:SetScript("OnFinished", nil); After(0, function() self:UpdateGradientSize(); end) end) self.ItemLevel.anim1:Play(); self.Name.anim1:Play(); else self.ItemLevel:SetText(effectiveLvl); self.Name:SetText(itemName); self.Name:SetTextColor(bR, bG, bB); self:SetBorderTexture(self.Border, borderTexKey); if itemIcon then self.Icon:SetTexture(itemIcon); end self:UpdateGradientSize(); end --self.GradientBackground:SetHeight(self.Name:GetHeight() + self.ItemLevel:GetHeight() + 18); self.itemNameColor = {bR, bG, bB}; return true end function NarciEquipmentSlotMixin:UpdateGradientSize() local text2Width = self.ItemLevel:GetWrappedWidth(); local extraWidth; if self.TempEnchantIndicator then extraWidth = 48; self.TempEnchantIndicator:ClearAllPoints(); if self.isRight then self.TempEnchantIndicator:SetPoint("TOPRIGHT", self.ItemLevel, "TOPRIGHT", -text2Width - 6, 0); else local extraOffset; if self.ItemLevel:IsTruncated() then text2Width = self.ItemLevel:GetWidth(); end self.TempEnchantIndicator:SetPoint("TOPLEFT", self.ItemLevel, "TOPLEFT", text2Width + 6, 0); end else extraWidth = 0; end self.GradientBackground:SetHeight(self.Name:GetHeight() + self.ItemLevel:GetHeight() + 18); self.GradientBackground:SetWidth(max(self.Name:GetWrappedWidth(), text2Width + extraWidth, 48) + 48); end function NarciEquipmentSlotMixin:OnLoad() local slotName = self.slotName; local slotID, textureName = GetInventorySlotInfo(slotName); self.emptyTexture = textureName; self:SetID(slotID); self.slotID = slotID; self:SetAttribute("type2", "item"); self:SetAttribute("item", slotID); self:RegisterForDrag("LeftButton"); self:RegisterForClicks("LeftButtonUp", "RightButtonDown", "RightButtonUp"); if self:GetParent() then if not self:GetParent().slotTable then self:GetParent().slotTable = {} end tinsert(self:GetParent().slotTable, self); end SLOT_TABLE[slotID] = self; self:SetScript("OnLoad", nil); self.OnLoad = nil; end function NarciEquipmentSlotMixin:OnEvent(event, ...) if event == "MODIFIER_STATE_CHANGED" then local key, state = ...; if ( key == "LALT" and self:IsMouseOver() ) then local flyout = EquipmentFlyoutFrame; if state == 1 then if flyout:IsShown() and flyout.slotID == self:GetID() then flyout:Hide(); else flyout:SetItemSlot(self, true); end else if not MOG_MODE then ItemTooltip:SetFromSlotButton(self, -2, 6); end end end elseif event == "UI_ERROR_MESSAGE" then self:OnErrorMessage(...); end end function NarciEquipmentSlotMixin:UntrackCooldown() if self.CooldownFrame then self.CooldownFrame:Clear(); self.CooldownFrame = nil; end end function NarciEquipmentSlotMixin:ClearOverlay() if SHOW_MISSING_ENCHANT_ALERT and self.slotOverlay then SlotButtonOverlayUtil:ClearOverlay(self); self.slotOverlay = nil; end end function NarciEquipmentSlotMixin:TrackCooldown() local start, duration, enable = GetInventoryItemCooldown("player", self:GetID()); if enable and enable ~= 0 and start > 0 and duration > 0 then if not self.CooldownFrame then self.CooldownFrame = NarciItemCooldownUtil.AccquireFrame(self); end self.CooldownFrame:SetCooldown(start, duration); return true else self:UntrackCooldown(); end return false end function NarciEquipmentSlotMixin:UntrackTempEnchant() if self.TempEnchantIndicator then self.TempEnchantIndicator:Hide(); self.TempEnchantIndicator = nil; end end function NarciEquipmentSlotMixin:OnEnter(motion, isGamepad) self:RegisterEvent("MODIFIER_STATE_CHANGED"); if isGamepad then self:PlayGamePadAnimation(); else FadeFrame(self.Highlight, 0.15, 1); end if IsAltKeyDown() and not MOG_MODE then EquipmentFlyoutFrame:SetItemSlot(self, true); return end if EquipmentFlyoutFrame:IsShown() then Narci_Comparison_SetComparison(EquipmentFlyoutFrame.BaseItem, self); return; end if MOG_MODE then ItemTooltip:SetTransmogFromSlotButton(self, -2, 6); else ItemTooltip:SetFromSlotButton(self, -2, 6, isGamepad and 0.4); --delay 0.4s end --[[ DefaultTooltip:SetOwner(self, "ANCHOR_NONE"); if self.isRight then DefaultTooltip:SetPoint("TOPRIGHT", self, "TOPLEFT", DefaultTooltip.offsetX, DefaultTooltip.offsetY); else DefaultTooltip:SetPoint("TOPLEFT", self, "TOPRIGHT", -DefaultTooltip.offsetX, DefaultTooltip.offsetY); end if (self.hyperlink) then DefaultTooltip:SetHyperlink(self.hyperlink); DefaultTooltip:Show(); return; end local hasItem, hasCooldown, repairCost = DefaultTooltip:SetPlayerInventoryItem(self:GetID()); if isGamepad then DefaultTooltip:SetAlpha(0); if self.isRight then ShowDelayedTooltip("TOPRIGHT", self, "TOPLEFT", DefaultTooltip.offsetX, DefaultTooltip.offsetY); else ShowDelayedTooltip("TOPLEFT", self, "TOPRIGHT", -DefaultTooltip.offsetX, DefaultTooltip.offsetY); end else DefaultTooltip:Show(); end --]] end function NarciEquipmentSlotMixin:OnLeave() self:UnregisterEvent("MODIFIER_STATE_CHANGED"); self:UnregisterErrorEvent(); FadeFrame(self.Highlight, 0.25, 0); Narci:HideButtonTooltip(); self:ResetAnimation(); end function NarciEquipmentSlotMixin:OnHide() self.Highlight:Hide(); self.Highlight:SetAlpha(0); self:ResetAnimation(); end function NarciEquipmentSlotMixin:PreClick(button) end function NarciEquipmentSlotMixin:PostClick(button) if CursorHasItem() then EquipCursorItem(self:GetID()); return end ClearCursor(); if ( IsModifiedClick() ) then if IsAltKeyDown() and button == "LeftButton" then local action = EquipmentManager_UnequipItemInSlot(self:GetID()) if action then EquipmentManager_RunAction(action) end return; elseif IsShiftKeyDown() and button == "LeftButton" then if self.hyperlink then if ChatEdit_InsertLink(self.hyperlink) then return elseif SocialPostFrame and Social_IsShown() then Social_InsertLink(self.hyperlink); return end end else PaperDollItemSlotButton_OnModifiedClick(self, button); TakeOutFrames(true); SetItemSocketingFramePosition(self); end else if button == "LeftButton" then if not MOG_MODE then --Undress an item from player model while in Xmog Mode --EquipmentFlyoutFrame:SetItemSlot(self); Narci_EquipmentOption:SetFromSlotButton(self, true) end elseif button == "RightButton" then self:AnchorAlertFrame(); end end end function NarciEquipmentSlotMixin:OnDragStart() local itemLocation = ItemLocation:CreateFromEquipmentSlot(self:GetID()) if C_Item.DoesItemExist(itemLocation) then C_Item.UnlockItem(itemLocation); PickupInventoryItem(self:GetID()); end end function NarciEquipmentSlotMixin:OnReceiveDrag() PickupInventoryItem(self:GetID()); --In fact, attemp to equip cursor item end function NarciEquipmentSlotMixin:DisplayDirectionMark(visible, itemQuality) if self.slotID == 2 or self.slotID == 3 then if visible then if not self.DirectionMark then self.DirectionMark = CreateFrame("Frame", nil, self, "NarciTransmogSlotDirectionMarkTemplate"); self.DirectionMark:SetPoint("RIGHT", self, "LEFT", 9, 0); self.DirectionMark:SetDirection(self.slotID - 1); end FadeFrame(self.DirectionMark, 0.25, 1); if itemQuality then self.DirectionMark:SetQualityColor(itemQuality); end else if self.DirectionMark then self.DirectionMark:Hide(); self.DirectionMark:SetAlpha(0); end end end end function NarciEquipmentSlotMixin:ShowVFX(effectName) if effectName then if self.VFX then self.VFX:SetUpByName(effectName); else self.VFX = NarciItemVFXContainer:AcquireAndSetModelScene(self, effectName); end else self:HideVFX(); end end function NarciEquipmentSlotMixin:HideVFX() if self.VFX then self.VFX:Remove(); end end local function SetStatTooltipText(self) DefaultTooltip:ClearAllPoints(); DefaultTooltip:SetOwner(self, "ANCHOR_NONE"); DefaultTooltip:SetText(self.tooltip); if ( self.tooltip2 ) then DefaultTooltip:AddLine(self.tooltip2, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true); end if ( self.tooltip3 ) then DefaultTooltip:AddLine(" "); DefaultTooltip:AddLine(self.tooltip3, RAID_CLASS_COLORS["MAGE"].r, RAID_CLASS_COLORS["MAGE"].g, RAID_CLASS_COLORS["MAGE"].b, true); end if ( self.tooltip4 ) then DefaultTooltip:AddLine(" "); DefaultTooltip:AddDoubleLine(self.tooltip4[1], self.tooltip4[2], NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); end end function Narci_ShowStatTooltip(self, direction) if ( not self.tooltip ) then return; end SetStatTooltipText(self) if (not direction) then DefaultTooltip:SetPoint("TOPRIGHT",self,"TOPLEFT", -4, 0) elseif direction=="RIGHT" then DefaultTooltip:SetPoint("LEFT",self,"RIGHT", 0, 0) elseif direction=="TOP" then DefaultTooltip:SetPoint("BOTTOM",self,"TOP", 0, -4) elseif direction=="CURSOR" then DefaultTooltip:SetOwner(self, "ANCHOR_CURSOR"); end DefaultTooltip:Show(); end function Narci_ShowStatTooltipDelayed(self) if ( not self.tooltip ) then return; end SetStatTooltipText(self); DefaultTooltip:SetAlpha(0); ShowDelayedTooltip("BOTTOM", self, "TOP", 0, -4); --print("Narci_ShowStatTooltipDelayed") end --/dump GetItemStats(GetInventoryItemLink("player", 8)) --/script DEFAULT_CHAT_FRAME:AddMessage("\124cff0070dd\124Hitem:152783::::::::120::::1:1672:\124h[Mac'Aree Focusing Amethyst]\124h\124r"); --/script DEFAULT_CHAT_FRAME:AddMessage("\124cff0070dd\124Hitem:152783::::::::120::::1:1657:\124h[Mac'Aree Focusing Amethyst]\124h\124r"); --/script DEFAULT_CHAT_FRAME:AddMessage("\124cff0070dd\124Hitem:158362::::::::120::::2:1557:4778:\124h[Lord Waycrest's Signet]\124h\124r"); --[[ Stats sum ilvl ilvl+ from Gem Ring 1.7626*ilvl - 246.88 (sum + 246.88) / 1.7626 40 / 1.7626 = 22.6937 --]] function NarciItemLevelFrameMixin:OnLoad() --Declared in Modules\CharacterFrame\ItemLevelFrame.lua ItemLevelFrame = self; local function SideButton_OnEnter(f) if f.onEnterFunc then f.onEnterFunc(f); FadeFrame(f.Highlight, 0.15, 1); end end local function SideButton_OnLeave(f) Narci:HideButtonTooltip(); FadeFrame(f.Highlight, 0.25, 0); end local function SideButton_ShowDetailedItemLevel(f) if f.isSameLevel then f.tooltipHeadline = string.format(f.tooltipFormat, f.Level:GetText()); else f.tooltipHeadline = string.format(f.tooltipFormat, f.Level:GetText()) .. string.format(" (max %s)", f.avgItemLevel); end if f.avgItemLevelPvp and f.avgItemLevelPvp ~= 0 then f.tooltipSpecial = string.format(STAT_AVERAGE_PVP_ITEM_LEVEL, f.avgItemLevelPvp); else f.tooltipSpecial = nil; end Narci_ShowButtonTooltip(f); end local function SideButton_ShowMajorFactionInfo(f) DefaultTooltip:HideTooltip(); DefaultTooltip:SetOwner(f, "ANCHOR_NONE"); DefaultTooltip:SetPoint("BOTTOM", f, "TOP", 0, 2); DefaultTooltip:SetText(DRAGONFLIGHT_LANDING_PAGE_TITLE); local factionIDs = C_MajorFactions.GetMajorFactionIDs(); local factionList = {}; if factionIDs and #factionIDs > 0 then local factionData; for _, majorFactionID in ipairs(factionIDs) do factionData = C_MajorFactions.GetMajorFactionData(majorFactionID); if factionData then table.insert(factionList, factionData); end end local function UnlockOrderSort(faction1, faction2) if faction1.uiPriority then return faction1.uiPriority < faction2.uiPriority; else return faction1.unlockOrder < faction2.unlockOrder; end end table.sort(factionList, UnlockOrderSort); --Embedded Frame if not f.FactionListFrame then f.FactionListFrame = CreateFrame("Frame", nil, f); f.factionButtons = {}; f.FactionListFrame:SetWidth(154); end for i = 1, #f.factionButtons do f.factionButtons[i]:Hide(); end local maxTextWidth = 0; local description, level, textWidth; for i, data in ipairs(factionList) do if not f.factionButtons[i] then f.factionButtons[i] = CreateFrame("Frame", nil, f.FactionListFrame, "NarciGameTooltipEmbeddedIconTextFrame"); if i == 1 then f.factionButtons[i]:SetPoint("TOPLEFT", f.FactionListFrame, "TOPLEFT", 0, 0); else f.factionButtons[i]:SetPoint("TOPLEFT", f.factionButtons[i - 1], "BOTTOMLEFT", 0, -6); end end level = data.renownLevel or 0; if level < 10 then level = level.." "; end if not data.isUnlocked then description = MAJOR_FACTION_BUTTON_FACTION_LOCKED; elseif C_MajorFactions.HasMaximumRenown(data.factionID) then if C_Reputation.IsFactionParagon(data.factionID) then local totalEarned, threshold = C_Reputation.GetFactionParagonInfo(data.factionID); if totalEarned and threshold and threshold ~= 0 then local paragonLevel = floor(totalEarned / threshold); local currentValue = totalEarned - paragonLevel * threshold; description = string.format("|cff00ccffP%s|r %d/%d", paragonLevel, currentValue, threshold); else description = MAJOR_FACTION_MAX_RENOWN_REACHED; end else description = MAJOR_FACTION_MAX_RENOWN_REACHED; end else description = string.format("|cffffd100%s|r %d/%d", level, data.renownReputationEarned, data.renownLevelThreshold); end f.factionButtons[i].Icon:SetAtlas(string.format("majorFactions_icons_%s512", data.textureKit), false); f.factionButtons[i].Text:SetText(string.format("|cffffffff%s|r\n%s", data.name, description)); f.factionButtons[i].Text:SetTextColor(0.5, 0.5, 0.5); f.factionButtons[i]:Show(); textWidth = f.factionButtons[i].Text:GetWrappedWidth(); if textWidth and textWidth > maxTextWidth then maxTextWidth = textWidth; end end local numButtons = #factionList; f.FactionListFrame:SetHeight((28 + 6)*numButtons - 12); f.FactionListFrame:SetWidth(floor(maxTextWidth + 0.5) + 28 + 6); local function GameTooltip_InsertFrame(tooltipFrame, frame, verticalPadding) -- this is an exact copy of GameTooltip_InsertFrame to avoid "Execution tainted" verticalPadding = verticalPadding or 0; local textSpacing = tooltipFrame:GetCustomLineSpacing() or 2; local textHeight = Round(_G[tooltipFrame:GetName().."TextLeft2"]:GetLineHeight()); local neededHeight = Round(frame:GetHeight() + verticalPadding); local numLinesNeeded = math.ceil(neededHeight / (textHeight + textSpacing)); local currentLine = tooltipFrame:NumLines(); if numLinesNeeded ~= nil then for i = 1, numLinesNeeded do tooltipFrame:AddLine(" "); end end frame:SetParent(tooltipFrame); frame:ClearAllPoints(); frame:SetPoint("TOPLEFT", tooltipFrame:GetName().."TextLeft"..(currentLine + 1), "TOPLEFT", 0, -verticalPadding); if not tooltipFrame.insertedFrames then tooltipFrame.insertedFrames = { }; end local frameWidth = frame:GetWidth(); if tooltipFrame:GetMinimumWidth() < frameWidth then tooltipFrame:SetMinimumWidth(frameWidth); end frame:Show(); tinsert(tooltipFrame.insertedFrames, frame); return (numLinesNeeded * textHeight) + (numLinesNeeded - 1) * textSpacing; end GameTooltip_InsertFrame(DefaultTooltip, f.FactionListFrame, 6); else DefaultTooltip:AddLine(MAJOR_FACTION_BUTTON_FACTION_LOCKED, 0.5, 0.5, 0.5, true); end DefaultTooltip:Show(); DefaultTooltip:FadeIn(); end local LeftButton = self.LeftButton; LeftButton:SetScript("OnEnter", SideButton_OnEnter); LeftButton:SetScript("OnLeave", SideButton_OnLeave); LeftButton.onEnterFunc = SideButton_ShowDetailedItemLevel; LeftButton.tooltipFormat = L["Equipped Item Level Format"]; LeftButton.tooltipLine1 = STAT_AVERAGE_ITEM_LEVEL_TOOLTIP; local RightButton = self.RightButton; RightButton:SetScript("OnEnter", SideButton_OnEnter); RightButton:SetScript("OnLeave", SideButton_OnLeave); RightButton.onEnterFunc = SideButton_ShowMajorFactionInfo; end local function UpdateCharacterInfoFrame(newLevel) local level = newLevel or UnitLevel("player"); local _, currentSpecName; local currentSpec = GetSpecialization(); if currentSpec then _, currentSpecName = GetSpecializationInfo(currentSpec); else currentSpecName = " "; end local className, englishClass = UnitClass("player"); local _, _, _, rgbHex = GetClassColor(englishClass); local frame = Narci_PlayerInfoFrame; if currentSpecName then local titleID = GetCurrentTitle(); local titleName = GetTitleName(titleID); if titleName then titleName = strtrim(titleName); --delete the space in Title frame.Miscellaneous:SetText(titleName.." | ".."|cFFFFD100"..level.."|r ".."|c"..rgbHex..currentSpecName.." "..className.."|r"); else frame.Miscellaneous:SetText("Level".." |cFFFFD100"..level.."|r ".."|c"..rgbHex..currentSpecName.." "..className.."|r"); end end ItemLevelFrame:UpdateItemLevel(level); end local SlotController = {}; SlotController.updateFrame = CreateFrame("Frame"); SlotController.updateFrame:Hide(); SlotController.updateFrame:SetScript("OnUpdate", function(f, elapsed) f.t = f.t + elapsed; if f.t >= 0.05 then f.t = 0; if SlotController:Refresh(f.sequence[f.i], f.forceRefresh) then f.i = f.i + 1; else f:Hide(); if MOG_MODE and Toolbar.TransmogListFrame:IsShown() then After(0.5, function() Toolbar.TransmogListFrame:UpdateTransmogList(); end); end end end end); SlotController.refreshSequence = { 1, 2, 3, 15, 5, 9, 16, 17, 4, 10, 6, 7, 8, 11, 12, 13, 14, 19, }; SlotController.tempEnchantSequence = {}; for slotID in pairs(ValidForTempEnchant) do tinsert(SlotController.tempEnchantSequence, slotID); end function SlotController:Refresh(slotID, forceRefresh) if SLOT_TABLE[slotID] then SLOT_TABLE[slotID]:Refresh(forceRefresh); return true; end end function SlotController:RefreshAll(forceRefresh) for slotID, slotButton in pairs(SLOT_TABLE) do slotButton:Refresh(forceRefresh); end end function SlotController:StopRefresh() if self.updateFrame then self.updateFrame:Hide(); end end function SlotController:LazyRefresh(sequenceName) local f = self.updateFrame; f:Hide(); f.t = 0; f.i = 1; if sequenceName == "temp" then f.sequence = self.tempEnchantSequence; f.forceRefresh = true; else f.sequence = self.refreshSequence; f.forceRefresh = false; end f:Show(); end function SlotController:ClearCache() for slotID, slotButton in pairs(SLOT_TABLE) do slotButton.itemLink = nil; end end function SlotController:PlayAnimOut() if not InCombatLockdown() and Narci_Character:IsShown() then for slotID, slotButton in pairs(SLOT_TABLE) do slotButton.animOut:Play(); end Narci_Character.animOut:Play(); end end function SlotController:IsMouseOver() for slotID, slotButton in pairs(SLOT_TABLE) do if slotButton:IsMouseOver() then return true end end return false end ------------------------------------------------------------------ -----Some of the codes are derivated from EquipmentFlyout.lua----- ------------------------------------------------------------------ NarciEquipmentFlyoutButtonMixin = CreateFromMixins{NarciItemButtonSharedMixin}; function NarciEquipmentFlyoutButtonMixin:OnClick(button, down, isGamepad) if button == "LeftButton" then local action = EquipmentManager_EquipItemByLocation(self.location, self.slotID) if action then self:AnchorAlertFrame(); EquipmentManager_RunAction(action) end self:Disable(); if isGamepad then EquipmentFlyoutFrame.gamepadButton = self; end end end function NarciEquipmentFlyoutButtonMixin:OnLeave() FadeFrame(self.Highlight, 0.25, 0); Narci:HideButtonTooltip(); self:ResetAnimation(); end function NarciEquipmentFlyoutButtonMixin:OnEnter(motion, isGamepad) Narci_Comparison_SetComparison(self.itemLocation, self); if isGamepad then self:PlayGamePadAnimation(); else FadeFrame(self.Highlight, 0.15, 1); end end function NarciEquipmentFlyoutButtonMixin:OnEvent(event, ...) if event == "UI_ERROR_MESSAGE" then self:OnErrorMessage(...); end end function NarciEquipmentFlyoutButtonMixin:SetUp(maxItemLevel) self.FlyUp:Stop(); local itemLocation = self.itemLocation; self.hyperlink = C_Item.GetItemLink(itemLocation) if ( not itemLocation ) then return; end local itemID = C_Item.GetItemID(itemLocation); local itemQuality = C_Item.GetItemQuality(itemLocation); local itemLevel = C_Item.GetCurrentItemLevel(itemLocation); local itemIcon = C_Item.GetItemIcon(itemLocation); local itemLink = C_Item.GetItemLink(itemLocation) if C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItem(itemLocation) then itemQuality = "Azerite"; --AzeriteEmpoweredItem elseif C_AzeriteItem.IsAzeriteItem(itemLocation) then itemQuality = "Heart"; elseif IsCorruptedItem(itemLink) then itemQuality = "NZoth"; elseif C_LegendaryCrafting.IsRuneforgeLegendary(itemLocation) then itemQuality = "Runeforge"; itemIcon = GetRuneForgeLegoIcon(itemLocation) or itemIcon; end itemQuality = GetBorderArtByItemID(itemID) or itemQuality; if maxItemLevel and itemLevel < maxItemLevel and itemQuality ~= "Runeforge" then itemQuality = 0; self.Icon:SetDesaturated(true); else self.Icon:SetDesaturated(false); end self.Icon:SetTexture(itemIcon) --self.Border:SetTexture(BorderTexture[itemQuality]) self:SetBorderTexture(self.Border, itemQuality); self.ItemLevelCenter.ItemLevel:SetText(itemLevel); self.ItemLevelCenter:Show(); if itemLink then DisplayRuneSlot(self, self.slotID, itemQuality, itemLink); end end function NarciEquipmentFlyoutButtonMixin:HideButton() self:Hide(); self.location = nil; self.hyperlink = nil; end local function ShowLessItemInfo(self, bool) if bool then self.Name:Hide(); self.ItemLevel:Hide(); self.ItemLevelCenter:Show(); else self.Name:Show(); self.ItemLevel:Show(); self.ItemLevelCenter:Hide(); end end local function ShowAllItemInfo() if MOG_MODE then return end local level = Narci_FlyoutBlack:GetFrameLevel() - 1; for slotID, slotButton in pairs(SLOT_TABLE) do ShowLessItemInfo(slotButton, false); slotButton:SetFrameLevel(level -1) slotButton.RuneSlot:SetFrameLevel(level) end end NarciEquipmentFlyoutFrameMixin = {}; function NarciEquipmentFlyoutFrameMixin:OnLoad() EquipmentFlyoutFrame = self; self.buttons = {}; self.slotID = -1; self.itemSortFunc = function(a,b) return tonumber(a.level)> tonumber(b.level) end self:SetScript("OnLoad", nil); self.OnLoad = nil; self:SetFixedFrameStrata(true); self:SetFrameStrata("HIGH"); end function NarciEquipmentFlyoutFrameMixin:OnHide() ShowAllItemInfo(); self.slotID = -1; self:UnregisterEvent("MODIFIER_STATE_CHANGED"); self:UnregisterEvent("GLOBAL_MOUSE_DOWN"); self.Arrow:Hide(); self:StopAnimating(); if Narci_Character.animOut:IsPlaying() then return; end Narci_FlyoutBlack:Out(); end function NarciEquipmentFlyoutFrameMixin:OnShow() self:RegisterEvent("MODIFIER_STATE_CHANGED"); self:RegisterEvent("GLOBAL_MOUSE_DOWN"); self.Arrow.anim:Play(); end function NarciEquipmentFlyoutFrameMixin:OnEvent(event, ...) --Hide Flyout if Left-Alt is released if ( event == "MODIFIER_STATE_CHANGED" ) then local key, state = ...; if ( key == "LALT" ) then local flyout = EquipmentFlyoutFrame; if state == 0 and flyout:IsShown() then flyout:Hide(); end end elseif (event == "GLOBAL_MOUSE_DOWN") then if not self:IsMouseOverButtons() then self:Hide(); end end end function NarciEquipmentFlyoutFrameMixin:SetItemSlot(slotButton, showArrow) if MOG_MODE then return; end local slotID = slotButton.slotID; if (slotID == -1 or (self:IsShown() and self.parentButton and self.parentButton.slotID == slotID)) and (not IsAltKeyDown()) then self:Hide(); return; end if self.parentButton then local level = Narci_FlyoutBlack:GetFrameLevel() -1 self.parentButton:SetFrameLevel(level - 1); self.parentButton.RuneSlot:SetFrameLevel(level); ShowLessItemInfo(self.parentButton, false); end self.parentButton = slotButton; self:DisplayItemsBySlotID(slotID, self.slotID ~= slotID); self.slotID = slotID; self:SetParent(slotButton); self:ClearAllPoints(); if slotButton.isRight then self:SetPoint("TOPRIGHT", slotButton, "TOPLEFT", 0, 0); --EquipmentFlyout's Position else self:SetPoint("TOPLEFT", slotButton, "TOPRIGHT", 0, 0); end --Unequip Arrow self.Arrow:ClearAllPoints(); self.Arrow:SetPoint("TOP", slotButton, "TOP", 0, 8); if showArrow then self.Arrow:Show(); end Narci_FlyoutBlack:In(); slotButton:SetFrameLevel(Narci_FlyoutBlack:GetFrameLevel() + 1) self:SetFrameLevel(50); NarciEquipmentTooltip:HideTooltip(); ShowLessItemInfo(slotButton, true) --Reposition Comparison Tooltip if it reaches the top of the screen-- local Tooltip = Narci_Comparison; Tooltip:ClearAllPoints(); Tooltip:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 8, 12); if slotButton:GetTop() > Tooltip:GetBottom() then Tooltip:ClearAllPoints(); Tooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT", 8, -12); end Narci_Comparison_SetComparison(self.BaseItem, slotButton); Narci_ShowComparisonTooltip(Tooltip); end function NarciEquipmentFlyoutFrameMixin:CreateItemButton() local perRow = 5; --EQUIPMENTFLYOUT_ITEMS_PER_ROW local numButtons = #self.buttons; local button = CreateFrame("Button", nil, self.ButtonFrame, "NarciEquipmentFlyoutButtonTemplate"); button:SetFrameStrata("DIALOG"); local row = floor(numButtons/perRow); local col = numButtons - row * perRow; button:SetPoint("TOPLEFT", self, "TOPLEFT", 70*col, -74*row); self.buttons[numButtons + 1] = button; button.FlyUp.Move:SetStartDelay(numButtons/25); button.FlyUp.Fade:SetStartDelay(numButtons/25); button.isFlyout = true; return button end function NarciEquipmentFlyoutFrameMixin:DisplayItemsBySlotID(slotID, playFlyUpAnimation) local LoadItemData = C_Item.RequestLoadItemData; --Cache Item Info local id = slotID or self.slotID; if not id or id <= 0 then return end self:Show(); local baseItemLevel; local bastItemLocation = ItemLocation:CreateFromEquipmentSlot(id); if C_Item.DoesItemExist(bastItemLocation) then baseItemLevel = C_Item.GetCurrentItemLevel(bastItemLocation); else baseItemLevel = 0; end self.BaseItem = bastItemLocation; local buttons = self.buttons; --Get the items from bags; local itemTable = {}; local sortedItems = {}; local numItems = 0; GetInventoryItemsForSlot(id, itemTable); local itemLocation, itemLevel, itemInfo; local invLocationPlayer = ITEM_INVENTORY_LOCATION_PLAYER; for location, hyperlink in pairs(itemTable) do if ( location - id == invLocationPlayer ) then -- Remove the currently equipped item from the list itemTable[location] = nil; else local _, _, bags, _, slot, bag = EquipmentManager_UnpackLocation(location); if bags then itemLocation = ItemLocation:CreateFromBagAndSlot(bag, slot); itemLevel = C_Item.GetCurrentItemLevel(itemLocation); LoadItemData(itemLocation); itemInfo = {level = itemLevel, itemLocation = itemLocation, location = location}; numItems = numItems + 1; sortedItems[numItems] = itemInfo; end end end table.sort(sortedItems, self.itemSortFunc); --Sorted by item level local numTotalItems = #sortedItems; local buttonWidth, buttonHeight = self.parentButton:GetWidth(), self.parentButton:GetHeight(); buttonWidth, buttonHeight = floor(buttonWidth + 0.5), floor(buttonHeight + 0.5); local borderSize = self.parentButton.Border:GetSize(); borderSize = floor(borderSize + 0.5); self:SetWidth(max(buttonWidth, math.min(numTotalItems, 5)*buttonWidth)); local numDisplayedItems = math.min(numTotalItems, 20); --EQUIPMENTFLYOUT_ITEMS_PER_PAGE self:SetHeight(max(floor((numDisplayedItems-1)/5 + 1)*buttonHeight, buttonHeight)); local gamepadButton = self.gamepadButton; self.gamepadButton = nil; baseItemLevel = baseItemLevel - 14; --darken button if the item level is lower than the base local button; for i = 1, numDisplayedItems do button = buttons[i]; if not button then button = self:CreateItemButton(); end button.itemLocation = sortedItems[i].itemLocation; button.location = sortedItems[i].location; button.slotID = id; button:SetUp(baseItemLevel); button:Show(); button:SetSize(buttonWidth, buttonHeight); button.Border:SetSize(borderSize, borderSize); button:Enable(); if button == gamepadButton then Narci_Comparison_SetComparison(gamepadButton.itemLocation, gamepadButton); Narci_GamepadOverlayContainer.SlotBorder:UpdateQualityColor(gamepadButton); end end for i = numDisplayedItems + 1, #buttons do buttons[i]:HideButton(); end if playFlyUpAnimation then for i = 1, numDisplayedItems do buttons[i].FlyUp:Play(); end end self.numDisplayedItems = numDisplayedItems; --For gamepad to cycle end function NarciEquipmentFlyoutFrameMixin:IsMouseOverButtons() for i = 1, #self.buttons do if self.buttons[i]:IsShown() and self.buttons[i]:IsMouseOver() then return true; end end if self.parentButton:IsMouseOver() then return true end if SlotController:IsMouseOver() then return true end return false end ----------------------------------------------------------- ------------------------Color Theme------------------------ ----------------------------------------------------------- local ColorUtil = {}; ColorUtil.themeColor = NarciThemeUtil:GetColorTable(); function ColorUtil:UpdateByMapID() local mapID = C_Map.GetBestMapForUnit("player"); --print("mapID:".. mapID) if mapID then --and NarcissusDB.AutoColorTheme if mapID == self.mapID then self.requireUpdate = false; else self.mapID = mapID; self.requireUpdate = true; self.themeColor = NarciThemeUtil:SetColorIndex(mapID); RadarChart:UpdateColor(); Narci_NavBar:SetThemeColor(self.themeColor); end else self.requireUpdate = false; end end function ColorUtil:SetWidgetColor(frame) if not self.requireUpdate then return end; local r, g, b = self.themeColor[1], self.themeColor[2], self.themeColor[3]; local type = frame:GetObjectType(); if type == "FontString" then local sqrt = math.sqrt; r, g, b = sqrt(r), sqrt(g), sqrt(b); frame:SetTextColor(r, g, b); else frame:SetColorTexture(r, g, b); end end --------------------------------------------- NarciRadarChartMixin = {} function NarciRadarChartMixin:OnLoad() RadarChart = self; local circleTex = "Interface\\AddOns\\Narcissus\\Art\\Widgets\\RadarChart\\Radar-Vertice"; local filter = "TRILINEAR"; local tex; local texs = {}; for i = 1, 4 do tex = self:CreateTexture(nil, "OVERLAY", nil, 2); tinsert(texs, tex); tex:SetSize(12, 12); tex:SetTexture(circleTex, nil, nil, filter); end self.vertices = texs; self:SetScript("OnLoad", nil); self.OnLoad = nil; end function NarciRadarChartMixin:OnShow() self.MaskedBackground:SetAlpha(0.4); self.MaskedBackground2:SetAlpha(0.4); end function NarciRadarChartMixin:OnHide() self:StopAnimating(); end function NarciRadarChartMixin:SetVerticeSize(attributeFrame, size) local name = attributeFrame.token; local vertice; if name == "Crit" then vertice = self.vertices[1]; elseif name == "Haste" then vertice = self.vertices[2]; elseif name == "Mastery" then vertice = self.vertices[3]; elseif name == "Versatility" then vertice = self.vertices[4]; end vertice:SetSize(size, size); end function NarciRadarChartMixin:UpdateColor() ColorUtil:SetWidgetColor(self.MaskedBackground) ColorUtil:SetWidgetColor(self.MaskedBackground2) ColorUtil:SetWidgetColor(self.MaskedLine1) ColorUtil:SetWidgetColor(self.MaskedLine2) ColorUtil:SetWidgetColor(self.MaskedLine3) ColorUtil:SetWidgetColor(self.MaskedLine4) end local GetEffectiveCrit = Narci.GetEffectiveCrit; local GetCombatRating = GetCombatRating; function NarciRadarChartMixin:SetValue(c, h, m, v, manuallyInPutSum) --c, h, m, v: Input manually or use combat ratings local deg = math.deg; local rad = math.rad; local atan2 = math.atan2; local sqrt = math.sqrt; local Radar = self; local chartWidth = 96 / 2; --In half local crit, haste, mastery, versatility; if c then crit = c; else local _, rating = GetEffectiveCrit(); crit = GetCombatRating(rating) or 0; end if h then haste = h; else haste = GetCombatRating(CR_HASTE_MELEE) or 0; end if m then mastery = m; else mastery = GetCombatRating(CR_MASTERY) or 0; end if v then versatility = v; else versatility = GetCombatRating(CR_VERSATILITY_DAMAGE_DONE) or 0; end -- | p1(x1,y1) Line4 p3(x3,y3) -- | * * -- | * * -- | Line1 * Line3 -- | * * -- | * * -- | p2(x2,y2) Line2 p4(x4,y4) local v1, v2, v3, v4, v5, v6 = true, true, true, true, true, true; if crit == 0 and haste == 0 and mastery == 0 and versatility == 0 then v1, v2, v3, v4, v5, v6 = false, false, false, false, false, false; else if crit == 0 and haste == 0 then v1 = false; end; if haste == 0 and versatility == 0 then v2 = false; end; if mastery == 0 and versatility == 0 then v3 = false; end; if crit == 0 and mastery == 0 then v4 = false; end; crit, haste, mastery = crit + 0.03, haste + 0.02, mastery + 0.01; --Avoid some mathematical issues end Radar.MaskedLine1:SetShown(v1); Radar.MaskedLine2:SetShown(v2); Radar.MaskedLine3:SetShown(v3); Radar.MaskedLine4:SetShown(v4); Radar.MaskedBackground:SetShown(v5); Radar.MaskedBackground2:SetShown(v6); --[[ --4500 9.0 Stats Sum Level 50 Enchancements on ilvl 445 (Mythic Eternal Palace) Player Lvl 120 Neck 159 Weapon 25 Back 51 Wrist 28 Hands 37 Waist 36 Legs 50 Feet 37 Ring 89 Trinket 35 Max:696 + 12*7 ~= 800 Player Lvl 60 iLvl 233(Mythic Castle Nathria): Back 82 Leg 141 Chest 141 Neck 214 Waist 105 Hand 105 Feet 105 Wrist 79 Ring 226 Shoulder 109 Head 146 Trinket 200 ~=1900 Player Lvl 60 iLvl 259(Mythic Sanctum of Domination): Back 90 Leg 165 Chest 165 Neck 268 Waist 124 Hand 130 Feet 124 Wrist 91 Ring 268 Shoulder 124 Head 146 Trinket 200 weapon 162 ~= 2500 (+ 8 sockets) ilvl 240 (Mythic Antorus) Player Lvl 110 Head 87 Shoulder 64 Chest 88 Weapon 152 Back 49 Wrist 49 Hands 64 Waist 64 Legs 87 Feet 63 Ring 165 Trinket 62 Max ~= 1100 ilvl 149 (Mythic HFC) Player Lvl 100 Head 48 Shoulder 36 Chest 48 Weapon 24 Back 28 Wrist 27 Hands 36 Waist 36 Legs 48 Feet 35 Ring 27 Trinket 32 Max ~= 510 Heirlooms Player Lvl 20 Weapon 4 Back 4 Wrist 4 Hands 6 Waist 6 Legs 8 Feet 6 Ring 5 Trinket 6 ~= 60 --]] local Sum = manuallyInPutSum or 0; local maxNum = max(crit + haste + mastery + versatility, 1); if maxNum > 0.95 * Sum then Sum = maxNum; end local d1, d2, d3, d4 = (crit / Sum), (haste / Sum) , (mastery / Sum) , (versatility / Sum); local a; if (d1 + d4) ~= 0 and (d2 + d3) ~= 0 then --a = chartWidth * math.sqrt(0.618/(d1 + d4)/(d2 + d3)/2)* 96; a = 1.414 * chartWidth; else a = 0; end local x1, x2, x3, x4 = -d1*a, -d2*a, d3*a, d4*a; local y1, y2, y3, y4 = d1*a, -d2*a, d3*a, -d4*a; local mx1, mx2, mx3, mx4 = (x1 + x2)/2, (x2 + x4)/2, (x3 + x4)/2, (x1 + x3)/2; local my1, my2, my3, my4 = (y1 + y2)/2, (y2 + y4)/2, (y3 + y4)/2, (y1 + y3)/2; local ma1 = atan2((y1 - y2), (x1 - x2)); local ma2 = atan2((y2 - y4), (x2 - x4)); local ma3 = atan2((y4 - y3), (x4 - x3)); local ma4 = atan2((y3 - y1), (x3 - x1)); if my1 == 0 then my1 = 0.01; end if my3 == 0 then my1 = -0.01; end if deg(ma1) == 90 then ma1 = rad(89); end if deg(ma3) == -90 then ma1 = rad(-89); end Radar.vertices[1]:SetPoint("CENTER", x1, y1); Radar.vertices[2]:SetPoint("CENTER", x2, y2); Radar.vertices[3]:SetPoint("CENTER", x3, y3); Radar.vertices[4]:SetPoint("CENTER", x4, y4); Radar.Mask1:SetRotation(ma1); Radar.Mask2:SetRotation(ma2); Radar.Mask3:SetRotation(ma3); Radar.Mask4:SetRotation(ma4); local hypo1 = sqrt(2*x1^2 + 2*x2^2); local hypo2 = sqrt(2*x2^2 + 2*x4^2); local hypo3 = sqrt(2*x4^2 + 2*x3^2); local hypo4 = sqrt(2*x3^2 + 2*x1^2); if (hypo1 - 4) > 0 then Radar.MaskLine1:SetWidth(hypo1 - 4); --Line length else Radar.MaskLine1:SetWidth(0.1); end if (hypo2 - 4) > 0 then Radar.MaskLine2:SetWidth(hypo2 - 4); else Radar.MaskLine2:SetWidth(0.1); end if (hypo3 - 4) > 0 then Radar.MaskLine3:SetWidth(hypo3 - 4); else Radar.MaskLine3:SetWidth(0.1); end if (hypo4 - 4) > 0 then Radar.MaskLine4:SetWidth(hypo4 - 4); else Radar.MaskLine4:SetWidth(0.1); end Radar.MaskLine1:ClearAllPoints(); Radar.MaskLine1:SetRotation(0); Radar.MaskLine1:SetRotation(ma1); Radar.MaskLine1:SetPoint("CENTER", Radar, "CENTER", mx1, my1); Radar.MaskLine2:ClearAllPoints(); Radar.MaskLine2:SetRotation(0); Radar.MaskLine2:SetRotation(ma2); Radar.MaskLine2:SetPoint("CENTER", Radar, "CENTER", mx2, my2); Radar.MaskLine3:ClearAllPoints(); Radar.MaskLine3:SetRotation(0); Radar.MaskLine3:SetRotation(ma3); Radar.MaskLine3:SetPoint("CENTER", Radar, "CENTER", mx3, my3); Radar.MaskLine4:ClearAllPoints(); Radar.MaskLine4:SetRotation(0); Radar.MaskLine4:SetRotation(ma4); Radar.MaskLine4:SetPoint("CENTER", Radar, "CENTER", mx4, my4); Radar.Mask1:SetPoint("CENTER", mx1, my1); Radar.Mask2:SetPoint("CENTER", mx2, my2); Radar.Mask3:SetPoint("CENTER", mx3, my3); Radar.Mask4:SetPoint("CENTER", mx4, my4); Radar.MaskedBackground:SetAlpha(0.4); Radar.MaskedBackground2:SetAlpha(0.4); Radar.n1, Radar.n2, Radar.n3, Radar.n4 = crit, haste, mastery, versatility; end function NarciRadarChartMixin:AnimateValue(c, h, m, v) --Update the radar chart using animation local Radar = self; local UpdateFrame = Radar.UpdateFrame; if not UpdateFrame then UpdateFrame = CreateFrame("Frame", nil, Radar, "NarciUpdateFrameTemplate"); Radar.UpdateFrame = UpdateFrame; Radar.n1, Radar.n2, Radar.n3, Radar.n4 = 0, 0, 0, 0; end local s1, s2, s3, s4 = Radar.n1, Radar.n2, Radar.n3, Radar.n4; --start/end point local critChance, critRating = GetEffectiveCrit(); local e1 = c or GetCombatRating(critRating) or 0; local e2 = h or GetCombatRating(CR_HASTE_MELEE) or 0; local e3 = m or GetCombatRating(CR_MASTERY) or 0; local e4 = v or GetCombatRating(CR_VERSATILITY_DAMAGE_DONE) or 0; local duration = 0.2; local playerLevel = UnitLevel("player"); local sum; if playerLevel == 50 then sum = max(e1 + e2 + e3 + e4 , 800); --Status Sum for 8.3 Raid elseif playerLevel == 60 then sum = max(e1 + e2 + e3 + e4 , 2500); --Status Sum for 9.1 Raid else --sum = 31 * math.exp( 0.04 * UnitLevel("player")) + 40; sum = (e1 + e2 + e3 + e4) * 1.5; end local function UpdateFunc(frame, elapsed) local t = frame.t; frame.t = t + elapsed; local v1 = outSine(t, s1, e1, duration); local v2 = outSine(t, s2, e2, duration); local v3 = outSine(t, s3, e3, duration); local v4 = outSine(t, s4, e4, duration); if t >= duration then v1, v2, v3, v4 = e1, e2, e3, e4; frame:Hide(); end Radar:SetValue(v1, v2, v3, v4, sum); end UpdateFrame:Hide(); UpdateFrame:SetScript("OnUpdate", UpdateFunc); UpdateFrame:Show(); if self.Primary:IsShown() then self.Primary:Update(); self.Health:Update(); end end function NarciRadarChartMixin:TogglePrimaryStats(state) state = false; if state then self.Primary.Color:SetColorTexture(0.24, 0.24, 0.24, 0.75); self.Health.Color:SetColorTexture(0.15, 0.15, 0.15, 0.75); FadeFrame(self.Primary, 0.15, 1); FadeFrame(self.Health, 0.15, 1); self.Primary:Update(); self.Health:Update(); else FadeFrame(self.Primary, 0.25, 0); FadeFrame(self.Health, 0.25, 0); end end function Narci_AttributeFrame_UpdateBackgroundColor(self) local frameID = self:GetID() or 0; local themeColor = ColorUtil.themeColor; local r, g, b = themeColor[1], themeColor[2], themeColor[3]; if frameID % 2 == 0 then if self.Color then self.Color:SetColorTexture(r, g, b, 0.75); return; elseif self.Color1 and self.Color2 then self.Color1:SetColorTexture(r, g, b, 0.75); self.Color2:SetColorTexture(r, g, b, 0.75); end else if self.Color then self.Color:SetColorTexture(0.1, 0.1, 0.1, 0.75); return; elseif self.Color1 and self.Color2 then self.Color1:SetColorTexture(0.1, 0.1, 0.1, 0.75); self.Color2:SetColorTexture(0.1, 0.1, 0.1, 0.75); end end end function Narci_AttributeFrame_OnLoad(self) Narci_AttributeFrame_UpdateBackgroundColor(self); end local function RefreshStats(id, frame) frame = frame or "Detailed"; if frame == "Detailed" then if STAT_STABLE[id] then STAT_STABLE[id]:Update(); end elseif frame == "Concise" then if SHORT_STAT_TABLE[id] then SHORT_STAT_TABLE[id]:Update(); end end end local StatsUpdator = CreateFrame("Frame"); StatsUpdator:Hide(); StatsUpdator.t = 0; StatsUpdator.index = 1; StatsUpdator:SetScript("OnUpdate", function(self, elapsed) self.t = self.t + elapsed; if self.t > 0.05 then self.t = 0; local i = self.index; if STAT_STABLE[i] then STAT_STABLE[i]:Update(); end if SHORT_STAT_TABLE[i] then SHORT_STAT_TABLE[i]:Update(); end if i >= 20 then self:Hide(); self.index = 1; else self.index = i + 1; end end end); function StatsUpdator:Gradual() ItemLevelFrame:AsyncUpdate(0.05); self.index = 1; self.t = 0; self:Show(); end function StatsUpdator:Instant() if not StatsUpdator.pauseUpdate then StatsUpdator.pauseUpdate = true; After(0, function() for i = 1, 20 do RefreshStats(i); end for i = 1, 12 do RefreshStats(i, "Concise"); end StatsUpdator.pauseUpdate = nil; end); end end function StatsUpdator:UpdateCooldown() for slotID, slotButton in pairs(SLOT_TABLE) do slotButton:TrackCooldown(); end end local function PlayAttributeAnimation() if not NarcissusDB.DetailedIlvlInfo then RadarChart:AnimateValue(); return end if not RadarChart:IsShown() then return --Attributes is not the active tab end local anim; for i = 1, 20 do anim = STAT_STABLE[i].animIn; if anim then anim.A2:SetToAlpha(STAT_STABLE[i]:GetAlpha()); anim:Play(); end end RadarChart.animIn:Play(); end local function ShowAttributeButton(bool) if NarcissusDB.DetailedIlvlInfo then Narci_DetailedStatFrame:SetShown(true); Narci_ConciseStatFrame:SetShown(false); RadarChart:SetShown(true); else Narci_DetailedStatFrame:SetShown(false); Narci_ConciseStatFrame:SetShown(true); RadarChart:SetShown(false); end ItemLevelFrame:SetShown(true); end local function AssignFrame() local statFrame = Narci_DetailedStatFrame; local radar = RadarChart; STAT_STABLE[1] = statFrame.Primary; STAT_STABLE[2] = statFrame.Stamina; STAT_STABLE[3] = statFrame.Damage; STAT_STABLE[4] = statFrame.AttackSpeed; STAT_STABLE[5] = statFrame.Power; STAT_STABLE[6] = statFrame.Regen; STAT_STABLE[7] = statFrame.Health; STAT_STABLE[8] = statFrame.Armor; STAT_STABLE[9] = statFrame.Reduction; STAT_STABLE[10]= statFrame.Dodge; STAT_STABLE[11]= statFrame.Parry; STAT_STABLE[12]= statFrame.Block; STAT_STABLE[13]= radar.Crit; STAT_STABLE[14]= radar.Haste; STAT_STABLE[15]= radar.Mastery; STAT_STABLE[16]= radar.Versatility; STAT_STABLE[17]= statFrame.Leech; STAT_STABLE[18]= statFrame.Avoidance; STAT_STABLE[19]= statFrame.MovementSpeed; STAT_STABLE[20]= statFrame.Speed; local statFrame_Short = Narci_ConciseStatFrame; SHORT_STAT_TABLE[1] = statFrame_Short.Primary; SHORT_STAT_TABLE[2] = statFrame_Short.Stamina; SHORT_STAT_TABLE[3] = statFrame_Short.Health; SHORT_STAT_TABLE[4] = statFrame_Short.Power; SHORT_STAT_TABLE[5] = statFrame_Short.Regen; SHORT_STAT_TABLE[6] = statFrame_Short.Crit; SHORT_STAT_TABLE[7] = statFrame_Short.Haste; SHORT_STAT_TABLE[8] = statFrame_Short.Mastery; SHORT_STAT_TABLE[9] = statFrame_Short.Versatility; SHORT_STAT_TABLE[10] = statFrame_Short.Leech; SHORT_STAT_TABLE[11] = statFrame_Short.Avoidance; SHORT_STAT_TABLE[12] = statFrame_Short.Speed; end function Narci_SetPlayerName(self) local playerName = UnitName("player"); self.PlayerName:SetShadowColor(0, 0, 0); self.PlayerName:SetShadowOffset(2, -2); self.PlayerName:SetText(playerName); SmartFontType(self.PlayerName); end function Narci_AliasButton_SetState() local editBox = Narci_PlayerInfoFrame.PlayerName; local button = Narci_AliasButton; if NarcissusDB_PC.UseAlias then editBox:Enable(); editBox:SetText((NarcissusDB_PC.PlayerAlias or UnitName("player"))); button.Label:SetText(L["Use Player Name"]); else editBox:Disable(); editBox:SetText(UnitName("player")); button.Label:SetText(L["Use Alias"]); end local LetterNum = editBox:GetNumLetters(); local w = max(LetterNum*16, 160); editBox:SetWidth(w); button:SetWidth(button.Label:GetWidth() + 12); end function Narci_AliasButton_OnClick(self) local editBox = Narci_PlayerInfoFrame.PlayerName; NarcissusDB_PC.UseAlias = not NarcissusDB_PC.UseAlias; if NarcissusDB_PC.UseAlias then self.Label:SetText(L["Use Player Name"]); editBox:Enable(); editBox:SetFocus(); editBox:SetText(NarcissusDB_PC.PlayerAlias or UnitName("player")); editBox:HighlightText(); else self.Label:SetText(L["Use Alias"]); local text = strtrim(editBox:GetText()); editBox:SetText(text); NarcissusDB_PC.PlayerAlias = text; editBox:Disable(); editBox:HighlightText(0,0) editBox:SetText(UnitName("player")); end self:SetWidth(self.Label:GetWidth() + 12); local LetterNum = editBox:GetNumLetters(); local w = max(LetterNum*16, 160); editBox:SetWidth(w); end function Narci_Open() if not IS_OPENED then if InCombatLockdown() then --[[ --Can't open the default character pane either ShowUIPanel(CharacterFrame); local subFrame = _G["PaperDollFrame"]; if not subFrame:IsShown() then ToggleCharacter("PaperDollFrame"); end --]] return; end IS_OPENED = true; CVarTemp:BackUp(); Toolbar:ShowUI("Narcissus"); ViewProfile:SaveView(5); CameraUtil:UpdateParameters(); CameraMover:MakeActive(); MOG_MODE_OFFSET = 0; local speedFactor = 180/(GetCVar("cameraYawMoveSpeed") or 180); ZoomFactor.toSpeed = speedFactor * ZoomFactor.toSpeedBasic; ZoomFactor.fromSpeed = speedFactor * ZoomFactor.fromSpeedBasic; EL:Show(); After(0, function() CameraMover:Enter(); RadarChart:SetValue(0,0,0,0,1); PlayLetteboxAnimation(); local Vignette = Narci_Vignette; Vignette.VignetteLeft:SetAlpha(VIGNETTE_ALPHA); Vignette.VignetteRight:SetAlpha(VIGNETTE_ALPHA); Vignette.VignetteRightSmall:SetAlpha(0); FadeFrame(Vignette, 0.5, 1); Vignette.VignetteRight.animIn:Play(); Vignette.VignetteLeft.animIn:Play(); SlotButtonOverlayUtil:UpdateData(); After(0, function() SlotController:LazyRefresh(); StatsUpdator:Gradual(); end); end); Narci.refreshCombatRatings = true; Narci.isActive = true; else if Narci.showExitConfirm and not InCombatLockdown() then local ExitConfirm = Narci_ExitConfirmationDialog; if not ExitConfirm:IsShown() then FadeFrame(ExitConfirm, 0.25, 1); --"Nullify" ShowUI UIParent:SetAlpha(0); Minimap:Hide(); After(0, function() SetUIVisibility(false); MiniButton:Enable(); UIParent:SetAlpha(1); Minimap:Show() end); return; else FadeFrame(ExitConfirm, 0.15, 0); end end SlotController:PlayAnimOut(); ExitFunc(); PlayLetteboxAnimation("OUT"); EquipmentFlyoutFrame:Hide(); Narci_ModelSettings:Hide(); Toolbar:HideUI(); TakeOutFrames(false); Narci.showExitConfirm = false; end NarciAPI.UpdateSessionTime(); end function Narci_OpenGroupPhoto() if not IS_OPENED then if InCombatLockdown() then return; end IS_OPENED = true; CVarTemp:BackUp(); Toolbar:ShowUI("Narcissus"); ViewProfile:SaveView(5); CameraUtil:UpdateParameters(); CameraMover:MakeActive(); SetCVar("test_cameraDynamicPitch", 1); local speedFactor = 180/(GetCVar("cameraYawMoveSpeed") or 180); ZoomFactor.toSpeed = speedFactor*ZoomFactor.toSpeedBasic; ZoomFactor.fromSpeed = speedFactor*ZoomFactor.fromSpeedBasic; EL:Show(); CameraMover:Pitch(); After(0, function() Toolbar:Expand(true); local toolbarButton = GetToolbarButtonByButtonType("Mog"); toolbarButton:OnClick(); SlotController:LazyRefresh(); local Vignette = Narci_Vignette; Vignette.VignetteLeft:SetAlpha(VIGNETTE_ALPHA); Vignette.VignetteRight:SetAlpha(VIGNETTE_ALPHA); Vignette.VignetteRightSmall:SetAlpha(0); FadeFrame(Vignette, 0.8, 1); Vignette.VignetteRight.animIn:Play(); Vignette.VignetteLeft.animIn:Play(); if UIParent:IsShown() then UIPA.endAlpha = 0; UIPA:Show(); end After(0, function() After(0.5, function() SetUIVisibility(false); --Same as pressing Alt + Z After(0.3, function() UIParent:SetAlpha(1); end) end) end) end) Narci.isActive = true; MsgAlertContainer:Display(); end NarciAPI.UpdateSessionTime(); end ------------------------------------------------------ ------------------Photo Mode Controller--------------- ------------------------------------------------------ function Narci_KeyListener_OnEscapePressed(self) if IS_OPENED then MiniButton:Click(); if self then self:SetPropagateKeyboardInput(false); After(0, function() self:SetPropagateKeyboardInput(true); end); end end end local function UseXmogLayout() MOG_MODE_OFFSET = 0.2; NarciPlayerModelFrame1.xmogMode = 2; if Narci_Character:IsVisible() then FadeFrame(NarciModel_RightGradient, 0.5, 1); end Narci_ModelContainer:Show(); Narci_PlayerModelAnimIn:Show(); Narci_PlayerModelGuideFrame.VignetteRightSmall:Show(); Narci_GuideLineFrame.VirtualLineRight.AnimFrame.toX = -600; Narci_GuideLineFrame.VirtualLineRight.AnimFrame:Show(); After(0, function() if not IsMounted() then CameraMover:Pitch(); CameraMover:ZoomIn(ZOOM_IN_VALUE_MOG); --ajust by raceID else CameraMover:ZoomIn(8); --ajust by raceID end end) end local function ActivateMogMode() Narci_GuideLineFrame.VirtualLineRight.AnimFrame:Hide(); if MOG_MODE then FadeFrame(Narci_Attribute, 0.5, 0) FadeFrame(Narci_XmogNameFrame, 0.2, 1, 0) MOG_MODE_OFFSET = 0.2; NarciPlayerModelFrame1.xmogMode = 2; MsgAlertContainer:Display(); UseXmogLayout(); else Narci_GuideLineFrame.VirtualLineRight.AnimFrame.toX = Narci_GuideLineFrame.VirtualLineRight.AnimFrame.defaultX if Toolbar:IsShown() then Narci_GuideLineFrame.VirtualLineRight.AnimFrame:Show() FadeFrame(Narci_Attribute, 0.5, 1) local zoom = GetCameraZoom() SmoothShoulderCVar(SHOULDER_FACTOR_1*zoom + SHOULDER_FACTOR_2) end FadeFrame(Narci_XmogNameFrame, 0.2, 0) ShowAttributeButton(); MOG_MODE_OFFSET = 0; MsgAlertContainer:Hide(); RadarChart:SetValue(); end end local function UpdateXmogName(SpecOnly) local frame = Narci_XmogNameFrame; local currentSpec = GetSpecialization(); if not currentSpec then return; end local IsSpellKnown = IsSpellKnown; local token = 159243; local ArmorType; if not SpecOnly then Narci_SetPlayerName(frame); if IsSpellKnown(76273) or IsSpellKnown(106904) or IsSpellKnown(202782) or IsSpellKnown(76275) then --ArmorType = "Leather" token = 159300; elseif IsSpellKnown(76250) or IsSpellKnown(76272) or IsSpellKnown(366522) then --ArmorType = "Mail" token = 159371; elseif IsSpellKnown(76276) or IsSpellKnown(76277) or IsSpellKnown(76279) then --ArmorType = "Cloth" token = 159243; elseif IsSpellKnown(76271) or IsSpellKnown(76282) or IsSpellKnown(76268) then --ArmorType = "Plate" token = 159418; end local _; _, _, ArmorType = GetItemInfoInstant(token); frame.armorType = ArmorType; end --Leather 76273 Mail 76250 Cloth 76276 76279 Plate 76271 76282 ArmorType = frame.armorType or ArmorType or "ArmorType"; local _, currentSpecName = GetSpecializationInfo(currentSpec); currentSpecName = currentSpecName or ""; local className, englishClass, _ = UnitClass("player"); local _, _, _, rgbHex = GetClassColor(englishClass); frame.ArmorString:SetText("|cFFFFD100"..ArmorType.."|r".." | ".."|c"..rgbHex..currentSpecName.." "..className.."|r"); end local function GetWowHeadDressingRoomURL() local slot; local ItemList = {}; for i = 1, #xmogTable do slot = xmogTable[i][1]; if SLOT_TABLE[slot] and SLOT_TABLE[slot].itemID then ItemList[slot] = {SLOT_TABLE[slot].itemID, SLOT_TABLE[slot].bonusID}; end end return NarciAPI.EncodeItemlist(ItemList); end local function CopyTexts(textFormat, includeID) local texts = Narci_XmogNameFrame.PlayerName:GetText() or "My Transmog"; textFormat = textFormat or "text"; local source; if textFormat == "text" then texts = texts.."\n" for i = 1, #xmogTable do local index = xmogTable[i][1] if SLOT_TABLE[index] and SLOT_TABLE[index].Name:GetText() then local text = "|cFFFFD100"..xmogTable[i][2]..":|r "..(SLOT_TABLE[index].Name:GetText() or " "); if includeID and SLOT_TABLE[index].itemID then text = text.." |cFFacacac"..SLOT_TABLE[index].itemID.."|r"; end source = SLOT_TABLE[index].ItemLevel:GetText(); if source and source ~= " " then text = text.." ("..source..")" end if text then texts = texts.."\n"..text; end end end elseif textFormat == "reddit" then texts = "|cFF959595**|r"..texts.."|cFF959595**\n\n| Slot | Name | Source |".."\n".."|:--|:--|:--|" for i=1, #xmogTable do local index = xmogTable[i][1] if SLOT_TABLE[index] and SLOT_TABLE[index].Name:GetText() then local text = "|cFF959595| |r|cFFFFD100"..xmogTable[i][2].."|r |cFF959595| |r" if includeID and SLOT_TABLE[index].itemID then text = text.."|cFF959595[|r"..(SLOT_TABLE[index].Name:GetText() or " ").."|cFF959595](https://www.wowhead.com/item=|r"..SLOT_TABLE[index].itemID..")|r" else text = text..(SLOT_TABLE[index].Name:GetText() or " ") end source = SLOT_TABLE[index].ItemLevel:GetText() if source then text = text.." |cFF959595| |r|cFF40C7EB"..source.."|r |cFF959595| |r" else text = text.." |cFF959595| |r" end if text then texts = texts.."\n"..text; end end end texts = texts.."\n"; else if textFormat == "wowhead" then texts = "|cFF959595[table border=2 cellpadding=4]\n[tr][td colspan=3 align=center][b]|r"..texts.."|r|cFF959595[/b][/td][/tr]\n[tr][td align=center]Slot[/td][td align=center]Name[/td][td align=center]Source[/td][/tr]|r" elseif textFormat == "nga" then texts = "|cFF959595[table]\n[tr][td colspan=3][align=center][b]|r"..texts.."|r|cFF959595[/b][/align][/td][/tr]\n[tr][td][align=center]部位[/align][/td][td][align=center]装备名称[/align][/td][td][align=center]来源[/align][/td][/tr]|r" elseif textFormat == "mmo-champion" then texts = "|cFF959595[table=\"width: 640, class: grid\"]\n[tr][td=\"colspan: 3\"][center][b]|r"..texts.."|r|cFF959595[/b][/center][/td][/tr]\n[tr][td][center]Slot[/center][/td][td][center]Name[/center][/td][td][center]Source[/center][/td][/tr]|r" end for i=1, #xmogTable do local index = xmogTable[i][1] if SLOT_TABLE[index] and SLOT_TABLE[index].Name:GetText() then local text = "|cFF959595[tr][td]|r".."|cFFFFD100"..xmogTable[i][2].."|r|cFF959595[/td][td]|r" if includeID and SLOT_TABLE[index].itemID then if textFormat == "wowhead" then text = text.."[item="..SLOT_TABLE[index].itemID.."|r|cFF959595][/td]|r" elseif textFormat == "nga" then text = text.."|cFF959595[url=https://www.wowhead.com/item="..SLOT_TABLE[index].itemID.."]|r"..(SLOT_TABLE[index].Name:GetText() or " ").."|cFF959595[/url][/td]|r" elseif textFormat == "mmo-champion" then text = text.."|cFF959595[url=https://www.wowdb.com/items/"..SLOT_TABLE[index].itemID.."]|r"..(SLOT_TABLE[index].Name:GetText() or " ").."|cFF959595[/url][/td]|r" end else text = text..(SLOT_TABLE[index].Name:GetText() or " ").."|r|cFF959595[/td]|r" end source = SLOT_TABLE[index].ItemLevel:GetText() if source then text = text.."|cFF959595[td]|r|cFF40C7EB"..source.."|r|cFF959595[/td]|r" else text = text.."|cFF959595[td] [/td]|r" end if text then texts = texts.."\n"..text.."|cFF959595[/tr]|r" end end end texts = texts.."\n|cFF959595[/table]|r" ----- if textFormat == "wowhead" then texts = GetWowHeadDressingRoomURL(); end end return texts; end local function Narci_XmogButton_OnClick(self) MoveViewRightStop(); EquipmentFlyoutFrame:Hide(); MOG_MODE = not MOG_MODE; self.isOn = MOG_MODE; if self.isOn then FadeFrame(Narci_VignetteRightSmall, 0.5, NarcissusDB.VignetteStrength); FadeFrame(Narci_VignetteRightLarge, 0.5, 0); Narci_SnowEffect(false); PlayLetteboxAnimation("OUT"); Narci_XmogNameFrame.PlayerName:SetText(Narci_PlayerInfoFrame.PlayerName:GetText()) Toolbar.TransmogListFrame:ShowUI(); Toolbar.showTransmogFrame = true; else --Exit Xmog mode Toolbar.TransmogListFrame:Hide(); Toolbar.showTransmogFrame = nil; FadeFrame(Narci_VignetteRightSmall, 0.5, 0); FadeFrame(Narci_VignetteRightLarge, 0.5, NarcissusDB.VignetteStrength); Narci_SnowEffect(true); PlayLetteboxAnimation(); if Narci_ModelContainer:IsVisible() then if IS_OPENED then CameraMover:Pitch(); else --SmoothShoulderCVar(0); end Narci_PlayerModelAnimOut:Show() After(0.4, function() FadeFrame(NarciPlayerModelFrame1, 0.5 , 0); end) end Narci_ModelSettings:Hide(); if not Narci_ExitConfirmationDialog:IsShown() then Narci.showExitConfirm = false; end if (not InCombatLockdown()) and (not Narci_Character:IsShown()) then Narci_Character:Show(); Narci_Character:SetAlpha(1); StatsUpdator:Gradual(); end end SlotController:LazyRefresh(); After(0.1, function() ActivateMogMode(); end) self:UpdateIcon(); end addon.OverrideToolbarButtonOnClickFunc("Mog", Narci_XmogButton_OnClick); addon.OverrideToolbarButtonOnInitFunc("Mog", function(self) if MOG_MODE then self.isOn = true; self:UpdateIcon(); end end); Toolbar.TransmogListFrame.getItemListFunc = CopyTexts; function Narci_SetButtonColor(self) ColorUtil:SetWidgetColor(self.Color); ColorUtil:SetWidgetColor(self.HighlightColor); end function CameraMover:ShowFrame() local GuideLineFrame = Narci_GuideLineFrame; local VirtualLineRight = GuideLineFrame.VirtualLineRight; VirtualLineRight.AnimFrame:Hide(); local offsetX = GuideLineFrame.VirtualLineRight.AnimFrame.defaultX or -496; VirtualLineRight:SetPoint("RIGHT", offsetX + 120, 0); if MOG_MODE then FadeFrame(Narci_Attribute, 0.4, 0) else VirtualLineRight.AnimFrame.toX = offsetX; FadeFrame(Narci_Attribute, 0.4, 1, 0); end VirtualLineRight.AnimFrame:Show(); GuideLineFrame.VirtualLineLeft.AnimFrame:Show(); PlayAttributeAnimation(); After(0, function() FadeFrame(Narci_Character, 0.6, 1); end) Narci_SnowEffect(true); end ------Photo Mode Toolbar------ hooksecurefunc("SetUIVisibility", function(state) if IS_OPENED then --when Narcissus hide the UI if state then MsgAlertContainer:SetDND(true); Toolbar:UseLowerLevel(true); else local bar = Toolbar; Toolbar.ExitButton:Show(); if not bar:IsShown() then bar:Show(); end MsgAlertContainer:SetDND(false); bar:UseLowerLevel(false); end else --when user hide the UI manually if state then --When player closes the full-screen world map, SetUIVisibility(true) fires twice, and WorldMapFrame:IsShown() returns true and false. --Thus, use this VisibilityTracker instead to check if WorldMapFrame has been closed recently. --WorldMapFrame.VisibilityTracker.state MsgAlertContainer:Hide(); if Narci_Character:IsShown() then return; end if not GetKeepActionCam() then After(0.6, function() ConsoleExec( "actioncam off" ); end) end Toolbar:HideUI(); else local bar = Toolbar; if not bar:IsShown() then CVarTemp.shoulderOffset = GetCVar("test_cameraOverShoulder"); end bar:ShowUI("Blizzard"); end end end) do --Slash Command local commandName = "narci"; local commandAlias = "narcissus"; local function callback(msg) if not msg then msg = ""; end msg = string.lower(msg); if msg == "" then MiniButton:Click(); elseif msg == "minimap" then MiniButton:EnableButton(); print("Minimap button has been re-enabled."); elseif msg == "itemlist" then DressUpFrame_Show(DressUpFrame); if NarciDressingRoomOverlay then NarciDressingRoomOverlay:ShowItemList(); end elseif msg == "resetposition" then MiniButton:ResetPosition(); elseif string.find(msg, "/outfit") then Narci:LoadOutfitSlashCommand(msg); --/narci /outfit v1 50109,182541,0,77345,182521,2633,0,181613,182527,79067,182538,84323,80378,-1,0,77903,0 else local color = "|cff40C7EB"; print(" "); print(color.."Show Minimap Button:|r /narci minimap"); print(color.."Reset Minimap Button Position:|r /narci resetposition"); print(color.."Copy Item List:|r /narci itemlist"); end end --RegisterNewSlashCommand(callback, commandName, commandAlias); ---- Alternative method to avoid slash command taint if ChatEdit_HandleChatType then local VALID_COMMANDS = { ["/NARCI"] = true, ["/NARCISSUS"] = true, }; local c, m; hooksecurefunc("ChatEdit_HandleChatType", function(editBox, msg, command, send) c = command; m = msg; if send == 1 then if c and VALID_COMMANDS[c] then callback(m); end c = nil; m = nil; end end); end --local f = CreateFrame("Frame"); --f:RegisterEvent("EXECUTE_CHAT_LINE"); --f:SetScript("OnEvent", function(self, event, line) -- print(line) --end) end ---------------- --3D Animation-- local function InitializeAnimationContainer(frame, SequenceInfo, TargetFrame) frame.OppoDirection = false; frame.t = 0 frame.totalTime = 0; frame.Index = 1; frame.Pending = false; frame.IsPlaying = false; frame.SequenceInfo = SequenceInfo; frame.Target = TargetFrame end local function AnimationContainer_OnHide(self) self.totalTime = 0; self.TimeSinceLastUpdate = 0; self.OppoDirection = not self.OppoDirection if self.Index <= 0 then self.Index = 0; end end local PlayAnimationSequence = NarciAPI_PlayAnimationSequence; local ASC2 = CreateFrame("Frame", "AnimationSequenceContainer_Heart"); ASC2.Delay = 5; ASC2.IsPlaying = false; ASC2:Hide(); local function Generic_AnimationSequence_OnUpdate(self, elapsed) if self.Pending then return; end self.totalTime = self.totalTime + elapsed; if (not self.OppoDirection and self.totalTime < self.Delay) and (not self.IsPlaying) then return; elseif not self.IsPlaying then if not self.OppoDirection then --box closing FadeFrame(Narci_HeartofAzeroth_AnimFrame, 0.25, 1) After(0.3, function() Narci_HeartofAzeroth_AnimFrame.Background:SetAlpha(1); Narci_HeartofAzeroth_AnimFrame.Quote:SetAlpha(1); Narci_HeartofAzeroth_AnimFrame.SN:SetAlpha(1); end) end self.IsPlaying = true; end self.t = self.t + elapsed; if self.t >= 0.01666 then self.t = 0; if self.OppoDirection then self.Index = self.Index - 1; else self.Index = self.Index + 1; end if not PlayAnimationSequence(self.Index, self.SequenceInfo, self.Target) then self:Hide() self.IsPlaying = false; if not self.OppoDirection then Narci_HeartofAzeroth_AnimFrame.Background:SetAlpha(0); Narci_HeartofAzeroth_AnimFrame.Quote:SetAlpha(0); Narci_HeartofAzeroth_AnimFrame.SN:SetAlpha(0); FadeFrame(Narci_HeartofAzeroth_AnimFrame, 0.25, 0) end return; end end end ASC2:SetScript("OnUpdate", Generic_AnimationSequence_OnUpdate); ASC2:SetScript("OnHide", AnimationContainer_OnHide); local RACE_PORTRAIT_CAMERA = { --For 3D Portait on the top-left --[RaceID] = {[GenderID] = {offsetX, offsetY, distance, angle, CameraIndex, {animation} }} [1] = {[2] = {10, -10, 0.75, false, 0}, --Human Male √ [3] = {12, -10, 0.71, false, 1, 2}, -- Female √ }, [2] = {[2] = {12, -16, 1.3, 1.1, 0}, --Orcs Male √ [3] = {18, -16, 0.72, 1.1, 0, 1}, -- Female √ }, [3] = {[2] = {14, -20, 0.88, 0.9, 1}, --Dwarf Male [3] = {2, -12, 0.75, false, 0}, -- Female √ }, [4] = {[2] = {16, -5, 1, 1.5, 0}, --NE Male [3] = {8, -10, 0.75, false, 0}, -- Female }, [5] = {[2] = {16, -6, 0.6, 0.8, 1}, --UD Male [3] = {10, -6, 0.68, 1.0, 1, 3}, -- Female }, [6] = {[2] = {24, -15, 3, 0.6, 1}, --Tauren Male √ [3] = {24, -8, 1.8, false, 1}, -- Female }, [7] = {[2] = {10, -14, 1, 0.5, 1}, --Gnome Male [3] = {14, -14, 0.8, 0.55, 0}, -- Female }, [8] = {[2] = {16, -4, 1.15, 1.3, 0}, --Troll Male √ [3] = {18, -10, 0.75, 1.3, 0}, -- Female √ }, [9] = {[2] = {8, 0, 0.8, 0.6, 0}, --Goblin Male √ [3] = {20, -14, 0.85, 0.8, 0}, -- Female √ }, [10] = {[2] = {8, -5, 0.75, 1.2, 0}, -- BE Male [3] = {0, -4, 0.53, 1.1, 0}, -- Female }, [11] = {[2] = {15, -12, 1, 1.4, 0}, -- Goat Male [3] = {10, -10, 0.66, 1.4, 0}, -- Female }, [22] = {[2] = {10, -10, 0.75, false, 0}, --Worgen Male Human Form [3] = {12, -12, 0.72, 1.1, 1}, --Female √ }, [24] = {[2] = {14, 0, 1.1, 1.15, 0}, --Pandaren Male √ [3] = {12, 4, 1.0, 1.1, 0}, --Female }, [27] = {[2] = {24, -10, 0.72, false, 0}, --Highborne Male √ [3] = {16, -4, 0.70, false, 0}, --Female }, [28] = {[2] = {24, -15, 2.4, 0.6, 0}, --Tauren Male √ [3] = {4, -10, 0.62, false, 0}, -- Female }, [128] = {[2] = {18, -18, 1.4, 0.85, 0}, --Worgen Male Wolf Form [3] = {18, -15, 1.1, 1.25, 0}, --Female √ }, [31] = {[2] = {4, 0, 1.2, 1.6, 0}, --Zandalari Male √ [3] = {18, -12, 0.95, 1.6, 0}, -- Female √ }, [32] = {[2] = {10, -16, 1.25, 1.15, 1}, --Kul'tiran Male √ [3] = {12, -10, 0.9, 1.5, 0}, --Female }, [36] = {[2] = {14, -10, 1.2, 1.2, 0, 2}, --Mag'har Male [3] = {20, -20, 0.75, false, 0, 1}, -- Female √ }, [35] = {[2] = {18, -8, 0.7, false, 1, 2}, --Vulpera Male [3] = {18, -8, 0.7, false, 1, 2}, -- Female √ }, [52] = {[2] = {18, -18, 1.4, false, 1}, --Dracthyr [3] = {18, -18, 1.4, false, 1}, }, [520] = {[2] = {8, -5, 0.75, 1.2, 0}, --Dracthyr Visage Male [3] = {12, -10, 0.71, false, 1, 2}, -- Female √ }, } function Narci_PortraitPieces_OnLoad(self) local unit = "player"; local a1, a2, a3; local ModelPieces = self.Pieces; local _, _, raceID = UnitRace(unit); local GenderID = UnitSex(unit); --print("raceID: "..raceID) if raceID == 34 then --DarkIron raceID = 3; elseif raceID == 29 then --VE raceID = 10 elseif raceID == 28 then --Highmountain raceID = 6 elseif raceID == 30 then --LightForged raceID = 11 elseif raceID == 25 or raceID == 26 then --Pandaren A|H raceID = 24 elseif raceID == 37 then --Mechagnome raceID = 7; elseif raceID == 22 then --Worgen local inHumanForm = IsPlayerInAlteredForm(); if not inHumanForm then raceID = 128; end elseif raceID == 52 or raceID == 70 then local inVisageForm = IsPlayerInAlteredForm(); if not inVisageForm then raceID = 52; else raceID = 520; end end local model; if RACE_PORTRAIT_CAMERA[raceID] and RACE_PORTRAIT_CAMERA[raceID][GenderID] then if Narci_FigureModelReference then Narci_FigureModelReference:SetPoint("CENTER", RACE_PORTRAIT_CAMERA[raceID][GenderID][1], RACE_PORTRAIT_CAMERA[raceID][GenderID][2]) end for i = 1, #ModelPieces do model = ModelPieces[i]; TransitionAPI.SetModelByUnit(model, "player"); model:SetCamera(RACE_PORTRAIT_CAMERA[raceID][GenderID][5]); model:MakeCurrentCameraCustom(); if RACE_PORTRAIT_CAMERA[raceID][GenderID][3] then model:SetCameraDistance(RACE_PORTRAIT_CAMERA[raceID][GenderID][3]) end if RACE_PORTRAIT_CAMERA[raceID][GenderID][4] then a1, a2, a3 = model:GetCameraPosition(); model:SetCameraPosition(a1, a2, RACE_PORTRAIT_CAMERA[raceID][GenderID][4]) end if RACE_PORTRAIT_CAMERA[raceID][GenderID][6] then model:SetAnimation(2, RACE_PORTRAIT_CAMERA[raceID][GenderID][6]) end end else for i = 1, #ModelPieces do model = ModelPieces[i]; model:SetCamera(0); model:MakeCurrentCameraCustom(); a1, a2, a3 = model:GetCameraPosition(); model:SetCameraPosition(a1, a2, 1.1); end end for i = 1, #ModelPieces do model = ModelPieces[i]; model:SetFacing(-math.pi/24) --Front pi/6 model:SetAnimation(804, 1); TransitionAPI.SetModelLight(model, true, false, - 0.44699833180028 , 0.72403680806459 , -0.52532198881773, 0.8, 0.7, 0.5, 0.8, 1, 0.8, 0.8, 0.8) model:UndressSlot(1); model:UndressSlot(3); model:UndressSlot(15); --Remove the cloak model:UndressSlot(16); model:UndressSlot(17); end end --Static Events EL:RegisterEvent("PLAYER_ENTERING_WORLD"); EL:RegisterUnitEvent("UNIT_NAME_UPDATE", "player"); EL:RegisterEvent("PLAYER_AVG_ITEM_LEVEL_UPDATE"); EL:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED"); EL:RegisterEvent("PLAYER_LEVEL_CHANGED"); --These events might become deprecated in future expansions EL:RegisterEvent("COVENANT_CHOSEN"); EL:SetScript("OnEvent",function(self, event, ...) --print(event) if event == "PLAYER_ENTERING_WORLD" then self:UnregisterEvent(event); After(2, function() Narci_AliasButton_SetState(); StatsUpdator:Instant(); RadarChart:SetValue(0,0,0,0,1); UpdateXmogName(); end) local AnimSequenceInfo = Narci.AnimSequenceInfo; InitializeAnimationContainer(ASC2, AnimSequenceInfo["Heart"], Narci_HeartofAzeroth_AnimFrame.Sequence) local HeartSerialNumber = strsub(UnitGUID("player"), 8, 15); Narci_HeartofAzeroth_AnimFrame.SN:SetText("No."..HeartSerialNumber); Narci_HeartofAzeroth_AnimFrame.Quote:SetText(L["Heart Azerite Quote"]); UpdateXmogName(); SetCVar("CameraKeepCharacterCentered", 0); --CameraMover:SetBlend(NarcissusDB.CameraTransition); --Load in Settings.lua DefaultTooltip = NarciGameTooltip; --Created in Module\GameTooltip.lua if not ItemTooltip then ItemTooltip = DefaultTooltip; end DefaultTooltip:SetParent(Narci_Character); DefaultTooltip:SetFrameStrata("TOOLTIP"); DefaultTooltip.offsetX = 4; DefaultTooltip.offsetY = -16; DefaultTooltip:SetIgnoreParentAlpha(true); if IsAddOnLoaded("DynamicCam") then CVarTemp.isDynamicCamLoaded = true; --Check validity if not (DynamicCam.BlockShoulderOffsetZoom and DynamicCam.AllowShoulderOffsetZoom) then return end; hooksecurefunc("Narci_Open", function() if IS_OPENED then DynamicCam:BlockShoulderOffsetZoom(); else DynamicCam:AllowShoulderOffsetZoom(); end end) hooksecurefunc("Narci_OpenGroupPhoto", function() DynamicCam:BlockShoulderOffsetZoom(); end) ViewProfile:Disable(); else if NarcissusDB.CameraSafeMode then local temp = GetCVar("test_cameraOverShoulder"); if tonumber(temp) ~= 0 then --SetCVar("test_cameraOverShoulder", 0); ConsoleExec( "actioncam off" ); NarciAPI.PrintPresetMessage("camera"); end end end After(1.7, function() UpdateCharacterInfoFrame(); if CVarTemp.isDynamicCamLoaded then CameraMover:UpdateMovementMethodForDynamicCam(); else hooksecurefunc("CameraZoomIn", function(increment) if IS_OPENED then UpdateShoulderCVar:Start(-increment); end end) hooksecurefunc("CameraZoomOut", function(increment) if IS_OPENED then UpdateShoulderCVar:Start(increment); end end) end end) elseif event == "PLAYER_EQUIPMENT_CHANGED" then local slotID, isItem = ...; USE_DELAY = false; SlotController:Refresh(slotID); if EquipmentFlyoutFrame:IsShown() and EquipmentFlyoutFrame.slotID then EquipmentFlyoutFrame:DisplayItemsBySlotID(EquipmentFlyoutFrame.slotID, false); end USE_DELAY = true; ItemLevelFrame:AsyncUpdate(); local slot = SLOT_TABLE[slotID]; if slot and slot:IsMouseOver() then slot:Disable(); After(0, function() slot:Enable(); end); end elseif event == "AZERITE_ESSENCE_ACTIVATED" then local neckSlotID = 2; SlotController:Refresh(neckSlotID); --Heart of Azeroth elseif event == "PLAYER_AVG_ITEM_LEVEL_UPDATE" then if not self.pendingItemLevel then self.pendingItemLevel = true; After(0.1, function() -- only want 1 update per 0.1s ItemLevelFrame:UpdateItemLevel(); self.pendingItemLevel = nil; end) end elseif event == "COVENANT_CHOSEN" then local covenantID = ...; ItemLevelFrame:AsyncUpdate(); MiniButton:SetBackground(covenantID); elseif event == "COVENANT_SANCTUM_RENOWN_LEVEL_CHANGED" then local newRenownLevel = ...; ItemLevelFrame:UpdateRenownLevel(newRenownLevel); elseif event == "UNIT_NAME_UPDATE" then local unit = ...; if unit == "player" then UpdateCharacterInfoFrame(); end elseif event == "ACTIVE_TALENT_GROUP_CHANGED" then UpdateCharacterInfoFrame(); UpdateXmogName(true); SlotButtonOverlayUtil:UpdateData(); elseif event == "PLAYER_LEVEL_CHANGED" then local oldLevel, newLevel = ...; UpdateCharacterInfoFrame(newLevel) elseif ( event == "COMBAT_RATING_UPDATE" or event == "UNIT_MAXPOWER" or event == "UNIT_STATS" or event == "UNIT_DAMAGE" or event == "UNIT_ATTACK_SPEED" or event == "UNIT_MAXHEALTH" or event == "UNIT_AURA" ) and Narci.refreshCombatRatings then -- don't refresh stats when equipment set manager is activated StatsUpdator:Instant(); if event == "COMBAT_RATING_UPDATE" then if Narci_Character:IsShown() then RadarChart:AnimateValue(); end end if event == "UNIT_AURA" then local inAlteredForm = IsPlayerInAlteredForm(); if self.wasAlteredForm ~= inAlteredForm then self.wasAlteredForm = inAlteredForm; CameraUtil:OnPlayerFormChanged(0.0); end end elseif event == "PLAYER_TARGET_CHANGED" then RefreshStats(8); --Armor RefreshStats(9); --Damage Reduction elseif event == "UPDATE_SHAPESHIFT_FORM" then CameraUtil:OnPlayerFormChanged(0.1); elseif event == "PLAYER_MOUNT_DISPLAY_CHANGED" then CameraUtil:OnPlayerFormChanged(0.0); elseif event == "PLAYER_REGEN_DISABLED" then if Narci.isAFK and Narci.isActive then --exit when entering combat during AFK mode MiniButton:Click(); Narci:PlayVoice("DANGER"); end elseif event == "PLAYER_STARTED_MOVING" then self:UnregisterEvent(event); MoveViewRightStop(); if Narci.isAFK and Narci.isActive then --exit when entering combat during AFK mode MiniButton:Click(); end elseif event == "PLAYER_STARTED_TURNING" and not MOG_MODE then NarciAR.Turning.radian = GetPlayerFacing(); NarciAR.Turning:Show(); elseif event == "PLAYER_STOPPED_TURNING" and not MOG_MODE then NarciAR.Turning:Hide(); elseif event == "BAG_UPDATE_COOLDOWN" then StatsUpdator:UpdateCooldown(); elseif event == "BAG_UPDATE" then local newTime = GetTime(); if self.lastTime then if newTime > self.lastTime + 0.2 then self.lastTime = newTime; else return end else self.lastTime = newTime; end ItemLevelFrame:AsyncUpdate(0.1); elseif event == "UNIT_INVENTORY_CHANGED" then SlotController:LazyRefresh("temp"); end end) function EL:ToggleDynamicEvents(state) if state then for _, event in ipairs(self.EVENTS_DYNAMIC) do self:RegisterUnitEvent(event); end for _, event in ipairs(self.EVENTS_UNIT) do self:RegisterUnitEvent(event, "player"); end else for _, event in ipairs(self.EVENTS_DYNAMIC) do self:UnregisterEvent(event); end for _, event in ipairs(self.EVENTS_UNIT) do self:UnregisterEvent(event); end end end EL:SetScript("OnShow",function(self) self:ToggleDynamicEvents(true); if NarciAR then NarciAR:Show(); end end) EL:SetScript("OnHide",function(self) self:ToggleDynamicEvents(false); if NarciAR then NarciAR:Hide(); end end) ---------------------------------------------------------------------- --Double-click PaperDoll Button to open Narcissus NarciPaperDollDoubleClickTriggerMixin = {}; local function Narci_DoubleClickTrigger_OnUpdate(self, elapsed) self.t = self.t + elapsed; if self.t > 0.25 then self:SetScript("OnUpdate", nil); end end function NarciPaperDollDoubleClickTriggerMixin:OnLoad() self.t = 0; AssignFrame(); AssignFrame = nil; self:SetScript("OnLoad", nil); self.OnLoad = nil; end function NarciPaperDollDoubleClickTriggerMixin:OnShow() self.t = 0; self:SetScript("OnUpdate", Narci_DoubleClickTrigger_OnUpdate); end function NarciPaperDollDoubleClickTriggerMixin:OnHide() if (self.t < 0.25) and NarcissusDB.EnableDoubleTap then MiniButton:Click(); end end ---------------------------------------------------------------------- function Narci_GuideLineFrame_OnSizing(self, offset) local W; local W0, H = WorldFrame:GetSize(); if (W0 and H) and H ~= 0 then local ratio = floor(W0 / H * 100 + 0.5)/100 ; if ratio == 1.78 then return end self:ClearAllPoints(); self:SetPoint("TOP", UIParent, "TOP", 0, 0); self:SetPoint("BOTTOM", UIParent, "BOTTOM", 0, 0); offset = offset or 0; W = math.min(H / 9 * 16, W0); W = floor(W + 0.5); --print("Original: "..W0.." Calculated: "..W); self:SetWidth(W - offset); else W = self:GetWidth(); end local C = W*0.618; self.VirtualLineRight:SetPoint("RIGHT", C - W +32, 0); self.VirtualLineRight.defaultX = C - W +32; local AnimFrame = self.VirtualLineRight.AnimFrame; AnimFrame.OppoDirection = false; AnimFrame.TimeSinceLastUpdate = 0; AnimFrame.anchorPoint, AnimFrame.relativeTo, AnimFrame.relativePoint, AnimFrame.toX, AnimFrame.toY = AnimFrame:GetParent():GetPoint(); AnimFrame.defaultX = AnimFrame.toX; end NarciFlyoutOverlayMixin = {}; function NarciFlyoutOverlayMixin:In() --FadeFrame(self, 0.2, 1); self:Init(); self.animFrame.toAlpha = 1; self.animFrame:Show(); self:Show(); end function NarciFlyoutOverlayMixin:Out() --FadeFrame(self, 0.2, 0); self:Init(); self.animFrame.toAlpha = 0; self.animFrame:Show(); self:Show(); end function NarciFlyoutOverlayMixin:OnHide() self:SetAlpha(0); self:Hide(); end function NarciFlyoutOverlayMixin:Init() if not self.animFrame then self.animFrame = CreateFrame("Frame", nil, self); self.animFrame:SetScript("OnUpdate", function(f, elapsed) f.t = f.t + elapsed; local alpha; if f.t < 0.25 then alpha = outSine(f.t, f.fromAlpha, f.toAlpha, 0.25); else alpha = f.toAlpha; if alpha <= 0 then self:Hide(); end f:Hide(); end self:SetAlpha(alpha); end); end self.animFrame.t = 0; self.animFrame.fromAlpha = self:GetAlpha(); end function NarciFlyoutOverlayMixin:RaiseFrameLevel(widget) local selfLevel = self:GetFrameLevel(); if self.lastWidget then self.lastWidget:SetFrameLevel(selfLevel - 1); self.lastWidget = nil; end local widgetLevel = widget:GetFrameLevel(); if widgetLevel <= selfLevel then widget:SetFrameLevel(selfLevel + 1); self.lastWidget = widget; end end Narci.GetEquipmentSlotByID = function(slotID) return SLOT_TABLE[slotID] end; Narci.RefreshSlot = function(slotID) SlotController:Refresh(slotID) return SLOT_TABLE[slotID] end; Narci.RefreshAllSlots = SlotController.RefreshAll; Narci.RefreshAllStats = StatsUpdator.Instant; function Narci:SetItemTooltipStyle(id) end function Narci:CloseCharacterUI() if IS_OPENED then Narci_Open(); end end do local SettingFunctions = addon.SettingFunctions; function SettingFunctions.SetItemTooltipStyle(id, db) if id == nil then id = db["ItemTooltipStyle"]; end if id == 2 then ItemTooltip = NarciGameTooltip; else ItemTooltip = NarciEquipmentTooltip; end NarciEquipmentTooltip:SetParent(Narci_Character); end function SettingFunctions.SetVignetteStrength(alpha, db) if alpha == nil then alpha = db["VignetteStrength"]; end alpha = tonumber(alpha) or 0.5; VIGNETTE_ALPHA = alpha; Narci_Vignette.VignetteLeft:SetAlpha(alpha); Narci_Vignette.VignetteRight:SetAlpha(alpha); Narci_Vignette.VignetteRightSmall:SetAlpha(alpha); Narci_PlayerModelGuideFrame.VignetteRightSmall:SetAlpha(alpha); end function SettingFunctions.SetUltraWideFrameOffset(offset, db) --A positive offset expands the reference frame. if not offset then offset = db["BaseLineOffset"]; offset = tonumber(offset) or 0 end Narci_GuideLineFrame_OnSizing(Narci_GuideLineFrame, -offset); end function SettingFunctions.ShowDetailedStats(state, db) if state == nil then state = db["DetailedIlvlInfo"]; end if Narci_Attribute:IsVisible() then if state then FadeFrame(Narci_DetailedStatFrame, 0.5, 1); FadeFrame(RadarChart, 0.5, 1); FadeFrame(Narci_ConciseStatFrame, 0.5, 0); else FadeFrame(Narci_DetailedStatFrame, 0.5, 0); FadeFrame(RadarChart, 0.5, 0); FadeFrame(Narci_ConciseStatFrame, 0.5, 1); end else if state then FadeFrame(Narci_DetailedStatFrame, 0, 1); FadeFrame(RadarChart, 0, 1); FadeFrame(Narci_ConciseStatFrame, 0, 0); else FadeFrame(Narci_DetailedStatFrame, 0, 0); FadeFrame(RadarChart, 0, 0); FadeFrame(Narci_ConciseStatFrame, 0, 1); end end Narci_ItemLevelFrame:ToggleExtraInfo(state); Narci_ItemLevelFrame.showExtraInfo = state; Narci_NavBar:SetMaximizedMode(state); end function SettingFunctions.SetCharacterUIScale(scale, db) if not scale then scale = db["GlobalScale"]; end scale = tonumber(scale) or 1; NarciScreenshotToolbar:SetDefaultScale(scale); Narci_Character:SetScale(scale); Narci_Attribute:SetScale(scale); NarciTooltip:SetScale(scale); end function SettingFunctions.SetItemNameTextHeight(height, db) if not height then height = db["FontHeightItemName"]; end height = tonumber(height) or 10; local font, _, flag = SLOT_TABLE[1].Name:GetFont(); for id, slotButton in pairs(SLOT_TABLE) do slotButton.Name:SetFont(font, height, flag); slotButton:UpdateGradientSize(); end end function SettingFunctions.SetItemNameTextWidth(width, db) if not width then width = db["ItemNameWidth"]; end width = tonumber(width) or 200; if width >= 200 then width = 512; end for id, slotButton in pairs(SLOT_TABLE) do slotButton.Name:SetWidth(width); slotButton.ItemLevel:SetWidth(width); slotButton:UpdateGradientSize(); end end function SettingFunctions.SetItemNameTruncated(state, db) if state == nil then state = db["TruncateText"]; end local maxLines; if state then maxLines = 1; else maxLines = 2; end for id, slotButton in pairs(SLOT_TABLE) do slotButton.Name:SetMaxLines(maxLines); slotButton.ItemLevel:SetMaxLines(maxLines); slotButton.Name:SetWidth(slotButton.Name:GetWidth()+1) slotButton.Name:SetWidth(slotButton.Name:GetWidth()-1) slotButton.ItemLevel:SetWidth(slotButton.Name:GetWidth()+1) slotButton.ItemLevel:SetWidth(slotButton.Name:GetWidth()-1) slotButton:UpdateGradientSize(); end end function SettingFunctions.UseCameraTransition(state, db) if state == nil then state = db["CameraTransition"]; end CameraMover:SetBlend(state); end function SettingFunctions.EnableCameraSafeMode(state, db) if state == nil then state = db["CameraSafeMode"]; end CVarTemp.cameraSafeMode = state; end function SettingFunctions.SetDefaultZoomClose(state, db) if state == nil then state = db["UseBustShot"]; end if state then CAM_DISTANCE_INDEX = 1; else CAM_DISTANCE_INDEX = 4; end end function SettingFunctions.EnableMissingEnchantAlert(state, db) if state == nil then state = db["MissingEnchantAlert"]; end --only enabled when player reach max level if not NarciAPI.IsPlayerAtMaxLevel() then state = false; end SHOW_MISSING_ENCHANT_ALERT = state; SlotButtonOverlayUtil:SetEnabled(state); SlotController:ClearCache(); if Narci_Character and Narci_Character:IsShown() then SlotController:LazyRefresh(); end end end --[[ C_BarberShop.GetAvailableCustomizations(); /run BarberShopFrame:SetPropagateKeyboardInput(true) CharCustomizeFrame:SetCustomizationChoice hooksecurefunc(CharCustomizeFrame, "SetCustomizationChoice", function(optionID, choiceID) print("Set ",optionID, choiceID) end) hooksecurefunc(CharCustomizeFrame, "PreviewCustomizationChoice", function(optionID, choiceID) print("Preview ", optionID, choiceID) end) Blizzard_CharacterCustomize Blizzard_BarbershopUI slotID shoulder ~ 3 C_Transmog.SetPending(self.transmogLocation, sourceID, self.activeCategory); WardrobeCollectionFrame.ItemsCollectionFrame:SelectVisual() /run WardrobeCollectionFrame.ItemsCollectionFrame.RightShoulderCheckbox:Show(); /run GetMouseFocus().transmogLocation = TransmogUtil.GetTransmogLocation(3, 0, 0) --96875 New APIs: CenterCamera(); /run CenterCamera(); --]] --Ember Court Correspondence --https://wowpedia.fandom.com/wiki/Quill_of_Correspondence --[[ function SaveCurrentMail() local m = OpenMailBodyText:GetTextData(); m.subject = OpenMailSubject:GetText(); NarciDevToolOutput.mail = m; end --]]