--[[ This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/. --]] --Settings storaged in NarcissusDB local _, addon = ... local MsgAlertContainer = addon.MsgAlertContainer; local Narci = Narci; Narci.refreshCombatRatings = true; local slotTable = {}; local statTable = {}; local statTable_Short = {}; local L = Narci.L; local VIGNETTE_ALPHA = 0.5; local IS_OPENED = false; --Addon was opened by clicking local MOG_MODE = false; local xmogMode = 0; -- 0 off 1 "Texts Only" 2 "Texts & Model" local GetItemEnchantID = NarciAPI.GetItemEnchantID; local GetItemEnchantText = NarciAPI.GetItemEnchantText; local EnchantInfo = Narci.EnchantData; --Bridge/GearBonus.lua local IsItemSourceSpecial = NarciAPI.IsItemSourceSpecial; local Narci_LetterboxAnimation = NarciAPI_LetterboxAnimation; local SmartFontType = NarciAPI.SmartFontType; local LanguageDetector = NarciAPI.LanguageDetector; local IsItemSocketable = NarciAPI.IsItemSocketable; local SetBorderTexture = NarciAPI.SetBorderTexture; local GetBorderArtByItemID = NarciAPI.GetBorderArtByItemID; local DoesItemHaveDomationSocket = NarciAPI.DoesItemHaveDomationSocket; local GetDominationBorderTexture = NarciAPI.GetDominationBorderTexture; local GetItemDominationGem = NarciAPI.GetItemDominationGem; local GetVerticalRunicLetters = NarciAPI.GetVerticalRunicLetters; local GetTemporaryItemBuff = NarciAPI.GetTemporaryItemBuff; local FadeFrame = NarciFadeUI.Fade; --local GetCorruptedItemAffix = NarciAPI_GetCorruptedItemAffix; local Narci_AlertFrame_Autohide = Narci_AlertFrame_Autohide; local C_Item = C_Item; local C_TransmogCollection = C_TransmogCollection; local After = C_Timer.After; local ItemLocation = ItemLocation; local GetAlternateFormInfo = C_PlayerInfo.GetAlternateFormInfo or HasAlternateForm; local floor = math.floor; local sin = math.sin; local cos = math.cos; local pi = math.pi; local max = math.max; local UIParent = _G.UIParent; local EquipmentFlyoutFrame; local ItemLevelFrame; local Toolbar; local RadarChart; local MiniButton; 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(); function Narci:UpdateVignetteStrength() local alpha = tonumber(NarcissusDB.VignetteStrength) 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 --[[ 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; function Narci_ShowButtonTooltip(self) DefaultTooltip:Hide(); DefaultTooltip:SetOwner(self, "ANCHOR_NONE"); if not self.tooltipHeadline then return end DefaultTooltip:SetText(self.tooltipHeadline); if self.IsOn then DefaultTooltip:AddLine(self.tooltipLineClose, 1, 1, 1, true); else DefaultTooltip:AddLine(self.tooltipLineOpen, 1 ,1 ,1 ,true); end if self.tooltipSpecial then DefaultTooltip:AddLine(" "); DefaultTooltip:AddLine(self.tooltipSpecial, 0.25, 0.78, 0.92, true); end DefaultTooltip:SetAlpha(0); NarciAPI_ShowDelayedTooltip("BOTTOM", self, "TOP", 0, 2); end function Narci:HideButtonTooltip() DefaultTooltip:Hide(); --DefaultTooltip:SetFrameStrata("TOOLTIP"); end --[[ LibEasing -- -- Original Lua implementations -- from 'EmmanuelOga' -- https://github.com/EmmanuelOga/easing/ -- -- Adapted from -- Tweener's easing functions (Penner's Easing Equations) -- and http://code.google.com/p/tweener/ (jstweener javascript version) -- Disclaimer for Robert Penner's Easing Equations license: TERMS OF USE - EASING EQUATIONS Open source under the BSD License. Copyright © 2001 Robert Penner All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ]] local function linear(t, b, e, d) return (e - b) * t / d + b end local function outSine(t, b, e, d) return (e - b) * sin(t / d * (pi / 2)) + b end local function inOutSine(t, b, e, d) return (b - e) / 2 * (cos(pi * t / d) - 1) + b 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 = GetCVar; local SetCVar = SetCVar; ConsoleExec("pitchlimit 88"); local CVarTemp = {}; function CVarTemp:BackUp() self.ZoomLevel = GetCameraZoom(); self.DynamicPitch = tonumber(GetCVar("test_cameraDynamicPitch")); self.OverShoulder = GetCVar("test_cameraOverShoulder"); self.MusicVolume = GetCVar("Sound_MusicVolume"); 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 Narci.keepActionCam end CVarTemp.OverShoulder = 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.MusicVolume = tonumber(GetCVar("Sound_MusicVolume")); 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 MogModeOffset = 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] = {3.61, 0.1067, -0.02, 5}, --Fly Swift [29] = {3.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"] = {[1] = {8, 1.2495, -4, 5.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 }; local _, _, playerRaceID = UnitRace("player") local playerGenderID = UnitSex("player") local _, _, playerClassID = UnitClass("player"); local distanceIndex = 1; local ZoomInValue = ZoomValuebyRaceID[0][1]; local ZoomInValue_XmogMode = 3.8; local Shoulder_Factor1 = ZoomValuebyRaceID[0][2]; local Shoulder_Factor2 = ZoomValuebyRaceID[0][3]; local function ReIndexRaceID(raceID) if raceID == 25 or raceID == 26 then --Pandaren A|H raceID = 24; elseif raceID == 30 then --Lightforged raceID = 11; elseif raceID == 36 then --Mag'har Orc raceID = 2; elseif raceID == 34 then --DarkIron raceID = 3; elseif raceID == 37 then --Mechagnome raceID = 7; end return raceID end playerRaceID = ReIndexRaceID(playerRaceID) ReIndexRaceID = nil; for raceKey, data in pairs(ZoomValuebyRaceID) do local id = tonumber(raceKey); if id and id > 1 and id ~= playerRaceID then ZoomValuebyRaceID[raceKey] = nil; end end function Narci:InitializeCameraFactors() if NarcissusDB and not NarcissusDB.UseBustShot then distanceIndex = 4; else distanceIndex = 1; end end local function ModifyCameraForMounts() if IsMounted() then local index = "Mounted"; ZoomInValue = ZoomValuebyRaceID[index][1][1]; Shoulder_Factor1 = ZoomValuebyRaceID[index][1][2]; Shoulder_Factor2 = ZoomValuebyRaceID[index][1][3]; else local zoom = ZoomValuebyRaceID[playerRaceID] or ZoomValuebyRaceID[1]; ZoomInValue = zoom[playerGenderID][1]; Shoulder_Factor1 = zoom[playerGenderID][2]; Shoulder_Factor2 = zoom[playerGenderID][3]; ZoomInValue_XmogMode = zoom[playerGenderID][4]; end end local function ModifyCameraForShapeshifter() if IsMounted() then local index = "Mounted"; ZoomInValue = ZoomValuebyRaceID[index][1][1]; Shoulder_Factor1 = ZoomValuebyRaceID[index][1][2]; Shoulder_Factor2 = ZoomValuebyRaceID[index][1][3]; return; end if playerRaceID ~= 22 and playerClassID ~= 11 then --22 Worgen 11 druid local zoom = ZoomValuebyRaceID[playerRaceID] or ZoomValuebyRaceID[1]; ZoomInValue = zoom[playerGenderID][distanceIndex]; Shoulder_Factor1 = zoom[playerGenderID][2]; Shoulder_Factor2 = zoom[playerGenderID][3]; ZoomInValue_XmogMode = zoom[playerGenderID][4]; return; end local raceID_shouldUse = 1; if playerClassID ~= 11 then --Not Druid local _, inAlternateForm = GetAlternateFormInfo(); if not inAlternateForm then --Is curren in wolf form raceID_shouldUse = "Wolf"; else raceID_shouldUse = 1; end ZoomInValue = ZoomValuebyRaceID[raceID_shouldUse][playerGenderID][distanceIndex]; Shoulder_Factor1 = ZoomValuebyRaceID[raceID_shouldUse][playerGenderID][2]; Shoulder_Factor2 = ZoomValuebyRaceID[raceID_shouldUse][playerGenderID][3]; ZoomInValue_XmogMode = ZoomValuebyRaceID[raceID_shouldUse][playerGenderID][4]; return; else --Druid raceID_shouldUse = "Druid"; EL:RegisterEvent("UPDATE_SHAPESHIFT_FORM"); local formID = GetShapeshiftFormID(); if ( not formID ) or ( not ZoomValuebyRaceID[raceID_shouldUse][formID] ) then if playerRaceID == 22 then local _, inAlternateForm = GetAlternateFormInfo(); if not inAlternateForm then --Is curren in wolf form raceID_shouldUse = "Wolf"; else raceID_shouldUse = 1; end else raceID_shouldUse = playerRaceID; end formID = playerGenderID; elseif formID == 31 then local _, GlyphID = GetCurrentGlyphNameForSpell(24858); --Moonkin form with Glyph of Stars use regular configuration if GlyphID and GlyphID == 114301 then local zoom = ZoomValuebyRaceID[playerRaceID] or ZoomValuebyRaceID[1]; ZoomInValue = zoom[playerGenderID][distanceIndex]; Shoulder_Factor1 = zoom[playerGenderID][2]; Shoulder_Factor2 = zoom[playerGenderID][3]; ZoomInValue_XmogMode = zoom[playerGenderID][4]; return; end end ZoomInValue = ZoomValuebyRaceID[raceID_shouldUse][formID][distanceIndex]; Shoulder_Factor1 = ZoomValuebyRaceID[raceID_shouldUse][formID][2]; Shoulder_Factor2 = ZoomValuebyRaceID[raceID_shouldUse][formID][3]; ZoomInValue_XmogMode = ZoomValuebyRaceID[raceID_shouldUse][formID][4]; end end local SmoothShoulder = CreateFrame("Frame"); SmoothShoulder.t = 0; SmoothShoulder.duration = 1; SmoothShoulder:Hide(); SmoothShoulder:SetScript("OnShow", function(self) self.fromPoint = GetCVar("test_cameraOverShoulder"); end); SmoothShoulder:SetScript("OnUpdate", function(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); 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.t = 0; SmoothShoulder.toPoint = toPoint; SmoothShoulder:Show(); end local UpdateShoulderCVar = {}; function UpdateShoulderCVar:Start(increment, clampToZero) if ( not self.pauseUpdate ) then self.zoom = GetCameraZoom(); self.pauseUpdate = true; After(0.1, function() -- Execute after 0.1s self.pauseUpdate = nil; SmoothShoulderCVar(self.zoom * Shoulder_Factor1 + Shoulder_Factor2 + MogModeOffset, clampToZero); end) end self.zoom = self.zoom + increment; end local duration_Lock = 1.5; 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 ---Camera --[[ hooksecurefunc("CameraZoomIn", function(increment) if IS_OPENED and (xmogMode ~= 1) then UpdateShoulderCVar:Start(-increment); end end) hooksecurefunc("CameraZoomOut", function(increment) if IS_OPENED and (xmogMode ~= 1)then UpdateShoulderCVar:Start(increment); end end) --]] local CameraMover = {}; 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.05, function() self:ZoomIn(ZoomInValue); self.pauseUpdate = nil; end); end end function CameraMover:SetBlend(enable) local divisor; if enable then --Smooth duration_Lock = 1.5; duration_Translation = 0.8; divisor = 20; else --Instant duration_Lock = 0.4; duration_Translation = 0.4; divisor = 80; end for k, slot in pairs(statTable) do local delay = (slot:GetID())/divisor; if slot.animIn then slot.animIn.A2:SetStartDelay(delay); end end for k, slot in pairs(statTable_Short) 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 = ZoomInValue or GetCameraZoom(); local shoulderOffset = zoom * Shoulder_Factor1 + Shoulder_Factor2 + MogModeOffset; SetCVar("test_cameraOverShoulder", shoulderOffset); --CameraZoomIn(0.0) --Smooth self:ZoomIn(ZoomInValue); 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(ZoomInValue); 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(ZoomInValue); 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 ------------------------------ ------------------------------ local function ExitFunc() IS_OPENED = false; xmogMode = 0; MogModeOffset = 0; NarciPlayerModelFrame1.xmogMode = 0; EL:Hide(); 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.OverShoulder); 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 CameraFollowStyle = GetCVar("cameraSmoothStyle"); if CameraFollowStyle == "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:Hide(); MsgAlertContainer:Hide(); UIErrorsFrame:Clear(); 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.OverShoulder = 0; SetCVar("test_cameraOverShoulder", 0); SetCVar("cameraViewBlendStyle", 1); ConsoleExec( "actioncam off" ); Narci_ModelContainer:Hide(); Narci_ModelSettings:Hide(); Narci_Character:Hide(); Narci_Attribute:Hide(); Narci_Vignette:Hide(); IS_OPENED = false; xmogMode = 0; MogModeOffset = 0; NarciPlayerModelFrame1.xmogMode = 0; EL:Hide(); end -- Derivative from [[LibDBIcon-1.0]] local MapShapeUtil = {}; MapShapeUtil.allShapes = { ["ROUND"] = {true, true, true, true}, ["SQUARE"] = {false, false, false, false}, ["CORNER-TOPLEFT"] = {false, false, false, true}, ["CORNER-TOPRIGHT"] = {false, false, true, false}, ["CORNER-BOTTOMLEFT"] = {false, true, false, false}, ["CORNER-BOTTOMRIGHT"] = {true, false, false, false}, ["SIDE-LEFT"] = {false, true, false, true}, ["SIDE-RIGHT"] = {true, false, true, false}, ["SIDE-TOP"] = {false, false, true, true}, ["SIDE-BOTTOM"] = {true, true, false, false}, ["TRICORNER-TOPLEFT"] = {false, true, true, true}, ["TRICORNER-TOPRIGHT"] = {true, false, true, true}, ["TRICORNER-BOTTOMLEFT"] = {true, true, false, true}, ["TRICORNER-BOTTOMRIGHT"] = {true, true, true, false}, }; MapShapeUtil.cornerRadius = 10; --Minimap Button Offset function MapShapeUtil:IsAnchoredToMinimap(x, y) local shape = GetMinimapShape and GetMinimapShape() or "ROUND"; if shape == "SQUARE" then local x1, x2 = Minimap:GetLeft(), Minimap:GetRight(); local y1, y2 = Minimap:GetBottom(), Minimap:GetTop(); local offset = self.cornerRadius + 2; x1 = x1 - offset; x2 = x2 + offset; y1 = y1 - offset; y2 = y2 + offset; return (x >= x1 and x <= x2 and y >= y1 and y <= y2) else local r = Minimap:GetWidth() / 2 + self.cornerRadius + 2; local x0, y0 = Minimap:GetCenter(); local d = math.sqrt( (x - x0)^2 + (y - y0)^2 ); return d <= r end end local function MinimapButton_SetAngle(radian) local x, y, q = cos(radian), sin(radian), 1; if x < 0 then q = q + 1 end if y > 0 then q = q + 2 end local minimapShape = GetMinimapShape and GetMinimapShape() or "ROUND"; local quadTable = MapShapeUtil.allShapes[minimapShape]; local w = (Minimap:GetWidth() / 2) + MapShapeUtil.cornerRadius; local h = (Minimap:GetHeight() / 2) + MapShapeUtil.cornerRadius; if quadTable[q] then x, y = x*w, y*h; else local diagRadiusW = math.sqrt(2*(w)^2) - MapShapeUtil.cornerRadius; local diagRadiusH = math.sqrt(2*(h)^2) - MapShapeUtil.cornerRadius; x = math.max(-w, math.min(x*diagRadiusW, w)); y = math.max(-h, math.min(y*diagRadiusH, h)); end MiniButton:SetPoint("CENTER", Minimap, "CENTER", x, y); end NarciMinimapButtonMixin = {}; function NarciMinimapButtonMixin:CreatePanel() local Panel = self.Panel; local button; local buttons = {}; local LOCALIZED_NAMES = {L["Photo Mode"], DRESSUP_FRAME, "Wardrobe", ACHIEVEMENT_BUTTON}; -- CHARACTER_BUTTON, "Character Info" "Dressing Room" "Achievements" local frameNames = {}; frameNames[4] = "Narci_Achievement"; local func = { Narci_OpenGroupPhoto, function() Narci_ShowDressingRoom(); end, nil, --function() Narci_Outfit:Open() end, function() if not Narci_AchievementFrame then Narci.LoadAchievementPanel(); return else Narci_AchievementFrame:SetShown(not Narci_AchievementFrame:IsShown()); end end }; local numButtons = #LOCALIZED_NAMES; local BUTTON_HEIGHT = 24; local offsetY = BUTTON_HEIGHT * (numButtons - 1) / 2; local middleHeight = 48 + (numButtons - 4) * BUTTON_HEIGHT; local button1OffsetY = offsetY - middleHeight/2 + BUTTON_HEIGHT/2 local buttonFrameLevel = Panel:GetFrameLevel() + 1; local ClipFrame = Panel.ClipFrame; ClipFrame:SetFrameLevel(buttonFrameLevel + 1); ClipFrame:ClearAllPoints(); ClipFrame:SetPoint("CENTER", Panel.Middle, "CENTER", 0, offsetY); ClipFrame.Highlight:SetTexture("Interface/AddOns/Narcissus/Art/Minimap/Panel", nil, nil, "TRILINEAR"); ClipFrame.PushedHighlight:SetTexture("Interface/AddOns/Narcissus/Art/Minimap/Panel", nil, nil, "TRILINEAR"); local animHighlight = NarciAPI_CreateAnimationFrame(0.25); animHighlight.object = ClipFrame; Panel:SetHeight(numButtons * BUTTON_HEIGHT + self:GetHeight()); Panel:SetScript("OnLeave", function(frame) if not frame:IsMouseOver() then self:ShowPopup(false); end end) Panel:SetScript("OnHide", function(frame) frame:SetAlpha(0); frame:Hide(); animHighlight:Hide(); ClipFrame:SetPoint("CENTER", Panel.Middle, "CENTER", 0, offsetY); ClipFrame:Hide(); self:UnregisterEvent("GLOBAL_MOUSE_DOWN"); end) ----------------------------------------------------------- animHighlight:SetScript("OnUpdate", function(frame, elapsed) frame.total = frame.total + elapsed; local y = inOutSine(frame.total, frame.fromY, frame.toY, frame.duration); if frame.total >= frame.duration then y = frame.toY; frame:Hide(); end frame.object:SetPoint("CENTER", Panel.Middle, "CENTER", 0, y); end); self.lastIndex = 1; local function UpdateHighlight(buttonIndex) ClipFrame:Show(); if animHighlight:IsShown() then local newDirection; if buttonIndex > self.lastIndex then newDirection = -1; else newDirection = 1; end if newDirection ~= self.lastDirection then animHighlight:Hide(); local _; _, _, _, _, animHighlight.fromY = ClipFrame:GetPoint(); else --animHighlight.total = animHighlight.total / 2; end else local _; _, _, _, _, animHighlight.fromY = ClipFrame:GetPoint(); end animHighlight.toY = offsetY - (buttonIndex - 1)*24; animHighlight:Show(); end function self:IsInBound() for i = 1, numButtons do if buttons[i]:IsMouseOver() then return true end end return false end ----------------------------------------------------------- local panelEntrance = NarciAPI_CreateAnimationFrame(0.25); self.panelEntrance = panelEntrance; panelEntrance.object = Panel.Middle; Panel.Middle:SetHeight(middleHeight); panelEntrance.toHeight = middleHeight; panelEntrance:SetScript("OnUpdate", function(frame, elapsed) frame.total = frame.total + elapsed; local height = outSine(frame.total, frame.fromHeight, frame.toHeight, frame.duration); local buttonDistance = outSine(frame.total, 12, 0, frame.duration); local alpha = math.min(Panel:GetAlpha() + elapsed/frame.duration, 1); if frame.total >= frame.duration then height = frame.toHeight; buttonDistance = 0; alpha = 1; frame:Hide(); end frame.object:SetHeight(height); for i = 1, numButtons do if i == 1 then buttons[i]:SetPoint("TOP", Panel.Middle, "TOP", 0, button1OffsetY + buttonDistance); else buttons[i]:SetPoint("TOP", buttons[i - 1], "BOTTOM", 0, buttonDistance * math.sqrt(i)); end end Panel:SetAlpha(alpha); end) Panel:SetScript("OnShow", function() panelEntrance.total = 0; if panelEntrance:IsShown() then panelEntrance.fromHeight = Panel:GetHeight(); else panelEntrance.fromHeight = 1; panelEntrance:Show(); end end) ----------------------------------------------------------- local function OnEnter(button) if not ClipFrame:IsShown() then FadeFrame(ClipFrame, 0.2, 1); end if button:IsEnabled() then UpdateHighlight(button.index); end SetCursor("Interface/CURSOR/Item.blp"); end local function OnLeave(button) if not self:IsInBound() then FadeFrame(ClipFrame, 0.2, 0); ResetCursor(); end if not Panel:IsMouseOver() then self:ShowPopup(false); end end local function OnMouseDown() ClipFrame.PushedHighlight:Show(); end local function OnMouseUp() ClipFrame.PushedHighlight:Hide(); end for i = 1, numButtons do local frameName = frameNames[i]; if frameName then frameName = frameName.."_MinimapButton"; end button = CreateFrame("Button", frameName, Panel, "NarciMinimapPanelButtonTemplate"); tinsert(buttons, button); button:SetFrameLevel(buttonFrameLevel); button.BlackText:SetText(LOCALIZED_NAMES[i]); button.WhiteText:SetText(LOCALIZED_NAMES[i]); button.BlackText:SetParent(ClipFrame); button.index = i; button.func = func[i]; if i == 1 then button:SetPoint("TOP", Panel.Middle, "TOP", 0, button1OffsetY); else button:SetPoint("TOP", buttons[i - 1], "BOTTOM", 0, 0); --button:SetPoint("TOP", Panel.Middle, "TOP", 0, offsetY - middleHeight/2 + BUTTON_HEIGHT/2 - BUTTON_HEIGHT * (i - 1) ); end button:SetScript("OnEnter", OnEnter); button:SetScript("OnLeave", OnLeave); button:SetScript("OnMouseDown", OnMouseDown); button:SetScript("OnMouseUp", OnMouseUp); button:SetScript("OnClick", function(frame, key) self:ShowPopup(false); if key == "LeftButton" and frame.func then frame.func(); end end); if not func[i] then button:Disable(); end end self.buttons = buttons; self.CreatePanel = nil; end function NarciMinimapButtonMixin:OnLoad() MiniButton = self; self:RegisterForClicks("LeftButtonUp","RightButtonUp","MiddleButtonUp"); self:RegisterForDrag("LeftButton"); self.endAlpha = 1; self:CreatePanel(); --Create Popup Delay local delay = NarciAPI_CreateAnimationFrame(0.35); --Mouseover Delay self.onEnterDelay = delay; delay:SetScript("OnUpdate", function(frame, elapsed) frame.total = frame.total + elapsed; if frame.total >= frame.duration then if self:IsMouseOver() then self:ShowPopup(true); end frame:Hide(); end end) local tooltip = self.TooltipFrame; tooltip.Left:SetVertexColor(0.686, 0.914, 0.996); tooltip.Middle:SetVertexColor(0.686, 0.914, 0.996); tooltip.Right:SetVertexColor(0.686, 0.914, 0.996); --Position Update Frame local f = CreateFrame("Frame"); self.PositionUpdator = f; f:Hide(); f.t = 0; f:SetScript("OnUpdate", function() local radian; local px, py = GetCursorPosition(); px, py = px / f.uiScale, py / f.uiScale; radian = math.atan2(py - f.mapY, px - f.mapX); MinimapButton_SetAngle(radian); NarcissusDB.MinimapButton.Position = radian; end) self:SetScript("OnLoad", nil); self.OnLoad = nil; end function NarciMinimapButtonMixin:InitPosition() if NarcissusDB.AnchorToMinimap then self:ClearAllPoints(); local radian = NarcissusDB.MinimapButton.Position; MinimapButton_SetAngle(radian); end end function NarciMinimapButtonMixin:IsAnchoredToMinimap() local x, y = self:GetCenter(); return MapShapeUtil:IsAnchoredToMinimap(x, y); end function NarciMinimapButtonMixin:SetTooltipText(text) local tooltip = self.TooltipFrame; tooltip.Description:SetText(text); local textWidth = tooltip.Description:GetWidth(); tooltip:SetWidth(max(32, textWidth + 8)); tooltip:ClearAllPoints(); local scale = UIParent:GetEffectiveScale(); local x, y = self:GetCenter(); y = y + 36; tooltip:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x*scale, y*scale); tooltip:Show(); end function NarciMinimapButtonMixin:StartRepositioning() self:ShowPopup(false); self:StopMovingOrSizing(); self.PositionUpdator:Hide(); self.TooltipFrame:Hide(); self:ClearAllPoints(); if not IsShiftKeyDown() and self:IsAnchoredToMinimap() then self:SetTooltipText("Hold Shift for free move"); self.PositionUpdator.mapX, self.PositionUpdator.mapY = Minimap:GetCenter(); self.PositionUpdator.uiScale = Minimap:GetEffectiveScale(); self.PositionUpdator:Show(); NarcissusDB.AnchorToMinimap = true; else self:StartMoving(); NarcissusDB.AnchorToMinimap = false; end self:RegisterEvent("MODIFIER_STATE_CHANGED"); end function NarciMinimapButtonMixin:OnDragStart() self:StartRepositioning(); end function NarciMinimapButtonMixin:OnDragStop() self.PositionUpdator:Hide(); self:StopMovingOrSizing(); self:SetUserPlaced(true); if self:IsMouseOver() then self:OnEnter(); end self:UnregisterEvent("MODIFIER_STATE_CHANGED"); self.TooltipFrame:Hide(); end function NarciMinimapButtonMixin:PostClick(button, down) if button == "MiddleButton" then Narci:EmergencyStop(); end end function NarciMinimapButtonMixin:OnMouseDown() self.onEnterDelay:Hide(); end function NarciMinimapButtonMixin:OnClick(button, down) self.onEnterDelay:Hide(); GameTooltip:Hide(); if button == "MiddleButton" then return; elseif button == "RightButton" then if IsShiftKeyDown() then NarcissusDB.ShowMinimapButton = false; print("Minimap button has been hidden. You may type /Narci minimap to re-enable it."); self:Hide(); else if self.showPanelOnMouseOver then Narci_OpenGroupPhoto(); GameTooltip:Hide(); self:Disable(); After(duration_Lock, function() self:Enable() end) else self:ShowPopup(true); end end return; end --"LeftButton" if IsShiftKeyDown() then Narci_ShowDressingRoom(); return; end self:Disable(); Narci_Open(); After(duration_Lock, function() self:Enable(); end) end function NarciMinimapButtonMixin:SetBackground(index) local useCovenantColor = false; local prefix = "Interface/AddOns/Narcissus/Art/Minimap/LOGO-"; local tex; local customStyleID = NarcissusDB.MinimapIconStyle; if not customStyleID then if IsAddOnLoaded("AzeriteUI") then customStyleID = 2; elseif IsAddOnLoaded("SexyMap") then customStyleID = 3; else customStyleID = 1; end --NarcissusDB.MinimapIconStyle = customStyleID; end if customStyleID == 2 then tex = prefix.."Thick"; --AzeriteUI elseif customStyleID == 3 then tex = prefix.."Hollow"; --SexyMap else useCovenantColor = true; end if useCovenantColor then local id = index or C_Covenants.GetActiveCovenantID(); if id == 2 then tex = prefix.."Brown"; --Venthyr elseif id == 4 then tex = prefix.."Green"; --Necrolord else tex = prefix.."Cyan"; end end self.Background:SetTexture(tex); self.Color:SetTexture(tex); end function NarciMinimapButtonMixin:SetIconScale(scale) self.Background:SetScale(scale); end function NarciMinimapButtonMixin:OnEnter() if IsMouseButtonDown() then return; end; self:ShowMouseMotionVisual(true); if (not IsShiftKeyDown()) then if self.showPanelOnMouseOver then self.onEnterDelay:Show(); elseif not self.Panel:IsShown() then local tooltip = GameTooltip; tooltip:SetOwner(self, "ANCHOR_NONE"); tooltip:SetPoint("TOPRIGHT", self, "BOTTOM", 0, 0); tooltip:SetText(NARCI_GRADIENT); --Normal Tooltip local HotKey1, HotKey2 = GetBindingKey("TOGGLECHARACTER0"); local KeyText; local LeftClickText = L["Minimap Tooltip Left Click"]; if HotKey1 and NarcissusDB.EnableDoubleTap then KeyText = "("..HotKey1..")"; if HotKey2 then KeyText = KeyText .. "|cffffffff or |r("..HotKey2..")"; end LeftClickText = LeftClickText.." |cffffffff".."/".." |r"..L["Minimap Tooltip Double Click"].." "..KeyText.."|r"; end local bindAction = "CLICK MiniButton:LeftButton"; local keyBind = GetBindingKey(bindAction); if keyBind and keyBind ~= "" then LeftClickText = LeftClickText.." |cffffffff".."/|r "..keyBind; end tooltip:AddLine(LeftClickText.." "..L["Minimap Tooltip To Open"], nil, nil, nil, false); tooltip:AddLine(L["Minimap Tooltip Right Click"].." "..L["Minimap Tooltip Module Panel"], nil, nil, nil, false); tooltip:AddLine(L["Minimap Tooltip Shift Left Click"].." "..L["Toggle Dressing Room"], nil, nil, nil, true); tooltip:AddLine(L["Minimap Tooltip Shift Right Click"].." "..L["Minimap Tooltip Hide Button"], nil, nil, nil, true); tooltip:AddLine(L["Minimap Tooltip Middle Button"], nil, nil, nil, true); tooltip:AddLine(" ", nil, nil, nil, true); tooltip:AddDoubleLine(NARCI_VERSION_INFO, NARCI_DEVELOPER_INFO, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8); tooltip:AddLine("https://wow.curseforge.com/projects/narcissus", 0.5, 0.5, 0.5, false); tooltip:Show(); end end end function NarciMinimapButtonMixin:ShowMouseMotionVisual(visible) if not self:IsShown() then return end; if visible then SetCursor("Interface/CURSOR/Item.blp"); self.Color:Show(); self:SetIconScale(1.1); FadeFrame(self.Color, 0.2, 1); FadeFrame(self, 0.2, 1); else ResetCursor(); FadeFrame(self.Color, 0.2, 0); FadeFrame(self, 0.2, self.endAlpha); self:SetIconScale(1); end end function NarciMinimapButtonMixin:PlayBling() self.Bling:Show(); self.Bling.animScale:Play(); end function NarciMinimapButtonMixin:OnLeave() GameTooltip:Hide(); if self.PositionUpdator:IsShown() then return; end if self:IsShown() then if not (self.Panel:IsMouseOver() and self.Panel:IsShown() ) then self:ShowPopup(false); end else self.Color:SetAlpha(0); end end function NarciMinimapButtonMixin:OnHide() self:ShowPopup(false); self.Panel.ClipFrame:Hide(); self:UnregisterEvent("MODIFIER_STATE_CHANGED"); end function NarciMinimapButtonMixin:ShowPopup(visible) if visible then self.Panel:Show(); self:RegisterEvent("GLOBAL_MOUSE_DOWN"); else FadeFrame(self.Panel, 0.15, 0); self:ShowMouseMotionVisual(false); self.onEnterDelay:Hide(); self.panelEntrance:Hide(); self:UnregisterEvent("GLOBAL_MOUSE_DOWN"); end end function NarciMinimapButtonMixin:OnEvent(event) if event == "GLOBAL_MOUSE_DOWN" then if not self:IsInBound() then self:ShowPopup(false); end elseif event == "MODIFIER_STATE_CHANGED" then if self:IsDragging() then self:StartRepositioning(); end end end ---------------End of derivation--------------- local RunePlateTexture = { [0] = "Interface/AddOns/Narcissus/Art/Runes/Bright/Black", --Enchantable but unenchanted [1] = "Interface/AddOns/Narcissus/Art/Runes/RunePlate-Black", [2] = "Interface/AddOns/Narcissus/Art/Runes/RunePlate-Uncommon", [3] = "Interface/AddOns/Narcissus/Art/Runes/RunePlate-Rare", [4] = "Interface/AddOns/Narcissus/Art/Runes/RunePlate-Epic", [5] = "Interface/AddOns/Narcissus/Art/Runes/RunePlate-Legendary", [6] = "Interface/AddOns/Narcissus/Art/Runes/RunePlate-Artifact", [7] = "Interface/AddOns/Narcissus/Art/Runes/RunePlate-Heirloom", } ---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 slotTable[index] and slotTable[index].hyperlink then After(delay, function() SendChatMessage(xmogTable[i][2]..": "..slotTable[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:Hide(); end end local function ShowOrHideEquiment(self) if not self.sourceID then return; end; self.isSlotHidden = not self.isSlotHidden; local slotID = self:GetID(); if self.isSlotHidden then NarciPlayerModelFrame1:UndressSlot(slotID); else NarciPlayerModelFrame1:TryOn(self.sourceID, Narci.SlotIDtoName[slotID][1]); --weapon enchant end end local IsItemEnchantable = { [11] = true, [12] = true, [16] = true, [17] = true, [5] = true, [8] = true, [9] = true, [10] = true, [15] = true, }; local RunicLetters = { ["crit"] = "ᚲ\nᚱ\nᛁ", --CRI ["haste"] = "ᚼ\nᛆ\nᛋ", --HAS ["mastery"] = "ᛘ\nᛋ\nᛐ", --MST ["versatility"] = "ᚡ\nᚽ\nᚱ", --VER ["STR"] = "ᛊ\nᛏ\nᚱ", --STR ["AGI"] = "ᛆ\nᚵ\nᛁ", --AGI ["INT"] = "ᛁ\nᚾ\nᛐ", --INT ["speed"] = "ᛋ\nᛕ\nᛑ", --SPD ["armor"] = "ᛆ\nᚱ\nᛘ", --ARM ["heal"] = "ᚺ\nᛁ\nᛚ", --HIL ["leech"] = "ᛒ\nᛚ\nᛑ", --BLD ["spell"] = "ᛗ\nᚷ\nᚲ", --MGC } 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(); --equipmentSlot.RuneSlot.Background:SetTexture(RunePlateTexture[0]); 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.Background:SetTexture(RunePlateTexture[0]) --if the item is enchantable but unenchanted, set its texture to black 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(); 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 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:ResetAnimation() self.Icon.scaleUp:Stop(); self.Border.scaleUp:Stop(); self.IconMask.scaleUp:Stop(); self.Icon:SetScale(1); self.Border:SetScale(1); self.IconMask:SetScale(1); 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, }; NarciEquipmentSlotMixin = CreateFromMixins{NarciItemButtonSharedMixin}; 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 isRuneforgeLegendary; --Shadowlands local isDominationItem; --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:HideVFX(); self.isSlotHidden = false; --Undress an item from player model self.RuneSlot:Hide(); self.GradientBackground:Show(); local appliedSourceID, appliedVisualID, hasSecondaryAppearance = GetSlotVisualID(slotID); if appliedVisualID > 0 then --[[ local sourceInfo = {}; if appliedVisualID ~= self.appliedVisualID or (not (self.sourceInfo and self.sourceInfo.name)) then self.appliedVisualID = appliedVisualID; sourceInfo = C_TransmogCollection.GetSourceInfo(appliedSourceID); self.sourceInfo = sourceInfo; _, self.sourceID = C_TransmogCollection.GetItemInfo(sourceInfo.itemID, sourceInfo.itemModID); if sourceInfo.sourceType == 1 then self.drops = C_TransmogCollection.GetAppearanceSourceDrops(self.sourceID); end else sourceInfo = self.sourceInfo; end --]] 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; itemIcon = C_TransmogCollection.GetSourceIcon(appliedSourceID); local _, _, _, hex = GetItemQualityColor(itemQuality); _, self.hyperlink = GetItemInfo(sourceInfo.itemID); self.itemModID = sourceInfo.itemModID; local sourceType = sourceInfo.sourceType; local difficulty; local bonusID; if sourceType == 1 then --TRANSMOG_SOURCE_BOSS_DROP = 1 local drops = C_TransmogCollection.GetAppearanceSourceDrops(appliedSourceID); if drops and drops[1] then effectiveLvl = drops[1].encounter.." ".."|cFFFFD100"..drops[1].instance.."|r|CFFf8e694"; self.sourcePlainText = drops[1].encounter.." "..drops[1].instance; if sourceInfo.itemModID == 0 then difficulty = PLAYER_DIFFICULTY1; bonusID = 3561; self.hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."1"..":1476:|h|r"; elseif sourceInfo.itemModID == 1 then difficulty = PLAYER_DIFFICULTY2; bonusID = 3562; self.hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."2"..":1476:|h|r"; elseif sourceInfo.itemModID == 3 then difficulty = PLAYER_DIFFICULTY6; bonusID = 3563; self.hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."3"..":1476:|h|r"; elseif sourceInfo.itemModID == 4 then difficulty = PLAYER_DIFFICULTY3; bonusID = 3564; self.hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."4"..":1476:|h|r"; end if difficulty then effectiveLvl = effectiveLvl.." "..difficulty; self.sourcePlainText = self.sourcePlainText.." "..difficulty; end end else if sourceType == 2 then --quest effectiveLvl = TRANSMOG_SOURCE_2 if sourceInfo.itemModID == 3 then self.hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:512".."6"..":1562:|h|r"; bonusID = 5126; elseif sourceInfo.itemModID == 2 then self.hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:512".."5"..":1562:|h|r"; bonusID = 5125; elseif sourceInfo.itemModID == 1 then self.hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:512".."4"..":1562:|h|r"; bonusID = 5124; end elseif sourceType == 3 then --vendor effectiveLvl = TRANSMOG_SOURCE_3; elseif sourceType == 4 then --world drop effectiveLvl = TRANSMOG_SOURCE_4; elseif sourceType == 5 then --achievement effectiveLvl = TRANSMOG_SOURCE_5; elseif sourceType == 6 then --profession effectiveLvl = TRANSMOG_SOURCE_6; else if itemQuality == 6 then effectiveLvl = ITEM_QUALITY6_DESC; elseif itemQuality == 5 then effectiveLvl = ITEM_QUALITY5_DESC; end end self.sourcePlainText = effectiveLvl; end if self.hyperlink then _, self.hyperlink = GetItemInfo(self.hyperlink); --original hyperlink cannot be printed (workaround) end 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 local _, sourceName = IsItemSourceSpecial(self.itemID); effectiveLvl = sourceName 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(); --[[ 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 buffText, durationText = GetTemporaryItemBuff(slotID); if buffText and durationText then buffText = "|cffa1cca4"..buffText.."|r"; durationText = "|cffa8a8a8"..durationText.."|r"; effectiveLvl = effectiveLvl.." "..buffText.." "..durationText; end --]] 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 local itemVFX; local itemID = GetItemInfoInstant(itemLink); borderTexKey, itemVFX, bR, bG, bB = GetBorderArtByItemID(itemID); itemIcon = GetInventoryItemTexture("player", slotID); 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 isDominationItem = DoesItemHaveDomationSocket(itemID); 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 if isDominationItem then gemName, gemID = GetItemDominationGem(itemLink); else gemName, gemLink = IsItemSocketable(itemLink); end end self.hyperlink = nil; 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.GetItemRank(itemLink, "ITEM_MOD_CORRUPTION_RESISTANCE"); effectiveLvl = effectiveLvl.." "..rank.." |cFFFFD100"..corruptionResistance.."|r"; borderTexKey = "BlackDragon"; itemVFX = "DragonFire"; end end if slotID ~= 13 and slotID ~= 14 then isRuneforgeLegendary = C_LegendaryCrafting.IsRuneforgeLegendary(itemLocation); if isRuneforgeLegendary then itemVFX = "Runeforge"; borderTexKey = "Runeforge"; end end local enchantText = GetItemEnchantText(itemLink, true); if enchantText then if self.isRight then effectiveLvl = enchantText.." "..effectiveLvl; else effectiveLvl = effectiveLvl.." "..enchantText; 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 self.itemLink = itemLink; else self:UntrackCooldown(); self:UntrackTempEnchant(); 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.isDominationItem = isDominationItem; 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; --Test --[[ if isRuneforgeLegendary then itemName = "|cff8cb7c7Banshee's Lament|r"; itemName = "Old Warrior\'s Soul"; itemName = "|cffeb5b50Decanter of Endless Howling|r"; end --]] 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; if isDominationItem then if gemID then _, _, _, _, gemIcon = GetItemInfoInstant(gemID); gemBorder = GetDominationBorderTexture(gemID); else gemBorder = GetDominationBorderTexture(nil); end self.GemSlot.GemBorder:SetTexture(gemBorder); else --regular gems if gemLink then gemID, _, _, _, gemIcon, _, itemSubClassID = GetItemInfoInstant(gemLink); gemBorder = GetGemBorderTexture(itemSubClassID, gemID); else gemBorder = GetGemBorderTexture(nil); end end self.GemSlot.GemBorder:SetTexture(gemBorder); self.GemSlot.GemIcon:SetTexture(gemIcon); self.GemSlot.GemIcon:Show(); self.GemSlot.sockedGemItemID = gemID; self.GemSlot:Show(); if self:IsVisible() then self.GemSlot.animIn:Play(); end self.GemSlot.isDomiationSocket = isDominationItem; else if self:IsVisible() then self.GemSlot.animOut:Play(); else self.GemSlot:Hide(); end self.GemSlot.sockedGemItemID = nil; end -------------------------------------------------- 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() self.ItemLevel:SetText(effectiveLvl); self.ItemLevel.anim2:Play(); end) self.Name.anim1:SetScript("OnFinished", function() self.Name:SetText(itemName); self.Name:SetTextColor(bR, bG, bB); self.Name.anim2:Play(); 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); 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", "RightButtonUp"); if self:GetParent() then if not self:GetParent().slotTable then self:GetParent().slotTable = {} end tinsert(self:GetParent().slotTable, self); end slotTable[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 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: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.Icon.scaleUp:Play(); self.Border.scaleUp:Play(); self.IconMask.scaleUp:Play(); else FadeFrame(self.Highlight, 0.15, 1); end if IsAltKeyDown() and not MOG_MODE then EquipmentFlyoutFrame:SetItemSlot(self, true); end if EquipmentFlyoutFrame:IsShown() then Narci_Comparison_SetComparison(EquipmentFlyoutFrame.BaseItem, self); return; 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:SetInventoryItem("player", self:GetID(), nil, true); if isGamepad then DefaultTooltip:SetAlpha(0); if self.isRight then NarciAPI_ShowDelayedTooltip("TOPRIGHT", self, "TOPLEFT", DefaultTooltip.offsetX, DefaultTooltip.offsetY); else NarciAPI_ShowDelayedTooltip("TOPLEFT", self, "TOPRIGHT", -DefaultTooltip.offsetX, DefaultTooltip.offsetY); end else DefaultTooltip:Show(); if hasItem then DefaultTooltip.HotkeyFrame:FadeIn(); end 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: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 SendChatMessage(self.hyperlink) end --ShareHyperLink() else PaperDollItemSlotButton_OnModifiedClick(self, button); TakeOutFrames(true); SetItemSocketingFramePosition(self); end else if button == "LeftButton" then if MOG_MODE then --Undress an item from player model while in Xmog Mode ShowOrHideEquiment(self); else --EquipmentFlyoutFrame:SetItemSlot(self); Narci_EquipmentOption:SetFromSlotButton(self, true) end elseif button == "RightButton" then Narci_AlertFrame_Autohide:SetAnchor(self, -24, true); 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); NarciAPI_ShowDelayedTooltip("BOTTOM", self, "TOP", 0, -4); end local function ShowDetailedIlvlInfo(self) if NarcissusDB.DetailedIlvlInfo 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 --/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 --]] NarciItemLevelFrameMixin = {}; function NarciItemLevelFrameMixin:OnLoad() ItemLevelFrame = self; if NarciDominationIndicatorMixin then local inhertMethods = { "IsNarcissusUI", "Update", "CheckSetBonus", "SetNodeLayout", "ShowTooltip", }; for k, v in pairs(inhertMethods) do self.DominationOverlay[v] = NarciDominationIndicatorMixin[v]; end self.checkDomination = true; end local LeftButton = self.LeftButton; LeftButton:SetScript("OnEnter", function(f) if f.isSameLevel then f.tooltipHeadline = format(f.tooltipFormat, f.Level:GetText()); else f.tooltipHeadline = format(f.tooltipFormat, f.Level:GetText()) .. format(" (max %s)", f.avgItemLevel); end if f.avgItemLevelPvp and f.avgItemLevelPvp ~= 0 then f.tooltipSpecial = format(STAT_AVERAGE_PVP_ITEM_LEVEL, f.avgItemLevelPvp); else f.tooltipSpecial = nil; end Narci_ShowButtonTooltip(f); FadeFrame(f.Highlight, 0.15, 1); end); end function NarciItemLevelFrameMixin:Update(playerLevel) playerLevel = playerLevel or UnitLevel("player"); local avgItemLevel, avgItemLevelEquipped, avgItemLevelPvp = GetAverageItemLevel(); local avgItemLevelBase = floor(avgItemLevel); avgItemLevel = floor(avgItemLevel * 100 + 0.5)/100; avgItemLevelEquipped = floor(avgItemLevelEquipped * 100 + 0.5)/100; avgItemLevelPvp = floor(avgItemLevelEquipped * 100 + 0.5)/100; self.LeftButton.avgItemLevel = avgItemLevel; self.LeftButton.avgItemLevelPvp = avgItemLevelPvp; self.LeftButton.isSameLevel = (avgItemLevel == avgItemLevelEquipped); self.LeftButton.Level:SetText(avgItemLevelEquipped); local r, g, b = 0.25, 0.25, 0.25; local colorName, qualityIndex; local covenantID; if playerLevel >= 48 then covenantID = C_Covenants.GetActiveCovenantID(); end if covenantID and covenantID ~= 0 then self:UpdateRenownLevel(); if covenantID == 1 then colorName = "CovenantKyrian"; r, g, b = 0.76, 0.89, 0.94; elseif covenantID == 2 then colorName = "CovenantVenthyr"; r, g, b = 0.55, 0, 0.19; elseif covenantID == 3 then colorName = "CovenantNightFae"; r, g, b = 0.11, 0.42, 0.80; elseif covenantID == 4 then colorName = "CovenantNecrolord"; r, g, b = 0, 0.63, 0.43; end else self:UpdateRenownLevel(0); if playerLevel <= 15 then colorName = "Grey"; qualityIndex = 0; elseif playerLevel <= 30 then colorName = "Green"; qualityIndex = 2; elseif playerLevel <= 45 then colorName = "Blue"; qualityIndex = 3; elseif playerLevel > 45 then if avgItemLevel < 85 then colorName = "Blue"; qualityIndex = 3; else colorName = "Purple"; qualityIndex = 4; end elseif playerLevel > 50 then if avgItemLevel < 158 then colorName = "Green"; qualityIndex = 2; elseif avgItemLevel < 183 then colorName = "Blue"; qualityIndex = 3; else colorName = "Purple"; qualityIndex = 4; end end r, g, b = GetItemQualityColor(qualityIndex); end local frame = self.CenterButton; frame.Background:SetTexture("Interface\\AddOns\\Narcissus\\ART\\Solid\\"..colorName); frame.Background:SetTexCoord(0, 1, 0, 1); frame.Fluid:SetColorTexture(r, g, b); local percentage = avgItemLevel - avgItemLevelBase; local height; --Set the bar(Fluid) height in the Tube if percentage < 0.10 then height = 0.1; elseif percentage > 0.90 then height = 84; else height = 84 * percentage; end frame.Fluid:SetHeight(height); frame.Level:SetText(avgItemLevelBase); frame.tooltip = STAT_AVERAGE_ITEM_LEVEL .." "..avgItemLevel; end function NarciItemLevelFrameMixin:UpdateRenownLevel(newLevel) local renownLevel = newLevel or C_CovenantSanctumUI.GetRenownLevel() or 0; local headerText = string.format(COVENANT_SANCTUM_LEVEL, renownLevel); if C_CovenantSanctumUI.HasMaximumRenown() then headerText = headerText.. " (maxed)"; else --to-do: get max level: C_CovenantSanctumUI.GetRenownLevels is too much end local frame = self.RightButton; frame.Header:SetText("RN"); frame.tooltipHeadline = headerText; frame.Number:SetText(renownLevel); if renownLevel == 0 then frame.tooltipLineOpen = "You will be able to join a Covenant and progress Renown level once you reach 60."; else frame.tooltipLineOpen = COVENANT_RENOWN_TUTORIAL_PROGRESS; end end function NarciItemLevelFrameMixin:SetTheme(isDomination) local file; if isDomination then file = "Interface\\AddOns\\Narcissus\\Art\\Widgets\\Domination\\ItemLevelHexagon"; self.CenterButton:ShowMaxLevel(false); self.CenterButton.Highlight:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Widgets\\Domination\\ItemLevelHexagonHighlight"); self.CenterButton.Highlight:SetSize(128, 128); self.CenterButton.Highlight:SetBlendMode("BLEND"); else file = "Interface\\AddOns\\Narcissus\\Art\\Widgets\\ItemLevel\\HexagonTube"; self.CenterButton:ShowMaxLevel(true); self.CenterButton.Highlight:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Solid\\HexagonSolid-Highlight"); self.CenterButton.Highlight:SetSize(100, 100); self.CenterButton.Highlight:SetBlendMode("ADD"); end local textures = { self.CenterButton.FluidBackground, self.CenterButton.TubeBorder, self.LeftButton.Background, self.LeftButton.Highlight, self.RightButton.Background, self.RightButton.Highlight, }; for k, tex in pairs(textures) do tex:SetTexture(file); end end function NarciItemLevelFrameMixin:UpdateDomination() if not self.checkDomination then return end; if not self.pauseUpdate then self.pauseUpdate = true; After(0, function() local isDomination = self.DominationOverlay:Update(); self.CenterButton.isDomination = isDomination; if self.isDomination ~= isDomination then self.isDomination = isDomination; self:SetTheme(isDomination); end self.pauseUpdate = nil; end) end end function NarciItemLevelFrameMixin:ToggleExtraInfo(state, replayAnimation) if not self.animFrame then self.animFrame = CreateFrame("Frame"); self.animFrame:Hide(); self.animFrame:SetScript("OnUpdate", function(f, elapsed) f.t = f.t + elapsed; local offsetX = outSine(f.t, f.fromX, f.toX, 0.4); if f.t >= 0.4 then offsetX = f.toX; f:Hide(); if f.hideButton then self.LeftButton:Hide(); self.RightButton:Hide(); end end self.LeftButton:SetPoint("RIGHT", self, "CENTER", -offsetX, 0); self.RightButton:SetPoint("LEFT", self, "CENTER", offsetX, 0); end); end self.animFrame:Hide(); self.animFrame.t = 0; local _, _, _, fromX = self.RightButton:GetPoint(); self.animFrame.fromX = fromX; if state then self.animFrame.toX = 28; self.LeftButton:Show(); self.RightButton:Show(); self.animFrame.hideButton = false; else self.animFrame.toX = -32; self.animFrame.hideButton = true; end if fromX ~= self.animFrame.toX or replayAnimation then self.animFrame:Show(); end end NarciItemLevelCenterButtonMixin = {}; function NarciItemLevelCenterButtonMixin:OnLoad() self.tooltip2 = HIGHLIGHT_FONT_COLOR_CODE .. STAT_AVERAGE_ITEM_LEVEL_TOOLTIP .. FONT_COLOR_CODE_CLOSE; --self.tooltip3 = L["Toggle Equipment Set Manager"]; self:SetScript("OnLoad", nil); self.OnLoad = nil; end function NarciItemLevelCenterButtonMixin:OnEnter() FadeFrame(self.Highlight, 0.2, 1); --EquipmentSetManager --corruption or not --[[ if self.isCorrupted then NarciAPI_RunDelayedFunction(self, 0.2, function() local frame = Narci_CorruptionTooltip; if not frame:IsVisible() and not self.isSetManagerOpen and not IsMouseButtonDown() then frame:ClearAllPoints(); frame.ModelScene.Background:SetGradientAlpha("VERTICAL", 1, 1, 1, 1, 1, 1, 1, 1); frame:SetScale(self:GetScale()); frame:SetParent(self); frame:SetPoint("TOP", self, "BOTTOM", 0, -12); frame:SetHitRectInsets(-32, -32, -32, -32); FadeFrame(frame, 0.25, 1); end end); end --]] if self.isDomination then NarciAPI_RunDelayedFunction(self, 0.2, function() self:GetParent().DominationOverlay:ShowTooltip(DefaultTooltip, "TOP", self, "BOTTOM", 0, -12); DefaultTooltip:SetAlpha(0); FadeFrame(DefaultTooltip, 0.2, 1); end); else Narci_ShowStatTooltipDelayed(self); end end function NarciItemLevelCenterButtonMixin:OnMouseDown() self.Background:SetPoint("CENTER", 0, -4); if self.isCorrupted then NarciAPI_FadeFrame(Narci_CorruptionTooltip, 0.2, 0); end end function NarciItemLevelCenterButtonMixin:OnMouseUp() self.Background:SetPoint("CENTER", 0, 0); end function NarciItemLevelCenterButtonMixin:OnLeave() FadeFrame(self.Highlight, 0.2, 0); Narci:HideButtonTooltip(); end function NarciItemLevelCenterButtonMixin:OnClick() Narci_NavBar:ToggleView(2); end function NarciItemLevelCenterButtonMixin:OnHide() if self.onHideFunc then self.onHideFunc(self); end end function NarciItemLevelCenterButtonMixin:ShowItemLevel() ItemLevelFrame:Update(); end function NarciItemLevelCenterButtonMixin:ShowMaxLevel(state) self.Header:SetShown(state); self.Level:SetShown(state); self.Surface:SetShown(state); self.Fluid:SetShown(state); self.Background:SetShown(state); 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:Update(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(); 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 slotTable[slotID] then slotTable[slotID]:Refresh(forceRefresh); return true; end end function SlotController:RefreshAll() for slotID, slotButton in pairs(slotTable) do slotButton:Refresh(); 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:PlayAnimOut() if not InCombatLockdown() and Narci_Character:IsShown() then for slotID, slotButton in pairs(slotTable) do slotButton.animOut:Play(); end Narci_Character.animOut:Play(); end end function SlotController:IsMouseOver() for slotID, slotButton in pairs(slotTable) do if slotButton:IsMouseOver() then return true end end return false end local function CacheSourceInfo(slotID) local appliedSourceID, appliedVisualID; if slotID then After(AssignDelay(slotID, true), function() appliedSourceID, appliedVisualID = GetSlotVisualID(slotID); if appliedVisualID > 0 then local sourceInfo = C_TransmogCollection.GetSourceInfo(appliedSourceID); local sources = C_TransmogCollection.GetAppearanceSources(appliedVisualID); if slotTable[slotID] then local slot = slotTable[slotID]; slot.sourceInfo = sourceInfo; slot.appliedVisualID = appliedVisualID; local _, sourceID = C_TransmogCollection.GetItemInfo(sourceInfo.itemID, sourceInfo.itemModID); if sourceInfo and sourceInfo.sourceType == 1 then slot.drops = C_TransmogCollection.GetAppearanceSourceDrops(sourceID); end end --print("Caching Slot... #"..slotID) end end) else for id, slotButton in pairs(slotTable) do appliedSourceID, appliedVisualID = GetSlotVisualID(id); if appliedVisualID > 0 then local sourceInfo = C_TransmogCollection.GetSourceInfo(appliedSourceID); local sources = C_TransmogCollection.GetAppearanceSources(appliedVisualID); end end end 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:RegisterErrorEvent(); Narci_AlertFrame_Autohide:SetAnchor(self, -24, true); 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) FadeFrame(self.Highlight, 0.15, 1); Narci_Comparison_SetComparison(self.itemLocation, self); if isGamepad then self.Icon.scaleUp:Play(); self.Border.scaleUp:Play(); self.IconMask.scaleUp:Play(); 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"; end itemQuality = GetBorderArtByItemID(itemID) or itemQuality; if maxItemLevel and itemLevel < maxItemLevel 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 xmogMode ~=0 then return; end local level = Narci_FlyoutBlack:GetFrameLevel() - 1; for slotID, slotButton in pairs(slotTable) 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; 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(20); Narci:HideButtonTooltip(); 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); Tooltip:Show(); end function NarciEquipmentFlyoutFrameMixin:CreateItemButton() local perRow = 5; --EQUIPMENTFLYOUT_ITEMS_PER_ROW local buttons = self.buttons; local numButtons = #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); tinsert(buttons, button); button.FlyUp.Move:SetStartDelay(numButtons/25); button.FlyUp.Fade:SetStartDelay(numButtons/25); 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 = {}; 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); NarciCacheTooltip:SetHyperlink(hyperlink); LoadItemData(itemLocation); itemInfo = {level = itemLevel, itemLocation = itemLocation, location = location}; tinsert(sortedItems, 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; 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 h = GetCombatRating(CR_HASTE_MELEE) or 0; end if m then mastery = m; else m = 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 function XmogList_OnLoad(self) Narci_AttributeFrame_UpdateBackgroundColor(self); end local function RefreshStats(id, frame) frame = frame or "Detailed"; if frame == "Detailed" then if statTable[id] then statTable[id]:Update(); end elseif frame == "Concise" then if statTable_Short[id] then statTable_Short[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 statTable[i] then statTable[i]:Update(); end if statTable_Short[i] then statTable_Short[i]:Update(); end if i >= 20 then self:Hide(); self.index = 1; else self.index = i + 1; end end end); function StatsUpdator:Gradual() ItemLevelFrame:Update(); ItemLevelFrame:UpdateDomination(); 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(slotTable) 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 = statTable[i].animIn; if anim then anim.A2:SetToAlpha(statTable[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() Narci.slotTable = slotTable; local statFrame = Narci_DetailedStatFrame; local radar = RadarChart; statTable[1] = statFrame.Primary; statTable[2] = statFrame.Stamina; statTable[3] = statFrame.Damage; statTable[4] = statFrame.AttackSpeed; statTable[5] = statFrame.Power; statTable[6] = statFrame.Regen; statTable[7] = statFrame.Health; statTable[8] = statFrame.Armor; statTable[9] = statFrame.Reduction; statTable[10]= statFrame.Dodge; statTable[11]= statFrame.Parry; statTable[12]= statFrame.Block; statTable[13]= radar.Crit; statTable[14]= radar.Haste; statTable[15]= radar.Mastery; statTable[16]= radar.Versatility; statTable[17]= statFrame.Leech; statTable[18]= statFrame.Avoidance; statTable[19]= statFrame.MovementSpeed; statTable[20]= statFrame.Speed; local statFrame_Short = Narci_ConciseStatFrame; statTable_Short[1] = statFrame_Short.Primary; statTable_Short[2] = statFrame_Short.Stamina; statTable_Short[3] = statFrame_Short.Health; statTable_Short[4] = statFrame_Short.Power; statTable_Short[5] = statFrame_Short.Regen; statTable_Short[6] = statFrame_Short.Crit; statTable_Short[7] = statFrame_Short.Haste; statTable_Short[8] = statFrame_Short.Mastery; statTable_Short[9] = statFrame_Short.Versatility; statTable_Short[10] = statFrame_Short.Leech; statTable_Short[11] = statFrame_Short.Avoidance; statTable_Short[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 --Music Fade In/Out local MusicIO = CreateFrame("Frame", "Narci_MusicInOut"); MusicIO.t = 0; MusicIO:Hide() local function MusicIO_Update(self, elapsed) self.t = self.t + elapsed local volume; if self.state then volume = max((self.t/2), CVarTemp.MusicVolume) else volume = max((self.fromVolume - self.t/2), CVarTemp.MusicVolume) end SetCVar("Sound_MusicVolume",volume) if (self.state and volume >= 1) or ((not self.state) and volume <= tonumber(CVarTemp.MusicVolume)) then self:Hide() self.t = 0; end end MusicIO:SetScript("OnShow", function(self) self.fromVolume = GetCVar("Sound_MusicVolume") or 1; end) MusicIO:SetScript("OnUpdate", MusicIO_Update) MusicIO:SetScript("OnHide", function(self) self.t = 0; end) function MusicIO:In() if not NarcissusDB.FadeMusic then return; end self:Hide(); self.state = true; self:Show(); end function MusicIO:Out() self:Hide(); self.state = false; self:Show(); 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(); ViewProfile:SaveView(5); ModifyCameraForShapeshifter(); xmogMode = 0; MogModeOffset = 0; NarciPlayerModelFrame1.xmogMode = 0; local speedFactor = 180/(GetCVar("cameraYawMoveSpeed") or 180); ZoomFactor.toSpeed = speedFactor * ZoomFactor.toSpeedBasic; ZoomFactor.fromSpeed = speedFactor * ZoomFactor.fromSpeedBasic; MusicIO:In(); EL:Show(); Toolbar:FlyIn(); Narci_XmogButton:Enable(); DefaultTooltip:SetScale(UIParent:GetEffectiveScale() or 1); After(0, function() CameraMover:Enter(); RadarChart:SetValue(0,0,0,0,1); Narci_LetterboxAnimation(); 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(); 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(); MusicIO:Out(); Narci_LetterboxAnimation("OUT"); if Narci_TitleManager_Switch.IsOn then Narci_TitleManager_Switch:Click(); end EquipmentFlyoutFrame:Hide(); Narci_TitleManager_TitleTooltip:Hide(); --TitleManager Narci_ModelSettings:Hide(); Toolbar:FlyOut(); 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(); ViewProfile:SaveView(5); ModifyCameraForShapeshifter(); SetCVar("test_cameraDynamicPitch", 1) local xmogMode_Temp = NarcissusDB.DefaultLayout; NarcissusDB.DefaultLayout = 2; Narci_XmogButton:Enable(); Narci_XmogButton:Click(); After(0.4, function() NarcissusDB.DefaultLayout = xmogMode_Temp; end) local speedFactor = 180/(GetCVar("cameraYawMoveSpeed") or 180); ZoomFactor.toSpeed = speedFactor*ZoomFactor.toSpeedBasic; ZoomFactor.fromSpeed = speedFactor*ZoomFactor.fromSpeedBasic; EL:Show(); CameraMover:Pitch(); DefaultTooltip:SetScale(UIParent:GetEffectiveScale() or 1); After(0, function() 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() if not Narci_PhotoModeButton.IsOn then Narci_PhotoModeButton:Click(); end Toolbar:FlyIn(); 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 ---Widgets--- function CameraControllerThumb_OnLoad(self) self:RegisterForClicks("RightButtonUp"); self:RegisterForDrag("LeftButton"); self.Reading:SetText(string.format("%.2f", 0)); end local function CameraControlBarThumb_Reposition(self, ofsx) self:GetParent().Thumb:SetPoint("CENTER", ofsx, 0); NarciCameraOffsetControlBar.PosX = ofsx; SetCVar("test_cameraOverShoulder", 0 - ofsx/20) --Ajust the zoom - Shoulder factor local currentShoulder = GetCVar("test_cameraOverShoulder"); local zoom = GetCameraZoom(); end function CameraControlBar_DraggingFrame_OnUpdate(self) local scale = self:GetParent():GetEffectiveScale(); local xpos = GetCursorPosition() / scale; local xmin, xmax = self:GetParent():GetLeft() + 18 , self:GetParent():GetRight() - 18; NarciCameraOffsetControlBar.Range = xmax - xmin; local xcenter = self:GetParent():GetCenter(); local ofsx; if xpos < xmin then ofsx = xmin - xcenter; elseif xpos > xmax then ofsx = xmax - xcenter; else ofsx = xpos - xcenter; end CameraControlBarThumb_Reposition(self, ofsx); end function CameraControlBarThumb_OnClick(self, button, down) --self:GetParent().Thumb:SetPoint("CENTER", 0, 0); self:Disable() CameraControlBar_ResetPosition_AnimFrame.OppoDirection = true CameraControlBar_ResetPosition_AnimFrame:Show(); After(0.6, function() self:Enable(); NarciCameraOffsetControlBar.PosX = 0; NarciCameraOffsetControlBar.PosRadian = 0; end) local zoom = GetCameraZoom() SmoothShoulderCVar(Shoulder_Factor1*zoom + Shoulder_Factor2); self:GetParent().Thumb.Reading:SetText(string.format(0)); end local shaftDiameter = 53; local lastDegree = 0; local tinyIncre = 1000; local function TinyZoom(degree, lastDegree) if (degree >= 0 and lastDegree >= 0) or (degree <= 0 and lastDegree <= 0) then if degree < lastDegree then CameraZoomIn((lastDegree - degree)/tinyIncre); elseif degree > lastDegree then CameraZoomOut((degree - lastDegree)/tinyIncre); end elseif degree >= 0 and lastDegree < 0 then if degree >= 90 then CameraZoomIn((180 - degree)/tinyIncre); else CameraZoomOut((0 + degree)/tinyIncre); end elseif degree <= 0 and lastDegree > 0 then if degree <= -90 then CameraZoomOut((180 + degree)/tinyIncre); else CameraZoomIn((0 - degree)/tinyIncre); end end end local function RotateShaftNode(radian) local ofsx = shaftDiameter*math.cos(radian) local ofsy = shaftDiameter*math.sin(radian) CameraControllerNode:SetPoint("CENTER", "CameraControllerThumb", "CENTER", ofsx, ofsy); CameraControllerThumb.Shaft:SetRotation(radian) end function CameraZoomController_DraggingFrame_OnUpdate(self) local scale = self:GetParent():GetEffectiveScale() local xpos, ypos = GetCursorPosition() xpos, ypos = xpos/scale, ypos/scale local radian = math.atan2( (ypos - self.cy),(xpos - self.cx)) RotateShaftNode(radian); NarciCameraOffsetControlBar.PosRadian = radian; local degree = math.deg(radian) if not self.isPressed then TinyZoom(degree, lastDegree) else if degree < 0 then CameraZoomIn( (-degree)/tinyIncre) elseif degree > 0 then CameraZoomOut( (degree)/tinyIncre) end end lastDegree = degree; end ------------------------------------------------------ ------------------Photo Mode Controller--------------- ------------------------------------------------------ function Narci_KeyListener_OnEscapePressed() if IS_OPENED then MiniButton:Click(); end end function Narci_ExitButton_OnClick(self) if IS_OPENED then Narci_Open(); SetUIVisibility(true); end end local function TokenButton_ClearMarker(self) local parent = self:GetParent(); if parent.buttons then for i = 1, #parent.buttons do parent.buttons[i].HighlightColor:Hide(); end end end ---Set Graphics Settings to Ultra--- local PhotoMode_Cvar_GraphicsBackup = {}; local PhotoMode_Cvar_GraphicsList = { ["ffxAntiAliasingMode"] = 2, ["graphicsTextureResolution"] = 3, ["graphicsTextureFiltering"] = 6, ["graphicsProjectedTextures"] = 2, ["graphicsViewDistance"] = 10, ["graphicsEnvironmentDetail"] = 10, ["graphicsGroundClutter"] = 10, ["graphicsShadowQuality"] = 6, ["graphicsLiquidDetail"] = 4, ["graphicsSunshafts"] = 3, ["graphicsParticleDensity"] = 5, ["graphicsSSAO"] = 5, ["graphicsDepthEffects"] = 4, --["graphicsLightingQuality"] = 3, ["lightMode"] = 2, ["MSAAQuality"] = 4, --4 is invalid. But used for backup ["shadowrt"] = -1, --invalid } ---Hide Names and Bubbles--- --local PhotoMode_Cvar_TrackingList = 1 --Track Battle Pet local PhotoMode_Cvar_TrackingBAK = true; local PhotoMode_Cvar_NamesBackup = {}; local PhotoMode_Cvar_NamesList = { --Unit Name CVars ["UnitNameOwn"] = 0, ["UnitNameNonCombatCreatureName"] = 0, ["UnitNameFriendlyPlayerName"] = 0, ["UnitNameFriendlyPetName"] = 0, ["UnitNameFriendlyMinionName"] = 0, ["UnitNameFriendlyGuardianName"] = 0, ["UnitNameFriendlySpecialNPCName"] = 0, ["UnitNameEnemyPlayerName"] = 0, ["UnitNameEnemyPetName"] = 0, ["UnitNameEnemyGuardianName"] = 0, ["UnitNameNPC"] = 0, ["UnitNameInteractiveNPC"] = 0, ["UnitNameHostleNPC"] = 0, ["chatBubbles"] = 0, ["floatingCombatTextCombatDamage"] = 0, ["floatingCombatTextCombatHealing"] = 0, }; local function PhotoMode_BackupCvar(BackupTable, OriginalTable) if OriginalTable then for k, v in pairs(OriginalTable) do BackupTable[k] = GetCVar(k) or 0; end end end local function PhotoMode_RestoreCvar(BackupTable) --it can also be used to set CVars to pre-defined values if BackupTable then for k, v in pairs(BackupTable) do SetCVar(k, v) --print(k.." "..v) end end end local function PhotoMode_ZeroCvar(BackupTable) if BackupTable then for k, v in pairs(BackupTable) do SetCVar(k, 0) end end end local function PhotoMode_GetTrackingInfo(id) local id = 1; local _, _, active = GetTrackingInfo(id) PhotoMode_Cvar_TrackingBAK = active; end local ControllerButtonTooltip = { -- [ Name ] = { HeadLine, Line, Special, Guide Pic Index } ["Narci_PhotoModeButton"] = { L["Photo Mode"], L["Photo Mode Tooltip Open"], L["Photo Mode Tooltip Special"], }, ["Narci_XmogButton"] = { L["Xmog Button"], L["Xmog Button Tooltip Open"], L["Xmog Button Tooltip Special"], }, ["Narci_EmoteButton"] = { L["Emote Button"], L["Emote Button Tooltip Open"], L["Emote Button Tooltip Special"], }, ["Narci_HideTextsButton"] = { L["HideTexts Button"], L["HideTexts Button Tooltip Open"], L["HideTexts Button Tooltip Special"], 1, }, ["Narci_TopQualityButton"] = { L["TopQuality Button"], L["TopQuality Button Tooltip Open"], L["HideTexts Button Tooltip Special"], 2, }, } function Narci_PhotoModeButton_OnLoad(self) self.IsOn = false; local name = self:GetName(); if ControllerButtonTooltip[name] then if ControllerButtonTooltip[name][3] then --special notes self.tooltip = {ControllerButtonTooltip[name][1], ControllerButtonTooltip[name][2] .. "\n|cff6b6b6b".. ControllerButtonTooltip[name][3]}; --42% Grey else self.tooltip = {ControllerButtonTooltip[name][1], ControllerButtonTooltip[name][2]}; end if ControllerButtonTooltip[name][4] then self.guideIndex = ControllerButtonTooltip[name][4]; end wipe(ControllerButtonTooltip[name]); end if self.Pushed and self.Icon then self.Pushed:SetTexture(self.Icon:GetTexture()) end end local function TemporarilyHidePopUp(frame) if frame:IsShown() then frame.AnimFrame:Hide(); frame.AnimFrame.OppoDirection = true; frame.AnimFrame:Show(); frame.AnimFrame.toY = -20; end end function NarciXmogButtonPopUp_OnShow(self) ColorUtil:SetWidgetColor(self.Color); ColorUtil:SetWidgetColor(self.Option); end function XmogButtonPopUp_OnLoad(self) self.CopyButton.Label:SetText(L["Copy Texts"]); self.ModeButton.Background:SetColorTexture(0.06, 0.06, 0.06, 0.8); self.ModeButton.Label:SetText(L["Layout"]); self.ModeButton.Option:SetText(L["Symmetry"]); self.ModelToggle.Label:SetText(L["3D Model"]); ColorUtil:SetWidgetColor(self.ModeButton.Option); local SyntaxButton = self.CopyButton.GearTexts; SyntaxButton.PlainText.Background:SetColorTexture(0.06, 0.06, 0.06, 0.8); SyntaxButton.BBSCode.Background:SetColorTexture(0.06, 0.06, 0.06, 0.8); SyntaxButton.Markdown.Background:SetColorTexture(0.06, 0.06, 0.06, 0.8); SyntaxButton.PlainText.Label:SetText(L["Plain Text"]); SyntaxButton.BBSCode.Label:SetText(L["BB Code"]); SyntaxButton.Markdown.Label:SetText(L["Markdown"]); end local function HidePlayerModel() if (not Narci_ModelContainer:IsVisible()) or (NarcissusDB.AlwaysShowModel) then return; end Narci_PlayerModelAnimOut:Show() After(0.4, function() FadeFrame(NarciPlayerModelFrame1, 0.5 , 0) end) end local function UseXmogLayout(index) if index == 1 then xmogMode = 1; NarciPlayerModelFrame1.xmogMode = 1; Narci_XmogButtonPopUp_ModeButton.Option:SetText(L["Asymmetry"]); CameraMover:Pitch(); HidePlayerModel(); SmoothShoulder.toPoint = 0.01; SmoothShoulder:Show(); Narci_GuideLineFrame.VirtualLineRight.AnimFrame.toX = -80; Narci_GuideLineFrame.VirtualLineRight.AnimFrame:Show(); SmoothShoulderCVar(0.01); Narci_XmogButtonPopUp_ModeButton.ShowModel = false; if NarcissusDB.AlwaysShowModel then NarciModel_RightGradient:Hide(); Narci_PlayerModelGuideFrame.VignetteRightSmall:Hide(); if not NarciPlayerModelFrame1:IsVisible() then Narci_PlayerModelAnimIn:Show(); end end elseif index == 2 then xmogMode = 2; MogModeOffset = 0.2; NarciPlayerModelFrame1.xmogMode = 2; if Narci_Character:IsVisible() then FadeFrame(NarciModel_RightGradient, 0.5, 1); end Narci_XmogButtonPopUp_ModeButton.Option:SetText(L["Symmetry"]); if not NarciPlayerModelFrame1:IsVisible() then Narci_PlayerModelAnimIn:Show(); end Narci_PlayerModelGuideFrame.VignetteRightSmall:Show(); Narci_GuideLineFrame.VirtualLineRight.AnimFrame.toX = -600; Narci_GuideLineFrame.VirtualLineRight.AnimFrame:Show(); Narci_XmogButtonPopUp_ModeButton.ShowModel = true; After(0, function() if not IsMounted() then CameraMover:Pitch(); CameraMover:ZoomIn(ZoomInValue_XmogMode); --ajust by raceID else CameraMover:ZoomIn(8); --ajust by raceID end end) end end local function PlayCheckSound(self, state) if not self.enableSFX then return; elseif state then PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON); else PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF); 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) local DefaultLayout = NarcissusDB.DefaultLayout; if DefaultLayout == 1 then xmogMode = 1; elseif DefaultLayout == 2 then xmogMode = 2; MogModeOffset = 0.2; elseif DefaultLayout == 3 then xmogMode = 2; MogModeOffset = 0.2; end UseXmogLayout(xmogMode); NarciPlayerModelFrame1.xmogMode = xmogMode; MsgAlertContainer:Display(); 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_Factor1*zoom + Shoulder_Factor2) end FadeFrame(Narci_XmogNameFrame, 0.2, 0) ShowAttributeButton(); xmogMode = 0; MogModeOffset = 0; NarciPlayerModelFrame1.xmogMode = 0; MsgAlertContainer:Hide(); end end function Narci_XmogButton_OnClick(self) self.IsOn = not self.IsOn MoveViewRightStop(); EquipmentFlyoutFrame:Hide(); MOG_MODE = not MOG_MODE; local PopUp = Narci_XmogButtonPopUp; if not self.IsOn then --Exit Xmog mode FadeFrame(Narci_VignetteRightSmall, 0.5, 0); FadeFrame(Narci_VignetteRightLarge, 0.5, NarcissusDB.VignetteStrength); Narci_SnowEffect(true); Narci_LetterboxAnimation(); PlayCheckSound(self, false) self.Icon:SetTexCoord(0, 0.5, 0, 1); PopUp.AnimFrame:Hide(); PopUp.AnimFrame.OppoDirection = true PopUp.AnimFrame:Show(); PopUp.AnimFrame.toY = -20; 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(); self.tooltip = {L["Xmog Button"], L["Xmog Button Tooltip Open"] .. "\n|cff6b6b6b"..L["Xmog Button Tooltip Special"]}; if not Narci_ExitConfirmationDialog:IsShown() then Narci.showExitConfirm = false; end else FadeFrame(Narci_VignetteRightSmall, 0.5, NarcissusDB.VignetteStrength); FadeFrame(Narci_VignetteRightLarge, 0.5, 0); Narci_SnowEffect(false); Narci_LetterboxAnimation("OUT"); PlayCheckSound(self, true) self.Icon:SetTexCoord(0.5, 1, 0, 1); PopUp:Show(); PopUp.AnimFrame:Hide(); PopUp.AnimFrame.OppoDirection = false; PopUp.AnimFrame:Show(); PopUp.AnimFrame.toY = 8; Narci_XmogNameFrame.PlayerName:SetText(Narci_PlayerInfoFrame.PlayerName:GetText()) self.tooltip = {L["Xmog Button"], L["Xmog Button Tooltip Close"]}; end SlotController:LazyRefresh(); After(0.1, function() ActivateMogMode(); end) NarciTooltip:FadeOut(); TemporarilyHidePopUp(Narci_EmoteButtonPopUp); 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) 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 slotTable[slot] and slotTable[slot].itemID then ItemList[slot] = {slotTable[slot].itemID, slotTable[slot].bonusID}; end end return NarciAPI.EncodeItemlist(ItemList); end local function CopyTexts(type, subType) local texts = Narci_XmogNameFrame.PlayerName:GetText() or "My Transmog"; type = type or "TEXT"; subType = subType or "Wowhead"; local showItemID = Narci_XmogButtonPopUp.CopyButton.showItemID or false; local source; if type == "TEXT" then texts = texts.."\n" for i = 1, #xmogTable do local index = xmogTable[i][1] if slotTable[index] and slotTable[index].Name:GetText() then local text = "|cFFFFD100"..xmogTable[i][2]..":|r "..(slotTable[index].Name:GetText() or " "); if showItemID and slotTable[index].itemID then text = text.." |cFFacacac"..slotTable[index].itemID.."|r"; end source = slotTable[index].ItemLevel:GetText(); if source and source ~= " " then text = text.." |cFF40C7EB("..source..")|r" end if text then texts = texts.."\n"..text; end end end elseif type == "BBS" then if subType == "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 subType == "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 subType == "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 slotTable[index] and slotTable[index].Name:GetText() then local text = "|cFF959595[tr][td]|r".."|cFFFFD100"..xmogTable[i][2].."|r|cFF959595[/td][td]|r" if showItemID and slotTable[index].itemID then if subType == "Wowhead" then text = text.."[item="..slotTable[index].itemID.."|r|cFF959595][/td]|r" elseif subType == "NGA" then text = text.."|cFF959595[url=https://www.wowhead.com/item="..slotTable[index].itemID.."]|r"..(slotTable[index].Name:GetText() or " ").."|cFF959595[/url][/td]|r" elseif subType == "mmo-champion" then text = text.."|cFF959595[url=https://www.wowdb.com/items/"..slotTable[index].itemID.."]|r"..(slotTable[index].Name:GetText() or " ").."|cFF959595[/url][/td]|r" end else text = text..(slotTable[index].Name:GetText() or " ").."|r|cFF959595[/td]|r" end source = slotTable[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 subType == "Wowhead" then texts = GetWowHeadDressingRoomURL(); end elseif type == "MARKDOWN" then texts = "|cFF959595**|r"..texts.."|cFF959595**\n\n| Slot | Name | Source |".."\n".."|:--|:--|:--|" for i=1, #xmogTable do local index = xmogTable[i][1] if slotTable[index] and slotTable[index].Name:GetText() then local text = "|cFF959595| |r|cFFFFD100"..xmogTable[i][2].."|r |cFF959595| |r" if showItemID and slotTable[index].itemID then text = text.."|cFF959595[|r"..(slotTable[index].Name:GetText() or " ").."|cFF959595](https://www.wowhead.com/item=|r"..slotTable[index].itemID..")|r" else text = text..(slotTable[index].Name:GetText() or " ") end source = slotTable[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" end return texts; end local websites = { [0] = {"reddit", "Interface/AddOns/Narcissus/Art/Logos/reddit"}, [1] = {"Wowhead", "Interface/AddOns/Narcissus/Art/Logos/Wowhead"}, [2] = {"NGA", "Interface/AddOns/Narcissus/Art/Logos/NGA"}, [3] = {"mmo-champion", "Interface/AddOns/Narcissus/Art/Logos/mmo-champion"}, --[4] = {"Vanion", "Interface/AddOns/Narcissus/Art/Logos/Vanion"}, } function Narci_WebsiteButton_OnLoad(self) local index = self:GetID() or 2; if websites[index] then self.NormalTex:SetTexture(websites[index][2]); self.PushedTex:SetTexture(websites[index][2]); if not self:GetParent().buttons then self:GetParent().buttons = {}; end tinsert(self:GetParent().buttons, self); else self:Hide() end end local function WebsiteButton_DesatureLogo(self) local parent = self:GetParent(); if parent.buttons then for i=1, #parent.buttons do parent.buttons[i].NormalTex:SetTexCoord(0, 0.5, 0, 1); parent.buttons[i].PushedTex:SetTexCoord(0, 0.5, 0, 1); parent.buttons[i].IsOn = false; end end end function WebsiteButton_OnClick(self) WebsiteButton_DesatureLogo(self) self.NormalTex:SetTexCoord(0.5, 1, 0, 1); self.PushedTex:SetTexCoord(0.5, 1, 0, 1); self.IsOn = true; self:GetParent().subType = websites[self:GetID()][1]; self:GetParent():Click(); end local function SetClipboard(self, type, subType) local frame = self or Narci_XmogButtonPopUp.CopyButton; local type = type or frame.CodeType or "TEXT"; local subType = subType or frame.GearTexts.BBSCode.subType or "Wowhead"; local texts = CopyTexts(type, subType); frame.GearTexts:SetText(texts); if frame.GearTexts then frame.GearTexts:SetFocus(); frame.GearTexts:HighlightText(); end end local codeTokens = { [1] = "TEXT", [2] = "BBS", [3] = "MARKDOWN", } function Narci_CodeTokenButton_OnClick(self) self:GetParent():GetParent().CodeType = codeTokens[self:GetID()]; SetClipboard(); TokenButton_ClearMarker(self); self.HighlightColor:Show(); self.AnimFrame.Anim:SetScale(1.8); self.AnimFrame.Anim.Bling:Play(); end function IncludeIDButton_OnClick(self) self.IsOn = not self.IsOn if self.IsOn then self.Tick:Show(); Narci_XmogButtonPopUp.CopyButton.showItemID = true; else self.Tick:Hide(); Narci_XmogButtonPopUp.CopyButton.showItemID = false; end SetClipboard() end function Narci_CopyButton_OnClick(self) self.IsOn = not self.IsOn; if self.IsOn then SetClipboard(self); FadeFrame(self.GearTexts, 0.25, 1); else FadeFrame(self.GearTexts, 0.25, 0); end self.AnimFrame.Anim:SetScale(1.5); self.AnimFrame.Anim.Bling:Play(); end --Narci_EmoteButton local EmoteTokenList = { [1] = {{"Talk", EMOTE94_CMD1}, {"TALKEX", EMOTE95_CMD1} , {"TALKQ", EMOTE96_CMD2} , {"Flee", YELL} }, [2] = {{"Kiss", EMOTE59_CMD1}, {"Salute", EMOTE79_CMD1} , {"Bye", EMOTE102_CMD1}, {"Bow", EMOTE17_CMD1} }, [3] = {{"Dance", EMOTE35_CMD1}, {"Read", EMOTE453_CMD2}, {"Train", EMOTE155_CMD1}, {"Chicken", EMOTE22_CMD1} }, [4] = {{"Clap", EMOTE24_CMD1}, {"Cheer", EMOTE21_CMD1}, {"Cackle", EMOTE61_CMD1} }, [5] = {{"Nod", EMOTE68_CMD1}, {"Doubt", EMOTE67_CMD1}, {"Point", EMOTE73_CMD1} }, [6] = {{"Rude", EMOTE78_CMD1}, {"Flex", EMOTE42_CMD1}, {"ROAR", EMOTE76_CMD1}}, [7] = {{"Cower", EMOTE29_CMD1}, {"Beg", EMOTE8_CMD1}, {"Cry", EMOTE32_CMD1}}, [8] = {{"Laydown", EMOTE62_CMD1}, {"Stand", EMOTE143_CMD1}, {"Sit", EMOTE87_CMD1}, {"Kneel", EMOTE60_CMD1}}, } local function EmoteButton_CreateList(self, buttonTemplate, List) local ltrim = string.trim; local PopUp = self; local button, buttonWidth, buttonHeight; local buttons = {}; local initialPoint = "TOPLEFT"; local initialRelative = "TOPLEFT"; local point = "TOPLEFT"; local relativePoint = "TOPRIGHT"; local offsetX = 0; local subListNum, subListNum_Max = 1, 1; if List and List[1] then for i = 1, #List do subListNum = #List[i]; subListNum_Max = max(subListNum, subListNum_Max); end end for i = 1, #List do for j = 1 , subListNum_Max do button = CreateFrame("Button", nil, PopUp, buttonTemplate); if List[i][j] then local text = ltrim(List[i][j][2],"/"); --remove the slash if LanguageDetector(text) == "RM" then text = strupper(string.sub(text, 1, 1)) .. string.sub(text, 2); --upper initial end button.Label:SetText(text); button.Token = List[i][j][1]; else button.Label:SetText(" ") button.Token = nil; button:Disable(); end if i % 2 == 0 then button.Background:SetColorTexture(0.06, 0.06, 0.06, 0.8) end buttonWidth = button:GetWidth(); buttonHeight = button:GetHeight(); local offsetY = (1-i)*buttonHeight; if not buttons then button:SetPoint(initialPoint, PopUp, initialRelative, 0, offsetY); elseif j == 1 then button:SetPoint(initialPoint, PopUp, initialRelative, 0, offsetY); else local index = #buttons button:SetPoint(point, buttons[index], relativePoint, 0, 0); end tinsert(buttons, button); end end self.buttons = buttons; local popUpHeight = #List * buttonHeight; local popUpWidth = 4 * buttonWidth; PopUp:SetHeight(popUpHeight); PopUp:SetWidth(popUpWidth + 2 + 150); EmoteTokenList = nil; end function Narci_EmoteButtonPopUp_OnLoad(self) EmoteButton_CreateList(self, "NarciEmoteTokenButtonTemplate", EmoteTokenList); self.autoCapture = false; self:SetScript("OnEnter", function() Toolbar.OnEnter(); end); self:SetScript("OnLeave", function() if not self:IsMouseOver() then Toolbar.OnLeave(); end end); self.AutoCaptureButton:SetScript("OnEnter", function(f) f.Color:Show(); Toolbar.OnEnter(); end); self.AutoCaptureButton:SetScript("OnLeave", function(f) f.Color:Hide(); if not self:IsMouseOver() then Toolbar.OnLeave(); end end); end function Narci_EmoteButton_OnClick(self) self.IsOn = not self.IsOn local popupFrame = Narci_EmoteButtonPopUp; if not self.IsOn then PlayCheckSound(self, false) self.Icon:SetTexCoord(0, 0.5, 0, 1); self.UpdateFrame:Hide(); popupFrame.AnimFrame:Hide(); popupFrame.AnimFrame:Show(); popupFrame.AnimFrame.toY = -40; else PlayCheckSound(self, true) self.Icon:SetTexCoord(0.5, 1, 0, 1); popupFrame:Show(); popupFrame.AnimFrame:Hide(); popupFrame.AnimFrame:Show(); popupFrame.AnimFrame.toY = 8; end NarciTooltip:FadeOut(); if Narci_XmogButton.IsOn then Narci_XmogButtonPopUp.AnimFrame:Hide(); Narci_XmogButtonPopUp.AnimFrame:Show(); Narci_XmogButtonPopUp.AnimFrame.toY = -20; end end NarciEmoteTokenButtonMixin = {}; function NarciEmoteTokenButtonMixin:OnClick() Narci_EmoteButton.UpdateFrame.Emote = self.Token; if Narci_EmoteButton.IsOn then Narci_EmoteButton.UpdateFrame:Hide(); Narci_EmoteButton.UpdateFrame:Show(); end self.AnimFrame.Anim.Bling:Play(); end function NarciEmoteTokenButtonMixin:OnEnter() if self:IsEnabled() then local highlight = self:GetParent().HighlightColorFrame; highlight:SetParent(self); highlight:ClearAllPoints(); highlight:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0); highlight:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 0); highlight:Show(); end Toolbar.OnEnter(); end function NarciEmoteTokenButtonMixin:OnLeave() self:GetParent().HighlightColorFrame:Hide(); Toolbar.OnLeave(); end function EmoteButtonPopUp_AnimFrame_OnUpdate(self, elapsed) local duration = 0.35; local t = self.TimeSinceLastUpdate; local frame = self:GetParent(); local offsetY = outSine(t, self.fromY, self.toY, duration) if not self.OppoDirection then frame:SetAlpha(2*t/duration); else frame:SetAlpha(1 - 1.5*t/duration); end if t >= duration then offsetY = self.toY; if not self.OppoDirection then frame:SetAlpha(1) frame:Show() else frame:SetAlpha(0) frame:Hide() end self:Hide() return; end frame:SetPoint(self.anchorPoint, self.relativeTo, self.relativePoint, self.toX, offsetY); self.TimeSinceLastUpdate = self.TimeSinceLastUpdate + elapsed; end function EmoteButton_UpdateFrame_OnShow(self) self.TimeSinceLastUpdate = 0; self.duration = self.duration or 0; DoEmote(self.Emote, "none"); if self.duration == 0 then self:Hide(); end if Narci_EmoteButtonPopUp.autoCapture then After(0.8, function() Screenshot() end) end end function EmoteButton_UpdateFrame_OnUpdate(self, elapsed) self.TimeSinceLastUpdate = self.TimeSinceLastUpdate + elapsed; if self.TimeSinceLastUpdate >= self.duration then DoEmote(self.Emote, "none"); self.TimeSinceLastUpdate = 0; end end function Narci_AutoCaptureButton_OnClick(self) self.IsOn = not self.IsOn if self.IsOn then self.Tick:Show(); self:GetParent().autoCapture = true; else self.Tick:Hide(); self:GetParent().autoCapture = false; end end function Narci_SetButtonColor(self) ColorUtil:SetWidgetColor(self.Color); ColorUtil:SetWidgetColor(self.HighlightColor); end function Narci_HideTextsButton_OnClick(self) self.IsOn = not self.IsOn NarcissusDB.PhotoModeButton.HideTexts = self.IsOn if not self.IsOn then PlayCheckSound(self, false) PhotoMode_RestoreCvar(PhotoMode_Cvar_NamesBackup); SetTracking(1, PhotoMode_Cvar_TrackingBAK); --Track Battle Pet self.Icon:SetTexCoord(0, 0.5, 0, 1); self.tooltip = {L["HideTexts Button"], L["HideTexts Button Tooltip Open"] .. "\n|cff6b6b6b"..L["HideTexts Button Tooltip Special"]}; else PlayCheckSound(self, true) PhotoMode_BackupCvar(PhotoMode_Cvar_NamesBackup, PhotoMode_Cvar_NamesList); PhotoMode_ZeroCvar(PhotoMode_Cvar_NamesBackup); PhotoMode_GetTrackingInfo(); SetTracking(1, false); self.Icon:SetTexCoord(0.5, 1, 0, 1); self.tooltip = {L["HideTexts Button"], L["HideTexts Button Tooltip Close"] .. "\n|cff6b6b6b"..L["HideTexts Button Tooltip Special"]}; end NarciTooltip:FadeOut(); end function TopQualityButton_OnClick(self) self.IsOn = not self.IsOn if not self.IsOn then PlayCheckSound(self, false) PhotoMode_RestoreCvar(PhotoMode_Cvar_GraphicsBackup); self.Icon:SetTexCoord(0, 0.5, 0, 1); FadeFrame(TopQualityButton_MSAASlider, 0.25, 0); TopQualityButton_RayTracingToggle:FadeOut(); self.tooltip = {L["TopQuality Button"], L["TopQuality Button Tooltip Open"] .. "\n|cff6b6b6b"..L["HideTexts Button Tooltip Special"]}; else PlayCheckSound(self, true) PhotoMode_BackupCvar(PhotoMode_Cvar_GraphicsBackup, PhotoMode_Cvar_GraphicsList); PhotoMode_RestoreCvar(PhotoMode_Cvar_GraphicsList); self.Icon:SetTexCoord(0.5, 1, 0, 1); FadeFrame(TopQualityButton_MSAASlider, 0.25, 1); TopQualityButton_RayTracingToggle:FadeIn(); self.tooltip = {L["TopQuality Button"], L["TopQuality Button Tooltip Close"] .. "\n|cff6b6b6b"..L["HideTexts Button Tooltip Special"]}; end NarciTooltip:FadeOut(); end function TopQualityButton_MSAASlider_OnValueChanged(self, value, userInput) if not self:IsShown() then return; end self.VirtualThumb:SetPoint("CENTER", self.Thumb, "CENTER", 0, 0) if value ~= self.oldValue then self.oldValue = value local value, valueText = tonumber(value), ""; if value ~= 0 then if value == 1 then valueText = "2x"; elseif value == 2 then valueText = "4x"; elseif value == 3 then valueText = "8x"; end valueText = "|cfffced00"..valueText; else valueText = "|cffee3224".."OFF"; end self.KeyLabel2:SetText(MULTISAMPLE_ANTI_ALIASING.." "..valueText) if value ~=0 then ConsoleExec("MSAAQuality "..value..",0" ) else ConsoleExec("MSAAQuality 0") end end 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 ---------------------------- --[[ Set Graphics Settings to Ultra ffxAntiAliasingMode 2-3 MSAAQuality = not advanced graphicsTextureResolution 3 graphicsTextureFiltering 6 graphicsProjectedTextures 2 graphicsViewDistance 10 graphicsEnvironmentDetail 10 graphicsGroundClutter 10 graphicsShadowQuality 6 graphicsLiquidDetail 6 graphicsSunshafts 3 graphicsParticleDensity 5 graphicsSSAO 5 graphicsDepthEffects 4 graphicsLightingQuality 3 --]] ------Photo Mode Toolbar------ NarciPhotoModeToolbarMixin = {}; function NarciPhotoModeToolbarMixin:OnLoad() Toolbar = self; local animRotation = NarciAPI_CreateAnimationFrame(0.6); self.animRotation = animRotation; animRotation:SetScript("OnUpdate", function(frame, elapsed) local t = frame.total + elapsed; frame.total = t; local radian = outSine(t, frame.fromRadian, frame.toRadian, frame.duration); local width = outSine(t, frame.fromWidth, frame.toWidth, frame.duration); if t >= frame.duration then radian = frame.toRadian; width = frame.toWidth; frame:Hide(); if self.Switch.IsOn then self.Bar:SetClipsChildren(false); else self.Bar:SetClipsChildren(true); end end self.Switch.Ring:SetRotation(radian); self.Bar:SetWidth(width); end) animRotation:SetScript("OnShow", function(frame) frame.fromRadian = self.Switch.Ring:GetRotation(); frame.fromWidth = self.Bar:GetWidth(); end) self.Switch.Ring:SetRotation(2*pi); local animFly = NarciAPI_CreateAnimationFrame(0.4); self.animFly = animFly; animFly:SetScript("OnUpdate", function(frame, elapsed) local t = frame.total + elapsed; frame.total = t; local offsetY = outSine(t, frame.fromY, frame.toY, frame.duration); if t >= frame.duration then offsetY = frame.toY; frame:Hide(); if self.shouldHide then self:Hide(); end end self:SetPoint("BOTTOMLEFT", 10, offsetY); end); local animFade = NarciAPI_CreateAnimationFrame(0.4); self.animFade = animFade; animFade.defaultAlpha = 1; --visible the first time user enters Narcissus animFade:SetScript("OnUpdate", function(frame, elapsed) local t = frame.total + elapsed; frame.total = t; local alpha = frame.fromAlpha + frame.speed * elapsed; if alpha > 1 then alpha = 1; elseif alpha < 0 then alpha = 0; end frame.fromAlpha = alpha if t >= frame.duration then alpha = frame.toAlpha; frame:Hide(); end self:SetAlpha(alpha); end) local function AutoHideContainer_OnEnter() self:FadeTo(1, 0.2); end local function AutoHideContainer_OnLeave() if self:ShouldBeVisible() then return end; self:FadeTo(0, 0.2); if not self.Switch.IsOn then self.Bar:SetAlpha(0); end Narci_GearTexts:ClearFocus(); Narci_GearTexts:HighlightText(0,0); return true end Toolbar.OnEnter = AutoHideContainer_OnEnter; Toolbar.OnLeave = AutoHideContainer_OnLeave; local function AutoHideTimer_OnFinished(animationGroup) if not AutoHideContainer_OnLeave() then animationGroup:Play(); end end self.AutoHideContainer:SetScript("OnEnter", AutoHideContainer_OnEnter); self.AutoHideContainer:SetScript("OnLeave", AutoHideContainer_OnLeave); self.AutoHideContainer.AutoHideTimer:SetScript("OnFinished", AutoHideTimer_OnFinished); self:SetScript("OnLoad", nil); self.OnLoad = nil; end function NarciPhotoModeToolbarMixin:ShouldBeVisible() return (self.AutoHideContainer:IsMouseOver()) and not (Narci_EquipmentOption:HasMouseFocus()) end function NarciPhotoModeToolbarMixin:DisableAll() local Bar = self.Bar; if Bar.Emote.IsOn then Bar.Emote:Click(); end if Bar.HideTexts.IsOn then Bar.HideTexts:Click(); NarcissusDB.PhotoModeButton.HideTexts = true; end if Bar.Xmog.IsOn then Bar.Xmog:Click() --Quit Xmog Mode end if Bar.TopQuality.IsOn then Bar.TopQuality:Click(); end end function NarciPhotoModeToolbarMixin:OnHide() self:DisableAll(); self:UnregisterEvent("PLAYER_LOGOUT"); self.animFly:Hide(); self.animFade:Hide(); self.AutoHideContainer.AutoHideTimer:Stop(); end function NarciPhotoModeToolbarMixin:OnShow() self:RegisterEvent("PLAYER_LOGOUT"); ColorUtil:UpdateByMapID(); self.AutoHideContainer:Show(); end function NarciPhotoModeToolbarMixin:OnEvent(event) self:DisableAll(); SetCVar("Sound_MusicVolume", CVarTemp.MusicVolume); if CVarTemp.DynamicPitch ~= 1 then --Restore the acioncam state SetCVar("test_cameraDynamicPitch", 0); ConsoleExec( "actioncam off"); end ViewProfile:ResetView(5); end function NarciPhotoModeToolbarMixin:FadeTo(toAlpha, duration) --Only changes alpha not show/hide status local f = self.animFade; f:Hide(); f.total = 0; f.fromAlpha = self:GetAlpha(); duration = duration or 0.4; f.duration = duration; local delta = toAlpha - f.fromAlpha; if delta > 0 then f.speed = 1/duration; elseif delta < 0 then f.speed = -1/duration; else return end if self:ShouldBeVisible() then f.toAlpha = 1; else f.toAlpha = toAlpha or f.defaultAlpha; end if f.defaultAlpha == 1 then if NarcissusDB.LetterboxEffect then f.toAlpha = 0; end f.defaultAlpha = 0; end f:Show(); end function NarciPhotoModeToolbarMixin:FlyIn(toAlpha) local f = self.animFly; f:Hide(); f.total = 0; f.fromY = -80; f.toY = 10; f:Show(); self.shouldHide = nil; self:Show(); self:FadeTo(toAlpha or self.animFade.defaultAlpha or 1); self.AutoHideContainer.AutoHideTimer:Play(); end function NarciPhotoModeToolbarMixin:FlyOut() local f = self.animFly; if f.toY == -80 then return end f:Hide(); f.total = 0; f.fromY = 10; f.toY = -80; self.shouldHide = true; f:Show(); self:FadeTo(0); end function NarciPhotoModeToolbarMixin:UseLowerLevel(state) local strata; if state then strata = "BACKGROUND"; self:DisableMotion(); else strata = "HIGH"; self:EnableMotion(); end self:SetFrameStrata(strata); self.PreferenceToggle:SetFrameStrata(strata); self.AutoHideContainer:SetFrameStrata("LOW"); self.MotionBlock:SetFrameStrata("BACKGROUND"); self.MotionBlock:SetFrameLevel(self:GetFrameLevel() + 3); self.MotionBlock:SetShown(state); end function NarciPhotoModeToolbarMixin:DisableMotion() self.AutoHideContainer:Hide(); self:SetAlpha(0); end function NarciPhotoModeToolbarMixin:EnableMotion() self.AutoHideContainer:Show(); end function Narci_PhotoModeButton_OnClick(self, key) self.IsOn = not self.IsOn; local updateFrame = self:GetParent().animRotation; updateFrame:Hide(); local barWidth = self:GetParent().Bar:GetWidth(); if self.IsOn then updateFrame.duration = math.min(0.6, math.sqrt(0.4 * (220 - barWidth)/180) ); updateFrame.toRadian = 1.25*pi; updateFrame.toWidth = 220; else updateFrame.duration = math.min(0.6, math.sqrt(0.4 * (barWidth - 40)/180) ); updateFrame.toRadian = 2*pi; updateFrame.toWidth = 40; end updateFrame:Show(); if self.IsOn then self.Icon:SetTexCoord(0.25, 0.5, 0.75, 1); Toolbar.Bar:SetAlpha(1) else self.Icon:SetTexCoord(0, 0.25, 0.75, 1); Toolbar.Bar:SetClipsChildren(true); end NarciTooltip:FadeOut(); TemporarilyHidePopUp(Narci_XmogButtonPopUp); TemporarilyHidePopUp(Narci_EmoteButtonPopUp); end hooksecurefunc("SetUIVisibility", function(state) if IS_OPENED then --when Narcissus hide the UI if state then MsgAlertContainer:SetDND(true); Toolbar:UseLowerLevel(true); else if NarcissusDB.PhotoModeButton.HideTexts and (not Narci_HideTextsButton.IsOn) then Narci_HideTextsButton:Click(); end 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 SmoothShoulderCVar(CVarTemp.OverShoulder); if not GetKeepActionCam() then After(0.6, function() ConsoleExec( "actioncam off" ); end) end if Toolbar:IsShown() then Toolbar:FlyOut(); NarciCameraOffsetControlBar.Thumb:SetPoint("CENTER", 0, 0); end else local bar = Toolbar; if not bar:IsShown() then CVarTemp.OverShoulder = GetCVar("test_cameraOverShoulder"); end bar:FlyIn(0); bar.ExitButton:Hide(); if NarcissusDB.PhotoModeButton.HideTexts and (not Narci_HideTextsButton.IsOn) then Narci_HideTextsButton:Click(); end Narci_XmogButton:Disable(); end end end) SLASH_NARCI1 = "/narci"; SLASH_NARCI2 = "/narcissus"; SlashCmdList["NARCI"] = function(msg) msg = string.lower(msg); if msg == "" then MiniButton:Click(); elseif msg == "minimap" then MiniButton:Show(); MiniButton:PlayBling(); NarcissusDB.ShowMinimapButton = true; print("Minimap button has been re-enabled."); elseif msg == "itemlist" then DressUpFrame_Show(DressUpFrame); elseif msg == "parser" then FadeFrame(Narci_ItemParser, 0.25, 1); else local color = "|cff40C7EB"; print(color.."Show Minimap Button:|r /narci minimap"); print(color.."Copy Item List:|r /narci itemlist"); print(color.."Corruption Item Parser:|r /narci parser"); end end function Narci_ModelToggle_OnClick(self) self:Disable() After(1, function() self:Enable() end) self.AnimFrame.Anim:SetScale(1.5) self.AnimFrame.Anim.Bling:Play(); NarcissusDB.AlwaysShowModel = not NarcissusDB.AlwaysShowModel; self.IsOn = NarcissusDB.AlwaysShowModel; self.Tick:SetShown(self.IsOn); Narci_AlwaysShowModelToggle.Tick:SetShown(self.IsOn); if self.IsOn and xmogMode == 1 then if not NarciPlayerModelFrame1:IsVisible() then if xmogMode == 1 then NarciModel_RightGradient:Hide(); end Narci_PlayerModelAnimIn:Show() end elseif xmogMode ~= 2 then HidePlayerModel() end end function Narci_XmogLayoutButton_OnClick(self) self:Disable() After(0.8, function() self:Enable() end) self.ShowModel = not self.ShowModel; if self.ShowModel then UseXmogLayout(2) else UseXmogLayout(1) end self.AnimFrame.Anim:SetScale(1.5) self.AnimFrame.Anim.Bling:Play() end local function HideContollerButton(state) if state then Narci_XmogButton:Hide() Narci_EmoteButton:Hide() Narci_HideTextsButton:Hide() Narci_TopQualityButton:Hide() else Narci_XmogButton:Show() Narci_EmoteButton:Show() Narci_HideTextsButton:Show() Narci_TopQualityButton:Show() end end function PhotoMode_WheelEventContrainer_OnMouseWheel(self, delta) if Narci_PhotoModeButton.IsOn then if NarciCameraOffsetControlBar:IsShown() then CameraControlBar_ResetPosition(true) end TemporarilyHidePopUp(Narci_XmogButtonPopUp); TemporarilyHidePopUp(Narci_EmoteButtonPopUp); AnimationSequenceContainer_Controller:Hide() AnimationSequenceContainer_Controller:Show() end end local function TemporarilyDisableWheel(frame) frame:SetScript("OnMouseWheel", function(self, delta) end) After(0.2, function() frame:SetScript("OnMouseWheel", PhotoMode_WheelEventContrainer_OnMouseWheel) end) end ---------------- --3D Animation-- local ASC = CreateFrame("Frame", "AnimationSequenceContainer_Controller"); ASC:Hide(); 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 function Controller_AnimationSequence_OnUpdate(self, elapsed) if self.Pending then return; end self.t = self.t + elapsed; self.totalTime = self.totalTime + 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 Narci_PhotoModeButton:SetAlpha(1); Toolbar.Bar:SetAlpha(1); if self.OppoDirection then FadeFrame(PhotoModeControllerTransition.Sequence, 0.2, 0) HideContollerButton(false) Narci_PhotoModeButton:SetAlpha(1); Toolbar.Bar:SetAlpha(1); NarciCameraOffsetControlBar:Hide() else HideContollerButton(true) NarciCameraOffsetControlBar:Show() NarciCameraOffsetControlBar:SetAlpha(1); FadeFrame(PhotoModeControllerTransition.Sequence, 0.2, 0) After(0.25, function() CameraControlBar_ResetPosition(false) end) end TemporarilyDisableWheel(PhotoMode_WheelEventContrainer); self:Hide() self.IsPlaying = false; return; end --NarciCameraOffsetControlBar:SetAlpha(0); Narci_PhotoModeButton:SetAlpha(0); Toolbar.Bar:SetAlpha(0); end end ASC:SetScript("OnUpdate", Controller_AnimationSequence_OnUpdate) ASC:SetScript("OnHide", AnimationContainer_OnHide) ASC:SetScript("OnShow", function(self) self.IsPlaying = true; end) 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); function CameraControlBar_ResetPosition_AnimFrame_OnShow(self) local StartX = NarciCameraOffsetControlBar.PosX or 0; local StartAngle = NarciCameraOffsetControlBar.PosRadian or 0; self.tOut = max(math.abs(StartX) / NarciCameraOffsetControlBar.Range, math.abs(StartAngle)/(2*pi), 0.2) end function CameraControlBar_ResetPosition_AnimFrame_OnUpdate(self, elapsed) AnimationSequenceContainer_Controller.Pending = true; self.TimeSinceLastUpdate = self.TimeSinceLastUpdate + elapsed local StartX, EndX, StartAngle, EndAngle, t; if self.OppoDirection then StartX = NarciCameraOffsetControlBar.PosX or 0; EndX = 0; StartAngle = NarciCameraOffsetControlBar.PosRadian or 0; EndAngle = 0; t = self.tOut else StartX = 0; EndX = NarciCameraOffsetControlBar.PosX or 0; StartAngle = 0; EndAngle = NarciCameraOffsetControlBar.PosRadian or 0; --NarciCameraOffsetControlBar.PosRadian or t = 0.5 end local Value_Angle = outSine(self.TimeSinceLastUpdate, StartAngle, EndAngle, t) local Value_X = outSine(self.TimeSinceLastUpdate, StartX, EndX, t) RotateShaftNode(Value_Angle) CameraControllerThumb:SetPoint("CENTER", Value_X, 0); if self.TimeSinceLastUpdate >= t then RotateShaftNode(EndAngle) CameraControllerThumb:SetPoint("CENTER", EndX, 0); self:Hide(); AnimationSequenceContainer_Controller.Pending = false; NarciCameraOffsetControlBar.PosRadian = 0; end end function CameraControlBar_ResetPosition(bool) if NarciCameraOffsetControlBar:IsShown() and (not AnimationSequenceContainer_Controller.IsPlaying) then CameraControlBar_ResetPosition_AnimFrame.OppoDirection = bool AnimationSequenceContainer_Controller.Pending = true; CameraControlBar_ResetPosition_AnimFrame:Show(); end end local raceList = { --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 √ }, } 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 _, inAlternateForm = GetAlternateFormInfo(); if not inAlternateForm then raceID = 128; end end local model; if raceList[raceID] and raceList[raceID][GenderID] then if Narci_FigureModelReference then Narci_FigureModelReference:SetPoint("CENTER", raceList[raceID][GenderID][1], raceList[raceID][GenderID][2]) end for i = 1, #ModelPieces do model = ModelPieces[i]; model:SetUnit(unit); model:SetCamera(raceList[raceID][GenderID][5]); model:MakeCurrentCameraCustom(); if raceList[raceID][GenderID][3] then model:SetCameraDistance(raceList[raceID][GenderID][3]) end if raceList[raceID][GenderID][4] then a1, a2, a3 = model:GetCameraPosition(); model:SetCameraPosition(a1, a2, raceList[raceID][GenderID][4]) end if raceList[raceID][GenderID][6] then model:SetAnimation(2, raceList[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); model:SetLight(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("ADDON_LOADED"); EL:RegisterEvent("PLAYER_ENTERING_WORLD"); EL:RegisterEvent("UNIT_NAME_UPDATE"); 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:RegisterEvent("COVENANT_SANCTUM_RENOWN_LEVEL_CHANGED"); EL:SetScript("OnEvent",function(self, event, ...) --print(event) if event == "ADDON_LOADED" then local name = ...; if name ~= "Narcissus" then return; end self:UnregisterEvent(event); AssignFrame(); AssignFrame = nil; ShowDetailedIlvlInfo(); After(2, function() Narci_AliasButton_SetState(); Narci_SetActiveBorderTexture(); StatsUpdator:Instant(); RadarChart:SetValue(0,0,0,0,1); UpdateXmogName(); end) local AnimSequenceInfo = Narci.AnimSequenceInfo; InitializeAnimationContainer(ASC2, AnimSequenceInfo["Heart"], Narci_HeartofAzeroth_AnimFrame.Sequence) InitializeAnimationContainer(ASC, AnimSequenceInfo["Controller"], PhotoModeControllerTransition.Sequence) local HeartSerialNumber = strsub(UnitGUID("player"), 8, 15); Narci_HeartofAzeroth_AnimFrame.SN:SetText("No."..HeartSerialNumber); --[[ local timeStart = Narci.timeLoadingStart; local timeFinished = GetTimePreciseSec(); print("Loading Time: "..(timeFinished - timeStart)) --]] elseif event == "PLAYER_ENTERING_WORLD" then self:UnregisterEvent(event); MiniButton:InitPosition(); UpdateXmogName(); SetCVar("CameraKeepCharacterCentered", 0); --CameraMover:SetBlend(NarcissusDB.CameraTransition); --Load in Preference.lua DefaultTooltip = NarciGameTooltip; --Created in NarciAPI.lua DefaultTooltip:SetParent(Narci_Character); DefaultTooltip:SetFrameStrata("TOOLTIP"); DefaultTooltip.offsetX = 6; DefaultTooltip.offsetY = -18; DefaultTooltip:SetIgnoreParentScale(true); DefaultTooltip:SetIgnoreParentAlpha(true); local HotkeyFrame = CreateFrame("Frame", nil, Narci_Attribute, "NarciHotkeyNotificationTemplate"); HotkeyFrame:SetKey(NARCI_MODIFIER_ALT, "LeftButton", L["Swap items"]); HotkeyFrame:SetPoint("BOTTOM", DefaultTooltip, "TOP", -2, 8); HotkeyFrame:SetFrameStrata("TOOLTIP"); HotkeyFrame:SetIgnoreParentScale(true); DefaultTooltip.HotkeyFrame = HotkeyFrame; DefaultTooltip:HookScript("OnHide", function() HotkeyFrame:FadeOut(); end) MiniButton:SetBackground(); 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(); end After(1.7, function() UpdateCharacterInfoFrame(); hooksecurefunc("CameraZoomIn", function(increment) if IS_OPENED and (xmogMode ~= 1) then UpdateShoulderCVar:Start(-increment, true); end end) hooksecurefunc("CameraZoomOut", function(increment) if IS_OPENED and (xmogMode ~= 1)then UpdateShoulderCVar:Start(increment, true); end end) end) --Cache if false then MiniButton:Disable(); --Disable minimap button while caching After(1.3, function() CacheSourceInfo(); end) After(2.9, function() MOG_MODE = true; USE_DELAY = true; SlotController:RefreshAll(); --Cache transmog appearance sources end) After(3.7, function() MOG_MODE = false; SlotController:RefreshAll(); MiniButton:Enable(); MiniButton:SetMotionScriptsWhileDisabled(false); end) end elseif event == "PLAYER_EQUIPMENT_CHANGED" then local slotID, isItem = ...; --CacheSourceInfo(slotID) USE_DELAY = false; SlotController:Refresh(slotID); if EquipmentFlyoutFrame:IsShown() and EquipmentFlyoutFrame.slotID == slotID then EquipmentFlyoutFrame:DisplayItemsBySlotID(slotID, false); end USE_DELAY = true; ItemLevelFrame:UpdateDomination(); 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.isRefreshing then self.isRefreshing = true; After(0, function() -- only want 1 update per 0.1s ItemLevelFrame:Update(); After(0.1, function() self.isRefreshing = nil; end) end) end elseif event == "COVENANT_CHOSEN" then local covenantID = ...; ItemLevelFrame:Update(); 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); 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 elseif event == "PLAYER_TARGET_CHANGED" then RefreshStats(8); --Armor RefreshStats(9); --Damage Reduction elseif event == "UPDATE_SHAPESHIFT_FORM" then ModifyCameraForShapeshifter(); CameraMover:OnCameraChanged(); elseif event == "PLAYER_MOUNT_DISPLAY_CHANGED" then ModifyCameraForMounts(); CameraMover:OnCameraChanged(); 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:UpdateDomination(); elseif event == "UNIT_INVENTORY_CHANGED" then SlotController:LazyRefresh("temp"); end end) function EL:ToggleDynamicEvents(state) local dynamicEvents = {"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", }; local unitEvents = {"UNIT_DAMAGE", "UNIT_ATTACK_SPEED", "UNIT_MAXHEALTH", "UNIT_AURA", "UNIT_INVENTORY_CHANGED"}; if state then for i = 1, #dynamicEvents do self:RegisterUnitEvent(dynamicEvents[i]); end for i = 1, #unitEvents do self:RegisterUnitEvent(unitEvents[i], "player"); end else for i = 1, #dynamicEvents do self:UnregisterEvent(dynamicEvents[i]); end for i = 1, #unitEvents do self:UnregisterEvent(unitEvents[i]); end end dynamicEvents = nil; unitEvents = nil; end EL:SetScript("OnShow",function(self) self:ToggleDynamicEvents(true); if NarciAR then NarciAR:Show(); end end) EL:SetScript("OnHide",function(self) self:ToggleDynamicEvents(false); self:UnregisterEvent("UPDATE_SHAPESHIFT_FORM"); 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; 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_SetActiveBorderTexture() local themeName = NarciAPI.GetBorderThemeName(); local MinimapButton = MiniButton; local minimapBackgroundSize = 42; local slotWidth, slotHeight, iconSize, slotShadow, runePlateVisible; local borderSize; if themeName == "Dark" then slotWidth = 70; slotHeight = 72; iconSize = 50; borderSize = 128; runePlateVisible = false; else slotWidth = 64; slotHeight = 68; iconSize = 48; borderSize = 64; runePlateVisible = true; end for slotID, slotButton in pairs(slotTable) do --slotButton.RuneSlot.Background:SetShown(runePlateVisible); slotButton.Icon:SetSize(iconSize, iconSize); slotButton:SetSize(slotWidth, slotHeight); slotButton.Border:SetSize(borderSize, borderSize); end SlotController:LazyRefresh(); --Optimize this minimap button's radial offset local IsAddOnLoaded = IsAddOnLoaded; if IsAddOnLoaded("AzeriteUI") then MapShapeUtil.cornerRadius = 18; minimapBackgroundSize = 48; --Skin Tooltip --Background gets reset once gametooltip is hidden. Ask Goldpaw some day. local backdropInfo = { bgFile = "Interface\\AddOns\\AddOns\\Narcissus\\Art\\Masks\\Full", edgeFile = "Interface\\AddOns\\AzeriteUI\\media\\tooltip_border_hex", tile = true, tileEdge = true, tileSize = 24, edgeSize = 24, insets = { left = 8, right = 8, top = 8, bottom = 8 }, }; DefaultTooltip.backdropInfo = backdropInfo; DefaultTooltip.offsetX = 2; DefaultTooltip.offsetY = -12; DefaultTooltip:HookScript("OnShow", function(self) self:SetPadding(8, 8, 8, 8); end) elseif IsAddOnLoaded("DiabolicUI") then MapShapeUtil.cornerRadius = 12; elseif IsAddOnLoaded("GoldieSix") then --GoldpawUI MapShapeUtil.cornerRadius = 18; elseif IsAddOnLoaded("GW2_UI") then MapShapeUtil.cornerRadius = 44; elseif IsAddOnLoaded("SpartanUI") then MapShapeUtil.cornerRadius = 8; else MapShapeUtil.cornerRadius = 10; end MinimapButton.Background:SetSize(minimapBackgroundSize, minimapBackgroundSize); end function Narci_GuideLineFrame_OnSizing(self, offset) local W; local W0, H = WorldFrame:GetSize(); if (W0 and H) and H ~= 0 then self:ClearAllPoints(); self:SetPoint("TOP", UIParent, "TOP", 0, 0); self:SetPoint("BOTTOM", UIParent, "BOTTOM", 0, 0); local 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 function Narci:SetReferenceFrameOffset(offset) --A positive offset expands the reference frame. Narci_GuideLineFrame_OnSizing(Narci_GuideLineFrame, -offset); end NarciRayTracingToggleMixin = {}; function NarciRayTracingToggleMixin:SetVisual(level) if level and level > 0 then self.Label:SetText("|cffd9d9d9RTX|r ".. level); self.Fill:SetWidth(level * 42/3); self.Fill:Show(); else self.Label:SetText("|cffd9d9d9RTX|r OFF"); self.Fill:Hide(); end end function NarciRayTracingToggleMixin:SetLevel(level) level = tonumber(level) or 0; if level > 3 then level = 3; end self:SetVisual(level); SetCVar("shadowrt", level); end function NarciRayTracingToggleMixin:Restore() if self.oldValue then self:SetLevel(self.oldValue); end end function NarciRayTracingToggleMixin:OnClick() self.IsOn = not self.IsOn; if self.IsOn then self:SetLevel(3); else self:Restore(); end end function NarciRayTracingToggleMixin:OnShow() local level = tonumber(GetCVar("shadowrt")); self.oldValue = level; self:SetVisual(level); end function NarciRayTracingToggleMixin:OnHide() self.IsOn = false; end function NarciRayTracingToggleMixin:OnEnter() self.Fill:SetAlpha(1); self.Background:SetAlpha(1); end function NarciRayTracingToggleMixin:OnLeave() self.Fill:SetAlpha(0.5); self.Background:SetAlpha(0.5); end function NarciRayTracingToggleMixin:OnLoad() local validity; if Advanced_RTShadowQualityDropDown then validity = true; end local info = { GetToolTipInfo(1, 4, "shadowrt", 0, 1, 2, 3) }; for i = 1, #info do if info[i] ~= 0 then validity = validity and false; break; end end self.isValid = validity; if not validity then self:Hide(); self:Disable(); TopQualityButton_MSAASlider:SetPoint("TOPLEFT", Narci_XmogButton, "BOTTOMLEFT", 4, -12); end self:SetScript("OnLoad", nil); self.OnLoad = nil; end function NarciRayTracingToggleMixin:FadeIn() if self.isValid then FadeFrame(TopQualityButton_RayTracingToggle, 0.25, 1); end end function NarciRayTracingToggleMixin:FadeOut() if self.isValid then FadeFrame(TopQualityButton_RayTracingToggle, 0.25, 0); end 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 slotTable[slotID] end; Narci.RefreshSlot = function(slotID) SlotController:Refresh(slotID) return slotTable[slotID] end; Narci.RefreshAllSlots = SlotController.RefreshAll; Narci.RefreshAllStats = StatsUpdator.Instant; --[[ 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 --]]