mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-01 03:21:41 +00:00
244 lines
9.4 KiB
Lua
244 lines
9.4 KiB
Lua
local camera = require('openmw.camera')
|
|
local input = require('openmw.input')
|
|
local settings = require('openmw.settings')
|
|
local util = require('openmw.util')
|
|
local self = require('openmw.self')
|
|
|
|
local head_bobbing = require('scripts.omw.head_bobbing')
|
|
local third_person = require('scripts.omw.third_person')
|
|
|
|
local MODE = camera.MODE
|
|
|
|
local previewIfStandSill = settings._getBoolFromSettingsCfg('Camera', 'preview if stand still')
|
|
local showCrosshairInThirdPerson = settings._getBoolFromSettingsCfg('Camera', 'view over shoulder')
|
|
|
|
local primaryMode
|
|
|
|
local noModeControl = 0
|
|
local noStandingPreview = 0
|
|
local noHeadBobbing = 0
|
|
local noZoom = 0
|
|
|
|
local function init()
|
|
camera.allowCharacterDeferredRotation(settings._getBoolFromSettingsCfg('Camera', 'deferred preview rotation'))
|
|
if camera.getMode() == MODE.FirstPerson then
|
|
primaryMode = MODE.FirstPerson
|
|
else
|
|
primaryMode = MODE.ThirdPerson
|
|
camera.setMode(MODE.ThirdPerson)
|
|
end
|
|
end
|
|
|
|
local smoothedSpeed = 0
|
|
local previewTimer = 0
|
|
|
|
local function updatePOV(dt)
|
|
local switchLimit = 0.25
|
|
if input.isActionPressed(input.ACTION.TogglePOV) and input.getControlSwitch(input.CONTROL_SWITCH.ViewMode) then
|
|
previewTimer = previewTimer + dt
|
|
if primaryMode == MODE.ThirdPerson or previewTimer >= switchLimit then
|
|
third_person.standingPreview = false
|
|
camera.setMode(MODE.Preview)
|
|
end
|
|
elseif previewTimer > 0 then
|
|
if previewTimer <= switchLimit then
|
|
if primaryMode == MODE.FirstPerson then
|
|
primaryMode = MODE.ThirdPerson
|
|
else
|
|
primaryMode = MODE.FirstPerson
|
|
end
|
|
end
|
|
camera.setMode(primaryMode)
|
|
previewTimer = 0
|
|
end
|
|
end
|
|
|
|
local idleTimer = 0
|
|
local vanityDelay = settings.getGMST('fVanityDelay')
|
|
|
|
local function updateVanity(dt)
|
|
if input.isIdle() then
|
|
idleTimer = idleTimer + dt
|
|
else
|
|
idleTimer = 0
|
|
end
|
|
local vanityAllowed = input.getControlSwitch(input.CONTROL_SWITCH.VanityMode)
|
|
if vanityAllowed and idleTimer > vanityDelay and camera.getMode() ~= MODE.Vanity then
|
|
camera.setMode(MODE.Vanity)
|
|
end
|
|
if camera.getMode() == MODE.Vanity then
|
|
if not vanityAllowed or idleTimer == 0 then
|
|
camera.setMode(primaryMode)
|
|
else
|
|
camera.setYaw(camera.getYaw() + math.rad(3) * dt)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function updateSmoothedSpeed(dt)
|
|
local speed = self:getCurrentSpeed()
|
|
speed = speed / (1 + speed / 500)
|
|
local maxDelta = 300 * dt
|
|
smoothedSpeed = smoothedSpeed + util.clamp(speed - smoothedSpeed, -maxDelta, maxDelta)
|
|
end
|
|
|
|
local minDistance = 30
|
|
local maxDistance = 800
|
|
|
|
local function zoom(delta)
|
|
if not input.getControlSwitch(input.CONTROL_SWITCH.ViewMode) or
|
|
not input.getControlSwitch(input.CONTROL_SWITCH.Controls) or
|
|
camera.getMode() == MODE.Static or noZoom > 0 then
|
|
return
|
|
end
|
|
if camera.getMode() ~= MODE.FirstPerson then
|
|
local obstacleDelta = third_person.preferredDistance - camera.getThirdPersonDistance()
|
|
if delta > 0 and third_person.baseDistance == minDistance and
|
|
(camera.getMode() ~= MODE.Preview or third_person.standingPreview) and noModeControl == 0 then
|
|
primaryMode = MODE.FirstPerson
|
|
camera.setMode(primaryMode)
|
|
elseif delta > 0 or obstacleDelta < -delta then
|
|
third_person.baseDistance = util.clamp(third_person.baseDistance - delta - obstacleDelta, minDistance, maxDistance)
|
|
end
|
|
elseif delta < 0 and noModeControl == 0 then
|
|
primaryMode = MODE.ThirdPerson
|
|
camera.setMode(primaryMode)
|
|
third_person.baseDistance = minDistance
|
|
end
|
|
end
|
|
|
|
local function applyControllerZoom(dt)
|
|
if camera.getMode() == MODE.Preview then
|
|
local triggerLeft = input.getAxisValue(input.CONTROLLER_AXIS.TriggerLeft)
|
|
local triggerRight = input.getAxisValue(input.CONTROLLER_AXIS.TriggerRight)
|
|
local controllerZoom = (triggerRight - triggerLeft) * 100 * dt
|
|
if controllerZoom ~= 0 then
|
|
zoom(controllerZoom)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function updateStandingPreview()
|
|
local mode = camera.getMode()
|
|
if not previewIfStandSill or noStandingPreview > 0
|
|
or mode == MODE.FirstPerson or mode == MODE.Static or mode == MODE.Vanity then
|
|
third_person.standingPreview = false
|
|
return
|
|
end
|
|
local standingStill = self:getCurrentSpeed() == 0 and not self:isInWeaponStance() and not self:isInMagicStance()
|
|
if standingStill and mode == MODE.ThirdPerson then
|
|
third_person.standingPreview = true
|
|
camera.setMode(MODE.Preview)
|
|
elseif not standingStill and third_person.standingPreview then
|
|
third_person.standingPreview = false
|
|
camera.setMode(primaryMode)
|
|
end
|
|
end
|
|
|
|
local function updateCrosshair()
|
|
camera.showCrosshair(
|
|
camera.getMode() == MODE.FirstPerson or
|
|
(showCrosshairInThirdPerson and (camera.getMode() == MODE.ThirdPerson or third_person.standingPreview)))
|
|
end
|
|
|
|
local function onUpdate(dt)
|
|
camera.setExtraPitch(0)
|
|
camera.setExtraYaw(0)
|
|
camera.setRoll(0)
|
|
camera.setFirstPersonOffset(util.vector3(0, 0, 0))
|
|
updateSmoothedSpeed(dt)
|
|
end
|
|
|
|
local function onInputUpdate(dt)
|
|
local mode = camera.getMode()
|
|
if mode == MODE.FirstPerson or mode == MODE.ThirdPerson then
|
|
primaryMode = mode
|
|
end
|
|
if mode ~= MODE.Static then
|
|
if not camera.getQueuedMode() or camera.getQueuedMode() == MODE.Preview then
|
|
if noModeControl == 0 then
|
|
updatePOV(dt)
|
|
updateVanity(dt)
|
|
end
|
|
updateStandingPreview()
|
|
end
|
|
updateCrosshair()
|
|
end
|
|
applyControllerZoom(dt)
|
|
third_person.update(dt, smoothedSpeed)
|
|
if noHeadBobbing == 0 then head_bobbing.update(dt, smoothedSpeed) end
|
|
end
|
|
|
|
return {
|
|
interfaceName = 'Camera',
|
|
--- @module Camera
|
|
-- @usage require('openmw.interfaces').Camera
|
|
interface = {
|
|
--- @field [parent=#Camera] #number version Interface version
|
|
version = 0,
|
|
|
|
--- @function [parent=#Camera] getPrimaryMode Returns primary mode (MODE.FirstPerson or MODE.ThirdPerson).
|
|
getPrimaryMode = function() return primaryMode end,
|
|
--- @function [parent=#Camera] getBaseThirdPersonDistance
|
|
getBaseThirdPersonDistance = function() return third_person.baseDistance end,
|
|
--- @function [parent=#Camera] setBaseThirdPersonDistance
|
|
setBaseThirdPersonDistance = function(v) third_person.baseDistance = v end,
|
|
--- @function [parent=#Camera] getTargetThirdPersonDistance
|
|
getTargetThirdPersonDistance = function() return third_person.preferredDistance end,
|
|
|
|
--- @function [parent=#Camera] isModeControlEnabled
|
|
isModeControlEnabled = function() return noModeControl == 0 end,
|
|
--- @function [parent=#Camera] disableModeControl
|
|
disableModeControl = function() noModeControl = noModeControl + 1 end,
|
|
--- @function [parent=#Camera] enableModeControl
|
|
enableModeControl = function() noModeControl = math.max(0, noModeControl - 1) end,
|
|
|
|
--- @function [parent=#Camera] isStandingPreviewEnabled
|
|
isStandingPreviewEnabled = function() return previewIfStandSill and noStandingPreview == 0 end,
|
|
--- @function [parent=#Camera] disableStandingPreview
|
|
disableStandingPreview = function() noStandingPreview = noStandingPreview + 1 end,
|
|
--- @function [parent=#Camera] enableStandingPreview
|
|
enableStandingPreview = function() noStandingPreview = math.max(0, noStandingPreview - 1) end,
|
|
|
|
--- @function [parent=#Camera] isHeadBobbingEnabled
|
|
isHeadBobbingEnabled = function() return head_bobbing.enabled and noHeadBobbing == 0 end,
|
|
--- @function [parent=#Camera] disableHeadBobbing
|
|
disableHeadBobbing = function() noHeadBobbing = noHeadBobbing + 1 end,
|
|
--- @function [parent=#Camera] enableHeadBobbing
|
|
enableHeadBobbing = function() noHeadBobbing = math.max(0, noHeadBobbing - 1) end,
|
|
|
|
--- @function [parent=#Camera] isZoomEnabled
|
|
isZoomEnabled = function() return noZoom == 0 end,
|
|
--- @function [parent=#Camera] disableZoom
|
|
disableZoom = function() noZoom = noZoom + 1 end,
|
|
--- @function [parent=#Camera] enableZoom
|
|
enableZoom = function() noZoom = math.max(0, noZoom - 1) end,
|
|
|
|
--- @function [parent=#Camera] isThirdPersonOffsetControlEnabled
|
|
isThirdPersonOffsetControlEnabled = function() return third_person.noOffsetControl == 0 end,
|
|
--- @function [parent=#Camera] disableThirdPersonOffsetControl
|
|
disableThirdPersonOffsetControl = function() third_person.noOffsetControl = third_person.noOffsetControl + 1 end,
|
|
--- @function [parent=#Camera] enableThirdPersonOffsetControl
|
|
enableThirdPersonOffsetControl = function() third_person.noOffsetControl = math.max(0, third_person.noOffsetControl - 1) end,
|
|
},
|
|
engineHandlers = {
|
|
onUpdate = onUpdate,
|
|
onInputUpdate = onInputUpdate,
|
|
onInputAction = function(action)
|
|
if action == input.ACTION.ZoomIn then
|
|
zoom(10)
|
|
elseif action == input.ACTION.ZoomOut then
|
|
zoom(-10)
|
|
end
|
|
end,
|
|
onActive = init,
|
|
onLoad = function(data)
|
|
if data and data.distance then third_person.baseDistance = data.distance end
|
|
end,
|
|
onSave = function()
|
|
return {version = 0, distance = third_person.baseDistance}
|
|
end,
|
|
},
|
|
}
|
|
|