From 65acacd6383337057060e0d0aa9d8b5d80c04bc7 Mon Sep 17 00:00:00 2001 From: jhaakma Date: Mon, 2 Sep 2024 00:40:44 +1200 Subject: [PATCH] Improve menu flow, add multi-choice locations for mage/fighters guild quests and more --- .../controllers/registerClutter.lua | 88 +++++ .../controllers/registerLocations.lua | 62 +--- .../ScenarioBuilder/luaLogger.lua | 26 ++ .../chargenScenarios/ScenarioBuilder/main.lua | 1 + .../chargenScenarios/component/ItemPick.lua | 26 +- .../chargenScenarios/component/Location.lua | 16 + .../chargenScenarios/component/Scenario.lua | 57 +-- .../component/ScenarioSelector.lua | 90 ++++- .../integrations/locations.lua | 16 - .../integrations/mer_mods.lua | 14 + .../integrations/scenarios.lua | 332 ++++++++++++++++-- .../integrations/tr_scenarios.lua | 23 +- .../modules/chargenMenuController.lua | 139 ++++++-- 13 files changed, 714 insertions(+), 176 deletions(-) create mode 100644 Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/controllers/registerClutter.lua create mode 100644 Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/luaLogger.lua delete mode 100644 Data Files/MWSE/mods/mer/chargenScenarios/integrations/locations.lua create mode 100644 Data Files/MWSE/mods/mer/chargenScenarios/integrations/mer_mods.lua diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/controllers/registerClutter.lua b/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/controllers/registerClutter.lua new file mode 100644 index 0000000..aa9ccb7 --- /dev/null +++ b/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/controllers/registerClutter.lua @@ -0,0 +1,88 @@ + +local common = require("mer.chargenScenarios.common") +local Controls = require("mer.chargenScenarios.util.Controls") + + +local logger = require("mer.chargenScenarios.ScenarioBuilder.luaLogger").new{ + outputFile = "ChargenScenarioClutter.txt", +} + +local luaClutterTemplate = [[ + { --${name} + ids = {"${ids}"}, + position = {${posx}, ${posy}, ${posz}}, + orientation = {${orz}}, + cell = "${cell}", + scale = ${scale}, + }, +]] + +local function addClutter(clutterToAdd) + local clutterString = luaClutterTemplate: + gsub("${name}", clutterToAdd.name): + gsub("${id}", clutterToAdd.id): + gsub("${posx}", clutterToAdd.position[1]): + gsub("${posy}", clutterToAdd.position[2]): + gsub("${posz}", clutterToAdd.position[3]): + gsub("${orz}", table.concat(clutterToAdd.orientation, ", ")): + gsub("${cell}", clutterToAdd.cell.id): + gsub("${scale}", clutterToAdd.scale) + logger:info("\n" .. clutterString) +end + +---@param target tes3reference +local function registerClutter(target) + local clutter = { + name = target.object.name, + id = target.object.id, + position = { + math.floor(target.position.x), + math.floor(target.position.y), + math.floor(target.position.z), + }, + orientation = { + math.floor(target.orientation.x), + math.floor(target.orientation.y), + math.floor(target.orientation.z), + }, + cell = target.cell, + scale = string.format("%.2d", target.scale) + } + addClutter(clutter) +end + +---@param e keyDownEventData +local function onKeyDown(e) + if common.config.mcm.registerClutterEnabled then + if Controls.isKeyPressed(e, common.config.mcm.registerClutterHotKey) then + local result = tes3.rayTest{ + position = tes3.getPlayerEyePosition(), + direction = tes3.getPlayerEyeVector(), + ignore = { tes3.player }, + maxDistance = tes3.getPlayerActivationDistance() + } + if not (result and result.reference) then + tes3.messageBox("No reference found.") + return + end + local target = result.reference + + tes3ui.showMessageMenu{ + message = string.format("Register %s as clutter?", target.object.name), + buttons = { + { + text = "Yes", + callback = function() + registerClutter(target) + end + }, + { + text = "Cancel" + } + } + } + end + end +end +event.register("keyDown", onKeyDown) + diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/controllers/registerLocations.lua b/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/controllers/registerLocations.lua index d141db2..b914cef 100644 --- a/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/controllers/registerLocations.lua +++ b/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/controllers/registerLocations.lua @@ -2,13 +2,14 @@ To use this ]] local common = require('mer.chargenScenarios.common') -local logger = common.createLogger("registerLocations") local Controls = require("mer.chargenScenarios.util.Controls") -local Location = require("mer.chargenScenarios.component.Location") +local logger = require("mer.chargenScenarios.ScenarioBuilder.luaLogger").new{ + outputFile = "chargenScenariosLocations.txt", +} local luaLocationTemplate = [[ - ["${id}"] = { + { --${name} position = {${posx}, ${posy}, ${posz}}, orientation =${orz}, cell = "${cell}" @@ -17,19 +18,18 @@ local luaLocationTemplate = [[ local function addLocation(locationToAdd, name) - logger:info("Location: ") local locationString = luaLocationTemplate: - gsub("${id}", name): + gsub("${name}", name): gsub("${posx}", locationToAdd.position[1]): gsub("${posy}", locationToAdd.position[2]): gsub("${posz}", locationToAdd.position[3]): - gsub("${orz}", locationToAdd.orientation[3]) + gsub("${orz}", locationToAdd.orientation) if tes3.player.cell.isInterior then locationString = locationString:gsub("${cell}", locationToAdd.cell.id) else locationString = locationString:gsub("${cell}", "nil") end - mwse.log(locationString) + logger:info("\n" .. locationString) end local function registerLocation() @@ -39,11 +39,7 @@ local function registerLocation() math.floor(tes3.player.position.y), math.floor(tes3.player.position.z), }, - orientation = { - math.floor(tes3.player.orientation.x), - math.floor(tes3.player.orientation.y), - math.floor(tes3.player.orientation.z), - }, + orientation = math.floor(tes3.player.orientation.z), cell = tes3.player.cell } timer.delayOneFrame(function() @@ -53,8 +49,8 @@ local function registerLocation() menu.alignX = 0.5 ---@diagnostic disable-line menu.alignY = 0 ---@diagnostic disable-line menu.autoHeight = true - local t = { name = ""} - mwse.mcm.createTextField( + local t = { name = tes3.player.cell.name } + local textField = mwse.mcm.createTextField( menu, { label = "Enter name of location:", @@ -63,43 +59,13 @@ local function registerLocation() table = t }, callback = function() - if Location.get(t.name) then - tes3ui.showMessageMenu{ - message = "Location with this id already exists.", - buttons = { - { - text = "Overwrite", - callback = function() - addLocation(location, t.name) - tes3ui.leaveMenuMode() - tes3ui.findMenu(menuId):destroy() - end - }, - { - text = "Rename", - callback = function() - tes3ui.leaveMenuMode() - tes3ui.findMenu(menuId):destroy() - registerLocation() - end, - }, - { - text = "Cancel", - callback = function() - tes3ui.leaveMenuMode() - tes3ui.findMenu(menuId):destroy() - end - } - } - } - else - addLocation(location, t.name) - tes3ui.leaveMenuMode() - tes3ui.findMenu(menuId):destroy() - end + addLocation(location, t.name) + tes3ui.leaveMenuMode() + tes3ui.findMenu(menuId):destroy() end } ) + tes3ui.acquireTextInput(textField.elements.inputField) tes3ui.enterMenuMode(menuId) end) end diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/luaLogger.lua b/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/luaLogger.lua new file mode 100644 index 0000000..248f05a --- /dev/null +++ b/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/luaLogger.lua @@ -0,0 +1,26 @@ +--[[ + Logs lua code templates to a custom file +]] + +local luaLogger = {} + + +---@param params { outputFile: string } +function luaLogger.new(params) + local self = { + outputFile = io.open(params.outputFile, "w"), + } + + function self:info(output) + if self.outputFile then + self.outputFile:write(output .. "\n") + self.outputFile:flush() + else + print(output) + end + end + + return self +end + +return luaLogger \ No newline at end of file diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/main.lua b/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/main.lua index df3968a..099a99c 100644 --- a/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/main.lua +++ b/Data Files/MWSE/mods/mer/chargenScenarios/ScenarioBuilder/main.lua @@ -1,5 +1,6 @@ --Controllers for the scenario builder require('mer.chargenScenarios.ScenarioBuilder.controllers.registerLocations') +require('mer.chargenScenarios.ScenarioBuilder.controllers.registerClutter') --MCM local mcm = require('mer.chargenScenarios.ScenarioBuilder.mcm') event.register("modConfigReady", mcm.registerModConfig) \ No newline at end of file diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/component/ItemPick.lua b/Data Files/MWSE/mods/mer/chargenScenarios/component/ItemPick.lua index d545c21..3c1d1e8 100644 --- a/Data Files/MWSE/mods/mer/chargenScenarios/component/ItemPick.lua +++ b/Data Files/MWSE/mods/mer/chargenScenarios/component/ItemPick.lua @@ -123,12 +123,26 @@ function ItemPick:giveToPlayer() count = 1, playSound = false, } - if pickedItem.enchantCapacity then - local isBoots = pickedItem.objectType == tes3.objectType.armor and pickedItem.slot == tes3.armorSlot.boots - local isShoes = pickedItem.objectType == tes3.objectType.clothing and pickedItem.slot == tes3.clothingSlot.shoes - local isHelmet = pickedItem.objectType == tes3.objectType.armor and pickedItem.slot == tes3.armorSlot.helmet - local blockBeast = tes3.player.object.race.isBeast and (isBoots or isShoes or isHelmet) - if not blockBeast then + + local equippableTypes = { + [tes3.objectType.armor] = true, + [tes3.objectType.clothing] = true, + [tes3.objectType.weapon] = true, + } + + if equippableTypes[pickedItem.objectType] then + local beastBlocked = { + [tes3.objectType.armor] = { + [tes3.armorSlot.boots] = true, + [tes3.armorSlot.helmet] = true, + }, + [tes3.objectType.clothing] = { + [tes3.clothingSlot.shoes] = true, + } + } + local blockedForBeasts = beastBlocked[pickedItem.objectType] + and beastBlocked[pickedItem.objectType][pickedItem.slot] + if not (tes3.player.object.race.isBeast and blockedForBeasts) then tes3.equip{ item = pickedItem, reference = tes3.player, diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/component/Location.lua b/Data Files/MWSE/mods/mer/chargenScenarios/component/Location.lua index 9a41def..26c9a97 100644 --- a/Data Files/MWSE/mods/mer/chargenScenarios/component/Location.lua +++ b/Data Files/MWSE/mods/mer/chargenScenarios/component/Location.lua @@ -1,4 +1,5 @@ ---@class (exact) ChargenScenariosLocationInput +---@field name string? @The name of the location, required for scenarios where you can choose the location ---@field position table @The position where the player will be spawned ---@field orientation number @The orientation where the player will be spawned ---@field cell? string @The cell where the player will be spawned. Nil for exteriors @@ -58,6 +59,7 @@ function Location:new(data) ---@type ChargenScenariosLocation local location = { + name = data.name, position = data.position, orientation = data.orientation, cell = data.cell, @@ -106,5 +108,19 @@ function Location.doClutter(self) end end +--Checks name, then cell, then region +function Location:getName() + if self.name then + return self.name + end + if self.cell then + return self.cell + end + local cell = tes3.getCell{ id = self.cell } + if cell and cell.region then + return cell.region.name + end + return "Unknown Location" +end return Location \ No newline at end of file diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/component/Scenario.lua b/Data Files/MWSE/mods/mer/chargenScenarios/component/Scenario.lua index fc980c7..6cc5099 100644 --- a/Data Files/MWSE/mods/mer/chargenScenarios/component/Scenario.lua +++ b/Data Files/MWSE/mods/mer/chargenScenarios/component/Scenario.lua @@ -12,29 +12,30 @@ local Clutter = require("mer.chargenScenarios.component.Clutter") local ClutterList = require("mer.chargenScenarios.component.ClutterList") ---@class ChargenScenariosScenarioInput ----@field name string @The name of the Scenario. Will be displayed in the scenario selection menu. ----@field description string @The description of the Scenario. Will be displayed in the scenario selection menu. ----@field location nil|string|ChargenScenariosLocationInput @The location of the scenario. If used instead of 'locations', this location will be used for the scenario. ----@field locations nil|string[]|ChargenScenariosLocationInput[] @A list of locations. If used instead of 'location', one from this list will be randomly selected for the scenario. ----@field items nil|ChargenScenariosItemPickInput[] @A list of items that will be added to the player's inventory. ----@field spells nil|ChargenScenariosSpellPickInput[] @A list of spells that will be added to the player ----@field requirements nil|ChargenScenariosRequirementsInput @The requirements that need to be met for this scenario to be used. ----@field clutter nil|string|ChargenScenariosClutterInput[] @The clutter for the location. Can be a list of clutter data or a cluterList ID ----@field onStart nil|fun(self: ChargenScenariosScenario) @Callback triggered when a scenario starts. ----@field doVanillaChargen nil|boolean @If true, the vanilla chargen will be used. +---@field id string A unique ID for the scenario +---@field name string The name of the Scenario. Will be displayed in the scenario selection menu. +---@field description string The description of the Scenario. Will be displayed in the scenario selection menu. +---@field location nil|string|ChargenScenariosLocationInput The location of the scenario. If used instead of 'locations', this location will be used for the scenario. +---@field locations nil|string[]|ChargenScenariosLocationInput[] A list of locations. If used instead of 'location', one from this list will be randomly selected for the scenario. +---@field items nil|ChargenScenariosItemPickInput[] A list of items that will be added to the player's inventory. +---@field spells nil|ChargenScenariosSpellPickInput[] A list of spells that will be added to the player +---@field requirements nil|ChargenScenariosRequirementsInput The requirements that need to be met for this scenario to be used. +---@field clutter nil|string|ChargenScenariosClutterInput[] The clutter for the location. Can be a list of clutter data or a cluterList ID +---@field onStart nil|fun(self: ChargenScenariosScenario) Callback triggered when a scenario starts. + ---@class (exact) ChargenScenariosScenario ----@field name string @the name of the scenario ----@field description string @the description of the scenario ----@field requirements ChargenScenariosRequirements @the requirements for the scenario ----@field locations ChargenScenariosLocation[] @the list of locations for the scenario ----@field itemList? ChargenScenariosItemList @the list of items for the scenario ----@field spellList? ChargenScenariosSpellList @the list of spells given to the player for this scenario. May include abilities, diseases etc ----@field clutterList? ChargenScenariosClutterList @the clutter for the location ----@field onStart? fun(self: ChargenScenariosScenario) @Callback triggered when a scenario starts. ----@field doVanillaChargen boolean @whether or not to do the vanilla chargen. ----@field decidedLocation? ChargenScenariosLocation @the location that was decided for this scenario ----@field registeredScenarios table @the list of registered scenarios +---@field id string A unique ID for hte scenario +---@field name string the name of the scenario +---@field description string the description of the scenario +---@field requirements ChargenScenariosRequirements the requirements for the scenario +---@field locations ChargenScenariosLocation[] the list of locations for the scenario +---@field itemList? ChargenScenariosItemList the list of items for the scenario +---@field spellList? ChargenScenariosSpellList the list of spells given to the player for this scenario. May include abilities, diseases etc +---@field clutterList? ChargenScenariosClutterList the clutter for the location +---@field onStart? fun(self: ChargenScenariosScenario) Callback triggered when a scenario starts. +---@field decidedLocation? ChargenScenariosLocation the index of the location that was decided for this scenario +---@field registeredScenarios table the list of registered scenarios local Scenario = { registeredScenarios = {}, } @@ -56,6 +57,7 @@ function Scenario:new(data) end local scenario = { + id = data.id, name = data.name, description = data.description, requirements = Requirements:new(data.requirements), @@ -64,7 +66,6 @@ function Scenario:new(data) spellList = data.spells and SpellList:new(data.spells), clutterList = clutter, onStart = data.onStart, - doVanillaChargen = data.doVanillaChargen, } --Create scenario setmetatable(scenario, { __index = Scenario }) @@ -82,7 +83,7 @@ end function Scenario:register(data) local scenario = self:new(data) logger:debug("Adding %s to scenario list", scenario.name) - Scenario.registeredScenarios[scenario.name] = scenario + Scenario.registeredScenarios[scenario.id] = scenario return scenario end @@ -117,6 +118,16 @@ function Scenario:getStartingLocation() return self.decidedLocation end +function Scenario:getValidLocations() + local validLocations = {} + for _, location in pairs(self.locations) do + if location:checkRequirements() then + table.insert(validLocations, location) + end + end + return validLocations +end + --- Move the player to the starting location function Scenario:moveToLocation() if not self.locations then diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/component/ScenarioSelector.lua b/Data Files/MWSE/mods/mer/chargenScenarios/component/ScenarioSelector.lua index 3c5ed65..a9972a6 100644 --- a/Data Files/MWSE/mods/mer/chargenScenarios/component/ScenarioSelector.lua +++ b/Data Files/MWSE/mods/mer/chargenScenarios/component/ScenarioSelector.lua @@ -2,6 +2,7 @@ local ScenarioSelector = {} local menuId = tes3ui.registerID("Mer_ScenarioSelectorMenu") local descriptionHeaderID = tes3ui.registerID("Mer_ScenarioSelectorDescriptionHeader") local descriptionID = tes3ui.registerID("Mer_ScenarioSelectorDescription") +local locationDropdownBlockID = tes3ui.registerID("Mer_ScenarioSelectorLocationDropdownBlock") local common = require("mer.chargenScenarios.common") local logger = common.createLogger("ScenarioSelector") @@ -16,6 +17,7 @@ local function createHeading(parent) id = tes3ui.registerID("Mer_ScenarioSelectorMenu_heading"), text = "Select your Scenario:" } + title.color = tes3ui.getPalette("header_color") title.absolutePosAlignX = 0.5 title.borderTop = 4 title.borderBottom = 4 @@ -42,7 +44,7 @@ local function createScenarioListBlock(parent) local scenarioListBlock = parent:createVerticalScrollPane{ id = tes3ui.registerID("scenarioListBlock") } - scenarioListBlock.layoutHeightFraction = 1.0 + scenarioListBlock.heightProportional = 1.0 scenarioListBlock.minWidth = 300 scenarioListBlock.autoWidth = true scenarioListBlock.paddingAllSides = 4 @@ -63,7 +65,9 @@ local function sortListAlphabetically(list) return sortedList end +---@param scenario ChargenScenariosScenario local function onClickScenario(scenario) + logger:debug("Clicked Scenario %s", scenario.name) local menu = tes3ui.findMenu(menuId) if not menu then return end local header = menu:findChild(descriptionHeaderID) @@ -74,7 +78,10 @@ local function onClickScenario(scenario) scenario.requirements:getDescription()) local okayButton = menu:findChild(tes3ui.registerID("Mer_ScenarioSelectorMenu_okayButton")) - if not scenario:checkRequirements() then + + local scenarioValid = scenario:checkRequirements() + + if not scenarioValid then header.color = tes3ui.getPalette("disabled_color") okayButton.widget.state = 2 okayButton.disabled = true @@ -85,6 +92,72 @@ local function onClickScenario(scenario) okayButton.disabled = false end + local locationDropdownBlock = menu:findChild(locationDropdownBlockID) + locationDropdownBlock:destroyChildren() + + local validLocations = scenario:getValidLocations() + if scenarioValid and #validLocations > 1 then + + local button = locationDropdownBlock:createButton{ text = "Location: " .. scenario:getStartingLocation():getName()} + button:register("mouseClick", function() + local selectLocationMenu = tes3ui.createMenu{ id = tes3ui.registerID("Mer_SelectLocationMenu"), fixedFrame = true } + tes3ui.enterMenuMode(selectLocationMenu.id) + local outerBlock = selectLocationMenu:createBlock() + outerBlock.flowDirection = "top_to_bottom" + outerBlock.autoHeight = true + outerBlock.autoWidth = true + + local heading = outerBlock:createLabel{ text = "Select Location:"} + heading.color = tes3ui.getPalette("header_color") + + local currentLocationText = outerBlock:createLabel{ text = scenario:getStartingLocation():getName()} + + local locationListBlock = outerBlock:createVerticalScrollPane{} + local rowHeight = 23 + locationListBlock.minHeight = math.clamp(#validLocations * rowHeight, rowHeight*2, rowHeight*14) + locationListBlock.minWidth = 300 + locationListBlock.autoWidth = true + locationListBlock.paddingAllSides = 4 + locationListBlock.borderRight = 6 + + for _, location in ipairs(validLocations) do + local locationButton = locationListBlock:createTextSelect{ + text = location:getName(), + id = tes3ui.registerID("locationButton_" .. location:getName()) + } + locationButton.autoHeight = true + locationButton.widthProportional = 1.0 + locationButton.paddingAllSides = 2 + locationButton.borderAllSides = 2 + locationButton:register("mouseClick", function() + scenario.decidedLocation = location + currentLocationText.text = location:getName() + button.text = "Location: " .. location:getName() + end) + end + + local buttonsBlock = outerBlock:createBlock() + buttonsBlock.flowDirection = "left_to_right" + buttonsBlock.widthProportional = 1.0 + buttonsBlock.autoHeight = true + + --randomise button + local randomButton = buttonsBlock:createButton{ text = "Random"} + randomButton:register("mouseClick", function() + local index = math.random(#validLocations) + local list = locationListBlock:getContentElement().children + list[index]:triggerEvent("mouseClick") + end) + + --okay button + local okayButton = buttonsBlock:createButton{ text = "Ok"} + okayButton:register("mouseClick", function() + selectLocationMenu:destroy() + end) + + selectLocationMenu:updateLayout() + end) + end description:updateLayout() end @@ -120,10 +193,11 @@ local function populateScenarioList(listBlock, list, onScenarioSelected, current end end +---@param parent tes3uiElement local function createDescriptionBlock(parent) local descriptionBlock = parent:createThinBorder() - descriptionBlock.layoutHeightFraction = 1.0 - descriptionBlock.width = 300 + descriptionBlock.heightProportional = 1.0 + descriptionBlock.width = 350 descriptionBlock.borderRight = 10 descriptionBlock.flowDirection = "top_to_bottom" descriptionBlock.paddingAllSides = 10 @@ -133,6 +207,14 @@ local function createDescriptionBlock(parent) local descriptionText = descriptionBlock:createLabel{id = descriptionID, text = ""} descriptionText.wrapText = true + descriptionText.heightProportional = 1.0 + + + local locationDropdownBlock = descriptionBlock:createBlock{ id = locationDropdownBlockID} + locationDropdownBlock.autoHeight = true + locationDropdownBlock.widthProportional = 1.0 + locationDropdownBlock.childAlignX = 0.5 + return descriptionText end diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/integrations/locations.lua b/Data Files/MWSE/mods/mer/chargenScenarios/integrations/locations.lua deleted file mode 100644 index af23dd7..0000000 --- a/Data Files/MWSE/mods/mer/chargenScenarios/integrations/locations.lua +++ /dev/null @@ -1,16 +0,0 @@ -local Location = require("mer.chargenScenarios.component.Location") - - - -local locations = { - ["vanillaStart"] = { - orientation = 2, - position = {33,-87,194}, - cell = "Seyda Neen, Census and Excise Office" - }, - -} - -for id, location in pairs(locations) do - Location.register(id, location) -end \ No newline at end of file diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/integrations/mer_mods.lua b/Data Files/MWSE/mods/mer/chargenScenarios/integrations/mer_mods.lua new file mode 100644 index 0000000..a535224 --- /dev/null +++ b/Data Files/MWSE/mods/mer/chargenScenarios/integrations/mer_mods.lua @@ -0,0 +1,14 @@ +--[[ + Scenarioss specific to other Merlord Mods +]] + +local Scenario = require("mer.chargenScenarios.component.Scenario") + +---@type ChargenScenariosScenarioInput[] +local scenarios = { + +} + +for _, scenario in ipairs(scenarios) do + Scenario:register(scenario) +end \ No newline at end of file diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/integrations/scenarios.lua b/Data Files/MWSE/mods/mer/chargenScenarios/integrations/scenarios.lua index 4aa4c8a..cbf3bb5 100644 --- a/Data Files/MWSE/mods/mer/chargenScenarios/integrations/scenarios.lua +++ b/Data Files/MWSE/mods/mer/chargenScenarios/integrations/scenarios.lua @@ -32,14 +32,19 @@ local excludesOaabShipwreck = { ---@type ChargenScenariosScenarioInput[] local scenarios = { { + id = "vanilla", name = "--Vanilla--", description = "Start the game in the Seyda Neen Census and Excise Office.", - location = "vanillaStart", - doVanillaChargen = true + location = { + orientation = 2, + position = {33,-87,194}, + cell = "Seyda Neen, Census and Excise Office" + }, }, { + id = "hidingFromTheLaw", name = "Hiding from the Law", - description = "You are a wanted criminal, hiding in the outskirts of the Ascadia Isles. You have a bounty on your head and a few stolen gems in you possession. Can you escape the law and make a new life for yourself?", + description = "You are a wanted criminal, hiding in the outskirts of the Ascadian Isles.", location = { position = { 13078, -78339, 402}, orientation = 217 @@ -60,7 +65,7 @@ local scenarios = { } }, { - + id = "pearlDiving", name = "Pearl Diving", description = "You are diving for pearls in the waters near Pelagiad", location = { @@ -81,6 +86,7 @@ local scenarios = { }, { + id = "huntingInGrazelands", name = "Hunting in the Grazelands", description = "You are a hunter, stalking your prey in the Grazelands.", location = { @@ -104,6 +110,7 @@ local scenarios = { } }, { + id = "workingInTheFields", name = "Working in the Fields", description = "You are a lowly slave, toiling in the fields outside of Pelagiad.", location = { @@ -124,12 +131,12 @@ local scenarios = { requirements = requiresBeastRace, }, { + id = "gatheringMushrooms", name = "Gathering Mushrooms", description = "You are in the swamps of the Bitter Coast, searching for ingredients.", location = { - position = {-42653, 28795, 355}, - orientation = 0, - cell = "-6,3" + position = {-44618, 29841, 598}, + orientation =2, }, items = { { @@ -153,12 +160,165 @@ local scenarios = { end }, { + id = "graveRobbing", name = "Grave Robbing", - description = "You are a grave robber, looting the Tharys Ancestral Tomb near Balmora.", - location = { - position = {2043, 263, -164}, - orientation = 268, - cell = "Tharys Ancestral Tomb" + description = "You are a grave robber looting an ancestral tomb.", + locations = { + { --Andalen Ancestral Tomb + position = {878, -1008, 258}, + orientation =-1, + cell = "Andalen Ancestral Tomb" + }, + { --Andalor Ancestral Tomb + position = {3065, 2881, 386}, + orientation =-2, + cell = "Andalor Ancestral Tomb" + }, + { --Andas Ancestral Tomb + position = {763, -542, -702}, + orientation =-1, + cell = "Andas Ancestral Tomb" + }, + { --Andavel Ancestral Tomb + position = {-5194, -601, 2050}, + orientation =-4, + cell = "Andavel Ancestral Tomb" + }, + { --Andrethi Ancestral Tomb + position = {2617, 1182, -894}, + orientation =-2, + cell = "Andrethi Ancestral Tomb" + }, + { --Andules Ancestral Tomb + position = {-900, 26, 257}, + orientation =0, + cell = "Andules Ancestral Tomb" + }, + { --Aran Ancestral Tomb + position = {-2353, 5163, -190}, + orientation =3, + cell = "Aran Ancestral Tomb" + }, + { --Arethan Ancestral Tomb + position = {-737, 1530, -30}, + orientation =-1, + cell = "Arethan Ancestral Tomb" + }, + { --Arys Ancestral Tomb + position = {12802, -4140, -702}, + orientation =-1, + cell = "Arys Ancestral Tomb" + }, + { --Baram Ancestral Tomb + position = {-2533, 248, 1442}, + orientation =-4, + cell = "Baram Ancestral Tomb" + }, + { --Dareleth Ancestral Tomb + position = {3802, -3038, 1602}, + orientation =-2, + cell = "Dareleth Ancestral Tomb" + }, + { --Dreloth Ancestral Tomb + position = {0, 1907, 130}, + orientation =3, + cell = "Dreloth Ancestral Tomb" + }, + { --Drinith Ancestral Tomb + position = {-300, -4552, 2722}, + orientation =-4, + cell = "Drinith Ancestral Tomb" + }, + { --Falas Ancestral Tomb + position = {-2705, -1280, 1282}, + orientation =1, + cell = "Falas Ancestral Tomb" + }, + { --Helan Ancestral Tomb + position = {-1776, 380, 258}, + orientation =1, + cell = "Helan Ancestral Tomb" + }, + { --Heran Ancestral Tomb + position = {-17, 2755, 258}, + orientation =3, + cell = "Heran Ancestral Tomb" + }, + { --Hlaalu Ancestral Tomb + position = {-249, 1261, 386}, + orientation =3, + cell = "Hlaalu Ancestral Tomb" + }, + { --Hlervi Ancestral Tomb + position = {3202, -876, 1058}, + orientation =-2, + cell = "Hlervi Ancestral Tomb" + }, + { --Hlervu Ancestral Tomb + position = {9, 2544, -510}, + orientation =3, + cell = "Hlervu Ancestral Tomb" + }, + { --Indalen Ancestral Tomb + position = {-487, -97, 2466}, + orientation =3, + cell = "Indalen Ancestral Tomb" + }, + { --Lleran Ancestral Tomb + position = {995, -958, 98}, + orientation =0, + cell = "Lleran Ancestral Tomb" + }, + { --Norvayn Ancestral Tomb + position = {-1156, -1793, 1666}, + orientation =1, + cell = "Norvayn Ancestral Tomb" + }, + { --Releth Ancestral Tomb + position = {2690, 901, 386}, + orientation =-2, + cell = "Releth Ancestral Tomb" + }, + { --Rethandus Ancestral Tomb + position = {-3160, -100, 1410}, + orientation =-4, + cell = "Rethandus Ancestral Tomb" + }, + { --Sadryn Ancestral Tomb + position = {703, -639, 34}, + orientation =0, + cell = "Sadryon Ancestral Tomb" + }, + { --Samarys Ancestral Tomb + position = {-2272, 992, 258}, + orientation =1, + cell = "Samarys Ancestral Tomb" + }, + { --Sandas Ancestral Tomb + position = {1660, 7, 258}, + orientation =-2, + cell = "Sandas Ancestral Tomb" + }, + { --Sarys Ancestral Tomb + position = {7028, 4415, 14914}, + orientation =-2, + cell = "Sarys Ancestral Tomb" + }, + { --Tharys Ancestral Tomb + position = {2092, 272, -190}, + orientation =-2, + cell = "Tharys Ancestral Tomb" + }, + { --Thelas Ancestral Tomb + position = {374, 3176, 770}, + orientation =3, + cell = "Thelas Ancestral Tomb" + }, + { --Uveran Ancestral Tomb + position = {1934, -1559, 1695}, + orientation =-4, + cell = "Uveran Ancestral Tomb" + }, }, items = { { @@ -173,7 +333,8 @@ local scenarios = { }, { id = "pick_apprentice_01", - count = 2 + count = 1, + noDuplicates = true, }, { id = "probe_apprentice_01", @@ -183,12 +344,39 @@ local scenarios = { }, }, { - name = "Mage in Training", - description = "You are a student in the Balmora Mages Guild.", - location = { - position = {505, -387, -752}, - orientation = 205, - cell = "Balmora, Guild of Mages" + id = "magesGuild", + name = "Faction: Mages Guild", + description = "You are an associate of the Mages Guild.", + onStart = function() + local mageGuild = tes3.getFaction("Mages Guild") + mageGuild.playerJoined = true + mageGuild.playerRank = 0 + end, + locations = { + { + position = {14, 187, -252}, + orientation =-4, + name = "Vivec", + cell = "Vivec, Guild of Mages" + }, + { + position = {370, -584, -761}, + orientation =-4, + name = "Balmora", + cell = "Balmora, Guild of Mages" + }, + { + position = {695, 537, 404}, + orientation =0, + name = "Caldera", + cell = "Caldera, Guild of Mages" + }, + { + position = {186, 542, 66}, + orientation =0, + name = "Sadrith Mora", + cell = "Sadrith Mora, Wolverine Hall: Mage's Guild" + }, }, items = { { @@ -204,6 +392,59 @@ local scenarios = { }, }, { + id = "fightersGuild", + name = "Faction: Fighters Guild", + description = "You are an associate of the Fighters Guild.", + onStart = function() + local fightersGuild = tes3.getFaction("Fighters Guild") + fightersGuild.playerJoined = true + fightersGuild.playerRank = 0 + end, + locations = { + { + position = {-901, -379, -764}, + orientation =0, + name = "Ald-Rhun", + cell = "Ald-ruhn, Guild of Fighters" + }, + { + position = {304, 293, -377}, + orientation =0, + name = "Balmora", + cell = "Balmora, Guild of Fighters" + }, + { + position = {306, -222, 3}, + orientation =-1, + name = "Sadrith Mora", + cell = "Sadrith Mora, Wolverine Hall: Fighter's Guild" + }, + { + position = {179, 822, -508}, + orientation =-2, + name = "Vivec", + cell = "Vivec, Guild of Fighters" + }, + }, + items = { + { + id = "iron_greaves", + count = 1, + noDuplicates = true, + }, + { + id = "AB_w_IronRapier", + count = 1, + noDuplicates = true, + }, + { + id = "p_restore_health_s", + count = 4, + } + } + }, + { + id = "lumberjack", name = "Lumberjack", description = "You are gathering firewood in the wilderness.", location = { @@ -225,7 +466,8 @@ local scenarios = { }, }, { - name = "Prisoner", + id = "prisoner", + name = "Imprisoned", description = "You are imprisoned in the Vivec Hlaalu Prison.", location = { position = {274, -214, -100}, @@ -245,95 +487,113 @@ local scenarios = { }, }, { + id = "shipwrecked", name = "Shipwrecked", description = "You are the sole survivor of a shipwreck.", locations = { { --abandoned shipwreck - OAAB + name = "Abandoned Shipwreck", position = {9256, 187865, 79}, orientation = 2, requirements = requiresOaabShipwreck, }, - { --loneseom shipwreck - OAAB + { --Lonesome shipwreck - OAAB + name = "Lonesome Shipwreck", position = {112247, 127534, 30}, orientation = -2, requirements = requiresOaabShipwreck, }, { --neglected shipwreck - OAAB + name = "Neglected Shipwreck", position = {4049, 4179, 79}, orientation = -3, cell = "Neglected Shipwreck, Cabin", requirements = requiresOaabShipwreck, }, { --prelude shipwreck - OAAB + name = "Prelude Shipwreck", position = {4170, 4245, 63}, orientation = -3, cell = "Prelude Shipwreck, Cabin", requirements = requiresOaabShipwreck, }, { --remote shipwreck - OAAB + name = "Remote Shipwreck", position = {-8307, -84454, 93}, orientation =-2, requirements = requiresOaabShipwreck, }, { --shunned shipwreck - OAAB + name = "Shunned Shipwreck", position = {-74895, 14527, -29}, orientation =-3, requirements = requiresOaabShipwreck, }, { -- abandoned shipwreck - Vanilla + name = "Abandoned Shipwreck", position = {-1, -185, -26}, orientation =-4, requirements = excludesOaabShipwreck, cell = "Abandoned Shipwreck, Cabin" }, { -- derelict shipwreck - Vanilla + name = "Derelict Shipwreck", position = {-51690, 152197, 256}, orientation =2, requirements = excludesOaabShipwreck, }, { -- deserted shipwreck - Vanilla + name = "Deserted Shipwreck", position = {74492, -85701, 29}, orientation =-4, requirements = excludesOaabShipwreck, }, { -- lonely shipwreck - Vanilla + name = "Lonely Shipwreck", position = {154892, -6903, 51}, orientation =2, requirements = excludesOaabShipwreck, }, { -- lost shipwreck - Vanilla + name = "Lost Shipwreck", position = {127245, 94761, 71}, orientation =2, requirements = excludesOaabShipwreck, }, { -- remote shipwreck - Vanilla + name= "Remote Shipwreck", position = {-7894, -84541, 90}, orientation =2, requirements = excludesOaabShipwreck, }, { -- shunned shipwreck - Vanilla + name= "Shunned Shipwreck", position = {-75958, 14512, -20}, orientation =1, requirements = excludesOaabShipwreck, }, { -- strange shipwreck - Vanilla + name= "Strange Shipwreck", position = {4172, 4017, 15651}, orientation =-1, requirements = excludesOaabShipwreck, cell = "Strange Shipwreck, Cabin" }, { -- unchartered shipwreck - Vanilla + name= "Unchartered Shipwreck", position = {4221, 4034, 15466}, orientation =-1, requirements = excludesOaabShipwreck, cell = "Unchartered Shipwreck, Cabin" }, { -- unexplored shipwreck - Vanilla + name= "Unexplored Shipwreck", position = {-40235, -55708, 79}, orientation =-1, requirements = excludesOaabShipwreck, }, { -- unknown shipwreck - Vanilla + name= "Unknown Shipwreck", position = {132532, 37476, 338}, orientation =-2, requirements = excludesOaabShipwreck, @@ -347,7 +607,8 @@ local scenarios = { } }, { - name = "Khuul Camping", + id = "khuulCamping", + name = "Camping", description = "You are setting up camp near Khuul.", location = { position = {-78170, 143029, 427}, @@ -374,14 +635,9 @@ local scenarios = { } }, }, - --[[ elseif ( button == 6 ) ;Working as a commoner in Maar Gan - Player->PositionCell 29,-384,-386,0, "Maar Gan, Andus Tradehouse" - Player->AddItem "gold_001", 35 - Player->AddItem "misc_com_bucket_01", 1 - Player->AddItem "misc_de_cloth10", 1 - Player->AddItem "misc_de_tankard_01", 1]] { - name = "Working as a Commoner", + id= "commoner", + name = "Commoner", description = "You are working as a commoner in the Andus Tradehouse in Maar Gan.", location = { position = {29, -384, -386}, @@ -411,14 +667,8 @@ local scenarios = { } } }, - --[[ elseif ( button == 7 ) ;Paying homage at the Fields of Kummu - Player->PositionCell 14330,-33457,774,57, "1,-5" - Player->RemoveItem "iron dagger", 1 - Player->RemoveItem "common_shirt_01", 1 - Player->AddItem "bk_PilgrimsPath", 1 - Player->AddItem "common_robe_01", 1 - ]] { + id = "pilgrimage", name = "Pilgrimage", description = "You are paying homage at the Fields of Kummu.", location = { @@ -443,6 +693,7 @@ local scenarios = { } }, { + id = "shakingDownFargoth", name = "Shaking Down Fargoth", description = "You are in Seyda Neen, shaking down Fargoth for all he's worth.", location = { @@ -478,6 +729,7 @@ local scenarios = { } }, { + id = "houseOfEarthlyDelights", name = "House of Earthly Delights", description = "You are enjoying the pleasures of Desele's House of Earthly Delights in Suran.", location = { @@ -497,7 +749,8 @@ local scenarios = { } }, { - name = "Fishing in Hla Oad", + id = "fishing", + name = "Fishing", description = "You are fishing in the waters of Hla Oad.", location ={ position = {-48464, -38956, 211}, @@ -538,7 +791,8 @@ local scenarios = { } }, { - name = "Egg Farming", + id = "eggFarmer", + name = "Egg Farmer", description = "You are farming Kwama Eggs in the Shulk Egg Mine.", location = { position = {4457, 3423, 12612}, @@ -566,6 +820,7 @@ local scenarios = { } }, { + id = "hauntedRoom", name = "Haunted Room", description = "You are sleeping in a haunted room at the Gateway Inn in Sadrith Mora.", location = { @@ -589,6 +844,7 @@ local scenarios = { end }, { + id = "bardInPelagiad", name = "Bard in Pelagiad", description = "You are a bard in the Halfway Tavern in Pelagiad.", location = { diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/integrations/tr_scenarios.lua b/Data Files/MWSE/mods/mer/chargenScenarios/integrations/tr_scenarios.lua index 73f96ce..d6de315 100644 --- a/Data Files/MWSE/mods/mer/chargenScenarios/integrations/tr_scenarios.lua +++ b/Data Files/MWSE/mods/mer/chargenScenarios/integrations/tr_scenarios.lua @@ -1,8 +1,10 @@ local Scenario = require("mer.chargenScenarios.component.Scenario") +---@type ChargenScenariosScenarioInput[] local scenarios = { { + id = "oldEbonheartAlley", name = "Old Ebonheart Alley", description = "You are playing dice in an alley in Old Ebonheart.", location = { @@ -27,6 +29,7 @@ local scenarios = { } }, { + id = "firewatchCollege", name = "College of Firewatch", description = "You are a student at the College of Firewatch.", location = { @@ -47,6 +50,7 @@ local scenarios = { } }, { + id = "caravanGuard", name = "Caravan Guard", description = "You are guarding a caravan in Arvud.", location = { @@ -67,6 +71,7 @@ local scenarios = { } }, { + id = "kemelZeRuins", name = "Kemel-Ze Ruins", description = "You are exploring the ruins of Kemel-Ze.", location = { @@ -91,6 +96,7 @@ local scenarios = { }, }, { + id = "dreynimSpa", name = "Dreynim Spa", description = "You are on holiday at Dreynim Spa.", location = { @@ -116,6 +122,7 @@ local scenarios = { }, }, { + id = "arrivingInNivalis", name = "Arriving in Nivalis", description = "You have just arrived at the Imperial settlement of Nivalis.", location = { @@ -141,6 +148,7 @@ local scenarios = { }, }, { + id = "sadasPlantation", name = "Sadas Plantation", description = "You are a slave working on the Sadas Plantation.", location = { @@ -165,10 +173,11 @@ local scenarios = { }, }, requirements = { - races = {"Argonian", "Khajiit"} + races = {"Argonian", "Khajiit"}, }, }, { + id = "workingOnTheDocks", name = "Working on the Docks", description = "You are a dock worker in Andothren.", location = { @@ -198,6 +207,7 @@ local scenarios = { }, }, { + id = "fishingAtDragonheadPoint", name = "Fishing at Dragonhead Point", description = "You are fishing at Dragonhead Point.", location = { @@ -238,8 +248,13 @@ local scenarios = { } for _, scenario in ipairs(scenarios) do - scenario.requirements = { - plugins = {"TR_Mainland.esm"} - } + if not scenario.requirements then + scenario.requirements = {} + end + if not scenario.requirements.plugins then + scenario.requirements.plugins = {} + end + table.insert(scenario.requirements.plugins, "TR_Mainland.esm") + Scenario:register(scenario) end diff --git a/Data Files/MWSE/mods/mer/chargenScenarios/modules/chargenMenuController.lua b/Data Files/MWSE/mods/mer/chargenScenarios/modules/chargenMenuController.lua index 6aa8563..e3f3919 100644 --- a/Data Files/MWSE/mods/mer/chargenScenarios/modules/chargenMenuController.lua +++ b/Data Files/MWSE/mods/mer/chargenScenarios/modules/chargenMenuController.lua @@ -3,9 +3,54 @@ local logger = common.createLogger("chargenMenuController") local scenarioSelector = require('mer.chargenScenarios.component.ScenarioSelector') local Scenario = require("mer.chargenScenarios.component.Scenario") local Tooltip = require("mer.chargenScenarios.util.Tooltip") +local backgroundsInterop = include('mer.characterBackgrounds.interop') -local function returnToStatsMenu() - tes3.runLegacyScript{ command = "EnableStatReviewMenu"} ---@diagnostic disable-line +---@return ChargenScenariosScenario? +local function getSelectedScenario() + return tes3.player.tempData.selectedChargenScenario +end + +local function setScenario(scenario) + tes3.player.tempData.selectedChargenScenario = scenario +end + +local function nameChosen() + return tes3.player.tempData.chargenScenariosNameChosen +end + +local function setNameChosen() + tes3.player.tempData.chargenScenariosNameChosen = true +end + +local function raceChosen() + return tes3.player.tempData.chargenScenariosRaceChosen +end + +local function setRaceChosen() + tes3.player.tempData.chargenScenariosRaceChosen = true +end + +local function birthsignChosen() + return tes3.player.tempData.chargenScenariosBirthsignChosen +end + +local function setBirthsignChosen() + tes3.player.tempData.chargenScenariosBirthsignChosen = true +end + +local function classChosen() + return tes3.player.tempData.chargenScenariosClassChosen +end + +local function setClassChosen() + tes3.player.tempData.chargenScenariosClassChosen = true +end + +local characterBackgroundsConfig = include("mer.characterBackgrounds.config") +local function characterBackgroundsActive() + return backgroundsInterop + and characterBackgroundsConfig + and characterBackgroundsConfig.mcm.enableBackgrounds end local function openScenarioMenu() @@ -13,21 +58,30 @@ local function openScenarioMenu() scenarioList = Scenario.registeredScenarios, onScenarioSelected = function(scenario) logger:debug("Clicked scenario: %s", scenario.name) - tes3.player.tempData.selectedChargenScenario = scenario + setScenario(scenario) end, onOkayButton = function() logger:debug("Okay button pressed") - if tes3.player.tempData.selectedChargenScenario then + if getSelectedScenario() then --Return to stat review tes3.runLegacyScript{ command = "EnableStatReviewMenu"} ---@diagnostic disable-line else logger:error("No scenario selected") end end, - currentScenario = tes3.player.tempData.selectedChargenScenario + currentScenario = getSelectedScenario() } end +local function returnToStatsMenu() + local selectedScenario = getSelectedScenario() + if selectedScenario and not selectedScenario:checkRequirements() then + tes3.messageBox("Scenario Requirements no longer met. Please select again.") + openScenarioMenu() + else + tes3.runLegacyScript{ command = "EnableStatReviewMenu"} ---@diagnostic disable-line + end +end local function registerTooltip(block, name, description) local onTooltip = function() @@ -68,20 +122,18 @@ local function createScenarioButton(parent) openScenarioMenu() end) - local scenarioName = tes3.player.tempData.selectedChargenScenario and tes3.player.tempData.selectedChargenScenario.name or "" + local scenario = getSelectedScenario() + local scenarioName = scenario and scenario.name or "" createStatsButtonLabel(block, scenarioName) - local scenarioDescription = tes3.player.tempData.selectedChargenScenario and tes3.player.tempData.selectedChargenScenario.description or "" + local scenarioDescription = scenario and scenario.description or "" registerTooltip(block, scenarioName, scenarioDescription) end - - - local function createBackgroundButton(parent) - local backgroundsInterop = include('mer.characterBackgrounds.interop') - if not backgroundsInterop then return end + + if not characterBackgroundsActive() then return end local block = parent:createBlock() block.widthProportional = 1.0 block.autoHeight = true @@ -102,11 +154,11 @@ local function createBackgroundButton(parent) end local function hasCompletedChargen() - return tes3.player.tempData.chargenScenariosNameChosen - and tes3.player.tempData.chargenScenariosRaceChosen - and tes3.player.tempData.chargenScenariosBirthsignChosen - and tes3.player.tempData.chargenScenariosClassChosen - and tes3.player.tempData.selectedChargenScenario + return nameChosen() + and raceChosen() + and birthsignChosen() + and classChosen() + and getSelectedScenario() end --MenuStatReview_Okbutton @@ -134,10 +186,17 @@ local function modifyStatReviewMenu(e) --OK button should trigger the scenario to start local okButton = menu:findChild("MenuStatReview_Okbutton") okButton:register("mouseClick", function(eMouseClick) - if hasCompletedChargen() then - okButton:forwardEvent(eMouseClick) - tes3.runLegacyScript{ script = "RaceCheck" } ---@diagnostic disable-line - tes3.player.tempData.selectedChargenScenario:start() + local scenario = getSelectedScenario() + if scenario and hasCompletedChargen() then + if not scenario:checkRequirements() then + tes3.messageBox("Scenario Requirements no longer met. Please select again.") + menu:destroy() + openScenarioMenu() + else + okButton:forwardEvent(eMouseClick) + tes3.runLegacyScript{ script = "RaceCheck" } ---@diagnostic disable-line + scenario:start() + end else tes3.messageBox("You must complete the character generation process before you can continue.") end @@ -155,16 +214,19 @@ local function modifyRaceSexMenu(e) if (not e.newlyCreated) then return end + + logger:debug("Modifying racesex menu") local menu = e.element --hide back button menu:findChild("MenuRaceSex_Backbutton").visible = false - --OK button should trigger the class menu + + --override OK button local okButton = menu:findChild("MenuRaceSex_Okbutton") okButton:register("mouseClick", function(eMouseClick) - --trigger the stat review menu - okButton:forwardEvent(eMouseClick) - tes3.player.tempData.chargenScenariosRaceChosen = true - if not tes3.player.tempData.chargenScenariosClassChosen then + menu:destroy() + + setRaceChosen() + if not classChosen() then tes3.runLegacyScript{ command = "EnableClassMenu"} ---@diagnostic disable-line else returnToStatsMenu() @@ -216,8 +278,8 @@ local function modifyCreateClassMenu(e) logger:debug("Clicked ok button, returning to stat review menu") --trigger the stat review menu okButton:forwardEvent(eMouseClick) - tes3.player.tempData.chargenScenariosClassChosen = true - if not tes3.player.tempData.chargenScenariosBirthsignChosen then + setClassChosen() + if not birthsignChosen() then tes3.runLegacyScript{ command = "EnableBirthMenu"} ---@diagnostic disable-line else returnToStatsMenu() @@ -238,8 +300,8 @@ local function modifyChooseClassMenu(e) okButton:register("mouseClick", function(eMouseClick) logger:debug("Clicked ok button, returning to stat review menu") okButton:forwardEvent(eMouseClick) - tes3.player.tempData.chargenScenariosClassChosen = true - if not tes3.player.tempData.chargenScenariosBirthsignChosen then + setClassChosen() + if not birthsignChosen() then tes3.runLegacyScript{ command = "EnableBirthMenu"} ---@diagnostic disable-line else returnToStatsMenu() @@ -268,8 +330,8 @@ local function modifyBirthSignMenu(e) logger:debug("Clicked ok button, returning to stat review menu") --trigger the stat review menu okButton:forwardEvent(eMouseClick) - tes3.player.tempData.chargenScenariosBirthsignChosen = true - if not tes3.player.tempData.chargenScenariosNameChosen then + setBirthsignChosen() + if not nameChosen() then tes3.runLegacyScript{ command = "EnableNameMenu"} ---@diagnostic disable-line else returnToStatsMenu() @@ -279,7 +341,6 @@ end event.register("uiActivated", modifyBirthSignMenu, { filter = "MenuBirthSign"}) - local function selectRandomName(menu) local okButton = menu:findChild("MenuName_OkNextbutton") local race = tes3.player.object.race.name @@ -325,16 +386,20 @@ local function modifyNameMenu(e) okButton:register("mouseClick", function(eMouseClick) okButton:forwardEvent(eMouseClick) + --If character backgrounds is installed, trigger the perks menu - if tes3.player.data.merBackgrounds and not tes3.player.tempData.chargenScenariosNameChosen then + if nameChosen() then + returnToStatsMenu() + elseif characterBackgroundsActive() then logger:debug("Backgrounds is active, opening perks menu") timer.delayOneFrame(function() event.trigger("CharacterBackgrounds:OpenPerksMenu") end) else - logger:debug("Clicked okNext button, returning to stat review menu") + logger:debug("Backgrounds not active, going to scenario menu") + openScenarioMenu() end - tes3.player.tempData.chargenScenariosNameChosen = true + setNameChosen() end) --Prepopulate name option based on player race @@ -349,7 +414,7 @@ event.register("uiActivated", modifyNameMenu, { filter = "MenuName", priority = local function openScenarioSelectorOnBackgroundsFinish() logger:debug("Background selected, opening scenario menu") - if not tes3.player.tempData.selectedChargenScenario then + if not getSelectedScenario() then openScenarioMenu() else logger:debug("Scenario already selected, skipping scenario menu")