302 lines
7.8 KiB
Lua
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)
|
|
|
|
|
|
|
|
|
|
|