update gunslinger

added bloom, reloading delay, damage reduction with range, a weapon entity that is attached when you have the weapon in your inv, and making your inventory smaller when you have large weapons
This commit is contained in:
Elkien3 2020-11-20 11:25:56 -06:00
parent 05aa97769b
commit e5976cebe0
2 changed files with 220 additions and 6 deletions

50
api.lua
View File

@ -13,6 +13,7 @@ local types = {}
local automatic = {}
local scope_overlay = {}
local interval = {}
local bloom = {}
--
-- Internal API functions
@ -100,6 +101,7 @@ local function reload(stack, player, ammo)
if not ammo then
return stack
end
local playername = player:get_player_name()
local is_mag = minetest.get_item_group(ammo, "gunslinger_magazine") > 0
local inv = player:get_inventory()
if inv:contains_item("main", ammo) then
@ -124,6 +126,15 @@ local function reload(stack, player, ammo)
stack:set_wear(0)
inv:remove_item("main", ammo)
end
local def = gunslinger.get_def(stack:get_name())
interval[playername] = def.unit_time-1
minetest.after(-interval[playername], function()
minetest.sound_play("gunslinger_charge", {
object = player,
max_hear_distance = 30,
pitch = math.random(70,90)*.01
})
end)
minetest.sound_play("gunslinger_loadmag", {
object = player,
max_hear_distance = 30,
@ -211,6 +222,25 @@ local function fire(stack, player, base_spread, max_spread, pellets)
end
--a little calculation. speed divided by max speed should always be a value between 0 and 1.
base_spread = base_spread + max_spread*(speed/max_speed)
--add bloom
local bloomref = bloom[player:get_player_name()]
if bloomref then
base_spread = base_spread + bloomref.time or 0
bloomref.time = bloomref.time + def.bloom_amount or 0
if bloomref.time > def.bloom_amount*4 then
bloomref.time = def.bloom_amount*4
end
elseif def.bloom_amount then
bloomref = {}
bloomref.time = def.bloom_amount
bloomref.multiplier = (def.bloom_decay or 1)*def.bloom_amount
end
--don't allow spread to go beyond the maximum for the gun.
if base_spread > max_spread then
base_spread = max_spread
end
bloom[player:get_player_name()] = bloomref
end
if not pellets then pellets = 1 end
for i = 1, pellets do
@ -255,9 +285,9 @@ local function fire(stack, player, base_spread, max_spread, pellets)
local target = pointed.ref
local point = pointed.intersection_point
local dmg = def.base_dmg * def.dmg_mult
local targetpos = target:get_pos()
-- Add 50% damage if headshot
if point.y > target:get_pos().y + 1.5 then
if point.y > targetpos.y + 1.5 then
dmg = dmg * 1.5
end
@ -265,7 +295,9 @@ local function fire(stack, player, base_spread, max_spread, pellets)
if scope_overlay[player:get_player_name()] then
dmg = dmg * 1.2
end
local distmulti = -(vector.distance(p1, targetpos)/def.range)^2+1
dmg = dmg*distmulti
if dmg < 0 then dmg = 0 end
target:punch(player, nil, {damage_groups={fleshy=dmg}})
end
end
@ -363,8 +395,9 @@ local function on_rclick(stack, player)
end
local function on_q(itemstack, dropper, pos)
local playername = dropper:get_player_name()
local name = itemstack:get_name()
if dropper:get_wielded_item():get_name() ~= name or not minetest.get_player_by_name(dropper:get_player_name()) then return end
if dropper:get_wielded_item():get_name() ~= name or not playername then return end
local def = gunslinger.get_def(name)
local inv = dropper:get_inventory()
minetest.sound_play("gunslinger_dropmag", {
@ -383,6 +416,10 @@ end
--------------------------------
local function on_step(dtime)
for name, data in pairs(bloom) do
bloom[name].time = data.time - dtime*data.multiplier or 1
if data.time <= 0 then bloom[name] = nil end
end
for name in pairs(interval) do
interval[name] = interval[name] + dtime
end
@ -418,7 +455,8 @@ end
--
function gunslinger.get_def(name)
return guns[name]
if not name then return guns end
return guns[name:gsub("%_empty", "")]
end
function gunslinger.register_type(name, def)
@ -519,7 +557,7 @@ function gunslinger.register_magazine(magazine, ammunition, size)
minetest.register_craft({
type = "shapeless",
output = magazine,
recipe = {magazine, ammunition},
recipe = {magazine, ammunition.." "..size},
})
minetest.register_craft({
type = "shapeless",

176
invspace.lua Normal file
View File

@ -0,0 +1,176 @@
local gunitems = {}
local invsize = 8*4
minetest.register_entity("gunslinger:gunitem",{
hp_max = 1,
visual="wielditem",
visual_size={x=.4,y=.4},
collisionbox = {0,0,0,0,0,0},
physical=false,
textures={"air"},
on_activate = function(self, staticdata)
if not staticdata or staticdata == "" then self.object:remove() return end
local data = minetest.deserialize(staticdata)
if not data or not data.owner or not data.item then self.object:remove() return end
local player = minetest.get_player_by_name(data.owner)
if not player then gunitems[data.owner] = nil self.object:remove() return end
self.object:set_attach(player, "Body", {x=0,y=4,z=1.5}, {x=0,y=0,z=0})
self.object:set_properties({textures = { data.item }})
end
})
local function get_weapons(player)
local name = player:get_player_name()
local inv = player:get_inventory()
local lists = inv:get_lists()
local weapons = {}
for list, data in pairs(lists) do
local size = inv:get_size(list)
for i = 1, size do
local stack = inv:get_stack(list, i)
local stackname = stack:get_name()
if stackname then
stacksub = stackname
if gunslinger.get_def(stacksub) and not gunslinger.get_def(stacksub).concealed then
if (wieldview or wield3d) and list == "main" and player:get_wield_index() == i then
weapons["wield"] = stackname
else
table.insert(weapons, stackname)
end
end
end
end
end
return weapons
end
local function get_largest(weapons)
local size = 0
local bigindex
for index, weapon in pairs(weapons) do
if index ~= "wield" then
local gunsize = gunslinger.get_def(weapon).space
if gunsize and gunsize > size then size = gunsize bigindex = index end
end
end
return bigindex or 1
end
local function update_weapon(player)
local weapons = get_weapons(player)
local weapon = weapons[get_largest(weapons)]
local name = player:get_player_name()
local gunspace = 0
for index, gun in pairs(weapons) do
gun = gun
local def = gunslinger.get_def(gun)
if def and def.space then
gunspace = gunspace + def.space-1
end
end
local player_inv = player:get_inventory()
if invsize-gunspace ~= player_inv:get_size("main") then
for i = invsize-gunspace+1, invsize do
minetest.item_drop(player_inv:get_stack("main", i), player, player:get_pos())
end
player_inv:set_size("main", invsize-gunspace)
end
if not weapon then
if gunitems[name] then
gunitems[name]:remove()
gunitems[name] = nil
end
return
end
if not gunitems[name] then
gunitems[name] = minetest.add_entity(player:get_pos(), "gunslinger:gunitem", minetest.serialize({owner = name, item = weapon}))
else
gunitems[name]:set_properties({textures = { weapon }})
end
end
minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info)
--minetest.chat_send_all("oi")
--return 0
end)
--[[ * Determines how much of a stack may be taken, put or moved to a
player inventory.
* `player` (type `ObjectRef`) is the player who modified the inventory
`inventory` (type `InvRef`).
* List of possible `action` (string) values and their
`inventory_info` (table) contents:
* `move`: `{from_list=string, to_list=string, from_index=number, to_index=number, count=number}`
* `put`: `{listname=string, index=number, stack=ItemStack}`
* `take`: Same as `put`
* Return a numeric value to limit the amount of items to be taken, put or
moved. A value of `-1` for `take` will make the source stack infinite.--]]
minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
local stack = inventory_info.stack
if not stack and action == "move" then
stack = inventory:get_stack(inventory_info.to_list, inventory_info.to_index)
if not stack or not gunslinger.get_def(stack:get_name()) then
stack = inventory:get_stack(inventory_info.from_list, inventory_info.from_index)
end
end
if stack and gunslinger.get_def(stack:get_name()) then
update_weapon(player)
end
end)
minetest.register_on_joinplayer(function(player, last_login)
update_weapon(player)
end)
minetest.register_on_leaveplayer(function(player, last_login)
local name = player:get_player_name()
if gunitems[name] then
gunitems[name]:remove()
gunitems[name] = nil
end
end)
minetest.register_on_respawnplayer(function(player, last_login)
local name = player:get_player_name()
if gunitems[name] then
gunitems[name]:remove()
gunitems[name] = nil
end
end)
if armor then
local origfunc = armor.update_player_visuals
armor.update_player_visuals = function(self, player)
minetest.after(0, update_weapon, player)
return origfunc(self, player)
end
else
local wieldtimer = 0
local lastwield = {}
minetest.register_globalstep(function(dtime)
wieldtimer = wieldtimer + dtime
if wieldtimer > .5 then
for _,player in ipairs(minetest.get_connected_players()) do
local name = player:get_player_name()
local wielditem = player:get_wielded_item():get_name()
if not lastwield[name] then lastwield[name] = wielditem else
if wielditem ~= lastwield[name] then
update_weapon(player)
end
lastwield[name] = wielditem
end
end
wieldtimer = 0
end
end)
end
local function reattach()
for _,player in ipairs(minetest.get_connected_players()) do
local name = player:get_player_name()
if gunitems[name] then
gunitems[name]:set_attach(player, "Body", {x=0,y=4,z=1.5}, {x=0,y=0,z=0})
end
end
minetest.after(5, reattach)
end
--minetest.after(5, reattach) --uncomment if you have issues with item getting detached in multiplayer