forked from VoxeLibre/VoxeLibre
Merge pull request 'Fix the FOV issues with Bows, Sprinting and Spyglasses.' (#4045) from Fix-FOV into master
Reviewed-on: MineClone2/MineClone2#4045 Reviewed-by: the-real-herowl <the-real-herowl@noreply.git.minetest.land>
This commit is contained in:
commit
56ebb5ac09
|
@ -33,6 +33,15 @@ local bow_load = {}
|
|||
-- Another player table, this one stores the wield index of the bow being charged
|
||||
local bow_index = {}
|
||||
|
||||
-- define FOV modifier(s)
|
||||
mcl_fovapi.register_modifier({
|
||||
name = "bowcomplete",
|
||||
fov_factor = 0.8,
|
||||
time = 1,
|
||||
reset_time = 0.3,
|
||||
is_multiplier = true,
|
||||
})
|
||||
|
||||
function mcl_bows.shoot_arrow(arrow_item, pos, dir, yaw, shooter, power, damage, is_critical, bow_stack, collectable)
|
||||
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, arrow_item.."_entity")
|
||||
if power == nil then
|
||||
|
@ -183,6 +192,9 @@ end
|
|||
|
||||
-- Resets the bow charging state and player speed. To be used when the player is no longer charging the bow
|
||||
local function reset_bow_state(player, also_reset_bows)
|
||||
-- clear the FOV change from the player.
|
||||
mcl_fovapi.remove_modifier(player, "bowcomplete") -- for the complete zoom in FOV Modifier.
|
||||
|
||||
bow_load[player:get_player_name()] = nil
|
||||
bow_index[player:get_player_name()] = nil
|
||||
if minetest.get_modpath("playerphysics") then
|
||||
|
@ -314,6 +326,9 @@ controls.register_on_hold(function(player, key, time)
|
|||
end
|
||||
bow_load[name] = minetest.get_us_time()
|
||||
bow_index[name] = player:get_wield_index()
|
||||
|
||||
-- begin Bow Zoom.
|
||||
mcl_fovapi.apply_modifier(player, "bowcomplete")
|
||||
else
|
||||
if player:get_wield_index() == bow_index[name] then
|
||||
if type(bow_load[name]) == "number" then
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name = mcl_bows
|
||||
author = Arcelmi
|
||||
description = This mod adds bows and arrows for MineClone 2.
|
||||
depends = controls, mcl_particles, mcl_enchanting, mcl_init, mcl_util, mcl_shields
|
||||
depends = controls, mcl_particles, mcl_enchanting, mcl_init, mcl_util, mcl_shields, mcl_fovapi
|
||||
optional_depends = awards, mcl_achievements, mcl_core, mcl_mobitems, playerphysics, doc, doc_identifier, mesecons_button
|
||||
|
||||
|
|
|
@ -17,6 +17,15 @@ minetest.register_craft({
|
|||
}
|
||||
})
|
||||
|
||||
mcl_fovapi.register_modifier({
|
||||
name = "spyglass",
|
||||
fov_factor = 8,
|
||||
time = 0.1,
|
||||
reset_time = 0,
|
||||
is_multiplier = false,
|
||||
exclusive = true,
|
||||
})
|
||||
|
||||
local spyglass_scope = {}
|
||||
|
||||
local function add_scope(player)
|
||||
|
@ -37,7 +46,8 @@ local function remove_scope(player)
|
|||
player:hud_remove(spyglass_scope[player])
|
||||
spyglass_scope[player] = nil
|
||||
player:hud_set_flags({wielditem = true})
|
||||
player:set_fov(86.1)
|
||||
mcl_fovapi.remove_modifier(player, "spyglass") -- use the api to remove the FOV effect.
|
||||
-- old code: player:set_fov(86.1)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -55,7 +65,8 @@ controls.register_on_hold(function(player, key, time)
|
|||
if key ~= "RMB" then return end
|
||||
local wielditem = player:get_wielded_item()
|
||||
if wielditem:get_name() == "mcl_spyglass:spyglass" then
|
||||
player:set_fov(8, false, 0.1)
|
||||
mcl_fovapi.apply_modifier(player, "spyglass") -- apply the FOV effect.
|
||||
-- old code: player:set_fov(8, false, 0.1)
|
||||
if spyglass_scope[player] == nil then
|
||||
add_scope(player)
|
||||
end
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
name = mcl_spyglass
|
||||
author = NO11
|
||||
description = This mod adds a spyglass, which is an item that can be used for zooming in on specific locations.
|
||||
depends = mcl_core, controls
|
||||
depends = mcl_core, controls, mcl_fovapi
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
### FOV API
|
||||
|
||||
<!-- TOC -->
|
||||
* [FOV API](#fov-api)
|
||||
* [Description](#description)
|
||||
* [Troubleshooting](#troubleshooting)
|
||||
* [Modifier Definition](#modifier-definition-)
|
||||
* [Global MCL_FOVAPI Tables](#global-mclfovapi-tables)
|
||||
* [Namespaces](#namespaces)
|
||||
* [Functions](#functions)
|
||||
<!-- TOC -->
|
||||
|
||||
#### Description
|
||||
This API defines and applies different Field Of View effects to players via MODIFIERS.
|
||||
|
||||
#### Troubleshooting
|
||||
In the `init.lua` file for this module, there is a `DEBUG` variable at the top that will turn on logging.
|
||||
Use it to see what is going on.
|
||||
|
||||
#### Modifier Definition
|
||||
```lua
|
||||
def = {
|
||||
name = name,
|
||||
fov_factor = fov_factor,
|
||||
time = time,
|
||||
reset_time = reset_time,
|
||||
is_multiplier = is_multiplier,
|
||||
exclusive = exclusive,
|
||||
on_start = on_start,
|
||||
on_end = on_end,
|
||||
}
|
||||
```
|
||||
* Name: The name of the Modifier, used to identify the specific modifier. Case sensitive.
|
||||
* FOV Factor: A float value defining the FOV to apply. Can be an absolute or percentage, depending on Exclusive and
|
||||
Is_Multiplier.
|
||||
* Time: A float value defining the number of seconds to take when applying the FOV Factor.
|
||||
Used to smoothly move between FOVs. Use 0 for an immediate FOV Shift. (Transition time.)
|
||||
* Reset Time: A float value defining the number of seconds to take when removing the FOV Factor.
|
||||
Used to smoothly move between FOVs. Use 0 for an immediate FOV Shift. (Reset transition time.)
|
||||
Defaults to `time` if not defined.
|
||||
* Is Multiplier: A bool value used to specify if the FOV Factor is an absolute FOV value or if it should be a percentage
|
||||
of the current FOV. Defaults to `true` if not defined.
|
||||
* Exclusive: A bool value used to specify whether the modifier will override all other FOV modifiers. An example of this
|
||||
is how the spy glass sets the FOV to be a specific value regardless of any other FOV effects applied. Defaults to
|
||||
`false` if not defined.
|
||||
* On Start: the `on_start` is a callback function `on_start(player)` that is called if defined. The parameter `player`
|
||||
is a ref to the player that had the modifier applied. Called from `mcl_fovapi.apply_modifier` immediately after
|
||||
the FOV Modifier has been applied.
|
||||
* On End: the `on_end` is a callback function `on_end(player)` that is called if defined. The parameter `player`
|
||||
is a ref to the player that had the modifier applied. Called from `mcl_fovapi.remove_modifier` immediately after
|
||||
the FOV Modifier has been removed.
|
||||
|
||||
Note: passing incorrect values in the definition will have unintended consequences.
|
||||
|
||||
#### Global MCL_FOVAPI Tables
|
||||
There are three tables that are accessible via the API. They are `registered_modifiers` and `applied_modifiers`.
|
||||
|
||||
`mcl_fovapi.registered_modifiers` has the definitions of all the registered FOV Modifiers. Indexed by Modifier Name.
|
||||
And, `mcl_fovapi.applied_modifiers` is indexed by the Player Name. It contains the names of all the modifiers applied to the
|
||||
player.
|
||||
|
||||
#### Namespaces
|
||||
`mcl_fovapi` is the default API Namespace.
|
||||
|
||||
#### Functions
|
||||
`mcl_fovapi.register_modifier(def)`
|
||||
|
||||
Used to register a new FOV Modifier for use. Must be called before applying said modifier to a player.
|
||||
See Modifier Definition for what the parameters are.
|
||||
|
||||
`mcl_fovapi.apply_modifier(player, modifier_name)`
|
||||
|
||||
Used to apply a registered FOV modifier to a player. Takes a reference to the player and the modifier's name (string).
|
||||
|
||||
`mcl_fovapi.remove_modifier(player, modifier_name)`
|
||||
|
||||
Used to remove a specific FOV modifier from a Player. Takes a reference to the player and the modifier's name (string).
|
||||
Removed immediately.
|
||||
|
||||
`mcl_fovapi.remove_all_modifiers(player)`
|
||||
|
||||
Used to remove all FOV modifiers from a Player. Takes a reference to the Player. FOV change is instantaneous.
|
|
@ -0,0 +1,232 @@
|
|||
---
|
||||
--- Copyright 2023, Michieal.
|
||||
--- License: GPL3. (Default Mineclone2 License)
|
||||
--- Created by michieal.
|
||||
--- DateTime: 12/2/23 5:47 AM
|
||||
---
|
||||
|
||||
-- Locals (and cached)
|
||||
local DEBUG = false -- debug constant for troubleshooting.
|
||||
local pairs = pairs
|
||||
|
||||
-- Globals
|
||||
mcl_fovapi = {}
|
||||
|
||||
mcl_fovapi.registered_modifiers = {}
|
||||
mcl_fovapi.applied_modifiers = {}
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local player_name = player:get_player_name()
|
||||
|
||||
-- initialization
|
||||
mcl_fovapi.applied_modifiers[player_name] = {}
|
||||
end)
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
local player_name = player:get_player_name()
|
||||
|
||||
-- handle clean up
|
||||
mcl_fovapi.applied_modifiers[player_name] = nil
|
||||
end)
|
||||
|
||||
function mcl_fovapi.register_modifier(def)
|
||||
if type(def.name) ~= "string" then
|
||||
error("Modifier name must be a string")
|
||||
end
|
||||
if type(def.fov_factor) ~= "number" then
|
||||
error("FOV factor must be a number")
|
||||
end
|
||||
if type(def.time) ~= "number" then
|
||||
error("Transition time must be a number")
|
||||
end
|
||||
if def.reset_time ~= nil and type(def.reset_time) ~= "number" then
|
||||
error("Reset time, if provided, must be a number")
|
||||
end
|
||||
|
||||
if def.on_start ~= nil and type(def.on_start) ~= "function" then
|
||||
error("Callback on_start must be a function")
|
||||
end
|
||||
if def.on_end ~= nil and type(def.on_end) ~= "function" then
|
||||
error("Callback on_end must be a function")
|
||||
end
|
||||
|
||||
local mdef = {}
|
||||
|
||||
mdef.fov_factor = def.fov_factor
|
||||
mdef.time = def.time
|
||||
mdef.reset_time = def.reset_time or def.time
|
||||
|
||||
if def.is_multiplier == false then mdef.is_multiplier = false
|
||||
else mdef.is_multiplier = true end
|
||||
if def.exclusive == true then mdef.exclusive = true
|
||||
else mdef.exclusive = false end
|
||||
|
||||
mdef.on_start = def.on_start
|
||||
mdef.on_end = def.on_end
|
||||
|
||||
if DEBUG then
|
||||
minetest.log("FOV::Modifier Definition Registered:\n" .. dump(def))
|
||||
end
|
||||
|
||||
mcl_fovapi.registered_modifiers[def.name] = mdef
|
||||
|
||||
end
|
||||
|
||||
minetest.register_on_respawnplayer(function(player)
|
||||
mcl_fovapi.remove_all_modifiers(player)
|
||||
end)
|
||||
|
||||
function mcl_fovapi.apply_modifier(player, modifier_name)
|
||||
if not player or not modifier_name then
|
||||
return
|
||||
end
|
||||
if mcl_fovapi.registered_modifiers[modifier_name] == nil then
|
||||
return
|
||||
end
|
||||
local player_name = player:get_player_name()
|
||||
if mcl_fovapi.applied_modifiers and mcl_fovapi.applied_modifiers[player_name] and mcl_fovapi.applied_modifiers[player_name][modifier_name] then
|
||||
return
|
||||
end
|
||||
|
||||
for k, _ in pairs(mcl_fovapi.applied_modifiers[player_name]) do
|
||||
if mcl_fovapi.registered_modifiers[k].exclusive == true then return end
|
||||
end
|
||||
|
||||
local modifier = mcl_fovapi.registered_modifiers[modifier_name]
|
||||
if modifier.on_start then
|
||||
modifier.on_start(player)
|
||||
end
|
||||
|
||||
mcl_fovapi.applied_modifiers[player_name][modifier_name] = true -- set the applied to be true.
|
||||
|
||||
if DEBUG then
|
||||
minetest.log("FOV::Player Applied Modifiers :" .. dump(mcl_fovapi.applied_modifiers[player_name]))
|
||||
end
|
||||
|
||||
if DEBUG then
|
||||
minetest.log("FOV::Modifier applied to player:" .. player_name .. " modifier: " .. modifier_name)
|
||||
end
|
||||
|
||||
-- modifier apply code.
|
||||
if modifier.exclusive == true then
|
||||
-- if exclusive, reset the player's fov, and apply the new fov.
|
||||
if modifier.is_multiplier then
|
||||
player:set_fov(0, false, 0)
|
||||
end
|
||||
player:set_fov(modifier.fov_factor, modifier.is_multiplier, modifier.time)
|
||||
else
|
||||
-- not exclusive? let's apply it in the mix.
|
||||
local fov_factor, is_mult = player:get_fov()
|
||||
if fov_factor == 0 then
|
||||
fov_factor = 1
|
||||
is_mult = true
|
||||
end
|
||||
if modifier.is_multiplier or is_mult then
|
||||
fov_factor = fov_factor * modifier.fov_factor
|
||||
else
|
||||
fov_factor = (fov_factor + modifier.fov_factor) / 2
|
||||
end
|
||||
if modifier.is_multiplier and is_mult then
|
||||
player:set_fov(fov_factor, true, modifier.time)
|
||||
else
|
||||
player:set_fov(fov_factor, false, modifier.time)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function mcl_fovapi.remove_modifier(player, modifier_name)
|
||||
if not player or not modifier_name then
|
||||
return
|
||||
end
|
||||
|
||||
local player_name = player:get_player_name()
|
||||
if not mcl_fovapi.applied_modifiers[player_name]
|
||||
or not mcl_fovapi.applied_modifiers[player_name][modifier_name] then
|
||||
return
|
||||
end
|
||||
|
||||
if DEBUG then
|
||||
minetest.log("FOV::Player: " .. player_name .. " modifier: " .. modifier_name .. "removed.")
|
||||
end
|
||||
|
||||
mcl_fovapi.applied_modifiers[player_name][modifier_name] = nil
|
||||
local modifier = mcl_fovapi.registered_modifiers[modifier_name]
|
||||
|
||||
-- check for other fov modifiers, and set them up, or reset to default.
|
||||
|
||||
local applied = {}
|
||||
for k, _ in pairs(mcl_fovapi.applied_modifiers[player_name]) do
|
||||
applied[k] = mcl_fovapi.registered_modifiers[k]
|
||||
end
|
||||
|
||||
local elem = next
|
||||
if elem(applied) == nil then
|
||||
player:set_fov(0, false, modifier.reset_time)
|
||||
return
|
||||
end
|
||||
local exc = false
|
||||
for k, _ in pairs(applied) do
|
||||
if applied[k].exclusive == true then
|
||||
exc = applied[k]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- handle exclusives.
|
||||
if exc ~= false then
|
||||
player:set_fov(exc.fov_factor, exc.is_multiplier, 0) -- we want this to be immediate.
|
||||
else
|
||||
-- handle normal fov modifiers.
|
||||
local fov_factor = 1
|
||||
local non_multiplier_added = false
|
||||
for _, x in pairs(applied) do
|
||||
if not x.is_multiplier then
|
||||
if non_multiplier_added then
|
||||
fov_factor = (fov_factor + x.fov_factor) / 2
|
||||
else
|
||||
non_multiplier_added = true
|
||||
fov_factor = fov_factor * x.fov_factor
|
||||
end
|
||||
else
|
||||
fov_factor = fov_factor * x.fov_factor
|
||||
end
|
||||
end
|
||||
player:set_fov(fov_factor, not non_multiplier_added, modifier.reset_time)
|
||||
end
|
||||
|
||||
if mcl_fovapi.registered_modifiers[modifier_name].on_end then
|
||||
mcl_fovapi.registered_modifiers[modifier_name].on_end(player)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_fovapi.remove_all_modifiers(player)
|
||||
if not player then
|
||||
return
|
||||
end
|
||||
|
||||
local player_name = player:get_player_name()
|
||||
if DEBUG then
|
||||
minetest.log("FOV::Player: " .. player_name .. " modifiers have been reset.")
|
||||
end
|
||||
|
||||
for name, x in pairs(mcl_fovapi.applied_modifiers[player_name]) do
|
||||
x = nil
|
||||
if mcl_fovapi.registered_modifiers[name].on_end then
|
||||
mcl_fovapi.registered_modifiers[name].on_end(player)
|
||||
end
|
||||
end
|
||||
|
||||
player:set_fov(0, false, 0)
|
||||
end
|
||||
|
||||
--[[
|
||||
Notes:
|
||||
set_fov(fov, is_multiplier, transition_time): Sets player's FOV
|
||||
|
||||
fov: FOV value.
|
||||
is_multiplier: Set to true if the FOV value is a multiplier. Defaults to false.
|
||||
transition_time: If defined, enables smooth FOV transition. Interpreted as the time (in seconds) to reach target FOV.
|
||||
If set to 0, FOV change is instantaneous. Defaults to 0.
|
||||
Set fov to 0 to clear FOV override.
|
||||
|
||||
--]]
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_fovapi
|
||||
author = Michieal, Herowl
|
||||
description = An API for handling FOV changes.
|
||||
depends = mcl_player
|
|
@ -177,7 +177,7 @@ minetest.register_on_joinplayer(function(player)
|
|||
player_textures[name] = { "character.png", "blank.png", "blank.png" }
|
||||
|
||||
--player:set_local_animation({x=0, y=79}, {x=168, y=187}, {x=189, y=198}, {x=200, y=219}, 30)
|
||||
player:set_fov(86.1) -- see <https://minecraft.gamepedia.com/Options#Video_settings>>>>
|
||||
-- player:set_fov(86.1) -- see <https://minecraft.gamepedia.com/Options#Video_settings>>>>
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
|
|
|
@ -64,40 +64,24 @@ local function cancelClientSprinting(name)
|
|||
players[name].clientSprint = false
|
||||
end
|
||||
|
||||
mcl_fovapi.register_modifier({
|
||||
name = "sprint",
|
||||
fov_factor = 1.1,
|
||||
time = 0.15,
|
||||
is_multiplier = true,
|
||||
})
|
||||
|
||||
local function setSprinting(playerName, sprinting) --Sets the state of a player (0=stopped/moving, 1=sprinting)
|
||||
if not sprinting and not mcl_sprint.is_sprinting(playerName) then return end
|
||||
local player = minetest.get_player_by_name(playerName)
|
||||
local controls = player:get_player_control()
|
||||
if players[playerName] then
|
||||
players[playerName].sprinting = sprinting
|
||||
local fov_old = players[playerName].fov
|
||||
local fov_new = fov_old
|
||||
local fade_time = .15
|
||||
if sprinting == true
|
||||
or controls.RMB
|
||||
and string.find(player:get_wielded_item():get_name(), "mcl_bows:bow")
|
||||
and player:get_wielded_item():get_name() ~= "mcl_bows:bow" then
|
||||
if sprinting == true then
|
||||
fov_new = math.min(players[playerName].fov + 0.05, 1.2)
|
||||
else
|
||||
fov_new = .7
|
||||
players[playerName].fade_time = .3
|
||||
end
|
||||
if sprinting == true then
|
||||
playerphysics.add_physics_factor(player, "speed", "mcl_sprint:sprint", mcl_sprint.SPEED)
|
||||
end
|
||||
elseif sprinting == false
|
||||
and player:get_wielded_item():get_name() ~= "mcl_bows:bow_0"
|
||||
and player:get_wielded_item():get_name() ~= "mcl_bows:bow_1"
|
||||
and player:get_wielded_item():get_name() ~= "mcl_bows:bow_2" then
|
||||
fov_new = math.max(players[playerName].fov - 0.05, 1.0)
|
||||
if sprinting == false then
|
||||
playerphysics.remove_physics_factor(player, "speed", "mcl_sprint:sprint")
|
||||
end
|
||||
end
|
||||
if fov_new ~= fov_old then
|
||||
players[playerName].fov = fov_new
|
||||
player:set_fov(fov_new, true, fade_time)
|
||||
if sprinting then
|
||||
playerphysics.add_physics_factor(player, "speed", "mcl_sprint:sprint", mcl_sprint.SPEED)
|
||||
mcl_fovapi.apply_modifier(player, "sprint")
|
||||
else
|
||||
playerphysics.remove_physics_factor(player, "speed", "mcl_sprint:sprint")
|
||||
mcl_fovapi.remove_modifier(player, "sprint")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
name = mcl_sprint
|
||||
author = GunshipPenguin
|
||||
description = Allows the player to sprint by pressing the “Use” key (default: E).
|
||||
depends = mcl_playerinfo, playerphysics, mcl_hunger
|
||||
description = Allows the player to sprint by pressing the “AUX” key (default: E).
|
||||
depends = mcl_playerinfo, playerphysics, mcl_hunger, mcl_fovapi
|
||||
optional = mcl_bows
|
Loading…
Reference in New Issue