guns4d-cd2025/init.lua

287 lines
12 KiB
Lua

local Vec = vector
Guns4d = {
players = {},
handler_by_ObjRef = {},
gun_by_ObjRef = {}, --used for getting the gun object by the ObjRef of the gun
version = {1, 3, 0}
}
--default config values, config will be added soon:tm:
Guns4d.config = {
show_mag_inv_ammo_bar = true,
show_mag_inv_ammo_count = true,
show_gun_inv_ammo_count = true,
control_hybrid_toggle_threshold = .3,
control_held_toggle_threshold = 0,
empty_symbol = "E",
default_damage_group = "fleshy",
infinite_ammo_priv = "guns4d_infinite_ammo",
interpret_initial_wear_as_ammo = false,
punch_from_player_not_gun = true,
vertical_rotation_factor = 25, --the rate at which the gun moves to the player's look vetically. With bone interpolation as of 5.9 this can be a lot higher now.
player_axial_interpolation_time = .05, --the time it takes for the gun to reach the new angle (around the player's eye) set by the server. This includes recoil, sway, or anything that shifts the gun without misaligning sights.
gun_axial_interpolation_time = .05, --the same as player_axial but for the rotation of the gun.
translation_interpolation_time = .09, --time it takes for nonrotation components (i.e. hip offset, aiming offset, bone location, etc) to interpolate.
simple_headshot = true, --holdover feature before a more complex system is implemented
simple_headshot_body_ratio = .75, --percentage of hitbox height that is body.
default_fov = 80,
headshot_damage_factor = 1.75,
enable_touchscreen_command_name = "guns4d_enable_touchmode",
minimum_supersonic_energy_assumption = 900, --used to determine the energy of a "supersonic" bullet for bullet whizzing sound effects
default_audio_attenuation_rate = .8, --changes the dropoff rate of sound. Acts as a multiplier for the distance used to calculate inverse square law. Most guns (from the gun packs) set their own, so this is mainly for reloads.
mix_supersonic_and_subsonic_sounds = true,
default_pass_sound_mixing_factor = 10,
third_person_gain_multiplier = 1/3,
default_penetration_iteration_distance = .25,
maximum_bullet_holes = 20,
inventory_listname = "main",
aim_out_multiplier = 1.5,
--enable_assert = false,
realistic_items = false
--`["official_content.replace_ads_with_bloom"] = false,
--`["official_content.uses_magazines"] = true
}
local modpath = minetest.get_modpath("guns4d")
local conf = Settings(modpath.."/guns4d_settings.conf"):to_table() or {}
local mt_conf = minetest.settings:to_table() --allow use of MT config for servers that regularly update 4dguns through it's development
for i, v in pairs(Guns4d.config) do
--Guns4d.config[i] = conf[i] or minetest.settings["guns4d."..i] or Guns4d.config[i]
--cant use or because it'd evaluate to false if the setting is alse
if mt_conf["guns4d."..i] ~= nil then
Guns4d.config[i] = mt_conf["guns4d."..i]
elseif conf[i] ~= nil then
Guns4d.config[i] = conf[i]
end
end
minetest.rmdir(modpath.."/temp", true)
minetest.mkdir(modpath.."/temp")
dofile(modpath.."/misc_helpers.lua")
dofile(modpath.."/item_entities.lua")
dofile(modpath.."/play_sound.lua")
dofile(modpath.."/visual_effects.lua")
dofile(modpath.."/default_controls.lua")
dofile(modpath.."/touch_support.lua")
dofile(modpath.."/block_values.lua")
dofile(modpath.."/ammo_api.lua")
dofile(modpath.."/menus_and_guides.lua")
local path = modpath .. "/classes"
dofile(path.."/Bullet_hole.lua")
dofile(path.."/Bullet_ray.lua")
dofile(path.."/Control_handler.lua")
dofile(path.."/Ammo_handler.lua")
dofile(path.."/Part_handler.lua")
dofile(path.."/Sprite_scope.lua")
dofile(path.."/Reflector_sight.lua")
dofile(path.."/Dynamic_crosshair.lua")
dofile(path.."/Gun.lua") --> loads /classes/gun_construct.lua
dofile(path.."/Player_model_handler.lua")
dofile(path.."/Player_handler.lua")
--model compatibility
path = modpath .. "/models"
dofile(path.."/3darmor/init.lua")
--infinite ammo
minetest.register_privilege(Guns4d.config.infinite_ammo_priv, {
description = "allows player to have infinite ammo.",
give_to_singleplayer = false,
on_grant = function(name, granter_name)
local handler = Guns4d.players[name]
handler.infinite_ammo = true
minetest.chat_send_player(name, "infinite ammo enabled by "..(granter_name or "unknown"))
if handler.gun then
handler.gun:update_image_and_text_meta()
end
end,
on_revoke = function(name, revoker_name)
local handler = Guns4d.players[name]
handler.infinite_ammo = false
minetest.chat_send_player(name, "infinite ammo disabled by "..(revoker_name or "unknown"))
if handler.gun then
handler.gun:update_image_and_text_meta()
end
end,
})
minetest.register_chatcommand("ammoinf", {
parameters = "player",
description = "quick toggle infinite ammo",
privs = {privs=true},
func = function(caller, arg)
local trgt
local args = string.split(arg, " ")
local set_arg
if #args > 1 then
trgt = args[1]
set_arg = args[2]
else
set_arg = args[1]
trgt = caller
end
local handler = Guns4d.players[trgt]
local set_to
if set_arg then
if set_arg == "true" then
set_to = true
elseif set_arg ~= "false" then --if it's false we leave it as nil
minetest.chat_send_player(caller, "cannot toggle ammoinf, invalid value:"..set_arg)
return
end
else
set_to = not handler.infinite_ammo --if it's false set it to nil, otherwise set it to true.
if set_to == false then set_to = nil end
end
local privs = minetest.get_player_privs(trgt)
privs[Guns4d.config.infinite_ammo_priv] = set_to
minetest.set_player_privs(trgt, privs)
minetest.chat_send_player(caller, "infinite ammo "..((set_to and "granted to") or "revoked from") .." user '"..trgt.."'")
handler.infinite_ammo = set_to or false
if handler.gun then
handler.gun:update_image_and_text_meta()
handler.player:set_wielded_item(handler.gun.itemstack)
end
end
})
--player handling
setmetatable(Guns4d.handler_by_ObjRef, {
__mode = "kv"
})
setmetatable(Guns4d.gun_by_ObjRef, {
__mode = "kv"
})
local player_handler = Guns4d.player_handler
local objref_mtable
minetest.register_on_joinplayer(function(player)
local pname = player:get_player_name()
Guns4d.players[pname] = player_handler:new({player=player}) --player handler does just what it sounds like- see classes/Player_handler
Guns4d.handler_by_ObjRef[player] = Guns4d.players[pname]
--set the FOV to a predictable value
player:set_fov(Guns4d.config.default_fov)
--ObjRef overrides will be integrated into leef (eventually TM)
if not objref_mtable then
objref_mtable = getmetatable(player)
local old_set_fov = objref_mtable.set_fov
Guns4d.old_set_fov = old_set_fov
function objref_mtable.set_fov(self, ...)
local handler = Guns4d.handler_by_ObjRef[self]
local fov = select(1, ...)
if handler then --check, just in case it's not a player (and thus should throw an error)
if fov == 0 then
fov = Guns4d.config.default_fov
elseif select(2, ...) == true then
fov = Guns4d.config.default_fov*fov
end
handler.default_fov = fov
if handler.fov_lock then return end
end
local args = {...}
args[1] = fov --basically permenantly set the player's fov to 80, making multipliers and resets return there.
old_set_fov(self, unpack(args))
end
local old_get_pos = objref_mtable.get_pos
function objref_mtable.get_pos(self, ...)
local gun = Guns4d.gun_by_ObjRef[self]
local mt_pos = old_get_pos(self, ...)
if mt_pos then --mods (including this) will frequently use this as a check if an ent is still around.
if (not gun) or gun.released then
return mt_pos
else
local v, _, _ = gun:get_pos()
return v
end
end
end
function objref_mtable._guns4d_old_get_pos(self, ...)
return old_get_pos(self, ...)
end
local old_set_animation = objref_mtable.set_animation
--put vargs there for maintainability.
function objref_mtable.set_animation(self, frame_range, frame_speed, frame_blend, frame_loop, ...)
local gun = Guns4d.gun_by_ObjRef[self]
if gun then
local data = gun.animation_data
data.runtime = 0
data.fps = frame_speed or 15
--dont use the frame_range table because it's parent could get GCed if it's a metatable (proxy table issue.)
data.frames.x = frame_range.x
data.frames.y = frame_range.y
data.current_frame = data.frames.x
end
return old_set_animation(self, frame_range, frame_speed, frame_blend, frame_loop, ...)
end
local old_set_frame_speed = objref_mtable.set_animation_frame_speed
function objref_mtable.set_animation_frame_speed(self, frame_speed, ...)
local gun = Guns4d.gun_by_ObjRef[self]
if gun then
gun.animation_data.fps = frame_speed or 15
end
old_set_frame_speed(self, frame_speed, ...)
end
local old_remove = objref_mtable.remove
function objref_mtable.remove(self)
local gun = Guns4d.gun_by_ObjRef[self]
if gun then
Guns4d.gun_by_ObjRef[self] = nil
end
return old_remove(self)
end
--[[minetest.after(1, function(playername)
minetest.get_player_by_name(playername):hud_add({
hud_elem_type = "compass",
text = "gun_mrkr.png",
scale = {x=1, y=1},
alignment = {x=0,y=0},
position = {x=.5,y=.5},
size = {x=200, y=200},
offset = {x=-.5,y=.5},
direction = 0
})
end, player:get_player_name())]]
end
end)
--we grab the ObjRef metatable from the first available source.
--because we want guns to function as real objects, we have to override the metatable get_pos() for all objects
--this is made more efficient by using a table lookup for ObjRefs we want to update properly.
--"uns4d[ObjRef] = gun" is declared on_activate() in the entity.
--[[minetest.after(0, function()
end)]]
minetest.register_on_leaveplayer(function(player)
local pname = player:get_player_name()
Guns4d.players[pname]:prepare_deletion()
Guns4d.players[pname] = nil
Guns4d.handler_by_ObjRef[player] = nil
end)
--ticks are rarely used, but still ideal for rare checks with minimal overhead.
TICK = 0
minetest.register_globalstep(function(dt)
TICK = TICK + 1
if TICK > 100000 then TICK = 0 end
for player, handler in pairs(Guns4d.players) do
if not handler then
--spawn the player handler. The player handler handles the gun(s),
--the player's model, and controls
handler = player_handler:new({player=player})
end
handler:update(dt)
--[[minetest.get_player_by_name(player):hud_add({
hud_elem_type = "compass",
text = "gay.png",
scale = {x=10, y=10},
alignment = {x=0,y=0},
offset = {x=-.5,y=-.5},
direction = 0
})]]
end
end)