fixed animation rotation offset, added todo, added system for infinite ammo privelage, fixed a crash when changing weapons with sprite_scope(s)

This commit is contained in:
FatalErr42O 2023-12-23 21:15:40 -08:00
parent 74f92aa77f
commit b972ee78b8
16 changed files with 278 additions and 95 deletions

46
TODO.txt Normal file
View File

@ -0,0 +1,46 @@
( ) add audio
( ) add config
(x) fix crash when switching from a gun into a gun with a sprite_scope
(x) add infinite ammo privelage and quick command
( ) privilege not directly tied to infinite ammo, fix without breaking performance?
(x) fix animation rotation offset not displaying the correct frame
-was a problem with MTUL, changes push :D
( ) add entity scopes (for holo sights etc)
( ) add attachments
( ) add other reloading types
(x) magazine
( ) fractional
( ) flat (magless)
( ) fractional clip
( ) (for 5.9) make infinite ammo priv to rely on on_grant and on_revoke callback for runtime changes (broken as of 5.8)
( ) (5.9) POTENTIALLY make models use new PR that allows bone offsets to be disabled
-I'd probably have to modify models at loadtime to have an eye and hipfire bone? Probably easier then current system though.
( ) Fix HORRIBLE namespace violation in misc_helpers.lua. Also migrate features to MTUL libraries
this won't be fun.
documentation
( ) Instantiatable_class
( ) Player_model_handler
( ) Registering a model for compatibility
( ) Gun
( ) Sprite_scope
( ) Controls/Control_handler
( ) Creating controls
( ) default_controls.lua
( ) reloading types
( ) Dynamic_crosshair
( ) Ammunition penetration system/raycasting
( ) Ammunition registering
( ) Bullet
( ) Bullet_ray
( ) play_sound.lua
( ) misc_helpers.lua

View File

@ -46,8 +46,8 @@ function Ammo_handler:spend_round()
local meta = self.gun.meta
--subtract the bullet
if self.ammo.total_bullets > 0 then
--only actually subtract the round if INFINITE_AMMO_IN_CREATIVE isnt true or they arent creative.
if not (self.gun.consts.INFINITE_AMMO_IN_CREATIVE and minetest.check_player_privs(self.gun.player, "creative")) then
--only actually subtract the round if infinite_ammo is false.
if not self.handler.infinite_ammo then
self.ammo.loaded_bullets[bullet_spent] = self.ammo.loaded_bullets[bullet_spent]-1
if self.ammo.loaded_bullets[bullet_spent] == 0 then self.ammo.loaded_bullets[bullet_spent] = nil end
self.ammo.total_bullets = self.ammo.total_bullets - 1

View File

