GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER = 1 GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE = 2 GAMEPAD_BUCKET_CONTROL_TYPE_CUSTOM = 3 GAMEPAD_BUCKET_CUSTOM_CONTROL_GENDER = 1 GAMEPAD_BUCKET_CUSTOM_CONTROL_ALLIANCE = 2 GAMEPAD_BUCKET_CUSTOM_CONTROL_RACE = 3 GAMEPAD_BUCKET_CUSTOM_CONTROL_CLASS = 4 GAMEPAD_BUCKET_CUSTOM_CONTROL_PHYSIQUE = 5 GAMEPAD_BUCKET_CUSTOM_CONTROL_FACE = 6 local DEFAULT_OFFSET = -60 -- Table for the Bucket data. Each Bucket is a tab in the UI. ZO_CHARACTER_CREATE_BUCKET_WINDOW_DATA_GAMEPAD = { [CREATE_BUCKET_RACE] = { windowName = "RaceBucket_Gamepad", title = GetString(SI_CREATE_CHARACTER_GAMEPAD_BUCKET_TITLE_CHARACTER), onExpandFn = function() if not ZO_CHARACTERCREATE_MANAGER:GetPlayingTransitionAnimations() then CharacterCreateSetIdlePosture() end SetCharacterCameraZoomAmount(-1) end, -- Controls for the tab controls = { -- , { GAMEPAD_BUCKET_CONTROL_TYPE_CUSTOM, GAMEPAD_BUCKET_CUSTOM_CONTROL_CLASS }, { GAMEPAD_BUCKET_CONTROL_TYPE_CUSTOM, GAMEPAD_BUCKET_CUSTOM_CONTROL_GENDER }, { GAMEPAD_BUCKET_CONTROL_TYPE_CUSTOM, GAMEPAD_BUCKET_CUSTOM_CONTROL_ALLIANCE }, { GAMEPAD_BUCKET_CONTROL_TYPE_CUSTOM, GAMEPAD_BUCKET_CUSTOM_CONTROL_RACE }, }, }, [CREATE_BUCKET_BODY] = { windowName = "BodyTypeBucket_Gamepad", title = GetString(SI_CREATE_CHARACTER_GAMEPAD_BUCKET_TITLE_BODY_TYPE), onExpandFn = function() SetCharacterCameraZoomAmount(-1) end, controls = { { GAMEPAD_BUCKET_CONTROL_TYPE_CUSTOM, GAMEPAD_BUCKET_CUSTOM_CONTROL_PHYSIQUE }, }, }, [CREATE_BUCKET_BODY_SHAPE] = { windowName = "BodyShapeBucket_Gamepad", title = GetString(SI_CREATE_CHARACTER_BUCKET_TITLE_BODY), onExpandFn = function() SetCharacterCameraZoomAmount(-1) end, controls = { { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_CHARACTER_HEIGHT }, { GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE, APPEARANCE_NAME_SKIN_TINT }, { GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE, APPEARANCE_NAME_BODY_MARKING }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_TORSO_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_CHEST_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_GUT_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_WAIST_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_ARM_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_HAND_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_HIP_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_BUTTOCKS_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_LEG_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_FOOT_SIZE }, }, }, [CREATE_BUCKET_HEAD_TYPE] = { windowName = "HeadTypeBucket_Gamepad", title = GetString(SI_CREATE_CHARACTER_GAMEPAD_BUCKET_TITLE_HEAD_TYPE), onExpandFn = function() SetCharacterCameraZoomAmount(1) end, controls = { { GAMEPAD_BUCKET_CONTROL_TYPE_CUSTOM, GAMEPAD_BUCKET_CUSTOM_CONTROL_FACE }, } }, [CREATE_BUCKET_FEATURES] = { windowName = "FeaturesBucket_Gamepad", title = GetString(SI_CREATE_CHARACTER_GAMEPAD_BUCKET_TITLE_HEAD), previousTab = CREATE_BUCKET_CLASS, onExpandFn = function() SetCharacterCameraZoomAmount(1) end, controls = { { GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE, APPEARANCE_NAME_AGE }, { GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE, APPEARANCE_NAME_ACCESSORY }, -- "adornment" { GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE, APPEARANCE_NAME_HAIR_STYLE }, { GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE, APPEARANCE_NAME_HAIR_TINT }, { GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE, APPEARANCE_NAME_HEAD_MARKING }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_FOREHEAD_SLOPE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_CHEEK_BONE_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_CHEEK_BONE_HEIGHT }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_JAW_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_CHIN_HEIGHT }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_CHIN_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_NECK_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EAR_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EAR_ROTATION }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EAR_HEIGHT }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EAR_TIP_FLARE }, }, }, [CREATE_BUCKET_FACE] = { windowName = "FaceBucket_Gamepad", title = GetString(SI_CREATE_CHARACTER_BUCKET_TITLE_FACE), onExpandFn = function() SetCharacterCameraZoomAmount(1) end, controls = { { GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE, APPEARANCE_NAME_VOICE }, { GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE, APPEARANCE_NAME_EYE_TINT }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EYE_SIZE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EYE_ANGLE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EYE_SEPARATION }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EYE_HEIGHT }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EYE_SQUINT }, { GAMEPAD_BUCKET_CONTROL_TYPE_APPEARANCE, APPEARANCE_NAME_EYEBROW }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EYEBROW_HEIGHT }, --{ GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EYEBROW_ANGLE}, -- TODO Missing from Design? { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EYEBROW_SKEW }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_EYEBROW_DEPTH }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_NOSE_SHAPE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_NOSE_HEIGHT }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_NOSE_WIDTH }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_NOSE_LENGTH }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_MOUTH_HEIGHT }, --{ GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_MOUTH_WIDTH}, -- TODO Missing from Design? { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_MOUTH_CURVE }, { GAMEPAD_BUCKET_CONTROL_TYPE_SLIDER, SLIDER_NAME_LIP_FULLNESS }, }, }, } --[[ Character Creation Bucket Instances ]]-- ZO_CharacterCreateBucket_Gamepad = ZO_CharacterCreateBucket_Base:Subclass() function ZO_CharacterCreateBucket_Gamepad:New(...) return ZO_CharacterCreateBucket_Base.New(self, ...) end function ZO_CharacterCreateBucket_Gamepad:Initialize(...) ZO_CharacterCreateBucket_Base.Initialize(self, ...) local windowData = ZO_CHARACTER_CREATE_BUCKET_WINDOW_DATA_GAMEPAD[self.category] local container = CreateControlFromVirtual("$(parent)" .. windowData.windowName, self.parent, "ZO_CategoryBucket_Gamepad") container.bucket = self self.windowData = windowData self.container = container self.scrollChild = ZO_GamepadVerticalParametricScrollList:New(container:GetNamedChild("List")) self.scrollChild:SetFixedCenterOffset(DEFAULT_OFFSET) -- Handle all the input through this screen -- (so the focused control gets first access then we pass the input to the scrollchild) self.scrollChild:SetDirectionalInputEnabled(false) local narrationInfo = { canNarrate = function() return self.expanded end, headerNarrationFunction = function() return GAMEPAD_BUCKET_MANAGER:GetHeaderNarration() end, } SCREEN_NARRATION_MANAGER:RegisterParametricList(self.scrollChild, narrationInfo) end function ZO_CharacterCreateBucket_Gamepad:SetTabIndex(index) self.tabIndex = index end function ZO_CharacterCreateBucket_Gamepad:GetTabIndex() return self.tabIndex end function ZO_CharacterCreateBucket_Gamepad:SetEnabled(enabled) self.manager:EnableTabBarCategory(self, enabled) end function ZO_CharacterCreateBucket_Gamepad:Finalize() self:GetScrollChild():Commit() end function ZO_CharacterCreateBucket_Gamepad:AddControl(control, updateFn, randomizeFn, subCategoryId, narrationText, directionalInputNarrationFunction) control.bucket = self control:ClearAnchors() local list = self:GetScrollChild() list:AddEntry("ZO_CharacterCreateEntry_Gamepad", { control = control, narrationText = narrationText, additionalInputNarrationFunction = directionalInputNarrationFunction }, control.prePadding, control.postPadding, control.preSelectedOffsetAdditionalPadding, control.postSelectedOffsetAdditionalPadding, control.selectedCenterOffset) control:SetHidden(true) self.controlData[control] = { updateFn = updateFn, randomizeFn = randomizeFn } end function ZO_CharacterCreateBucket_Gamepad:RemoveControl(control) control.bucket = nil self.controlData[control] = nil end do -- Bucket List Entry Setup -- We use an empty template and then add/remove controls to the template. local function SetupListEntry(control, data, selected, selectedDuringRebuild, enable, activated) if control.occupiedBy then if control.occupiedBy:GetParent() == control then -- Detach old control control.occupiedBy:ClearAnchors() control.occupiedBy:SetParent(ZO_CharacterCreate_Gamepad) control.occupiedBy:SetAnchor(TOPLEFT, ZO_CharacterCreate_Gamepad, TOPLEFT, 0, 0) control.occupiedBy:SetHidden(true) control.occupiedBy = nil end end control:SetDimensions(data.control:GetDimensions()) data.control:SetParent(control) data.control:SetHidden(false) control.occupiedBy = data.control data.control:ClearAnchors() data.control:SetAnchorFill(control) if selected and activated then GAMEPAD_CHARACTER_CREATE_MANAGER:SetFocus(data.control.sliderObject) end end function ZO_CharacterCreateBucket_Gamepad:Reset() self.expanded = false self.controlData = {} self.scrollChild:Clear() self.scrollChild:AddDataTemplate("ZO_CharacterCreateEntry_Gamepad", SetupListEntry, ZO_GamepadMenuEntryTemplateParametricListFunction) end end function ZO_CharacterCreateBucket_Gamepad:Expand() local container = self:GetContainer() container:SetHidden(false) self.expanded = true local expandFn = self.windowData.onExpandFn if expandFn then expandFn() end end function ZO_CharacterCreateBucket_Gamepad:Collapse() self:GetContainer():SetHidden(true) self.expanded = false local collapseFunction = self.windowData.onCollapseFn if collapseFunction then collapseFunction() end end --[[ Character Creation Bucket Manager ]]-- -- order specified here is the order they will appear in game local CHARACTER_CREATE_BUCKETS = { CREATE_BUCKET_RACE, CREATE_BUCKET_BODY, CREATE_BUCKET_BODY_SHAPE, CREATE_BUCKET_HEAD_TYPE, CREATE_BUCKET_FEATURES, CREATE_BUCKET_FACE, } ZO_CharacterCreateBucketManager_Gamepad = ZO_CharacterCreateBucketManager_Base:Subclass() function ZO_CharacterCreateBucketManager_Gamepad:New(...) return ZO_CharacterCreateBucketManager_Base.New(self, ...) end function ZO_CharacterCreateBucketManager_Gamepad:Initialize(container) self.tabBarEntries = {} self.headerData = { tabBarEntries = self.tabBarEntries, --Hacky solution; pretend the gear preview info is part of the header for narration purposes. Some day we should actually make it part of the header subtitleTextNarration = function() return GAMEPAD_CHARACTER_CREATE_MANAGER:GetCurrentGearPreviewInfo().modeName end, } ZO_CharacterCreateBucketManager_Base.Initialize(self, container, CHARACTER_CREATE_BUCKETS) self.active = false self.onTargetDataChangedCallback = function(...) self:OnTargetDataChanged(...) end local header = GAMEPAD_CHARACTER_CREATE_MANAGER.header ZO_GamepadGenericHeader_Refresh(header, self.headerData) end function ZO_CharacterCreateBucketManager_Gamepad:AddBucket(bucketCategory) local bucket = ZO_CharacterCreateBucket_Gamepad:New(self.container, bucketCategory, self) local bucketContainer = bucket:GetContainer() bucketContainer:SetAnchor(TOPLEFT, self.container, TOPLEFT, 13, 138) bucketContainer:SetAnchor(BOTTOMRIGHT, self.container, BOTTOMRIGHT, -14, -73) self.buckets[bucketCategory] = bucket local tabBarParams = { text = bucket.windowData.title, bucket = bucket.windowData, callback = function() self:OnTabBarCategoryChanged(bucket.category) end, } table.insert(self.tabBarEntries, tabBarParams) bucket:SetTabIndex(#self.tabBarEntries) end function ZO_CharacterCreateBucketManager_Gamepad:OnTabBarCategoryChanged(bucketCategory) self:SwitchBucketsInternal(bucketCategory) end function ZO_CharacterCreateBucketManager_Gamepad:EnableTabBarCategory(bucket, enabled) local tabBarParams = self.tabBarEntries[bucket:GetTabIndex()] tabBarParams.visible = enabled local header = GAMEPAD_CHARACTER_CREATE_MANAGER.header ZO_GamepadGenericHeader_Refresh(header, self.headerData) end function ZO_CharacterCreateBucketManager_Gamepad:OnTargetDataChanged(list, selectedData, oldSelectedData) local selectedInfo = selectedData and selectedData.control and selectedData.control.sliderObject and selectedData.control.sliderObject.info GAMEPAD_CHARACTER_CREATE_MANAGER:UpdateCollectibleBlockingInfoTooltip(selectedInfo) end function ZO_CharacterCreateBucketManager_Gamepad:Activate() if not self.active then self.active = true if self.currentBucket then self.currentBucket:Expand() self.currentBucket:GetScrollChild():SetOnTargetDataChangedCallback(self.onTargetDataChangedCallback) self.currentBucket:GetScrollChild():Activate() self.currentBucket:GetScrollChild():RefreshVisible() end end end function ZO_CharacterCreateBucketManager_Gamepad:Deactivate() if self.active then self.active = false if self.currentBucket then self.currentBucket:Collapse() if self.onTargetDataChangedCallback then self.currentBucket:GetScrollChild():RemoveOnTargetDataChangedCallback(self.onTargetDataChangedCallback) end self.currentBucket:GetScrollChild():Deactivate() end end end function ZO_CharacterCreateBucketManager_Gamepad:SwitchBuckets(bucketCategory) local bucket = self:BucketForCategory(bucketCategory) local tab = bucket:GetTabIndex() ZO_GamepadGenericHeader_SetActiveTabIndex(GAMEPAD_CHARACTER_CREATE_MANAGER.header, tab) end function ZO_CharacterCreateBucketManager_Gamepad:SwitchBucketsInternal(bucketCategory) local bucket = self:BucketForCategory(bucketCategory) if bucket == self.currentBucket then return end -- collapse current bucket if self.currentBucket then self.currentBucket:Collapse() if self.active then if self.onTargetDataChangedCallback then self.currentBucket:GetScrollChild():RemoveOnTargetDataChangedCallback(self.onTargetDataChangedCallback) end self.currentBucket:GetScrollChild():Deactivate() end self.currentBucket = nil end -- expand desired bucket if bucket then bucket:Expand() self.currentBucket = bucket if self.active then self.currentBucket:GetScrollChild():SetOnTargetDataChangedCallback(self.onTargetDataChangedCallback) self.currentBucket:GetScrollChild():Activate() self.currentBucket:GetScrollChild():RefreshVisible() end end end function ZO_CharacterCreateBucketManager_Gamepad:MoveNext() self.currentBucket:GetScrollChild():MoveNext() end function ZO_CharacterCreateBucketManager_Gamepad:MovePrevious() self.currentBucket:GetScrollChild():MovePrevious() end function ZO_CharacterCreateBucketManager_Gamepad:SetEnabled(category, enabled) local bucket = self:BucketForCategory(category) bucket:SetEnabled(enabled) end function ZO_CharacterCreateBucketManager_Gamepad:Finalize() for _, bucket in pairs(self.buckets) do bucket:Finalize() end end function ZO_CharacterCreateBucketManager_Gamepad:GetHeaderNarration() return ZO_GamepadGenericHeader_GetNarrationText(GAMEPAD_CHARACTER_CREATE_MANAGER.header, self.headerData) end function ZO_CharacterCreateBucketManager_Gamepad:NarrateCurrentBucket(narrateHeader) if self.currentBucket then SCREEN_NARRATION_MANAGER:QueueParametricListEntry(self.currentBucket:GetScrollChild(), narrateHeader) end end function ZO_CharacterCreateBucketManager_Gamepad:Reset() ZO_CharacterCreateBucketManager_Base.Reset(self) if self.active and self.currentBucket then self.currentBucket:Expand() end end