spacecannon/util.lua
Kiëd Llaentenn 6737757471
Fix projectiles not damaging players (#20)
* fix: projectile not damaging players

* feat: allow servers to control entity/player damage

* tweak: lower cannon damage numbers a bit

* fix: style
2023-06-01 21:46:56 -04:00

230 lines
5.6 KiB
Lua

-- vi: noexpandtab
local has_digilines = minetest.get_modpath("digilines")
spacecannon.update_formspec = function(meta, is_th)
local formspec = ""
if not is_th then
formspec = formspec ..
"formspec_version[4]" ..
"size[10.5,9;]"
-- Ammo inventory
formspec = formspec ..
"list[current_name;src;0.375,0.5;1,1;]" ..
"list[current_player;main;0.375,4;8,4;]" ..
"listring[]" ..
"label[1.75,1;Ammunition]"
-- Manual "fire" button
formspec = formspec ..
"button_exit[5.125,0.5;5,1;fire;Fire]"
-- Digiline channel
if has_digilines then
local channel = meta:get_string("channel") or ""
formspec = formspec ..
"field[0.375,2.375;4,1;digiline_channel;Digiline Channel;" .. channel .. "]" ..
"button_exit[4.5,2.375;1,1;set_digiline_channel;Set]"
end
else
formspec = formspec .. "formspec_version[4]"
if has_digilines then
formspec = formspec .. "size[6,4;]"
else
formspec = formspec .. "size[6,2;]"
end
-- Manual "fire" button
formspec = formspec ..
"button_exit[0.5,0.5;5,1;fire;Fire]"
-- Digiline channel
if has_digilines then
local channel = meta:get_string("channel") or ""
formspec = formspec ..
"field[0.5,2.5;3.5,1;digiline_channel;Digiline Channel;" .. channel .. "]" ..
"button_exit[4.5,2.5;1,1;set_digiline_channel;Set]"
end
end
meta:set_string("formspec", formspec)
end
spacecannon.can_shoot = function()
-- arguments: pos, playername
return true
end
spacecannon.can_destroy = function()
-- arguments: pos
return true
end
spacecannon.can_damage = function(_obj)
return true
end
spacecannon.fire = function(pos, playername, color, speed, is_th, storage_require_mod)
if not spacecannon.can_shoot(pos, playername) then
return
end
-- check fuel/power
local meta = minetest.get_meta(pos)
local config_store = spacecannon.config.ki_powerstorage * storage_require_mod
if is_th then config_store = spacecannon.config.th_powerstorage * storage_require_mod end
if meta:get_int("powerstorage") < config_store then
-- not enough power
return
end
-- check ammunition
if not is_th then
local inv = meta:get_inventory()
if inv:is_empty("src") then
--minetest.chat_send_player(playername, "No ammunition loaded!")
return false
end
local src_stack = inv:get_list("src")[1]
if not src_stack or src_stack:get_name() ~= "spacecannon:railgun_slug" then
--minetest.chat_send_player(playername, "Incorrect ammunition!")
return
end
end
-- use power
meta:set_int("powerstorage", 0)
-- use ammo
if not is_th then
local src_stack = (meta:get_inventory()):get_list("src")[1]
src_stack:take_item();
(meta:get_inventory()):set_stack("src", 1, src_stack)
end
minetest.sound_play("spacecannon_shoot", {
pos = pos,
gain = 1.0,
max_hear_distance = 16
})
local node = minetest.get_node(pos)
local dir = spacecannon.facedir_to_down_dir(node.param2)
local obj = minetest.add_entity({x=pos.x+dir.x, y=pos.y+dir.y, z=pos.z+dir.z}, "spacecannon:energycube_" .. color)
obj:setvelocity({x=dir.x*speed, y=dir.y*speed, z=dir.z*speed})
end
-- destroy stuff in range
-- TODO: resilient material list
spacecannon.destroy = function(pos, range, intensity)
if not spacecannon.can_destroy(pos) then
return
end
local particle_texture = nil
for x=-range,range do
for y=-range,range do
for z=-range,range do
if x*x+y*y+z*z <= range * range + range then
local np={x=pos.x+x,y=pos.y+y,z=pos.z+z}
if minetest.is_protected(np, "") then
return -- fail fast
end
local n = minetest.get_node_or_nil(np)
if n and n.name ~= "air" then
local node_def = minetest.registered_nodes[n.name]
if node_def and node_def.tiles and node_def.tiles[1] then
particle_texture = node_def.tiles[1]
end
if node_def.on_blast then
-- custom on_blast
node_def.on_blast(np, intensity)
else
-- default behavior
local resilience = spacecannon.node_resilience[n.name] or 1
if resilience <= 1 or math.random(resilience) == resilience then
minetest.set_node(np, {name="air"})
local itemstacks = minetest.get_node_drops(n.name)
for _, itemname in ipairs(itemstacks) do
if math.random(5) == 5 then
-- chance drop
minetest.add_item(np, itemname)
end
end
end
end
end
end
end
end
end
local radius = range
-- https://github.com/minetest/minetest_game/blob/master/mods/tnt/init.lua
minetest.add_particlespawner({
amount = 64,
time = 0.5,
minpos = vector.subtract(pos, radius / 2),
maxpos = vector.add(pos, radius / 2),
minvel = {x = -10, y = -10, z = -10},
maxvel = {x = 10, y = 10, z = 10},
minacc = vector.new(),
maxacc = vector.new(),
minexptime = 1,
maxexptime = 2.5,
minsize = radius * 3,
maxsize = radius * 5,
texture = "spacecannon_spark.png",
glow = 5
})
if particle_texture then
minetest.add_particlespawner({
amount = 64,
time = 0.5,
minpos = vector.subtract(pos, radius / 2),
maxpos = vector.add(pos, radius / 2),
minvel = {x = -10, y = -10, z = -10},
maxvel = {x = 10, y = 10, z = 10},
minacc = vector.new(),
maxacc = vector.new(),
minexptime = 1,
maxexptime = 2.5,
minsize = radius * 3,
maxsize = radius * 5,
texture = particle_texture,
glow = 5
})
end
minetest.sound_play("tnt_explode", {pos = pos, gain = 1.5, max_hear_distance = math.min(radius * 20, 128)})
end
-- convert face dir to vector
spacecannon.facedir_to_down_dir = function(facing)
return (
{[0]={x=0, y=-1, z=0},
{x=0, y=0, z=-1},
{x=0, y=0, z=1},
{x=-1, y=0, z=0},
{x=1, y=0, z=0},
{x=0, y=1, z=0}})[math.floor(facing/4)]
end