@ -13,6 +13,7 @@ Guns4d.control_handler = {
}
}
]]
ads = false,
}
--data table:
--[[
@ -88,7 +89,7 @@ function controls.construct(def)
assert(def.player, "no player provided")
def.controls = table.deep_copy(def.controls)
def.busy_list = {}
def.handler = Guns4d.players[def.player:get_player_name()].handler
def.handler = Guns4d.players[def.player:get_player_name()]
for i, control in pairs(def.controls) do
if not (i=="on_use") and not (i=="on_secondary_use") then
control.timer = control.timer or 0

View File

@ -30,14 +30,14 @@ end
local function render_length(rotation, fov)
local dir = vector.rotate({x=0,y=0,z=1}, {x=rotation.x*math.pi/180,y=0,z=0})
vector.rotate(dir,{x=0,y=rotation.y*math.pi/180,z=0})
local out = Point_to_hud(dir, fov, 1)
local out = rltv_point_to_hud(dir, fov, 1)
return math.sqrt(out.x^2+out.y^2)
end
function Dynamic_crosshair:update(dt)
assert(self.instance, "attemptr to call object method on a class")
local handler = self.handler
local gun = self.gun
if handler.wininfo and not handler.control_bools.ads then
if handler.wininfo and not handler.control_handler.ads then
local fov = self.player:get_fov()
--we have to recalc the rough direction, otherwise walking will look wonky.
local temp_vector = vector.new()
@ -85,7 +85,7 @@ function Dynamic_crosshair:update(dt)
--now figure out what frame will be our correct spread
local offset = Point_to_hud(dir, fov, 1) --pretend it's a 1:1 ratio so we can do things correctly.
local offset = rltv_point_to_hud(dir, fov, 1) --pretend it's a 1:1 ratio so we can do things correctly.
local length = math.sqrt(offset.x^2+offset.y^2) --get the max length.
local img_perc = (self.scale*2*handler.wininfo.real_hud_scaling*self.width)/handler.wininfo.size.x --the percentage that the hud element takes up

View File

@ -20,8 +20,8 @@ local gun_default = {
},
firemodes = {
"single", --not limited to semi-automatic.
"burst",
"auto"
--"burst",
--"auto"
},
firemode_inventory_overlays = {
single = "inventory_overlay_single.png",
@ -29,6 +29,7 @@ local gun_default = {
burst = "inventory_overlay_burst.png",
safe = "inventory_overlay_safe.png"
},
infinite_inventory_overlay = "inventory_overlay_inf_ammo.png",
recoil = { --used by update_recoil()
velocity_correction_factor = { --velocity correction factor is currently very broken.
gun_axial = 1,
@ -175,7 +176,6 @@ local gun_default = {
HAS_WAG = true,
HAS_GUN_AXIAL_OFFSETS = true,
ANIMATIONS_OFFSET_AIM = false,
INFINITE_AMMO_IN_CREATIVE = true,
LOOP_IDLE_ANIM = false
},
animation_data = { --where animations data is stored.
@ -236,14 +236,6 @@ function gun_default:update(dt)
if self.consts.HAS_BREATHING then self:update_breathing(dt) end
if self.consts.HAS_WAG then self:update_wag(dt) end
--dynamic crosshair needs to be updated BEFORE wag
if self.properties.sprite_scope then
self.sprite_scope:update()
end
if self.properties.crosshair then
self.crosshair:update()
end
self:update_animation(dt)
self.dir = self:get_dir()
self.local_dir = self:get_dir(true)
@ -251,6 +243,14 @@ function gun_default:update(dt)
self.local_paxial_dir = self:get_player_axial_dir(true)
self.pos = self:get_pos()+self.handler:get_pos()
if self.properties.sprite_scope then
self.sprite_scope:update()
end
if self.properties.crosshair then
self.crosshair:update()
end
local offsets = self.offsets
--local player_axial = offsets.recoil.player_axial + offsets.walking.player_axial + offsets.sway.player_axial + offsets.breathing.player_axial
--local gun_axial = offsets.recoil.gun_axial + offsets.walking.gun_axial + offsets.sway.gun_axial
@ -282,6 +282,7 @@ function gun_default:cycle_firemodes()
self:update_image_and_text_meta()
self.player:set_wielded_item(self.itemstack)
end
--remember to set_wielded_item to self.itemstack! otherwise these changes will not apply!
function gun_default:update_image_and_text_meta(meta)
meta = meta or self.meta
local ammo = self.ammo_handler.ammo
@ -305,10 +306,11 @@ function gun_default:update_image_and_text_meta(meta)
image = self.properties.inventory_image_empty
end
--add the firemode overlay to the image
if self.properties.firemode_inventory_overlays[self.properties.firemodes[self.current_firemode]] then
minetest.chat_send_all(self.current_firemode)
if #self.properties.firemodes > 1 and self.properties.firemode_inventory_overlays[self.properties.firemodes[self.current_firemode]] then
image = image.."^"..self.properties.firemode_inventory_overlays[self.properties.firemodes[self.current_firemode]]
else
end
if self.handler.infinite_ammo then
image = image.."^"..self.properties.infinite_inventory_overlay
end
meta:set_string("inventory_image", image)
end
@ -364,7 +366,7 @@ function gun_default:get_player_axial_dir(rltv)
local dir = Vec.new(Vec.rotate({x=0, y=0, z=1}, {y=0, x=((rotation.player_axial.x)*math.pi/180), z=0}))
dir = Vec.rotate(dir, {y=((rotation.player_axial.y)*math.pi/180), x=0, z=0})
if not rltv then
if (self.properties.sprite_scope and handler.control_bools.ads) or (self.properties.crosshair and not handler.control_bools.ads) then
if (self.properties.sprite_scope and handler.control_handler.ads) or (self.properties.crosshair and not handler.control_handler.ads) then
--we need the head rotation in either of these cases, as that's what they're showing.
dir = Vec.rotate(dir, {x=-handler.look_rotation.x*math.pi/180,y=-handler.look_rotation.y*math.pi/180,z=0})
else
@ -393,7 +395,7 @@ function gun_default:get_dir(rltv)
local dir = Vec.new(Vec.rotate({x=0, y=0, z=1}, {y=0, x=((rotation.gun_axial.x+rotation.player_axial.x)*math.pi/180), z=0}))
dir = Vec.rotate(dir, {y=((rotation.gun_axial.y+rotation.player_axial.y)*math.pi/180), x=0, z=0})
if not rltv then
if (self.properties.sprite_scope and handler.control_bools.ads) or (self.properties.crosshair and not handler.control_bools.ads) then
if (self.properties.sprite_scope and handler.control_handler.ads) or (self.properties.crosshair and not handler.control_handler.ads) then
--we need the head rotation in either of these cases, as that's what they're showing.
dir = Vec.rotate(dir, {x=-handler.look_rotation.x*math.pi/180,y=-handler.look_rotation.y*math.pi/180,z=0})
else
@ -423,7 +425,7 @@ function gun_default:get_pos(added_pos, relative, debug)
local handler = self.handler
local bone_location
local gun_offset
if handler.control_bools.ads then
if handler.control_handler.ads then
gun_offset = self.properties.ads.offset
bone_location = player:get_eye_offset() or vector.zero()
bone_location.y = bone_location.y + handler:get_properties().eye_height
@ -651,7 +653,7 @@ function gun_default:update_sway(dt)
end
function gun_default:update_animation_rotation()
local current_frame = self.animation_data.current_frame
local current_frame = self.animation_data.current_frame+self.consts.KEYFRAME_SAMPLE_PRECISION
local frame1 = math.floor(current_frame/self.consts.KEYFRAME_SAMPLE_PRECISION)
local frame2 = math.floor(current_frame/self.consts.KEYFRAME_SAMPLE_PRECISION)+1
current_frame = current_frame/self.consts.KEYFRAME_SAMPLE_PRECISION
@ -659,16 +661,20 @@ function gun_default:update_animation_rotation()
if self.b3d_model.global_frames.rotation then
if self.b3d_model.global_frames.rotation[frame1] then
if (not self.b3d_model.global_frames.rotation[frame2]) or (current_frame==frame1) then
out = vector.copy(self.b3d_model.global_frames.rotation[frame1])
out = vector.new(self.b3d_model.global_frames.rotation[frame1]:to_euler_angles_unpack())*180/math.pi
--print("rawsent")
else --to stop nan
local ip_ratio = current_frame-frame1
local vec1 = self.b3d_model.global_frames.rotation[frame1]
local vec2 = self.b3d_model.global_frames.rotation[frame2]
out = vec1+((vec1-vec2)*ip_ratio)
out = vector.new(vec1:slerp(vec2, ip_ratio):to_euler_angles_unpack())*180/math.pi
--out = vec1+((vec1-vec2)*ip_ratio) --they're euler angles... actually I wouldnt think this works, but it's good enough for my purposes.
--print("interpolated")
end
else
out = vector.copy(self.b3d_model.global_frames.rotation[1])
end
--print(frame1, frame2, current_frame, dump(out))
else
out = vector.new()
end
@ -678,9 +684,9 @@ end
--relative to the gun's entity. Returns left, right vectors.
local out = {arm_left=vector.new(), arm_right=vector.new()}
function gun_default:get_arm_aim_pos()
local current_frame = self.animation_data.current_frame
local frame1 = math.floor(current_frame/self.consts.KEYFRAME_SAMPLE_PRECISION)
local frame2 = math.floor(current_frame/self.consts.KEYFRAME_SAMPLE_PRECISION)+1
local current_frame = self.animation_data.current_frame+1
local frame1 = (math.floor(current_frame)/self.consts.KEYFRAME_SAMPLE_PRECISION)
local frame2 = (math.floor(current_frame)/self.consts.KEYFRAME_SAMPLE_PRECISION)+1
current_frame = current_frame/self.consts.KEYFRAME_SAMPLE_PRECISION
for i, v in pairs(out) do
@ -706,6 +712,7 @@ function gun_default:get_arm_aim_pos()
end
function gun_default:prepare_deletion()
self.released = true
assert(self.instance, "attempt to call object method on a class")
if self:has_entity() then self.entity:remove() end
if self.sprite_scope then self.sprite_scope:prepare_deletion() end
@ -823,10 +830,10 @@ gun_default.construct = function(def)
}
--print(table.tostring(def.b3d_model))
--precalculate keyframe "samples" for intepolation.
--mildly infuriating that lua just stops short by one (so I have to add one extra) I *think* I get why though.
local left = mtul.b3d_nodes.get_node_by_name(def.b3d_model, props.visuals.arm_left, true)
local right = mtul.b3d_nodes.get_node_by_name(def.b3d_model, props.visuals.arm_right, true)
local main = mtul.b3d_nodes.get_node_by_name(def.b3d_model, props.visuals.root, true)
--we add 2 because we have to add 1 for the loop to make it there if it's a float val, and MTUL uses a system where frame 0 is 1
for target_frame = 0, def.b3d_model.node.animation.frames+1, def.consts.KEYFRAME_SAMPLE_PRECISION do
--we need to check that the bone exists first.
if left then
@ -843,14 +850,20 @@ gun_default.construct = function(def)
if main then
--use -1 as it does not exist and thus will always go to the default resting pose
--we compose it by the inverse because we need to get the global CHANGE in rotation for the animation rotation offset. I really need to comment more often
local newvec = (mtul.b3d_nodes.get_node_rotation(def.b3d_model, main, nil, -1):inverse())*mtul.b3d_nodes.get_node_rotation(def.b3d_model, main, nil, target_frame)
newvec = vector.new(newvec:to_euler_angles_unpack())*180/math.pi
--newvec.z = 0
--used to use euler
table.insert(def.b3d_model.global_frames.rotation, newvec)
print(target_frame)
print(dump(vector.new(mtul.b3d_nodes.get_node_rotation(def.b3d_model, main, nil, -1):to_euler_angles_unpack())*180/math.pi))
end
end
if main then
local quat = mtul.math.quat.new(main.keys[1].rotation)
print(dump(main.keys[1]), vector.new(quat:to_euler_angles_unpack(quat)))
end
for i, v in pairs(def.b3d_model.global_frames.rotation) do
print(i, dump(vector.new(v:to_euler_angles_unpack())*180/math.pi))
end
--print()
-- if it's not a template, then create an item, override some props
if def.name ~= "__template" then
assert(def.itemstring, "no itemstring provided. Cannot create a gun without an associated itemstring.")
@ -870,13 +883,13 @@ gun_default.construct = function(def)
if old_on_use then
old_on_use(itemstack, user, pointed_thing)
end
Guns4d.players[user:get_player_name()].handler.control_handler:on_use(itemstack, pointed_thing)
Guns4d.players[user:get_player_name()].control_handler:on_use(itemstack, pointed_thing)
end,
on_secondary_use = function(itemstack, user, pointed_thing)
if old_on_s_use then
old_on_s_use(itemstack, user, pointed_thing)
end
Guns4d.players[user:get_player_name()].handler.control_handler:on_secondary_use(itemstack, pointed_thing)
Guns4d.players[user:get_player_name()].control_handler:on_secondary_use(itemstack, pointed_thing)
end
})
end
@ -907,12 +920,12 @@ gun_default.construct = function(def)
local obj = self.object
if not self.parent_player then obj:remove() return end
local player = self.parent_player
local handler = Guns4d.players[player:get_player_name()].handler
local handler = Guns4d.players[player:get_player_name()]
local lua_object = handler.gun
if not lua_object then obj:remove() return end
--this is changing the point of rotation if not aiming, this is to make it look less shit.
local axial_modifier = Vec.new()
if not handler.control_bools.ads then
if not handler.control_handler.ads then
local pitch = lua_object.total_offset_rotation.player_axial.x+lua_object.player_rotation.x
axial_modifier = Vec.new(pitch*(1-lua_object.consts.HIP_PLAYER_GUN_ROT_RATIO),0,0)
end
@ -922,7 +935,7 @@ gun_default.construct = function(def)
if lua_object.sprite_scope and lua_object.sprite_scope.hide_gun and (not (handler.ads_location == 0)) then
visibility = false
end
if handler.control_bools.ads then
if handler.control_handler.ads then
local normal_pos = (props.ads.offset)*10
obj:set_attach(player, lua_object.consts.AIMING_BONE, normal_pos, -axial_rot, visibility)
else

View File

@ -1,7 +1,4 @@
local Vec = vector
local default_active_controls = {
ads = false
}
local player_handler = {
--player = playerref
--name = playername
@ -9,10 +6,10 @@ local player_handler = {
--gun = Gun (class)
--wield_index = Int
--player_model_handler = player_model_handler
--infinite_ammo = false
look_rotation = {x=0, y=0},
look_offset = Vec.new(),
ads_location = 0, --interpolation scalar for gun aiming location
controls = {},
default_fov = 80,
fov = 80,
horizontal_offset = 0
@ -31,19 +28,17 @@ function player_handler:update(dt)
--initialize important player data
self.itemstack = self.wielded_item
self.inventory = player:get_inventory()
----gun (handler w/physical manifestation)----
--initialize our handlers
if self.gun then --delete gun object if present
self.gun:prepare_deletion()
self.gun = nil
end
self.gun = held_gun:new({itemstack=self.wielded_item, handler=self}) --this will set itemstack meta, and create the gun based off of meta and other data.
----model handler----
if self.player_model_handler then --if player_model_handler present, then delete
self.player_model_handler:prepare_deletion()
self.player_model_handler = nil
end
self.player_model_handler = Guns4d.player_model_handler.get_handler(self:get_properties().mesh):new({player=self.player})
----control handler----
self.control_handler = Guns4d.control_handler:new({player=player, controls=self.gun.properties.controls})
--this needs to be stored for when the gun is unset!
@ -75,18 +70,18 @@ function player_handler:update(dt)
--delete gun object
self.gun:prepare_deletion()
self.gun = nil
self:reset_controls_table() --return controls to default
--delete model handler object (this resets the player model)
self.player_model_handler:prepare_deletion()
self.player_model_handler = nil
player:hud_set_flags({wielditem = true, crosshair = true}) --reenable hud elements
end
--eye offsets and ads_location
if self.control_bools.ads and (self.ads_location<1) then
if (self.control_handler and self.control_handler.ads) and (self.ads_location<1) then
--if aiming, then increase ADS location
self.ads_location = math.clamp(self.ads_location + (dt/self.gun.properties.ads.aim_time), 0, 1)
elseif (not self.control_bools.ads) and self.ads_location>0 then
elseif ((not self.control_handler) or (not self.control_handler.ads)) and self.ads_location>0 then
local divisor = .2
if self.gun then
divisor = self.gun.properties.ads.aim_time/self.gun.consts.AIM_OUT_AIM_IN_SPEED_RATIO
@ -146,11 +141,6 @@ function player_handler:unset_fov(transition)
self.fov_lock = false
Guns4d.old_set_fov(self.player, self.default_fov, nil, transition)
end
--resets the controls bools table for the player_handler
function player_handler:reset_controls_table()
assert(self.instance, "attempt to call object method on a class")
self.control_bools = table.deep_copy(default_active_controls)
end
--doubt I'll ever use this... but just in case I don't want to forget.
function player_handler:get_pos()
assert(self.instance, "attempt to call object method on a class")
@ -219,7 +209,7 @@ function player_handler.construct(def)
end
end
def.look_rotation = table.deep_copy(player_handler.look_rotation)
def.control_bools = table.deep_copy(default_active_controls)
def.infinite_ammo = minetest.check_player_privs(def.player, Guns4d.config.infinite_ammo_priv)
end
end
Guns4d.player_handler = Instantiatable_class:inherit(player_handler)

View File

@ -64,7 +64,7 @@ function player_model:update(dt)
--gun bones:
local first, second = player:get_eye_offset()
local eye_pos = vector.new(0, handler:get_properties().eye_height*10, 0)+first
if handler.control_bools.ads then
if handler.control_handler.ads then
eye_pos.x = handler.horizontal_offset*10
end
player:set_bone_position(self.bone_names.hipfire, self.offsets.relative.arm_right, {x=-(pitch*gun.consts.HIP_PLAYER_GUN_ROT_RATIO), y=180-player_axial_offset.y, z=0})
@ -110,7 +110,7 @@ end
--should be renamed to "release" but, whatever.
function player_model:prepare_deletion()
assert(self.instance, "attempt to call object method on a class")
local handler = Guns4d.players[self.player:get_player_name()].handler
local handler = Guns4d.players[self.player:get_player_name()]
local properties = handler:get_properties()
if minetest.get_modpath("player_api") then
player_api.set_model(self.player, self.old)
@ -123,7 +123,7 @@ end
function player_model.construct(def)
if def.instance then
assert(def.player, "no player provided")
def.handler = Guns4d.players[def.player:get_player_name()].handler
def.handler = Guns4d.players[def.player:get_player_name()]
local properties = def.handler:get_properties()
def.old = properties.mesh
--set the mesh

View File

@ -46,11 +46,12 @@ local Sprite_scope = Instantiatable_class:inherit({
end
end,
})
Guns4d.sprite_scope = Sprite_scope
--rename to draw?
function Sprite_scope:update()
local handler = self.handler
if handler.wininfo and self.handler.control_bools.ads then
if handler.wininfo and self.handler.control_handler.ads then
if not self.fov_set then
self.fov_set = true
handler:set_fov(80/self.magnification)
@ -62,12 +63,12 @@ function Sprite_scope:update()
dir = dir + (self.gun.properties.ads.offset+vector.new(self.gun.properties.ads.horizontal_offset,0,0))*0
end
local fov = self.player:get_fov()
local real_aim = Point_to_hud(dir, fov, ratio)
local anim_aim = Point_to_hud(vector.rotate({x=0,y=0,z=1}, self.gun.animation_rotation*math.pi/180), fov, ratio)
local real_aim = rltv_point_to_hud(dir, fov, ratio)
local anim_aim = rltv_point_to_hud(vector.rotate({x=0,y=0,z=1}, self.gun.animation_rotation*math.pi/180), fov, ratio)
real_aim.x = real_aim.x+anim_aim.x; real_aim.y = real_aim.y+anim_aim.y
--print(dump(self.gun.animation_rotation))
local paxial_aim = Point_to_hud(self.gun.local_paxial_dir, fov, ratio)
local paxial_aim = rltv_point_to_hud(self.gun.local_paxial_dir, fov, ratio)
--so custom scopes can do their thing without doing more calcs
self.hud_projection_real = real_aim
self.hud_projection_paxial = paxial_aim
@ -102,4 +103,4 @@ function Sprite_scope:prepare_deletion()
for i, v in pairs(self.elements) do
self.player:hud_remove(v)
end
end
end

View File

@ -7,7 +7,7 @@ Guns4d.default_controls.aim = {
timer = 0,
func = function(active, interrupted, data, busy_list, gun, handler)
if active then
handler.control_bools.ads = not handler.control_bools.ads
handler.control_handler.ads = not handler.control_handler.ads
end
end
}

View File

@ -20,7 +20,7 @@ The control system is designed to be simple but versatile,
timer = 0,
func = function(active, interrupted, data, busy_list, handler)
if active then
handler.control_bools.ads = not handler.control_bools.ads
handler.control_handler.ads = not handler.control_handler.ads
end
end
},

59
infinite_ammo.lua Normal file
View File

@ -0,0 +1,59 @@
--register the infinite ammo privelage.
minetest.register_privilege(Guns4d.config.infinite_ammo_priv, {
description = "allows player to have infinite ammo.",
give_to_singleplayer = false,
give_to_admin = true,
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 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
handler.gun:update_image_and_text_meta()
handler.player:set_wielded_item(handler.gun.itemstack)
end
})

View File

@ -4,12 +4,22 @@ Guns4d = {
handler_by_ObjRef = {},
gun_by_ObjRef = {} --used for getting the gun object by the ObjRef of the gun
}
--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,
empty_symbol = "0e",
infinite_ammo_priv = "guns4d_infinite_ammo"
}
local path = minetest.get_modpath("guns4d")
dofile(path.."/infinite_ammo.lua")
dofile(path.."/misc_helpers.lua")
dofile(path.."/play_sound.lua")
dofile(path.."/visual_effects.lua")
dofile(path.."/default_controls.lua")
dofile(path.."/block_values.lua")
dofile(path.."/register_ammo.lua")
dofile(path.."/ammo_api.lua")
path = path .. "/classes"
dofile(path.."/Instantiatable_class.lua")
dofile(path.."/Bullet_ray.lua")
@ -22,15 +32,6 @@ dofile(path.."/Player_model_handler.lua")
dofile(path.."/Player_handler.lua")
dofile(path.."/Proxy_table.lua")
--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,
empty_symbol = "0e"
}
--load after
path = minetest.get_modpath("guns4d")
@ -38,16 +39,14 @@ local player_handler = Guns4d.player_handler
local objref_mtable
minetest.register_on_joinplayer(function(player)
local pname = player:get_player_name()
Guns4d.players[pname] = {
handler = player_handler:new({player=player})
}
Guns4d.handler_by_ObjRef[player] = Guns4d.players[pname].handler
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(80)
--ObjRef overrides will be integrated into MTUL (eventually TM)
if not objref_mtable then
objref_mtable = getmetatable(player)
print(dump(objref_mtable))
local old_set_fov = objref_mtable.set_fov
Guns4d.old_set_fov = old_set_fov
@ -61,15 +60,21 @@ minetest.register_on_joinplayer(function(player)
end
local old_get_pos = objref_mtable.get_pos
function objref_mtable.get_pos(self)
function objref_mtable.get_pos(self, ...)
local gun = Guns4d.gun_by_ObjRef[self]
if not gun then
return old_get_pos(self)
else
local v, _, _ = gun:get_pos()
return v
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.
@ -87,7 +92,7 @@ minetest.register_on_joinplayer(function(player)
--This means I literally need to flip flop between +1 frames
frame_range = table.copy(frame_range)
--minetest.chat_send_all(dump(frame_range))
if data.frames.x == frame_range.x and data.frames.y == frame_range.y then
if (data.frames.x == frame_range.x and data.frames.y == frame_range.y) and not (frame_range.x==frame_range.y) then
--oh yeah, and it only accepts whole frames... because of course.
frame_range.x = frame_range.x+1
--minetest.chat_send_all("+1")
@ -128,7 +133,7 @@ end)
end)]]
minetest.register_on_leaveplayer(function(player)
local pname = player:get_player_name()
Guns4d.players[pname].handler:prepare_deletion()
Guns4d.players[pname]:prepare_deletion()
Guns4d.players[pname] = nil
Guns4d.handler_by_ObjRef[player] = nil
end)
@ -138,12 +143,12 @@ TICK = 0
minetest.register_globalstep(function(dt)
TICK = TICK + 1
if TICK > 100000 then TICK = 0 end
for player, obj in pairs(Guns4d.players) do
if not obj.handler then
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
obj.handler = player_handler:new({player=player})
handler = player_handler:new({player=player})
end
obj.handler:update(dt)
handler:update(dt)
end
end)

View File

@ -261,10 +261,10 @@ function table.shallow_copy(t)
return new_table
end
--for the following code and functions only:
--for the following function only:
--for license see the link on the next line (direct permission was granted).
--https://github.com/3dreamengine/3DreamEngine
function Point_to_hud(pos, fov, aspect)
function rltv_point_to_hud(pos, fov, aspect)
local n = .1 --near
local f = 1000 --far
--wherever you are
@ -282,5 +282,5 @@ function Point_to_hud(pos, fov, aspect)
local x = (pos.x/pos.z)*a1
local y = (pos.y/pos.z)*a6
local z = (pos.z/pos.z)*a11
return {x=x / 2,y=-y / 2,}
return {x=x / 2,y=-y / 2} --output needs to be offset by +.5 on both for HUD elements, but this cannot be integrated.
end

68
play_sound.lua Normal file
View File

@ -0,0 +1,68 @@
--simple specification for playing a sound in relation to an action, acts as a layer of minetest.play_sound
--"gsp" guns4d-sound-spec
--first person for the gun holder, third person for everyone else. If first not present, third will be used.
--passes table directly to minetest.play_sound and adds a few additional parameters
--example:
--[[
additional properties
first_person = playername,
second_person = playername
sounds = { --weighted randoms:
fire_fp = .5.
fire_fp_2 = .2.
fire_fp_3 = .3
},
pitch = {
min = .6,
max = 1
},
gain = 1, --format for pitch and gain is interchangable.
min_hear_distance = 20, --this is for distant gunshots, for example. Entirely optional. Cannot be used with to_player
to_player
--when present it automatically plays positionless audio, as this is for first person effects.
]]
local sqrt = math.sqrt
function Guns4d.play_sounds(...)
local args = {...}
local out = {}
assert(args[1], "no arguments provided")
for i, soundspec in pairs(args) do
assert(not (soundspec.to_player and soundspec.min_distance), "in argument '"..tostring(i).."' `min_distance` and `to_player` are incompatible parameters.")
local sound
local outval
if type(soundspec.pitch) == "table" then
local pitch = soundspec.pitch
soundspec.pitch = pitch.min+(math.random()*(pitch.max-pitch.min))
end
if type(soundspec.gain) == "table" then
local gain = soundspec.gain
soundspec.pitch = gain.min+(math.random()*(gain.max-gain.min))
end
if type(soundspec.sound) == "table" then
sound = math.weighted_randoms(soundspec.sound)
end
if soundspec.to_player then soundspec.pos = nil end
if soundspec.min_hear_distance then
local exclude_player_ref
if soundspec.exclude_player then
exclude_player_ref = minetest.get_player_by_name(soundspec.exclude_player)
end
for _, player in pairs(minetest.get_connected_players()) do
local pos = player:get_pos()
local dist = sqrt( sqrt(pos.x^2+pos.y^2)^2 +pos.z^2 )
if (dist > soundspec.min_distance) and (player~=exclude_player_ref) then
soundspec.exclude_player = nil --not needed anyway because we can just not play it for this player.
soundspec.to_player = player:get_player_name()
outval = minetest.play_sound(sound, soundspec)
end
end
else
outval = minetest.play_sound(sound, soundspec)
end
out[i] = outval
end
return out
end
function Guns4d.stop_sounds(handle_list)
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 B