From 312f6c90e018bc8a4a6e18576b1b6a8b1ce0b581 Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Wed, 6 Mar 2024 18:13:21 +0100 Subject: [PATCH] Rewrite SkillProgression.skillUsed to allow directly adding xp instead of going via useType. --- files/data/builtin.omwscripts | 2 +- .../omw/mechanics/playercontroller.lua | 19 ++-- files/data/scripts/omw/skillhandlers.lua | 97 +++++++++++-------- 3 files changed, 67 insertions(+), 51 deletions(-) diff --git a/files/data/builtin.omwscripts b/files/data/builtin.omwscripts index 4021ef9f11..81fb76f023 100644 --- a/files/data/builtin.omwscripts +++ b/files/data/builtin.omwscripts @@ -12,6 +12,7 @@ GLOBAL: scripts/omw/cellhandlers.lua GLOBAL: scripts/omw/usehandlers.lua GLOBAL: scripts/omw/worldeventhandlers.lua CREATURE, NPC, PLAYER: scripts/omw/mechanics/animationcontroller.lua +PLAYER: scripts/omw/skillhandlers.lua PLAYER: scripts/omw/mechanics/playercontroller.lua MENU: scripts/omw/camera/settings.lua MENU: scripts/omw/input/settings.lua @@ -19,7 +20,6 @@ PLAYER: scripts/omw/input/playercontrols.lua PLAYER: scripts/omw/camera/camera.lua PLAYER: scripts/omw/input/actionbindings.lua PLAYER: scripts/omw/input/smoothmovement.lua -PLAYER: scripts/omw/skillhandlers.lua NPC,CREATURE: scripts/omw/ai.lua # User interface diff --git a/files/data/scripts/omw/mechanics/playercontroller.lua b/files/data/scripts/omw/mechanics/playercontroller.lua index 935bf5029f..333e097404 100644 --- a/files/data/scripts/omw/mechanics/playercontroller.lua +++ b/files/data/scripts/omw/mechanics/playercontroller.lua @@ -83,18 +83,16 @@ local function skillLevelUpHandler(skillid, source, params) if not source or source == I.SkillProgression.SKILL_INCREASE_SOURCES.Usage then skillStat.progress = 0 end end -local function skillUsedHandler(skillid, useType, params) +local function skillUsedHandler(skillid, params) if NPC.isWerewolf(self) then return false end - if params.skillGain then - local skillStat = NPC.stats.skills[skillid](self) - skillStat.progress = skillStat.progress + params.skillGain + local skillStat = NPC.stats.skills[skillid](self) + skillStat.progress = skillStat.progress + params.skillGain / I.SkillProgression.getSkillProgressRequirement(skillid) - if skillStat.progress >= 1 then - I.SkillProgression.skillLevelUp(skillid, I.SkillProgression.SKILL_INCREASE_SOURCES.Usage) - end + if skillStat.progress >= 1 then + I.SkillProgression.skillLevelUp(skillid, I.SkillProgression.SKILL_INCREASE_SOURCES.Usage) end end @@ -106,14 +104,11 @@ local function onUpdate() processAutomaticDoors() end -local function onActive() - I.SkillProgression.addSkillUsedHandler(skillUsedHandler) - I.SkillProgression.addSkillLevelUpHandler(skillLevelUpHandler) -end +I.SkillProgression.addSkillUsedHandler(skillUsedHandler) +I.SkillProgression.addSkillLevelUpHandler(skillLevelUpHandler) return { engineHandlers = { onUpdate = onUpdate, - onActive = onActive, }, } diff --git a/files/data/scripts/omw/skillhandlers.lua b/files/data/scripts/omw/skillhandlers.lua index 57fc224cee..db726e8474 100644 --- a/files/data/scripts/omw/skillhandlers.lua +++ b/files/data/scripts/omw/skillhandlers.lua @@ -7,7 +7,7 @@ local Skill = core.stats.Skill --- -- Table of skill use types defined by morrowind. --- Each entry corresponds to an index into the available skill gain values +-- Each entry corresponds to an index into the available skill gain values -- of a @{openmw.types#SkillRecord} -- @type SkillUseType -- @field #number Armor_HitByOpponent 0 @@ -35,7 +35,7 @@ local Skill = core.stats.Skill -- @field #number Athletics_SwimOneSecond 1 --- --- Table of valid sources for skill increases +-- Table of all existing sources for skill increases. Any sources not listed below will be treated as equal to Trainer. -- @type SkillLevelUpSource -- @field #string Book book -- @field #string Trainer trainer @@ -52,10 +52,16 @@ local function tableHasValue(table, value) return false end -local function getSkillProgressRequirementUnorm(npc, skillid) - local npcRecord = NPC.record(npc) +local function shallowCopy(t1) + local t2 = {} + for key, value in pairs(t1) do t2[key] = value end + return t2 +end + +local function getSkillProgressRequirement(skillid) + local npcRecord = NPC.record(self) local class = NPC.classes.record(npcRecord.class) - local skillStat = NPC.stats.skills[skillid](npc) + local skillStat = NPC.stats.skills[skillid](self) local skillRecord = Skill.record(skillid) local factor = core.getGMST('fMiscSkillBonus') @@ -72,32 +78,33 @@ local function getSkillProgressRequirementUnorm(npc, skillid) return (skillStat.base + 1) * factor end -local function skillUsed(skillid, useType, scale) + +local function skillUsed(skillid, options) if #skillUsedHandlers == 0 then -- If there are no handlers, then there won't be any effect, so skip calculations return end + + -- Make a copy so we don't change the caller's table + options = shallowCopy(options) + + -- Compute use value if it was not supplied directly + if not options.skillGain then + if not options.useType or options.useType > 3 or options.useType < 0 then + print('Error: Unknown useType: '..tostring(options.useType)) + return + end + local skillStat = NPC.stats.skills[skillid](self) + local skillRecord = Skill.record(skillid) + options.skillGain = skillRecord.skillGain[options.useType + 1] - if useType > 3 or useType < 0 then - print('Error: Unknown useType: '..tostring(useType)) - return + if options.scale then + options.skillGain = options.skillGain * options.scale + end end - -- Compute skill gain - local skillStat = NPC.stats.skills[skillid](self) - local skillRecord = Skill.record(skillid) - local skillGainUnorm = skillRecord.skillGain[useType + 1] - if scale then skillGainUnorm = skillGainUnorm * scale end - local skillProgressRequirementUnorm = getSkillProgressRequirementUnorm(self, skillid) - local skillGain = skillGainUnorm / skillProgressRequirementUnorm - - -- Put skill gain in a table so that handlers can modify it - local options = { - skillGain = skillGain, - } - for i = #skillUsedHandlers, 1, -1 do - if skillUsedHandlers[i](skillid, useType, options) == false then + if skillUsedHandlers[i](skillid, options) == false then return end end @@ -156,8 +163,8 @@ return { -- end) -- -- -- Scale sneak skill progression based on active invisibility effects - -- I.SkillProgression.addSkillUsedHandler(function(skillid, useType, params) - -- if skillid == 'sneak' and useType == I.SkillProgression.SKILL_USE_TYPES.Sneak_AvoidNotice then + -- I.SkillProgression.addSkillUsedHandler(function(skillid, params) + -- if skillid == 'sneak' and params.useType == I.SkillProgression.SKILL_USE_TYPES.Sneak_AvoidNotice then -- local activeEffects = Actor.activeEffects(self) -- local visibility = activeEffects:getEffect(core.magic.EFFECT_TYPE.Chameleon).magnitude / 100 -- visibility = visibility + activeEffects:getEffect(core.magic.EFFECT_TYPE.Invisibility).magnitude @@ -172,9 +179,10 @@ return { -- @field [parent=#SkillProgression] #number version version = 0, - --- Add new skill level up handler for this actor + --- Add new skill level up handler for this actor. + -- For load order consistency, handlers should be added in the body if your script. -- If `handler(skillid, source, options)` returns false, other handlers (including the default skill level up handler) - -- will be skipped. Where skillid and source are the parameters passed to @{SkillProgression#skillLevelUp}, and options is + -- will be skipped. Where skillid and source are the parameters passed to @{#skillLevelUp}, and options is -- a modifiable table of skill level up values, and can be modified to change the behavior of later handlers. -- These values are calculated based on vanilla mechanics. Setting any value to nil will cause that mechanic to be skipped. By default contains these values: -- @@ -191,14 +199,11 @@ return { skillLevelUpHandlers[#skillLevelUpHandlers + 1] = handler end, - --- Add new skillUsed handler for this actor - -- If `handler(skillid, useType, options)` returns false, other handlers (including the default skill progress handler) - -- will be skipped. Where skillid and useType are the parameters passed to @{SkillProgression#skillUsed}, - -- and options is a modifiable table of skill progression values, and can be modified to change the behavior of later handlers. - -- By default contains the single value: - -- - -- * `skillGain` - The numeric amount of skill progress gained, normalized to the range 0 to 1, where 1 is a full level. - -- + --- Add new skillUsed handler for this actor. + -- For load order consistency, handlers should be added in the body of your script. + -- If `handler(skillid, options)` returns false, other handlers (including the default skill progress handler) + -- will be skipped. Where options is a modifiable table of skill progression values, and can be modified to change the behavior of later handlers. + -- Contains a `skillGain` value as well as a shallow copy of the options passed to @{#skillUsed}. -- @function [parent=#SkillProgression] addSkillUsedHandler -- @param #function handler The handler. addSkillUsedHandler = function(handler) @@ -208,8 +213,19 @@ return { --- Trigger a skill use, activating relevant handlers -- @function [parent=#SkillProgression] skillUsed -- @param #string skillid The if of the skill that was used - -- @param #SkillUseType useType A number from 0 to 3 (inclusive) representing the way the skill was used, with each use type having a different skill progression rate. Available use types and its effect is skill specific. See @{SkillProgression#skillUseType} - -- @param #number scale A number that linearly scales the skill progress received from this use. Defaults to 1. + -- @param options A table of parameters. Must contain one of `skillGain` or `useType`. It's best to always include `useType` if applicable, even if you set `skillGain`, as it may be used + -- by handlers to make decisions. See the addSkillUsedHandler example at the top of this page. + -- + -- * `skillGain` - The numeric amount of skill to be gained. + -- * `useType` - #SkillUseType, A number from 0 to 3 (inclusive) representing the way the skill was used, with each use type having a different skill progression rate. Available use types and its effect is skill specific. See @{#SkillUseType} + -- + -- And may contain the following optional parameter: + -- + -- * `scale` - A numeric value used to scale the skill gain. Ignored if the `skillGain` parameter is set. + -- + -- Note that a copy of this table is passed to skill used handlers, so any parameters passed to this method will also be passed to the handlers. This can be used to provide additional information to + -- custom handlers when making custom skill progressions. + -- skillUsed = skillUsed, --- @{#SkillUseType} @@ -256,11 +272,16 @@ return { Usage = 'usage', Trainer = 'trainer', }, + + --- Compute the total skill gain required to level up a skill based on its current level, and other modifying factors such as major skills and specialization. + -- @function [parent=#SkillProgression] getSkillProgressRequirement + -- @param #string skillid The id of the skill to compute skill progress requirement for + getSkillProgressRequirement = getSkillProgressRequirement }, engineHandlers = { -- Use the interface in these handlers so any overrides will receive the calls. _onSkillUse = function (skillid, useType, scale) - I.SkillProgression.skillUsed(skillid, useType, scale) + I.SkillProgression.skillUsed(skillid, {useType = useType, scale = scale}) end, _onSkillLevelUp = function (skillid, source) I.SkillProgression.skillLevelUp(skillid, source)