You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/files/data/scripts/omw/playercontrols.lua

235 lines
8.7 KiB
Lua

local core = require('openmw.core')
local input = require('openmw.input')
local self = require('openmw.self')
local util = require('openmw.util')
local ui = require('openmw.ui')
local Actor = require('openmw.types').Actor
local Player = require('openmw.types').Player
local storage = require('openmw.storage')
local I = require('openmw.interfaces')
local settingsGroup = 'SettingsOMWControls'
local function boolSetting(key, default)
return {
key = key,
renderer = 'checkbox',
name = key,
description = key..'Description',
default = default,
}
end
I.Settings.registerPage({
key = 'OMWControls',
l10n = 'OMWControls',
name = 'ControlsPage',
description = 'ControlsPageDescription',
})
I.Settings.registerGroup({
key = settingsGroup,
page = 'OMWControls',
l10n = 'OMWControls',
name = 'MovementSettings',
permanentStorage = true,
settings = {
boolSetting('alwaysRun', false),
boolSetting('toggleSneak', false),
},
})
local settings = storage.playerSection(settingsGroup)
local attemptJump = false
local startAttack = false
local autoMove = false
local movementControlsOverridden = false
local combatControlsOverridden = false
local uiControlsOverridden = false
local function processMovement()
local controllerMovement = -input.getAxisValue(input.CONTROLLER_AXIS.MoveForwardBackward)
local controllerSideMovement = input.getAxisValue(input.CONTROLLER_AXIS.MoveLeftRight)
if controllerMovement ~= 0 or controllerSideMovement ~= 0 then
-- controller movement
if util.vector2(controllerMovement, controllerSideMovement):length2() < 0.25
and not self.controls.sneak and Actor.isOnGround(self) and not Actor.isSwimming(self) then
self.controls.run = false
self.controls.movement = controllerMovement * 2
self.controls.sideMovement = controllerSideMovement * 2
else
self.controls.run = true
self.controls.movement = controllerMovement
self.controls.sideMovement = controllerSideMovement
end
else
-- keyboard movement
self.controls.movement = 0
self.controls.sideMovement = 0
if input.isActionPressed(input.ACTION.MoveLeft) then
self.controls.sideMovement = self.controls.sideMovement - 1
end
if input.isActionPressed(input.ACTION.MoveRight) then
self.controls.sideMovement = self.controls.sideMovement + 1
end
if input.isActionPressed(input.ACTION.MoveBackward) then
self.controls.movement = self.controls.movement - 1
end
if input.isActionPressed(input.ACTION.MoveForward) then
self.controls.movement = self.controls.movement + 1
end
self.controls.run = input.isActionPressed(input.ACTION.Run) ~= settings:get('alwaysRun')
end
if self.controls.movement ~= 0 or not Actor.canMove(self) then
autoMove = false
elseif autoMove then
self.controls.movement = 1
end
self.controls.jump = attemptJump and Player.getControlSwitch(self, Player.CONTROL_SWITCH.Jumping)
if not settings:get('toggleSneak') then
self.controls.sneak = input.isActionPressed(input.ACTION.Sneak)
end
end
local function processAttacking()
if startAttack then
self.controls.use = 1
elseif Actor.stance(self) == Actor.STANCE.Spell then
self.controls.use = 0
elseif input.getAxisValue(input.CONTROLLER_AXIS.TriggerRight) < 0.6
and not input.isActionPressed(input.ACTION.Use) then
-- The value "0.6" shouldn't exceed the triggering threshold in BindingsManager::actionValueChanged.
-- TODO: Move more logic from BindingsManager to Lua and consider to make this threshold configurable.
self.controls.use = 0
end
end
local function onFrame(dt)
local controlsAllowed = Player.getControlSwitch(self, Player.CONTROL_SWITCH.Controls)
and not core.isWorldPaused() and not I.UI.getMode()
if not movementControlsOverridden then
if controlsAllowed then
processMovement()
else
self.controls.movement = 0
self.controls.sideMovement = 0
self.controls.jump = false
end
end
if controlsAllowed and not combatControlsOverridden then
processAttacking()
end
attemptJump = false
startAttack = false
end
local function checkNotWerewolf()
if Player.isWerewolf(self) then
ui.showMessage(core.getGMST('sWerewolfRefusal'))
return false
else
return true
end
end
local function isJournalAllowed()
-- During chargen journal is not allowed until magic window is allowed
return I.UI.getWindowsForMode(I.UI.MODE.Interface)[I.UI.WINDOW.Magic]
end
local function onInputAction(action)
if not Player.getControlSwitch(self, Player.CONTROL_SWITCH.Controls) then
return
end
if not uiControlsOverridden then
if action == input.ACTION.Inventory then
if I.UI.getMode() == nil then
I.UI.setMode(I.UI.MODE.Interface)
elseif I.UI.getMode() == I.UI.MODE.Interface or I.UI.getMode() == I.UI.MODE.Container then
I.UI.removeMode(I.UI.getMode())
end
elseif action == input.ACTION.Journal then
if I.UI.getMode() == I.UI.MODE.Journal then
I.UI.removeMode(I.UI.MODE.Journal)
elseif isJournalAllowed() then
I.UI.addMode(I.UI.MODE.Journal)
end
elseif action == input.ACTION.QuickKeysMenu then
if I.UI.getMode() == I.UI.MODE.QuickKeysMenu then
I.UI.removeMode(I.UI.MODE.QuickKeysMenu)
elseif checkNotWerewolf() and Player.isCharGenFinished(self) then
I.UI.addMode(I.UI.MODE.QuickKeysMenu)
end
end
end
if core.isWorldPaused() or I.UI.getMode() then
return
end
if action == input.ACTION.Jump then
attemptJump = true
elseif action == input.ACTION.Use then
startAttack = Actor.stance(self) ~= Actor.STANCE.Nothing
elseif action == input.ACTION.AutoMove and not movementControlsOverridden then
autoMove = not autoMove
elseif action == input.ACTION.AlwaysRun and not movementControlsOverridden then
settings:set('alwaysRun', not settings:get('alwaysRun'))
elseif action == input.ACTION.Sneak and not movementControlsOverridden then
if settings:get('toggleSneak') then
self.controls.sneak = not self.controls.sneak
end
elseif action == input.ACTION.ToggleSpell and not combatControlsOverridden then
if Actor.stance(self) == Actor.STANCE.Spell then
Actor.setStance(self, Actor.STANCE.Nothing)
elseif Player.getControlSwitch(self, Player.CONTROL_SWITCH.Magic) then
if checkNotWerewolf() then
Actor.setStance(self, Actor.STANCE.Spell)
end
end
elseif action == input.ACTION.ToggleWeapon and not combatControlsOverridden then
if Actor.stance(self) == Actor.STANCE.Weapon then
Actor.setStance(self, Actor.STANCE.Nothing)
elseif Player.getControlSwitch(self, Player.CONTROL_SWITCH.Fighting) then
Actor.setStance(self, Actor.STANCE.Weapon)
end
end
end
return {
engineHandlers = {
onFrame = onFrame,
onInputAction = onInputAction,
},
interfaceName = 'Controls',
---
-- @module Controls
-- @usage require('openmw.interfaces').Controls
interface = {
--- Interface version
-- @field [parent=#Controls] #number version
version = 1,
--- When set to true then the movement controls including jump and sneak are not processed and can be handled by another script.
-- If movement should be disallowed completely, consider to use `types.Player.setControlSwitch` instead.
-- @function [parent=#Controls] overrideMovementControls
-- @param #boolean value
overrideMovementControls = function(v) movementControlsOverridden = v end,
--- When set to true then the controls "attack", "toggle spell", "toggle weapon" are not processed and can be handled by another script.
-- If combat should be disallowed completely, consider to use `types.Player.setControlSwitch` instead.
-- @function [parent=#Controls] overrideCombatControls
-- @param #boolean value
overrideCombatControls = function(v) combatControlsOverridden = v end,
--- When set to true then the controls "open inventory", "open journal" and so on are not processed and can be handled by another script.
-- @function [parent=#Controls] overrideUiControls
-- @param #boolean value
overrideUiControls = function(v) uiControlsOverridden = v end,
}
}