diff --git a/MWSE/mods/celediel/ASinkingFeeling/common.lua b/MWSE/mods/celediel/ASinkingFeeling/common.lua index beea550..01fcd29 100644 --- a/MWSE/mods/celediel/ASinkingFeeling/common.lua +++ b/MWSE/mods/celediel/ASinkingFeeling/common.lua @@ -2,12 +2,62 @@ local this = {} this.modName = "A Sinking Feeling" this.author = "Celediel" -this.modInfo = "No longer can you swim in heavy plate; now your armour, equipment, or carried items drag you down while swimming.\n" .. +this.modInfo = "No longer can you swim in heavy plate; now your armour, equipment, or carried items drag you down while swimming.\n\n" .. "Options exist for formulas based on equipped armour weight class, total equipment weight or encumbrance percentage.\n\n" .. "What is dead may never die." this.version = "1.0.4" this.configString = string.gsub(this.modName, "%s+", "") -this.modes = {equippedArmour = 0, allEquipment = 1, encumbrancePercentage = 2, allEquipmentNecroEdit = 3} +this.modes = { + equippedArmour = { + value = 0, + description = "Actors are pulled down by their combined armour class (Light = 1, Medium = 2, Heavy = 3) multiplied by a tenth of " .. + "the down-pull multiplier. Default of 100 makes it impossible to surface in all heavy armour for all but the most Athletic.", + }, + allEquipment = { + value = 1, + description = "Actors are pulled down by double the weight of all equipped gear multiplied by a hundredth of the down-pull multiplier.", + }, + encumbrancePercentage = { + value = 2, + description = "Actors are pulled down by their encumbrance percentage multiplied by triple the down-pull multiplier.", + }, + allEquipmentNecroEdit = { + value = 3, + description = "Actors are pulled down by their encumbrance percentage multiplied by triple the down-pull multiplier, " .. + "except any weight above 135 only counts 10%. Lessens the gap between the lightest and heaviest heavy armours.", + }, + worstCaseScenario = { + value = 4, + description = "Calculates results from all formulas, and uses the highest value.", + } +} + this.log = function(...) mwse.log("[%s] %s", this.modName, string.format(...)) end +this.camelCaseToWords = function(str) + local function spaceBefore(word) + return " " .. word + end + + local function titleCase(first, rest) + return first:upper() .. rest:lower() + end + + local words = str:gsub("%u", spaceBefore) + return words:gsub("(%a)([%w_']*)", titleCase) +end + +-- picks the key of the largest value out of a key:whatever, value:number table +this.keyOfLargestValue = function(t) + local picked + local largest = 0 + for key, value in pairs(t) do + if value > largest then + largest = value + picked = key + end + end + return picked +end + return this \ No newline at end of file diff --git a/MWSE/mods/celediel/ASinkingFeeling/config.lua b/MWSE/mods/celediel/ASinkingFeeling/config.lua index d9f2a6c..7517dd0 100644 --- a/MWSE/mods/celediel/ASinkingFeeling/config.lua +++ b/MWSE/mods/celediel/ASinkingFeeling/config.lua @@ -1,6 +1,6 @@ local common = require("celediel.ASinkingFeeling.common") -local defaultConfig = {enabled = true, debug = false, playerOnly = false, downPullMultiplier = 100, mode = common.modes.equippedArmour} +local defaultConfig = {enabled = true, debug = false, playerOnly = false, downPullMultiplier = 100, mode = common.modes.equippedArmour.value} local config = mwse.loadConfig(common.configString, defaultConfig) return config \ No newline at end of file diff --git a/MWSE/mods/celediel/ASinkingFeeling/main.lua b/MWSE/mods/celediel/ASinkingFeeling/main.lua index 2c4fe5f..aa5a03e 100644 --- a/MWSE/mods/celediel/ASinkingFeeling/main.lua +++ b/MWSE/mods/celediel/ASinkingFeeling/main.lua @@ -32,6 +32,66 @@ local function getTotalEquipmentWeight(actor) return weight end +-- Formula functions +local formulas = {} + +formulas.equippedArmour = function(actor, ref) + local armourClass = getTotalArmourClass(actor) + local downPull = (config.downPullMultiplier / 10) * armourClass + local debugStr = string.format("Pulling %s down by %s using equipped armour mode (%s total armour class)", + ref.id, downPull, armourClass) + return downPull, debugStr +end + +formulas.allEquipment = function(actor, ref) + local totalWeight = getTotalEquipmentWeight(actor) + -- doubling this keeps this formula somewhat uniform with armour class @ multiplier 100 + local downPull = ((config.downPullMultiplier / 100) * totalWeight) * 2 + local debugStr = string.format("Pulling %s down by %s using equipment weight mode (%s total equipment weight)", + ref.id, downPull, totalWeight) + return downPull, debugStr +end + +formulas.allEquipmentNecroEdit = function(actor, ref) + local totalWeight = getTotalEquipmentWeight(actor) + -- Thanks Necrolesian for this formula + -- https://forums.nexusmods.com/index.php?/topic/10349253-a-sinking-feeling/page-2#entry97870268 + local term1 = ((config.downPullMultiplier / 100) * totalWeight) * 2 + local term2 = ((config.downPullMultiplier / 100) * (totalWeight - 135) * 0.2) + 270 + local downPull = math.min(term1, term2) + local debugStr = string.format("Pulling %s down by %s (instead of %s) using equipment weight mode (necro edit) (%s total equipment weight)", + ref.id, downPull, math.max(term1, term2), totalWeight) + return downPull, debugStr +end + +formulas.encumbrancePercentage = function(mobile, ref) + local encumbrance = mobile.encumbrance + -- tripling this keeps this formula somewhat uniform with armour class @ multiplier 100 + local downPull = (config.downPullMultiplier * encumbrance.normalized) * 3 + local debugStr = string.format("Pulling %s down by %s using encumbrance mode (%s/%s = %s encumbrance)", + ref.id, downPull, encumbrance.current, encumbrance.base, encumbrance.normalized) + return downPull, debugStr +end + +formulas.worstCaseScenario = function(actor, mobile, ref) + local downPull = 0 + + local results = {} + -- todo: maybe loop over formulas to calculate each instead of this + -- different formulas needing different actor/mobile might make it too unwieldy though + results.equippedArmour = formulas.equippedArmour(actor, ref) + results.allEquipment = formulas.allEquipment(actor, ref) + results.allEquipmentNecroEdit = formulas.allEquipmentNecroEdit(actor, ref) + results.encumbrancePercentage = formulas.encumbrancePercentage(mobile, ref) + + local largest = common.keyOfLargestValue(results) + downPull = results[largest] + + local debugStr = string.format("Pulling %s down by %s using worst mode:%s", ref.id, downPull, common.camelCaseToWords(largest)) + + return downPull, debugStr +end + -- Event functions local function sinkInWater(e) -- shortcut refs @@ -54,35 +114,16 @@ local function sinkInWater(e) if not config.enabled then downPull = 0 -- calculate the down-pull with the configured formula - elseif config.mode == common.modes.equippedArmour then - local armourClass = getTotalArmourClass(actor) - downPull = (config.downPullMultiplier / 10) * armourClass - debugStr = string.format("Pulling %s down by %s using equipped armour mode (%s total armour class)", - ref.id, downPull, armourClass) - - elseif config.mode == common.modes.allEquipment then - local totalWeight = getTotalEquipmentWeight(actor) - -- doubling this keeps this formula somewhat uniform with armour class @ multiplier 100 - downPull = ((config.downPullMultiplier / 100) * totalWeight) * 2 - debugStr = string.format("Pulling %s down by %s using equipment weight mode (%s total equipment weight)", - ref.id, downPull, totalWeight) - - elseif config.mode == common.modes.allEquipmentNecroEdit then - local totalWeight = getTotalEquipmentWeight(actor) - -- Thanks Necrolesian for this formula - -- https://forums.nexusmods.com/index.php?/topic/10349253-a-sinking-feeling/page-2#entry97870268 - local term1 = ((config.downPullMultiplier / 100) * totalWeight) * 2 - local term2 = ((config.downPullMultiplier / 100) * (totalWeight - 135) * 0.2) + 270 - downPull = math.min(term1, term2) - debugStr = string.format("Pulling %s down by %s (instead of %s) using equipment weight mode (necro edit) (%s total equipment weight)", - ref.id, downPull, math.max(term1, term2), totalWeight) - - elseif config.mode == common.modes.encumbrancePercentage then - local encumbrance = mobile.encumbrance - -- tripling this keeps this formula somewhat uniform with armour class @ multiplier 100 - downPull = (config.downPullMultiplier * encumbrance.normalized) * 3 - debugStr = string.format("Pulling %s down by %s using encumbrance mode (%s/%s = %s encumbrance)", - ref.id, downPull, encumbrance.current, encumbrance.base, encumbrance.normalized) + elseif config.mode == common.modes.equippedArmour.value then + downPull, debugStr = formulas.equippedArmour(actor, ref) + elseif config.mode == common.modes.allEquipment.value then + downPull, debugStr = formulas.allEquipment(actor, ref) + elseif config.mode == common.modes.allEquipmentNecroEdit.value then + downPull, debugStr = formulas.allEquipmentNecroEdit(actor, ref) + elseif config.mode == common.modes.encumbrancePercentage.value then + downPull, debugStr = formulas.encumbrancePercentage(mobile, ref) + elseif config.mode == common.modes.worstCaseScenario.value then + downPull, debugStr = formulas.worstCaseScenario(actor, mobile, ref) end -- reset if levitating diff --git a/MWSE/mods/celediel/ASinkingFeeling/mcm.lua b/MWSE/mods/celediel/ASinkingFeeling/mcm.lua index 674be7d..399464b 100644 --- a/MWSE/mods/celediel/ASinkingFeeling/mcm.lua +++ b/MWSE/mods/celediel/ASinkingFeeling/mcm.lua @@ -1,26 +1,36 @@ local common = require("celediel.ASinkingFeeling.common") local config = require("celediel.ASinkingFeeling.config") -local function camelCaseToWords(str) - local function spaceBefore(word) - return " " .. word - end - - local function titleCase(first, rest) - return first:upper() .. rest:lower() - end - - local words = str:gsub("%u", spaceBefore) - return words:gsub("(%a)([%w_']*)", titleCase) -end - local function createTableVar(id) return mwse.mcm.createTableVariable {id = id, table = config} end +local function createDescriptions() + local description = "Formula used to calculate down-pull amount.\n\nOptions are: " + local options = "" + + -- list all current modes + for mode, _ in pairs(common.modes) do + options = options .. common.camelCaseToWords(mode) .. ", " + end + + -- strip off ending ", " + options = options:sub(1, string.len(options) - 2) + + -- add modes to description + description = description .. options + + -- add descriptions to description + for mode, t in pairs(common.modes) do + description = description .. "\n\n" .. common.camelCaseToWords(mode) .. ": " .. t.description + end + + return description +end + local function createOptions() local options = {} - for mode, i in pairs(common.modes) do - options[#options+1] = {label = camelCaseToWords(mode), value = i} + for mode, t in pairs(common.modes) do + options[#options+1] = {label = common.camelCaseToWords(mode), value = t.value} end return options @@ -50,11 +60,7 @@ category:createYesNoButton({ category:createDropdown({ label = "Down-pull formula", - description = "Formula used to calculate down-pull amount.\n\nOptions are: Equipped Armour, Equipment Weight, Encumbrance\n\n" .. - "Equipped Armour: Actors are pulled down by their combined armour class (Light = 1, Medium = 2, Heavy = 3), " .. - "multiplied by a tenth of the down-pull multiplier. Default of 100 makes it impossible to surface in all heavy armour for all but the most Athletic.\n\n" .. - "Equipment weight: Actors are pulled down by double the weight of all equipped gear multiplied by a hundredth of the down-pull multiplier.\n\n" .. - "Encumbrance: Actors are pulled down by their encumbrance percentage multiplied by triple the down-pull multiplier.\n\n", + description = createDescriptions(), options = createOptions(), variable = createTableVar("mode") })