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.

2924 lines
90 KiB

local After = C_Timer.After;
local sin = math.sin;
local cos = math.cos;
local pi = math.pi;
local sqrt = math.sqrt;
local abs = math.abs;
local function linear(t, b, e, d)
return (e - b) * t / d + b
end
local function outSine(t, b, e, d)
return (e - b) * sin(t / d * (pi / 2)) + b
end
local function inOutSine(t, b, e, d)
return (b - e) / 2 * (cos(pi * t / d) - 1) + b
end
local UIFrameFadeIn = UIFrameFadeIn;
local L = Narci.L;
-----------------------------------------------
local MainFrame, BarbershopModel, MaleButtons, FemaleButtons, WorgenMaleButtons, WorgenFemaleButtons, EditButton, EditBox, DeleteButton, PlusButton, SettingFrame, SettingButton;
--[[
NarciBarberShopModelMixin = {};
local CameraUpdater = CreateFrame("Frame");
function CameraUpdater:ZoomTo(value)
BarbershopModel:MakeCurrentCameraCustom();
local currentDistance = BarbershopModel:GetCameraDistance();
self.zoomDistance = value
BarbershopModel:SetCameraDistance(value);
end
function NarciBarberShopModelMixin:OnLoad()
self:SetUnit("player")
self:SetLight(true, false, -0.707, 0, -0.707, 1, 1, 1, 1, 0.5, 1, 1, 1);
self:SetCamera(0);
self:SetPortraitZoom(0.9);
self:SetAnimation(0, 0);
self:SetPaused(true);
self:SetKeepModelOnHide(true);
local ScreenHeight = UIParent:GetHeight();
self:SetSize(ScreenHeight, ScreenHeight)
BarbershopModel = self;
self:SetViewTranslation(0, -80);
self:SetPosition(-0.5, 0.2, 0);
end
function NarciBarberShopModelMixin:OnShow()
end
function NarciBarberShopModelMixin:OnModelLoaded()
self:SetPaused(true)
end
function NarciBarberShopModelMixin:ZoomTo(value)
CameraUpdater:ZoomTo(value)
end
--]]
----------------------------------------------------------------------------------------------------
local CAMERA_PROFILES_BY_RACE = {
--modelX, modelY, modelZ, facing
bloodelf = {
male = {3.38, 0.07, -1.88, 0.43},
female = {3.54, -0.02, -1.75, 0.35},
},
voidelf = {
male = {3.38, 0.07, -1.88, 0.43},
female = {3.54, -0.02, -1.75, 0.35},
},
draenei = {
male = {2.94, -0.19, -2.24, 0.43},
female = {3.40, -0.09, -2.14, 0.35},
},
lightforgeddraenei = {
male = {2.94, -0.19, -2.24, 0.43},
female = {3.40, -0.09, -2.14, 0.35},
},
dwarf = {
male = {3.24, -0.08, -1.34, 0.44},
female = {3.43, -0.02, -1.34, 0.44},
},
darkirondwarf = {
male = {3.24, -0.08, -1.34, 0.44},
female = {3.43, -0.02, -1.34, 0.44},
},
gnome = {
male = {3.23, -0.01, -0.92, 0.43},
female = {3.37, -0.07, -0.9, 0.43},
},
mechagnome = {
male = {3.23, -0.05, -0.93, 0.43},
female = {3.37, -0.07, -0.9, 0.43},
},
goblin = {
male = {3.24, 0, -1.08, 0.43},
female = {3.40, -0.03, -1.14, 0.43},
},
human = {
male = {3.38, -0.04, -1.87, 0.35},
female = {3.51, -0.025, -1.745, 0.43},
},
kultiran = {
male = {3.06, -0.05, -2.32, 0.43},
female = {3.34, -0.01, -2.21, 0.43},
},
nightborne = {
male = {3.37, 0.01, -2.26, 0.35},
female = {3.40, 0.05, -2.09, 0.43},
},
nightelf = {
male = {3.26, -0.07, -2.21, 0.43},
female = {3.38, -0.06, -2.09, 0.43},
},
orc = {
male = {2.79, -0.06, -1.84, 0.35},
female = {3.59, -0.02, -1.87, 0.35},
},
uprightorc = {
male = {3.11, -0.02, -2.08, 0.35},
female = {3.59, -0.02, -1.87, 0.35},
},
magharorc = {
male = {3.11, -0.02, -2.08, 0.35},
female = {3.59, -0.02, -1.87, 0.35},
},
pandaren = {
male = {3.14, -0.11, -2.11, 0.43},
female = {3.1, -0.16, -1.95, 0.43},
},
tauren = {
male = {1.97, -0.35, -2.2, 0.43},
female = {2.86, -0.35, -2.4, 0.52},
},
highmountaintauren = {
male = {1.97, -0.35, -2.2, 0.43},
female = {2.86, -0.35, -2.4, 0.52},
},
troll = {
male = {2.79, -0.19, -2.01, 0.43},
female = {3.43, 0.035, -2.19, 0.35},
},
scourge = {
male = {3.37, 0.03, -1.6, 0.43},
female = {3.39, -0.035, -1.665, 0.43},
},
vulpera = {
male = {3.33, -0.05, -1.09, 0.26},
female = {3.33, -0.04, -1.09, 0.26},
},
worgen = {
male = {2.41, -0.18, -1.93, 0.43},
female = {3.06, -0.04, -2.19, 0.52},
},
zandalaritroll = {
male = {3.16, 0.05, -2.55, 0.52},
female = {3.35, 0.04, -2.51, 0.44},
},
};
local WORGEN_HUMAN_FORM_ID = 220; --custom
local MAX_SAVES = 10;
local NUM_ACTIVE_BUTTONS = 0;
local CAMERA_PROFILE;
local ACTIVE_CAMERA_PROFILE;
local ScrollFrameCenterY;
local function UpdateScrollButtonAlpha(buttons)
local button;
local alpha;
local x, y, dy;
local abs = abs;
for i = 1, NUM_ACTIVE_BUTTONS do
button = buttons[i];
x, y = button:GetCenter();
dy = abs(y - ScrollFrameCenterY);
if dy < 128 then
alpha = 1;
button:Show();
else
alpha = 1 - (dy - 128)/64;
if alpha < 0 then
alpha = 0;
button:Hide();
else
button:Show();
end
end
button:SetAlpha(alpha);
end
end
local ScrollButtonAlphaUpdater = CreateFrame("Frame");
ScrollButtonAlphaUpdater:Hide();
ScrollButtonAlphaUpdater.t = 0;
ScrollButtonAlphaUpdater.duration = 1/60;
ScrollButtonAlphaUpdater:SetScript("OnUpdate", function(self, elapsed)
self.t = self.t + elapsed;
if self.t >= self.duration then
self.t = 0;
UpdateScrollButtonAlpha(self.activeButtons);
end
end);
function ScrollButtonAlphaUpdater:Start()
self:Show();
end
function ScrollButtonAlphaUpdater:Stop()
self:Hide();
end
function ScrollButtonAlphaUpdater:Refresh()
UpdateScrollButtonAlpha(self.activeButtons);
end
local ScrollBoundMarkUpdater = CreateFrame("Frame");
ScrollBoundMarkUpdater:Hide();
ScrollBoundMarkUpdater.t = 0;
ScrollBoundMarkUpdater.duration = 0.2;
ScrollBoundMarkUpdater.lastAlpha = 0;
ScrollBoundMarkUpdater:SetScript("OnUpdate", function(self, elapsed)
local alpha = self.lastAlpha + 2 * elapsed;
self.lastAlpha = alpha;
if alpha >= self.toAlpha then
alpha = self.toAlpha;
self:Hide();
end
self.object1:SetAlpha(alpha);
self.object2:SetAlpha(alpha);
end);
function ScrollBoundMarkUpdater:Start()
self.lastAlpha = 0; --self.object1:GetAlpha();
self.toAlpha = 0.5;
self:Show();
end
function ScrollBoundMarkUpdater:Stop()
self:Hide();
end
local function UpdateScrollBoundMark(ScrollFrame)
--local ScrollFrame = MainFrame.activeCategory;
local scrollValue = ScrollFrame.scrollBar:GetValue();
local a, b = ScrollFrame.scrollBar:GetMinMaxValues();
local isTop = scrollValue <= 0.1;
local isBottom = scrollValue + 0.1 >= b;
local numButtons = NUM_ACTIVE_BUTTONS or 0;
ScrollFrame.BoundTop:SetShown(not isTop);
ScrollFrame.BoundBottom:SetShown(not isBottom);
ScrollFrame.BoundTop:SetAlpha(0);
ScrollFrame.BoundBottom:SetAlpha(0);
ScrollBoundMarkUpdater:Start();
end
local function UpdateScrollRange(ScrollFrame)
if not ScrollFrame then
ScrollFrame = MainFrame.activeCategory;
end
local range;
local numButtons = NUM_ACTIVE_BUTTONS;
if numButtons == 0 then
range = 0;
else
range = (64 + 16) * numButtons -16 - ScrollFrame:GetHeight() + 14; --the active sex is not neccessarily male, just use the male buttons for height referencing
if range < 0 then
range = 0;
end
end
local scrollBar = ScrollFrame.scrollBar;
scrollBar:SetMinMaxValues(0, range);
ScrollFrame.range = range;
scrollBar:SetShown(range ~= 0);
UpdateScrollButtonAlpha(ScrollButtonAlphaUpdater.activeButtons);
UpdateScrollBoundMark(ScrollFrame);
if numButtons >= MAX_SAVES then
PlusButton:SetCase(3);
end
end
local function CreateSavedLooksButton(ScrollFrame, sex, isWorgen)
local button;
local buttons = {};
local ScrollChild = ScrollFrame.ScrollChild;
local buttonHeight = 64;
local frameHeight = 4 * (buttonHeight + 16) - 2;
ScrollFrame:SetSize(280, frameHeight);
ScrollChild:SetSize(280, frameHeight);
for i = 1, MAX_SAVES do
button = CreateFrame("Button", nil, ScrollFrame.ClipFrame, "NarciBarberShopSavedLooksTemplate");
tinsert(buttons, button);
button:SetPoint("TOPLEFT", ScrollChild, "TOPLEFT", 0, -8 + (buttonHeight + 16)*(1 - i));
button.order = i;
button:Hide();
end
local deltaRatio = 1;
local speedRatio = 0.14;
local range = buttons[1]:GetTop() - buttons[MAX_SAVES]:GetBottom() - ScrollFrame:GetHeight() + 14;
local parentScrollFunc;
local positionFunc = function(endValue, delta, scrollBar, isTop, isBottom)
ScrollButtonAlphaUpdater:Start();
ScrollFrame.BoundTop:SetShown(not isTop);
ScrollFrame.BoundBottom:SetShown(not isBottom);
ScrollBoundMarkUpdater:Stop();
ScrollFrame.BoundTop:SetAlpha(0.0);
ScrollFrame.BoundBottom:SetAlpha(0.0);
ScrollFrame.BoundTop:StopAnimating();
ScrollFrame.BoundBottom:StopAnimating();
end;
local onScrollFinishedFunc = function()
ScrollButtonAlphaUpdater:Stop();
ScrollBoundMarkUpdater:Start();
ScrollFrame.BoundTop.BoundTopArrow.spring:Play();
ScrollFrame.BoundBottom.BoundBottomArrow.spring:Play();
end
ScrollBoundMarkUpdater.object1 = ScrollFrame.BoundTop;
ScrollBoundMarkUpdater.object2 = ScrollFrame.BoundBottom;
NarciAPI_ApplySmoothScrollToScrollFrame(ScrollFrame, deltaRatio, speedRatio, positionFunc, (buttonHeight + 16), range, parentScrollFunc, onScrollFinishedFunc);
if sex == "male" then
if isWorgen then
WorgenMaleButtons = buttons;
else
MaleButtons = buttons;
end
else
if isWorgen then
WorgenFemaleButtons = buttons;
else
FemaleButtons = buttons;
end
end
end
local function GetOrcCameraProfile(model)
local fileID = model:GetModelFileID();
if fileID == 1968587 then
--Upright
return CAMERA_PROFILES_BY_RACE.uprightorc.male
elseif fileID == 917116 then
--Regular Orc and Maghar: 917116
return CAMERA_PROFILES_BY_RACE.orc.male
else
return ACTIVE_CAMERA_PROFILE
end
end
local function GetWorgenCameraProfile(model)
local fileID = model:GetModelFileID();
if fileID == 307453 then
return CAMERA_PROFILES_BY_RACE.worgen.female
elseif fileID == 307454 then
return CAMERA_PROFILES_BY_RACE.worgen.male
elseif fileID == 1000764 then
return CAMERA_PROFILES_BY_RACE.human.female
else
return CAMERA_PROFILES_BY_RACE.human.male
end
end
local function UpdatePortraitCameraGeneric(model, profile)
if not profile then
profile = ACTIVE_CAMERA_PROFILE;
end
if not profile then return end;
local modelX, modelY, modelZ, modelFacing = unpack(profile);
if modelFacing then
model:MakeCurrentCameraCustom();
model:SetFacing(modelFacing);
model:SetPosition(modelX, modelY, modelZ);
local cameraX, cameraY, cameraZ = model:TransformCameraSpaceToModelSpace(4, 0, 0);
local targetX, targetY, targetZ = model:TransformCameraSpaceToModelSpace(0, 0, 0);
model:SetCameraPosition(cameraX, cameraY, cameraZ);
model:SetCameraTarget(targetX, targetY, targetZ);
return true
end
end
local UpdatePortraitCamera = UpdatePortraitCameraGeneric;
local function UpdatePortraitCameraForOrc(model)
UpdatePortraitCameraGeneric(model, GetOrcCameraProfile(model))
end
local function UpdatePortraitCameraForWorgen(model)
UpdatePortraitCameraGeneric(model, GetWorgenCameraProfile(model))
end
local IS_PLAYER_WORGEN, IS_HUMAN_FORM = false, false;
local DataProvider = {};
DataProvider.numMales = 0;
DataProvider.numFemales = 0;
DataProvider.numWorgenMales = 0;
DataProvider.numWorgenFemales = 0;
DataProvider.maleButtonOrder = {};
DataProvider.femaleButtonOrder = {};
DataProvider.worgenMaleButtonOrder = {};
DataProvider.worgenFemaleButtonOrder = {};
function DataProvider:GetCurrentSelection(customizationData, generateDescription)
customizationData = customizationData or C_BarberShop.GetAvailableCustomizations();
if not customizationData then
return
end
local numCatetroy = #customizationData;
local options, optionName, optionID, cuurentChoiceIndex, choice, choiceName, choiceID;
local selectedOptions = {};
local description = "";
local addComma = false;
for i = 1, numCatetroy do
options = customizationData[i].options;
local numOptions = #options;
for j = 1, numOptions do
optionName = options[j].name;
optionID = options[j].id;
cuurentChoiceIndex = options[j].currentChoiceIndex or 1;
choice = options[j].choices[cuurentChoiceIndex];
choiceName = choice.name or "";
choiceID = choice.id;
--print(optionName.."("..optionID.."): "..choiceName.."("..choiceID..")");
tinsert(selectedOptions, {optionID, choiceID} );
if generateDescription then
if choiceName ~= "" and choiceName ~= "None" then
if addComma then
description = description..", ";
else
addComma = true;
end
description = description.. choiceName.." "..optionName;
end
end
end
end
return selectedOptions, description
end
--sex 0 - Male 1- Female C_BarberShop.SetSelectedSex;
function DataProvider:LoadData()
local _, _, raceID = UnitRace("player");
self.raceID = raceID or 1;
if not NarciBarberShopDB then
NarciBarberShopDB = {};
end
local DB = NarciBarberShopDB;
--wipe(DB) --!!TEST
if not DB.PlayerData then
DB.PlayerData = {};
end
local unitType, realmID, playerID = string.split("-", UnitGUID("player"));
if not DB.PlayerData[playerID] then
local playerName = UnitName("player");
local realmName = GetRealmName();
DB.PlayerData[playerID] = { SavedLooks = {} , realmID = realmID, playerName = playerName, realmName = realmName};
end
if not DB.PlayerData[playerID].SavedLooks[raceID] then
DB.PlayerData[playerID].SavedLooks[raceID] = {male = {}, female = {}};
end
self.savedLooksByRace = DB.PlayerData[playerID].SavedLooks[raceID];
local currentCharacterData = C_BarberShop.GetCurrentCharacterData();
local raceName;
if currentCharacterData then
raceName = currentCharacterData.raceData.fileName;
else
raceName = "human";
end
raceName = strlower(raceName);
CreateSavedLooksButton(MainFrame.SavedLooksFrame.CategoryMale, "male");
CreateSavedLooksButton(MainFrame.SavedLooksFrame.CategoryFemale, "female");
--Worgen in human form
if raceID == 22 then
raceID = WORGEN_HUMAN_FORM_ID;
raceName = "human";
IS_PLAYER_WORGEN = true;
if not DB.PlayerData[playerID].SavedLooks[raceID] then
DB.PlayerData[playerID].SavedLooks[raceID] = { male = {}, female = {} };
end
self.savedLooksInHumanForm = DB.PlayerData[playerID].SavedLooks[raceID];
--MainFrame.SavedLooksFrame.CategoryWorgenMale = CreateFrame("ScrollFrame", nil, MainFrame.SavedLooks, "NarciBarberShopScrollFrameTemplate");
--MainFrame.SavedLooksFrame.CategoryWorgenFemale = CreateFrame("ScrollFrame", nil, MainFrame.SavedLooks, "NarciBarberShopScrollFrameTemplate");
CreateSavedLooksButton(MainFrame.SavedLooksFrame.CategoryWorgenMale, "male", IS_PLAYER_WORGEN);
CreateSavedLooksButton(MainFrame.SavedLooksFrame.CategoryWorgenFemale, "female", IS_PLAYER_WORGEN);
UpdatePortraitCamera = UpdatePortraitCameraForWorgen;
end
CAMERA_PROFILE = CAMERA_PROFILES_BY_RACE[raceName];
local sexString;
local useHiRez = true;
local raceAtlasMale = GetRaceAtlas(raceName, "male", useHiRez);
local raceAtlasFemale = GetRaceAtlas(raceName, "female", useHiRez);
if raceName == "orc" or raceName == "magharorc" then
UpdatePortraitCamera = UpdatePortraitCameraForOrc;
end
--NarciDevReferencePortrait:SetAtlas(raceAtlasMale);
self.raceAtlasMale = raceAtlasMale;
self.raceAtlasFemale = raceAtlasFemale;
local maleDB = DB.PlayerData[playerID].SavedLooks[raceID].male;
local femaleDB = DB.PlayerData[playerID].SavedLooks[raceID].female;
local numMales = #maleDB;
local numFemales = #femaleDB;
self.numMales = numMales;
self.numFemales = numFemales;
for i = 1, MAX_SAVES do
self.maleButtonOrder[i] = i;
self.femaleButtonOrder[i] = i;
self.worgenMaleButtonOrder[i] = i;
self.worgenFemaleButtonOrder[i] = i;
end
local function SetUpSavedLooksButton(buttonPool, dataSource, atlas)
for i = 1, #dataSource do
if i <= 4 then
buttonPool[i]:Show();
end
buttonPool[i]:SetInfo(dataSource[i]);
buttonPool[i].Portrait:SetAtlas(atlas);
end
end
SetUpSavedLooksButton(MaleButtons, maleDB, raceAtlasMale);
SetUpSavedLooksButton(FemaleButtons, femaleDB, raceAtlasFemale);
--Worgen
if IS_PLAYER_WORGEN then
raceID = 22;
maleDB = DB.PlayerData[playerID].SavedLooks[raceID].male;
femaleDB = DB.PlayerData[playerID].SavedLooks[raceID].female;
numMales = #maleDB;
numFemales = #femaleDB;
self.numWorgenMales = numMales;
self.numWorgenFemales = numFemales;
raceAtlasMale = GetRaceAtlas("worgen", "male", useHiRez);
raceAtlasFemale = GetRaceAtlas("worgen", "female", useHiRez);
--NarciDevReferencePortrait:SetAtlas(raceAtlasFemale);
SetUpSavedLooksButton(WorgenMaleButtons, maleDB, raceAtlasMale);
SetUpSavedLooksButton(WorgenFemaleButtons, femaleDB, raceAtlasFemale);
end
end
function DataProvider:GetRandomAppearance()
local customizationData = C_BarberShop.GetAvailableCustomizations();
if not customizationData then --Not at the Barber
return
end
local random = math.random;
local selectedOptions = {};
local option, options, optionName, optionID, cuurentChoiceIndex, choice, choiceName, choiceID;
local numCatetroy = #customizationData;
for i = 1, numCatetroy do
options = customizationData[i].options;
local numOptions = #options;
for j = 1, numOptions do
option = options[j];
optionName = option.name;
optionID = option.id;
local numChoices = #option.choices;
choice = option.choices[ random(numChoices) ]
choiceID = choice.id;
tinsert(selectedOptions, {optionID, choiceID} );
end
end
return selectedOptions
end
function DataProvider:IsNewLooksUnique()
local newLooks, generatedDescription = DataProvider:GetCurrentSelection();
if not newLooks then
return
end
local checkOnly = true;
local isUnique = self:CheckAndSaveLooks(newLooks, nil, checkOnly);
return isUnique
end
function DataProvider:IsCharacterDataUnique(customizationData)
local sex = self.currentSex or 0;
local SavedLooks;
local newLooks = self:GetCurrentSelection(customizationData);
if IS_PLAYER_WORGEN then
if IS_HUMAN_FORM then
if sex == 0 then
SavedLooks = self.savedLooksInHumanForm.male;
else
SavedLooks = self.savedLooksInHumanForm.female;
end
else
if sex == 0 then
SavedLooks = self.savedLooksByRace.male;
else
SavedLooks = self.savedLooksByRace.female;
end
end
else
if sex == 0 then
SavedLooks = self.savedLooksByRace.male;
else
SavedLooks = self.savedLooksByRace.female;
end
end
local isUnique = true;
local tempTable = {};
local numLooks = #SavedLooks;
for i = 1, numLooks do
wipe(tempTable);
data = SavedLooks[i].data;
local numData = #data;
for j = 1, numData do
tempTable[ data[j][1] ] = data[j][2];
end
local numSame = 0;
for j = 1, #newLooks do
if tempTable[ newLooks[j][1] ] == newLooks[j][2] then
numSame = numSame + 1;
end
end
if numSame == numData then
isUnique = false;
break
end
end
if isUnique then
if numLooks < MAX_SAVES then
PlusButton:SetCase(1);
else
PlusButton:SetCase(3);
end
else
PlusButton:SetCase(2);
end
end
function DataProvider:CheckAndSaveLooks(newLooks, generatedDescription, checkOnly)
if not newLooks then return false end;
local currentCharacterData = C_BarberShop.GetCurrentCharacterData();
if not currentCharacterData then return false end;
local sex = currentCharacterData.sex;
local SavedLooks;
if IS_PLAYER_WORGEN then
if IS_HUMAN_FORM then
if sex == 0 then
SavedLooks = self.savedLooksInHumanForm.male;
else
SavedLooks = self.savedLooksInHumanForm.female;
end
else
if sex == 0 then
SavedLooks = self.savedLooksByRace.male;
else
SavedLooks = self.savedLooksByRace.female;
end
end
else
if sex == 0 then
SavedLooks = self.savedLooksByRace.male;
else
SavedLooks = self.savedLooksByRace.female;
end
end
local isUnique = true;
local data;
local tempTable = {};
local numLooks = #SavedLooks;
for i = 1, numLooks do
wipe(tempTable);
data = SavedLooks[i].data;
local numData = #data;
for j = 1, numData do
tempTable[ data[j][1] ] = data[j][2];
end
local numSame = 0;
for j = 1, #newLooks do
if tempTable[ newLooks[j][1] ] == newLooks[j][2] then
numSame = numSame + 1;
end
end
if numSame == numData then
isUnique = false;
break
end
end
wipe(tempTable);
numLooks = numLooks + 1;
if numLooks > MAX_SAVES then
return false
end
local looksName = "New Look #"..(numLooks);
if isUnique then
if checkOnly then
return true;
else
if numLooks < MAX_SAVES then
PlusButton:SetCase(2);
else
PlusButton:SetCase(3);
end
local currentTime = time();
tinsert(SavedLooks, 1, {name = looksName , description = generatedDescription, data = newLooks, timeCreated = currentTime});
return SavedLooks[1], numLooks
end
end
end
function DataProvider:SaveNewLooks()
if NUM_ACTIVE_BUTTONS >= MAX_SAVES then
return
end
local generateDescription = true;
local newLooks, generatedDescription = DataProvider:GetCurrentSelection(nil, generateDescription);
local data, numLooks = self:CheckAndSaveLooks(newLooks, generatedDescription);
if data then
NUM_ACTIVE_BUTTONS = numLooks;
if numLooks >= 4 then
ScrollBoundMarkUpdater:Start();
end
return data
else
end
end
local function RepositionButtons(buttonPool)
local _, relativeTo = buttonPool[1]:GetPoint();
local buttonHeight = 64;
local button;
for i = 1, MAX_SAVES do
--buttonPool[ orderTable[i] ]:SetPoint("TOPLEFT", relativeTo, "TOPLEFT", 0, -8 + (buttonHeight + 16)*(1 - i));
button = buttonPool[i];
button:ClearAllPoints();
button:SetPoint("TOPLEFT", relativeTo, "TOPLEFT", 0, -8 + (buttonHeight + 16)*(1 - i));
button.order = i;
end
end
local function InsertButtonToTop(buttonPool, position)
local removedButton = tremove(buttonPool, position);
if removedButton then
for i = #buttonPool, 1, -1 do
buttonPool[i + 1] = buttonPool[i];
end
buttonPool[1] = removedButton;
--RepositionButtons(buttonPool);
end
end
function DataProvider:DeleteLooks(dataSource)
if not dataSource then return end;
local sex = self.currentSex;
local SavedLooks, OrderTable, ButtonPool, categoryID;
if IS_PLAYER_WORGEN then
if IS_HUMAN_FORM then
if sex == 0 then
SavedLooks = self.savedLooksInHumanForm.male;
OrderTable = self.maleButtonOrder;
ButtonPool = MaleButtons;
categoryID = 1;
else
SavedLooks = self.savedLooksInHumanForm.female;
OrderTable = self.femaleButtonOrder;
ButtonPool = FemaleButtons;
categoryID = 2;
end
else
if sex == 0 then
SavedLooks = self.savedLooksByRace.male;
OrderTable = self.worgenMaleButtonOrder;
ButtonPool = WorgenMaleButtons;
categoryID = 3;
else
SavedLooks = self.savedLooksByRace.female;
OrderTable = self.worgenFemaleButtonOrder;
ButtonPool = WorgenFemaleButtons;
categoryID = 4;
end
end
else
if sex == 0 then
SavedLooks = self.savedLooksByRace.male;
OrderTable = self.maleButtonOrder;
ButtonPool = MaleButtons;
categoryID = 1;
else
SavedLooks = self.savedLooksByRace.female;
OrderTable = self.femaleButtonOrder;
ButtonPool = FemaleButtons;
categoryID = 2;
end
end
local numLooks = #SavedLooks;
local position;
for i = 1, numLooks do
if SavedLooks[i] == dataSource then
position = i;
break
end
end
if position then
for i = position, numLooks do
SavedLooks[i] = SavedLooks[i + 1];
end
local removedIndex = tremove(OrderTable, position);
tinsert(OrderTable, removedIndex);
local removedButton = tremove(ButtonPool, position);
removedButton.isPortraitLoaded = false;
tinsert(ButtonPool, removedButton);
--RepositionButtons(ButtonPool);
if categoryID == 1 then
self.numMales = self.numMales - 1;
elseif categoryID == 2 then
self.numFemales = self.numFemales - 1;
elseif categoryID == 3 then
self.numWorgenMales = self.numWorgenMales - 1;
elseif categoryID == 4 then
self.numWorgenFemales = self.numWorgenFemales - 1;
end
NUM_ACTIVE_BUTTONS = NUM_ACTIVE_BUTTONS - 1;
return ButtonPool, removedButton, position
end
end
function DataProvider:GetButton()
local currentCharacterData = C_BarberShop.GetCurrentCharacterData();
if not currentCharacterData then
print("Error: No Character Data");
return
end
local sex = currentCharacterData.sex;
if sex == 0 then
if IS_PLAYER_WORGEN then
if IS_HUMAN_FORM then
self.numMales = self.numMales + 1;
if self.numMales > MAX_SAVES then
self.numMales = MAX_SAVES;
end
InsertButtonToTop(MaleButtons, self.numMales);
return MaleButtons[1], MaleButtons;
else
self.numWorgenMales = self.numWorgenMales + 1;
if self.numWorgenMales > MAX_SAVES then
self.numWorgenMales = MAX_SAVES;
end
InsertButtonToTop(WorgenMaleButtons, self.numWorgenMales);
return WorgenMaleButtons[1], WorgenMaleButtons;
end
else
self.numMales = self.numMales + 1;
if self.numMales > MAX_SAVES then
self.numMales = MAX_SAVES;
end
InsertButtonToTop(MaleButtons, self.numMales);
return MaleButtons[1], MaleButtons;
end
elseif sex == 1 then
if IS_PLAYER_WORGEN then
if IS_HUMAN_FORM then
self.numFemales = self.numFemales + 1;
if self.numFemales > MAX_SAVES then
self.numFemales = MAX_SAVES;
end
InsertButtonToTop(FemaleButtons, self.numFemales);
return FemaleButtons[1], FemaleButtons;
else
self.numWorgenFemales = self.numWorgenFemales + 1;
if self.numWorgenFemales > MAX_SAVES then
self.numWorgenFemales = MAX_SAVES;
end
local index = self.worgenFemaleButtonOrder[self.numWorgenFemales];
InsertButtonToTop(WorgenFemaleButtons, self.numWorgenFemales);
return WorgenFemaleButtons[1], WorgenFemaleButtons;
end
else
self.numFemales = self.numFemales + 1;
if self.numFemales > MAX_SAVES then
self.numFemales = MAX_SAVES;
end
local index = self.femaleButtonOrder[self.numFemales];
InsertButtonToTop(FemaleButtons, self.numFemales);
return FemaleButtons[1], FemaleButtons;
end
else
print("Error: Unknown Gender");
return
end
end
local function RandomizeApperance()
local data = DataProvider:GetRandomAppearance();
if not data then return end;
for i = 1, #data do
local optionID, choiceID = unpack(data[i]);
C_BarberShop.SetCustomizationChoice(optionID, choiceID);
end
BarberShopFrame:UpdateCharCustomizationFrame()
end
-------------------------------------------------------------
NarciBarberShopSavedLooksMixin = {};
local function PortraitModel_OnModelLoaded(self)
self:SetCamera(0);
self:SetPaused(true);
end
function NarciBarberShopSavedLooksMixin:OnLoad()
self.Portrait:SetVertexColor(0.5, 0.5, 0.5);
self.Portrait:SetDesaturation(0.6);
local Model = self.Model;
Model:SetUnit("player");
Model:SetKeepModelOnHide(true);
Model:SetFacing(pi/24);
--Model:SetLight(true, false, -0.707, 0, -0.707, 1, 1, 1, 1, 0.5, 1, 1, 1);
--Model:SetLight(true, false, -0.5124, -0.4872, -0.7071, 1, 1, 1, 1, 0.5, 1, 1, 1);
--Model:SetLight(true, false, - 0.44699833180028 , 0.72403680806459 , -0.52532198881773, 0.8, 1, 1, 1, 1, 0.8, 0.8, 0.8)
Model:SetLight(true, false, cos(pi/4)*sin(-pi/4) , cos(pi/4)*cos(-pi/4) , -cos(pi/4), 1, 0.5, 0.5, 0.5, 1, 0.9, 0.9, 0.9);
Model:SetCamera(0);
self:SetPortraitZoom(1);
Model:SetAnimation(0, 0);
Model:SetPaused(true);
Model:SetScript("OnModelLoaded", function()
Model:SetCamera(0);
Model:SetAnimation(0, 0);
Model:SetPaused(true);
self:SetPortraitZoom(0.975);
self:SetPortraitZoom(1);
end);
Model:SetViewTranslation(0, 0);
--Animation Frame
local animZoom = NarciAPI_CreateAnimationFrame(0.35);
animZoom:SetScript("OnUpdate", function(frame, elapsed)
frame.total = frame.total + elapsed;
local zoom = inOutSine(frame.total, frame.fromZoom, frame.toZoom, frame.duration);
if frame.total >= frame.duration then
zoom = frame.toZoom;
frame:Hide();
end
self:SetPortraitZoom(zoom);
end);
function self:ZoomModel(fromValue, value)
animZoom:Hide();
local currentZoom = self:GetPortraitZoom();
animZoom.fromZoom = currentZoom;
animZoom.toZoom = value;
local duration = sqrt( abs( (currentZoom - value)/0.025) ) * 0.35;
animZoom.duration = duration;
if duration > 0 then
animZoom:Show();
end
end
self:OnLeave();
end
function NarciBarberShopSavedLooksMixin:SetPortraitZoom(value)
self.Model:SetPortraitZoom(value);
self.portraitZoom = value;
end
function NarciBarberShopSavedLooksMixin:GetPortraitZoom(value)
return self.portraitZoom or 1;
end
function NarciBarberShopSavedLooksMixin:RefreshPortrait(forcedRefresh)
if (not self.isPortraitLoaded) or (forcedRefresh) then
self.Model:Show();
self.Portrait:Hide();
self.PortraitText:Hide();
self.isPortraitLoaded = true;
self.Model:RefreshUnit();
UpdatePortraitCamera(self.Model);
end
end
function NarciBarberShopSavedLooksMixin:UpdateText()
local textHeight = self.Name:GetHeight() + self.Description:GetHeight() + 6;
self.Reference:SetHeight(textHeight);
end
function NarciBarberShopSavedLooksMixin:SetInfo(dataSource)
self.dataSource = dataSource;
self.Name:SetText(dataSource.name);
self.Description:SetText(dataSource.description);
self.appearanceData = dataSource.data;
self:UpdateText()
end
function NarciBarberShopSavedLooksMixin:OnEnter()
self.Name:SetAlpha(1);
self.Description:SetAlpha(1);
UIFrameFadeIn(self.RingHighlight, 0.15, self.RingHighlight:GetAlpha(), 1);
MainFrame:FadeIn(0.2);
--self.Model:SetPaused(false); --Playing character idle animation seems distractive, disabled
EditButton:SetParentObject(self);
DeleteButton:SetParentObject(self);
end
function NarciBarberShopSavedLooksMixin:OnLeave()
if self:IsMouseOver() then
return
end
self.Name:SetAlpha(0.66);
self.Description:SetAlpha(0.66);
UIFrameFadeIn(self.RingHighlight, 0.25, self.RingHighlight:GetAlpha(), 0);
MainFrame:OnLeave();
end
function NarciBarberShopSavedLooksMixin:OnClick()
self:UpdateCustomization();
if not self.isPortraitLoaded then
After(0.1, function()
self:RefreshPortrait();
end)
end
end
function NarciBarberShopSavedLooksMixin:LoadPortrait()
self:UpdateCustomization(true);
if not self.isPortraitLoaded then
After(0.1, function()
self:RefreshPortrait();
end)
end
end
local SetCustomizationChoice = C_BarberShop.SetCustomizationChoice;
function NarciBarberShopSavedLooksMixin:UpdateCustomization(dontUpdateButton)
if not self.appearanceData then return end
local BarberShopFrame = BarberShopFrame;
for i = 1, #self.appearanceData do
local optionID, choiceID = unpack(self.appearanceData[i]);
SetCustomizationChoice(optionID, choiceID);
--C_BarberShop.PreviewCustomizationChoice(optionID, choiceID);
end
if not dontUpdateButton then
BarberShopFrame:UpdateCharCustomizationFrame();
end
end
----------------------------------
local DURATION_FADE_OUT = 1.5;
local autoHideTimer = NarciAPI_CreateAnimationFrame(4);
autoHideTimer:SetScript("OnUpdate", function(self, elapsed)
self.total = self.total + elapsed;
if self.total >= self.duration then
self:Hide();
if not MainFrame:IsMouseOver() then
MainFrame:FadeOut(DURATION_FADE_OUT);
end
end
end)
local animScrollFrame = NarciAPI_CreateAnimationFrame(0.25);
animScrollFrame:SetScript("OnUpdate", function(self, elapsed)
self.total = self.total + elapsed;
local offsetY = linear(self.total, self.fromY, 0, self.duration);
if self.total >= self.duration then
self:Hide();
offsetY = 0;
ScrollButtonAlphaUpdater:Stop();
if self.onFinishedFunc then
self.onFinishedFunc();
self.onFinishedFunc = nil;
end
end
self.parentScrollBar:SetValue(offsetY);
end);
function animScrollFrame:ScrollToTop(ScrollFrame)
self:Hide();
local value = ScrollFrame:GetVerticalScroll();
if value == 0 then
return
end
self.parentScrollBar = ScrollFrame.scrollBar;
self.fromY = value;
local duration = sqrt( value/ 400) * 0.25;
self.duration = duration;
ScrollButtonAlphaUpdater:Start();
self:Show();
end
function ScrollToTop(ScrollFrame)
animScrollFrame:ScrollToTop(ScrollFrame)
--/run ScrollToTop(Narci_BarbershopFrame.SavedLooksFrame.CategoryFemale)
end
local animScrollButtons = NarciAPI_CreateAnimationFrame(0.4);
animScrollButtons:SetScript("OnUpdate", function(self, elapsed)
self.total = self.total + elapsed;
local offsetY = outSine(self.total, self.fromY, self.toY, self.duration);
if self.newButton then
local alpha = self.total/0.35;
if alpha > 1 then
alpha = 1;
end
local offsetX = inOutSine(self.total, -32, 0, self.duration);
self.newButton:Show();
self.newButton:SetAlpha(alpha);
if self.total >= self.duration then
offsetX = 0;
offsetY = self.toY;
end
self.newButton:SetPoint("TOPLEFT", self.relativeTo, "TOPLEFT", offsetX, -8);
end
if self.oldButton then
local alpha = 1 - self.total/0.35;
if alpha < 0 then
alpha = 0;
self.oldButton:Hide();
end
local offsetX = outSine(self.total, 0, -120, self.duration);
self.oldButton:SetAlpha(alpha);
if self.total >= self.duration then
offsetX = -64;
end
self.oldButton:SetPoint("TOPLEFT", self.relativeTo, "TOPLEFT", offsetX, self.oldButtonPosY);
end
if self.forthButton then
local alpha = self.fromAlpha - self.total/0.25;
if alpha < 0 then
alpha = 0;
end
self.forthButton:SetAlpha(alpha);
if alpha == 0 then
self.forthButton:Hide();
end
end
if self.total >= self.duration then
offsetY = self.toY;
self:Hide();
MainFrame.ScrollBlocker:Hide();
RepositionButtons(self.buttonPool);
UpdateScrollRange();
ScrollButtonAlphaUpdater:Stop();
end
for i = self.buttonIndex, self.numButtons do
self.buttonPool[i]:SetPoint("TOPLEFT", self.relativeTo, "TOPLEFT", 0, -8 + 80*(1 - i) + offsetY);
end
end)
function animScrollButtons:InsertNewButton(buttonPool, newButton)
self:Hide();
local _, ScrollChild = buttonPool[1]:GetPoint();
self.relativeTo = ScrollChild;
self.buttonPool = buttonPool;
self.numButtons = #buttonPool;
self.buttonIndex = 2;
self.newButton = newButton;
self.forthButton = buttonPool[5];
self.oldButton = nil;
self.fromAlpha = self.forthButton:GetAlpha();
self.fromY = 80;
self.toY = 0;
local ScrollFrame = ScrollChild:GetParent();
if ScrollFrame:GetVerticalScroll() > 0.1 then
--ScrollFrame.scrollBar:SetValue(0);
animScrollFrame.onFinishedFunc = function()
self:Show();
EditBox:SetParentObject(newButton, true);
end
animScrollFrame:ScrollToTop(ScrollFrame);
else
self:Show();
end
MainFrame.ScrollBlocker:Show();
end
function animScrollButtons:RemoveOldButton(buttonPool, button)
self:Hide();
self.forthButton = nil;
self.newButton = nil;
self.oldButton = button;
local _, ScrollChild, _, _, posY = button:GetPoint();
self.oldButtonPosY = posY;
self.buttonIndex = button.order;
self.relativeTo = ScrollChild;
self.buttonPool = buttonPool;
self.numButtons = #buttonPool - 1;
self.fromY = -80;
self.toY = 0;
self:Show();
ScrollButtonAlphaUpdater:Start();
MainFrame.ScrollBlocker:Show();
end
--Click to save new looks
NarciBarberShopPlusButtonMixin = {};
function NarciBarberShopPlusButtonMixin:OnLoad()
PlusButton = self;
self:OnLeave();
self.tooltipDefault = L["Save New Look"];
self.tooltipReachMax = L["No Available Slot"];
self.tooltipSaved = L["Look Saved"];
self.tooltipShapeShifted = L["Cannot Save Forms"];
self:SetCase(1);
end
function NarciBarberShopPlusButtonMixin:OnMouseDown()
if self:IsEnabled() then
self.Background:SetTexCoord(0.25, 0.5, 0, 1);
end
end
function NarciBarberShopPlusButtonMixin:OnMouseUp()
if self:IsEnabled() then
self.Background:SetTexCoord(0, 0.25, 0, 1);
end
end
function NarciBarberShopPlusButtonMixin:OnEnable()
self.Background:SetTexCoord(0, 0.25, 0, 1);
self.Label:SetTextColor(1, 1, 1);
self.Label:SetAlpha(0.66);
end
function NarciBarberShopPlusButtonMixin:OnDisable()
self.Background:SetTexCoord(0.5, 0.75, 0, 1);
self.Label:SetTextColor(0.5, 0.5, 0.5);
end
function NarciBarberShopPlusButtonMixin:SetCase(index)
if index == 1 then
self.Label:SetText(self.tooltipDefault);
self:Enable();
elseif index == 2 then
self.Label:SetText(self.tooltipSaved);
self:Disable();
elseif index == 3 then
self.Label:SetText(self.tooltipReachMax);
self:Disable();
elseif index == 4 then
self.Label:SetText(self.tooltipShapeShifted);
self:Disable();
end
end
function NarciBarberShopPlusButtonMixin:OnEnter()
self.Label:SetAlpha(1);
MainFrame:OnEnter();
EditButton:Hide();
DeleteButton:Hide();
end
function NarciBarberShopPlusButtonMixin:OnLeave()
self.Label:SetAlpha(0.66);
end
function NarciBarberShopPlusButtonMixin:OnClick()
--Save new Looks
local data = DataProvider:SaveNewLooks(self);
if data then
local button, buttonPool = DataProvider:GetButton();
if button then
animScrollButtons:InsertNewButton(buttonPool, button);
button:SetInfo(data);
button:Show();
EditBox:SetParentObject(button, true);
After(0.1, function()
button:RefreshPortrait();
end)
end
end
end
NarciBarberShopEditButtonMixin = {};
function NarciBarberShopEditButtonMixin:OnLoad()
EditButton = self;
self.Icon:SetTexCoord(0.25, 0.5, 0, 1);
self.Icon:SetVertexColor(0.66, 0.66, 0.66);
self.Ring:SetVertexColor(0.66, 0.66, 0.66);
self.Tooltip:SetText(L["Edit Name"]);
end
function NarciBarberShopEditButtonMixin:SetParentObject(object)
self:ClearAllPoints();
self:SetParent(object);
self:SetPoint("BOTTOMRIGHT", object, "RIGHT", 0, 0);
self:Show();
end
function NarciBarberShopEditButtonMixin:EditName()
EditBox:SetParentObject(self:GetParent());
end
function NarciBarberShopEditButtonMixin:OnClick()
self:EditName();
end
function NarciBarberShopEditButtonMixin:OnEnter()
self:GetParent():OnEnter();
self.Tooltip:Show();
end
function NarciBarberShopEditButtonMixin:OnLeave()
MainFrame:OnLeave();
self:GetParent():OnLeave();
self.Tooltip:Hide();
end
function NarciBarberShopEditButtonMixin:OnHide()
self:Hide();
end
function NarciBarberShopEditButtonMixin:OnMouseDown()
self.Icon:SetSize(16, 16);
end
function NarciBarberShopEditButtonMixin:OnMouseUp()
self.Icon:SetSize(20, 20);
end
NarciBarberShopDeleteButtonMixin = {};
function NarciBarberShopDeleteButtonMixin:OnLoad()
DeleteButton = self;
self.Icon:SetTexCoord(0, 0.25, 0, 1);
self.Ring:SetTexCoord(0.25, 0.5, 0, 1);
self.Ring:SetVertexColor(0.85, 0, 0);
self.SemiCircleRight:SetVertexColor(0.85, 0, 0);
self.SemiCircleLeft:SetVertexColor(0.85, 0, 0);
self.Tooltip:SetText(L["Delete Look"]);
self.Tooltip:SetTextColor(1, 0.31, 0.31);
end
function NarciBarberShopDeleteButtonMixin:SetParentObject(object)
self:SetParent(object);
self:Show();
self:OnMouseUp();
end
function NarciBarberShopDeleteButtonMixin:OnClick()
end
function NarciBarberShopDeleteButtonMixin:OnLongClick()
local ButtonPool, removedButton = DataProvider:DeleteLooks(self:GetParent().dataSource);
if ButtonPool then
--self:GetParent():Hide();
DataProvider:IsCharacterDataUnique();
animScrollButtons:RemoveOldButton(ButtonPool, removedButton);
end
end
function NarciBarberShopDeleteButtonMixin:OnEnter()
self:GetParent():OnEnter();
self.Tooltip:Show();
end
function NarciBarberShopDeleteButtonMixin:OnLeave()
MainFrame:OnLeave();
self:GetParent():OnLeave();
self.Tooltip:Hide();
end
function NarciBarberShopDeleteButtonMixin:OnHide()
self:Hide();
end
function NarciBarberShopDeleteButtonMixin:OnMouseDown()
self.Icon:SetSize(16, 16);
self:LockHighlight();
self.SemiCircleLeft:Show();
self.SemiCircleRight:Show();
self.SemiCircleLeft.rotation:Play();
self.SemiCircleRight.rotation:Play();
end
function NarciBarberShopDeleteButtonMixin:OnMouseUp()
self.Icon:SetSize(20, 20);
self:UnlockHighlight();
self.SemiCircleRight:Hide();
self.SemiCircleLeft:Hide();
self:StopAnimating();
end
NarciBarberShopEditBoxMixin = {};
function NarciBarberShopEditBoxMixin:OnLoad()
EditBox = self;
end
function NarciBarberShopEditBoxMixin:SetParentObject(object, alsoHighlightText)
if self.parentObject then
self.parentObject.Name:Show();
self.parentObject:OnLeave();
end
self:ClearAllPoints();
self:SetParent(object);
self:SetPoint("LEFT", object.Name, "LEFT", 0, 0);
self:SetText(object.Name:GetText());
self:Show();
self.parentObject = object;
object.Name:Hide();
if alsoHighlightText then
After(0, function()
self:HighlightText();
end)
end
end
function NarciBarberShopEditBoxMixin:OnEscapePressed()
self.exitByPressingEscape = true;
self:DiscardChanges();
end
function NarciBarberShopEditBoxMixin:OnEnterPressed()
self:ConfirmChanges();
end
function NarciBarberShopEditBoxMixin:OnTextChanged()
local remainingLetters = 36 - self:GetNumLetters(true);
self.LetterCount:SetText(remainingLetters);
if remainingLetters == 0 then
self.LetterCount:SetTextColor(0.85, 0, 0);
elseif remainingLetters <= 12 then
self.LetterCount:SetTextColor(0.96, 0.64, 0.13);
else
self.LetterCount:SetTextColor(0.66, 0.66, 0.66);
end
end
function NarciBarberShopEditBoxMixin:DiscardChanges()
self:Hide();
end
function NarciBarberShopEditBoxMixin:ConfirmChanges()
local text = strtrim(self:GetText() or "");
if text ~= "" then
self.parentObject.Name:SetText(text);
self.parentObject:UpdateText();
self.parentObject.dataSource.name = text;
end
self:Hide();
end
function NarciBarberShopEditBoxMixin:OnShow()
self:SetFocus();
self:SetCursorPosition(100);
end
function NarciBarberShopEditBoxMixin:OnHide()
self:HighlightText(0, 0);
self:ClearFocus();
self:Hide();
if self.parentObject then
self.parentObject.Name:Show();
self.parentObject:OnLeave();
end
end
function NarciBarberShopEditBoxMixin:OnEditFocusGained()
autoHideTimer:Hide();
end
function NarciBarberShopEditBoxMixin:OnEditFocusLost()
if self.exitByPressingEscape then
self.exitByPressingEscape = nil;
self:Hide();
else
self:ConfirmChanges();
end
end
----------------------------------
--Main Frame
--Hotkey
local RotateBarberShopCamera = C_BarberShop.RotateCamera;
local CameraRotator = CreateFrame("Frame");
CameraRotator:Hide();
CameraRotator.speed = 0;
CameraRotator.maxSpeed = 2.5;
CameraRotator.direction = 1; --Counterclockwise
CameraRotator:SetScript("OnUpdate", function(self, elapsed)
local direction = self.direction;
local speed = self.speed + 12 * elapsed * direction;
if direction > 0 then
if speed > self.maxSpeed then
speed = self.maxSpeed;
end
elseif direction < 0 then
if speed <= -self.maxSpeed then
speed = -self.maxSpeed;
end
else
--inertia
if self.lastDirection > 0 then
speed = speed - 16 * elapsed;
if speed <= 0 then
speed = 0;
self.lastDirection = 0;
self:Hide();
end
else
speed = speed + 16 * elapsed;
if speed >= 0 then
speed = 0;
self.lastDirection = 0;
self:Hide();
end
end
end
self.speed = speed;
RotateBarberShopCamera(speed);
end)
local ZoomCamera = C_BarberShop.ZoomCamera;
local CameraZoomer = CreateFrame("Frame");
CameraZoomer:Hide();
CameraZoomer.direction = 1;
CameraZoomer.amountPerSecond = 150;
CameraZoomer:SetScript("OnUpdate", function(self, elapsed)
ZoomCamera( self.direction * self.amountPerSecond * elapsed );
end)
local function RotateBarberShopCameraLeft()
CameraRotator:Hide();
CameraRotator.direction = -1;
CameraRotator.lastDirection = -1;
CameraRotator:Show();
end
local function RotateBarberShopCameraRight()
CameraRotator:Hide();
CameraRotator.direction = 1;
CameraRotator.lastDirection = 1;
CameraRotator:Show();
end
local function StopRotatingCamera()
CameraRotator.direction = 0;
end
local function ZoomCameraIn()
CameraZoomer:Hide();
CameraZoomer.direction = 1;
CameraZoomer:Show();
end
local function ZoomCameraOut()
CameraZoomer:Hide();
CameraZoomer.direction = -1;
CameraZoomer:Show();
end
local function StopZoomingCamera()
CameraZoomer:Hide();
end
local HotkeyList = {
--[key] = {downFunc, upFunc, commandName},
};
local HotkeyManager = {};
HotkeyManager.buttons = {};
HotkeyManager.ignoredKeys = {
LALT = 1,
RALT = 2,
LCTRL = 3,
RCTRL = 4,
LSHIFT = 5,
RSHIFT = 6,
LMETA = 7,
RMETA = 8,
ALT = 9,
CTRL = 10,
SHIFT = 11,
META = 12,
UNKNOWN = true,
BUTTON1 = true,
BUTTON2 = true,
BUTTON3 = true,
};
HotkeyManager.CommandList = {
--[name] = {downFunc, upFunc, defaultKey, customKey},
["RotateLeft"] = {
onMouseDownFunc = RotateBarberShopCameraLeft,
onMouseUpFunc = StopRotatingCamera,
defaultKey = "A",
defaultKeyFrench = "Q",
},
["RotateRight"] = {
onMouseDownFunc = RotateBarberShopCameraRight,
onMouseUpFunc = StopRotatingCamera,
defaultKey = "D",
defaultKeyFrench = "D",
},
["ZoomIn"] = {
onMouseDownFunc = ZoomCameraIn,
onMouseUpFunc = StopZoomingCamera,
defaultKey = "W",
defaultKeyFrench = "Z",
},
["ZoomOut"] = {
onMouseDownFunc = ZoomCameraOut,
onMouseUpFunc = StopZoomingCamera,
defaultKey = "S",
defaultKeyFrench = "S",
},
};
function HotkeyManager:LoadHotkeys()
--Check French Keyboard
--GetOSLocale, GetLocale
local isAZERTY = false;
local key1, key2 = GetBindingKey("MOVEFORWARD");
if key1 == "Z" or key2 == "Z" then
isAZERTY = true;
end
----
local DB = NarciBarberShopDB;
if not DB.Hotkeys then
DB.Hotkeys = {};
end
for command, data in pairs(self.CommandList) do
local key = DB.Hotkeys[command];
if not key then
if isAZERTY then
key = data.defaultKeyFrench;
else
key = data.defaultKey;
end
DB.Hotkeys[command] = key;
end
if key ~= "NONE" then
HotkeyList[key] = {data.onMouseDownFunc, data.onMouseUpFunc, command};
end
end
end
function HotkeyManager:SetHotkey(command, newKey)
if command and self.CommandList[command] then
local overriddenCommand;
--Check conflicted command
for key, v in pairs(HotkeyList) do
if v then
if v[3] == command then
HotkeyList[key] = nil;
elseif key == newKey then
overriddenCommand = v[3];
HotkeyList[key] = nil;
NarciBarberShopDB.Hotkeys[overriddenCommand] = "NONE";
--print("Conflict: "..overriddenCommand)
end
end
end
local success;
if newKey then
if self.ignoredKeys[newKey] then
success = false;
else
HotkeyList[newKey] = {self.CommandList[command].onMouseDownFunc, self.CommandList[command].onMouseUpFunc, command};
NarciBarberShopDB.Hotkeys[command] = newKey;
success = true;
end
else
--An empty newKey will unbind the command
NarciBarberShopDB.Hotkeys[command] = "NONE";
success = true;
end
self:RefreshKeybindingButtons();
return success
end
end
function HotkeyManager:GetHotkey(command)
if command and self.CommandList[command] then
return NarciBarberShopDB.Hotkeys[command];
end
end
function HotkeyManager:RefreshKeybindingButtons()
for i = 1, #self.buttons do
local key = self:GetHotkey(self.buttons[i].command);
self.buttons[i]:SetText( key );
end
end
NarciBarberShopMixin = {};
function NarciBarberShopMixin:OnLoad()
MainFrame = self;
NarciAPI_CreateFadingFrame(self);
end
function NarciBarberShopMixin:OnKeyDown(key)
local funcs = HotkeyList[key];
if funcs and funcs[1] then
funcs[1]();
self:SetPropagateKeyboardInput(false);
else
self:SetPropagateKeyboardInput(true);
end
end
function NarciBarberShopMixin:ToggleNotification(state)
self.checkUniqueness = state;
end
function NarciBarberShopMixin:ToggleRandomizeAppearanceButton(visible)
local button = CharCustomizeFrame.RandomizeAppearanceButton;
if button then
button:SetShown(visible);
button:SetScript("OnClick", RandomizeApperance);
end
end
function NarciBarberShopMixin:OnKeyUp(key)
local funcs = HotkeyList[key];
if funcs and funcs[2] then
funcs[2]();
self:SetPropagateKeyboardInput(false);
else
self:SetPropagateKeyboardInput(true);
end
end
function NarciBarberShopMixin:OnShow()
local _;
_, ScrollFrameCenterY = self.SavedLooksFrame.CategoryMale:GetCenter();
UpdateScrollButtonAlpha(ScrollButtonAlphaUpdater.activeButtons);
end
function NarciBarberShopMixin:OnHide()
ScrollButtonAlphaUpdater:Stop();
CameraZoomer:Hide();
CameraRotator:Hide();
end
function NarciBarberShopMixin:OnEnter()
autoHideTimer:Hide();
self:FadeIn(0.2);
end
function NarciBarberShopMixin:OnLeave()
if not self:IsMouseOver() and not IsMouseButtonDown() then
autoHideTimer:Show();
end
end
local PortraitLoader = CreateFrame("Frame");
PortraitLoader.t = 0;
PortraitLoader.index = 1;
PortraitLoader:Hide();
PortraitLoader:SetScript("OnUpdate", function(self, elapsed)
self.t = self.t + elapsed;
if self.t >= 0.12 then
self.t = 0;
local button = self.buttons[self.index];
if button and button.appearanceData then
button:LoadPortrait();
self.index = self.index + 1;
else
BarberShopFrame:RegisterEvent("BARBER_SHOP_FORCE_CUSTOMIZATIONS_UPDATE");
self:Hide();
local sex = UnitSex("player");
if self.sex == 0 then
if self.isWorgen then
self.isWorgenMaleLoaded = true;
else
self.isMaleLoaded = true;
end
if self.index ~= 1 then
if sex == 2 then
C_BarberShop.ResetCustomizationChoices();
else
BarberShopFrame:UpdateCharCustomizationFrame();
end
end
elseif self.sex == 1 then
if self.isWorgen then
self.isWorgenFemaleLoaded = true;
else
self.isFemaleLoaded = true;
end
if self.index ~= 1 then
if sex == 3 then
C_BarberShop.ResetCustomizationChoices();
else
BarberShopFrame:UpdateCharCustomizationFrame();
end
end
end
self.index = 1;
end
end
end)
function PortraitLoader:Load(sex)
self:Hide();
self.sex = sex;
if IS_PLAYER_WORGEN and not IS_HUMAN_FORM then
self.isWorgen = true;
if sex == 0 and not self.isWorgenMaleLoaded then
self.buttons = WorgenMaleButtons;
After(0, function()
self:Show();
end)
BarberShopFrame:UnregisterEvent("BARBER_SHOP_FORCE_CUSTOMIZATIONS_UPDATE");
BarberShopFrame:UpdateCharCustomizationFrame();
elseif sex == 1 and not self.isWorgenFemaleLoaded then
self.buttons = WorgenFemaleButtons;
After(0, function()
self:Show();
end)
BarberShopFrame:UnregisterEvent("BARBER_SHOP_FORCE_CUSTOMIZATIONS_UPDATE");
BarberShopFrame:UpdateCharCustomizationFrame();
end
else
self.isWorgen = false;
if sex == 0 and not self.isMaleLoaded then
self.buttons = MaleButtons;
After(0, function()
self:Show();
end)
BarberShopFrame:UnregisterEvent("BARBER_SHOP_FORCE_CUSTOMIZATIONS_UPDATE");
BarberShopFrame:UpdateCharCustomizationFrame();
elseif sex == 1 and not self.isFemaleLoaded then
self.buttons = FemaleButtons;
After(0, function()
self:Show();
end)
BarberShopFrame:UnregisterEvent("BARBER_SHOP_FORCE_CUSTOMIZATIONS_UPDATE");
BarberShopFrame:UpdateCharCustomizationFrame();
end
end
end
function NarciBarberShopMixin:ToggleSaves(visible)
--For Shapeshifter
if visible then
self.SavedLooksFrame:Show();
self:FadeIn(0.2);
else
PlusButton:SetCase(4);
self.SavedLooksFrame:Hide();
self:SetAlpha(0);
end
end
function NarciBarberShopMixin:UpdateGenderCategory(sex)
self:FadeIn(0.2);
autoHideTimer:Hide();
autoHideTimer:Show();
if not sex then
local currentCharacterData = C_BarberShop.GetCurrentCharacterData();
if currentCharacterData then
sex = currentCharacterData.sex;
else
print("Error: No Character Data");
return
end
end
DataProvider.currentSex = sex;
if IS_PLAYER_WORGEN then
IS_HUMAN_FORM = C_BarberShop.IsViewingAlteredForm();
if sex == self.lastSex and IS_HUMAN_FORM == self.lastFrom then
return
else
self.lastSex = sex;
self.lastFrom = IS_HUMAN_FORM;
end
else
if sex == self.lastSex then
return
else
self.lastSex = sex;
end
end
local activeCategory;
if sex == 0 then
if IS_PLAYER_WORGEN then
if IS_HUMAN_FORM then
activeCategory = self.SavedLooksFrame.CategoryMale;
self.SavedLooksFrame.CategoryFemale:Hide();
self.SavedLooksFrame.CategoryWorgenMale:Hide();
self.SavedLooksFrame.CategoryWorgenFemale:Hide();
ScrollButtonAlphaUpdater.activeButtons = MaleButtons;
NUM_ACTIVE_BUTTONS = DataProvider.numMales;
ACTIVE_CAMERA_PROFILE = CAMERA_PROFILES_BY_RACE.human.male;
else
activeCategory = self.SavedLooksFrame.CategoryWorgenMale;
self.SavedLooksFrame.CategoryMale:Hide();
self.SavedLooksFrame.CategoryFemale:Hide();
self.SavedLooksFrame.CategoryWorgenFemale:Hide();
ScrollButtonAlphaUpdater.activeButtons = WorgenMaleButtons;
NUM_ACTIVE_BUTTONS = DataProvider.numWorgenMales;
ACTIVE_CAMERA_PROFILE = CAMERA_PROFILES_BY_RACE.worgen.male;
end
else
activeCategory = self.SavedLooksFrame.CategoryMale;
self.SavedLooksFrame.CategoryFemale:Hide();
ScrollButtonAlphaUpdater.activeButtons = MaleButtons;
NUM_ACTIVE_BUTTONS = DataProvider.numMales;
ACTIVE_CAMERA_PROFILE = CAMERA_PROFILE.male;
end
else
if IS_PLAYER_WORGEN then
if IS_HUMAN_FORM then
activeCategory = self.SavedLooksFrame.CategoryFemale;
self.SavedLooksFrame.CategoryMale:Hide();
self.SavedLooksFrame.CategoryWorgenMale:Hide();
self.SavedLooksFrame.CategoryWorgenFemale:Hide();
ScrollButtonAlphaUpdater.activeButtons = FemaleButtons;
NUM_ACTIVE_BUTTONS = DataProvider.numFemales;
ACTIVE_CAMERA_PROFILE = CAMERA_PROFILES_BY_RACE.human.female;
else
activeCategory = self.SavedLooksFrame.CategoryWorgenFemale;
self.SavedLooksFrame.CategoryMale:Hide();
self.SavedLooksFrame.CategoryFemale:Hide();
self.SavedLooksFrame.CategoryWorgenMale:Hide();
ScrollButtonAlphaUpdater.activeButtons = WorgenFemaleButtons;
NUM_ACTIVE_BUTTONS = DataProvider.numWorgenFemales;
ACTIVE_CAMERA_PROFILE = CAMERA_PROFILES_BY_RACE.worgen.female;
end
else
activeCategory = self.SavedLooksFrame.CategoryFemale;
self.SavedLooksFrame.CategoryMale:Hide();
ScrollButtonAlphaUpdater.activeButtons = FemaleButtons;
NUM_ACTIVE_BUTTONS = DataProvider.numFemales;
ACTIVE_CAMERA_PROFILE = CAMERA_PROFILE.female;
end
end
self.activeCategory = activeCategory;
PortraitLoader:Load(sex);
activeCategory:Show();
ScrollBoundMarkUpdater:Hide();
ScrollBoundMarkUpdater.object1 = activeCategory.BoundTop;
ScrollBoundMarkUpdater.object2 = activeCategory.BoundBottom;
UpdateScrollRange(activeCategory);
end
-----------------------------------------------------------------
local function InitializeBarberShopFrame()
local frame = Narci_BarbershopFrame;
frame:ClearAllPoints();
frame:SetParent(BarberShopFrame);
frame:SetPoint("TOPLEFT", BarberShopFrame, "TOPLEFT", 0, -95);
frame:ToggleRandomizeAppearanceButton(true);
frame:Show();
--Yogg-Salon Mockup
if false then --Narci_InteractiveSplash
local MoneyFrame = CreateFrame("Frame", nil, BarberShopFrame, "NarciBarberShopDiscountMoneyFrameTemplate");
MoneyFrame:ClearAllPoints();
local PriceFrame = BarberShopFrame.PriceFrame;
if not PriceFrame then return end;
function PriceFrame:SetFakeAmount(rawCopper)
self.rawCopper = rawCopper;
local gold = floor(rawCopper / (COPPER_PER_SILVER * SILVER_PER_GOLD));
local silver = floor((rawCopper - (gold * COPPER_PER_SILVER * SILVER_PER_GOLD)) / COPPER_PER_SILVER);
local copper = mod(rawCopper, COPPER_PER_SILVER);
self.GoldDisplay:SetAmount(gold);
self.SilverDisplay:SetAmount(silver);
self.CopperDisplay:SetAmount(copper);
if self.resizeToFit then
self:UpdateWidth();
else
self:UpdateAnchoring();
end
end
local isDiscountEnabled = true;
MoneyFrame:SetScript("OnEnter", function(self)
local tooltip = CharCustomizeNoHeaderTooltip;
if tooltip then
tooltip:SetOwner(self, "ANCHOR_NONE");
tooltip:SetPoint("BOTTOM", self, "TOP", 0, 4);
tooltip:AddLine("|cffec008cYogg Salon|r Special Offer Day", 1, 0.82, 0, true, 0);
tooltip:AddLine("(Right click to refuse Offer.)", 0.5, 0.5, 0.5, true, 0);
tooltip:Show();
end
end);
MoneyFrame:SetScript("OnLeave", function(self)
local tooltip = CharCustomizeNoHeaderTooltip;
if tooltip then
tooltip:Hide();
end
end);
MoneyFrame:SetScript("OnMouseDown", function(self, button)
if button == "RightButton" then
self:Hide();
isDiscountEnabled = false;
PriceFrame:SetFakeAmount( 0.999*(PriceFrame.rawCopper or 0) );
end
end);
MoneyFrame:SetFrameLevel(PriceFrame:GetFrameLevel() + 1);
MoneyFrame:SetPoint("BOTTOM", PriceFrame, "TOP", 0, 4);
MoneyFrame.RedLine:ClearAllPoints();
MoneyFrame.RedLine:SetPoint("LEFT", PriceFrame, "LEFT", -2, 0);
MoneyFrame.RedLine:SetPoint("RIGHT", PriceFrame, "RIGHT", 2, 0);
hooksecurefunc(PriceFrame, "SetAmount", function(self, rawCopper)
if isDiscountEnabled then
MoneyFrame:SetShown(rawCopper ~= 0);
MoneyFrame:SetAmount(rawCopper);
self:SetFakeAmount(rawCopper / 0.999);
end
end);
end
--The WoW default action is automatically closing the BarberShopFrame
--But here we want to check if the newly applied appearance is unique and notifiy user to save it
BarberShopFrame:UnregisterEvent("BARBER_SHOP_APPEARANCE_APPLIED");
SettingFrame:Initialize();
end
--/run TestPlayerModel:SetZoomDistance()
local function RefreshModel()
After(0.1, function()
TestPlayerModel:RefreshUnit();
end)
end
local function HookMixin()
--[[
hooksecurefunc(CharCustomizeFrame, "SetCustomizationChoice", function(self, optionID, choiceID)
print("Set ",optionID, choiceID)
end)
hooksecurefunc(CharCustomizeFrame, "PreviewCustomizationChoice", function(self, optionID, choiceID)
print("Preview ", optionID, choiceID)
end)
--]]
hooksecurefunc(C_BarberShop, "SetSelectedSex", function(sexID)
MainFrame:UpdateGenderCategory(sexID);
end);
hooksecurefunc(C_BarberShop, "SetViewingShapeshiftForm", function(formID)
if formID then
MainFrame:ToggleSaves(false);
else
MainFrame:ToggleSaves(true);
end
end);
if IS_PLAYER_WORGEN then
hooksecurefunc(C_BarberShop, "SetViewingAlteredForm", function(viewingAlteredForm)
MainFrame:UpdateGenderCategory();
end);
end
--Add looks uniqueness check
--Constantly monitor this mixin!!
function BarberShopFrame:UpdateCharCustomizationFrame(alsoReset)
local customizationCategoryData = C_BarberShop.GetAvailableCustomizations();
if not customizationCategoryData then
return;
end
DataProvider:IsCharacterDataUnique(customizationCategoryData);
if alsoReset then
CharCustomizeFrame:Reset();
end
CharCustomizeFrame:SetCustomizations(customizationCategoryData);
self:UpdatePrice();
end
end
------------------------------------------------------------------------------
--Statistics
local StatManager = {};
StatManager.widgets = {};
StatManager.LocationFrames = {};
function StatManager:LoadData()
if not NarciStatisticsDB_PC.Barbershop then
NarciStatisticsDB_PC.Barbershop = {};
end
if not NarciStatisticsDB_PC.Barbershop.Locations then
NarciStatisticsDB_PC.Barbershop.Locations = {}; --[mapID] = {visit, time};
end
self.DB = NarciStatisticsDB_PC.Barbershop;
end
function StatManager:StartTimer()
self.startTime = time();
end
function StatManager:StopTimer()
if self.startTime then
local stopTime = time();
local duration = stopTime - self.startTime;
self.startTime = 0;
local mapID = self.mapID;
if mapID then
self.DB.Locations[mapID].time = self.DB.Locations[mapID].time + duration;
end
end
end
function StatManager:UpdateLocationFrame()
local Locations = self.DB.Locations;
local list = {};
for mapID, data in pairs(Locations) do
tinsert(list, {mapID, data.visit, data.time});
end
if #list > 0 then
table.sort(list, function(a, b) return a[1] < b[1] end );
local timestamp = time();
local mapID = self.mapID;
for i = 1, #list do
local widget = self.LocationFrames[i];
if not widget then
widget = CreateFrame("Frame", nil, self.StatFrame, "NarciBarberShopStatsLocationFrameTemplate");
if i == 1 then
widget:SetPoint("TOP", self.widgets.LocationHeader, "BOTTOM", 0, 16*(1 - i));
else
widget:SetPoint("TOP", self.LocationFrames[i - 1], "BOTTOM", 0, 0);
end
self.LocationFrames[i] = widget;
end
widget:SetLocation(list[i][1]);
widget:SetValue(list[i][2], list[i][3], timestamp);
if list[i][1] == mapID then
widget:StartTimer();
else
widget:StopTimer();
end
end
end
end
function StatManager:UpdateLocationFramesHeight()
local numFrames = #self.LocationFrames;
if numFrames > 0 then
local height = self.LocationFrames[1]:GetTop() - self.LocationFrames[numFrames]:GetBottom() + 100;
self.StatFrame.tabHeight = self.StatFrame.basicHeight + height;
if self.StatFrame:IsShown() then
SettingFrame:SelectTab(self.StatFrame);
end
return height
else
return 0
end
end
function StatManager:UpdateZone()
local mapID = C_Map.GetBestMapForUnit("player");
self.mapID = mapID;
if mapID then
--print(C_Map.GetMapInfo(mapID).name);
if not self.DB.Locations[mapID] then
self.DB.Locations[mapID] = { visit = 0, time = 0 };
end
self.DB.Locations[mapID].visit = self.DB.Locations[mapID].visit + 1;
self:UpdateLocationFrame();
self:UpdateLocationFramesHeight();
end
end
function StatManager:OnBarberShopOpen()
After(0.1, function()
self:UpdateZone();
self:StartTimer();
self:UpdateMoney();
end)
end
function StatManager:OnBarberShopClose()
self:StopTimer();
end
function StatManager:UpdateMoney()
local moneyLifetime = GetStatistic(1147);
local copperLifetime;
if moneyLifetime then
--"544|TInterface\\MoneyFrame\\UI-GoldIcon:0:0:2:0|t"
local gold = string.match(moneyLifetime, "(%d+)|TInterface\\MoneyFrame\\UI%-GoldIcon") or 0;
local silver = string.match(moneyLifetime, "(%d+)|TInterface\\MoneyFrame\\UI%-SilverIcon") or 0;
local copper = string.match(moneyLifetime, "(%d+)|TInterface\\MoneyFrame\\UI%-CopperIcon") or 0;
local rawCopper = 10000 * gold + 100 * silver + copper;
self.widgets.CoinsSpentLifetime:SetAmount(rawCopper);
if not self.DB.CoinSpentBeforeShadowlands then
self.DB.CoinSpentBeforeShadowlands = rawCopper;
end
local diff = rawCopper - self.DB.CoinSpentBeforeShadowlands;
self.widgets.CoinsSpentSinceShadowlands:SetAmount(diff);
else
copperLifetime = 0;
end
end
local EventListener = CreateFrame("Frame");
local events = {"BARBER_SHOP_COST_UPDATE", "BARBER_SHOP_FORCE_CUSTOMIZATIONS_UPDATE", "BARBER_SHOP_RESULT", "BARBER_SHOP_OPEN", "BARBER_SHOP_CLOSE", "BARBER_SHOP_APPEARANCE_APPLIED", "ADDON_LOADED"}; --"UNIT_MODEL_CHANGED"
for i = 1, #events do
EventListener:RegisterEvent(events[i])
end
EventListener:SetScript("OnEvent", function(self, event, ...)
if event == "ADDON_LOADED" then
local name = ...;
--Blizzard_CharacterCustomize
--Blizzard_BarbershopUI
if name == "Narcissus_Barbershop" then --Narcissus_Barbershop
self:UnregisterEvent(event);
if not IsAddOnLoaded("Blizzard_BarbershopUI") then
print("Narcissus Error: Blizzard_BarbershopUI not loaded!");
self:UnregisterAllEvents();
return
end
DataProvider:LoadData();
HotkeyManager:LoadHotkeys();
StatManager:LoadData();
HookMixin();
InitializeBarberShopFrame();
MainFrame:UpdateGenderCategory();
StatManager:OnBarberShopOpen();
end
elseif event == "BARBER_SHOP_OPEN" then
MainFrame:UpdateGenderCategory();
StatManager:OnBarberShopOpen();
elseif event == "BARBER_SHOP_CLOSE" then
PortraitLoader:Hide();
StatManager:OnBarberShopClose();
elseif event == "BARBER_SHOP_FORCE_CUSTOMIZATIONS_UPDATE" then
--MainFrame:UpdateGenderCategory();
elseif event == "BARBER_SHOP_APPEARANCE_APPLIED" then
if MainFrame.checkUniqueness and DataProvider:IsNewLooksUnique() then
BarberShopFrame:UpdateCharCustomizationFrame();
else
BarberShopFrame:Cancel();
end
StatManager:UpdateMoney();
end
end)
-------------------------------------------------------
--Settings
local TabButtons = {};
NarciBarberShopSettingTabButtonMixin = {};
function NarciBarberShopSettingTabButtonMixin:OnLoad()
tinsert(TabButtons, self);
end
function NarciBarberShopSettingTabButtonMixin:OnEnter()
if not self.isSelected then
self.ButtonText:SetTextColor(1, 1, 1);
end
end
function NarciBarberShopSettingTabButtonMixin:OnLeave()
if not self.isSelected then
self.ButtonText:SetTextColor(0.5, 0.5, 0.5);
end
end
function NarciBarberShopSettingTabButtonMixin:SetSelection(isSelected)
self.isSelected = isSelected;
SettingFrame:ScrollToTop();
if isSelected then
self.ButtonText:SetTextColor(1, 0.82, 0);
SettingFrame:SelectTab(self.Tab);
else
self:OnLeave();
if self.Tab then
self.Tab:Hide();
end
end
end
function NarciBarberShopSettingTabButtonMixin:OnClick()
if self.isSelected then return end;
for i = 1, #TabButtons do
TabButtons[i]:SetSelection( TabButtons[i] == self );
end
end
NarciBarberShopSettingCheckBoxMixin = {};
function NarciBarberShopSettingCheckBoxMixin:OnLoad()
self.Box:SetVertexColor(0.8, 0.8, 0.8);
self.Highlight:SetVertexColor(0.5, 0.5, 1);
end
function NarciBarberShopSettingCheckBoxMixin:SetChecked(state)
self.isOn = state;
self.Check:SetShown(state);
if self.onClickFunc then
self.onClickFunc(self.isOn);
end
end
function NarciBarberShopSettingCheckBoxMixin:OnClick()
self.isOn = not self.isOn;
self:SetChecked(self.isOn);
if self.name then
NarciBarberShopDB[self.name] = self.isOn;
end
end
NarciBarberShopSettingKeyBindingButtonMixin = {};
function NarciBarberShopSettingKeyBindingButtonMixin:OnLoad()
tinsert(HotkeyManager.buttons, self);
self:OnLeave();
end
function NarciBarberShopSettingKeyBindingButtonMixin:OnEnter()
self.Background:SetVertexColor(1, 1, 1);
end
function NarciBarberShopSettingKeyBindingButtonMixin:OnLeave()
if not self.isOn then
self.Background:SetVertexColor(0.6, 0.6, 0.6);
end
end
function NarciBarberShopSettingKeyBindingButtonMixin:Activate()
self.Background:SetTexCoord(0, 1, 0.5, 1);
self.ButtonText:SetTextColor(0, 0, 0);
self:SetScript("OnKeyDown", function(self, key)
self:Deactivate();
if HotkeyManager:SetHotkey(self.command, key) then
self:SetText(key);
end
end);
self:SetPropagateKeyboardInput(false);
self:RegisterEvent("GLOBAL_MOUSE_DOWN");
end
function NarciBarberShopSettingKeyBindingButtonMixin:Deactivate()
self.Background:SetTexCoord(0, 1, 0, 0.5);
self.ButtonText:SetTextColor(1, 0.82, 0);
self:SetScript("OnKeyDown", nil);
self.isOn = false;
self:UnregisterEvent("GLOBAL_MOUSE_DOWN");
end
function NarciBarberShopSettingKeyBindingButtonMixin:OnClick(button)
if button == "RightButton" then
HotkeyManager:SetHotkey(self.command, nil);
self:SetText("NONE");
else
self.isOn = not self.isOn;
if self.isOn then
self:Activate();
else
self:Deactivate();
end
end
end
function NarciBarberShopSettingKeyBindingButtonMixin:OnEvent()
if not self:IsMouseOver() then
self:Deactivate();
end
end
function NarciBarberShopSettingKeyBindingButtonMixin:OnHide()
if self.isOn then
self:Deactivate();
end
end
local TabData = {
{ name= "General", order = 1, localizedName = GENERAL,
layout = {
{ name = "ToggleNotification", type = "checkbox", localizedName = L["Save Notify"], defaultState = true, onClickFunc = function(state) MainFrame:ToggleNotification(state) end },
{ name = "ToggleRandomAppearance", type = "checkbox", localizedName = L["Show Randomize Button"], defaultState = false, onClickFunc = function(state) MainFrame:ToggleRandomizeAppearanceButton(state) end }, --RANDOMIZE_APPEARANCE
},
},
{ name = "Shortcuts", order = 2, localizedName = NARCI_SHORTCUTS,
layout = {
{ name = "Camera", type = "header", localizedName = CAMERA_LABEL },
{ name = "RotateLeft", type = "keybinding", localizedName = ROTATE_LEFT},
{ name = "RotateRight", type = "keybinding", localizedName = ROTATE_RIGHT},
{ name = "ZoomIn", type = "keybinding", localizedName = ZOOM_IN},
{ name = "ZoomOut", type = "keybinding", localizedName = ZOOM_OUT},
},
},
{ name = "Profiles", order = 3, localizedName = L["Profiles"],
layout = {
{ name = "Notes", type = "header", localizedName = "Profile management will be availible in the next update.\nAt this moment you cannot access the appearances that were created by your other characters.", anchor = "LEFT" },
},
},
{ name = "Statistics", order = 0, localizedName = STATISTICS,
layout = {
{ name = "Money", type = "header", localizedName = L["Coins Spent"] },
{ name = "CoinsSpentSinceShadowlands", type="money", localizedName = "9.0+", tooltip = "Coins spent since 9.0"},
{ name = "CoinsSpentLifetime", type="money", localizedName = HONOR_LIFETIME, tooltip = "Coins spent during lifetime"},
{ name = "Blank", type="header", localizedName=" ",},
{ name = "LocationHeader", type = "location", localizedName = L["Locations"] },
},
},
}
local function CreateTabs(frame)
local Data;
for i = 1, #TabData do
Data = TabData[i];
local button = CreateFrame("Button", nil, frame, "NarciBarberShopSettingTabButtonTemplate");
local order = Data.order;
button.order = order;
if order ~= 0 then
button:SetPoint("TOPLEFT", frame, "TOPLEFT", 12, -12 + 16 *(1 - i));
else
button:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 12, 12);
end
button:SetText(Data.name);
if Data.layout then
local totalHeight = 8;
local objects = {};
local ScrollFrame = frame.ScrollFrame;
local Tab = CreateFrame("Frame", nil, ScrollFrame);
button.Tab = Tab;
if order == 0 then
StatManager.StatFrame = Tab;
end
Tab:SetSize(ScrollFrame:GetSize());
Tab:SetPoint("TOPLEFT", frame.ScrollFrame.ScrollChild, "TOPLEFT", 0, 0);
for j = 1, #Data.layout do
local type = Data.layout[j].type;
local object;
if type == "checkbox" then
object = CreateFrame("Button", nil, Tab, "NarciBarberShopSettingCheckBoxTemplate");
object.onClickFunc = Data.layout[j].onClickFunc;
object.Label:SetText(Data.layout[j].localizedName);
object:SetPoint("TOPLEFT", Tab, "TOPLEFT", 8, -totalHeight);
local textHeight = object.Label:GetHeight() or 12;
object:SetHeight(textHeight + 2);
totalHeight = totalHeight + textHeight + 12;
--Load settings
local dbName = Data.layout[j].name;
object.name = dbName;
if NarciBarberShopDB[dbName] == nil then
NarciBarberShopDB[dbName] = Data.layout[j].defaultState;
end
object:SetChecked(NarciBarberShopDB[dbName]);
elseif type == "keybinding" then
object = CreateFrame("Button", nil, Tab, "NarciBarberShopSettingKeyBindingButtonTemplate");
object.Label:SetText(Data.layout[j].localizedName);
object.command = Data.layout[j].name;
object:SetPoint("TOPRIGHT", Tab, "TOPRIGHT", -60, -totalHeight);
local textHeight = object.Label:GetHeight() or 12;
totalHeight = totalHeight + textHeight + 12;
object:SetText(HotkeyManager:GetHotkey(object.command));
elseif type == "header" then
object = Tab:CreateFontString(nil, "OVERLAY", "SystemFont_Tiny");
object:SetText(Data.layout[j].localizedName);
if Data.layout[j].anchor then
object:SetJustifyH("LEFT");
else
object:SetJustifyH("CENTER");
end
object:SetSpacing(2);
object:SetJustifyV("TOP");
object:SetPoint("TOP", Tab, "TOP", 0, -totalHeight);
object:SetTextColor(0.5, 0.5, 0.5);
object:SetWidth(270);
totalHeight = totalHeight + 16;
elseif type == "money" then
object = CreateFrame("Frame", nil, Tab, "NarciBarberShopStatsMoneyFrameTemplate");
object:SetPoint("TOPLEFT", Tab, "TOPLEFT", 8, -totalHeight);
object:SetLabel(Data.layout[j].localizedName);
local textHeight = object.Label:GetHeight() or 12;
totalHeight = totalHeight + textHeight + 8;
StatManager.widgets[Data.layout[j].name] = object;
elseif type == "location" then
object = CreateFrame("Frame", nil, Tab, "NarciBarberShopStatsLocationFrameTemplate");
object:SetPoint("TOPLEFT", Tab, "TOPLEFT", 8, -totalHeight);
object:SetHeader();
totalHeight = totalHeight + 16;
StatManager.widgets[Data.layout[j].name] = object;
end
end
Tab.tabHeight = totalHeight;
Tab.basicHeight = totalHeight;
end
end
end
NarciBarberShopSettingsMixin = CreateFromMixins(NarciChamferedFrameMixin);
function NarciBarberShopSettingsMixin:OnLoad()
SettingFrame = self;
local v = 0.2;
self:SetBorderColor(v, v, v, 1);
self:SetBackgroundColor(0, 0, 0, 1);
self.Divider:SetVertexColor(v, v, v);
self.ScrollFrame.scrollBar.Background:SetVertexColor(v, v, v);
local frameHeight = math.floor(self.ScrollFrame:GetHeight() + 0.5);
self.frameHeight = frameHeight;
local deltaRatio = 1;
local speedRatio = 0.2;
local positionFunc;
local buttonHeight = 40;
local range = 120;
NarciAPI_ApplySmoothScrollToScrollFrame(self.ScrollFrame, deltaRatio, speedRatio, positionFunc, buttonHeight, range);
end
function NarciBarberShopSettingsMixin:Initialize()
CreateTabs(self);
TabButtons[1]:Click();
end
function NarciBarberShopSettingsMixin:OnEvent(event)
if not self:IsMouseOver() and not SettingButton:IsMouseOver() then
self:Hide();
end
end
function NarciBarberShopSettingsMixin:OnShow()
self:RegisterEvent("GLOBAL_MOUSE_DOWN");
end
function NarciBarberShopSettingsMixin:OnHide()
self:Hide();
self:UnregisterEvent("GLOBAL_MOUSE_DOWN");
end
function NarciBarberShopSettingsMixin:Toggle()
self:SetShown(not self:IsShown());
end
function NarciBarberShopSettingsMixin:ScrollToTop()
self.ScrollFrame.scrollBar:SetValue(0);
end
function NarciBarberShopSettingsMixin:SelectTab(tab)
--Update Scroll Range
local frameHeight = math.floor(self.ScrollFrame:GetHeight() + 0.5);
local range;
if tab and tab.tabHeight then
tab:Show();
range = tab.tabHeight - frameHeight;
if range < 4 then
range = 0;
end
else
range = 0;
end
local scrollBar = self.ScrollFrame.scrollBar;
scrollBar:SetMinMaxValues(0, range);
scrollBar:SetShown(range ~= 0);
self.ScrollFrame.range = range;
end
--Click to open Settings
NarciBarberShopSettingButtonMixin = {};
function NarciBarberShopSettingButtonMixin:OnLoad()
SettingButton = self;
self.Label:SetText(SETTINGS);
end
function NarciBarberShopSettingButtonMixin:OnMouseDown()
self.Background:SetTexCoord(0.25, 0.5, 0, 1);
end
function NarciBarberShopSettingButtonMixin:OnMouseUp()
self.Background:SetTexCoord(0, 0.25, 0, 1);
end
function NarciBarberShopSettingButtonMixin:OnEnter()
self.Label:Show();
EditButton:Hide();
DeleteButton:Hide();
end
function NarciBarberShopSettingButtonMixin:OnLeave()
self.Label:Hide();
end
function NarciBarberShopSettingButtonMixin:OnClick()
SettingFrame:Toggle();
end
-----------------------------------------------
--Dev Tool
local function round(number, digit)
digit = digit or 0;
local fold = 10^digit;
return math.floor((number * fold + 0.5))/fold
end
NarciDevToolPortraitMixin = {};
function NarciDevToolPortraitMixin:OnLoad()
if true then return end;
local Model = self.Model;
Model:SetUnit("player");
Model:SetKeepModelOnHide(true);
Model:SetDoBlend(true);
Model:SetFacing(0);
Model:SetLight(true, false, cos(pi/4)*sin(-pi/4) , cos(pi/4)*cos(-pi/4) , -cos(pi/4), 1, 0.5, 0.5, 0.5, 1, 0.9, 0.9, 0.9);
Model:SetCamera(0);
Model:SetPortraitZoom(1);
Model:SetAnimation(0, 0);
Model:SetPaused(true);
self.facing = 0;
self.cameraDistance = 1;
self.cameraPitch = pi/2;
self.translationX, self.translationY = 0, 0;
self.FacingButton:SetScript("OnClick", function(frame, button)
local delta = frame.delta;
if button == "LeftButton" then
delta = - delta;
end
if IsShiftKeyDown() then
delta = 4 * delta;
end
self.facing = Model:GetFacing() + delta;
Model:SetFacing(self.facing);
frame.Value:SetText( round(self.facing, 2) );
end)
--[[
self.CameraPitchButton:SetScript("OnClick", function(frame, button)
local delta = frame.delta;
if button == "RightButton" then
delta = - delta;
end
local cameraPitch = self.cameraPitch + delta;
self.cameraPitch = cameraPitch;
Model:SetCameraPosition( self.cameraDistance*sin(cameraPitch), 0, self.cameraDistance*cos(cameraPitch) + 0.8);
frame.Value:SetText(cameraPitch);
end)
--]]
self.ModelXButton:SetScript("OnClick", function(frame, button)
local delta = frame.delta;
if button == "RightButton" then
delta = - delta;
end
if IsShiftKeyDown() then
delta = 16 * delta;
end
local x, y, z = Model:GetPosition();
Model:SetPosition(x + delta, y, z);
frame.Value:SetText( round(x + delta, 2) );
end)
self.ModelYButton:SetScript("OnClick", function(frame, button)
local delta = frame.delta;
if button == "RightButton" then
delta = - delta;
end
if IsShiftKeyDown() then
delta = 16 * delta;
end
local x, y, z = Model:GetPosition();
Model:SetPosition(x, y + delta, z);
frame.Value:SetText( round(y + delta, 2) );
end)
self.ModelZButton:SetScript("OnClick", function(frame, button)
local delta = frame.delta;
if button == "RightButton" then
delta = - delta;
end
if IsShiftKeyDown() then
delta = 16 * delta;
end
local x, y, z = Model:GetPosition();
Model:SetPosition(x, y, z + delta);
frame.Value:SetText( round(z + delta, 2) );
end)
self.DistanceButton:SetScript("OnClick", function(frame, button)
local delta = frame.delta;
if button == "LeftButton" then
delta = - delta;
end
if IsShiftKeyDown() then
delta = 4 * delta;
end
local cameraDistance = self.cameraDistance + delta;
self.cameraDistance = cameraDistance;
Model:SetCameraPosition( cameraDistance*sin(self.cameraPitch), 0, cameraDistance*cos(self.cameraPitch) + 0.8);
frame.Value:SetText( round(cameraDistance, 4) );
end)
self.OffsetXButton:SetScript("OnClick", function(frame, button)
local delta = frame.delta;
if button == "LeftButton" then
delta = - delta;
end
if IsShiftKeyDown() then
delta = 4 * delta;
end
local x, y = Model:GetViewTranslation();
Model:SetViewTranslation(x + delta, y);
frame.Value:SetText( round(x + delta) );
end)
self.OffsetYButton:SetScript("OnClick", function(frame, button)
local delta = frame.delta;
if button == "RightButton" then
delta = - delta;
end
if IsShiftKeyDown() then
delta = 4 * delta;
end
local x, y = Model:GetViewTranslation();
Model:SetViewTranslation(x, y + delta);
frame.Value:SetText( round(y + delta) );
end)
self.ReloadButton:SetScript("OnClick", function()
self:LoadProfile();
end)
end
function NarciDevToolPortraitMixin:OnShow()
local Model = self.Model;
Model:MakeCurrentCameraCustom();
self.cameraDistance = Model:GetCameraDistance();
self.cameraPitch = pi/2;
--Model:SetCameraPosition( self.cameraDistance*sin(self.cameraPitch), 0, self.cameraDistance*cos(self.cameraPitch) + 0.8);
--Model:SetCameraTarget(0, 0, 0.8);
Model:SetPosition(0, 0, 0);
self.FacingButton.Value:SetText(Model:GetFacing());
self.DistanceButton.Value:SetText(self.cameraDistance);
local x, y = Model:GetViewTranslation();
self.OffsetXButton.Value:SetText(x);
self.OffsetYButton.Value:SetText(y);
end
function NarciDevToolPortraitMixin:LoadProfile(race, sex)
local Model = self.Model;
Model:RefreshUnit();
Model:SetAnimation(0, 0);
Model:SetPaused(true);
Model:MakeCurrentCameraCustom();
if not UpdatePortraitCamera(Model) then
Model:SetFacing(0.52);
local modelX, modelY, modelZ = 3.4, -0.07, -2.09;
Model:SetPosition(modelX, modelY, modelZ);
end
local cameraX, cameraY, cameraZ = Model:TransformCameraSpaceToModelSpace(4, 0, 0);
local targetX, targetY, targetZ = Model:TransformCameraSpaceToModelSpace(0, 0, 0);
Model:SetCameraTarget(targetX, targetY, targetZ);
Model:SetCameraPosition(cameraX, cameraY, cameraZ);
local modelFacing = Model:GetFacing();
local modelPosX, modelPosY, modelPosZ = Model:GetPosition();
self.ModelXButton.Value:SetText(modelPosX);
self.ModelYButton.Value:SetText(modelPosY);
self.ModelZButton.Value:SetText(modelPosZ);
self.FacingButton.Value:SetText(modelFacing);
end
--[[
Statistics
Gold spent at barber shops GetStatistic(1147)
C_MapExplorationInfo.GetExploredAreaIDsAtPosition(109, C_Map.GetPlayerMapPosition(109, "player"))
C_Map.GetMapInfoAtPosition(109, C_Map.GetPlayerMapPosition(109, "player"):GetXY())
--]]