diff --git a/mods/ENTITIES/mcl_burning/init.lua b/mods/ENTITIES/mcl_burning/init.lua index daaf6d9e..259346bd 100644 --- a/mods/ENTITIES/mcl_burning/init.lua +++ b/mods/ENTITIES/mcl_burning/init.lua @@ -1,13 +1,34 @@ -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, - }) +mcl_burning = {} + +function mcl_burning.get_default(datatype) + local default_table = {string = "", float = 0.0, int = 0, bool = false} + return default_table[datatype] +end + +function mcl_burning.get(obj, datatype, name) + local key + if obj:is_player() then + local meta = obj:get_meta() + return meta["get_" .. datatype](meta, "mcl_burning:" .. name) + else + local luaentity = obj:get_luaentity() + return luaentity["mcl_burning_" .. name] or mcl_burning.get_default(datatype) + end +end + +function mcl_burning.set(obj, datatype, name, value) + if obj:is_player() then + local meta = obj:get_meta() + meta["set_" .. datatype](meta, "mcl_burning:" .. name, value or mcl_burning.get_default(datatype)) + else + local luaentity = obj:get_luaentity() + if mcl_burning.get_default(datatype) == value then + value = nil + end + luaentity["mcl_burning_" .. name] = value + end end function mcl_burning.get_collisionbox(obj) @@ -23,168 +44,166 @@ function mcl_burning.is_touching_nodes(obj, 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.damage(obj) + local luaentity = obj:get_luaentity() + local health -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 + if luaentity then + health = luaentity.health end + + local hp = health or obj:get_hp() + 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 obj: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)) + local deathmsg = S("@1 burned to death.", name) + local reason = mcl_burning.get(obj, "string", "reason") + if reason ~= "" then + deathmsg = S("@1 was burned by @2.", name, reason) + end + mcl_death_messages.player_damage(obj, deathmsg) + end + else + if luaentity.fire_damage_resistant then + do_damage = false end end + if do_damage then - if is_player then - obj:set_hp(hp - 1) - else - meta.health = hp - 1 + local damage = mcl_burning.get(obj, "float", "damage") + if damage == 0 then + damage = 1 + end + local new_hp = hp - damage + obj:set_hp(new_hp) + if health then + luaentity.health = new_hp end end end -local etime = 0 +function mcl_burning.set_on_fire(obj, burn_time, damage, reason) + local luaentity = obj:get_luaentity() + if luaentity and luaentity.fire_resistant then + return + end -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) + local old_burn_time = mcl_burning.get(obj, "float", "burn_time") + local max_fire_prot_lvl = 0 + + if obj:is_player() then + local inv = obj:get_inventory() + + for i = 2, 5 do + local stack = inv:get_stack("armor", i) + + local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection") + max_fire_prot_lvl = math.max(max_fire_prot_lvl, fire_prot_lvl) end - mcl_burning.set_burning(obj, burn_time, old_burn_time, meta, is_player) end - if burn_time > 0 then + + if max_fire_prot_lvl > 0 then + burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15) + end + + if old_burn_time <= burn_time then + mcl_burning.set(obj, "float", "burn_time", burn_time) + mcl_burning.set(obj, "float", "damage", damage or 0) + mcl_burning.set(obj, "string", "reason", reason or "") + + end +end + +function mcl_burning.extinguish(obj) + local old_burn_time = mcl_burning.get(obj, "float", "burn_time") + + if old_burn_time > 0 then + minetest.sound_play("fire_extinguish_flame", { + object = obj, + gain = 0.18, + max_hear_distance = 32, + }) + + mcl_burning.delete_particlespawner(obj) + + mcl_burning.set(obj, "float", "damage") + mcl_burning.set(obj, "string", "reason") + mcl_burning.set(obj, "float", "burn_time") + mcl_burning.set(obj, "float", "damage_timer") + end +end + +function mcl_burning.catch_fire_tick(obj, dtime) + local lava_nodes = {"mcl_core:lava_source", "mcl_core:lava_flowing"} + local fire_nodes = {"mcl_fire:fire", "mcl_fire:eternal_fire"} + local water_nodes = {"mcl_core:water_source", "mcl_core:water_flowing"} + + if mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos()) or mcl_burning.is_touching_nodes(obj, water_nodes) then + mcl_burning.extinguish(obj) + elseif mcl_burning.is_touching_nodes(obj, lava_nodes) then + mcl_burning.set_on_fire(obj, 15) + elseif mcl_burning.is_touching_nodes(obj, fire_nodes) then + mcl_burning.set_on_fire(obj, 8) + end +end + +function mcl_burning.tick(obj, dtime) + local burn_time = mcl_burning.get(obj, "float", "burn_time") - dtime + + if burn_time <= 0 then + mcl_burning.extinguish(obj) + else + mcl_burning.set(obj, "float", "burn_time", burn_time) + if math.random() < dtime then - mcl_burning.play_sound(obj, "fire_fire") + minetest.sound_play("fire_fire", { + object = obj, + gain = 0.18, + max_hear_distance = 32, + }) end - if etime > 1 then - mcl_burning.damage(obj, meta, is_player) + + local damage_timer = mcl_burning.get(obj, "float", "damage_timer") + dtime + + if damage_timer >= 1 then + damage_timer = 0 + mcl_burning.damage(obj) end + + mcl_burning.set(obj, "float", "damage_timer", damage_timer) end + + mcl_burning.catch_fire_tick(obj, dtime) 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) + mcl_burning.tick(player, dtime) end end) minetest.register_on_respawnplayer(function(player) - mcl_burning.set_burning(player, 0) + mcl_burning.extinguish(player) end) minetest.register_chatcommand("burn", { func = function(name, param) local player = minetest.get_player_by_name(name) - local burn_time = tonumber(param) or 5 + local sparam = param:split(" ") + local burn_time = tonumber(sparam[1]) or 5 + local damage = tonumber(sparam[2]) or 5 if player then - mcl_burning.set_burning(player, burn_time) + mcl_burning.set_on_fire(player, burn_time, damage) end end }) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 15232c24..fdf36a21 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -3360,7 +3360,7 @@ end local mob_step = function(self, dtime) if not self.fire_resistant then - mcl_burning.step(self.object, dtime) + mcl_burning.tick(self.object, dtime) end if use_cmi then @@ -3790,6 +3790,7 @@ minetest.register_entity(name, { follow_velocity = def.follow_velocity or 2.4, instant_death = def.instant_death or false, fire_resistant = def.fire_resistant or false, + fire_damage_resistant = def.fire_damage_resistant or false, -- End of MCL2 extensions on_spawn = def.on_spawn, diff --git a/mods/ENTITIES/mobs_mc/zombiepig.lua b/mods/ENTITIES/mobs_mc/zombiepig.lua index 08e82f62..89649c4a 100644 --- a/mods/ENTITIES/mobs_mc/zombiepig.lua +++ b/mods/ENTITIES/mobs_mc/zombiepig.lua @@ -86,7 +86,7 @@ local pigman = { fear_height = 4, view_range = 16, harmed_by_heal = true, - fire_resistant = true, + fire_damage_resistant = true, } mobs:register_mob("mobs_mc:pigman", pigman)