local KEYBOARD_BUCKET_MANAGER --[[ Slider Randomization Helper...all sliders share the sliderObject from the top control, so this just helps cut down on duplicate functions ]]-- local function RandomizeSlider(control, randomizeType) control.sliderObject:Randomize(randomizeType) end --[[ Character Create Slider and Appearance Slider Managers ]]-- -- Manages a collection of sliders with a pool local CharacterCreateSliderManager = ZO_InitializingObject:Subclass() function CharacterCreateSliderManager:Initialize(parent) local function CreateSlider(pool) local control = ZO_ObjectPool_CreateNamedControl("CharacterCreateSlider", "ZO_CharacterCreateSlider_Keyboard", pool, parent) return ZO_CharacterCreateSlider_Keyboard:New(control) end local function CreateAppearanceSlider(pool) local control = ZO_ObjectPool_CreateNamedControl("CharacterCreateAppearanceSlider", "ZO_CharacterCreateSlider_Keyboard", pool, parent) return ZO_CharacterCreateAppearanceSlider_Keyboard:New(control) end local function CreateColorPicker(pool) local control = ZO_ObjectPool_CreateNamedControl("CharacterCreateColorPicker", "ZO_CharacterCreateColorSlider_Keyboard", pool, parent) return ZO_CharacterCreateColorSlider_Keyboard:New(control) end local function CreateDropdown(pool) local control = ZO_ObjectPool_CreateNamedControl("CharacterCreateDropdown", "ZO_CharacterCreateDropDownSlider_Keyboard", pool, parent) return ZO_CharacterCreateDropdownSlider_Keyboard:New(control) end local function ResetSlider(slider) local sliderControl = slider.control KEYBOARD_BUCKET_MANAGER:RemoveControl(sliderControl) sliderControl:SetHidden(true) slider:SetLocked(false) end local function ResetColorPicker(slider) local sliderControl = slider.control KEYBOARD_BUCKET_MANAGER:RemoveControl(sliderControl) ZO_ColorSwatchPicker_Clear(sliderControl:GetNamedChild("Slider")) sliderControl:SetHidden(true) slider:SetLocked(false) end self.pools = { [CHARACTER_CREATE_SLIDER_TYPE_SLIDER] = ZO_ObjectPool:New(CreateSlider, ResetSlider), [CHARACTER_CREATE_SLIDER_TYPE_ICON] = ZO_ObjectPool:New(CreateAppearanceSlider, ResetSlider), [CHARACTER_CREATE_SLIDER_TYPE_COLOR] = ZO_ObjectPool:New(CreateColorPicker, ResetColorPicker), [CHARACTER_CREATE_SLIDER_TYPE_NAMED] = ZO_ObjectPool:New(CreateDropdown, ResetSlider), } end function CharacterCreateSliderManager:AcquireObject(objectType) local pool = self.pools[objectType] if pool then return pool:AcquireObject() end end function CharacterCreateSliderManager:ReleaseAllObjects() for poolType, pool in pairs(self.pools) do pool:ReleaseAllObjects() end end --[[ Creator Control Initialization ]]-- local function FindOrdering(orderingTable, name) for i = 1, #orderingTable do if orderingTable[i] == name then return i end end return 1 end --[[ Character Create Keyboard ]]-- local ZO_CharacterCreate_Keyboard = ZO_CharacterCreate_Base:Subclass() function ZO_CharacterCreate_Keyboard:Initialize(...) ZO_CharacterCreate_Base.Initialize(self, ...) local function HandleZoomChanged(eventCode, zoomInAllowed, zoomOutAllowed) ZO_CharacterCreateZoomIn:SetEnabled(zoomInAllowed) ZO_CharacterCreateZoomOut:SetEnabled(zoomOutAllowed) end EVENT_MANAGER:RegisterForEvent("ZO_CharacterCreate", EVENT_CHARACTER_CREATE_ZOOM_CHANGED, HandleZoomChanged) local function OnStateChanged(oldState, newState) if newState == SCENE_FRAGMENT_SHOWING then self:ResetControls() elseif newState == SCENE_FRAGMENT_HIDING then self:UpdateUnsavedSettings() end end CHARACTER_CREATE_FRAGMENT = ZO_FadeSceneFragment:New(self.control, 300) CHARACTER_CREATE_FRAGMENT:RegisterCallback("StateChange", OnStateChanged) end function ZO_CharacterCreate_Keyboard:UpdateUnsavedSettings() for name, nameTable in pairs(self.controlsByNameCategory) do for category, slider in pairs(nameTable) do ZO_CHARACTERCREATE_MANAGER:SetCharacterUnsavedSetting(name, category, slider:GetValue(), slider:IsLocked()) end end local UNUSED_VALUE = nil ZO_CHARACTERCREATE_MANAGER:SetCharacterUnsavedSetting("triangle", "physique", UNUSED_VALUE, self.physiqueTriangle:IsLocked()) ZO_CHARACTERCREATE_MANAGER:SetCharacterUnsavedSetting("triangle", "face", UNUSED_VALUE, self.faceTriangle:IsLocked()) end function ZO_CharacterCreate_Keyboard:OnCharacterCreateRequested() self.createButton:SetEnabled(false) end do local reasonsThatDisableCreateButton = { [CHARACTER_CREATE_EDIT_ERROR_INVALID_NAME] = true, [CHARACTER_CREATE_EDIT_ERROR_DUPLICATE_NAME] = true, [CHARACTER_CREATE_EDIT_ERROR_NAME_TOO_SHORT] = true, [CHARACTER_CREATE_EDIT_ERROR_NAME_TOO_LONG] = true, } function ZO_CharacterCreate_Keyboard:OnCharacterCreateFailed(reason) local errorReason = GetString("SI_CHARACTERCREATEEDITERROR", reason) -- Show the fact that the character could not be created. ZO_Dialogs_ShowDialog("CHARACTER_CREATE_FAILED_REASON", nil, { mainTextParams = { errorReason } }) if reasonsThatDisableCreateButton[reason] then self.createButton:SetEnabled(false) end end end do local function CreateTriangle(control, setterFn, updaterFn, triangleStringId, topStringId, leftStringId, rightStringId) local triangle = ZO_CharacterCreateTriangle_Keyboard:New(control, setterFn, updaterFn, triangleStringId, topStringId, leftStringId, rightStringId) triangle:SetOnValueChangedCallback(OnCharacterCreateOptionChanged) return triangle end function ZO_CharacterCreate_Keyboard:InitializeControls() self.control.fadeTimeline = ANIMATION_MANAGER:CreateTimelineFromVirtual("CharacterCreateMainControlsFade", self.control) self.bucketsControl = self.control:GetNamedChild("Buckets") self.sliderManager = CharacterCreateSliderManager:New(self.bucketsControl) -- create the radio button groups self.allianceRadioGroup = ZO_RadioButtonGroup:New() self.raceRadioGroup = ZO_RadioButtonGroup:New() self.classRadioGroup = ZO_RadioButtonGroup:New() self.genderRadioGroup = ZO_RadioButtonGroup:New() -- create the triangle controls self.physiqueTriangleControl = CreateControlFromVirtual("$(parent)PhysiqueSelection", self.control, "ZO_CharacterCreateTriangleTemplate_Keyboard") self.physiqueTriangle = CreateTriangle(self.physiqueTriangleControl, SetPhysique, GetPhysique, SI_CREATE_CHARACTER_BODY_TRIANGLE_LABEL, SI_CREATE_CHARACTER_TRIANGLE_MUSCULAR, SI_CREATE_CHARACTER_TRIANGLE_FAT, SI_CREATE_CHARACTER_TRIANGLE_THIN) self.faceTriangleControl = CreateControlFromVirtual("$(parent)FaceSelection", self.control, "ZO_CharacterCreateTriangleTemplate_Keyboard") self.faceTriangle = CreateTriangle(self.faceTriangleControl, SetFace, GetFace, SI_CREATE_CHARACTER_FACE_TRIANGLE_LABEL, SI_CREATE_CHARACTER_TRIANGLE_FACE_MUSCULAR, SI_CREATE_CHARACTER_TRIANGLE_FACE_FAT, SI_CREATE_CHARACTER_TRIANGLE_FACE_THIN) -- setup the create button and link it to the name control self.createButton = self.control:GetNamedChild("CreateButton") self.createButton:SetEnabled(false) self.instructionsControl = self.control:GetNamedChild("NameInstructions") local VALIDATOR_RULES = { NAME_RULE_TOO_SHORT, NAME_RULE_CANNOT_START_WITH_SPACE, NAME_RULE_MUST_END_WITH_LETTER, NAME_RULE_TOO_MANY_IDENTICAL_ADJACENT_CHARACTERS, NAME_RULE_NO_NUMBERS, NAME_RULE_NO_ADJACENT_PUNCTUATION_CHARACTERS, NAME_RULE_TOO_MANY_PUNCTUATION_CHARACTERS, NAME_RULE_INVALID_CHARACTERS } local DEFAULT_TEMPLATE = nil self.nameInstructionsObject = ZO_ValidNameInstructions:New(self.instructionsControl, DEFAULT_TEMPLATE, VALIDATOR_RULES) self.nameControl = self.control:GetNamedChild("CharacterName") SetupEditControlForNameValidation(self.nameControl) self.nameControl.linkedButton = self.createButton self.nameControl.linkedInstructions = self.nameInstructionsObject self.saveButton = self.control:GetNamedChild("SaveButton") self.templateControl = self.control:GetNamedChild("Template") self.raceSelectionControl = self.control:GetNamedChild("Race") self.classSelectionControl = self.control:GetNamedChild("ClassSelection") self.genderSelectionControl = self.control:GetNamedChild("GenderSelection") end end function ZO_CharacterCreate_Keyboard:InitializeSelectorButtonTextures(buttonControl, data) buttonControl:SetNormalTexture(data.normalIcon) buttonControl:SetPressedTexture(data.pressedIcon) buttonControl:SetMouseOverTexture(data.mouseoverIcon) end function ZO_CharacterCreate_Keyboard:InitializeSelectors() self:InitializeGenderSelector() self:InitializeAllianceSelectors() self:InitializeRaceSelectors() self:InitializeClassSelectors() self:InitializeTemplateList() end function ZO_CharacterCreate_Keyboard:InitializeAllianceSelectors() local layoutTable = { ZO_CharacterCreateRaceAllianceSelector1, ZO_CharacterCreateRaceAllianceSelector2, ZO_CharacterCreateRaceAllianceSelector3, } local alliances = self.characterData:GetAllianceInfo() for _, alliance in ipairs(alliances) do local selector = layoutTable[alliance.position] self:InitializeAllianceSelector(selector, alliance) end end function ZO_CharacterCreate_Keyboard:InitializeRaceSelectors() local layoutTable = { ZO_CharacterCreateRaceColumn11, ZO_CharacterCreateRaceColumn21, ZO_CharacterCreateRaceColumn31, ZO_CharacterCreateRaceColumn12, ZO_CharacterCreateRaceColumn22, ZO_CharacterCreateRaceColumn32, ZO_CharacterCreateRaceColumn13, ZO_CharacterCreateRaceColumn23, ZO_CharacterCreateRaceColumn33, ZO_CharacterCreateRaceSingleButton, } local races = self.characterData:GetRaceInfo() for _, race in ipairs(races) do local raceButton = layoutTable[race.position] self:InitializeSelectorButton(raceButton, race, self.raceRadioGroup) self:AddRaceSelectionDataToSelector(raceButton, race) end end function ZO_CharacterCreate_Keyboard:InitializeGenderSelector() local maleSelector = self.genderSelectionControl:GetNamedChild("Male") maleSelector:GetNamedChild("Label"):SetText(GetString("SI_GENDER", GENDER_MALE)) local femaleSelector = self.genderSelectionControl:GetNamedChild("Female") femaleSelector:GetNamedChild("Label"):SetText(GetString("SI_GENDER", GENDER_FEMALE)) local maleSelectorButton = maleSelector:GetNamedChild("Button") maleSelectorButton.gender = GENDER_MALE local femaleSelectorButton = femaleSelector:GetNamedChild("Button") femaleSelectorButton.gender = GENDER_FEMALE self.genderRadioGroup:Add(maleSelectorButton) self.genderRadioGroup:Add(femaleSelectorButton) end function ZO_CharacterCreate_Keyboard:InitializeTemplateList() local comboBox = ZO_ComboBox_ObjectFromContainer(self.templateControl) comboBox:ClearItems() comboBox:SetSortsItems(false) comboBox:SetFont("ZoFontGame") comboBox:SetSpacing(4) local function OnTemplateChanged(comboBox, entryText, entry) if self:SetTemplate(entry.templateData.template) then KEYBOARD_BUCKET_MANAGER:UpdateControlsFromData() end end local defaultTemplate = GetDefaultTemplate() local function SelectDefaultTemplate(entry) return entry.templateData.template == defaultTemplate end local templatesAllowed = GetTemplateStatus() if templatesAllowed then local templates = self.characterData:GetTemplateInfo() for _, templateData in ipairs(templates) do if templateData.isSelectable then local entry = comboBox:CreateItemEntry(templateData.name, OnTemplateChanged) entry.templateData = templateData comboBox:AddItem(entry) end end if not comboBox:SetSelectedItemByEval(SelectDefaultTemplate) then comboBox:SelectFirstItem() end self.templateControl:SetHidden(false) else self.templateControl:SetHidden(true) end end function ZO_CharacterCreate_Keyboard:SetTemplate(templateId) local templateData = self.characterData:GetTemplate(templateId) if not templateData then return false end local characterMode = ZO_CHARACTERCREATE_MANAGER:GetCharacterMode() if not templateData.isSelectable or CharacterCreateGetTemplate(characterMode) == templateId then return false end CharacterCreateSetTemplate(templateId) local validRaces = {} self:UpdateSelectorsForTemplate(function(...) return self:UpdateRaceSelectorsForTemplate(...) end, self.characterData:GetRaceInfo(), templateData, self.raceRadioGroup, validRaces) self:UpdateSelectorsForTemplate(function(...) return self:UpdateClassSelectorsForTemplate(...) end, self.characterData:GetClassInfo(), templateData, self.classRadioGroup) local validAlliances = {} self.characterData:UpdateAllianceSelectability() self:UpdateSelectorsForTemplate(function(...) return self:UpdateAllianceSelectorsForTemplate(...) end, self.characterData:GetAllianceInfo(), templateData, self.allianceRadioGroup, validAlliances) self:UpdateGenderSelectorsForTemplate(templateData) -- Pick a race if templateData.race ~= 0 then CharacterCreateSetRace(templateData.race) else CharacterCreateSetRace(self.characterData:PickRandomRace(validRaces)) end -- Pick an alliance if templateData.alliance ~= ALLIANCE_NONE then ZO_CharacterCreate_SetAlliance(templateData.alliance) else -- (never random unless a race without a fixed alliance is picked) local alliance = self.characterData:GetRaceForRaceDef(CharacterCreateGetRace(characterMode)).alliance if alliance ~= ALLIANCE_NONE then ZO_CharacterCreate_SetAlliance(alliance) else ZO_CharacterCreate_SetAlliance(self.characterData:PickRandomAlliance(validAlliances)) end end -- Pick a class if templateData.class ~= 0 then self:SetClass(templateData.class) else -- UpdateSelectorsForTemplate() should be called prior to this function or unselectable classes might be set (which would result in no class being set). self:PickRandomSelectableClass() end -- Pick a gender if templateData.gender ~= GENDER_NEUTER then self:SetGender(templateData.gender) else self:PickRandomGender() end -- Make the controls match what you picked... self:ResetControls() if not templateData.overrideAppearance then ZO_CharacterCreate_RandomizeAppearance("initial") else InitializeAppearanceFromTemplate(templateId) end -- Disable appearance related controls if the appearance is overridden in the template. -- buckets need to be disabled after resetting the controls local enabled = not templateData.overrideAppearance KEYBOARD_BUCKET_MANAGER:EnableBucketTab(CREATE_BUCKET_BODY, enabled) KEYBOARD_BUCKET_MANAGER:EnableBucketTab(CREATE_BUCKET_FACE, enabled) ZO_CharacterCreateRandomizeAppearance:SetEnabled(enabled) return true end function ZO_CharacterCreate_Keyboard:InitializeClassSelectors() local classes = self.characterData:GetClassInfo() local numClasses = #classes -- This is how many classes overflow into the last line without filling it up local numOverflowClasses = numClasses % 3 -- This is how many classes fill up our class grid without spilling onto an additional unfilled line local numGridClasses = numClasses - numOverflowClasses local parent = self.classSelectionControl:GetNamedChild("ButtonArea") local stride = 3 local padX = 0 local padY = 0 local controlWidth = 120 local controlHeight = 80 local initialX = 0 local initialY = 0 local anchor = ZO_Anchor:New(TOPLEFT, parent, TOPLEFT, initialX, initialY) for i, classData in ipairs(classes) do local selectorName = "SelectClass" .. classData.class local selector = GetControl(selectorName) if not selector then selector = CreateControlFromVirtual(selectorName, parent, "ClassSelectorButton") end selector.nameFn = GetClassName selector.defId = classData.class self:InitializeSelectorButton(selector, classData, self.classRadioGroup) local controlIndex = i - 1 if i > numGridClasses then -- If the last line has only one class in it, we want to center that class if numOverflowClasses % 2 == 1 then controlIndex = i -- If the last line has two classes, we want to offset them by half their width so the whole thing is still symmetrical. else -- The decimal value is valid because this value is only used to calculate anchor offsets. controlIndex = i - 0.5 end end ZO_Anchor_BoxLayout(anchor, selector, controlIndex, stride, padX, padY, controlWidth, controlHeight, initialX, initialY, GROW_DIRECTION_DOWN_RIGHT) end end do -- This table defines how sliders should be ordered within their sub-categories. -- It's not needed for sub-categories where all the controls are added manually, -- but when sliders are added in loops (like characterSlider and appearanceSlider) -- this is used to assist building the ordering table which will be passed over -- to actually add the sliders. local CONTROL_ORDERING = { [SLIDER_SUBCAT_BODY_FEATURES] = { APPEARANCE_NAME_SKIN_TINT, APPEARANCE_NAME_BODY_MARKING, SLIDER_NAME_CHARACTER_HEIGHT, }, [SLIDER_SUBCAT_BODY_UPPER] = { SLIDER_NAME_TORSO_SIZE, SLIDER_NAME_CHEST_SIZE, SLIDER_NAME_GUT_SIZE, SLIDER_NAME_WAIST_SIZE, SLIDER_NAME_ARM_SIZE, SLIDER_NAME_HAND_SIZE, }, [SLIDER_SUBCAT_BODY_LOWER] = { SLIDER_NAME_TAIL_SIZE, SLIDER_NAME_HIP_SIZE, SLIDER_NAME_BUTTOCKS_SIZE, SLIDER_NAME_LEG_SIZE, SLIDER_NAME_FOOT_SIZE, }, [SLIDER_SUBCAT_VOICE] = { APPEARANCE_NAME_VOICE, }, [SLIDER_SUBCAT_FACE_HAIR] = { APPEARANCE_NAME_HAIR_STYLE, APPEARANCE_NAME_HAIR_TINT, }, [SLIDER_SUBCAT_FACE_FEATURES] = { APPEARANCE_NAME_AGE, APPEARANCE_NAME_ACCESSORY, APPEARANCE_NAME_HEAD_MARKING, }, [SLIDER_SUBCAT_FACE_FACE] = { SLIDER_NAME_FOREHEAD_SLOPE, SLIDER_NAME_CHEEK_BONE_SIZE, SLIDER_NAME_CHEEK_BONE_HEIGHT, SLIDER_NAME_JAW_SIZE, SLIDER_NAME_CHIN_SIZE, SLIDER_NAME_CHIN_HEIGHT, SLIDER_NAME_NECK_SIZE, SLIDER_NAME_TOOTH_SIZE, }, [SLIDER_SUBCAT_FACE_EYES] = { APPEARANCE_NAME_EYE_TINT, SLIDER_NAME_EYE_SIZE, SLIDER_NAME_EYE_ANGLE, SLIDER_NAME_EYE_SEPARATION, SLIDER_NAME_EYE_HEIGHT, SLIDER_NAME_EYE_SQUINT, }, [SLIDER_SUBCAT_FACE_BROW] = { APPEARANCE_NAME_EYEBROW, SLIDER_NAME_EYEBROW_HEIGHT, SLIDER_NAME_EYEBROW_ANGLE, SLIDER_NAME_EYEBROW_SKEW, SLIDER_NAME_EYEBROW_DEPTH, }, [SLIDER_SUBCAT_FACE_NOSE] = { SLIDER_NAME_NOSE_SHAPE, SLIDER_NAME_NOSE_HEIGHT, SLIDER_NAME_NOSE_WIDTH, SLIDER_NAME_NOSE_LENGTH, }, [SLIDER_SUBCAT_FACE_MOUTH] = { SLIDER_NAME_MOUTH_HEIGHT, SLIDER_NAME_MOUTH_WIDTH, SLIDER_NAME_MOUTH_CURVE, SLIDER_NAME_LIP_FULLNESS, }, [SLIDER_SUBCAT_FACE_EARS] = { SLIDER_NAME_EAR_SIZE, SLIDER_NAME_EAR_ROTATION, SLIDER_NAME_EAR_HEIGHT, SLIDER_NAME_EAR_TIP_FLARE, }, } local function SliderComparator(data1, data2) local name1 = data1.name local name2 = data2.name local subCat1 = data1.subCat local subCat2 = data2.subCat if subCat1 ~= subCat2 then return subCat1 < subCat2 end return FindOrdering(CONTROL_ORDERING[subCat1], name1) < FindOrdering(CONTROL_ORDERING[subCat2], name2) end local SLIDER_CATEGORY_TO_CREATE_BUCKET = { [SLIDER_CATEGORY_AGE] = CREATE_BUCKET_BODY, [SLIDER_CATEGORY_BODY] = CREATE_BUCKET_BODY, [SLIDER_CATEGORY_FACE] = CREATE_BUCKET_FACE, } local APPEARANCE_NAME_TO_CREATE_BUCKET = { [APPEARANCE_NAME_HAIR_STYLE] = CREATE_BUCKET_FACE, [APPEARANCE_NAME_HAIR_TINT] = CREATE_BUCKET_FACE, [APPEARANCE_NAME_SKIN_TINT] = CREATE_BUCKET_BODY, [APPEARANCE_NAME_ACCESSORY] = CREATE_BUCKET_FACE, [APPEARANCE_NAME_HEAD_MARKING] = CREATE_BUCKET_FACE, [APPEARANCE_NAME_BODY_MARKING] = CREATE_BUCKET_BODY, [APPEARANCE_NAME_EYE_TINT] = CREATE_BUCKET_FACE, [APPEARANCE_NAME_AGE] = CREATE_BUCKET_FACE, [APPEARANCE_NAME_EYEBROW] = CREATE_BUCKET_FACE, [APPEARANCE_NAME_VOICE] = CREATE_BUCKET_FACE, } local SUBCATEGORY_FOR_SLIDER = { [SLIDER_NAME_FOREHEAD_SLOPE] = SLIDER_SUBCAT_FACE_FACE, [SLIDER_NAME_CHEEK_BONE_SIZE] = SLIDER_SUBCAT_FACE_FACE, [SLIDER_NAME_CHEEK_BONE_HEIGHT] = SLIDER_SUBCAT_FACE_FACE, [SLIDER_NAME_CHIN_HEIGHT] = SLIDER_SUBCAT_FACE_FACE, [SLIDER_NAME_CHIN_SIZE] = SLIDER_SUBCAT_FACE_FACE, [SLIDER_NAME_JAW_SIZE] = SLIDER_SUBCAT_FACE_FACE, [SLIDER_NAME_NECK_SIZE] = SLIDER_SUBCAT_FACE_FACE, [SLIDER_NAME_TOOTH_SIZE] = SLIDER_SUBCAT_FACE_FACE, [SLIDER_NAME_NOSE_SHAPE] = SLIDER_SUBCAT_FACE_NOSE, [SLIDER_NAME_NOSE_LENGTH] = SLIDER_SUBCAT_FACE_NOSE, [SLIDER_NAME_NOSE_HEIGHT] = SLIDER_SUBCAT_FACE_NOSE, [SLIDER_NAME_NOSE_WIDTH] = SLIDER_SUBCAT_FACE_NOSE, [SLIDER_NAME_EYE_HEIGHT] = SLIDER_SUBCAT_FACE_EYES, [SLIDER_NAME_EYE_SIZE] = SLIDER_SUBCAT_FACE_EYES, [SLIDER_NAME_EYE_SEPARATION] = SLIDER_SUBCAT_FACE_EYES, [SLIDER_NAME_EYE_ANGLE] = SLIDER_SUBCAT_FACE_EYES, [SLIDER_NAME_EYE_SQUINT] = SLIDER_SUBCAT_FACE_EYES, [SLIDER_NAME_MOUTH_HEIGHT] = SLIDER_SUBCAT_FACE_MOUTH, [SLIDER_NAME_MOUTH_WIDTH] = SLIDER_SUBCAT_FACE_MOUTH, [SLIDER_NAME_LIP_FULLNESS] = SLIDER_SUBCAT_FACE_MOUTH, [SLIDER_NAME_MOUTH_CURVE] = SLIDER_SUBCAT_FACE_MOUTH, [SLIDER_NAME_EAR_HEIGHT] = SLIDER_SUBCAT_FACE_EARS, [SLIDER_NAME_EAR_SIZE] = SLIDER_SUBCAT_FACE_EARS, [SLIDER_NAME_EAR_TIP_FLARE] = SLIDER_SUBCAT_FACE_EARS, [SLIDER_NAME_EAR_ROTATION] = SLIDER_SUBCAT_FACE_EARS, [SLIDER_NAME_EYEBROW_HEIGHT] = SLIDER_SUBCAT_FACE_BROW, [SLIDER_NAME_EYEBROW_ANGLE] = SLIDER_SUBCAT_FACE_BROW, [SLIDER_NAME_EYEBROW_SKEW] = SLIDER_SUBCAT_FACE_BROW, [SLIDER_NAME_EYEBROW_DEPTH] = SLIDER_SUBCAT_FACE_BROW, [SLIDER_NAME_LEG_SIZE] = SLIDER_SUBCAT_BODY_LOWER, [SLIDER_NAME_HIP_SIZE] = SLIDER_SUBCAT_BODY_LOWER, [SLIDER_NAME_FOOT_SIZE] = SLIDER_SUBCAT_BODY_LOWER, [SLIDER_NAME_BUTTOCKS_SIZE] = SLIDER_SUBCAT_BODY_LOWER, [SLIDER_NAME_TAIL_SIZE] = SLIDER_SUBCAT_BODY_LOWER, [SLIDER_NAME_TORSO_SIZE] = SLIDER_SUBCAT_BODY_UPPER, [SLIDER_NAME_HAND_SIZE] = SLIDER_SUBCAT_BODY_UPPER, [SLIDER_NAME_GUT_SIZE] = SLIDER_SUBCAT_BODY_UPPER, [SLIDER_NAME_ARM_SIZE] = SLIDER_SUBCAT_BODY_UPPER, [SLIDER_NAME_CHEST_SIZE] = SLIDER_SUBCAT_BODY_UPPER, [SLIDER_NAME_WAIST_SIZE] = SLIDER_SUBCAT_BODY_UPPER, [SLIDER_NAME_CHARACTER_HEIGHT] = SLIDER_SUBCAT_BODY_TYPE, } local SUBCATEGORY_FOR_APPEARANCE = { [APPEARANCE_NAME_HAIR_STYLE] = SLIDER_SUBCAT_FACE_HAIR, [APPEARANCE_NAME_HAIR_TINT] = SLIDER_SUBCAT_FACE_HAIR, [APPEARANCE_NAME_ACCESSORY] = SLIDER_SUBCAT_FACE_FEATURES, [APPEARANCE_NAME_HEAD_MARKING] = SLIDER_SUBCAT_FACE_FEATURES, [APPEARANCE_NAME_AGE] = SLIDER_SUBCAT_FACE_FEATURES, [APPEARANCE_NAME_BODY_MARKING] = SLIDER_SUBCAT_BODY_FEATURES, [APPEARANCE_NAME_SKIN_TINT] = SLIDER_SUBCAT_BODY_FEATURES, [APPEARANCE_NAME_EYE_TINT] = SLIDER_SUBCAT_FACE_EYES, [APPEARANCE_NAME_EYEBROW] = SLIDER_SUBCAT_FACE_BROW, [APPEARANCE_NAME_VOICE] = SLIDER_SUBCAT_VOICE, } local function UpdateSlider(slider) slider.sliderObject:Update() end function ZO_CharacterCreate_Keyboard:ResetControls() -- If this was being suppressed changes MUST be applied now or there will be no slider data to build SetSuppressCharacterChanges(false) self.sliderManager:ReleaseAllObjects() KEYBOARD_BUCKET_MANAGER:Reset() KEYBOARD_BUCKET_MANAGER:AddSubCategories() KEYBOARD_BUCKET_MANAGER:AddControl(self.genderSelectionControl, CREATE_BUCKET_RACE, function() self:UpdateGenderControl() end) KEYBOARD_BUCKET_MANAGER:AddControl(self.raceSelectionControl, CREATE_BUCKET_RACE, function() self:UpdateRaceControl() end) KEYBOARD_BUCKET_MANAGER:AddControl(self.classSelectionControl, CREATE_BUCKET_CLASS, function() self:UpdateClassControl() end) KEYBOARD_BUCKET_MANAGER:AddControl(self.physiqueTriangleControl, CREATE_BUCKET_BODY, UpdateSlider, RandomizeSlider, SLIDER_SUBCAT_BODY_TYPE) KEYBOARD_BUCKET_MANAGER:AddControl(self.faceTriangleControl, CREATE_BUCKET_FACE, UpdateSlider, RandomizeSlider, SLIDER_SUBCAT_FACE_TYPE) local _, physiqueIsLocked = ZO_CHARACTERCREATE_MANAGER:GetCharacterUnsavedSetting("triangle", "physique") if physiqueIsLocked ~= nil then self.physiqueTriangle:SetLocked(physiqueIsLocked) end local _, faceIsLocked = ZO_CHARACTERCREATE_MANAGER:GetCharacterUnsavedSetting("triangle", "face") if faceIsLocked ~= nil then self.faceTriangle:SetLocked(faceIsLocked) end -- TODO: this fixes a bug where the triangles don't reflect the correct data...there will be more fixes to pregameCharacterManager to address the real issue -- (where the triangle data needs to live on its own rather than being tied to the unit) self.physiqueTriangle:Update() self.faceTriangle:Update() self.controlsByNameCategory = {} local sliderData = {} for i = 1, GetNumSliders() do local name, category, steps, value, defaultValue = GetSliderInfo(i) if name then local slider = self.sliderManager:AcquireObject(CHARACTER_CREATE_SLIDER_TYPE_SLIDER) local unsavedValue, unsavedIsLocked = ZO_CHARACTERCREATE_MANAGER:GetCharacterUnsavedSetting(name, category) if unsavedValue and unsavedIsLocked then slider:SetLocked(unsavedIsLocked) end slider:SetData(i, name, category, steps, unsavedValue or value, defaultValue) local bucket = SLIDER_CATEGORY_TO_CREATE_BUCKET[category] local subCat = SUBCATEGORY_FOR_SLIDER[name] sliderData[#sliderData + 1] = { bucket = bucket, subCat = subCat, name = name, control = slider.control, } if not self.controlsByNameCategory[name] then self.controlsByNameCategory[name] = {} end self.controlsByNameCategory[name][category] = slider end end for i = 1, GetNumAppearances() do local appearanceName, appearanceType, numValues, displayName = GetAppearanceInfo(i) if numValues > 0 then local appearanceSlider = self.sliderManager:AcquireObject(appearanceType) local unsavedValue, unsavedIsLocked = ZO_CHARACTERCREATE_MANAGER:GetCharacterUnsavedSetting(appearanceName, appearanceType) if unsavedValue and unsavedIsLocked then appearanceSlider:SetLocked(unsavedIsLocked) end appearanceSlider:SetData(appearanceName, numValues, displayName) local bucket = APPEARANCE_NAME_TO_CREATE_BUCKET[appearanceName] local subCat = SUBCATEGORY_FOR_APPEARANCE[appearanceName] sliderData[#sliderData + 1] = { bucket = bucket, subCat = subCat, name = appearanceName, control = appearanceSlider.control, } if not self.controlsByNameCategory[appearanceName] then self.controlsByNameCategory[appearanceName] = {} end self.controlsByNameCategory[appearanceName][appearanceType] = appearanceSlider end end table.sort(sliderData, SliderComparator) for _, orderingData in ipairs(sliderData) do KEYBOARD_BUCKET_MANAGER:AddControl(orderingData.control, orderingData.bucket, UpdateSlider, RandomizeSlider, orderingData.subCat) end KEYBOARD_BUCKET_MANAGER:RemoveUnusedSubCategories() KEYBOARD_BUCKET_MANAGER:SwitchBuckets(CREATE_BUCKET_RACE) local appearanceControlsEnabled = self:DoesCurrentCharacterCreateModeAllowAppearanceChange() KEYBOARD_BUCKET_MANAGER:EnableBucketTab(CREATE_BUCKET_BODY, appearanceControlsEnabled) KEYBOARD_BUCKET_MANAGER:EnableBucketTab(CREATE_BUCKET_FACE, appearanceControlsEnabled) local classControlsEnabled = self:DoesCurrentCharacterCreateModeAllowClassChange() KEYBOARD_BUCKET_MANAGER:EnableBucketTab(CREATE_BUCKET_CLASS, classControlsEnabled) -- Update Gender Text self:UpdateGenderSpecificText() end end function ZO_CharacterCreate_Keyboard:ResetNameEdit() local nameEdit = self.nameControl nameEdit:TakeFocus() -- Fix an issue where the animated name text wouldn't display nameEdit:SetText("") nameEdit:LoseFocus() self.nameControl:GetNamedChild("Instructions"):SetHidden(false) end function ZO_CharacterCreate_Keyboard:Reset() -- Sanity check if not IsPregameCharacterConstructionReady() then return end SetCharacterCameraZoomAmount(-1) -- zoom all the way out when a reset happens SetSuppressCharacterChanges(true) -- this will be disabled later, right before controls are reset self:ResetNameEdit() local controlsInitialized = false local characterMode = ZO_CHARACTERCREATE_MANAGER:GetCharacterMode() if characterMode == CHARACTER_MODE_CREATION then self:InitializeTemplateList() -- assume that we have already initialized the controls because we have set the default template controlsInitialized = true local defaultTemplate = GetDefaultTemplate() if defaultTemplate == 0 then -- default template was undefined so see if we generated a new random character controlsInitialized = self:GenerateRandomCharacter() end end if not controlsInitialized then self:ResetControls() end KEYBOARD_BUCKET_MANAGER:SwitchBuckets(CREATE_BUCKET_RACE) KEYBOARD_BUCKET_MANAGER:UpdateControlsFromData() self.characterStartLocation = nil ZO_CHARACTERCREATE_MANAGER:SetShouldPromptForTutorialSkip(true) self.characterCreateOption = CHARACTER_CREATE_DEFAULT_LOCATION end function ZO_CharacterCreate_Keyboard:UpdateGenderSpecificText(currentGender) local characterMode = ZO_CHARACTERCREATE_MANAGER:GetCharacterMode() currentGender = currentGender or CharacterCreateGetGender(characterMode) self.raceSelectionControl:GetNamedChild("Name"):SetText(zo_strformat(SI_RACE_NAME, GetRaceName(currentGender, CharacterCreateGetRace(characterMode)))) self.classSelectionControl:GetNamedChild("Name"):SetText(zo_strformat(SI_CLASS_NAME, GetClassName(currentGender, CharacterCreateGetClass(characterMode)))) end function ZO_CharacterCreate_Keyboard:UpdateRaceControl() local characterMode = ZO_CHARACTERCREATE_MANAGER:GetCharacterMode() local currentRace = CharacterCreateGetRace(characterMode) local function IsRaceClicked(button) return button.defId == currentRace end self.raceRadioGroup:UpdateFromData(IsRaceClicked) local currentAlliance = CharacterCreateGetAlliance(characterMode) local function IsAllianceClicked(button) return button.defId == currentAlliance end self.allianceRadioGroup:UpdateFromData(IsAllianceClicked) local race = self.characterData:GetRaceForRaceDef(currentRace) if race then local allianceName, backdropTop, backdropBottom = self:GetCurrentAllianceData() self:UpdateGenderSpecificText() self.raceSelectionControl:GetNamedChild("Alliance"):SetText(zo_strformat(SI_ALLIANCE_NAME, allianceName)) self.raceSelectionControl:GetNamedChild("Description"):SetText(race.lore) self.raceSelectionControl:GetNamedChild("AllianceBG"):SetTexture(backdropTop) self.raceSelectionControl:GetNamedChild("AllianceBGBottom"):SetTexture(backdropBottom) end end function ZO_CharacterCreate_Keyboard:UpdateGenderControl() local characterMode = ZO_CHARACTERCREATE_MANAGER:GetCharacterMode() local currentGender = CharacterCreateGetGender(characterMode) local function IsGenderClicked(button) return button.gender == currentGender end self.genderRadioGroup:UpdateFromData(IsGenderClicked) end function ZO_CharacterCreate_Keyboard:UpdateClassControl() local characterMode = ZO_CHARACTERCREATE_MANAGER:GetCharacterMode() local currentClass = CharacterCreateGetClass(characterMode) local function IsClassClicked(button) return button.defId == currentClass end self.classRadioGroup:UpdateFromData(IsClassClicked) local class = self.characterData:GetClassForClassDef(currentClass) if class then self:UpdateGenderSpecificText() self.classSelectionControl:GetNamedChild("Description"):SetText(class.lore) end end function ZO_CharacterCreate_Keyboard:OnGenerateRandomCharacter() ZO_CharacterCreate_RandomizeAppearance("initial") end function ZO_CharacterCreate_Keyboard:CreateCharacter(startLocation, createOption) self.characterName = self.nameControl:GetText() ZO_CharacterCreate_Base.CreateCharacter(self, startLocation, createOption) end function ZO_CharacterCreate_Keyboard:OnCreateButtonClicked(startLocation) local characterName = self.nameControl:GetText() if characterName and #characterName > 0 then local characterMode = ZO_CHARACTERCREATE_MANAGER:GetCharacterMode() local currentTemplateId = CharacterCreateGetTemplate(characterMode) local templateSkipsTutorial = GetTemplateSkipsTutorial(currentTemplateId) if ZO_CHARACTERCREATE_MANAGER:GetShouldPromptForTutorialSkip() and CanSkipTutorialArea() and (currentTemplateId == 0 or not templateSkipsTutorial) and startLocation ~= CHARACTER_OPTION_CLEAN_TEST_AREA and startLocation ~= "CharacterSelect_FromIngame" then ZO_CHARACTERCREATE_MANAGER:SetShouldPromptForTutorialSkip(false) -- color the character name white so it's highlighted in the dialog local characterMode = ZO_CHARACTERCREATE_MANAGER:GetCharacterMode() local genderDecoratedCharacterName = ZO_SELECTED_TEXT:Colorize(GetGrammarDecoratedName(characterName, CharacterCreateGetGender(characterMode))) ZO_Dialogs_ShowDialog("CHARACTER_CREATE_SKIP_TUTORIAL", { startLocation = startLocation }, {mainTextParams = { genderDecoratedCharacterName }}) else if currentTemplateId ~= 0 and templateSkipsTutorial then self.characterCreateOption = CHARACTER_CREATE_SKIP_TUTORIAL end self:CreateCharacter(startLocation, self.characterCreateOption) end end end function ZO_CharacterCreate_Keyboard:InitializeForEditChanges(characterInfo, mode) self:SetCharacterCreateMode(mode) local raceTemplate = characterInfo if mode == CHARACTER_CREATE_MODE_EDIT_RACE then raceTemplate = { race = 0, alliance = characterInfo.alliance, } end local genderTemplate = { gender = GENDER_NEUTER } local allianceTemplate = characterInfo if mode == CHARACTER_CREATE_MODE_EDIT_ALLIANCE then allianceTemplate = { alliance = ALLIANCE_NONE, } genderTemplate = characterInfo end self:UpdateGenderSelectorsForTemplate(genderTemplate) self:UpdateSelectorsForTemplate(function(...) return self:UpdateRaceSelectorsForTemplate(...) end, self.characterData:GetRaceInfo(), raceTemplate, self.raceRadioGroup) self:UpdateSelectorsForTemplate(function(...) return self:UpdateClassSelectorsForTemplate(...) end, self.characterData:GetClassInfo(), characterInfo, self.classRadioGroup) self:UpdateSelectorsForTemplate(function(...) return self:UpdateAllianceSelectorsForTemplate(...) end, self.characterData:GetAllianceInfo(), allianceTemplate, self.allianceRadioGroup) self:Reset() local appearanceControlsEnabled = self:DoesCurrentCharacterCreateModeAllowAppearanceChange() ZO_CharacterCreateRandomizeAppearance:SetEnabled(appearanceControlsEnabled) self.templateControl:SetHidden(true) local name = zo_strformat(SI_CHARACTER_SELECT_NAME, characterInfo.name) self.nameControl:SetText(name) self.nameControl:SetColor(ZO_DEFAULT_DISABLED_COLOR:UnpackRGB()) self.nameControl:GetNamedChild("Instructions"):SetHidden(true) self.nameControl:SetEditEnabled(false) self.nameControl:SetMouseEnabled(false) self.saveButton:SetHidden(false) self.createButton:SetHidden(true) end function ZO_CharacterCreate_Keyboard:InitializeForCharacterCreate() self:SetCharacterCreateMode(CHARACTER_CREATE_MODE_CREATE) local characterMode = ZO_CHARACTERCREATE_MANAGER:GetCharacterMode() local templateData = self.characterData:GetTemplate(CharacterCreateGetTemplate(characterMode)) -- we may not have any template selected or we have no templates -- so create a default template with no restrictions if templateData == nil then templateData = self.characterData:GetNoneTemplate() end ZO_CharacterCreateRandomizeAppearance:SetEnabled(true) self:UpdateGenderSelectorsForTemplate(templateData) self:UpdateSelectorsForTemplate(function(...) return self:UpdateRaceSelectorsForTemplate(...) end, self.characterData:GetRaceInfo(), templateData, self.raceRadioGroup) self:UpdateSelectorsForTemplate(function(...) return self:UpdateClassSelectorsForTemplate(...) end, self.characterData:GetClassInfo(), templateData, self.classRadioGroup) self.characterData:UpdateAllianceSelectability() self:UpdateSelectorsForTemplate(function(...) return self:UpdateAllianceSelectorsForTemplate(...) end, self.characterData:GetAllianceInfo(), templateData, self.allianceRadioGroup) self.nameControl:SetEditEnabled(true) self.nameControl:SetMouseEnabled(true) self.nameControl:SetColor(ZO_NORMAL_TEXT:UnpackRGB()) self.saveButton:SetHidden(true) self.createButton:SetHidden(false) local currentAlliance = CharacterCreateGetAlliance(characterMode) ZO_CharacterCreate_SetChromaColorForAlliance(currentAlliance) end function ZO_CharacterCreate_Keyboard:UpdateGenderSelectorsForTemplate(templateData) for button in self.genderRadioGroup:IterateButtons() do local enabled = templateData.gender == GENDER_NEUTER or templateData.gender == button.gender self:SetSelectorButtonEnabled(button, self.genderRadioGroup, enabled) end end function ZO_CharacterCreate_Keyboard:ClickGenderButton(genderButton) self.genderRadioGroup:SetClickedButton(genderButton) end -- --[[ XML Handlers and global functions ]]-- -- function ZO_CharacterCreate_RandomizeAppearance(randomizeType) KEYBOARD_BUCKET_MANAGER:RandomizeAppearance(randomizeType) end function ZO_CharacterCreate_RandomizeAppearance_OnMouseEnter(control) -- If a button is disabled, add any disable reasons to the tooltip if control:GetState() == BSTATE_DISABLED or control:GetState() == BSTATE_DISABLED_PRESSED then InitializeTooltip(InformationTooltip, control, BOTTOM, 0, -5, TOP) -- Check if disabled due to a barbershop mode local characterCreateMode = KEYBOARD_CHARACTER_CREATE_MANAGER:GetCharacterCreateMode() if characterCreateMode ~= CHARACTER_CREATE_MODE_CREATE then local tokenType = KEYBOARD_CHARACTER_CREATE_MANAGER:GetTokenTypeForCharacterCreateMode(characterCreateMode) local tokenString = GetString("SI_SERVICETOKENTYPE", tokenType) InformationTooltip:AddLine(zo_strformat(SI_CREATE_CHARACTER_SELECTOR_TOKEN_DISABLED, tokenString), "", ZO_NORMAL_TEXT:UnpackRGB()) end end end function ZO_CharacterCreate_RandomizeAppearance_OnMouseExit(control) ClearTooltip(InformationTooltip) end function ZO_CharacterCreate_Initialize(control) KEYBOARD_CHARACTER_CREATE_MANAGER = ZO_CharacterCreate_Keyboard:New(control) SYSTEMS:RegisterKeyboardObject(ZO_CHARACTER_CREATE_SYSTEM_NAME, KEYBOARD_CHARACTER_CREATE_MANAGER) KEYBOARD_BUCKET_MANAGER = ZO_CharacterCreateBucketManager_Keyboard:New(ZO_CharacterCreateBuckets) end function ZO_CharacterCreateSkipTutorialDialog_Initialize(control) ZO_Dialogs_RegisterCustomDialog("CHARACTER_CREATE_SKIP_TUTORIAL", { customControl = control, canQueue = true, title = { text = SI_PROMPT_TITLE_SKIP_TUTORIAL, }, mainText = { text = SI_PROMPT_BODY_SKIP_TUTORIAL, }, noChoiceCallback = function(dialog) ZO_CHARACTERCREATE_MANAGER:SetShouldPromptForTutorialSkip(true) end, buttons = { { control = control:GetNamedChild("Play"), text = SI_PROMPT_PLAY_TUTORIAL_BUTTON, keybind = "DIALOG_PRIMARY", callback = function(dialog) KEYBOARD_CHARACTER_CREATE_MANAGER:CreateCharacter(dialog.data.startLocation, CHARACTER_CREATE_DEFAULT_LOCATION) end, }, { control = control:GetNamedChild("Skip"), text = SI_PROMPT_SKIP_TUTORIAL_BUTTON, keybind = "DIALOG_SECONDARY", callback = function(dialog) KEYBOARD_CHARACTER_CREATE_MANAGER:CreateCharacter(dialog.data.startLocation, CHARACTER_CREATE_SKIP_TUTORIAL) end, }, { control = control:GetNamedChild("Back"), text = SI_PROMPT_BACK_TUTORIAL_BUTTON, keybind = "DIALOG_NEGATIVE", callback = function(dialog) ZO_CHARACTERCREATE_MANAGER:SetShouldPromptForTutorialSkip(true) end, }, } }) end function ZO_CharacterCreate_OnCreateButtonClicked(startLocation) KEYBOARD_CHARACTER_CREATE_MANAGER:OnCreateButtonClicked(startLocation) end function ZO_CharacterCreate_OnSaveButtonClicked() KEYBOARD_CHARACTER_CREATE_MANAGER:SaveCharacterChanges() end local function ValidateNameText(editControl) local nameText = editControl:GetText() local nameViolations = { IsValidCharacterName(nameText) } local nameIsValid = (#nameViolations == 0) if nameIsValid then editControl:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_NORMAL)) else editControl:SetColor(GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_FAILED)) end local oldPos = editControl:GetCursorPosition() editControl:SetText(CorrectCharacterNameCase(nameText)) editControl:SetCursorPosition(oldPos) return nameIsValid, nameViolations end function ZO_CharacterCreate_CheckEnableCreateButton(editControl) -- Validation changes the text in the edit control, which causes this to be called again, bail if we're already validating to avoid recursion. if editControl.validating then return end editControl.validating = true local isValidName, nameViolations = ValidateNameText(editControl) if isValidName then editControl.linkedButton:SetState(BSTATE_NORMAL, false) else editControl.linkedButton:SetState(BSTATE_DISABLED, true) end if editControl:HasFocus() then editControl.linkedInstructions:Show(editControl, nameViolations) else editControl.linkedInstructions:Hide() end CALLBACK_MANAGER:FireCallbacks("OnCharacterCreateNameChanged", isValidName) editControl.validating = nil end function ZO_CharacterCreate_OnNameFieldFocusGained(editControl) editControl:GetNamedChild("Instructions"):SetHidden(true) editControl.linkedInstructions:Show(editControl) ZO_CharacterCreate_CheckEnableCreateButton(editControl) if WINDOW_MANAGER:IsHandlingHardwareEvent() then PlaySound(SOUNDS.EDIT_CLICK) end end function ZO_CharacterCreate_OnNameFieldFocusLost(editControl) if #editControl:GetText() == 0 then editControl:GetNamedChild("Instructions"):SetHidden(false) end editControl.linkedInstructions:Hide() end do local SELECTOR_CLICK_HANDLERS = { [CHARACTER_CREATE_SELECTOR_RACE] = function(button) KEYBOARD_CHARACTER_CREATE_MANAGER:SetRace(button.defId) KEYBOARD_CHARACTER_CREATE_MANAGER:UpdateRaceControl() end, [CHARACTER_CREATE_SELECTOR_CLASS] = function(button) KEYBOARD_CHARACTER_CREATE_MANAGER:SetClass(button.defId) KEYBOARD_CHARACTER_CREATE_MANAGER:UpdateClassControl() end, [CHARACTER_CREATE_SELECTOR_ALLIANCE] = function(button) KEYBOARD_CHARACTER_CREATE_MANAGER:SetAlliance(button.defId) KEYBOARD_CHARACTER_CREATE_MANAGER:UpdateRaceControl() end, [CHARACTER_CREATE_SELECTOR_GENDER] = function(button) KEYBOARD_CHARACTER_CREATE_MANAGER:SetGender(button.gender) end, } function ZO_CharacterCreate_OnSelectorClicked(button) local clickHandler = SELECTOR_CLICK_HANDLERS[button.selectorType] if clickHandler then OnCharacterCreateOptionChanged() clickHandler(button) end end end function ZO_CharacterCreate_MouseEnterNamedSelector(button) InitializeTooltip(InformationTooltip, button, TOPRIGHT, 0, 0, TOPLEFT) if button.name then SetTooltipText(InformationTooltip, zo_strformat(button.tooltipFormatter, button.name)) elseif button.nameFn then local characterMode = ZO_CHARACTERCREATE_MANAGER:GetCharacterMode() SetTooltipText(InformationTooltip, zo_strformat(button.tooltipFormatter, button.nameFn(CharacterCreateGetGender(characterMode), button.defId))) end -- If a button is disabled, add any disable reasons to the tooltip if button:GetState() == BSTATE_DISABLED or button:GetState() == BSTATE_DISABLED_PRESSED then -- Check if disabled due to a barbershop mode local characterCreateMode = KEYBOARD_CHARACTER_CREATE_MANAGER:GetCharacterCreateMode() if characterCreateMode ~= CHARACTER_CREATE_MODE_CREATE then local selectorType = button.selectorType local addDisableReason = false local tokenType = KEYBOARD_CHARACTER_CREATE_MANAGER:GetTokenTypeForCharacterCreateMode(characterCreateMode) if tokenType == SERVICE_TOKEN_APPEARANCE_CHANGE then addDisableReason = selectorType == CHARACTER_CREATE_SELECTOR_RACE or selectorType == CHARACTER_CREATE_SELECTOR_CLASS or selectorType == CHARACTER_CREATE_SELECTOR_ALLIANCE elseif tokenType == SERVICE_TOKEN_RACE_CHANGE then addDisableReason = selectorType == CHARACTER_CREATE_SELECTOR_CLASS or selectorType == CHARACTER_CREATE_SELECTOR_ALLIANCE elseif tokenType == SERVICE_TOKEN_ALLIANCE_CHANGE then addDisableReason = selectorType == CHARACTER_CREATE_SELECTOR_RACE or selectorType == CHARACTER_CREATE_SELECTOR_CLASS or selectorType == CHARACTER_CREATE_SELECTOR_GENDER end if addDisableReason then local tokenString = GetString("SI_SERVICETOKENTYPE", tokenType) InformationTooltip:AddLine(zo_strformat(SI_CREATE_CHARACTER_SELECTOR_TOKEN_DISABLED, tokenString), "", ZO_NORMAL_TEXT:UnpackRGB()) end end local raceSelector = button.selectorType == CHARACTER_CREATE_SELECTOR_RACE local classSelector = button.selectorType == CHARACTER_CREATE_SELECTOR_CLASS -- Check for race/class specific disable reasons if raceSelector or classSelector then local restrictionReasonFunction = raceSelector and GetRaceRestrictionReason or GetClassRestrictionReason local restrictionReason, restrictingCollectible = restrictionReasonFunction(button.defId) local restrictionString = ZO_CHARACTERCREATE_MANAGER.GetOptionRestrictionString(restrictionReason, restrictingCollectible) if restrictionString ~= "" then InformationTooltip:AddLine(restrictionString, "", ZO_NORMAL_TEXT:UnpackRGB()) if restrictingCollectible ~= 0 and IsCollectiblePurchasable(restrictingCollectible) then InformationTooltip:AddLine(GetString(SI_CHARACTER_CREATE_RESTRICTION_COLLECTIBLE_PURCHASABLE), "", ZO_NORMAL_TEXT:UnpackRGB()) end end end end end function ZO_CharacterCreate_MouseExitNamedSelector(button) ClearTooltip(InformationTooltip) end function ZO_CharacterCreateGenderSelector_OnMouseEnter(button) local characterCreateMode = KEYBOARD_CHARACTER_CREATE_MANAGER:GetCharacterCreateMode() if characterCreateMode == CHARACTER_CREATE_MODE_EDIT_ALLIANCE then if button:GetState() == BSTATE_DISABLED or button:GetState() == BSTATE_DISABLED_PRESSED then InitializeTooltip(InformationTooltip, button, TOPRIGHT, 0, 0, TOPLEFT) local tokenString = GetString("SI_SERVICETOKENTYPE", SERVICE_TOKEN_ALLIANCE_CHANGE) InformationTooltip:AddLine(zo_strformat(SI_CREATE_CHARACTER_SELECTOR_TOKEN_DISABLED, tokenString), "", ZO_NORMAL_TEXT:UnpackRGB()) end end end function ZO_CharacterCreateGenderSelector_OnMouseExit(button) ClearTooltip(InformationTooltip) end function ZO_CharacterCreateGenderSelectorLabel_OnMouseClicked(label, mouseButton, upInside) if mouseButton == MOUSE_BUTTON_INDEX_LEFT and upInside then local genderButton = label:GetParent():GetNamedChild("Button") KEYBOARD_CHARACTER_CREATE_MANAGER:ClickGenderButton(genderButton) end end function ZO_CharacterCreate_ChangeSlider(slider, changeAmount) OnCharacterCreateOptionChanged() slider:GetParent().sliderObject:ChangeValue(changeAmount) end function ZO_CharacterCreate_ChangePanel(direction) local currentTab = KEYBOARD_BUCKET_MANAGER:GetCurrentTab() if currentTab then KEYBOARD_BUCKET_MANAGER:SwitchBuckets(currentTab.windowData[direction]) end end function ZO_CharacterCreate_PreviewClicked(previewButton) local slider = previewButton:GetParent() slider.sliderObject:Preview() end function ZO_PaperdollManipulation_OnEffectivelyShown(self) --While we need a mouse down over the paper doll area to start spinning, the mouse up may not be delivered to this same control. If we press mouse left to start spinning (which starts --mouse tracking) then press mouse right this will release mouse left but it won't stop mouse tracking because tracking is locked when the up is delivered. So we catch it on the event instead --when tracking isn't locked. ESO-546877 self:RegisterForEvent(EVENT_GLOBAL_MOUSE_UP, CharacterCreateStopMouseSpin) end function ZO_PaperdollManipulation_OnEffectivelyHidden(self) CharacterCreateStopMouseSpin() self:UnregisterForEvent(EVENT_GLOBAL_MOUSE_UP) end