MineClone2/mods/ENTITIES/mcl_burning/init.lua

191 lines
5.3 KiB
Lua

mcl_burning = {}
local S = minetest.get_translator("mcl_burning")
function mcl_burning.play_sound(obj, soundname)
minetest.sound_play(soundname, {
object = obj,
gain = 0.18,
max_hear_distance = 32,
})
end
function mcl_burning.get_collisionbox(obj)
local box = obj:get_properties().collisionbox
return vector.new(box[1], box[2], box[3]), vector.new(box[4], box[5], box[6])
end
function mcl_burning.is_touching_nodes(obj, nodes)
local pos = obj:get_pos()
local box = obj:get_properties().collisionbox
local minp, maxp = mcl_burning.get_collisionbox(obj)
local nodes = minetest.find_nodes_in_area(vector.add(pos, minp), vector.add(pos, maxp), nodes)
return #nodes > 0
end
function mcl_burning.create_particlespawner(obj, burn_time, old_burn_time, old_spawner)
local new_spawner
if old_spawner == 0 then
old_spawner = nil
end
local delete_old_spawner = false
if burn_time and (not old_spawner or burn_time >= old_burn_time) then
delete_old_spawner = true
local minp, maxp = mcl_burning.get_collisionbox(obj)
new_spawner = minetest.add_particlespawner({
amount = 1000 * burn_time,
time = burn_time,
minpos = minp,
maxpos = maxp,
minvel = {x = -0.5, y = 1, z = -0.5},
maxvel = {x = 0.5, y = 2, z = -0.5},
minacc = {x = -0.1, y = 8, z = -0.1},
maxacc = {x = 0.1, y = 10, z = 0.1},
minexptime = 0.2,
maxexptime = 0.3,
minsize = 1,
maxsize = 2,
collisiondetection = true,
texture = "fire_basic_flame.png",
attached = obj,
})
elseif not burn_time and old_spawner then
delete_old_spawner = true
end
if delete_old_spawner and old_spawner then
minetest.delete_particlespawner(old_spawner)
old_spawner = nil
end
return new_spawner or old_spawner
end
function mcl_burning.analyse(obj, meta, is_player)
if meta then
return meta, is_player
end
is_player = obj:is_player()
if is_player then
meta = obj:get_meta()
else
meta = obj:get_luaentity()
end
return meta, is_player
end
function mcl_burning.set_burning(obj, burn_time, old_burn_time, meta, is_player)
meta, is_player = mcl_burning.analyse(obj, meta, is_player)
old_burn_time = old_burn_time or mcl_burning.get_burning(obj, meta, is_player)
if burn_time <= 0 then
burn_time = nil
end
if is_player then
if burn_time then
meta:set_float("mcl_burning:burn_time", burn_time)
elseif old_burn_time > 0 then
meta:set_string("mcl_burning:burn_time", "")
mcl_burning.play_sound(obj, "fire_extinguish_flame")
end
local fire_spawner = mcl_burning.create_particlespawner(obj, burn_time, old_burn_time, meta:get_int("mcl_burning:fire_spawner"))
if fire_spawner then
meta:set_int("mcl_burning:fire_spawner", fire_spawner)
else
meta:set_string("mcl_burning:fire_spawner", "")
end
elseif not meta._fire_resistant then
meta._burn_time = burn_time
meta._fire_spawner = mcl_burning.create_particlespawner(obj, burn_time, old_burn_time, meta._fire_spawner)
if not burn_time and old_burn_time > 0 then
mcl_burning.play_sound(obj, "fire_extinguish_flame")
end
end
end
function mcl_burning.get_burning(obj, meta, is_player)
meta, is_player = mcl_burning.analyse(obj, meta, is_player)
if is_player then
return meta:get_float("mcl_burning:burn_time")
else
return meta._burn_time or 0
end
end
function mcl_burning.damage(obj, meta, is_player)
local hp
if is_player then
hp = obj:get_hp()
else
hp = meta.health or 0
end
if hp <= 0 then
return
end
meta, is_player = mcl_burning.analyse(obj, meta, is_player)
local do_damage = true
if is_player then
if mcl_potions.player_has_effect(obj, "fire_proof") then
do_damage = false
else
local name = obj:get_player_name()
armor.last_damage_types[name] = "fire"
mcl_death_messages.player_damage(obj, S("@1 burned to a crisp.", name))
end
end
if do_damage then
if is_player then
obj:set_hp(hp - 1)
else
meta.health = hp - 1
end
end
end
local etime = 0
function mcl_burning.step(obj, dtime)
local burn_time, old_burn_time, meta, is_player
meta, is_player = mcl_burning.analyse(obj)
old_burn_time = mcl_burning.get_burning(obj, meta, is_player)
burn_time = old_burn_time - dtime
if burn_time < 5 and mcl_burning.is_touching_nodes(obj, {"mcl_fire:fire", "mcl_fire:eternal_fire", "mcl_core:lava_source", "mcl_core:lava_flowing"}) then
burn_time = 5
end
if burn_time > 0 or old_burn_time > 0 then
if mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos()) or mcl_burning.is_touching_nodes(obj, {"mcl_core:water_source", "mcl_core:water_flowing"}) then
burn_time = math.min(burn_time, 0.25)
end
mcl_burning.set_burning(obj, burn_time, old_burn_time, meta, is_player)
end
if burn_time > 0 then
if math.random() < dtime then
mcl_burning.play_sound(obj, "fire_fire")
end
if etime > 1 then
mcl_burning.damage(obj, meta, is_player)
end
end
end
minetest.register_globalstep(function(dtime)
if etime > 1 then
etime = 0
end
etime = etime + dtime
for _, player in ipairs(minetest.get_connected_players()) do
mcl_burning.step(player, dtime)
end
end)
minetest.register_on_respawnplayer(function(player)
mcl_burning.set_burning(player, 0)
end)
minetest.register_chatcommand("burn", {
func = function(name, param)
local player = minetest.get_player_by_name(name)
local burn_time = tonumber(param) or 5
if player then
mcl_burning.set_burning(player, burn_time)
end
end
})