local _, addon = ... local API = addon.API; local Narci = Narci; local MsgAlertContainer = addon.MsgAlertContainer; local TransitionAPI = addon.TransitionAPI; local SlotButtonOverlayUtil = addon.SlotButtonOverlayUtil; local TimerunningUtil = addon.TimerunningUtil; local TalentTreeDataProvider = addon.TalentTreeDataProvider; local CameraUtil = addon.CameraUtil; local UIParentFade = addon.UIParentFade; local CallbackRegistry = addon.CallbackRegistry; local SharedBlackScreen = addon.SharedBlackScreen; Narci.refreshCombatRatings = true; local SLOT_TABLE = {}; Narci.slotTable = SLOT_TABLE; local AttributeFrames = {}; local ShortAttributeFrames = {}; local L = Narci.L; local VIGNETTE_ALPHA = 0.5; local IS_OPENED = false; --Addon was opened by clicking local MOG_MODE = false; local SHOW_MISSING_ENCHANT_ALERT = true; local IS_LEGION_REMIX = false; local NarciAPI = NarciAPI; local GetItemEnchantID = NarciAPI.GetItemEnchantID; local GetItemEnchantText = NarciAPI.GetEnchantTextByItemLink; local EnchantInfo = Narci.EnchantData; --Bridge/GearBonus.lua local GetOverrideItemIcon = NarciAPI.GetOverrideItemIcon; local PlayLetteboxAnimation = NarciAPI_LetterboxAnimation; local SmartFontType = NarciAPI.SmartFontType; local IsItemSocketable = NarciAPI.IsItemSocketable; local SetBorderTexture = NarciAPI.SetBorderTexture; local GetBorderArtByItemID = NarciAPI.GetBorderArtByItemID; local GetVerticalRunicLetters = NarciAPI.GetVerticalRunicLetters; local FadeFrame = NarciFadeUI.Fade; local outSine = addon.EasingFunctions.outSine; local GetToolbarButtonByButtonType = addon.GetToolbarButtonByButtonType; local TransmogDataProvider = addon.TransmogDataProvider; local ConfirmBinding = addon.ConfirmBinding; --local GetCorruptedItemAffix = NarciAPI_GetCorruptedItemAffix; local Narci_AlertFrame_Autohide = Narci_AlertFrame_Autohide; local C_Item = C_Item; local GetItemInfo = C_Item.GetItemInfo; local GetItemInfoInstant = C_Item.GetItemInfoInstant; local C_LegendaryCrafting = C_LegendaryCrafting; local C_TransmogCollection = C_TransmogCollection; local After = C_Timer.After; local ItemLocation = ItemLocation; local IsPlayerInAlteredForm = TransitionAPI.IsPlayerInAlteredForm; local InCombatLockdown = InCombatLockdown; local GetInventoryItemTexture = GetInventoryItemTexture; local GetCameraZoom = GetCameraZoom; local GetSpellInfo = TransitionAPI.GetSpellInfo; local floor = math.floor; local max = math.max; local UIParent = _G.UIParent; local Toolbar = NarciScreenshotToolbar; local EquipmentFlyoutFrame; local ItemLevelFrame; local RadarChart; local ItemTooltip; local MiniButton = Narci_MinimapButton; local EL = CreateFrame("Frame"); --Event Listener EL:Hide(); EL.EVENTS_DYNAMIC = {"PLAYER_TARGET_CHANGED", "COMBAT_RATING_UPDATE", "PLAYER_MOUNT_DISPLAY_CHANGED", "PLAYER_STARTED_MOVING", "PLAYER_REGEN_DISABLED", "UNIT_MAXPOWER", "PLAYER_STARTED_TURNING", "PLAYER_STOPPED_TURNING", "BAG_UPDATE_COOLDOWN", "UNIT_STATS", "BAG_UPDATE", "PLAYER_EQUIPMENT_CHANGED", "AZERITE_ESSENCE_ACTIVATED", }; if API.IsPlayerDruid() then table.insert(EL.EVENTS_DYNAMIC, "UPDATE_SHAPESHIFT_FORM"); end EL.EVENTS_UNIT = {"UNIT_DAMAGE", "UNIT_ATTACK_SPEED", "UNIT_MAXHEALTH", "UNIT_AURA", "UNIT_INVENTORY_CHANGED", "UNIT_PORTRAIT_UPDATE"}; --take out frames from UIParent, so they will still be visible when UI is hidden local FRAME_TAKEN = false; local function TakeOutFrames(state) if (not state) and (not FRAME_TAKEN) then return end; local frameNames = { "AzeriteEmpoweredItemUI", "AzeriteEssenceUI", "ItemSocketingFrame", }; local frame; if state then FRAME_TAKEN = true; 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 FRAME_TAKEN = false; for _, frameName in pairs(frameNames) do frame = _G[frameName]; if frame then frame:SetParent(UIParent); frame:SetScale(1); end end end end local DefaultTooltip; local ShowDelayedTooltip = NarciAPI_ShowDelayedTooltip; function Narci_ShowButtonTooltip(self) DefaultTooltip:HideTooltip(); DefaultTooltip:SetOwner(self, "ANCHOR_NONE"); if not self.tooltipHeadline then return end DefaultTooltip:SetPoint("BOTTOM", self, "TOP", 0, 2); DefaultTooltip:SetText(self.tooltipHeadline); if self.tooltipLine1 then DefaultTooltip:AddLine(self.tooltipLine1, 1, 1, 1, true); end if self.tooltipSpecial then DefaultTooltip:AddLine(" "); DefaultTooltip:AddLine(self.tooltipSpecial, 0.25, 0.78, 0.92, true); end DefaultTooltip:Show(); DefaultTooltip:FadeIn(); end function Narci:HideButtonTooltip() DefaultTooltip:HideTooltip(); ItemTooltip:HideTooltip(); end --CVar Backup local ConsoleExec = ConsoleExec; local GetCVar = C_CVar.GetCVar; local SetCVar = C_CVar.SetCVar; ConsoleExec("pitchlimit 88"); local CVarTemp = {}; function CVarTemp:BackUp() self.zoomLevel = GetCameraZoom(); self.dynamicPitch = tonumber(GetCVar("test_cameraDynamicPitch")); self.shoulderOffset = GetCVar("test_cameraOverShoulder"); self.cameraViewBlendStyle = GetCVar("cameraViewBlendStyle"); end function CVarTemp:BackUpDynamicCam() self.DynmicCamShoulderOffsetZoomUpperBound = DynamicCam.db.profile.shoulderOffsetZoom.lowerBound; DynamicCam.db.profile.shoulderOffsetZoom.lowerBound = 0; end function CVarTemp:RestoreDynamicCam() DynamicCam.db.profile.shoulderOffsetZoom.lowerBound = self.DynmicCamShoulderOffsetZoomUpperBound; end function CVarTemp.BackUpAndChangeOccludedSilhouette() CVarTemp.occludedSilhouettePlayer = GetCVar("occludedSilhouettePlayer"); SetCVar("occludedSilhouettePlayer", 0); end CallbackRegistry:Register("UIParent.OnHide", CVarTemp.BackUpAndChangeOccludedSilhouette); function CVarTemp.RestoreOccludedSilhouette() if CVarTemp.occludedSilhouettePlayer then SetCVar("occludedSilhouettePlayer", CVarTemp.occludedSilhouettePlayer); CVarTemp.occludedSilhouettePlayer = nil; end end CallbackRegistry:Register("UIParent.OnShow", CVarTemp.RestoreOccludedSilhouette); local function GetKeepActionCam() return CVarTemp.isDynamicCamLoaded or CVarTemp.isActionCamPlusLoaded or (not CVarTemp.cameraSafeMode) end CVarTemp.shoulderOffset = tonumber(GetCVar("test_cameraOverShoulder")); CVarTemp.dynamicPitch = tonumber(GetCVar("test_cameraDynamicPitch")); --No CVar directly shows the current state of ActionCam. Check this CVar for the moment. 1~On 2~Off CVarTemp.zoomLevel = 2; local 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 local IntroMotion = {}; function IntroMotion:SetUseCameraTransition(enabled) local divisor; if enabled then --Smooth DURATION_TRANSLATION = 0.8; divisor = 20; else --Instant DURATION_TRANSLATION = 0.4; divisor = 80; end for k, slot in pairs(AttributeFrames) do local delay = (slot:GetID())/divisor; if slot.animIn then slot.animIn.A2:SetStartDelay(delay); end end for k, slot in pairs(ShortAttributeFrames) do local delay = (slot:GetID())/divisor; slot.animIn.A2:SetStartDelay(delay); end RadarChart.animIn.A2:SetStartDelay(9/divisor); self.useCameraTransition = enabled; end function IntroMotion:InstantZoomIn() SetCVar("cameraViewBlendStyle", 2); SetView(4); CameraUtil:InstantZoomIn(); self:ShowFrame(); UIParentFade:HideUIParent(); end function IntroMotion:Enter() SetCVar("test_cameraDynamicPitch", 1); if self.useCameraTransition then if NarcissusDB.CameraOrbit and not IsPlayerMoving() then if NarcissusDB.CameraOrbit then CameraUtil:SmoothYaw(); end SetView(2); end if not IsFlying("player") then CameraUtil:SmoothPitch(); end After(0.1, function() CameraUtil:ZoomToDefault(); After(0.7, function() self:ShowFrame(); end) end) UIParentFade:FadeOutUIParent(); else if not self.hasInitialized then if NarcissusDB.CameraOrbit then CameraUtil:SmoothYaw(); end SetView(2); CameraUtil:SmoothPitch(); After(0.1, function() CameraUtil:ZoomToDefault(); After(0.7, function() self:ShowFrame(); end) end) After(1, function() if not IsMounted() then self.hasInitialized = true; ViewProfile:SaveView(4); end end) UIParentFade:FadeOutUIParent(); else self:InstantZoomIn(); end end end function IntroMotion:PlayAttributeAnimation() if not NarcissusDB.DetailedIlvlInfo then RadarChart:UpdateChart(true); return end if not RadarChart:IsShown() then return --Attributes is not the active tab end local f, anim; for i = 1, 20 do f = AttributeFrames[i]; anim = f.animIn; if anim and not f.noAnimation then anim.A2:SetToAlpha(AttributeFrames[i]:GetAlpha()); anim:Play(); end end RadarChart.animIn:Play(); end function IntroMotion:ShowFrame() if not InCombatLockdown() then 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); VirtualLineRight.AnimFrame.toX = offsetX; VirtualLineRight.AnimFrame:Show(); GuideLineFrame.VirtualLineLeft.AnimFrame:Show(); After(0, function() FadeFrame(Narci_Character, 0.6, 1); end); Narci_SnowEffect(true); end self:PlayAttributeAnimation(); if MOG_MODE then FadeFrame(Narci_Attribute, 0.4, 0) else FadeFrame(Narci_Attribute, 0.4, 1, 0); end end local function ExitFunc() IS_OPENED = false; CameraUtil:SetUseMogOffset(false); EL:Hide(); MoveViewRightStop(); CameraUtil:RestoreMotionSickness(); 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 CameraUtil:SmoothShoulder(0); After(1, function() ConsoleExec( "actioncam off" ); MoveViewRightStop(); end) else --Restore the acioncam state CameraUtil:SmoothShoulder(CVarTemp.shoulderOffset); SetCVar("test_cameraDynamicPitch", CVarTemp.dynamicPitch); After(1, function() MoveViewRightStop(); end) end ConsoleExec("pitchlimit 88"); FadeFrame(Narci_Vignette, 0.5, 0); if Narci_Attribute:IsVisible() then Narci_Attribute.animOut:Play(); end UIParentFade:FadeInUIParent(); After(0.1, function() if not IntroMotion.useCameraTransition then SetCVar("cameraViewBlendStyle", 2); end local cameraSmoothStyle = GetCVar("cameraSmoothStyle"); if tonumber(cameraSmoothStyle) == 0 and ViewProfile.isEnabled then --workaround for auto-following SetView(5); else SetView(2); CameraUtil:ZoomTo(CVarTemp.zoomLevel); end SetCVar("cameraViewBlendStyle", CVarTemp.cameraViewBlendStyle); end); Narci.isActive = false; Narci.isAFK = false; DefaultTooltip:HideTooltip(); MsgAlertContainer:Hide(); UIErrorsFrame:Clear(); Narci_ModelContainer:HideAndClearModel(); Narci_ModelSettings:Hide(); Narci_XmogNameFrame:Hide(); NarciSettingsFrame:CloseUI(); MOG_MODE = false; CameraUtil:MakeInactive(); CallbackRegistry:Trigger("NarcissusCharacterUI.ShownState", false); end function Narci:EmergencyStop() print("Camera has been reset."); UIParentFade:ShowUIParent(); MoveViewRightStop(); MoveViewLeftStop(); ViewProfile:ResetView(5); ConsoleExec( "pitchlimit 88"); CVarTemp.shoulderOffset = 0; SetCVar("test_cameraOverShoulder", 0); SetCVar("cameraViewBlendStyle", 1); ConsoleExec("actioncam off"); Narci_ModelContainer:HideAndClearModel(); Narci_ModelSettings:Hide(); Narci_Character:Hide(); Narci_Attribute:Hide(); Narci_Vignette:Hide(); IS_OPENED = false; CameraUtil:SetUseMogOffset(false) EL:Hide(); CameraUtil:MakeInactive(); end ---Get Transmog Appearance--- --[[ ==sourceInfo== sourceType TRANSMOG_SOURCE_1 = "Boss Drop"; invType TRANSMOG_SOURCE_2 = "Quest"; visualID TRANSMOG_SOURCE_3 = "Vendor"; isCollected TRANSMOG_SOURCE_4 = "World Drop"; sourceID TRANSMOG_SOURCE_5 = "Achievement"; isHideVisual TRANSMOG_SOURCE_6 = "Profession"; itemID itemModID Normal 0, Heroic 1, Mythic 3, LFG 4 categoryID name quality --]] local xmogTable = { {1, INVTYPE_HEAD}, {3, INVTYPE_SHOULDER}, {15, INVTYPE_CLOAK}, {5, INVTYPE_CHEST}, {4, INVTYPE_BODY}, {19, INVTYPE_TABARD}, {9, INVTYPE_WRIST}, --Left **slotID for TABARD is 19 {10, INVTYPE_HAND}, {6, INVTYPE_WAIST}, {7, INVTYPE_LEGS}, {8, INVTYPE_FEET}, --Right {16, INVTYPE_WEAPONMAINHAND}, {17, INVTYPE_WEAPONOFFHAND}, --Weapon }; --[[ local function ShareHyperLink() --Send transmog hyperlink to chat local delay = 0; --Keep message in order print(MYMOG_GRADIENT) for i=1, #xmogTable do local index = xmogTable[i][1] if SLOT_TABLE[index] and SLOT_TABLE[index].hyperlink then After(delay, function() SendChatMessage(xmogTable[i][2]..": "..SLOT_TABLE[index].hyperlink, "GUILD") end) delay = delay + 0.1; end end end --]] local GetInventoryItemCooldown = GetInventoryItemCooldown; local function SetItemSocketingFramePosition(self) --Let ItemSocketingFrame appear on the side of the slot if ItemSocketingFrame then if self.GemSlot:IsShown() then ItemSocketingFrame:Show() else ItemSocketingFrame:Hide() return; end ItemSocketingFrame:ClearAllPoints(); if self.isRight then ItemSocketingFrame:SetPoint("TOPRIGHT", self, "TOPLEFT", 4, 0); else ItemSocketingFrame:SetPoint("TOPLEFT", self, "TOPRIGHT", -4, 0); end DefaultTooltip:HideTooltip(); end end local IsItemEnchantable = { [11] = true, [12] = true, [16] = true, [17] = true, [5] = true, [8] = true, [9] = true, [10] = true, [15] = true, }; local function DisplayRuneSlot(equipmentSlot, slotID, itemQuality, itemLink) --! RuneSlot.Background is disabled if not equipmentSlot.RuneSlot then return; elseif (itemQuality == 0) or (not itemLink) then equipmentSlot.RuneSlot:Hide(); return; end if IsItemEnchantable[slotID] then equipmentSlot.RuneSlot:Show(); else equipmentSlot.RuneSlot:Hide(); return; end local enchantID = GetItemEnchantID(itemLink); if enchantID ~= 0 then equipmentSlot.RuneSlot.RuneLetter:Show(); if EnchantInfo[enchantID] then equipmentSlot.RuneSlot.RuneLetter:SetText( GetVerticalRunicLetters( EnchantInfo[enchantID][1] ) ); equipmentSlot.RuneSlot.spellID = EnchantInfo[enchantID][3] end else equipmentSlot.RuneSlot.spellID = nil; equipmentSlot.RuneSlot.RuneLetter:Hide(); end end function Narci_RuneButton_OnEnter(self) local spellID = self.spellID; if (not spellID) then return; end DefaultTooltip:SetOwner(self, "ANCHOR_NONE"); if self:GetParent().isRight then DefaultTooltip:SetPoint("TOPRIGHT", self, "TOPLEFT", 8, 8); else DefaultTooltip:SetPoint("TOPLEFT", self, "TOPRIGHT", 0, 8); end DefaultTooltip:SetSpellByID(spellID); DefaultTooltip:Show(); DefaultTooltip:FadeIn(); end --------------------------------------------------- local function GetTraitsIcon(itemLocation) if not itemLocation then return; end local TierInfos = C_AzeriteEmpoweredItem.GetAllTierInfo(itemLocation); if not TierInfos then return; end local powerIDs, icon, _; local isRightSpec = true; local traitIcons = {}; local specIndex = GetSpecialization() or 1; local specID = GetSpecializationInfo(specIndex); local MAX_TIERS = 5; for i = 1, MAX_TIERS do if (not TierInfos[i]) or (not TierInfos[i].azeritePowerIDs) then return traitIcons; end powerIDs = TierInfos[i].azeritePowerIDs; for k, powerID in pairs(powerIDs) do if C_AzeriteEmpoweredItem.IsPowerSelected(itemLocation, powerID) then local PowerInfo = C_AzeriteEmpoweredItem.GetPowerInfo(powerID) isRightSpec = isRightSpec and C_AzeriteEmpoweredItem.IsPowerAvailableForSpec(powerID, specID); _, _, icon = GetSpellInfo(PowerInfo and PowerInfo.spellID); traitIcons[i] = icon; break; else traitIcons[i] = ""; end end end return traitIcons, isRightSpec; end local function GetRuneForgeLegoIcon(itemLocation) local componentInfo = C_LegendaryCrafting.GetRuneforgeLegendaryComponentInfo(itemLocation); if componentInfo and componentInfo.powerID then local powerInfo = C_LegendaryCrafting.GetRuneforgePowerInfo(componentInfo.powerID); return powerInfo and powerInfo.iconFileID end end local GetSlotVisualID = NarciAPI.GetSlotVisualID; local GetGemBorderTexture = NarciAPI.GetGemBorderTexture; local GetItemQualityColor = NarciAPI.GetItemQualityColor; local QueueFrame = NarciAPI.CreateProcessor(nil, 0.5); ----------------------------------------------------------------------- NarciItemButtonSharedMixin = {}; function NarciItemButtonSharedMixin:RegisterErrorEvent() self:RegisterEvent("UI_ERROR_MESSAGE"); end function NarciItemButtonSharedMixin:UnregisterErrorEvent() if self.errorFrame then self.errorFrame = nil; self:UnregisterEvent("UI_ERROR_MESSAGE"); end end function NarciItemButtonSharedMixin:OnErrorMessage(...) self:UnregisterErrorEvent(); local _, msg = ... Narci_AlertFrame_Autohide:AddMessage(msg, true); end function NarciItemButtonSharedMixin:AnchorAlertFrame() if not self.errorFrame then self.errorFrame = true; self:RegisterErrorEvent(); Narci_AlertFrame_Autohide:SetAnchor(self, -12, true); end end function NarciItemButtonSharedMixin:PlayGamePadAnimation() if self.gamepad then self.Icon.ScaleUp:Play(); self.IconMask.ScaleUp:Play(); self.Border.ScaleUp:Play(); self.Border.BorderMask.ScaleUp:Play(); end end function NarciItemButtonSharedMixin:ResetAnimation() if self.gamepad then self.Icon.ScaleUp:Stop(); self.Border.ScaleUp:Stop(); self.Border.BorderMask.ScaleUp:Stop(); self.IconMask.ScaleUp:Stop(); self.Icon:SetScale(1); self.Border:SetScale(1); self.IconMask:SetScale(1); self.Border.BorderMask:SetScale(1); if self.gamepadOverlay then self.gamepadOverlay:Hide(); self.gamepadOverlay = nil; end end end function NarciItemButtonSharedMixin:SetBorderTexture(border, texKey) SetBorderTexture(border, texKey, 2); end function NarciItemButtonSharedMixin:ShowAlphaChannel() self.Icon:SetColorTexture(1, 1, 1); self.Border:SetColorTexture(1, 1, 1); self.Border.textureKey = -1; end ----------------------------------------------------------------------- local ValidForTempEnchant = { [16] = true, [17] = true, }; local function GetFormattedSourceText(sourceInfo) local sourceType = sourceInfo.sourceType; local itemQuality = sourceInfo.quality or 1; local hex = NarciAPI.GetItemQualityHexColor(itemQuality); local difficulty; local bonusID; local colorizedText, plainText, hyperlink; --/dump Enum.TransmogSource if sourceType == 1 then --TRANSMOG_SOURCE_BOSS_DROP = 1 local drops = C_TransmogCollection.GetAppearanceSourceDrops(sourceInfo.sourceID); if drops and drops[1] then colorizedText = drops[1].encounter.." ".."|cFFFFD100"..drops[1].instance.."|r"; plainText = drops[1].encounter.." "..drops[1].instance; if sourceInfo.itemModID == 0 then difficulty = PLAYER_DIFFICULTY1; bonusID = 3561; hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."1"..":1476:|h|r"; elseif sourceInfo.itemModID == 1 then difficulty = PLAYER_DIFFICULTY2; bonusID = 3562; hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."2"..":1476:|h|r"; elseif sourceInfo.itemModID == 3 then difficulty = PLAYER_DIFFICULTY6; bonusID = 3563; hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."3"..":1476:|h|r"; elseif sourceInfo.itemModID == 4 then difficulty = PLAYER_DIFFICULTY3; bonusID = 3564; hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:356".."4"..":1476:|h|r"; end if difficulty then colorizedText = colorizedText.." |CFFf8e694"..difficulty.."|r"; plainText = plainText.." "..difficulty; end else local sourceText = _G["TRANSMOG_SOURCE_1"]; --Boss Drop colorizedText = sourceText; plainText = sourceText; end else if sourceType == 2 then --quest colorizedText = TRANSMOG_SOURCE_2; if sourceInfo.itemModID == 3 then hyperlink= "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:512".."6"..":1562:|h|r"; bonusID = 5126; elseif sourceInfo.itemModID == 2 then hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:512".."5"..":1562:|h|r"; bonusID = 5125; elseif sourceInfo.itemModID == 1 then hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID.."::::::::120::::2:512".."4"..":1562:|h|r"; bonusID = 5124; end elseif sourceType then colorizedText = TransitionAPI.GetTransmogSourceName(sourceType); end plainText = colorizedText; end if not hyperlink then hyperlink = "|c"..hex.."|Hitem:"..sourceInfo.itemID..":|h|r"; end return colorizedText, plainText, hyperlink; end NarciEquipmentSlotMixin = CreateFromMixins{NarciItemButtonSharedMixin}; function NarciEquipmentSlotMixin:SetTransmogSourceID(appliedSourceID, secondarySourceID) self.sourceID = appliedSourceID; if appliedSourceID and appliedSourceID > 0 then self.Icon:SetDesaturated(false); self.Name:Show(); self.ItemLevel:Show(); self.GradientBackground:Show(); else self.Icon:SetDesaturated(true); self.Icon:SetTexture(self.emptyTexture); self.Name:SetText(nil); self.ItemLevel:SetText(nil); self.GradientBackground:Hide(); self:SetBorderTexture(self.Border, 0); if self.slotID == 2 then self:DisplayDirectionMark(false); end return end local itemName, itemIcon, itemQuality, subText; local sourceInfo = C_TransmogCollection.GetSourceInfo(appliedSourceID); itemName = sourceInfo and sourceInfo.name; if not itemName or itemName == "" then QueueFrame:Add(self, self.Refresh); return end self.itemID = sourceInfo.itemID; self.itemModID = sourceInfo.itemModID; itemQuality = sourceInfo.quality or 1; itemIcon = C_TransmogCollection.GetSourceIcon(appliedSourceID); subText = TransmogDataProvider:GetSpecialItemSourceText(appliedSourceID, self.itemID, self.itemModID); if subText then self.sourcePlainText = NarciAPI.RemoveColorString(subText); _, _, self.hyperlink = GetFormattedSourceText(sourceInfo); else subText, self.sourcePlainText, self.hyperlink = GetFormattedSourceText(sourceInfo); end if not subText then subText = " "; end if self.hyperlink then _, self.hyperlink = GetItemInfo(self.hyperlink); --original hyperlink cannot be printed (workaround) end local bonusID; if itemQuality == 6 then if self.slotID == 16 then bonusID = (sourceInfo.itemModID or 0); --Artifact use itemModID "7V0" + modID - 1 else bonusID = 0; end end self.bonusID = bonusID; local bR, bG, bB = GetItemQualityColor(itemQuality); local borderTexKey = itemQuality; self:SetBorderTexture(self.Border, borderTexKey); if self:IsVisible() then if itemIcon then self.IconOverlay:SetTexture(itemIcon); self.Icon.anim:Play(); end self.ItemLevel.anim1:SetScript("OnFinished", function(f) self.ItemLevel:SetText(subText); self.ItemLevel.anim2:Play(); f:SetScript("OnFinished", nil); end) self.Name.anim1:SetScript("OnFinished", function(f) self.Name:SetText(itemName); self.Name:SetTextColor(bR, bG, bB); self.Name.anim2:Play(); f:SetScript("OnFinished", nil); After(0, function() self:UpdateGradientSize(); end) end) self.ItemLevel.anim1:Play(); self.Name.anim1:Play(); else self.ItemLevel:SetText(subText); self.Name:SetText(itemName); self.Name:SetTextColor(bR, bG, bB); if itemIcon then self.Icon:SetTexture(itemIcon); end self:UpdateGradientSize(); end if self.slotID == 3 then --shoulder if secondarySourceID and secondarySourceID > 0 and secondarySourceID ~= appliedSourceID then self:DisplayDirectionMark(true, itemQuality); SLOT_TABLE[2]:SetTransmogSourceID(secondarySourceID, secondarySourceID); else self:DisplayDirectionMark(false); end elseif self.slotID == 2 then self:DisplayDirectionMark(appliedSourceID, itemQuality); end end function NarciEquipmentSlotMixin:Refresh(forceRefresh) local _; local slotID = self.slotID; local itemLocation = ItemLocation:CreateFromEquipmentSlot(slotID); --print(slotName..slotID) --local texture = CharacterHeadSlot.popoutButton.icon:GetTexture() local itemLink; local itemIcon, itemName, itemQuality, effectiveLvl, gemName, gemLink, gemID; local borderTexKey; local isAzeriteEmpoweredItem = false; --3 Pieces **likely to be changed in patch 8.2 local isAzeriteItem = false; --Heart of Azeroth --local isCorruptedItem = false; local bR, bG, bB; --Item Name Color if C_Item.DoesItemExist(itemLocation) then if MOG_MODE then self:UntrackCooldown(); self:UntrackTempEnchant(); self:ClearOverlay(); self:HideVFX(); self.GemSlot:HideSlot(); self.itemLink = nil; self.isSlotHidden = false; --Undress an item from player model self.RuneSlot:Hide(); if TransmogDataProvider.RequestUpdateCharacterUI() then return true end self.GradientBackground:Show(); local appliedSourceID, appliedVisualID, hasSecondaryAppearance = GetSlotVisualID(slotID); self.sourceID = appliedSourceID; if appliedVisualID > 0 then local sourceInfo = C_TransmogCollection.GetSourceInfo(appliedSourceID); itemName = sourceInfo and sourceInfo.name; if not itemName or itemName == "" then QueueFrame:Add(self, self.Refresh); return end self.itemID = sourceInfo.itemID; itemQuality = sourceInfo.quality; self.itemModID = sourceInfo.itemModID; itemIcon = C_TransmogCollection.GetSourceIcon(appliedSourceID); effectiveLvl = TransmogDataProvider:GetSpecialItemSourceText(appliedSourceID, self.itemID, self.itemModID); if effectiveLvl then self.sourcePlainText = NarciAPI.RemoveColorString(effectiveLvl); _, _, self.hyperlink = GetFormattedSourceText(sourceInfo); else effectiveLvl, self.sourcePlainText, self.hyperlink = GetFormattedSourceText(sourceInfo); end if self.hyperlink then _, self.hyperlink = GetItemInfo(self.hyperlink); --original hyperlink cannot be printed (workaround) end local bonusID; if itemQuality == 6 then if slotID == 16 then bonusID = (sourceInfo.itemModID or 0); --Artifact use itemModID "7V0" + modID - 1 else bonusID = 0; end end self.bonusID = bonusID; if effectiveLvl == nil then effectiveLvl = TransmogDataProvider:GetSpecialItemSourceText(appliedSourceID, self.itemID, self.itemModID) or " "; end else --irrelevant slot itemName = " "; itemQuality = 0; itemIcon = GetInventoryItemTexture("player", slotID); self.Icon:SetDesaturated(true); self.Name:Hide(); self.ItemLevel:Hide(); self.GradientBackground:Hide(); self.bonusID = nil; end self:DisplayDirectionMark(hasSecondaryAppearance, itemQuality); else self:TrackCooldown(); self:DisplayDirectionMark(false); self.Icon:SetDesaturated(false) self.Name:Show(); self.ItemLevel:Show(); self.GradientBackground:Show(); self.sourceID = nil; self.hyperlink = nil; self.sourcePlainText = nil; --[[ local current, maximum = GetInventoryItemDurability(slotID); if current and maximum then self.durability = (current / maximum); end --]] itemLink = C_Item.GetItemLink(itemLocation); if ValidForTempEnchant[slotID] then local hasTempEnchant = NarciTempEnchantIndicatorController:InitFromSlotButton(self); if hasTempEnchant ~= self.hasTempEnchant then self.hasTempEnchant = hasTempEnchant; else if itemLink == self.itemLink then return end end else if itemLink == self.itemLink then return end end self.itemLink = itemLink; local itemVFX, hideItemIcon; local itemID = GetItemInfoInstant(itemLink); borderTexKey, itemVFX, bR, bG, bB, hideItemIcon = GetBorderArtByItemID(itemID); itemIcon = itemID and GetOverrideItemIcon(itemID); if not itemIcon then itemIcon = ((not hideItemIcon) and GetInventoryItemTexture("player", slotID)) or nil; end itemName = C_Item.GetItemName(itemLocation); itemQuality = C_Item.GetItemQuality(itemLocation); effectiveLvl = C_Item.GetCurrentItemLevel(itemLocation); self.ItemLevelCenter.ItemLevel:SetText(effectiveLvl); --Debug --if effectiveLvl and effectiveLvl > 1 then -- NarciDebug:CalculateAverage(effectiveLvl); --end if not hideItemIcon then if slotID == 13 or slotID == 14 then if itemID == 167555 then --Pocket-Sized Computation Device gemName, gemLink = IsItemSocketable(itemLink, 2); else gemName, gemLink = IsItemSocketable(itemLink); end else gemName, gemLink = IsItemSocketable(itemLink); end end self.GemSlot.ItemLevel = effectiveLvl; self.gemLink = gemLink; --Later used in OnEnter func in NarciSocketing.lua if slotID == 2 then isAzeriteItem = C_AzeriteItem.IsAzeriteItem(itemLocation); self.isAzeriteItem = isAzeriteItem; if isAzeriteItem then itemVFX = "Heart"; end elseif slotID == 1 or slotID == 3 or slotID == 5 then isAzeriteEmpoweredItem = C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItem(itemLocation); else --isCorruptedItem = IsCorruptedItem(itemLink); end if slotID == 15 then --Backslot if itemID == 169223 then --Ashjra'kamas, Shroud of Resolve Legendary Cloak local rank, corruptionResistance = NarciAPI.GetItemRankText(itemLink, "ITEM_MOD_CORRUPTION_RESISTANCE"); effectiveLvl = effectiveLvl.." "..rank.." |cFFFFD100"..corruptionResistance.."|r"; borderTexKey = "BlackDragon"; itemVFX = "DragonFire"; elseif itemID == 210333 then --Timerunning Thread local rank = TimerunningUtil.GetThreadRank(); if rank > 0 then rank = "|cff00ccff"..rank.."|r"; effectiveLvl = effectiveLvl.." "..rank; end end end if slotID ~= 13 and slotID ~= 14 then local isRuneforgeLegendary = C_LegendaryCrafting.IsRuneforgeLegendary(itemLocation); if isRuneforgeLegendary then itemVFX = "Runeforge"; borderTexKey = "Runeforge"; itemIcon = GetRuneForgeLegoIcon(itemLocation) or itemIcon; end end if IS_LEGION_REMIX and slotID == 16 then local configID = C_Traits.GetConfigIDByTreeID(1161); if configID then local nodeInfo = C_Traits.GetNodeInfo(configID, 108700); --Limits Unbound local rank = nodeInfo and nodeInfo.currentRank or 0; if rank > 0 then rank = "|cff00ccff"..rank.."|r"; effectiveLvl = effectiveLvl.." "..rank; end end end local enchantText, isEnchanted = GetItemEnchantText(itemLink, true, self.isRight); --enchantText (effect texts) may not be available yet if enchantText then if self.isRight then effectiveLvl = enchantText.." "..effectiveLvl; else effectiveLvl = effectiveLvl.." "..enchantText; end self:ClearOverlay(); elseif not isEnchanted then if SHOW_MISSING_ENCHANT_ALERT and SlotButtonOverlayUtil:IsSlotValidForEnchant(slotID, itemID) then SlotButtonOverlayUtil:ShowEnchantAlert(self, slotID, itemID); if self.isRight then effectiveLvl = effectiveLvl .. " ".. L["Missing Enchant"]; else effectiveLvl = L["Missing Enchant"].." "..effectiveLvl; end end end --Enchant Frame-- if itemQuality then --and not isRuneforgeLegendary DisplayRuneSlot(self, slotID, itemQuality, itemLink); end --Item Visual Effects if itemVFX then self:ShowVFX(itemVFX); else self:HideVFX(); end end if not itemName or itemName == "" then QueueFrame:Add(self, self.Refresh); return end else self:UntrackCooldown(); self:UntrackTempEnchant(); self:ClearOverlay(); self:HideVFX(); self:DisplayDirectionMark(false); self.GradientBackground:Hide(); self.Icon:SetDesaturated(false); self.ItemLevelCenter.ItemLevel:SetText(""); self.itemID = nil; self.bonusID = nil; self.itemLink = nil; self.gemLink = nil; itemQuality = 0; itemIcon = self.emptyTexture; itemName = " " ; effectiveLvl = ""; DisplayRuneSlot(self, slotID, 0); end self.itemQuality = itemQuality; if itemQuality and not bR then --itemQuality sometimes return nil. This is a temporary solution bR, bG, bB = GetItemQualityColor(itemQuality); if not borderTexKey then borderTexKey = itemQuality; end end bR = bR or 1; bG = bG or 1; bB = bB or 1; if isAzeriteEmpoweredItem then borderTexKey = "Azerite"; if not MOG_MODE then local icons, isRightSpec = GetTraitsIcon(itemLocation); for i = 1, #icons do effectiveLvl = effectiveLvl.." |T"..icons[i]..":12:12:0:0:64:64:4:60:4:60|t"; end end end if isAzeriteItem then local heartLevel = C_AzeriteItem.GetPowerLevel(itemLocation); local xp_Current, xp_Needed = C_AzeriteItem.GetAzeriteItemXPInfo(itemLocation); local GetEssenceInfo = C_AzeriteEssence.GetEssenceInfo; local GetMilestoneEssence = C_AzeriteEssence.GetMilestoneEssence; if not C_AzeriteItem.IsAzeriteItemAtMaxLevel() then heartLevel = heartLevel .. " |CFFf8e694" .. floor((xp_Current/xp_Needed)*100 + 0.5) .. "%"; end effectiveLvl = effectiveLvl.." |cFFFFD100"..heartLevel; local EssenceID = GetMilestoneEssence(115); if EssenceID then borderTexKey = "Heart"; local EssenceInfo = GetEssenceInfo(EssenceID); bR, bG, bB = GetItemQualityColor(EssenceInfo.rank + 1); itemName = EssenceInfo.name; itemIcon = EssenceInfo.icon; end for i = 116, 119 do --116, 117, 119 3 minor slots if i ~= 118 then EssenceID = GetMilestoneEssence(i); if EssenceID then local icon = GetEssenceInfo(EssenceID).icon; effectiveLvl = effectiveLvl.." |T"..icon..":12:12:0:0:64:64:4:60:4:60|t"; end end end end --[[ if isCorruptedItem then borderTexKey = "NZoth"; if not MOG_MODE then local corruption = GetItemStats(itemLink)["ITEM_MOD_CORRUPTION"]; if corruption then local Affix = GetCorruptedItemAffix(itemLink); if Affix then if self.isRight then effectiveLvl = Affix.." |cff946dd1"..corruption.."|r "..effectiveLvl; else effectiveLvl = effectiveLvl.." "..Affix.." |cff946dd1"..corruption.."|r"; end else if self.isRight then effectiveLvl = "|cff946dd1"..corruption.."|r "..effectiveLvl; else effectiveLvl = effectiveLvl.." |cff946dd1"..corruption.."|r"; end end end itemQuality = "NZoth"; end end --]] --Gem Slot-- if gemName ~= nil then local gemBorder, gemIcon, itemSubClassID; --regular gems if gemLink then gemID, _, _, _, gemIcon, _, itemSubClassID = GetItemInfoInstant(gemLink); gemBorder = GetGemBorderTexture(itemSubClassID, gemID); else gemBorder = GetGemBorderTexture(nil); end self.GemSlot.GemBorder:SetTexture(gemBorder); self.GemSlot.GemIcon:SetTexture(gemIcon); self.GemSlot.GemIcon:Show(); self.GemSlot.sockedGemItemID = gemID; if self:IsVisible() then self.GemSlot:FadeIn(); else self.GemSlot:ShowSlot(); end else if self:IsVisible() then self.GemSlot:FadeOut(); else self.GemSlot:HideSlot(); end self.GemSlot.sockedGemItemID = nil; end -------------------------------------------------- if self:IsVisible() then self:SetBorderTexture(self.Border, borderTexKey); if itemIcon then self.IconOverlay:SetTexture(itemIcon); self.Icon.anim:Play(); end self.ItemLevel.anim1:SetScript("OnFinished", function(f) self.ItemLevel:SetText(effectiveLvl); self.ItemLevel.anim2:Play(); f:SetScript("OnFinished", nil); end) self.Name.anim1:SetScript("OnFinished", function(f) self.Name:SetText(itemName); self.Name:SetTextColor(bR, bG, bB); self.Name.anim2:Play(); f:SetScript("OnFinished", nil); After(0, function() self:UpdateGradientSize(); end) end) self.ItemLevel.anim1:Play(); self.Name.anim1:Play(); else self.ItemLevel:SetText(effectiveLvl); self.Name:SetText(itemName); self.Name:SetTextColor(bR, bG, bB); self:SetBorderTexture(self.Border, borderTexKey); if itemIcon then self.Icon:SetTexture(itemIcon); end self:UpdateGradientSize(); end --self.GradientBackground:SetHeight(self.Name:GetHeight() + self.ItemLevel:GetHeight() + 18); self.itemNameColor = {bR, bG, bB}; return true end function NarciEquipmentSlotMixin:UpdateGradientSize() local text2Width = self.ItemLevel:GetWrappedWidth(); local extraWidth; if self.TempEnchantIndicator then extraWidth = 48; self.TempEnchantIndicator:ClearAllPoints(); if self.isRight then self.TempEnchantIndicator:SetPoint("TOPRIGHT", self.ItemLevel, "TOPRIGHT", -text2Width - 6, 0); else if self.ItemLevel:IsTruncated() then text2Width = self.ItemLevel:GetWidth(); end self.TempEnchantIndicator:SetPoint("TOPLEFT", self.ItemLevel, "TOPLEFT", text2Width + 6, 0); end else extraWidth = 0; end self.GradientBackground:SetHeight(self.Name:GetHeight() + self.ItemLevel:GetHeight() + 18); self.GradientBackground:SetWidth(max(self.Name:GetWrappedWidth(), text2Width + extraWidth, 48) + 48); end function NarciEquipmentSlotMixin:OnLoad() self:SetScript("OnLoad", nil); self.OnLoad = nil; local slotName = self.slotName; local slotID, textureName = GetInventorySlotInfo(slotName); self.emptyTexture = textureName; self:SetID(slotID); self.slotID = slotID; self:SetAttribute("type2", "item"); self:SetAttribute("item", slotID); self:RegisterForDrag("LeftButton"); self:RegisterForClicks("LeftButtonUp", "RightButtonDown", "RightButtonUp"); if self:GetParent() then if not self:GetParent().slotTable then self:GetParent().slotTable = {} end table.insert(self:GetParent().slotTable, self); end SLOT_TABLE[slotID] = self; local level = SharedBlackScreen:GetBaseFrameLevel() - 1; self:SetFrameLevel(level); end function NarciEquipmentSlotMixin:OnEvent(event, ...) if event == "MODIFIER_STATE_CHANGED" then local key, state = ...; if ( key == "LALT" and self:IsMouseOver() ) then local flyout = EquipmentFlyoutFrame; if state == 1 then if flyout:IsShown() and flyout.slotID == self:GetID() then flyout:Hide(); else flyout:SetItemSlot(self, true); end else if not MOG_MODE then ItemTooltip:SetFromSlotButton(self, -2, 6); end end end elseif event == "UI_ERROR_MESSAGE" then self:OnErrorMessage(...); end end function NarciEquipmentSlotMixin:UntrackCooldown() if self.CooldownFrame then self.CooldownFrame:Clear(); self.CooldownFrame = nil; end end function NarciEquipmentSlotMixin:ClearOverlay() if SHOW_MISSING_ENCHANT_ALERT and self.slotOverlay then SlotButtonOverlayUtil:ClearOverlay(self); self.slotOverlay = nil; end end function NarciEquipmentSlotMixin:TrackCooldown() local start, duration, enable = GetInventoryItemCooldown("player", self:GetID()); if enable and enable ~= 0 and start > 0 and duration > 0 then if not self.CooldownFrame then self.CooldownFrame = NarciItemCooldownUtil.AccquireFrame(self); end self.CooldownFrame:SetCooldown(start, duration); return true else self:UntrackCooldown(); end return false end function NarciEquipmentSlotMixin:UntrackTempEnchant() if self.TempEnchantIndicator then self.TempEnchantIndicator:Hide(); self.TempEnchantIndicator = nil; end end function NarciEquipmentSlotMixin:OnEnter(motion, isGamepad) self:RegisterEvent("MODIFIER_STATE_CHANGED"); if isGamepad then self:PlayGamePadAnimation(); else FadeFrame(self.Highlight, 0.15, 1); end if IsAltKeyDown() and not MOG_MODE then EquipmentFlyoutFrame:SetItemSlot(self, true); return end if EquipmentFlyoutFrame:IsShown() then Narci_Comparison_SetComparison(EquipmentFlyoutFrame.BaseItem, self); return; end if MOG_MODE then ItemTooltip:SetTransmogFromSlotButton(self, -2, 6); else ItemTooltip:SetFromSlotButton(self, -2, 6, isGamepad and 0.4); --delay 0.4s end end function NarciEquipmentSlotMixin:OnLeave() self:UnregisterEvent("MODIFIER_STATE_CHANGED"); self:UnregisterErrorEvent(); FadeFrame(self.Highlight, 0.25, 0); Narci:HideButtonTooltip(); self:ResetAnimation(); end function NarciEquipmentSlotMixin:OnHide() self.Highlight:Hide(); self.Highlight:SetAlpha(0); self:ResetAnimation(); end function NarciEquipmentSlotMixin:PreClick(button) end function NarciEquipmentSlotMixin:PostClick(button, down) if CursorHasItem() and button == "LeftButton" then EquipCursorItem(self:GetID()); return end ClearCursor(); if ( IsModifiedClick() ) then if IsAltKeyDown() and button == "LeftButton" then local action = EquipmentManager_UnequipItemInSlot(self:GetID()) if action then EquipmentManager_RunAction(action) end return; elseif IsShiftKeyDown() and button == "LeftButton" then if self.hyperlink then if ChatEdit_InsertLink(self.hyperlink) then return elseif SocialPostFrame and Social_IsShown() then Social_InsertLink(self.hyperlink); return end end else PaperDollItemSlotButton_OnModifiedClick(self, button); TakeOutFrames(true); SetItemSocketingFramePosition(self); end else if button == "LeftButton" then if not MOG_MODE then --Undress an item from player model while in Xmog Mode --EquipmentFlyoutFrame:SetItemSlot(self); Narci_EquipmentOption:SetFromSlotButton(self, true); end elseif button == "RightButton" then local useKeyDown = C_CVar.GetCVarBool("ActionButtonUseKeyDown"); if (useKeyDown and down) or (not useKeyDown and not down) then self:AnchorAlertFrame(); end 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 TransitionAPI.Secret_DoesStringExist(self.tooltip) then return end SetStatTooltipText(self) if (not direction) then DefaultTooltip:SetPoint("TOPRIGHT",self,"TOPLEFT", -4, 0) elseif direction=="RIGHT" then DefaultTooltip:SetPoint("LEFT",self,"RIGHT", 0, 0) elseif direction=="TOP" then DefaultTooltip:SetPoint("BOTTOM",self,"TOP", 0, -4) elseif direction=="CURSOR" then DefaultTooltip:SetOwner(self, "ANCHOR_CURSOR"); end DefaultTooltip:Show(); end function Narci_ShowStatTooltipDelayed(self) if ( not self.tooltip ) then return; end SetStatTooltipText(self); DefaultTooltip:SetAlpha(0); ShowDelayedTooltip("BOTTOM", self, "TOP", 0, -4); end function NarciItemLevelFrameMixin:OnLoad() --Declared in Modules\CharacterFrame\ItemLevelFrame.lua ItemLevelFrame = self; SharedBlackScreen:SetParent(Narci_Character); self:Init(); end local function UpdateCharacterInfoFrame(newLevel) local level = newLevel or UnitLevel("player"); local specClassName = TalentTreeDataProvider:GetPlayerSpecClassName(true); --colorized if specClassName then local frame = Narci_PlayerInfoFrame; local levelNumber = "|cFFFFD100"..level.."|r"; local titleID = GetCurrentTitle(); local titleName = GetTitleName(titleID); if titleName and titleName ~= "" then titleName = strtrim(titleName); --delete the space in Title frame.Miscellaneous:SetText(titleName.." | "..levelNumber.." "..specClassName); else frame.Miscellaneous:SetText("|cFFFFD100Level|r "..levelNumber.." "..specClassName); end end ItemLevelFrame:UpdateItemLevel(); end local function DisplayItemTransmogInfoList(itemTransmogInfoList) if MOG_MODE and Narci_Character:IsVisible() then for slotID, info in ipairs(itemTransmogInfoList) do --print(slotID, info.appearanceID); --appearanceID, secondaryAppearanceID, illusionID if SLOT_TABLE[slotID] then SLOT_TABLE[slotID]:SetTransmogSourceID(info.appearanceID, info.secondaryAppearanceID); --SetAppearance end end end end addon.DisplayItemTransmogInfoList = DisplayItemTransmogInfoList; local SlotController = {}; SlotController.updateFrame = CreateFrame("Frame"); SlotController.updateFrame:Hide(); SlotController.updateFrame:SetScript("OnUpdate", function(f, elapsed) f.t = f.t + elapsed; if f.t >= 0.05 then f.t = 0; if SlotController:Refresh(f.sequence[f.i], f.forceRefresh) then f.i = f.i + 1; else f:Hide(); if MOG_MODE and Toolbar.TransmogListFrame:IsShown() then After(0.5, function() Toolbar.TransmogListFrame:UpdateTransmogList(); end); end end end end); SlotController.refreshSequence = { 1, 2, 3, 15, 5, 9, 16, 17, 4, 10, 6, 7, 8, 11, 12, 13, 14, 19, }; SlotController.tempEnchantSequence = {}; for slotID in pairs(ValidForTempEnchant) do table.insert(SlotController.tempEnchantSequence, slotID); end function SlotController:Refresh(slotID, forceRefresh) if SLOT_TABLE[slotID] then SLOT_TABLE[slotID]:Refresh(forceRefresh); return true; end end function SlotController:RefreshAll(forceRefresh) for slotID, slotButton in pairs(SLOT_TABLE) do slotButton:Refresh(forceRefresh); end end function SlotController:StopRefresh() if self.updateFrame then self.updateFrame:Hide(); end end function SlotController:LazyRefresh(sequenceName) local f = self.updateFrame; f:Hide(); f.t = 0; f.i = 1; if sequenceName == "temp" then f.sequence = self.tempEnchantSequence; f.forceRefresh = true; else f.sequence = self.refreshSequence; f.forceRefresh = false; end f:Show(); end function SlotController:ClearCache() for slotID, slotButton in pairs(SLOT_TABLE) do slotButton.itemLink = nil; end end function SlotController:PlayAnimOut() if not InCombatLockdown() and Narci_Character:IsShown() then for slotID, slotButton in pairs(SLOT_TABLE) do slotButton.animOut:Play(); end Narci_Character.animOut:Play(); end end function SlotController:IsMouseOver() for slotID, slotButton in pairs(SLOT_TABLE) do if slotButton:IsMouseOver() then return true end end return false end ------------------------------------------------------------------ -----Some of the codes are derivated from EquipmentFlyout.lua----- ------------------------------------------------------------------ NarciEquipmentFlyoutButtonMixin = CreateFromMixins{NarciItemButtonSharedMixin}; function NarciEquipmentFlyoutButtonMixin:OnClick(button, down, isGamepad) if button == "LeftButton" then local action = EquipmentManager_EquipItemByLocation(self.location, self.slotID) if action then self:AnchorAlertFrame(); ConfirmBinding(); EquipmentManager_RunAction(action); end self:Disable(); if isGamepad then EquipmentFlyoutFrame.gamepadButton = self; end end end function NarciEquipmentFlyoutButtonMixin:OnLeave() FadeFrame(self.Highlight, 0.25, 0); Narci:HideButtonTooltip(); self:ResetAnimation(); end function NarciEquipmentFlyoutButtonMixin:OnEnter(motion, isGamepad) Narci_Comparison_SetComparison(self.itemLocation, self); if isGamepad then self:PlayGamePadAnimation(); else FadeFrame(self.Highlight, 0.15, 1); end end function NarciEquipmentFlyoutButtonMixin:OnEvent(event, ...) if event == "UI_ERROR_MESSAGE" then self:OnErrorMessage(...); end end function NarciEquipmentFlyoutButtonMixin:SetUp(maxItemLevel) self.FlyUp:Stop(); local itemLocation = self.itemLocation; self.hyperlink = C_Item.GetItemLink(itemLocation) if ( not itemLocation ) then return; end local itemID = C_Item.GetItemID(itemLocation); local itemQuality = C_Item.GetItemQuality(itemLocation); local itemLevel = C_Item.GetCurrentItemLevel(itemLocation); local itemIcon = GetOverrideItemIcon(itemID); if not itemIcon then itemIcon = C_Item.GetItemIcon(itemLocation); end local itemLink = C_Item.GetItemLink(itemLocation) if C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItem(itemLocation) then itemQuality = "Azerite"; --AzeriteEmpoweredItem elseif C_AzeriteItem.IsAzeriteItem(itemLocation) then itemQuality = "Heart"; elseif C_Item.IsCorruptedItem(itemLink) then itemQuality = "NZoth"; elseif C_LegendaryCrafting.IsRuneforgeLegendary(itemLocation) then itemQuality = "Runeforge"; itemIcon = GetRuneForgeLegoIcon(itemLocation) or itemIcon; end itemQuality = GetBorderArtByItemID(itemID) or itemQuality; if maxItemLevel and itemLevel < maxItemLevel and itemQuality ~= "Runeforge" then itemQuality = 0; self.Icon:SetDesaturated(true); else self.Icon:SetDesaturated(false); end self.Icon:SetTexture(itemIcon) --self.Border:SetTexture(BorderTexture[itemQuality]) self:SetBorderTexture(self.Border, itemQuality); self.ItemLevelCenter.ItemLevel:SetText(itemLevel); self.ItemLevelCenter:Show(); if itemLink then DisplayRuneSlot(self, self.slotID, itemQuality, itemLink); end end function NarciEquipmentFlyoutButtonMixin:HideButton() self:Hide(); self.location = nil; self.hyperlink = nil; end local function ShowLessItemInfo(self, bool) if bool then self.Name:Hide(); self.ItemLevel:Hide(); self.ItemLevelCenter:Show(); else self.Name:Show(); self.ItemLevel:Show(); self.ItemLevelCenter:Hide(); end end local function ShowAllItemInfo() if MOG_MODE then return end local level = SharedBlackScreen:GetBaseFrameLevel() - 1; for slotID, slotButton in pairs(SLOT_TABLE) do ShowLessItemInfo(slotButton, false); slotButton:SetFrameLevel(level -1); slotButton.RuneSlot:SetFrameLevel(level); end end NarciEquipmentFlyoutFrameMixin = {}; function NarciEquipmentFlyoutFrameMixin:OnLoad() EquipmentFlyoutFrame = self; self.buttons = {}; self.slotID = -1; self.itemSortFunc = function(a,b) return tonumber(a.level)> tonumber(b.level) end self:SetScript("OnLoad", nil); self.OnLoad = nil; self:SetFixedFrameStrata(true); self:SetFrameStrata("HIGH"); end function NarciEquipmentFlyoutFrameMixin:OnHide() ShowAllItemInfo(); self.slotID = -1; self:UnregisterEvent("MODIFIER_STATE_CHANGED"); self:UnregisterEvent("GLOBAL_MOUSE_DOWN"); self.Arrow:Hide(); self:StopAnimating(); if Narci_Character.animOut:IsPlaying() then return; end SharedBlackScreen:TryHide(); 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 = SharedBlackScreen:GetBaseFrameLevel() -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 SharedBlackScreen:TryShow(); SharedBlackScreen:RaiseFrameLevel(slotButton); self:SetFrameLevel(50); NarciEquipmentTooltip:HideTooltip(); ShowLessItemInfo(slotButton, true) --Reposition Comparison Tooltip if it reaches the top of the screen-- local Tooltip = Narci_Comparison; Tooltip:ClearAllPoints(); Tooltip:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 8, 12); if slotButton:GetTop() > Tooltip:GetBottom() then Tooltip:ClearAllPoints(); Tooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT", 8, -12); end Narci_Comparison_SetComparison(self.BaseItem, slotButton); Narci_ShowComparisonTooltip(Tooltip); end function NarciEquipmentFlyoutFrameMixin:CreateItemButton() local perRow = 5; --EQUIPMENTFLYOUT_ITEMS_PER_ROW local numButtons = #self.buttons; local button = CreateFrame("Button", nil, self.ButtonFrame, "NarciEquipmentFlyoutButtonTemplate"); button:SetFrameStrata("DIALOG"); local row = floor(numButtons/perRow); local col = numButtons - row * perRow; button:SetPoint("TOPLEFT", self, "TOPLEFT", 70*col, -74*row); self.buttons[numButtons + 1] = button; button.FlyUp.Move:SetStartDelay(numButtons/25); button.FlyUp.Fade:SetStartDelay(numButtons/25); button.isFlyout = true; return button end function NarciEquipmentFlyoutFrameMixin:DisplayItemsBySlotID(slotID, playFlyUpAnimation) local LoadItemData = C_Item.RequestLoadItemData; --Cache Item Info local id = slotID or self.slotID; if not id or id <= 0 then return end self:Show(); local baseItemLevel; local bastItemLocation = ItemLocation:CreateFromEquipmentSlot(id); if C_Item.DoesItemExist(bastItemLocation) then baseItemLevel = C_Item.GetCurrentItemLevel(bastItemLocation); else baseItemLevel = 0; end self.BaseItem = bastItemLocation; local buttons = self.buttons; --Get the items from bags; local itemTable = {}; local sortedItems = {}; local numItems = 0; GetInventoryItemsForSlot(id, itemTable); local itemLocation, itemLevel, itemInfo; local invLocationPlayer = ITEM_INVENTORY_LOCATION_PLAYER; for location, hyperlink in pairs(itemTable) do if ( location - id == invLocationPlayer ) then -- Remove the currently equipped item from the list itemTable[location] = nil; else local _, _, bags, _, slot, bag = TransitionAPI.EquipmentManager_UnpackLocation(location); if bags then itemLocation = ItemLocation:CreateFromBagAndSlot(bag, slot); itemLevel = C_Item.GetCurrentItemLevel(itemLocation); LoadItemData(itemLocation); itemInfo = {level = itemLevel, itemLocation = itemLocation, location = location}; numItems = numItems + 1; sortedItems[numItems] = itemInfo; end end end table.sort(sortedItems, self.itemSortFunc); --Sorted by item level local numTotalItems = #sortedItems; local buttonWidth, buttonHeight = self.parentButton:GetWidth(), self.parentButton:GetHeight(); buttonWidth, buttonHeight = floor(buttonWidth + 0.5), floor(buttonHeight + 0.5); local borderSize = self.parentButton.Border:GetSize(); borderSize = floor(borderSize + 0.5); self:SetWidth(max(buttonWidth, math.min(numTotalItems, 5)*buttonWidth)); local numDisplayedItems = math.min(numTotalItems, 20); --EQUIPMENTFLYOUT_ITEMS_PER_PAGE self:SetHeight(max(floor((numDisplayedItems-1)/5 + 1)*buttonHeight, buttonHeight)); local gamepadButton = self.gamepadButton; self.gamepadButton = nil; baseItemLevel = baseItemLevel - 14; --darken button if the item level is lower than the base local button; for i = 1, numDisplayedItems do button = buttons[i]; if not button then button = self:CreateItemButton(); end button.itemLocation = sortedItems[i].itemLocation; button.location = sortedItems[i].location; button.slotID = id; button:SetUp(baseItemLevel); button:Show(); button:SetSize(buttonWidth, buttonHeight); button.Border:SetSize(borderSize, borderSize); button:Enable(); if button == gamepadButton then Narci_Comparison_SetComparison(gamepadButton.itemLocation, gamepadButton); Narci_GamepadOverlayContainer.SlotBorder:UpdateQualityColor(gamepadButton); end end for i = numDisplayedItems + 1, #buttons do buttons[i]:HideButton(); end if playFlyUpAnimation then for i = 1, numDisplayedItems do buttons[i].FlyUp:Play(); end end self.numDisplayedItems = numDisplayedItems; --For gamepad to cycle end function NarciEquipmentFlyoutFrameMixin:IsMouseOverButtons() for i = 1, #self.buttons do if self.buttons[i]:IsShown() and self.buttons[i]:IsMouseOver() then return true; end end if self.parentButton:IsMouseOver() then return true end if SlotController:IsMouseOver() then return true end return false end --------------------------------------------- local function RefreshStats(id, frame) frame = frame or "Detailed"; if frame == "Detailed" then if AttributeFrames[id] then AttributeFrames[id]:Update(); end elseif frame == "Concise" then if ShortAttributeFrames[id] then ShortAttributeFrames[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 AttributeFrames[i] then AttributeFrames[i]:Update(); end if ShortAttributeFrames[i] then ShortAttributeFrames[i]:Update(); end if i >= 20 then self:Hide(); self.index = 1; else self.index = i + 1; end end end); function StatsUpdator:Gradual() ItemLevelFrame:AsyncUpdate(0.05); self.index = 1; self.t = 0; self:Show(); end function StatsUpdator:Instant() if not StatsUpdator.pauseUpdate then StatsUpdator.pauseUpdate = true; After(0, function() for i = 1, 20 do RefreshStats(i); end for i = 1, 12 do RefreshStats(i, "Concise"); end StatsUpdator.pauseUpdate = nil; end); end end function StatsUpdator:UpdateCooldown() for slotID, slotButton in pairs(SLOT_TABLE) do slotButton:TrackCooldown(); end end local function ShowAttributeButton(bool) if NarcissusDB.DetailedIlvlInfo then Narci_DetailedStatFrame:SetShown(true); Narci_ConciseStatFrame:SetShown(false); RadarChart:SetShown(true); else Narci_DetailedStatFrame:SetShown(false); Narci_ConciseStatFrame:SetShown(true); RadarChart:SetShown(false); end ItemLevelFrame:SetShown(true); end local function AssignFrame() local statFrame = Narci_DetailedStatFrame; RadarChart = Narci_RadarChartFrame; local radar = RadarChart; AttributeFrames[1] = statFrame.Primary; AttributeFrames[2] = statFrame.Stamina; AttributeFrames[3] = statFrame.Damage; AttributeFrames[4] = statFrame.AttackSpeed; AttributeFrames[5] = statFrame.Power; AttributeFrames[6] = statFrame.Regen; AttributeFrames[7] = statFrame.Health; AttributeFrames[8] = statFrame.Armor; AttributeFrames[9] = statFrame.Reduction; AttributeFrames[10]= statFrame.Dodge; AttributeFrames[11]= statFrame.Parry; AttributeFrames[12]= statFrame.Block; AttributeFrames[13]= radar.Crit; AttributeFrames[14]= radar.Haste; AttributeFrames[15]= radar.Mastery; AttributeFrames[16]= radar.Versatility; AttributeFrames[17]= statFrame.Leech; AttributeFrames[18]= statFrame.Avoidance; AttributeFrames[19]= statFrame.MovementSpeed; AttributeFrames[20]= statFrame.Speed; local statFrame_Short = Narci_ConciseStatFrame; ShortAttributeFrames[1] = statFrame_Short.Primary; ShortAttributeFrames[2] = statFrame_Short.Stamina; ShortAttributeFrames[3] = statFrame_Short.Health; ShortAttributeFrames[4] = statFrame_Short.Power; ShortAttributeFrames[5] = statFrame_Short.Regen; ShortAttributeFrames[6] = statFrame_Short.Crit; ShortAttributeFrames[7] = statFrame_Short.Haste; ShortAttributeFrames[8] = statFrame_Short.Mastery; ShortAttributeFrames[9] = statFrame_Short.Versatility; ShortAttributeFrames[10] = statFrame_Short.Leech; ShortAttributeFrames[11] = statFrame_Short.Avoidance; ShortAttributeFrames[12] = statFrame_Short.Speed; end function Narci_SetPlayerName(self) local playerName = UnitName("player"); local editBox = self.PlayerName or self.MogNameEditBox; editBox:SetShadowColor(0, 0, 0); editBox:SetShadowOffset(2, -2); editBox:SetText(playerName); SmartFontType(editBox); end local function Narci_Close() if Narci.showExitConfirm and not InCombatLockdown() then local ExitConfirm = Narci_ExitConfirmationDialog; if not ExitConfirm:IsShown() then FadeFrame(ExitConfirm, 0.25, 1); SetUIVisibility(false); MiniButton:Enable(); UIParent:SetAlpha(1); return else FadeFrame(ExitConfirm, 0.15, 0); end end SlotController:PlayAnimOut(); ExitFunc(); PlayLetteboxAnimation("OUT"); EquipmentFlyoutFrame:Hide(); Narci_ModelSettings:Hide(); Toolbar:HideUI(); TakeOutFrames(false); Narci.showExitConfirm = false; end function Narci_Open() if not IS_OPENED then if InCombatLockdown() then return end IS_OPENED = true; CVarTemp:BackUp(); Toolbar:ShowUI("Narcissus"); ViewProfile:SaveView(5); CameraUtil:DisableMotionSickness(); CameraUtil:UpdateParameters(); CameraUtil:MakeActive(); CameraUtil:SetUseMogOffset(false) EL:Show(); IntroMotion:Enter(); After(0, function() RadarChart:SetValue(0,0,0,0,1); PlayLetteboxAnimation(); local Vignette = Narci_Vignette; Vignette.VignetteLeft:SetAlpha(VIGNETTE_ALPHA); Vignette.VignetteRight:SetAlpha(VIGNETTE_ALPHA); Vignette.VignetteRightSmall:SetAlpha(0); FadeFrame(Vignette, 0.5, 1); Vignette.VignetteRight.animIn:Play(); Vignette.VignetteLeft.animIn:Play(); SlotButtonOverlayUtil:UpdateData(); After(0, function() SlotController:LazyRefresh(); StatsUpdator:Gradual(); end); end); Narci.refreshCombatRatings = true; Narci.isActive = true; CallbackRegistry:Trigger("NarcissusCharacterUI.ShownState", true); else Narci_Close(); end NarciAPI.UpdateSessionTime(); end function Narci_OpenGroupPhoto() if not IS_OPENED then if InCombatLockdown() then return; end IS_OPENED = true; CVarTemp:BackUp(); Toolbar:ShowUI("PhotoMode"); ViewProfile:SaveView(5); CameraUtil:DisableMotionSickness(); CameraUtil:UpdateParameters(); CameraUtil:MakeActive(); SetCVar("test_cameraDynamicPitch", 1); EL:Show(); CameraUtil:SmoothPitch(); UIParentFade:FadeOutUIParent(); After(0, function() Toolbar:Expand(true); local toolbarButton = GetToolbarButtonByButtonType("Mog"); toolbarButton:OnClick(); SlotController:LazyRefresh(); local Vignette = Narci_Vignette; Vignette.VignetteLeft:SetAlpha(VIGNETTE_ALPHA); Vignette.VignetteRight:SetAlpha(VIGNETTE_ALPHA); Vignette.VignetteRightSmall:SetAlpha(0); FadeFrame(Vignette, 0.8, 1); Vignette.VignetteRight.animIn:Play(); Vignette.VignetteLeft.animIn:Play(); end) Narci.isActive = true; CallbackRegistry:Trigger("NarcissusCharacterUI.ShownState", true); MsgAlertContainer:Display(); NarciAPI.UpdateSessionTime(); else Narci_Close(); end end ------------------------------------------------------ ------------------Photo Mode Controller--------------- ------------------------------------------------------ function Narci_KeyListener_OnEscapePressed(self) if IS_OPENED then MiniButton:Click(); if self then if not InCombatLockdown() then self:SetPropagateKeyboardInput(false); end end end end local function UseXmogLayout() CameraUtil:SetUseMogOffset(true); NarciPlayerModelFrame1.xmogMode = 2; if Narci_Character:IsVisible() then FadeFrame(NarciModel_RightGradient, 0.5, 1); end Narci_ModelContainer:Show(); Narci_PlayerModelAnimIn:Show(); Narci_PlayerModelGuideFrame.VignetteRightSmall:Show(); Narci_GuideLineFrame.VirtualLineRight.AnimFrame.toX = -600; Narci_GuideLineFrame.VirtualLineRight.AnimFrame:Show(); After(0, function() if not IsMounted() then CameraUtil:SmoothPitch(); CameraUtil:ZoomToDefault(true); else CameraUtil:ZoomTo(8); end end) end local function ActivateMogMode() Narci_GuideLineFrame.VirtualLineRight.AnimFrame:Hide(); if MOG_MODE then FadeFrame(Narci_Attribute, 0.5, 0) FadeFrame(Narci_XmogNameFrame, 0.2, 1, 0) CameraUtil:SetUseMogOffset(true); NarciPlayerModelFrame1.xmogMode = 2; MsgAlertContainer:Display(); UseXmogLayout(); else Narci_GuideLineFrame.VirtualLineRight.AnimFrame.toX = Narci_GuideLineFrame.VirtualLineRight.AnimFrame.defaultX; if Toolbar:IsShown() then Narci_GuideLineFrame.VirtualLineRight.AnimFrame:Show(); FadeFrame(Narci_Attribute, 0.5, 1); CameraUtil:SmoothShoulderByZoom(); end FadeFrame(Narci_XmogNameFrame, 0.2, 0); ShowAttributeButton(); CameraUtil:SetUseMogOffset(false); MsgAlertContainer:Hide(); RadarChart:SetValue(); end end local function UpdateXmogName(SpecOnly) local frame = Narci_XmogNameFrame; local currentSpec = GetSpecialization(); if not currentSpec then return; end local IsSpellKnown = IsSpellKnown; local token = 159243; local ArmorType; if not SpecOnly then Narci_SetPlayerName(frame); if IsSpellKnown(76273) or IsSpellKnown(106904) or IsSpellKnown(202782) or IsSpellKnown(76275) then --ArmorType = "Leather" token = 159300; elseif IsSpellKnown(76250) or IsSpellKnown(76272) or IsSpellKnown(366522) then --ArmorType = "Mail" token = 159371; elseif IsSpellKnown(76276) or IsSpellKnown(76277) or IsSpellKnown(76279) then --ArmorType = "Cloth" token = 159243; elseif IsSpellKnown(76271) or IsSpellKnown(76282) or IsSpellKnown(76268) then --ArmorType = "Plate" token = 159418; end local _; _, _, ArmorType = GetItemInfoInstant(token); frame.armorType = ArmorType; end ArmorType = frame.armorType or ArmorType or "ArmorType"; local _, currentSpecName = GetSpecializationInfo(currentSpec); currentSpecName = currentSpecName or ""; local className, englishClass, _ = UnitClass("player"); local _, _, _, rgbHex = GetClassColor(englishClass); frame.ArmorString:SetText("|cFFFFD100"..ArmorType.."|r".." | ".."|c"..rgbHex..currentSpecName.." "..className.."|r"); end local function GetWowHeadDressingRoomURL() local slot; local ItemList = {}; for i = 1, #xmogTable do slot = xmogTable[i][1]; if SLOT_TABLE[slot] and SLOT_TABLE[slot].itemID then ItemList[slot] = {SLOT_TABLE[slot].itemID, SLOT_TABLE[slot].bonusID}; end end return NarciAPI.EncodeItemlist(ItemList); end local function CopyTexts(textFormat, includeID) local texts = Narci_XmogNameFrame.MogNameEditBox:GetText() or "My Transmog"; textFormat = textFormat or "text"; local source; if textFormat == "text" then texts = texts.."\n" for i = 1, #xmogTable do local index = xmogTable[i][1] if SLOT_TABLE[index] and SLOT_TABLE[index].Name:GetText() then local text = "|cFFFFD100"..xmogTable[i][2]..":|r "..(SLOT_TABLE[index].Name:GetText() or " "); if includeID and SLOT_TABLE[index].itemID then text = text.." |cFFacacac"..SLOT_TABLE[index].itemID.."|r"; end source = SLOT_TABLE[index].ItemLevel:GetText(); if source and source ~= " " then text = text.." ("..source..")" end if text then texts = texts.."\n"..text; end end end elseif textFormat == "reddit" then texts = "|cFF959595**|r"..texts.."|cFF959595**\n\n| Slot | Name | Source |".."\n".."|:--|:--|:--|" for i=1, #xmogTable do local index = xmogTable[i][1] if SLOT_TABLE[index] and SLOT_TABLE[index].Name:GetText() then local text = "|cFF959595| |r|cFFFFD100"..xmogTable[i][2].."|r |cFF959595| |r" if includeID and SLOT_TABLE[index].itemID then text = text.."|cFF959595[|r"..(SLOT_TABLE[index].Name:GetText() or " ").."|cFF959595](https://www.wowhead.com/item=|r"..SLOT_TABLE[index].itemID..")|r" else text = text..(SLOT_TABLE[index].Name:GetText() or " ") end source = SLOT_TABLE[index].ItemLevel:GetText() if source then text = text.." |cFF959595| |r|cFF40C7EB"..source.."|r |cFF959595| |r" else text = text.." |cFF959595| |r" end if text then texts = texts.."\n"..text; end end end texts = texts.."\n"; else if textFormat == "wowhead" then texts = "|cFF959595[table border=2 cellpadding=4]\n[tr][td colspan=3 align=center][b]|r"..texts.."|r|cFF959595[/b][/td][/tr]\n[tr][td align=center]Slot[/td][td align=center]Name[/td][td align=center]Source[/td][/tr]|r" elseif textFormat == "nga" then texts = "|cFF959595[table]\n[tr][td colspan=3][align=center][b]|r"..texts.."|r|cFF959595[/b][/align][/td][/tr]\n[tr][td][align=center]部位[/align][/td][td][align=center]装备名称[/align][/td][td][align=center]来源[/align][/td][/tr]|r" elseif textFormat == "mmo-champion" then texts = "|cFF959595[table=\"width: 640, class: grid\"]\n[tr][td=\"colspan: 3\"][center][b]|r"..texts.."|r|cFF959595[/b][/center][/td][/tr]\n[tr][td][center]Slot[/center][/td][td][center]Name[/center][/td][td][center]Source[/center][/td][/tr]|r" end for i=1, #xmogTable do local index = xmogTable[i][1] if SLOT_TABLE[index] and SLOT_TABLE[index].Name:GetText() then local text = "|cFF959595[tr][td]|r".."|cFFFFD100"..xmogTable[i][2].."|r|cFF959595[/td][td]|r" if includeID and SLOT_TABLE[index].itemID then if textFormat == "wowhead" then text = text.."[item="..SLOT_TABLE[index].itemID.."|r|cFF959595][/td]|r" elseif textFormat == "nga" then text = text.."|cFF959595[url=https://www.wowhead.com/item="..SLOT_TABLE[index].itemID.."]|r"..(SLOT_TABLE[index].Name:GetText() or " ").."|cFF959595[/url][/td]|r" elseif textFormat == "mmo-champion" then text = text.."|cFF959595[url=https://www.wowdb.com/items/"..SLOT_TABLE[index].itemID.."]|r"..(SLOT_TABLE[index].Name:GetText() or " ").."|cFF959595[/url][/td]|r" end else text = text..(SLOT_TABLE[index].Name:GetText() or " ").."|r|cFF959595[/td]|r" end source = SLOT_TABLE[index].ItemLevel:GetText() if source then text = text.."|cFF959595[td]|r|cFF40C7EB"..source.."|r|cFF959595[/td]|r" else text = text.."|cFF959595[td] [/td]|r" end if text then texts = texts.."\n"..text.."|cFF959595[/tr]|r" end end end texts = texts.."\n|cFF959595[/table]|r" ----- if textFormat == "wowhead" then texts = GetWowHeadDressingRoomURL(); end end return texts; end local function Narci_XmogButton_OnClick(self) MoveViewRightStop(); EquipmentFlyoutFrame:Hide(); MOG_MODE = not MOG_MODE; self.isOn = MOG_MODE; if self.isOn then FadeFrame(Narci_VignetteRightSmall, 0.5, NarcissusDB.VignetteStrength); FadeFrame(Narci_VignetteRightLarge, 0.5, 0); Narci_SnowEffect(false); PlayLetteboxAnimation("OUT"); Narci_XmogNameFrame.MogNameEditBox:SetText(Narci_PlayerInfoFrame.PlayerName:GetText()) Toolbar.TransmogListFrame:ShowUI(); Toolbar.showTransmogFrame = true; else --Exit Xmog mode Toolbar.TransmogListFrame:Hide(); Toolbar.showTransmogFrame = nil; FadeFrame(Narci_VignetteRightSmall, 0.5, 0); FadeFrame(Narci_VignetteRightLarge, 0.5, NarcissusDB.VignetteStrength); Narci_SnowEffect(true); PlayLetteboxAnimation(); if Narci_ModelContainer:IsVisible() then if IS_OPENED then CameraUtil:SmoothPitch(); end Narci_PlayerModelAnimOut:Show() After(0.4, function() FadeFrame(NarciPlayerModelFrame1, 0.5 , 0); end) end Narci_ModelSettings:Hide(); if not Narci_ExitConfirmationDialog:IsShown() then Narci.showExitConfirm = false; end if (not InCombatLockdown()) and (not Narci_Character:IsShown()) then Narci_Character:Show(); Narci_Character:SetAlpha(1); end StatsUpdator:Gradual(); end if MOG_MODE then SlotController:RefreshAll(); else SlotController:LazyRefresh(); end After(0.1, function() ActivateMogMode(); end) self:UpdateIcon(); end addon.OverrideToolbarButtonOnClickFunc("Mog", Narci_XmogButton_OnClick); addon.OverrideToolbarButtonOnInitFunc("Mog", function(self) if MOG_MODE then self.isOn = true; self:UpdateIcon(); end end); Toolbar.TransmogListFrame.getItemListFunc = CopyTexts; ------Photo Mode Toolbar------ do local IsInteractingWithDialogNPC = addon.IsInteractingWithDialogNPC; --Prevent clash with DialogUI hooksecurefunc("SetUIVisibility", function(state) if IS_OPENED then --when Narcissus hide the UI if state then MsgAlertContainer:SetDND(true); Toolbar:UseLowerLevel(true); else local bar = Toolbar; Toolbar.ExitButton:Show(); if not bar:IsShown() then bar:Show(); end MsgAlertContainer:SetDND(false); bar:UseLowerLevel(false); end else --when user hide the UI manually if state then --When player closes the full-screen world map, SetUIVisibility(true) fires twice, and WorldMapFrame:IsShown() returns true and false. --Thus, use this VisibilityTracker instead to check if WorldMapFrame has been closed recently. --WorldMapFrame.VisibilityTracker.state MsgAlertContainer:Hide(); if Narci_Character:IsShown() then return end; if not Toolbar:IsShown() then return end; if not GetKeepActionCam() then After(0.6, function() ConsoleExec( "actioncam off" ); end) end Toolbar:HideUI(); else if IsInteractingWithDialogNPC() then return end; local bar = Toolbar; if not bar:IsShown() then CVarTemp.shoulderOffset = GetCVar("test_cameraOverShoulder"); end bar:ShowUI("Blizzard"); bar:FadeOut(true); end end end) end do --Slash Command local function callback(msg) if not msg then msg = ""; end msg = string.lower(msg); if msg == "" then MiniButton:Click(); elseif msg == "minimap" then MiniButton:EnableButton(); print(L["MinimapButton Reenabled"]); elseif msg == "itemlist" then DressUpFrame_Show(DressUpFrame); if NarciDressingRoomOverlay then NarciDressingRoomOverlay:ShowItemList(); end elseif msg == "resetposition" then MiniButton:ResetPosition(); elseif string.find(msg, "/outfit") then Narci:LoadOutfitSlashCommand(msg); --/narci /outfit v1 50109,182541,0,77345,182521,2633,0,181613,182527,79067,182538,84323,80378,-1,0,77903,0 else local color = "|cff40C7EB"; print(" "); print(color.."Show Minimap Button:|r /narci minimap"); print(color.."Reset Minimap Button Position:|r /narci resetposition"); print(color.."Copy Item List:|r /narci itemlist"); end end NarciAPI.CreateSlashCommand(callback, "narci", "narcissus"); end --3D Animation local function InitializeAnimationContainer(frame, SequenceInfo, TargetFrame) frame.OppoDirection = false; frame.t = 0 frame.totalTime = 0; frame.Index = 1; frame.Pending = false; frame.IsPlaying = false; frame.SequenceInfo = SequenceInfo; frame.Target = TargetFrame end local function AnimationContainer_OnHide(self) self.totalTime = 0; self.TimeSinceLastUpdate = 0; self.OppoDirection = not self.OppoDirection if self.Index <= 0 then self.Index = 0; end end local PlayAnimationSequence = NarciAPI_PlayAnimationSequence; local ASC2 = CreateFrame("Frame", "AnimationSequenceContainer_Heart"); ASC2.Delay = 5; ASC2.IsPlaying = false; ASC2:Hide(); local function Generic_AnimationSequence_OnUpdate(self, elapsed) if self.Pending then return; end self.totalTime = self.totalTime + elapsed; if (not self.OppoDirection and self.totalTime < self.Delay) and (not self.IsPlaying) then return; elseif not self.IsPlaying then if not self.OppoDirection then --box closing FadeFrame(Narci_HeartofAzeroth_AnimFrame, 0.25, 1) After(0.3, function() Narci_HeartofAzeroth_AnimFrame.Background:SetAlpha(1); Narci_HeartofAzeroth_AnimFrame.Quote:SetAlpha(1); Narci_HeartofAzeroth_AnimFrame.SN:SetAlpha(1); end) end self.IsPlaying = true; end self.t = self.t + elapsed; if self.t >= 0.01666 then self.t = 0; if self.OppoDirection then self.Index = self.Index - 1; else self.Index = self.Index + 1; end if not PlayAnimationSequence(self.Index, self.SequenceInfo, self.Target) then self:Hide() self.IsPlaying = false; if not self.OppoDirection then Narci_HeartofAzeroth_AnimFrame.Background:SetAlpha(0); Narci_HeartofAzeroth_AnimFrame.Quote:SetAlpha(0); Narci_HeartofAzeroth_AnimFrame.SN:SetAlpha(0); FadeFrame(Narci_HeartofAzeroth_AnimFrame, 0.25, 0) end return; end end end ASC2:SetScript("OnUpdate", Generic_AnimationSequence_OnUpdate); ASC2:SetScript("OnHide", AnimationContainer_OnHide); --Static Events EL:RegisterEvent("PLAYER_ENTERING_WORLD"); EL:RegisterUnitEvent("UNIT_NAME_UPDATE", "player"); EL:RegisterEvent("PLAYER_AVG_ITEM_LEVEL_UPDATE"); EL:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED"); EL:RegisterEvent("PLAYER_LEVEL_CHANGED"); --These events might become deprecated in future expansions EL:RegisterEvent("COVENANT_CHOSEN"); EL:SetScript("OnEvent",function(self, event, ...) --print(event) if event == "PLAYER_ENTERING_WORLD" then self:UnregisterEvent(event); After(2, function() StatsUpdator:Instant(); RadarChart:SetValue(0,0,0,0,1); UpdateXmogName(); end) local AnimSequenceInfo = Narci.AnimSequenceInfo; InitializeAnimationContainer(ASC2, AnimSequenceInfo["Heart"], Narci_HeartofAzeroth_AnimFrame.Sequence) local HeartSerialNumber = strsub(UnitGUID("player"), 8, 15); Narci_HeartofAzeroth_AnimFrame.SN:SetText("No."..HeartSerialNumber); Narci_HeartofAzeroth_AnimFrame.Quote:SetText(L["Heart Azerite Quote"]); UpdateXmogName(); DefaultTooltip = NarciGameTooltip; --Created in Module\GameTooltip.lua if not ItemTooltip then ItemTooltip = DefaultTooltip; end DefaultTooltip:SetParent(Narci_Character); DefaultTooltip:SetFrameStrata("TOOLTIP"); DefaultTooltip.offsetX = 4; DefaultTooltip.offsetY = -16; DefaultTooltip:SetIgnoreParentAlpha(true); if C_AddOns.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(); elseif C_AddOns.IsAddOnLoaded("ActionCamPlus") then CVarTemp.isActionCamPlusLoaded = true; else if NarcissusDB.CameraSafeMode then local temp = GetCVar("test_cameraOverShoulder"); if tonumber(temp) ~= 0 then --SetCVar("test_cameraOverShoulder", 0); ConsoleExec( "actioncam off" ); NarciAPI.PrintPresetMessage("camera"); end end end After(1.7, function() UpdateCharacterInfoFrame(); if CVarTemp.isDynamicCamLoaded then CameraUtil:UpdateMovementMethodForDynamicCam(); else hooksecurefunc("CameraZoomIn", function(increment) if IS_OPENED and (not Narci.groupPhotoMode) then CameraUtil:SmoothShoulderByZoom(-increment); end end) hooksecurefunc("CameraZoomOut", function(increment) if IS_OPENED and (not Narci.groupPhotoMode) then CameraUtil:SmoothShoulderByZoom(-increment); end end) end end) if TimerunningUtil.IsTimerunningMode() then Narci.deferGemManager = true; end elseif event == "PLAYER_EQUIPMENT_CHANGED" then local slotID, isItem = ...; SlotController:Refresh(slotID); if EquipmentFlyoutFrame:IsShown() and EquipmentFlyoutFrame.slotID then EquipmentFlyoutFrame:DisplayItemsBySlotID(EquipmentFlyoutFrame.slotID, false); end ItemLevelFrame:AsyncUpdate(); local slot = SLOT_TABLE[slotID]; if slot and slot:IsMouseOver() then slot:Disable(); After(0, function() slot:Enable(); end); end elseif event == "AZERITE_ESSENCE_ACTIVATED" then local neckSlotID = 2; SlotController:Refresh(neckSlotID); --Heart of Azeroth elseif event == "PLAYER_AVG_ITEM_LEVEL_UPDATE" then if not self.pendingItemLevel then self.pendingItemLevel = true; After(0.1, function() -- only want 1 update per 0.1s ItemLevelFrame:UpdateItemLevel(); self.pendingItemLevel = nil; end) end elseif event == "COVENANT_CHOSEN" then local covenantID = ...; ItemLevelFrame:AsyncUpdate(); MiniButton:SetBackground(covenantID); elseif event == "COVENANT_SANCTUM_RENOWN_LEVEL_CHANGED" then local newRenownLevel = ...; ItemLevelFrame:UpdateRenownLevel(newRenownLevel); elseif event == "UNIT_NAME_UPDATE" then local unit = ...; if unit == "player" then UpdateCharacterInfoFrame(); end elseif event == "ACTIVE_TALENT_GROUP_CHANGED" then UpdateCharacterInfoFrame(); UpdateXmogName(true); SlotButtonOverlayUtil:UpdateData(); elseif event == "PLAYER_LEVEL_CHANGED" then local oldLevel, newLevel = ...; UpdateCharacterInfoFrame(newLevel) elseif ( event == "COMBAT_RATING_UPDATE" or event == "UNIT_MAXPOWER" or event == "UNIT_STATS" or event == "UNIT_DAMAGE" or event == "UNIT_ATTACK_SPEED" or event == "UNIT_MAXHEALTH" or event == "UNIT_AURA" ) and Narci.refreshCombatRatings then -- don't refresh stats when equipment set manager is activated StatsUpdator:Instant(); if event == "COMBAT_RATING_UPDATE" then if Narci_Character:IsShown() then RadarChart:UpdateChart(true); end end if event == "UNIT_AURA" then --11.0 Worgen Two Forms no longer trigger this local inAlteredForm = IsPlayerInAlteredForm(); if self.wasAlteredForm ~= inAlteredForm then self.wasAlteredForm = inAlteredForm; CameraUtil:OnPlayerFormChanged(0.0); end end elseif event == "PLAYER_TARGET_CHANGED" then RefreshStats(8); --Armor RefreshStats(9); --Damage Reduction elseif event == "UPDATE_SHAPESHIFT_FORM" or event == "UNIT_PORTRAIT_UPDATE" then CameraUtil:OnPlayerFormChanged(0.1); elseif event == "PLAYER_MOUNT_DISPLAY_CHANGED" then CameraUtil:OnPlayerFormChanged(0.0); elseif event == "PLAYER_REGEN_DISABLED" then if Narci.isAFK and Narci.isActive then --exit when entering combat during AFK mode MiniButton:Click(); Narci:PlayVoice("DANGER"); end elseif event == "PLAYER_STARTED_MOVING" then self:UnregisterEvent(event); MoveViewRightStop(); if Narci.isAFK and Narci.isActive then --exit when entering combat during AFK mode MiniButton:Click(); end elseif event == "PLAYER_STARTED_TURNING" and not MOG_MODE then NarciAR.Turning.radian = GetPlayerFacing(); NarciAR.Turning:Show(); elseif event == "PLAYER_STOPPED_TURNING" and not MOG_MODE then NarciAR.Turning:Hide(); elseif event == "BAG_UPDATE_COOLDOWN" then StatsUpdator:UpdateCooldown(); elseif event == "BAG_UPDATE" then local newTime = GetTime(); if self.lastTime then if newTime > self.lastTime + 0.2 then self.lastTime = newTime; else return end else self.lastTime = newTime; end ItemLevelFrame:AsyncUpdate(0.1); elseif event == "UNIT_INVENTORY_CHANGED" then SlotController:LazyRefresh("temp"); end end) function EL:ToggleDynamicEvents(state) if state then for _, event in ipairs(self.EVENTS_DYNAMIC) do self:RegisterUnitEvent(event); end for _, event in ipairs(self.EVENTS_UNIT) do self:RegisterUnitEvent(event, "player"); end else for _, event in ipairs(self.EVENTS_DYNAMIC) do self:UnregisterEvent(event); end for _, event in ipairs(self.EVENTS_UNIT) do self:UnregisterEvent(event); end end end EL:SetScript("OnShow",function(self) self:ToggleDynamicEvents(true); if NarciAR then NarciAR:Show(); end end) EL:SetScript("OnHide",function(self) self:ToggleDynamicEvents(false); if NarciAR then NarciAR:Hide(); end end) ---------------------------------------------------------------------- --Double-click PaperDoll Button to open Narcissus NarciPaperDollDoubleClickTriggerMixin = {}; local function Narci_DoubleClickTrigger_OnUpdate(self, elapsed) self.t = self.t + elapsed; if self.t > 0.25 then self:SetScript("OnUpdate", nil); end end function NarciPaperDollDoubleClickTriggerMixin:OnLoad() self.t = 0; AssignFrame(); AssignFrame = nil; self:SetScript("OnLoad", nil); self.OnLoad = nil; end function NarciPaperDollDoubleClickTriggerMixin:OnShow() self.t = 0; self:SetScript("OnUpdate", Narci_DoubleClickTrigger_OnUpdate); end function NarciPaperDollDoubleClickTriggerMixin:OnHide() if (self.t < 0.25 and self.t > 0.03) and NarcissusDB.EnableDoubleTap then MiniButton:Click(); end end ---------------------------------------------------------------------- function Narci_GuideLineFrame_OnSizing(self, offset) local W; local W0, H = WorldFrame:GetSize(); if (W0 and H) and H ~= 0 then local ratio = floor(W0 / H * 100 + 0.5) / 100; if ratio == 1.78 then return end self:ClearAllPoints(); self:SetPoint("TOP", UIParent, "TOP", 0, 0); self:SetPoint("BOTTOM", UIParent, "BOTTOM", 0, 0); offset = offset or 0; W = math.min(H / 9 * 16, W0); W = floor(W + 0.5); --print("Original: "..W0.." Calculated: "..W); self:SetWidth(W - offset); else W = self:GetWidth(); end local C = W*0.618; self.VirtualLineRight:SetPoint("RIGHT", C - W +32, 0); self.VirtualLineRight.defaultX = C - W +32; local AnimFrame = self.VirtualLineRight.AnimFrame; AnimFrame.OppoDirection = false; AnimFrame.TimeSinceLastUpdate = 0; AnimFrame.anchorPoint, AnimFrame.relativeTo, AnimFrame.relativePoint, AnimFrame.toX, AnimFrame.toY = AnimFrame:GetParent():GetPoint(); AnimFrame.defaultX = AnimFrame.toX; end function Narci_GuideLineFrame_SnapToFinalPosition() local animFrames = { Narci_GuideLineFrame.VirtualLineLeft.AnimFrame, Narci_GuideLineFrame.VirtualLineRight.AnimFrame, }; for _, animFrame in ipairs(animFrames) do animFrame:Hide(); if animFrame.frame then animFrame.frame:SetPoint(animFrame.anchorPoint, animFrame.toX, 0); end end end Narci.GetEquipmentSlotByID = function(slotID) return SLOT_TABLE[slotID] end; Narci.RefreshSlot = function(slotID) SlotController:Refresh(slotID) return SLOT_TABLE[slotID] end; Narci.RefreshAllSlots = SlotController.RefreshAll; Narci.RefreshAllStats = StatsUpdator.Instant; function Narci:SetItemTooltipStyle(id) end function Narci:CloseCharacterUI() if IS_OPENED then Narci_Open(); end end do local SettingFunctions = addon.SettingFunctions; function SettingFunctions.SetItemTooltipStyle(id, db) if id == nil then id = db["ItemTooltipStyle"]; end if id == 2 then ItemTooltip = NarciGameTooltip; else ItemTooltip = NarciEquipmentTooltip; end NarciEquipmentTooltip:SetParent(Narci_Character); end function SettingFunctions.SetVignetteStrength(alpha, db) if alpha == nil then alpha = db["VignetteStrength"]; end alpha = tonumber(alpha) or 0.5; VIGNETTE_ALPHA = alpha; Narci_Vignette.VignetteLeft:SetAlpha(alpha); Narci_Vignette.VignetteRight:SetAlpha(alpha); Narci_Vignette.VignetteRightSmall:SetAlpha(alpha); Narci_PlayerModelGuideFrame.VignetteRightSmall:SetAlpha(alpha); end function SettingFunctions.SetUltraWideFrameOffset(offset, db) --A positive offset expands the reference frame. if not offset then offset = db["BaseLineOffset"]; offset = tonumber(offset) or 0 end Narci_GuideLineFrame_OnSizing(Narci_GuideLineFrame, -offset); end function SettingFunctions.ShowDetailedStats(state, db) if state == nil then state = db["DetailedIlvlInfo"]; end if Narci_Attribute:IsVisible() then if state then FadeFrame(Narci_DetailedStatFrame, 0.5, 1); FadeFrame(RadarChart, 0.5, 1); FadeFrame(Narci_ConciseStatFrame, 0.5, 0); else FadeFrame(Narci_DetailedStatFrame, 0.5, 0); FadeFrame(RadarChart, 0.5, 0); FadeFrame(Narci_ConciseStatFrame, 0.5, 1); end else if state then FadeFrame(Narci_DetailedStatFrame, 0, 1); FadeFrame(RadarChart, 0, 1); FadeFrame(Narci_ConciseStatFrame, 0, 0); else FadeFrame(Narci_DetailedStatFrame, 0, 0); FadeFrame(RadarChart, 0, 0); FadeFrame(Narci_ConciseStatFrame, 0, 1); end end Narci_ItemLevelFrame:ToggleExtraInfo(state); Narci_ItemLevelFrame.showExtraInfo = state; Narci_NavBar:SetMaximizedMode(state); end function SettingFunctions.SetCharacterUIScale(scale, db) if not scale then scale = db["GlobalScale"]; end scale = tonumber(scale) or 1; NarciScreenshotToolbar:SetDefaultScale(scale); Narci_Character:SetScale(scale); Narci_Attribute:SetScale(scale); NarciTooltip:SetScale(scale); end function SettingFunctions.SetItemNameTextHeight(height, db) if not height then height = db["FontHeightItemName"]; end height = tonumber(height) or 10; local font, _, flag = SLOT_TABLE[1].Name:GetFont(); for id, slotButton in pairs(SLOT_TABLE) do slotButton.Name:SetFont(font, height, flag); slotButton:UpdateGradientSize(); end end function SettingFunctions.SetItemNameTextWidth(width, db) if not width then width = db["ItemNameWidth"]; end width = tonumber(width) or 200; if width >= 200 then width = 512; end for id, slotButton in pairs(SLOT_TABLE) do slotButton.Name:SetWidth(width); slotButton.ItemLevel:SetWidth(width); slotButton:UpdateGradientSize(); end end function SettingFunctions.SetItemNameTruncated(state, db) if state == nil then state = db["TruncateText"]; end local maxLines; if state then maxLines = 1; else maxLines = 2; end for id, slotButton in pairs(SLOT_TABLE) do slotButton.Name:SetMaxLines(maxLines); slotButton.ItemLevel:SetMaxLines(maxLines); slotButton.Name:SetWidth(slotButton.Name:GetWidth()+1) slotButton.Name:SetWidth(slotButton.Name:GetWidth()-1) slotButton.ItemLevel:SetWidth(slotButton.Name:GetWidth()+1) slotButton.ItemLevel:SetWidth(slotButton.Name:GetWidth()-1) slotButton:UpdateGradientSize(); end end function SettingFunctions.UseCameraTransition(state, db) if state == nil then state = db["CameraTransition"]; end IntroMotion:SetUseCameraTransition(state); end function SettingFunctions.EnableCameraSafeMode(state, db) if state == nil then state = db["CameraSafeMode"]; end CVarTemp.cameraSafeMode = state; end function SettingFunctions.EnableMissingEnchantAlert(state, db) if state == nil then state = db["MissingEnchantAlert"]; end --only enabled when player reach max level if not NarciAPI.IsPlayerAtMaxLevel() then state = false; end SHOW_MISSING_ENCHANT_ALERT = state; SlotButtonOverlayUtil:SetEnabled(state); SlotController:ClearCache(); if Narci_Character and Narci_Character:IsShown() then SlotController:LazyRefresh(); end end end NarciCharacterUIPlayerNameEditBoxMixin = {}; do function NarciCharacterUIPlayerNameEditBoxMixin:OnLoad() end function NarciCharacterUIPlayerNameEditBoxMixin:OnShow() self:UpdateSize(); end function NarciCharacterUIPlayerNameEditBoxMixin:OnTextChanged() SmartFontType(self) self:UpdateSize(); end function NarciCharacterUIPlayerNameEditBoxMixin:UpdateSize() local numLetters = self:GetNumLetters(); local width = max(numLetters*16, 160); self:SetWidth(width); end function NarciCharacterUIPlayerNameEditBoxMixin:SaveAndExit() self:ClearFocus(); local text = strtrim(self:GetText()); self:SetText(text); NarcissusDB_PC.PlayerAlias = text; end function NarciCharacterUIPlayerNameEditBoxMixin:OnEscapePressed() self:SaveAndExit(); end function NarciCharacterUIPlayerNameEditBoxMixin:OnEnterPressed() self:SaveAndExit(); end end NarciCharacterUIAliasButtonMixin = {}; do function NarciCharacterUIAliasButtonMixin:OnLoad() local keepInvisibleFrame = true; NarciFadeUI.CreateFadeObject(self, keepInvisibleFrame); end function NarciCharacterUIAliasButtonMixin:OnEnter() self.Label:SetTextColor(0, 0, 0); self.Label:SetShadowColor(1, 1, 1); self.Highlight:Show(); end function NarciCharacterUIAliasButtonMixin:OnLeave() self.Label:SetTextColor(0.25, 0.78, 0.92); self.Label:SetShadowColor(0, 0, 0); self.Highlight:Hide(); end function NarciCharacterUIAliasButtonMixin:OnClick() NarcissusDB_PC.UseAlias = not NarcissusDB_PC.UseAlias; self:UpdateNames(true); end function NarciCharacterUIAliasButtonMixin:OnShow() self:SetScript("OnShow", nil); self:UpdateNames(); end function NarciCharacterUIAliasButtonMixin:OnHide() self:OnLeave(); end function NarciCharacterUIAliasButtonMixin:UpdateSize() self:SetWidth(self.Label:GetWidth() + 12); end function NarciCharacterUIAliasButtonMixin:UpdateNames(onClick) local editBox = self:GetParent(); if NarcissusDB_PC.UseAlias then self.Label:SetText(L["Use Player Name"]); editBox:Enable(); editBox:SetText(NarcissusDB_PC.PlayerAlias or UnitName("player")); if onClick then editBox:SetFocus(); editBox:HighlightText(); end 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:UpdateSize(); editBox:UpdateSize(); end end UIParent:UnregisterEvent("EXPERIMENTAL_CVAR_CONFIRMATION_NEEDED"); --Disable EXPERIMENTAL_CVAR_WARNING addon.AddLoadingCompleteCallback(function() local seasonID = NarciAPI.GetTimeRunningSeason(); if seasonID == 2 then IS_LEGION_REMIX = true; end end);