You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3250 lines
100 KiB

local _;
4 years ago
local C_Item = C_Item;
local After = C_Timer.After;
local GetItemInfo = GetItemInfo;
local GetItemInfoInstant = GetItemInfoInstant;
local UIFrameFadeIn = UIFrameFadeIn;
local UIFrameFadeOut = UIFrameFadeOut;
local FadeFrame = NarciFadeUI.Fade;
local PlaySound = PlaySound;
local unpack = unpack;
local _, _, _, tocversion = GetBuildInfo();
local match = string.match;
local strsub = string.sub;
local strsplit = strsplit;
local min = math.min;
local max = math.max;
local abs = math.abs;
local floor = math.floor;
local TEXT_LOCALE = GetLocale();
local Narci = Narci;
local NarciAPI = NarciAPI;
--local NarciGameTooltip = CreateFrame("GameTooltip", "NarciGameTooltip", UIParent, "GameTooltipTemplate");
4 years ago
local SecureContainer = CreateFrame("Frame", "NarciSecureFrameContainer");
SecureContainer:Hide();
------------------------
--Redirect API for 9.0--
------------------------
tocversion = tonumber(tocversion);
ExpansionTransitionBackdropTemplateMixin = {};
if BackdropTemplateMixin then
ExpansionTransitionBackdropTemplateMixin = CreateFromMixins(BackdropTemplateMixin);
end
--GetSlotVisualID
local function NarciAPI_GetSlotVisualID(slotID)
if (slotID > 10 and slotID < 15) then
--slotID = 2 ~ Use neck to show right shoulder
return 0, 0;
end
local isSecondaryAppearance;
if slotID == 2 then
isSecondaryAppearance = true; --Enum.TransmogModification.Secondary
slotID = 3;
end
local itemLocation = ItemLocation:CreateFromEquipmentSlot(slotID);
if not itemLocation or not C_Item.DoesItemExist(itemLocation) then
return 0, 0;
end
local transmogLocation = CreateFromMixins(TransmogLocationMixin);
local transmogType = 0;
local modification = 0;
if slotID == 3 then
--Shoulders
local itemTransmogInfo = C_Item.GetAppliedItemTransmogInfo(itemLocation);
local hasSecondaryAppearance;
if itemTransmogInfo then
hasSecondaryAppearance = itemTransmogInfo.secondaryAppearanceID ~= 0; --show direction mark
end
if isSecondaryAppearance then
if not hasSecondaryAppearance then
return 0, 0;
end
modification = 1; --Enum.TransmogModification : 0 ~ Main, 1 ~ Secondary
end
transmogLocation:Set(slotID, transmogType, modification);
local baseSourceID, baseVisualID, appliedSourceID, appliedVisualID, pendingSourceID, pendingVisualID, hasPendingUndo, isHideVisual, itemSubclass = C_Transmog.GetSlotVisualInfo(transmogLocation);
if ( appliedSourceID == 0 ) then
appliedSourceID = baseSourceID;
appliedVisualID = baseVisualID;
end
return appliedSourceID, appliedVisualID, hasSecondaryAppearance;
else
transmogLocation:Set(slotID, transmogType, modification);
local baseSourceID, baseVisualID, appliedSourceID, appliedVisualID, pendingSourceID, pendingVisualID, hasPendingUndo, isHideVisual, itemSubclass = C_Transmog.GetSlotVisualInfo(transmogLocation);
if ( appliedSourceID == 0 ) then
appliedSourceID = baseSourceID;
appliedVisualID = baseVisualID;
end
return appliedSourceID, appliedVisualID;
end
end
--/script for i =1, 17 do if C_Transmog.CanHaveSecondaryAppearanceForSlotID(i) then print(i) end end
--/script C_Transmog.GetSlotVisualInfo( CreateFromMixins(TransmogLocationMixin):Set(3, 0, 0) )
--/dump C_Item.GetAppliedItemTransmogInfo(ItemLocation:CreateFromEquipmentSlot(3))
--/dump C_Transmog.GetSlotVisualInfo((CreateFromMixins(TransmogLocationMixin)):Set(3, 0, 0));
NarciAPI.GetSlotVisualID = NarciAPI_GetSlotVisualID;
--------------------
----API Datebase----
--------------------
4 years ago
local _, COM_OF_ARGUS = GetAchievementInfo(12078); --Argus Weapon Transmogs: Arsenal: Weapons of the Lightforged
COM_OF_ARGUS = COM_OF_ARGUS or "Commander of Argus";
COM_OF_ARGUS = "|cFFFFD100"..BATTLE_PET_SOURCE_6 .."|r "..COM_OF_ARGUS;
--local EnsorcelledEverwyrm = C_MountJournal.GetMountFromSpell(307932);
local _, _, PROMOTION_SHADOWLANDS = C_MountJournal.GetMountInfoExtraByID(1289); --EnsorcelledEverwyrm Promotion: Shadowlands Heroic Edition
local HERITAGE_ARMOR = Narci.L["Heritage Armor"];
local HeritageArmorItemIDs = {
165931, 165932, 165933, 165934, 165935, 165936, 165937, 16598, --Dwarf
161008, 161009, 161010, 161011, 161012, 161013, 161014, 161015, --Dark Iron
156668, 156669, 156670, 156671, 156672, 156673, 156674, 156684, --Highmountain
156699, 156700, 156701, 156702, 156703, 156704, 156705, 156706, --Lightforged
161050, 161051, 161052, 161054, 161055, 161056, 161057, 161058, --Mag'har Orc (Blackrock Recolor)
161059, 161060, 161061, 161062, 161063, 161064, 161065, 161066, --Mag'har Orc (Frostwolf Recolor)
160992, 160993, 160994, 160999, 161000, 161001, 161002, 161003, --Mag'har Orc (Warsong Recolor)
156690, 156691, 156692, 156693, 156694, 156695, 156696, 156697, 157758, 158917, --Void Elf
156675, 156676, 156677, 156678, 156679, 156680, 156681, 156685, --Nightborne
166348, 166349, 166351, 166352, 166353, 166354, 166355, 166356, 166357, --Blood Elf
164993, 164994, 164995, 164996, 164997, 164998, 164999, 165000, --Zandalari
165002, 165003, 165004, 165005, 165006, 165007, 165008, 165009, --Kul'tiran
168282, 168283, 168284, 168285, 168286, 168287, 168288, 168289, 168290, --Gnome
168291, 168292, 168293, 168294, 168295, 168296, 168297, 168298, 170063, --Tauren
173968, 173966, 173970, 173971, 173967, 173969, 174354, 174355, --Vulpera
173961, 173962, 173963, 173964, 173958, 173972, --Mechagnome
174000, 174001, 174002, 174003, 174004, 174005, 174006, 173999, 173998, --Worgen
--Reserved for test ↓
}
local SecretlItemIDs = {
[162690] = true, --Waist of Time
}
local SpecialItemList = {
4 years ago
[152332] = COM_OF_ARGUS, --Brilliant Daybreak Aegis
[152333] = COM_OF_ARGUS, --Lustrous Daybreak Aegis
[152334] = COM_OF_ARGUS, --Brilliant Eventide Aegis
[152335] = COM_OF_ARGUS, --Lustrous Eventide Aegis
[152336] = COM_OF_ARGUS, --Lustrous Daybreak Blade
[152337] = COM_OF_ARGUS, --Brilliant Daybreak Blade
[152338] = COM_OF_ARGUS, --Lustrous Eventide Blade
[152339] = COM_OF_ARGUS, --Brilliant Daybreak Blade
[152340] = COM_OF_ARGUS, --Lustrous Daybreak Greatsword
[152341] = COM_OF_ARGUS, --Lustrous Eventide Greatsword
[152342] = COM_OF_ARGUS, --Lustrous Daybreak Staff
[152343] = COM_OF_ARGUS, --Lustrous Eventide Staff
[172075] = PROMOTION_SHADOWLANDS, --The Eternal Traveler's
[172076] = PROMOTION_SHADOWLANDS,
[172077] = PROMOTION_SHADOWLANDS,
[172078] = PROMOTION_SHADOWLANDS,
[172079] = PROMOTION_SHADOWLANDS,
[172080] = PROMOTION_SHADOWLANDS,
[172081] = PROMOTION_SHADOWLANDS,
[172082] = PROMOTION_SHADOWLANDS,
[172083] = PROMOTION_SHADOWLANDS,
--[134110] = PROMOTION_SHADOWLANDS, --Test
}
local Ensemble_TheChosenDead_ItemIDs = {
142423, 142421, 142422, 142434, 142420, 142433, --Mail
142427, 142425, 142431, 142435, 142426, 142424, --Plate
142419, 142430, 142432, 142417, 142418, 142416, --Leather
142415, 142411, 142410, 142413, 142429, 142414, --Cloth
143355, 143345, 143334, 143354, 143346, 143347,
143356, 143339, 143349, 143342, 143344, 143335,
143353, 143368, 143340, 143337, 143348, 143341,
143343, 143367, 143336, 143352, 143366, 143351,
143360, 143358, 143350, 143361, 143364, 143359,
143338, 143369, 143365, 143363, 143362, 143357,
};
local function BuildSearchTable(table)
if type(table) ~="table" then
return;
end
local newTable = {};
for k, v in pairs(table) do
newTable[v] = true;
end
wipe(table);
return newTable;
end
local HeritageArmorList = BuildSearchTable(HeritageArmorItemIDs);
local Ensemble_TheChosenDead = BuildSearchTable(Ensemble_TheChosenDead_ItemIDs);
--[[
function GetArtifactVisualModID(colorID)
colorID = colorID or 42;
local PRINT = false;
local baseSourceID, baseVisualID, appliedSourceID, appliedVisualID, pendingSourceID, pendingVisualID, hasPendingUndo, hideVisual = C_Transmog.GetSlotVisualInfo(16, 0);
if not appliedSourceID or appliedSourceID == 0 then
appliedSourceID = baseSourceID;
end
local categoryID, visualID, canEnchant, icon, _, itemLink, transmogLink, _ = C_TransmogCollection.GetAppearanceSourceInfo(appliedSourceID)
local sourceInfo = C_TransmogCollection.GetSourceInfo(appliedSourceID)
if sourceInfo and PRINT then
for k, v in pairs(sourceInfo) do
print(k.." "..tostring(v))
end
else
print(sourceInfo.itemModID);
end
itemID = sourceInfo.itemID or 127829;
itemLink = "\124cffe5cc80\124Hitem:".. itemID .."::::::::120::16777472::2:::"..colorID..":::::::::::::\124h[".. (sourceInfo.name or "") .."]\124h\124r"
DEFAULT_CHAT_FRAME:AddMessage(itemLink)
end
--]]
-----Color API------
local mapColors = {
--[0] = { 35, 96, 147}, --default Blue 0.1372, 0.3765, 0.5765
[0] = {78, 78, 78}, --Default Black
[1] = {121, 31, 35}, --Orgrimmar
[2] = { 49, 176, 107}, --Zuldazar
[3] = {187, 161, 134}, --Vol'dun
[4] = { 89, 140, 123}, --Tiragarde Sound
[5] = {127, 164, 114}, --Stormsong
[6] = {156, 165, 153}, --Drustvar
[7] = { 42, 63, 79}, --Halls of Shadow
--[UiMapID] = {r, g, b}
--Shadowlands
[1970] = {137, 218, 247}, --Zereth Mortis
[1670] = {76, 86, 109}, --Oribos
[1533] = {197, 185, 172}, --Bastion
[1707] = {193, 199, 210}, --Elysian Hold
[1708] = {168, 188, 232}, --Sanctum of Binding
[1701] = {57, 66, 154}, --Heart of the Forest
[1565] = {57, 66, 154}, --Ardenweald
[1536] = {25, 97, 85}, --Maldraxxus
[1698] = {25, 97, 85}, --Seat of the Primus
[1525] = {48, 96, 153}, --Revendreth
[1911] = {53, 80, 115}, --Torghast Entrance
[1912] = {53, 80, 115}, --Runecrafter
--Major City--
[84] = {129, 144, 155}, --Stormwind City
[85] = {121, 52, 55}, --Orgrimmar
[86] = {121, 31, 35}, --Orgrimmar - Cleft of Shadow
[463] = {163, 99, 89}, --Echo Isles
[87] = {102, 64, 58}, --Ironforge
[27] = {151, 198, 213}, --Dun Morogh
[469] = {151, 198, 213}, --New Tinkertown
[88] = {115, 140, 113}, --Thunder Bluff
[89] = {121, 31, 35}, --Darnassus R.I.P.
[90] = { 42, 63, 79}, --Undercity
[110] = {172, 58, 54}, --Silvermoon City
[202] = {78, 78, 78}, --Gilneas City
[217] = {78, 78, 78}, --Ruins of Gilneas
[627] = {102, 58, 64}, --Dalaran Broken Isles
[111] = {88, 108, 91}, --Shattrath City
-- TBC --
[107] = {181, 151, 93}, --Nagrand Outland
[109] = {96, 48, 108}, --Netherstorm
[102] = {61, 77, 162}, --Zangarmash
[105] = {123, 104, 80}, --Blade's Edge Mountains
-- MOP --
[378] = {120, 107, 81}, --The Wandering Isle
[371] = { 95, 132, 78}, --The Jade Forrest
[379] = { 90, 119, 156}, --Kun-Lai Summit
-- LEG --
[641] = { 70, 128, 116}, --Val'sharah
-- BFA --
[81] = { 98, 84, 77}, --Silithus
[1473]= {168, 136, 90}, --Chamber of Heart
[1163]= { 89, 140, 123}, --Dazar'alor - The Great Seal
[1164]= { 89, 140, 123}, --Dazar'alor - Hall of Chroniclers
[1165]= { 89, 140, 123}, --Dazar'alor
[862] = { 89, 140, 123}, --Zuldazar
[864] = {187, 161, 134}, --Vol'dun
[863] = {113, 173, 183}, --Nazmir
[895] = { 89, 140, 123}, --Tiragarde Sound
[1161]= { 89, 140, 123}, --Boralus
[942] = {127, 164, 114}, --Stormsong
[896] = {156, 165, 153}, --Drustvar
[1462] = {16, 156, 192}, --Mechagon
[1355] = {41, 74, 127}, --Nazjatar
[249] = {180,149, 121}, --Uldum Normal
[1527] = {180,149, 121}, --Uldum Assault
[390] = {150, 117, 94}, --Eternal Blossoms Normal
[1530] = {150, 117, 94}, --Eternal Blossoms Assault --{105, 71, 156}
["NZ"] = {105, 71, 156}, --During Assault: N'Zoth Purple Skybox
[1580] = {105, 71, 156}, --Ny'alotha - Vision of Destiny
[1581] = {105, 71, 156}, --Ny'alotha - Annex of Prophecy
[1582] = {105, 71, 156}, --Ny'alotha - Ny'alotha
[1590] = {105, 71, 156}, --Ny'alotha - The Hive
[1591] = {105, 71, 156}, --Ny'alotha - Terrace of Desolation
[1592] = {105, 71, 156}, --Ny'alotha - The Ritual Chamber
[1593] = {105, 71, 156}, --Ny'alotha - Twilight Landing
[1594] = {105, 71, 156}, --Ny'alotha - Maw of Gor'ma
[1595] = {105, 71, 156}, --Ny'alotha - Warren of Decay
[1596] = {105, 71, 156}, --Ny'alotha - Chamber of Rebirth
[1597] = {105, 71, 156}, --Ny'alotha - Locus of Infinite Truths
--Allied Race Starting Zone--
[124] = {87, 56, 132}, --DK
[1186] = {117, 26, 22}, --Dark Iron
[971] = {65, 57, 124}, --Void Elf
--Class Hall
[625] = { 42, 63, 79}, --Dalaran, Broken Isles Halls of Shadow
[626] = { 42, 63, 79}, --Hall of Shadow
[715] = {149, 180, 146}, --Emerald Dreamway
[747] = { 70, 128, 116}, --The Dreamgrove
--Frequently Visited
[198] = {78, 78, 78}, --Hyjal
};
NarciThemeUtil = {};
NarciThemeUtil.colorIndex = 0;
function NarciThemeUtil:GetColorTable()
local R, G, B = unpack(mapColors[self.colorIndex]);
return {R/255, G/255, B/255}
end
function NarciThemeUtil:GetColor()
local R, G, B = unpack(mapColors[self.colorIndex]);
return R/255, G/255, B/255
end
function NarciThemeUtil:GetColorIndex()
return self.colorIndex
end
function NarciThemeUtil:SetColorIndex(index)
if index and mapColors[index] then
self.colorIndex = index
else
self.colorIndex = 0;
end
return self:GetColorTable()
end
----------------------------------------------------------------------
local function NarciAPI_ConvertHexColorToRGB(hexColor, includeHex)
local r = tonumber(strsub(hexColor, 1, 2), 16) / 255;
local g = tonumber(strsub(hexColor, 3, 4), 16) / 255;
local b = tonumber(strsub(hexColor, 5, 6), 16) / 255;
if includeHex then
return {r, g, b, hexColor};
else
return {r, g, b};
end
end
local function RGB2HSV(r, g, b)
local Cmax = max(r, g, b);
local Cmin = min(r, g, b);
local dif = Cmax - Cmin;
local Hue = 0;
local Brightness = floor(100*(Cmax / 255) + 0.5)/100;
local Stauration = 0;
if Cmax ~= 0 then Stauration = floor(100*(dif / Cmax)+0.5)/100; end;
if dif ~= 0 then
if r == Cmax and g >= b then
Hue = (g - b) / dif + 0;
elseif r == Cmax and g < b then
Hue = (g - b) / dif + 6;
elseif g == Cmax then
Hue = (b - r) / dif + 2;
elseif b == Cmax then
Hue = (r - g) / dif + 4;
end
end
return floor(60*Hue + 0.5), Stauration, Brightness
end
local function RGBRatio2HSV(r, g, b)
return RGB2HSV(255 * r, 255 * g, 255 * b)
end
local function HSV2RGB(h, s, v)
local Cmax = 255 * v;
local Cmin = Cmax * (1 - s);
local i = floor(h / 60);
local dif = h % 60;
local Cmid = (Cmax - Cmin) * dif / 60;
local r, g, b;
if i == 0 or i == 6 then
r, g, b = Cmax, Cmin + Cmid, Cmin;
elseif i == 1 then
r, g, b = Cmax - Cmid, Cmax, Cmin;
elseif i == 2 then
r, g, b = Cmin, Cmax, Cmin + Cmid;
elseif i == 3 then
r, g, b = Cmin, Cmax - Cmid, Cmax;
elseif i == 4 then
r, g, b = Cmin + Cmid, Cmin, Cmax;
else
r, g, b = Cmax, Cmin, Cmax - Cmid;
end
r, g, b = floor(r + 0.5)/255, floor(g + 0.5)/255, floor(b + 0.5)/255;
return r, g, b
end
NarciAPI.ConvertHexColorToRGB = NarciAPI_ConvertHexColorToRGB;
NarciAPI.RGB2HSV = RGB2HSV;
NarciAPI.RGBRatio2HSV = RGBRatio2HSV;
NarciAPI.HSV2RGB = HSV2RGB;
Narci_FontColor = {
["Brown"] = {0.85098, 0.80392, 0.70588, "|cffd9cdb4"},
["DarkGrey"] = {0.42, 0.42, 0.42, "|cff6b6b6b"},
["LightGrey"] = {0.72, 0.72, 0.72, "|cffb8b8b8"},
["White"] = {0.88, 0.88, 0.88, "|cffe0e0e0"},
["Good"] = {0.4862, 0.7725, 0.4627, "|cff7cc576"},
["Bad"] = {1, 0.3137, 0.3137, 0.3137, "|cffff5050"},
["Corrupt"] = {0.584, 0.428, 0.82, "|cff946dd1"},
};
local customQualityColors= {
[0] = "9d9d9d", --Poor
[1] = "ffffff", --Common
[2] = "1eff00", --Uncommon
[3] = "699eff", --Rare 0070dd 699eff
[4] = "b953ff", --Epic a335ee
[5] = "ff8000", --Legend
[6] = "e6cc80", --Artifact
[7] = "00ccff", --Heirloom
[8] = "00ccff",
[9] = "ffffff",
};
for index, hex in pairs(customQualityColors) do
customQualityColors[index] = NarciAPI_ConvertHexColorToRGB(hex, true);
end
local function GetCustomQualityColor(itemQuality)
if (not itemQuality) or (not customQualityColors[itemQuality]) then
itemQuality = 1;
end
return unpack(customQualityColors[itemQuality]);
end
NarciAPI.GetItemQualityColor = GetCustomQualityColor;
4 years ago
local function GetCustomQualityColorByItemID(itemID)
local itemQuality = C_Item.GetItemQualityByID(itemID);
return GetCustomQualityColor(itemQuality);
end
NarciAPI.GetItemQualityColorByItemID = GetCustomQualityColorByItemID;
NarciAPI.GetItemQualityColorTable = function()
local newTable = {};
4 years ago
for k, v in pairs(customQualityColors) do
newTable[k] = v;
end
return newTable;
end
local gemBorderTexture = {
filePrefix = "Interface/AddOns/Narcissus/Art/GemBorder/Dark/",
[0] = "White", --Empty
[1] = "Primary", --Kraken's Eye
[2] = "Green",
[3] = "Primary", --Prismatic
[4] = "Primary", --Meta
[5] = "Orange", --Orange
[6] = "Purple",
[7] = "Yellow", --Yellow
[8] = "Blue", --Blue
[9] = "Yellow", --Empty
[10] = "Red", --Red
[11] = "White", --Artifact
[12] = "Crystallic",
};
local specialGemBoder = {
[153714] = 10,
[173125] = 10,
[153715] = 2,
[169220] = 2,
[173126] = 2,
[168636] = 1,
[168637] = 1,
[168638] = 1,
[153707] = 1,
[153708] = 1,
[153709] = 1,
[189723] = 12,
[189722] = 12,
[189732] = 12,
[189560] = 12,
[189763] = 12,
[189724] = 12,
[189725] = 12,
[189726] = 12,
[189762] = 12,
[189727] = 12,
[189728] = 12,
[189729] = 12,
[189730] = 12,
[189731] = 12,
[189764] = 12,
[189733] = 12,
[189734] = 12,
[189760] = 12,
[189761] = 12,
[189735] = 12,
};
local function GetGemBorderTexture(itemSubClassID, itemID)
local index = (itemID and specialGemBoder[itemID]) or itemSubClassID or 0;
return gemBorderTexture.filePrefix..gemBorderTexture[index], index
end
local function SetBorderTheme(theme)
--1.1.2 Override
theme = "Dark";
if theme == "Bright" then
gemBorderTexture.filePrefix = "Interface/AddOns/Narcissus/Art/GemBorder/Bright/";
elseif theme == "Dark" then
gemBorderTexture.filePrefix = "Interface/AddOns/Narcissus/Art/GemBorder/Dark/";
end
end
NarciAPI.SetBorderTheme = SetBorderTheme;
NarciAPI.GetGemBorderTexture = GetGemBorderTexture;
--------------------
------Item API------
--------------------
local function GetItemEnchantID(itemLink)
4 years ago
if itemLink then
local _, _, _, linkType, linkID, enchantID = strsplit(":|H", itemLink);
return tonumber(enchantID) or 0;
else
return 0
end
end
NarciAPI.GetItemEnchantID = GetItemEnchantID;
local function IsHeritageArmor(itemID)
if not itemID then
return false;
end
if HeritageArmorList[itemID] then
return true;
else
return false;
end
end
local ITEMSOURCE_SECRETFINDING = Narci.L["Secret Finding"];
local function NarciAPI_IsItemSourceSpecial(itemID, modID)
if not itemID then
return false;
end
if IsHeritageArmor(itemID) then
return true, HERITAGE_ARMOR;
end
local itemSource = SpecialItemList[itemID];
if itemSource ~= nil then
--print("Is Special")
return true, itemSource;
end
if SecretlItemIDs[itemID] then
return true, ITEMSOURCE_SECRETFINDING;
end
if Ensemble_TheChosenDead[itemID] then
return true, "|cFFFFD100"..DUNGEON_FLOOR_HELHEIMRAID1.."|r";
end
return false;
end
NarciAPI.IsItemSourceSpecial = NarciAPI_IsItemSourceSpecial;
local PrimaryStatsList = {
[LE_UNIT_STAT_STRENGTH] = NARCI_STAT_STRENGTH,
[LE_UNIT_STAT_AGILITY] = NARCI_STAT_AGILITY,
[LE_UNIT_STAT_INTELLECT] = NARCI_STAT_INTELLECT,
};
local function NarciAPI_GetPrimaryStats()
--Return name and value
local currentSpec = GetSpecialization() or 1;
local _, _, _, _, _, primaryStat = GetSpecializationInfo(currentSpec);
primaryStat = primaryStat or 1;
local value = UnitStat("player", primaryStat);
local name = PrimaryStatsList[primaryStat];
return name, value;
end
NarciAPI.GetPrimaryStats = NarciAPI_GetPrimaryStats;
local GemInfo = Narci.GemData;
local EnchantInfo = Narci.EnchantData;
local DoesItemExist = C_Item.DoesItemExist;
local GetCurrentItemLevel = C_Item.GetCurrentItemLevel;
local GetItemLink = C_Item.GetItemLink
local GetItemStats = GetItemStats;
local GetItemGem = GetItemGem;
function NarciAPI_GetItemStats(itemLocation)
local statsTable = {};
statsTable.gems = 0;
if not itemLocation or not DoesItemExist(itemLocation) then
statsTable.prim = 0;
statsTable.stamina = 0;
statsTable.crit = 0;
statsTable.haste = 0;
statsTable.mastery = 0;
statsTable.versatility = 0;
statsTable.corruption = 0;
statsTable.GemIcon = "";
statsTable.GemPos = "";
statsTable.EnchantPos = "";
statsTable.EnchantSpellID = nil;
statsTable.ilvl = 0;
return statsTable;
end
local ItemLevel = GetCurrentItemLevel(itemLocation)
local itemLink = GetItemLink(itemLocation)
local stats = GetItemStats(itemLink) or {};
local prim = stats["ITEM_MOD_AGILITY_SHORT"] or stats["ITEM_MOD_STRENGTH_SHORT"] or stats["ITEM_MOD_INTELLECT_SHORT"] or 0;
local stamina = stats["ITEM_MOD_STAMINA_SHORT"] or 0;
local crit = stats["ITEM_MOD_CRIT_RATING_SHORT"] or 0;
local haste = stats["ITEM_MOD_HASTE_RATING_SHORT"] or 0;
local mastery = stats["ITEM_MOD_MASTERY_RATING_SHORT"] or 0;
local versatility = stats["ITEM_MOD_VERSATILITY"] or 0;
local corruption = stats["ITEM_MOD_CORRUPTION"] or 0;
statsTable.prim = prim;
statsTable.stamina = stamina;
statsTable.crit = crit;
statsTable.haste = haste;
statsTable.mastery = mastery;
statsTable.versatility = versatility;
statsTable.corruption = corruption;
statsTable.ilvl = ItemLevel;
--Calculate bonus from Gems and Enchants--
local gemIndex = 1; --BFA 1 gem for each item.
4 years ago
local gemName, gemLink = GetItemGem(itemLink, gemIndex);
if gemLink then
local gemID = GetItemInfoInstant(gemLink);
local _, _, _, _, GemIcon, _, itemSubClassID = GetItemInfoInstant(gemLink);
statsTable.GemIcon = GemIcon
statsTable.gems = 1;
if GemInfo[gemID] then
local info = GemInfo[gemID]
statsTable.GemPos = GemInfo[1];
4 years ago
if info[1] == "crit" then
statsTable.crit = statsTable.crit + info[2];
elseif info[1] == "haste" then
statsTable.haste = statsTable.haste + info[2];
elseif info[1] == "mastery" then
statsTable.mastery = statsTable.mastery + info[2];
elseif info[1] == "versatility" then
statsTable.versatility = statsTable.versatility + info[2];
elseif info[1] == "AGI" or info[1] == "STR" or info[1] == "INT" then
statsTable.prim = statsTable.prim + info[2];
statsTable.GemPos = "prim";
end
end
end
local enchantID = GetItemEnchantID(itemLink);
if enchantID ~= 0 and EnchantInfo[enchantID] then
local data = EnchantInfo[enchantID]
statsTable.EnchantPos = data[1];
if data[1] == "crit" then
statsTable.crit = statsTable.crit + data[2];
elseif data[1] == "haste" then
statsTable.haste = statsTable.haste + data[2];
elseif data[1] == "mastery" then
statsTable.mastery = statsTable.mastery + data[2];
elseif data[1] == "versatility" then
statsTable.versatility = statsTable.versatility + data[2];
elseif data[1] == "AGI" or data[1] == "STR" or data[1] == "INT" then
statsTable.prim = statsTable.prim + data[2];
statsTable.EnchantPos = "prim";
4 years ago
elseif data[1] == "stamina" then
statsTable.stamina = statsTable.stamina + data[2];
statsTable.EnchantPos = "stamina";
end
statsTable.EnchantSpellID = data[3];
end
return statsTable;
end
function NarciAPI_GetItemStatsFromSlot(slotID)
local itemLocation = ItemLocation:CreateFromEquipmentSlot(slotID);
local itemLink = C_Item.GetItemLink(itemLocation)
return GetItemStats(itemLink);
end
4 years ago
local function GetItemBagPosition(itemID)
for bagID = 0, (NUM_BAG_SLOTS or 4) do
for slotID = 1, GetContainerNumSlots(bagID) do
if(GetContainerItemID(bagID, slotID) == itemID) then
return bagID, slotID
end
end
end
end
NarciAPI.GetItemBagPosition = GetItemBagPosition;
--------------------
---Formating API----
--------------------
local function NarciAPI_FormatLargeNumbers(value)
value = tonumber(value) or 0;
local formatedNumber = ""
if value >= 1000 and value < 1000000 then
formatedNumber = strsub(value, 1, -4) .. "," .. strsub(value, -3);
elseif value >= 1000000 and value < 1000000000 then
formatedNumber = strsub(value, 1, -7) .. "," .. strsub(value, -6, -4) .. "," .. strsub(value, -3);
else
formatedNumber = tostring(value)
end
return formatedNumber
end
NarciAPI.FormatLargeNumbers = NarciAPI_FormatLargeNumbers;
local RemoveTextBeforeColon;
if TEXT_LOCALE == "zhCN" or TEXT_LOCALE == "zhTW" then
function RemoveTextBeforeColon(text)
if string.find(text, ": ") then
return string.match(text, ": (.+)");
elseif string.find(text, "") then
return string.match(text, ":(.+)");
else
return text
end
end
else
function RemoveTextBeforeColon(text)
return string.gsub(text, "^.+[:]%s*", "");
end
end
NarciAPI.RemoveTextBeforeColon = RemoveTextBeforeColon;
--------------------
---Fade Frame API---
--------------------
local function SetFade_finishedFunc(frame)
if frame.fadeInfo.mode == "OUT" then
frame:Hide();
elseif frame.fadeInfo.mode == "IN" then
frame:Show();
end
end
function NarciAPI_FadeFrame(frame, time, mode)
if mode == "IN" then
UIFrameFadeIn(frame, time, frame:GetAlpha(), 1);
elseif mode == "OUT" then
if not frame:IsShown() then
return;
end
UIFrameFadeOut(frame, time, frame:GetAlpha(), 0);
elseif mode == "Forced_IN" then
UIFrameFadeIn(frame, time, 0, 1);
elseif mode == "Forced_OUT" then
UIFrameFadeOut(frame, time, 1, 0);
end
if not frame.fadeInfo then
return;
end
frame.fadeInfo.finishedArg1 = frame;
frame.fadeInfo.finishedFunc = SetFade_finishedFunc
end
------------------------------------------------------------------
--------------------
---UI Element API---
--------------------
NarciUIMixin = {};
function NarciUIMixin:Highlight(state)
if state then
self.Border.Highlight:SetAlpha(1);
self.Border.Normal:SetAlpha(0);
else
self.Border.Highlight:SetAlpha(0);
self.Border.Normal:SetAlpha(1);
end
end
function NarciUIMixin:SetColor(r, g, b)
if self.Color then
self.Color:SetColorTexture(r/255, g/255, b/255);
end
end
local SCREEN_WIDTH, SCREEN_HEIGHT = GetPhysicalScreenSize();
local function GetPixelForWidget(widget, pixelSize)
4 years ago
local scale = widget:GetEffectiveScale();
if pixelSize then
return pixelSize * (768/SCREEN_HEIGHT)/scale
else
return (768/SCREEN_HEIGHT)/scale
end
end
NarciAPI.GetPixelForWidget = GetPixelForWidget;
local function GetPixelByScale(scale, pixelSize)
if pixelSize then
return pixelSize * (768/SCREEN_HEIGHT)/scale
else
return (768/SCREEN_HEIGHT)/scale
end
4 years ago
end
NarciAPI.GetPixelByScale = GetPixelByScale;
function NarciAPI_OptimizeBorderThickness(self)
if not self.HasOptimized then
local point, relativeTo, relativePoint, xOfs, yOfs = self:GetPoint()
local uiScale = self:GetEffectiveScale();
local rate = (768/SCREEN_HEIGHT)/uiScale;
local borderWeight = 2.0;
local weight = borderWeight * rate;
local weight2 = weight * math.sqrt(2);
self.Border:SetPoint("TOPLEFT", self, "TOPLEFT", weight, -weight)
self.Border:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -weight, weight)
if self.ThumbBorder then
self.ThumbBorder:SetPoint("TOPLEFT", self.VirtualThumb, -weight2, weight2)
self.ThumbBorder:SetPoint("BOTTOMRIGHT", self.VirtualThumb,weight2, -weight2)
end
if self.Marks then
for i=1, #self.Marks do
self.Marks[i]:SetWidth(weight);
end
end
self.HasOptimized = true;
end
end
function NarciAPI_SliderWithSteps_OnLoad(self)
self.oldValue = -1208;
self.Marks = {};
local width = self:GetWidth();
local step = self:GetValueStep();
local sliderMin, sliderMax = self:GetMinMaxValues();
local range = sliderMax - sliderMin;
local num_Gap = floor((range / step) + 0.5);
if num_Gap == 0 then return; end;
local tex;
local markOffset = 5;
4 years ago
width = width - 2*markOffset;
local pixel = GetPixelForWidget(self);
for i = 1, (num_Gap + 1) do
tex = self:CreateTexture(nil, "BACKGROUND", nil, 1);
4 years ago
tex:SetSize(2*pixel, 20*pixel);
tex:SetColorTexture(0.25, 0.25, 0.25);
tex:SetPoint("CENTER", self, "LEFT", markOffset + (i-1)*width/num_Gap, 0);
tinsert(self.Marks, tex);
end
--self.VirtualThumb:SetTexture("Interface/AddOns/Narcissus/Art/BasicShapes/Diamond", nil, nil, "TRILINEAR");
end
-----Smooth Scroll-----
local function SmoothScrollContainer_OnUpdate(self, elapsed)
local value = self.scrollBar:GetValue();
local step = max(abs(value - self.endValue)*(self.speedRatio)*(elapsed*60) , self.minOffset); --if the step (Δy) is too small, the fontstring will jitter. --Consider elapsed -- scroll duration should be constant regardless of FPS
local remainedStep;
if ( self.delta == 1 ) then
--Up
remainedStep = min(self.endValue - value, 0);
if - remainedStep <= ( self.minOffset) then
self:Hide();
self.scrollBar:SetValue(min(self.maxVal, self.endValue));
if self.onScrollFinishedFunc then
self.onScrollFinishedFunc();
end
else
self.scrollBar:SetValue(max(0, value - step));
end
else
remainedStep = max(self.endValue - value, 0);
if remainedStep <= ( self.minOffset) then
self:Hide();
self.scrollBar:SetValue(min(self.maxVal, self.endValue));
if self.onScrollFinishedFunc then
self.onScrollFinishedFunc();
end
else
self.scrollBar:SetValue(min(self.maxVal, value + step));
end
end
end
local function NarciAPI_SmoothScroll_OnMouseWheel(self, delta, stepSize)
if ( not self.scrollBar:IsVisible() ) then
if self.parentScrollFunc then
self.parentScrollFunc(delta);
else
return;
end
end
4 years ago
local ScrollContainer = self.SmoothScrollContainer;
stepSize = stepSize or self.stepSize or self.buttonHeight;
ScrollContainer.stepSize = stepSize;
ScrollContainer.maxVal = self.range;
--self.scrollBar:SetValueStep(0.01);
ScrollContainer.delta = delta;
local current = self.scrollBar:GetValue();
if not((current <= 0.1 and delta > 0) or (current >= self.range - 0.1 and delta < 0 )) then
ScrollContainer:Show()
else
return;
end
local deltaRatio = ScrollContainer.deltaRatio or 1;
if IsShiftKeyDown() then
deltaRatio = 2 * deltaRatio;
end
local endValue = floor( (100 * min(max(0, ScrollContainer.endValue - delta*deltaRatio*self.buttonHeight), self.range) + 0.5)/100 );
ScrollContainer.endValue = endValue;
if self.positionFunc then
local isTop = endValue <= 0.1;
local isBottom = endValue >= self.range - 1;
self.positionFunc(endValue, delta, self.scrollBar, isTop, isBottom);
end
end
local function SetScrollRange(scrollFrame, range)
range = max(range, 0);
scrollFrame.scrollBar:SetMinMaxValues(0, range);
scrollFrame.scrollBar:SetShown(range ~= 0);
scrollFrame.range = range;
end
function NarciAPI_SmoothScroll_Initialization(scrollFrame, updatedList, updateFunc, deltaRatio, speedRatio, minOffset, positionFunc, onScrollFinishedFunc)
if updateFunc then
scrollFrame.update = updateFunc;
end
if positionFunc then
scrollFrame.positionFunc = positionFunc;
end
if updatedList then
scrollFrame.updatedList = updatedList;
end
local parentName = scrollFrame:GetName();
local frameName = parentName and (parentName .. "SmoothScrollContainer") or nil;
local SmoothScrollContainer = CreateFrame("Frame", frameName, scrollFrame);
SmoothScrollContainer:Hide();
--local scale = match(GetCVar( "gxWindowedResolution" ), "%d+x(%d+)" );
local uiScale = scrollFrame:GetEffectiveScale();
local pixel = (768/SCREEN_HEIGHT)/uiScale;
local scrollBar = scrollFrame.scrollBar;
scrollBar:SetValue(0);
scrollBar:SetValueStep(0.001);
SmoothScrollContainer.stepSize = 0;
SmoothScrollContainer.delta = 0;
SmoothScrollContainer.animationDuration = 0;
SmoothScrollContainer.endValue = 0;
SmoothScrollContainer.maxVal = 0;
SmoothScrollContainer.deltaRatio = deltaRatio or 1;
SmoothScrollContainer.speedRatio = speedRatio or 0.5;
SmoothScrollContainer.minOffset = minOffset or pixel;
SmoothScrollContainer.scrollBar = scrollFrame.scrollBar;
SmoothScrollContainer:SetScript("OnUpdate", SmoothScrollContainer_OnUpdate);
SmoothScrollContainer:SetScript("OnShow", function(self)
self.endValue = self:GetParent().scrollBar:GetValue();
end);
SmoothScrollContainer:SetScript("OnHide", function(self)
self:Hide();
end);
scrollFrame.SmoothScrollContainer = SmoothScrollContainer;
scrollFrame:SetScript("OnMouseWheel", NarciAPI_SmoothScroll_OnMouseWheel); --a position-related function
if onScrollFinishedFunc then
SmoothScrollContainer.onScrollFinishedFunc = onScrollFinishedFunc;
end
scrollFrame.SetScrollRange = SetScrollRange;
end
function NarciAPI_ApplySmoothScrollToScrollFrame(scrollFrame, deltaRatio, speedRatio, positionFunc, buttonHeight, range, parentScrollFunc, onScrollFinishedFunc)
scrollFrame.buttonHeight = buttonHeight or floor(scrollFrame:GetHeight() + 0.5);
scrollFrame.range = range or 0;
scrollFrame.scrollBar:SetMinMaxValues(0, range or 0)
scrollFrame.scrollBar:SetScript("OnValueChanged", function(self, value)
scrollFrame:SetVerticalScroll(value);
if self.onValueChangedFunc then
self.onValueChangedFunc(value);
end
end)
NarciAPI_SmoothScroll_Initialization(scrollFrame, nil, nil, deltaRatio, speedRatio, nil, positionFunc, onScrollFinishedFunc);
scrollFrame.parentScrollFunc = parentScrollFunc;
end
function NarciAPI_ApplySmoothScrollToBlizzardUI(scrollFrame, deltaRatio, speedRatio, positionFunc)
NarciAPI_SmoothScroll_Initialization(scrollFrame, nil, nil, deltaRatio, speedRatio, nil, positionFunc);
end
-----Create A List of Button----
--[[
function NarciAPI_BuildButtonList(self, buttonTemplate, buttonNameTable, initialOffsetX, initialOffsetY, initialPoint, initialRelative, offsetX, offsetY, point, relativePoint)
local button, buttonHeight, buttons, numButtons;
local parentName = self:GetName();
local buttonName = parentName and (parentName .. "Button") or nil;
initialPoint = initialPoint or "TOPLEFT";
initialRelative = initialRelative or "TOPLEFT";
initialOffsetX = initialOffsetX or 0;
initialOffsetY = initialOffsetY or 0;
point = point or "TOPLEFT";
relativePoint = relativePoint or "BOTTOMLEFT";
offsetX = offsetX or 0;
offsetY = offsetY or 0;
if ( self.buttons ) then
buttons = self.buttons;
buttonHeight = buttons[1]:GetHeight();
else
button = CreateFrame("BUTTON", buttonName and (buttonName .. 1) or nil, self, buttonTemplate);
buttonHeight = button:GetHeight();
button:SetPoint(initialPoint, self, initialRelative, initialOffsetX, initialOffsetY);
button:SetID(0);
buttons = {}
button.Name:SetText(buttonNameTable[1])
tinsert(buttons, button);
end
local numButtons = #buttonNameTable;
for i = 2, numButtons do
button = CreateFrame("BUTTON", buttonName and (buttonName .. i) or nil, self, buttonTemplate);
button:SetPoint(point, buttons[i-1], relativePoint, offsetX, offsetY);
button:SetID(i-1);
button.Name:SetText(buttonNameTable[i])
tinsert(buttons, button);
end
self.buttons = buttons;
end
--]]
-----Language Adaptor-----
4 years ago
local function LanguageDetector(str)
local len = string.len(str)
local i = 1
while i <= len do
local c = string.byte(str, i)
local shift = 1
if (c > 0 and c <= 127)then
shift = 1
elseif c == 195 then
shift = 2 --Latin/Greek
elseif (c >= 208 and c <=211) then
shift = 2
return "RU" --RU included
elseif (c >= 224 and c <= 227) then
shift = 3 --JP
return "JP"
elseif (c >= 228 and c <= 233) then
shift = 3 --CN
return "CN"
elseif (c >= 234 and c <= 237) then
shift = 3 --KR
return "KR"
elseif (c >= 240 and c <= 244) then
shift = 4 --Unknown invalid
end
i = i + shift
end
return "RM"
end
local function GetFirstLetterLanguage(str)
local c = string.byte(str, 1);
if (c > 0 and c <= 127)then
return "RM"
elseif c == 195 then
return "RM" --Latin/Greek
elseif (c >= 208 and c <=211) then
return "RU"
elseif (c >= 224 and c <= 227) then
return "JP"
elseif (c >= 228 and c <= 233) then
return "CN"
elseif (c >= 234 and c <= 237) then
return "KR"
elseif (c >= 240 and c <= 244) then
return "CN" --Unknown invalid
end
end
NarciAPI.LanguageDetector = LanguageDetector;
--[[
function LDTest(string)
local str = string
local lenInByte = #str
for i=1,lenInByte do
local char = strsub(str, i,i)
local curByte = string.byte(str, i)
print(char.." "..curByte)
end
return "roman"
end
local Eng = "abcdefghijklmnopqrstuvwxyz" --abcdefghijklmnopqrstuvwxyz Z~90 z~122 1-1
local DE = "äöüß" --195 1-2
local CN = "乀氺" --228 229 230 233 HEX E4-E9 Hexadecimal UTF-8 CJK
local KR = "" --237 236 235 234 1-3 EB-ED
local RU = "ѱӧ" --D0400-D04C0 208 209 210 211 1-2
local FR = "ÀÃÇÊÉÕàãçêõáéíóúà" --1-2 195 C3 -PR
local JP = "ひらがな" --1-3 227 E3 Kana
--LDTest("繁體繁体")
--local language = LanguageDetector("繁體中文")
--print("Str is: "..language)
--]]
local PlayerNameFont = {
["CN"] = "Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf",
["RM"] = "Interface\\AddOns\\Narcissus\\Font\\SemplicitaPro-Semibold.otf",
["RU"] = "Interface\\AddOns\\Narcissus\\Font\\NotoSans-Medium.ttf",
["KR"] = "Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf",
["JP"] = "Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf",
}
local EditBoxFont = {
["CN"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf", 8},
["RM"] = {"Interface\\AddOns\\Narcissus\\Font\\SourceSansPro-Semibold.ttf", 9},
["RU"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSans-Medium.ttf", 8},
["KR"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf", 8},
["JP"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf", 8},
}
4 years ago
local NormalFont12 = {
["CN"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf", 11},
["RM"] = {"Interface\\AddOns\\Narcissus\\Font\\SourceSansPro-Semibold.ttf", 12},
["RU"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSans-Medium.ttf", 11},
["KR"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf", 11},
["JP"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf", 11},
}
local ActorNameFont = {
["CN"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf", 8},
["RM"] = {"Interface\\AddOns\\Narcissus\\Font\\SourceSansPro-Semibold.ttf", 9},
["RU"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSans-Medium.ttf", 8},
["KR"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf", 8},
["JP"] = {"Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf", 8},
}
local function SmartSetActorName(fontstring, text)
--Automatically apply different font based on given text languange. Change text color after this step.
if not fontstring then return; end;
fontstring:SetText(text);
local language = GetFirstLetterLanguage(text);
if language and ActorNameFont[language] then
fontstring:SetFont(ActorNameFont[language][1] , ActorNameFont[language][2]);
end
end
4 years ago
local function SmartFontType(self, fontTable)
local str = self:GetText();
4 years ago
local language = LanguageDetector(str);
--print(str.." Language is: "..Language);
4 years ago
local height = self:GetHeight();
if language and fontTable[language] then
self:SetFont(fontTable[language] , height);
end
end
local function SmartEditBoxFont(self, extraHeight)
local str = self:GetText();
4 years ago
local language = LanguageDetector(str);
if language and EditBoxFont[language] then
local height = extraHeight or 0;
4 years ago
self:SetFont(EditBoxFont[language][1] , EditBoxFont[language][2] + height);
end
end
4 years ago
local function NarciAPI_SmartFontType(fontString)
SmartFontType(fontString, PlayerNameFont);
end
local function SmartSetName(fontString, str)
local language = LanguageDetector(str);
if language and NormalFont12[language] then
fontString:SetFont(NormalFont12[language][1], NormalFont12[language][2]);
end
fontString:SetText(str);
end
NarciAPI.SmartSetActorName = SmartSetActorName;
NarciAPI.SmartFontType = NarciAPI_SmartFontType;
4 years ago
NarciAPI.SmartSetName = SmartSetName;
function NarciAPI_SmartEditBoxType(self, isUserInput, extraHeight)
SmartEditBoxFont(self, extraHeight);
end
--[[
function NarciAPI_EditBox_OnLanguageChanged(self, language)
SmartEditBoxFont(self);
end
--]]
-----Filter Shared Functions-----
function NarciAPI_LetterboxAnimation(command)
local frame = Narci_FullScreenMask;
frame:StopAnimating();
if command == "IN" then
frame:Show();
frame.BottomMask.animIn:Play();
frame.TopMask.animIn:Play();
elseif command == "OUT" then
frame.BottomMask.animOut:Play();
frame.TopMask.animOut:Play();
else
if NarcissusDB.LetterboxEffect then
frame:Show();
frame.BottomMask.animIn:Play();
frame.TopMask.animIn:Play();
end
end
end
-----Format Normalization-----
local function SplitTooltipByLineBreak(str)
local str1, _, str2 = strsplit("\n", str);
return str1 or "", str2 or "";
end
NARCI_CRIT_TOOLTIP, NARCI_CRIT_TOOLTIP_FORMAT = SplitTooltipByLineBreak(CR_CRIT_TOOLTIP);
_, NARCI_HASTE_TOOLTIP_FORMAT = SplitTooltipByLineBreak(STAT_HASTE_BASE_TOOLTIP);
NARCI_VERSATILITY_TOOLTIP_FORMAT_1, NARCI_VERSATILITY_TOOLTIP_FORMAT_2 = SplitTooltipByLineBreak(CR_VERSATILITY_TOOLTIP);
-----Delayed Tooltip-----
local DelayedTP = CreateFrame("Frame");
DelayedTP:Hide();
DelayedTP:SetScript("OnShow", function(self)
self.t = 0; --Total time after ShowDelayedTooltip gets called
--self.ScanTime = 0; --Cursor scanning time
--self.CursorX, self.CursorY = GetCursorPosition(); --Cursor position
end)
DelayedTP:SetScript("OnHide", function(self)
self.t = 0;
--self.ScanTime = 0;
end)
DelayedTP:SetScript("OnUpdate", function(self, elapsed)
self.t = self.t + elapsed;
--self.ScanTime = self.ScanTime + elapsed;
if self.t >= 0.6 then
if self.focus and self.focus == GetMouseFocus() then
NarciGameTooltip:ClearAllPoints();
NarciGameTooltip:SetPoint(self.point, self.relativeTo, self.relativePoint, self.ofsx, self.ofsy);
FadeFrame(NarciGameTooltip, 0.15, 1, 0);
self.focus = nil;
end
self:Hide();
end
end)
function NarciAPI_ShowDelayedTooltip(point, relativeTo, relativePoint, ofsx, ofsy)
local tp = DelayedTP;
tp:Hide();
if point then
tp.focus = GetMouseFocus();
tp.point, tp.relativeTo, tp.relativePoint, tp.ofsx, tp.ofsy = point, relativeTo, relativePoint, ofsx, ofsy;
tp:Show();
else
tp.focus = nil;
FadeFrame(NarciGameTooltip, 0, 0);
end
end
-----Run Delayed Function-----
local DelayedFunc = CreateFrame("Frame");
DelayedFunc:Hide();
DelayedFunc.delay = 0;
DelayedFunc.t = 0;
DelayedFunc:SetScript("OnHide", function(self)
self.focus = nil;
self.t = 0;
end)
DelayedFunc:SetScript("OnUpdate", function(self, elapsed)
self.t = self.t + elapsed;
if self.t >= self.delay then
if self.focus == GetMouseFocus() then
self.func();
end
self:Hide();
end
end)
function NarciAPI_RunDelayedFunction(frame, delay, func)
DelayedFunc:Hide();
if func and type(func) == "function" then
delay = delay or 0;
DelayedFunc.focus = frame;
DelayedFunc.delay = delay;
DelayedFunc.func = func;
DelayedFunc:Show();
end
end
-----Alert Frame-----
if BackdropTemplateMixin then
NarciAlertFrameMixin = CreateFromMixins(BackdropTemplateMixin);
else
NarciAlertFrameMixin = {};
end
function NarciAlertFrameMixin:AddShakeAnimation(frame)
if frame.animError then return; end;
local ag = frame:CreateAnimationGroup();
local a1 = ag:CreateAnimation("Translation");
a1:SetOrder(1);
a1:SetOffset(4, 0);
a1:SetDuration(0.05);
local a2 = ag:CreateAnimation("Translation");
a2:SetOrder(2);
a2:SetOffset(-8, 0);
a2:SetDuration(0.1);
local a3 = ag:CreateAnimation("Translation");
a3:SetOrder(3);
a3:SetOffset(8, 0);
a3:SetDuration(0.1);
local a4 = ag:CreateAnimation("Translation");
a4:SetOrder(4);
a4:SetOffset(-4, 0);
a4:SetDuration(0.05);
ag:SetScript("OnPlay", function()
PlaySound(138528); --Mechagon_HK8_Lockon
end);
frame.animError = ag;
end
function NarciAlertFrameMixin:SetAnchor(frame, offsetY, AddErrorAnimation)
if frame.RegisterErrorEvent then
frame:RegisterErrorEvent();
After(0.5, function()
frame:UnregisterErrorEvent();
end)
else
frame:RegisterEvent("UI_ERROR_MESSAGE");
After(0.5, function()
frame:UnregisterEvent("UI_ERROR_MESSAGE");
end)
end
self:Hide();
self:ClearAllPoints();
self:SetScale(Narci_Character:GetEffectiveScale())
local y = offsetY or -12;
self:SetPoint("BOTTOM", frame, "TOP", 0, y);
self:SetFrameLevel(50)
self.anchor = frame;
if AddErrorAnimation then
self:AddShakeAnimation(frame);
end
end
function NarciAlertFrameMixin:AddMessage(msg, UseErrorAnimation)
self.Text:SetText(msg);
self:SetHeight(self.Background:GetHeight());
FadeFrame(self, 0.2, 1);
local anchorFrame = self.anchor;
if anchorFrame then
if anchorFrame.animError and UseErrorAnimation then
anchorFrame.animError:Play();
end
anchorFrame:UnregisterEvent("UI_ERROR_MESSAGE");
end
end
------------------------
--Filled Bar Animation--
------------------------
--Corruption Bar
--[[
local cos = math.cos;
local pi = math.pi;
local function inOutSine(t, b, c, d)
return -c / 2 * (cos(pi * t / d) - 1) + b
end
local FluidAnim = CreateFrame("Frame");
FluidAnim:Hide();
FluidAnim.d = 0.5;
FluidAnim.d1 = 0.25;
FluidAnim.d2 = 0.5;
local function FluidLevel(self, elapsed)
self.t = self.t + elapsed;
local height = inOutSine(self.t, self.startHeight, self.endHeight - self.startHeight, self.d);
if self.t >= self.d then
height = self.endHeight;
self:Hide();
end
self.Fluid:SetHeight(height);
end
local function FluidUp(self, elapsed)
self.t = self.t + elapsed;
local height;
if self.t <= self.d1 then
height = inOutSine(self.t, self.startHeight, 84 - self.startHeight, self.d1);
elseif self.t < self.d3 then
if not self.colorChanged then
self.colorChanged = true;
self.Fluid:SetColorTexture(self.r, self.g, self.b);
end
height = inOutSine(self.t - self.d1, 0.01, self.endHeight, self.d2);
else
height = self.endHeight;
self:Hide();
end
self.Fluid:SetHeight(height);
end
local function FluidDown(self, elapsed)
self.t = self.t + elapsed;
local height;
if self.t <= self.d1 then
height = inOutSine(self.t, self.startHeight, 0.01 - self.startHeight, self.d1);
elseif self.t < self.d3 then
if not self.colorChanged then
self.colorChanged = true;
self.Fluid:SetColorTexture(self.r, self.g, self.b);
end
height = inOutSine(self.t - self.d1, 84, self.endHeight - 84, self.d2);
else
height = self.endHeight;
self:Hide();
end
self.Fluid:SetHeight(height);
end
FluidAnim:SetScript("OnShow", function(self)
self.t = 0;
self.colorChanged = false;
end);
function NarciAPI_SmoothFluid(bar, newHeight, newLevel, r, g, b)
local FluidAnim = FluidAnim;
FluidAnim:Hide();
FluidAnim.endHeight = newHeight;
FluidAnim.Fluid = bar;
FluidAnim.r, FluidAnim.g, FluidAnim.b = r, g, b;
local oldLevel = FluidAnim.oldCorruptionLevel or newLevel;
FluidAnim.oldCorruptionLevel = newLevel;
local t1, t2;
local h = FluidAnim.Fluid:GetHeight();
FluidAnim.startHeight = h;
if newLevel == oldLevel then
FluidAnim:SetScript("OnUpdate", FluidLevel);
FluidAnim.d = max( abs(h - FluidAnim.endHeight) / 84 , 0.35);
bar:SetColorTexture(r, g, b);
elseif newLevel < oldLevel then
FluidAnim:SetScript("OnUpdate", FluidDown);
t1 = math.max(h / 84, 0);
t2 = math.max((84 - FluidAnim.endHeight) / 84, 0.4);
FluidAnim.d1 = t1
FluidAnim.d2 = t2
FluidAnim.d3 = t1 + t2;
else
FluidAnim:SetScript("OnUpdate", FluidUp);
t1 = math.max((84 - h) / 84, 0);
t2 = math.max(FluidAnim.endHeight / 84, 0.4);
FluidAnim.d1 = t1
FluidAnim.d2 = t2
FluidAnim.d3 = t1 + t2;
end
After(0, function()
FluidAnim:Show();
end)
return t1
end
local EyeballTexture = "Interface\\AddOns\\Narcissus\\ART\\Widgets\\CorruptionSystem\\Eyeball-Orange";
local CorruptionColor = "|cfff57f20";
local FluidColors = {0.847, 0.349, 0.145};
function NarciAPI_GetEyeballColor()
return EyeballTexture, CorruptionColor, FluidColors[1], FluidColors[2], FluidColors[3];
end
function NarciAPI_SetEyeballColor(index)
if index == 4 then
EyeballTexture = "Interface\\AddOns\\Narcissus\\ART\\Widgets\\CorruptionSystem\\Eyeball-Blue";
CorruptionColor = "|cff83c7e7";
FluidColors = {0.596, 0.73, 0.902};
elseif index == 2 then
EyeballTexture = "Interface\\AddOns\\Narcissus\\ART\\Widgets\\CorruptionSystem\\Eyeball-Purple";
CorruptionColor = "|cfff019ff";
FluidColors = {0.87, 0.106, 0.949};
elseif index == 3 then
EyeballTexture = "Interface\\AddOns\\Narcissus\\ART\\Widgets\\CorruptionSystem\\Eyeball-Green";
CorruptionColor = "|cff8cdacd";
FluidColors = {0.56, 0.855, 0.757};
else
index = 1;
EyeballTexture = "Interface\\AddOns\\Narcissus\\ART\\Widgets\\CorruptionSystem\\Eyeball-Orange";
CorruptionColor = "|cfff57f20";
FluidColors = {0.847, 0.349, 0.145};
end
NarcissusDB.EyeColor = index;
local Preview = Narci_EyeColorPreview;
local ColorButtons = Preview:GetParent().ColorButtons;
Preview:SetTexCoord(0.25*(index - 1), 0.25*index, 0, 1);
for i = 1, #ColorButtons do
--ColorButtons[i]Highlight(false);
end
--ColorButtons[index]:Highlight(true);
Narci:SetItemLevel();
end
--]]
--------------------
--UI 3D Animation---
--------------------
Narci.AnimSequenceInfo =
{ ["Controller"] = {
["TotalFrames"] = 30,
["cX"] = 0.205078125,
["cY"] = 0.1171875,
["Column"] = 4,
["Row"] = 8,
},
["Heart"] = {
["TotalFrames"] = 28,
["cX"] = 0.25,
["cY"] = 0.140625,
["Column"] = 4,
["Row"] = 7,
},
["ActorPanel"] = {
["TotalFrames"] = 26,
["cX"] = 0.4296875,
["cY"] = 0.056640625,
["Column"] = 2,
["Row"] = 17,
},
}
function NarciAPI_PlayAnimationSequence(index, SequenceInfo, Texture)
local Frames = SequenceInfo["TotalFrames"];
local cX, cY = SequenceInfo["cX"], SequenceInfo["cY"];
local col, row = SequenceInfo["Column"], SequenceInfo["Row"]
if index > Frames or index < 1 then
return false;
end
local n = math.modf((index -1)/ row) + 1;
local m = index % row
if m == 0 then
m = row;
end
local left, right = (n-1)*cX, n*cX;
local top, bottom = (m-1)*cY, m*cY;
Texture:SetTexCoord(left, right, top, bottom);
Texture:SetAlpha(1);
Texture:Show();
return true;
end
--------------------
-----Play Voice-----
--------------------
local _, _, raceID = UnitRace("player");
local genderID = UnitSex("player") or 2;
raceID = raceID or 1;
genderID = genderID - 1; --(2→1) Male (3→2) Female
if raceID == 25 or raceID == 26 then
--Pandaren faction
raceID = 24;
end
local VOICE_BY_RACE = {
--[raceID] = { [gender] = {Error_NoTarget, } }
[1] = {[1] = {1906, 2669, },
[2] = {2030, 2681, }}, --1 Human
[2] = {[1] = {2317, 2693, },
[2] = {2372, 2705, }}, --2 Orc
[3] = {[1] = {1614, 2717, },
[2] = {1684, 2729, }}, --3 Dwarf
[4] = {[1] = {56231, 56311, },
[2] = {56096, 56174, }}, --4 NE
[5] = {[1] = {2085, 2765, },
[2] = {2205, 2777, }}, --5 UD
[6] = {[1] = {2459, 2789, },
[2] = {2458, 2802, }}, --6 Tauren
[7] = {[1] = {1741, 2827, },
[2] = {1796, 2839, }}, --7 Gnome
[8] = {[1] = {1851, 2851, },
[2] = {1961, 2863, }}, --8 Troll
[9] = {[1] = {19109, 19137, },
[2] = {19218, 19246}}, --9 Goblin
[10] = {[1] = {9597, 9664, },
[2] = {9598, 9624, }}, --10 BloodElf
[11] = {[1] = {9463, 9714, },
[2] = {9514, 9689, }}, --11 Goat
[22] = {[1] = {18991, 19346, },
[2] = {18719, 19516, }}, --22 Worgen
[24] = {[1] = {28846, 28924, },
[2] = {29899, 29812, }}, --24 Pandaren
[27] = {[1] = {96356, 96383, },
[2] = {96288, 96315, }}, --27 Nightborne
[28] = {[1] = {95931, 95844, },
[2] = {95510, 95543, }}, --28 Highmountain Tauren
[29] = {[1] = {95636, 95665, },
[2] = {95806, 95857, }}, --29 Void Elf
[30] = {[1] = {96220, 96247, },
[2] = {96152, 96179, }}, --30 Light-forged
[31] = {[1] = {127289, 1273128, },
[2] = {126915, 126944, }}, --31 Zandalari
[32] = {[1] = {127102, 127131, },
[2] = {127008, 127037, }}, --32 Kul'Tiran
[34] = {[1] = {101933, 101962, },
[2] = {101859, 101888, }}, --36 Dark Iron Dwarf
[35] = {[1] = {144073, 144111, },
[2] = {143981, 144019, }}, --35 Vulpera
[36] = {[1] = {110370, 110399, },
[2] = {110295, 110324, }}, --36 Mag'har
[37] = {[1] = {143863, 143892, },
[2] = {144223, 144275, }}, --37 Mechagnome!!!!
}
local ERROR_NOTARGET, ALERT_INCOMING;
if VOICE_BY_RACE[raceID] then
ERROR_NOTARGET = VOICE_BY_RACE[raceID][genderID][1];
ALERT_INCOMING = VOICE_BY_RACE[raceID][genderID][2];
end
ERROR_NOTARGET = ERROR_NOTARGET or 2030;
ALERT_INCOMING = ALERT_INCOMING or 2669;
function Narci:PlayVoice(name)
if name == "ERROR" then
PlaySound(ERROR_NOTARGET, "Dialog");
elseif name == "DANGER" then
PlaySound(ALERT_INCOMING, "Dialog");
end
end
--Time
--C_DateAndTime.GetCurrentCalendarTime
local ActorIDByRace = {
--local GenderID = UnitSex(unit); 2 Male 3 Female
--[raceID] = {male actorID, female actorID, bustOffsetZ_M, bustOffsetZ_F},
[2] = {483, 483}, -- Orc bow
[3] = {471, nil}, -- Dwarf
[5] = {472, 487}, -- UD 0.9585 seems small
[6] = {449, 484}, -- Tauren
[7] = {450, 450}, -- Gnome
4 years ago
[8] = {485, 486}, -- Troll 0.9414 too high?
[9] = {476, 477}, -- Goblin
[11] = {475, 501}, -- Goat
[22] = {474, 500}, -- Worgen
[24] = {473, 473}, -- Pandaren
[28] = {490, 491}, -- Highmountain Tauren
[30] = {488, 489}, -- Lightforged Draenei
[31] = {492, 492}, -- Zandalari
[32] = {494, 497}, -- Kul'Tiran
[34] = {499, nil}, -- Dark Iron Dwarf
[35] = {924, 923}, -- Vulpera
[36] = {495, 498}, -- Mag'har
[37] = {929, 931}, -- Mechagnome
}
--Re-check this↑ table every major patch
--[[
function Narci_GetActorByTag(raceName, gender)
raceName = string.lower(raceName);
local playerRaceActor;
if gender == 1 then
playerRaceActor = raceName.."-".."male";
else
playerRaceActor = raceName.."-".."female";
end
return DressUpFrame.ModelScene:GetActorByTag(playerRaceActor);
end
--]]
local ZoomDistanceByRace = {
--[raceID] = {male Zoom, female Zoom, bustOffsetZ_M, bustOffsetZ_F},
[1] = {2.4, 2}, -- Human
[2] = {2.5, 2}, -- Orc bow
[3] = {2.5, 2}, -- Dwarf
[4] = {2.2, 2.1}, -- Night Elf
[5] = {2.5, 2}, -- UD
[6] = {3, 2.5}, -- Tauren
[7] = {2.6, 2.8}, -- Gnome
[8] = {2.5, 2}, -- Troll
[9] = {2.9, 2.9}, -- Goblin
[10] = {2, 2}, -- Blood Elf
[11] = {2.4, 2}, -- Goat
[22] = {2.8, 2}, -- Worgen
[24] = {2.9, 2.4}, -- Pandaren
[27] = {2, 2}, -- Nightborne
--[29] = {2, 2}, -- Void Elf
--[28] = {2, 2}, -- Highmountain Tauren
--[30] = {2, 2}, -- Lightforged Draenei
[31] = {2.2, 2}, -- Zandalari
[32] = {2.4, 2.3}, -- Kul'Tiran
--[34] = {2, 2}, -- Dark Iron Dwarf
[35] = {2.6, 2.1}, -- Vulpera
--[36] = {2, 2}, -- Mag'har
--[37] = {2, 2}, -- Mechagnome
}
function NarciAPI_GetCameraZoomDistanceByUnit(unit)
if not UnitExists(unit) or not UnitIsPlayer(unit) or not CanInspect(unit, false) then return; end
local _, _, raceID = UnitRace(unit);
local genderID = UnitSex(unit);
if raceID == 25 or raceID == 26 then --Pandaren A|H
raceID = 24;
elseif raceID == 29 then
raceID = 10;
elseif raceID == 37 then
raceID = 7;
elseif raceID == 30 then
raceID = 11;
elseif raceID == 28 then
raceID = 6;
elseif raceID == 34 then
raceID = 3;
elseif raceID == 36 then
raceID = 2;
elseif raceID == 22 then
if unit == "player" then
local _, inAlternateForm = HasAlternateForm();
if not inAlternateForm then
--Wolf
raceID = 22;
else
raceID = 1;
end
end
end
if not (raceID and genderID) then
return 2
elseif ZoomDistanceByRace[raceID] then
return ZoomDistanceByRace[raceID][genderID - 1] or 2;
else
return 2
end
end
local DEFAULT_ACTOR_INFO_ID = 438;
local PanningYOffsetByRace = {
--[raceID] = { { male = {offsetY1 when frame maximiazed, offsetY2} }, {female = ...} }
[0] = { --default
{-290, -110},
},
[4] = { --NE
{-317, -117},
{-282, -115.5},
},
[10] = { --BE
{-282, -110},
{-290, -116},
}
--/dump DressUpFrame.ModelScene:GetActiveCamera().panningYOffset
}
PanningYOffsetByRace[29] = PanningYOffsetByRace[10];
local function GetPanningYOffset(raceID, genderID)
genderID = genderID -1;
if PanningYOffsetByRace[raceID] and PanningYOffsetByRace[raceID][genderID] then
return PanningYOffsetByRace[raceID][genderID]
else
return PanningYOffsetByRace[0][1]
end
end
local GetModelSceneActorInfoByID = C_ModelInfo.GetModelSceneActorInfoByID;
function NarciAPI_GetActorInfoByUnit(unit)
if not UnitExists(unit) or not UnitIsPlayer(unit) or not CanInspect(unit, false) then return nil, PanningYOffsetByRace[0][1]; end
local _, _, raceID = UnitRace(unit);
local genderID = UnitSex(unit);
if raceID == 25 or raceID == 26 then --Pandaren A|H
raceID = 24
end
local actorInfoID;
if not (raceID and genderID) then
actorInfoID = DEFAULT_ACTOR_INFO_ID; --438
elseif ActorIDByRace[raceID] then
actorInfoID = ActorIDByRace[raceID][genderID - 1] or DEFAULT_ACTOR_INFO_ID;
else
actorInfoID = DEFAULT_ACTOR_INFO_ID; --438
end
return GetModelSceneActorInfoByID(actorInfoID), GetPanningYOffset(raceID, genderID)
end
NarciModelSceneActorMixin = CreateFromMixins(ModelSceneActorMixin);
function NarciModelSceneActorMixin:OnAnimFinished()
if self.oneShot then
--self:Hide();
if self.finalSequence then
self:SetAnimation(0, 0, 0, self.finalSequence);
else
self:Hide();
end
end
if self.onfinishedCallback then
self.onfinishedCallback();
end
end
function NarciAPI_SetupModelScene(modelScene, modelFileID, zoomDistance, view, actorIndex, UseTransit)
local pi = math.pi;
local model = modelScene;
local actorTag;
if not actorIndex then
actorTag = "narciEffectActor";
else
actorTag = "narciEffectActor"..actorIndex
end
local actor = model[actorTag];
if not actor then
local actorID = 156; --effect C_ModelInfo.GetModelSceneActorInfoByID(156)
local actorInfo = C_ModelInfo.GetModelSceneActorInfoByID(actorID);
--actor = model:AcquireAndInitializeActor(actorInfo);
actor = model:CreateActor(nil, "NarciModelSceneActorTemplate");
actor:SetYaw(pi);
model[actorTag] = actor;
local parentFrame = model:GetParent();
if parentFrame then
model:SetFrameLevel(parentFrame:GetFrameLevel() + 1 or 20);
else
model:SetFrameLevel(20);
end
end
--local cameraTag = "NarciUI";
local camera = model.narciCamera;
if not camera then
camera = CameraRegistry:CreateCameraByType("OrbitCamera");
if camera then
model.narciCamera = camera;
model:AddCamera(camera);
local modelSceneCameraInfo = C_ModelInfo.GetModelSceneCameraInfoByID(114);
camera:ApplyFromModelSceneCameraInfo(modelSceneCameraInfo, 1, 1); --1 ~ CAMERA_TRANSITION_TYPE_IMMEDIATE / CAMERA_MODIFICATION_TYPE_DISCARD
end
end
model:SetActiveCamera(camera);
if modelFileID then
actor:SetModelByFileID(modelFileID);
end
if zoomDistance then
if UseTransit then
--change camera.targetInterpolationAmount for smoothing time --:GetTargetInterpolationAmount() :SetTargetInterpolationAmount(value)
camera:SetZoomDistance(1);
camera:SnapAllInterpolatedValues();
After(0, function()
camera:SetZoomDistance(zoomDistance);
end);
else
camera:SetZoomDistance(zoomDistance);
camera:SynchronizeCamera();
end
end
if view then
local pitch, yaw;
if type(view) == "string" then
view = strupper(view);
if view == "FRONT" then
pitch = 0;
yaw = pi;
elseif view == "BACK" then
pitch = 0;
yaw = 0;
elseif view == "TOP" then
pitch = pi/2;
yaw = pi;
elseif view == "BOTTOM" then
pitch = -pi/2;
yaw = pi;
elseif view == "LEFT" then
pitch = 0;
yaw = -pi/2;
elseif view == "RIGHT" then
pitch = 0;
yaw = pi/2;
else
return;
end
elseif type(view) == "table" then
pitch = view[1];
yaw = view[2];
if not (pitch and yaw) then
return;
end
end
actor:SetPitch(pitch);
actor:SetYaw(yaw);
end
return actor, camera
--[[
if rollDegree then
actor:SetRoll(rad(-rollDegree)) --Clockwise
end
--]]
end
--[[
ScriptAnimatedEffectController:GetCurrentEffectID()
/dump ScriptedAnimationEffectsUtil.GetEffectByID() 101 Center Rune Wind Cyan
effect = {visual(fileID), visualScale, animationSpeed, ...}
fileID, effectID:
3483475 --Black Swirl 52
984698 --Center Rune Wind Cyan 101
3655832 --Circle Rune Effect 73
3656114 --69
--]]
------------------------------------------------------------------------------
local function ReAnchorFrame(frame)
--maintain frame top position when changing its height
local oldCenterX = frame:GetCenter();
--local oldBottom = frame:GetBottom();
local oldTop = frame:GetTop();
local screenWidth = WorldFrame:GetWidth();
local screenHeight = WorldFrame:GetHeight();
local scale = frame:GetEffectiveScale();
if not scale or scale == 0 then
scale = 1;
end
local width = frame:GetWidth()/2;
frame:ClearAllPoints();
--frame:SetPoint("BOTTOMRIGHT", nil, "BOTTOMRIGHT", oldCenterX + width - screenWidth / scale , oldBottom);
frame:SetPoint("TOPRIGHT", nil, "TOPRIGHT", oldCenterX + width - screenWidth / scale , oldTop - screenHeight/scale);
end
local function ParserButton_ShowTooltip(self)
if self.itemLink then
local frame = self:GetParent();
local tp = frame.tooltip;
--GameTooltip_SetBackdropStyle(TP, GAME_TOOLTIP_BACKDROP_STYLE_CORRUPTED_ITEM);
tp:SetOwner(self, "ANCHOR_NONE");
tp:SetPoint("TOP", frame.ItemString, "BOTTOM", 0, -14);
tp:SetHyperlink(self.itemLink);
tp:SetMinimumWidth(254 / 0.8);
tp:Show();
frame:SetHeight( max (floor(tp:GetHeight() - 260), 0) + 400);
ReAnchorFrame(frame);
end
end
local function ParserButton_GetCursor(self)
local infoType, itemID, itemLink = GetCursorInfo();
self.Highlight:Hide()
if not (infoType and infoType == "item") then return end
self.itemLink = itemLink;
local itemName, _, itemQuality, itemLevel, _, _, _, _, itemEquipLoc, itemIcon = GetItemInfo(itemLink);
local itemString = match(itemLink, "item:([%-?%d:]+)");
local enchantID = GetItemEnchantID(itemLink);
local r, g, b = GetCustomQualityColor(itemQuality);
--Show info
self.ItemIcon:SetTexture(itemIcon);
local frame = self:GetParent();
frame.ItemName:SetText(itemName);
frame.ItemName:SetTextColor(r, g, b);
frame.ItemString:SetText(itemString);
frame.Pointer:Hide();
ParserButton_ShowTooltip(self);
ClearCursor();
end
function Narci_ItemParser_OnLoad(self)
self:SetUserPlaced(false)
self:ClearAllPoints();
self:SetPoint("CENTER", UIParent, "CENTER", 0, 0);
self:RegisterForDrag("LeftButton");
self:SetScript("OnShow", ReAnchorFrame);
self.ItemButton:SetScript("OnReceiveDrag", ParserButton_GetCursor);
self.ItemButton:SetScript("OnClick", ParserButton_GetCursor);
self.ItemButton:SetScript("OnEnter", ParserButton_ShowTooltip);
local locale = TEXT_LOCALE;
local version, build, date, tocversion = GetBuildInfo();
self.ClientInfo:SetText(locale.." "..version.."."..build.." "..NARCI_VERSION_INFO);
local tooltip = CreateFrame("GameTooltip", "Narci_ItemParserTooltip", self, "GameTooltipTemplate");
tooltip:Hide();
self.tooltip = tooltip;
local scale = 0.8;
local tooltipScale = 0.8;
self:SetScale(0.8);
tooltip:SetScale(tooltipScale);
end
----------------------------
-----Item Import/Export-----
----------------------------
local WOWHEAD_ENCODING = "0zMcmVokRsaqbdrfwihuGINALpTjnyxtgevElBCDFHJKOPQSUWXYZ123456789"; --version: 9 WH.calc.hash.getEncoding(9)
local WOWHEAD_DELIMITER = 8; --WH.calc.hash.getDelimiter(9)
local COMPRESSION_INDICATOR = 7; --WH.calc.hash.getZeroDelimiterCompressionIndicator(9) :7 + single letter
local WOWHEAD_MAXCODING_INDEX = 58 --WH.calc.hash.getMaxEncodingIndex(a); //9 ~ 58
local WOWHEAD_CUSTOMIZATION = "0zJ89b";
local EncodeValue = {}
for i = 0, #WOWHEAD_ENCODING do
EncodeValue[i] = strsub(WOWHEAD_ENCODING, i+1, i+1);
end
local EquipmentOrderToCharacterSlot = {
[1] = 1,
[2] = 3,
[3] = 15,
[4] = 5,
[5] = 4,
[6] = 19,
[7] = 9,
[8] = 10,
[9] = 6,
[10]= 7,
[11]= 8,
[12]= 16,
[13]= 17,
};
local CharacterSlotToEquipmentOrder = {}
for k, v in pairs(EquipmentOrderToCharacterSlot) do
CharacterSlotToEquipmentOrder[v] = tostring(k);
v = tostring(v);
end
local function EncodeLongValue(number)
local m = WOWHEAD_MAXCODING_INDEX;
if number <= m then
return EncodeValue[number];
end
local floor = floor;
local shortValues = {number};
local v = 0;
while(shortValues[1] > m) do
v = floor(shortValues[1] / m);
tinsert(shortValues, shortValues[1] - m * v);
shortValues[1] = v;
end
local str = EncodeValue[ shortValues[1] ];
for i = #shortValues, 2, -1 do
if shortValues[2] ~= "0" then
str = str .. EncodeValue[ shortValues[i] ]
else
str = str .. "7"
end
end
return str
end
local function EncodeItemlist(itemlist, unitInfo)
if not itemlist or type(itemlist) ~= "table" or itemlist == {} then return ""; end
--itemlist = {[slot] = {itemID, bonusID}}
local raceID, genderID, classID;
if unitInfo then
raceID, genderID, classID = unitInfo.raceID, unitInfo.genderID, unitInfo.classID;
else
local _;
local unit = "player";
_, _, raceID = UnitRace(unit);
genderID = UnitSex(unit);
_, _, classID = UnitClass(unit);
end
if not (raceID and genderID and classID) then
local _;
local unit = "player";
_, _, raceID = UnitRace(unit);
_, _, classID = UnitClass(unit);
genderID = UnitSex(unit) or 2;
raceID = raceID or 1;
classID = classID or 1;
end
genderID = genderID - 2; --Male 2 → 0 Female 3 → 1
local wowheadLink = "https://www.wowhead.com/dressing-room#s".. EncodeValue[raceID] .. EncodeValue[genderID] .. EncodeValue[classID] .. WOWHEAD_CUSTOMIZATION.. WOWHEAD_DELIMITER;
local segment, slot, item;
local blanks = 0;
for i = 1, #EquipmentOrderToCharacterSlot do
--item = { itemID, bonusID }
slot = EquipmentOrderToCharacterSlot[i]
item = itemlist[slot];
if item and item[1] then
segment = EncodeLongValue(item[1])
if #segment < 3 then
segment = "7".. CharacterSlotToEquipmentOrder[slot] .. segment
end
item[2] = item[2] or 0; --bonusID
if slot == 16 and item[2] > 0 and item[2] < 99 then
local offHand = itemlist[17];
if offHand and offHand[1] then
segment = segment .. WOWHEAD_DELIMITER .. "0" .. WOWHEAD_DELIMITER .. EncodeLongValue(offHand[1]) .. WOWHEAD_DELIMITER .. "7c" .. EncodeValue[ item[2] ];
else
segment = segment .. WOWHEAD_DELIMITER .. "7V" .. EncodeValue[ item[2] ];
end
wowheadLink = wowheadLink .. segment;
break;
else
segment = segment .. WOWHEAD_DELIMITER .. EncodeLongValue(item[2]) .. WOWHEAD_DELIMITER;
end
wowheadLink = wowheadLink .. segment;
else
blanks = blanks + 1;
wowheadLink = wowheadLink .. "7M"
end
end
return wowheadLink
end
NarciAPI.EncodeItemlist = EncodeItemlist;
--------------------
----Model Widget----
--------------------
local function NarciAPI_InitializeModelLight(model)
--Model: DressUpModel/Cinematic Model/...
--Not ModelScene
model:SetLight(true, false, - 0.44699833180028 , 0.72403680806459 , -0.52532198881773, 0.8, 172/255, 172/255, 172/255, 1, 0.8, 0.8, 0.8);
end
NarciAPI.InitializeModelLight = NarciAPI_InitializeModelLight;
--------------------
--------Time--------
--------------------
function NarciAPI_FormatTime(seconds)
seconds = seconds or 0;
local hour = floor(seconds / 3600);
local minute = floor((seconds - 3600 * hour) / 60);
local second = mod(seconds, 60);
if hour > 0 then
return hour.."h "..minute.."m "..second.."s";
elseif minute > 0 then
return minute.."m "..second.."s";
else
return second.."s";
end
end
----------------------------
----UI Animation Generic----
----------------------------
function NarciAPI_CreateAnimationFrame(duration, frameName)
local frame = CreateFrame("Frame", frameName);
frame:Hide();
frame.total = 0;
frame.duration = duration;
frame:SetScript("OnHide", function(self)
self.total = 0;
end);
return frame;
end
function NarciAPI_CreateFadingFrame(parentObject)
local animFade = NarciAPI_CreateAnimationFrame(0.2);
animFade.timeFactor = 1;
parentObject.animFade = animFade;
animFade:SetScript("OnUpdate", function(frame, elapsed)
local alpha = frame.fromAlpha;
alpha = alpha + frame.timeFactor * elapsed;
frame.fromAlpha = alpha;
if alpha >= 1 then
alpha = 1;
frame:Hide();
elseif alpha <= 0 then
alpha = 0;
frame:Hide();
end
parentObject:SetAlpha(alpha);
end);
function parentObject:FadeOut(duration)
duration = duration or 0.15;
local alpha = parentObject:GetAlpha();
animFade.fromAlpha = alpha;
animFade.timeFactor = -1/duration;
if alpha ~= 0 then
animFade:Show();
end
end
function parentObject:FadeIn(duration)
duration = duration or 0.2;
local alpha = parentObject:GetAlpha();
animFade.fromAlpha = alpha;
animFade.timeFactor = 1/duration;
parentObject:Show();
if alpha ~= 1 then
animFade:Show();
end
end
return animFade
end
----------------------------
-------Frame Template-------
----------------------------
NarciFrameMixin = CreateFromMixins(ExpansionTransitionBackdropTemplateMixin);
function NarciFrameMixin:ShowFrame(state)
self:SetShown(state);
if state then
self:SetAlpha(1);
else
self:SetAlpha(0);
end
end
function NarciFrameMixin:HideFrame()
self:ShowFrame(false);
end
function NarciFrameMixin:ToggleFrame()
if self:IsShown() then
self:ShowFrame(false);
else
self:ShowFrame(true);
end
end
function NarciFrameMixin:SetHeaderText(text, r, g, b)
self.Header:SetText(text);
self.Header:SetTextColor(r or 0.4, g or 0.4, b or 0.4);
end
function NarciFrameMixin:SetSizeAndAnchor(x, y, point, relativeTo, relativePoint, offsetX, offsetY)
if x then x = max(x, 40) end;
if y then y = max(y, 40) end;
if x then
if y then
self:SetSize(x, y);
else
self:SetWidth(x);
end
else
self:SetHeight(y);
end
self:ClearAllPoints();
self:SetPoint(point, relativeTo, relativePoint, offsetX, offsetY);
end
function NarciFrameMixin:SetRelativeFrameLevel(offset)
local parent = self:GetParent();
if parent then
local parentLevel = parent:GetFrameLevel() or 0;
self:SetFrameStrata(parent:GetFrameStrata());
self:SetFrameLevel( max(parentLevel + offset, 0) );
end
end
function NarciFrameMixin:HideWhenParentIsHidden(state)
if state then
self:SetScript("OnHide", function(self)
self:HideFrame();
end);
local parent = self:GetParent();
if parent and not parent:IsVisible() then
self:HideFrame();
end
else
self:SetScript("OnHide", nil);
end
end
-------------------------------------------
local DelayedFadeIn = NarciAPI_CreateAnimationFrame(1);
DelayedFadeIn:SetScript("OnUpdate", function(self, elapsed)
self.total = self.total + elapsed;
if self.total >= self.duration then
self:Hide();
if self.anchor == GetMouseFocus() then
FadeFrame(self.object, 0.25, 1);
end
end
end);
NarciHotkeyNotificationMixin = {};
4 years ago
function NarciHotkeyNotificationMixin:SetKey(hotkey, mouseButton, description, alwaysShown, enableListener)
local ICON_HEIGHT = 20;
self.alwaysShown = alwaysShown;
4 years ago
self.enableListener = enableListener;
self.Label:SetText(description);
if description then
self.GradientM:Show();
self.GradientR:Show();
else
self.GradientM:Hide();
self.GradientR:Hide();
end
if alwaysShown then
self:SetAlpha(1);
else
self:SetAlpha(0);
end
local width = self.Label:GetWidth();
if hotkey then
self.KeyIcon:SetTexture("Interface/AddOns/Narcissus/Art/Keyboard/Key", nil, nil, "TRILINEAR");
self.KeyIcon:Show();
if string.lower(hotkey) == "alt" then
hotkey = NARCI_MODIFIER_ALT;
end
self.KeyLabel:SetText(hotkey);
self.KeyLabel:SetShadowColor(0, 0, 0);
self.KeyLabel:SetShadowOffset(0, 1.4);
local texWidth;
if string.len(hotkey) > 5 then
texWidth = 146;
self.KeyIcon:SetTexCoord(0, texWidth/256, 0.25, 0.5);
self.isLongButton = true
else
texWidth = 118;
self.isLongButton = nil;
self.KeyIcon:SetTexCoord(0, texWidth/256, 0, 0.25);
end
self.keyTexCoord = texWidth/256;
self.KeyIcon:SetSize(texWidth/64*ICON_HEIGHT, ICON_HEIGHT);
width = width + texWidth/64*ICON_HEIGHT;
end
if mouseButton then
self.key = mouseButton;
self.MouseIcon:SetTexture("Interface/AddOns/Narcissus/Art/Keyboard/Mouse", nil, nil, "TRILINEAR");
self.MouseIcon:Show();
self.MouseIcon:SetSize(ICON_HEIGHT, ICON_HEIGHT);
if mouseButton == "LeftButton" then
self.MouseIcon:SetTexCoord(0, 0.25, 0, 1);
elseif mouseButton == "RightButton" then
self.MouseIcon:SetTexCoord(0.25, 0.5, 0, 1);
elseif mouseButton == "MiddleButton" then
self.MouseIcon:SetTexCoord(0.5, 0.75, 0, 1);
elseif mouseButton == "MouseWheel" then
self.MouseIcon:SetTexCoord(0.75, 1, 0, 1);
end
if hotkey then
self.KeyIcon:ClearAllPoints();
self.KeyIcon:SetPoint("RIGHT", self.MouseIcon, "LEFT", 0, 0);
width = width + ICON_HEIGHT;
end
end
self:SetWidth(width);
end
function NarciHotkeyNotificationMixin:ShowTooltip()
DelayedFadeIn:Hide();
DelayedFadeIn.anchor = GetMouseFocus();
DelayedFadeIn.object = self;
DelayedFadeIn:Show();
end
function NarciHotkeyNotificationMixin:FadeIn()
DelayedFadeIn:Hide();
FadeFrame(self, 0.25, 1);
end
function NarciHotkeyNotificationMixin:FadeOut()
DelayedFadeIn:Hide();
FadeFrame(self, 0.25, 0);
end
4 years ago
function NarciHotkeyNotificationMixin:JustHide()
DelayedFadeIn:Hide();
FadeFrame(self, 0, 0);
4 years ago
end
function NarciHotkeyNotificationMixin:OnShow()
if self.enableListener then
self:RegisterEvent("GLOBAL_MOUSE_UP");
end
end
function NarciHotkeyNotificationMixin:OnHide()
if not self.alwaysShown then
DelayedFadeIn:Hide();
self:Hide();
self:SetAlpha(0);
end
if self.enableListener then
self:UnregisterEvent("GLOBAL_MOUSE_UP");
end
end
function NarciHotkeyNotificationMixin:OnEvent(event, key)
if key == self.key then
self:UnregisterEvent("GLOBAL_MOUSE_UP");
self:FadeOut();
end
print(event);
end
function NarciHotkeyNotificationMixin:SetHighlight(state)
if self.keyTexCoord then
local texCoordY;
if self.isLongButton then
texCoordY = 0.25;
else
texCoordY = 0;
end
if state then
texCoordY = texCoordY + 0.5;
self.KeyIcon:SetTexCoord(0, self.keyTexCoord, texCoordY + 0.25, texCoordY);
self.KeyLabel:SetPoint("CENTER", 0, -1);
self.KeyLabel:SetTextColor(0.72, 0.72, 0.72);
else
self.KeyIcon:SetTexCoord(0, self.keyTexCoord, texCoordY, texCoordY + 0.25);
self.KeyLabel:SetPoint("CENTER", 0, 0);
self.KeyLabel:SetTextColor(0.6, 0.6, 0.6);
end
end
end
NarciQuickFavoriteButtonMixin = {};
function NarciQuickFavoriteButtonMixin:SetIconSize(size)
self.iconSize = size;
self.Icon:SetSize(size, size);
self.Bling:SetSize(size, size);
self.Icon:SetTexCoord(0.5, 0.75, 0.25, 0.5);
self.favTooltip = Narci.L["Favorites Add"];
self.unfavTooltip = Narci.L["Favorites Remove"];
self.isFav = false;
end
function NarciQuickFavoriteButtonMixin:SetFavorite(isFavorite)
if isFavorite then
self.isFav = true;
self.Icon:SetTexCoord(0.75, 1, 0.25, 0.5);
self.Icon:SetAlpha(1);
else
self.isFav = false;
self.Icon:SetTexCoord(0.5, 0.75, 0.25, 0.5);
self.Icon:SetAlpha(0.4);
end
end
function NarciQuickFavoriteButtonMixin:PlayVisual()
self:StopAnimating();
if self.isFav then
self.Icon:SetTexCoord(0.75, 1, 0.25, 0.5);
self.parent.Star:Show();
self.Bling.animIn:Play();
else
self.Icon:SetTexCoord(0.5, 0.75, 0.25, 0.5);
self.parent.Star:Hide();
end
end
function NarciQuickFavoriteButtonMixin:OnEnter()
self.Icon:SetAlpha(1);
if self.isFav then
NarciTooltip:NewText(self.unfavTooltip, nil, nil, 1);
else
NarciTooltip:NewText(self.favTooltip, nil, nil, 1);
end
end
function NarciQuickFavoriteButtonMixin:OnLeave()
NarciTooltip:FadeOut();
if not self.isFav then
self.Icon:SetAlpha(0.6);
end
end
function NarciQuickFavoriteButtonMixin:OnHide()
self:StopAnimating();
end
function NarciQuickFavoriteButtonMixin:OnMouseDown()
self.Icon:SetSize(self.iconSize - 2, self.iconSize - 2);
NarciTooltip:FadeOut();
end
function NarciQuickFavoriteButtonMixin:OnMouseUp()
self.Icon:SetSize(self.iconSize, self.iconSize);
end
function NarciQuickFavoriteButtonMixin:OnDoubleClick()
end
-----------------------------------------------------------
NarciDarkRoundButtonMixin = {};
function NarciDarkRoundButtonMixin:OnLoad()
self.Background:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Buttons\\Button-Round", nil, nil, "TRILINEAR");
end
function NarciDarkRoundButtonMixin:SetLabelText(label)
self.Label:SetText("");
self.Label:SetText(label);
local textWidth = self.Label:GetWidth();
self.effectiveWidth = floor( self:GetWidth() + textWidth + 2 + 2);
end
function NarciDarkRoundButtonMixin:Initialize(groupIndex, label, tooltip, onClickFunc)
self:SetLabelText(label);
if tooltip then
self.tooltip = tooltip;
end
if groupIndex then
self.groupIndex = groupIndex;
local parent = self:GetParent();
if not parent.buttonGroups then
parent.buttonGroups = {};
end
if not parent.buttonGroups[groupIndex] then
parent.buttonGroups[groupIndex] = {};
end
tinsert(parent.buttonGroups[groupIndex], self);
end
if onClickFunc then
self.onClickFunc = onClickFunc;
end
end
function NarciDarkRoundButtonMixin:GetEffectiveWidth()
return self.effectiveWidth or self:GetWidth()
end
function NarciDarkRoundButtonMixin:GetGroupEffectiveWidth()
if self.groupIndex then
local buttons = self:GetParent().buttonGroups[self.groupIndex];
local width = 0;
local maxWidth = 0;
for i = 1, #buttons do
width = buttons[i]:GetEffectiveWidth();
if width > maxWidth then
maxWidth = width;
end
end
return maxWidth
else
return self:GetEffectiveWidth();
end
end
function NarciDarkRoundButtonMixin:Select()
self.SelectedIcon:Show();
self.isSelected = true;
end
function NarciDarkRoundButtonMixin:Deselect()
self.SelectedIcon:Hide();
self.isSelected = nil;
end
function NarciDarkRoundButtonMixin:UpdateVisual()
if self.groupIndex then
local buttons = self:GetParent().buttonGroups[self.groupIndex];
for i = 1, #buttons do
buttons[i]:Deselect()
end
end
self:Select();
end
function NarciDarkRoundButtonMixin:OnClick()
self:UpdateVisual();
if self.onClickFunc then
self.onClickFunc();
end
end
function NarciDarkRoundButtonMixin:OnMouseDown()
self.PushedHighlight:Show();
end
function NarciDarkRoundButtonMixin:OnMouseUp()
self.PushedHighlight:Hide();
end
function NarciDarkRoundButtonMixin:UpdateGroupHitBox()
if self.groupIndex then
local maxWidth = self:GetGroupEffectiveWidth();
local buttons = self:GetParent().buttonGroups[self.groupIndex];
for i = 1, #buttons do
buttons[i]:SetHitRectInsets(0, buttons[i]:GetWidth() - maxWidth, 0, 0);
end
return maxWidth
end
end
NarciDarkSquareButtonMixin = {};
function NarciDarkSquareButtonMixin:OnLoad()
self.Background:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Buttons\\Button-RoundedSquare", nil, nil, "TRILINEAR");
end
function NarciDarkSquareButtonMixin:Initialize(groupIndex, icon, texCoord, tooltip, onClickFunc)
if tooltip then
self.tooltip = tooltip;
end
if icon then
self.Icon:SetTexture(icon, nil, nil, "TRILINEAR");
if texCoord then
self.Icon:SetTexCoord( unpack(texCoord) );
end
end
if groupIndex then
self.groupIndex = groupIndex;
local parent = self:GetParent();
if not parent.buttonGroups then
parent.buttonGroups = {};
end
if not parent.buttonGroups[groupIndex] then
parent.buttonGroups[groupIndex] = {};
end
tinsert(parent.buttonGroups[groupIndex], self);
end
if onClickFunc then
self.onClickFunc = onClickFunc;
end
end
function NarciDarkSquareButtonMixin:OnClick()
self:UpdateVisual();
if self.onClickFunc then
self.onClickFunc();
end
end
function NarciDarkSquareButtonMixin:UpdateVisual()
if self.groupIndex then
local button;
local buttons = self:GetParent().buttonGroups[self.groupIndex];
for i = 1, #buttons do
button = buttons[i];
if self ~= button then
button:Deselect();
end
end
end
self:Select();
end
function NarciDarkSquareButtonMixin:OnEnter()
self.Icon:SetAlpha(1);
end
function NarciDarkSquareButtonMixin:OnLeave()
if not self.isSelected then
self.Icon:SetAlpha(0.5);
end
end
function NarciDarkSquareButtonMixin:OnMouseDown()
self.PushedHighlight:Show();
end
function NarciDarkSquareButtonMixin:OnMouseUp()
self.PushedHighlight:Hide();
end
function NarciDarkSquareButtonMixin:Select()
self.Background:SetTexCoord(0.25, 0.5, 0, 1);
self.Icon:SetAlpha(1);
self.isSelected = true;
end
function NarciDarkSquareButtonMixin:Deselect()
self.Background:SetTexCoord(0, 0.25, 0, 1);
self.Icon:SetAlpha(0.5);
self.isSelected = nil;
end
-----------------------------------------------------------
--Clipboard
NarciClipboardMixin = {};
function NarciClipboardMixin:OnLoad()
self.Tooltip:SetText(Narci.L["Copied"]);
end
function NarciClipboardMixin:SetText(text)
self.EditBox:SetText(text);
end
function NarciClipboardMixin:SetFocus()
self.EditBox:SetFocus();
end
function NarciClipboardMixin:ClearFocus()
self.EditBox:ClearFocus();
end
function NarciClipboardMixin:ShowClipboard()
self:Show();
self.EditBox:Show();
self:StopAnimating();
self.Tooltip:SetAlpha(0);
end
4 years ago
function NarciClipboardMixin:HasFocus()
return self.EditBox.hasFocus;
end
function NarciClipboardMixin:ReAnchorTooltipToObject(object)
if object then
self.Tooltip:ClearAllPoints();
self.Tooltip:SetPoint("CENTER", object, "CENTER", 0, 0);
end
end
NarciNonEditableEditBoxMixin = {};
function NarciNonEditableEditBoxMixin:OnLoad()
end
4 years ago
function NarciNonEditableEditBoxMixin:OnEditFocusGained()
self.hasFocus = true;
self:SelectText();
end
function NarciNonEditableEditBoxMixin:OnEditFocusLost()
self.hasFocus = nil;
self:Quit();
end
function NarciNonEditableEditBoxMixin:SelectText()
self:SetCursorPosition(self.defaultCursorPosition or 0);
self:HighlightText();
end
function NarciNonEditableEditBoxMixin:OnHide()
self:StopAnimating();
end
function NarciNonEditableEditBoxMixin:Quit()
self:ClearFocus();
if self.onQuitFunc then
self.onQuitFunc();
end
end
function NarciNonEditableEditBoxMixin:OnTextChanged(isUserInput)
if isUserInput then
self:Quit();
end
end
function NarciNonEditableEditBoxMixin:OnKeyDown(key, down)
4 years ago
local keys = CreateKeyChordStringUsingMetaKeyState(key);
if keys == "CTRL-C" or key == "COMMAND-C" then
self.hasCopied = true;
After(0, function()
self:GetParent().Tooltip.good:Play();
self:Hide();
end);
end
end
NarciChamferedFrameMixin = {};
function NarciChamferedFrameMixin:SetBackgroundColor(r, g, b, a)
if not self.backgroundAtlas then
self.backgroundAtlas = {
self.BackgroundTopLeft, self.BackgroundTop, self.BackgroundTopRight,
self.BackgroundMiddleLeft, self.BackgroundMiddle, self.BackgroundMiddleRight,
self.BackgroundBottomLeft, self.BackgroundBottom, self.BackgroundBottomRight,
};
end
a = a or 1;
for i = 1, #self.backgroundAtlas do
self.backgroundAtlas[i]:SetVertexColor(r, g, b);
self.backgroundAtlas[i]:SetAlpha(a);
end
end
function NarciChamferedFrameMixin:SetBorderColor(r, g, b, a)
if not self.borderAtlas then
self.borderAtlas = {
self.BorderTopLeft, self.BorderTop, self.BorderTopRight,
self.BorderMiddleLeft, self.BorderMiddle, self.BorderMiddleRight,
self.BorderBottomLeft, self.BorderBottom, self.BorderBottomRight,
};
end
a = a or 1;
for i = 1, #self.borderAtlas do
self.borderAtlas[i]:SetVertexColor(r, g, b);
self.borderAtlas[i]:SetAlpha(a);
end
end
function NarciChamferedFrameMixin:SetOffset(value)
--positive value expand the frame background
self.BackgroundTopLeft:SetPoint("TOPLEFT", self, "TOPLEFT", -value, value);
self.BorderTopLeft:SetPoint("TOPLEFT", self, "TOPLEFT", -value, value);
self.BackgroundTopRight:SetPoint("TOPRIGHT", self, "TOPRIGHT", value, value);
self.BorderTopRight:SetPoint("TOPRIGHT", self, "TOPRIGHT", value, value);
self.BackgroundBottomLeft:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", -value, -value);
self.BorderBottomLeft:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", -value, -value);
self.BackgroundBottomRight:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", value, -value);
self.BorderBottomRight:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", value, -value);
end
function NarciChamferedFrameMixin:Toggle()
self:SetShown(not self:IsShown());
end
function NarciChamferedFrameMixin:HideWhenParentIsHidden(state)
if state then
self:SetScript("OnHide", function()
self:Hide()
end);
else
self:SetScript("OnHide", nil);
end
end
-----------------------------------------------------------
NarciLanguageUtil = {};
NarciLanguageUtil.wowheadLinkPrefix = {
["default"] = "www",
["deDE"] = "de",
["esES"] = "es",
["esMX"] = "es",
["frFR"] = "fr",
["itIT"] = "it",
["ptBR"] = "pt",
["ruRU"] = "ru",
["koKR"] = "ko",
["zhCN"] = "cn",
["zhTW"] = "cn",
};
NarciLanguageUtil.wowheadLinkPrefix.primary = NarciLanguageUtil.wowheadLinkPrefix[TEXT_LOCALE] or "www";
function NarciLanguageUtil:GetWowheadLink(specificLanguage)
local prefix;
if specificLanguage then
prefix = self.wowheadLinkPrefix[ tostring(specificLanguage) ] or "www";
else
prefix = self.wowheadLinkPrefix.primary;
end
return ( "https://".. prefix .. ".wowhead.com/");
end
local function GetAllSelectedTalentIDsAndIcons(ignorePlayerLevel)
local talentInfo = {}
local maxTiers;
if ignorePlayerLevel then
maxTiers = 7;
else
maxTiers = GetMaxTalentTier(); --based on the character's level
end
local talentGroup = GetActiveSpecGroup();
local _, _, classID = UnitClass("player");
talentInfo.classID = classID;
if not talentGroup then
talentInfo.talentGroup = false;
return;
else
talentInfo.talentGroup = talentGroup;
end
local column, tierUnlockLevel, talentID, iconTexture, selected;
for tier = 1, maxTiers do
_, column, tierUnlockLevel = GetTalentTierInfo(tier, talentGroup);
if column then
talentID, _, iconTexture, selected = GetTalentInfo(tier, column, talentGroup);
talentInfo[tier] = {talentID, iconTexture, tierUnlockLevel};
else
talentInfo[tier] = {false, 134400}; --Question Mark Icon
end
end
return talentInfo
end
NarciAPI.GetAllSelectedTalentIDsAndIcons = GetAllSelectedTalentIDsAndIcons;
local round = function(number, digit)
digit = digit or 0;
local a = 10 ^ digit;
return math.floor(number * a + 0.5)/a
end
local function CreateColor(r, g, b)
return round(r/255, 4), round(g/255, 4), round(b/255, 4);
end
NarciAPI.CreateColor = CreateColor;
local timeStartNarcissus;
local function UpdateSessionTime()
local t = time();
if timeStartNarcissus then
local session = t - timeStartNarcissus;
local timeSpent = NarciStatisticsDB.TimeSpentInNarcissus;
if not timeSpent or type(timeSpent) ~= "number" then
timeSpent = 0;
end
NarciStatisticsDB.TimeSpentInNarcissus = timeSpent + session;
timeStartNarcissus = nil;
else
timeStartNarcissus = t;
end
end
NarciAPI.UpdateSessionTime = UpdateSessionTime;
local function UpdateScreenshotsCounter()
if Narci.isActive then
local numTaken = NarciStatisticsDB.ScreenshotsTakenInNarcissus;
if not numTaken or type(numTaken) ~= "number" then
numTaken = 0;
end
NarciStatisticsDB.ScreenshotsTakenInNarcissus = numTaken + 1;
end
end
NarciAPI.UpdateScreenshotsCounter = UpdateScreenshotsCounter;
local function GetClassColorByClassID(classID)
local classInfo = classID and C_CreatureInfo.GetClassInfo(classID);
if classInfo then
return C_ClassColor.GetClassColor(classInfo.classFile);
end
end
4 years ago
local function WrapNameWithClassColor(name, classID, specID, showIcon, offsetY)
local classInfo = C_CreatureInfo.GetClassInfo(classID);
if classInfo then
local color = GetClassColorByClassID(classID);
4 years ago
if color then
if specID and showIcon then
local str = color:WrapTextInColorCode(name);
local _, _, _, icon, role = GetSpecializationInfoByID(specID);
if icon then
offsetY = offsetY or 0;
str = "|T"..icon..":12:12:-1:"..offsetY..":64:64:4:60:4:60|t" ..str;
end
return str
else
return color:WrapTextInColorCode(name);
end
else
return name
end
else
return name
end
end
NarciAPI.GetClassColorByClassID = GetClassColorByClassID;
4 years ago
NarciAPI.WrapNameWithClassColor = WrapNameWithClassColor;
local function GetOutfitSlashCommand()
local playerActor = DressUpFrame.ModelScene:GetPlayerActor();
local itemTransmogInfoList = playerActor and playerActor:GetItemTransmogInfoList();
local slashCommand = TransmogUtil.CreateOutfitSlashCommand(itemTransmogInfoList);
return slashCommand
end
NarciAPI.GetOutfitSlashCommand = GetOutfitSlashCommand;
NarciAPI.GetScreenPixelSize = function()
return 768 / SCREEN_HEIGHT
end
local UtilityModel, ValidDisplayIDs;
local function DoesCreatureDisplayIDExist(id)
if not id then return end;
if not UtilityModel then
ValidDisplayIDs = {};
UtilityModel = CreateFrame("CinematicModel", nil, UIParent);
UtilityModel:SetKeepModelOnHide(true);
UtilityModel:SetSize(2, 2);
UtilityModel:SetPoint("TOP", UIParent, "BOTTOM", 0, -3);
UtilityModel:SetScript("OnModelLoaded", function(self)
local displayID = self:GetDisplayInfo();
if displayID and displayID ~= 0 then
ValidDisplayIDs[displayID] = true;
self.displayID = nil;
end
self:ClearModel();
end);
UtilityModel:Hide();
end
if ValidDisplayIDs[id] ~= nil then
return ValidDisplayIDs[id];
else
UtilityModel:ClearModel();
UtilityModel:SetDisplayInfo(id);
end
end
NarciAPI.DoesCreatureDisplayIDExist = DoesCreatureDisplayIDExist;
--[[
function TestFX(modelFileID, zoomDistance, view)
NarciAPI_SetupModelScene(TestScene, modelFileID, zoomDistance, view);
end
--]]
--/run TestFX(3152608, nil, ) 122972
--/run TestFX(1011653, 8, "
--/run TestFX(3004122, 8, "LEFT") --Eyeball
--Shake Frame SoulbindViewerMixin:Shake() Bliizard Blizzard_SoulbindsViewer.lua
--Debug
--[[
local DebugUtil = NarciAPI_CreateAnimationFrame(1, "NarciDebug");
DebugUtil:SetScript("OnUpdate", function(self, elapsed)
self.total = self.total + elapsed;
if self.total >= self.duration then
self:Hide();
self.isAdding = nil;
print("AVG: ".. self.sum / self.numNumber);
end
end);
function DebugUtil:RestartTimer()
self.total = 0;
self:Show();
end
function DebugUtil:CalculateAverage(number)
if not number then return end;
if self.isAdding then
self.sum = self.sum + number;
self.numNumber = self.numNumber + 1;
else
self.sum = number;
self.numNumber = 1;
self.isAdding = true;
self:RestartTimer();
end
end
--]]