VoxeLibre/mods/PLAYER/mcl_fovapi/init.lua

233 lines
6.2 KiB
Lua
Raw Normal View History

2023-12-02 13:00:25 +01:00
---
--- Copyright 2023, Michieal.
--- License: GPL3. (Default Mineclone2 License)
--- Created by michieal.
--- DateTime: 12/2/23 5:47 AM
---
2023-12-03 12:47:28 +01:00
-- Locals (and cached)
local DEBUG = false -- debug constant for troubleshooting.
local pairs = pairs
-- Globals
2023-12-02 13:00:25 +01:00
mcl_fovapi = {}
mcl_fovapi.registered_modifiers = {}
mcl_fovapi.applied_modifiers = {}
2023-12-13 00:29:22 +01:00
minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
-- initialization
mcl_fovapi.applied_modifiers[player_name] = {}
end)
2023-12-02 13:00:25 +01:00
minetest.register_on_leaveplayer(function(player)
2023-12-13 00:29:22 +01:00
local player_name = player:get_player_name()
-- handle clean up
2023-12-13 00:29:22 +01:00
mcl_fovapi.applied_modifiers[player_name] = nil
2023-12-02 13:00:25 +01:00
end)
2023-12-09 23:22:36 +01:00
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
2023-12-10 00:20:43 +01:00
if def.reset_time ~= nil and type(def.reset_time) ~= "number" then
error("Reset time, if provided, must be a number")
end
2023-12-09 23:22:36 +01:00
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
2023-12-10 00:20:43 +01:00
mdef.reset_time = def.reset_time or def.time
2023-12-09 23:22:36 +01:00
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
2023-12-02 13:00:25 +01:00
2023-12-03 12:47:28 +01:00
if DEBUG then
minetest.log("FOV::Modifier Definition Registered:\n" .. dump(def))
end
2023-12-09 23:22:36 +01:00
mcl_fovapi.registered_modifiers[def.name] = mdef
2023-12-02 13:00:25 +01:00
end
minetest.register_on_respawnplayer(function(player)
2023-12-13 00:29:22 +01:00
mcl_fovapi.remove_all_modifiers(player)
end)
2023-12-02 13:00:25 +01:00
function mcl_fovapi.apply_modifier(player, modifier_name)
2023-12-13 00:29:22 +01:00
if not player or not modifier_name then
2023-12-03 12:47:28 +01:00
return
end
if mcl_fovapi.registered_modifiers[modifier_name] == nil then
return
end
2023-12-13 00:29:22 +01:00
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
2023-12-13 00:29:22 +01:00
for k, _ in pairs(mcl_fovapi.applied_modifiers[player_name]) do
if mcl_fovapi.registered_modifiers[k].exclusive == true then return end
end
2023-12-02 13:00:25 +01:00
local modifier = mcl_fovapi.registered_modifiers[modifier_name]
2023-12-13 00:29:22 +01:00
if modifier.on_start then
2023-12-02 13:00:25 +01:00
modifier.on_start(player)
end
2023-12-13 00:29:22 +01:00
mcl_fovapi.applied_modifiers[player_name][modifier_name] = true -- set the applied to be true.
2023-12-03 12:47:28 +01:00
if DEBUG then
2023-12-13 00:29:22 +01:00
minetest.log("FOV::Player Applied Modifiers :" .. dump(mcl_fovapi.applied_modifiers[player_name]))
2023-12-03 12:47:28 +01:00
end
if DEBUG then
2023-12-13 00:29:22 +01:00
minetest.log("FOV::Modifier applied to player:" .. player_name .. " modifier: " .. modifier_name)
2023-12-03 12:47:28 +01:00
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.
2023-12-10 00:15:09 +01:00
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)
2023-12-10 00:15:09 +01:00
end
2023-12-03 12:47:28 +01:00
end
2023-12-02 13:00:25 +01:00
2023-12-03 12:47:28 +01:00
end
2023-12-02 13:00:25 +01:00
2023-12-03 12:47:28 +01:00
function mcl_fovapi.remove_modifier(player, modifier_name)
2023-12-13 00:29:22 +01:00
if not player or not modifier_name then
2023-12-03 12:47:28 +01:00
return
end
2023-12-13 00:29:22 +01:00
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
2023-12-03 12:47:28 +01:00
if DEBUG then
2023-12-13 00:29:22 +01:00
minetest.log("FOV::Player: " .. player_name .. " modifier: " .. modifier_name .. "removed.")
2023-12-03 12:47:28 +01:00
end
2023-12-02 13:00:25 +01:00
2023-12-13 00:29:22 +01:00
mcl_fovapi.applied_modifiers[player_name][modifier_name] = nil
2023-12-09 23:22:36 +01:00
local modifier = mcl_fovapi.registered_modifiers[modifier_name]
2023-12-03 12:47:28 +01:00
-- check for other fov modifiers, and set them up, or reset to default.
local applied = {}
2023-12-13 00:29:22 +01:00
for k, _ in pairs(mcl_fovapi.applied_modifiers[player_name]) do
2023-12-03 12:47:28 +01:00
applied[k] = mcl_fovapi.registered_modifiers[k]
end
2023-12-10 00:15:09 +01:00
local elem = next
if elem(applied) == nil then
2023-12-10 00:20:43 +01:00
player:set_fov(0, false, modifier.reset_time)
2023-12-03 12:47:28 +01:00
return
end
local exc = false
2023-12-10 00:15:09 +01:00
for k, _ in pairs(applied) do
2023-12-03 12:47:28 +01:00
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.
2023-12-09 23:22:36 +01:00
local fov_factor = 1
2023-12-10 00:15:09 +01:00
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
2023-12-03 12:47:28 +01:00
end
2023-12-10 00:20:43 +01:00
player:set_fov(fov_factor, not non_multiplier_added, modifier.reset_time)
2023-12-03 12:47:28 +01:00
end
2023-12-13 00:29:22 +01:00
if mcl_fovapi.registered_modifiers[modifier_name].on_end then
2023-12-03 12:47:28 +01:00
mcl_fovapi.registered_modifiers[modifier_name].on_end(player)
end
end
function mcl_fovapi.remove_all_modifiers(player)
2023-12-13 00:29:22 +01:00
if not player then
2023-12-03 12:47:28 +01:00
return
end
2023-12-13 00:29:22 +01:00
local player_name = player:get_player_name()
2023-12-03 12:47:28 +01:00
if DEBUG then
2023-12-13 00:29:22 +01:00
minetest.log("FOV::Player: " .. player_name .. " modifiers have been reset.")
2023-12-03 12:47:28 +01:00
end
2023-12-13 00:29:22 +01:00
for name, x in pairs(mcl_fovapi.applied_modifiers[player_name]) do
2023-12-03 12:47:28 +01:00
x = nil
2023-12-13 00:29:22 +01:00
if mcl_fovapi.registered_modifiers[name].on_end then
mcl_fovapi.registered_modifiers[name].on_end(player)
end
2023-12-03 12:47:28 +01:00
end
player:set_fov(0, false, 0)
2023-12-02 13:00:25 +01:00
end
2023-12-03 12:47:28 +01:00
--[[
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.
--]]