InsaneProtestor/mods/ip_extinguisher/init.lua
2022-11-24 00:51:57 -05:00

302 lines
7.8 KiB
Lua

local range = 100
local v = 1
local a = 100
local speed = 0.1 --0 or less for default maximum speed
local function spray_foam(pos)
if minetest.get_node(pos).name == "extinguisher:foam" then
-- Do not spray foam onto foam
return
end
for z = -1,1 do
for y = -1,1 do
for x = -1,1 do
local p = {x=pos.x+x, y=pos.y+y, z=pos.z+z}
local nn = minetest.get_node(p).name
if nn == "fire:basic_flame" or nn == "fire:permanent_flame" then
minetest.set_node(p, {name="air"})
minetest.sound_play("fire_extinguish_flame",
{pos = p, max_hear_distance = 16, gain = 0.15})
minetest.check_for_falling(p)
elseif math.random(0,3) >= 1 then
if nn == "air" then
minetest.set_node(p, {name="air"})
minetest.check_for_falling(p)
end
end
end
end
end
end
local function extinguish(player)
--local t1 = os.clock()
local playerpos = player:get_pos()
local dir = player:get_look_dir()
local startpos = vector.new(playerpos)
startpos.y = startpos.y+1.625
local bl, pos = minetest.line_of_sight(startpos,
vector.add(vector.multiply(dir, range), startpos), 1)
local snd = minetest.sound_play("extinguisher",
{pos = playerpos, gain = 0.5, max_hear_distance = range})
local flight_time = 1
if pos then
local s = math.max(vector.distance(startpos, pos)-0.5, 0)
flight_time = (math.sqrt(v * v + 2 * a * s) - v) / a
end
if not bl then
minetest.after(flight_time, function()
-- Extinguish the node
minetest.sound_stop(snd)
spray_foam(vector.round(pos))
end)
end
minetest.add_particle({
pos = startpos,
velocity = vector.multiply(dir, v),
acceleration = vector.multiply(dir, a),
expirationtime = flight_time,
size = 1,
texture = "extinguisher_shot.png^[transform" .. math.random(0,7),
})
--print("[extinguisher] my shot was calculated after "..tostring(os.clock()-t1).."s")
end
--[[
local function table_empty(t)
for _,_ in pairs(t) do
return false
end
return true
end
local function get_tab(pos)
local tab_tmp = {pos}
local tab_avoid = {[pos.x.." "..pos.y.." "..pos.z] = true}
local tab_done,num = {pos},2
while not table_empty(tab_tmp) do
for n,p in pairs(tab_tmp) do
tab_tmp[n] = nil
for z = -2,2 do
for y = -2,2 do
for x = -2,2 do
local p2 = {x=pos.x+x, y=pos.y+y, z=pos.z+z}
local pstr = p2.x.." "..p2.y.." "..p2.z
if not tab_avoid[pstr]
and minetest.get_node(p2).name == "fire:basic_flame" then
tab_avoid[pstr] = true
tab_done[num] = p2
num = num+1
table.insert(tab_tmp, p2)
end
end
end
end
end
end
return tab_done
end]]
local function stop_all_fire_sounds()
local players = minetest.get_connected_players()
for i = 1, #players do
fire.update_player_sound(players[i])
end
end
local c_fire, c_foam, c_lava, c_lavaf, c_obsidian, c_cobble
local function extinguish_fire(pos)
local t1 = os.clock()
c_fire = c_fire or minetest.get_content_id("fire:basic_flame")
c_fire1 = c_fire1 or minetest.get_content_id("fire:permanent_flame")
c_foam = c_foam or minetest.get_content_id("extinguisher:foam")
local tab = vector.explosion_table(40)
local manip = minetest.get_voxel_manip()
local emerged_pos1, emerged_pos2 = manip:read_from_map(vector.add(pos, -40),
vector.add(pos, 40))
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
local nodes = manip:get_data()
for _,i in pairs(tab) do
local ran = i[2]
if not ran
or math.random(2) == 1 then
local p = area:indexp(vector.add(pos, i[1]))
local d_p = nodes[p]
if d_p == c_fire then
nodes[p] = air;
elseif d_p == c_fire1 then
nodes[p] = air;
end
end
end
manip:set_data(nodes)
manip:write_to_map()
stop_all_fire_sounds()
print(string.format("[extinguisher] exploded at %s after ca. %.2fs",
minetest.pos_to_string(pos), os.clock() - t1))
--[[t1 = os.clock()
manip:update_map()
print(string.format("[extinguisher] map updated after ca. %.2fs", os.clock() - t1))]]
end
local function eexpl(pos)
if minetest.get_node(pos).name ~= "extinguisher:automatic" then
return
end
minetest.sound_play("extinguisher_explosion", {pos=pos})
minetest.set_node(pos, {name="extinguisher:destroyed"})
local startpos = minetest.find_node_near(pos, 2, {"fire:basic_flame"})
if not startpos then
return
end
extinguish_fire(startpos)
end
minetest.register_node(":extinguisher:foam", {
drawtype = "nodebox",
paramtype = "light",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
}
},
use_texture_alpha = "blend",
tiles = {"extinguisher_foam.png"},
drop = "",
groups = {dig_immediate=3, puts_out_fire=1, not_in_creative_inventory=1, falling_node=1},
})
local adtime = 0
local time = minetest.get_us_time()
local count = 0
minetest.register_abm({
nodenames = {"extinguisher:foam"},
interval = 5,
chance = 5,
catch_up = false,
action = function(pos)
count = count+1
local ct = minetest.get_us_time()
if count > 10
and ct-time < 1000000 then
return
end
time = ct
count = 0
minetest.remove_node(pos)
if adtime < 0.1 then
minetest.check_for_falling(pos)
end
end,
})
minetest.register_node(":extinguisher:automatic", {
description = "Extinguisher",
tiles = {"extinguisher_top.png", "extinguisher_bottom.png",
"extinguisher.png", "extinguisher.png^[transformFX",
"extinguisher_front.png", "extinguisher_back.png"},
use_texture_alpha = "opaque",
inventory_image = "extinguisher.png",
wield_image = "extinguisher_pipe.png",
paramtype = "light",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
-- Main bottle
{-2/16, -0.5, -5/16, 3/16, 0, 0},
{-1/16, 0, -5/16, 2/16, 3/16, 0},
{-2/16, 0, -4/16, 3/16, 3/16, -1/16},
{-1/16, 3/16, -4/16, 2/16, 5/16, -1/16},
{0, 5/16, -3/16, 1/16, 6/16, -2/16},
-- Outlet
{0, 3/16, -1/16, 1/16, 4/16, 2/16},
{-1/16, 3/16, 2/16, 0, 4/16, 4/16},
{1/16, 3/16, 2/16, 2/16, 4/16, 4/16},
{0, 4/16, 2/16, 1/16, 5/16, 6/16},
{0, 2/16, 2/16, 1/16, 3/16, 6/16},
-- Handle
{0, 6/16, -6/16, 1/16, 7/16, -1/16},
{-1/16, 6/16, -3/16, 2/16, 7/16, -2/16},
{0, 5/16, -7/16, 1/16, 6/16, -5/16},
{0, 4/16, -7/16, 1/16, 5/16, -6/16},
},
},
groups = {dig_immediate=2},
sounds = {dig=""},
on_punch = function(pos, _, player)
minetest.sound_play("extinguisher_touch", {pos=pos, gain=0.25, max_hear_distance=8})
if player:get_wielded_item():get_name() == "main:torch" then
minetest.after(math.random()*5, eexpl, pos)
end
end,
on_use = function() -- do not dig or punch nodes
end,
})
minetest.register_node(":extinguisher:destroyed", {
description = "Destroyed Extinguisher",
tiles = {"extinguisher_top.png", "extinguisher_bottom.png",
"extinguisher.png", "extinguisher.png^[transformFX",
"extinguisher_front.png", "extinguisher_destroyed.png"},
use_texture_alpha = "opaque",
inventory_image = "extinguisher.png",
wield_image = "extinguisher_pipe.png",
paramtype = "light",
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
-- Main bottle
{-2/16, -0.5, -3/16, 3/16, 0, 0},
{-1/16, 0, -5/16, 1/16, 3/16, 0},
{-1/16, 0, -4/16, 3/16, 3/16, -1/16},
{-1/16, -3/16, -4/16, 2/16, 4/16, -1/16},
},
},
groups = {dig_immediate=2},
sounds = {dig=""},
on_punch = function(pos, _, player)
minetest.sound_play("extinguisher_touch", {pos=pos, gain=0.25, max_hear_distance=8})
if player:get_wielded_item():get_name() == "main:torch" then
minetest.after(math.random()*5, eexpl, pos)
end
end,
on_use = function() -- do not dig or punch nodes
end,
})
local timer = 0
minetest.register_globalstep(function(dtime)
adtime = dtime
timer = timer+dtime
if timer < speed then
return
end
timer = 0
for _,player in pairs(minetest.get_connected_players()) do
if player:get_wielded_item():get_name() == "extinguisher:automatic"
and player:get_player_control().LMB then
extinguish(player)
end
end
end)