diff --git a/etc/Mods,WIP/mock_tnt/init.lua b/etc/Mods,WIP/mock_tnt/init.lua index 7bc9455..4f96fd7 100644 --- a/etc/Mods,WIP/mock_tnt/init.lua +++ b/etc/Mods,WIP/mock_tnt/init.lua @@ -7,6 +7,26 @@ if enable_tnt == nil then enable_tnt = minetest.is_singleplayer() end +local loss_prob = {} + +loss_prob["default:cobble"] = 3 +loss_prob["default:dirt"] = 4 + +local tnt_radius = tonumber(minetest.setting_get("tnt_radius") or 3) +-- Fill a list with data for content IDs, after all nodes are registered +local cid_data = {} +minetest.after(0, function() + for name, def in pairs(minetest.registered_nodes) do + cid_data[minetest.get_content_id(name)] = { + name = name, + drops = def.drops, + flammable = def.groups.flammable, + on_blast = def.on_blast, + } + end +end) + + local function notify(name, retcode) if(retcode == false) then minetest.chat_send_player(name, "You did not suffer any ill effects.") @@ -30,7 +50,6 @@ local function apply_flashbang_debuffs(player) end end -local tnt_radius = tonumber(minetest.setting_get("tnt_radius") or 3) local function rand_pos(center, pos, radius) local def @@ -49,41 +68,128 @@ local function rand_pos(center, pos, radius) until def and not def.walkable end +local function eject_drops(drops, pos, radius) + local drop_pos = vector.new(pos) + for _, item in pairs(drops) do + local count = math.min(item:get_count(), item:get_stack_max()) + while count > 0 do + local take = math.max(1,math.min(radius * radius, + count, + item:get_stack_max())) + rand_pos(pos, drop_pos, radius) + local dropitem = ItemStack(item) + dropitem:set_count(take) + local obj = minetest.add_item(drop_pos, dropitem) + if obj then + obj:get_luaentity().collect = true + obj:setacceleration({x = 0, y = -10, z = 0}) + obj:setvelocity({x = math.random(-3, 3), + y = math.random(0, 10), + z = math.random(-3, 3)}) + end + count = count - take + end + end +end --- minetest.register_node( "mock_tnt:mock_tnt", { --- description = "Unknown Explosive", --- tiles = { "mock_tnt_top.png", "mock_tnt_sides.png", "mock_tnt_sides.png", "mock_tnt_sides.png", "mock_tnt_sides.png", "mock_tnt_sides.png" }, --- is_ground_content = true, --- groups = {cracky = 1, level = 2}, --- sounds = default.node_sound_sand_defaults(), --- }) +local function add_drop(drops, item) + item = ItemStack(item) + local name = item:get_name() + if loss_prob[name] ~= nil and math.random(1, loss_prob[name]) == 1 then + return + end + local drop = drops[name] + if drop == nil then + drops[name] = item + else + drop:set_count(drop:get_count() + item:get_count()) + end +end --- Only when "not" to not overlap tnt mod: -if not enable_tnt then - minetest.register_alias("tnt:tnt", "mock_tnt:mock_tnt") - minetest.register_craft({ - output = "mock_tnt:mock_tnt", - recipe = { - {"group:wood", "tnt:gunpowder", "group:wood"}, - {"tnt:gunpowder", "tnt:gunpowder", "tnt:gunpowder"}, - {"group:wood", "tnt:gunpowder", "group:wood"} - } - }) +local function calc_velocity(pos1, pos2, old_vel, power) + -- Avoid errors caused by a vector of zero length + if vector.equals(pos1, pos2) then + return old_vel + end - minetest.register_abm({ - label = "mock_tnt ignition", - nodenames = {"group:tnt", "tnt:gunpowder"}, - neighbors = {"fire:basic_flame", "default:lava_source", "default:lava_flowing", "default:torch", "fire:permanent_flame"}, - interval = 4, - chance = 1, - action = function(pos, node) - mock_tnt.burn(pos, node.name) - end, + local vel = vector.direction(pos1, pos2) + vel = vector.normalize(vel) + vel = vector.multiply(vel, power) + + -- Divide by distance + local dist = vector.distance(pos1, pos2) + dist = math.max(dist, 1) + vel = vector.divide(vel, dist) + + -- Add old velocity + vel = vector.add(vel, old_vel) + + -- randomize it a bit + vel = vector.add(vel, { + x = math.random() - 0.5, + y = math.random() - 0.5, + z = math.random() - 0.5, }) + + -- Limit to terminal velocity + dist = vector.length(vel) + if dist > 250 then + vel = vector.divide(vel, dist / 250) + end + return vel end +local function entity_physics(pos, radius, drops) + local objs = minetest.get_objects_inside_radius(pos, radius) + for _, obj in pairs(objs) do + local obj_pos = obj:getpos() + local dist = math.max(1, vector.distance(pos, obj_pos)) + + local damage = (4 / dist) * radius + if obj:is_player() then + -- currently the engine has no method to set + -- player velocity. See #2960 + -- instead, we knock the player back 1.0 node, and slightly upwards + local dir = vector.normalize(vector.subtract(obj_pos, pos)) + local moveoff = vector.multiply(dir, dist + 1.0) + local newpos = vector.add(pos, moveoff) + newpos = vector.add(newpos, {x = 0, y = 0.2, z = 0}) + obj:setpos(newpos) + + obj:set_hp(obj:get_hp() - damage) + else + local do_damage = true + local do_knockback = true + local entity_drops = {} + local luaobj = obj:get_luaentity() + local objdef = minetest.registered_entities[luaobj.name] + + if objdef and objdef.on_blast then + do_damage, do_knockback, entity_drops = objdef.on_blast(luaobj, damage) + end + + if do_knockback then + local obj_vel = obj:getvelocity() + obj:setvelocity(calc_velocity(pos, obj_pos, + obj_vel, radius * 10)) + end + if do_damage then + if not obj:get_armor_groups().immortal then + obj:punch(obj, 1.0, { + full_punch_interval = 1.0, + damage_groups = {fleshy = damage}, + }, nil) + end + end + for _, item in pairs(entity_drops) do + add_drop(drops, item) + end + end + end +end + local function add_effects(pos, radius, drops) minetest.add_particle({ pos = pos, @@ -259,79 +365,6 @@ local function UNUSED_mock_tnt_explode(pos, radius, ignore_protection, ignore_on return drops, radius end -local function eject_drops(drops, pos, radius) - local drop_pos = vector.new(pos) - for _, item in pairs(drops) do - local count = math.min(item:get_count(), item:get_stack_max()) - while count > 0 do - local take = math.max(1,math.min(radius * radius, - count, - item:get_stack_max())) - rand_pos(pos, drop_pos, radius) - local dropitem = ItemStack(item) - dropitem:set_count(take) - local obj = minetest.add_item(drop_pos, dropitem) - if obj then - obj:get_luaentity().collect = true - obj:setacceleration({x = 0, y = -10, z = 0}) - obj:setvelocity({x = math.random(-3, 3), - y = math.random(0, 10), - z = math.random(-3, 3)}) - end - count = count - take - end - end -end - -local function entity_physics(pos, radius, drops) - local objs = minetest.get_objects_inside_radius(pos, radius) - for _, obj in pairs(objs) do - local obj_pos = obj:getpos() - local dist = math.max(1, vector.distance(pos, obj_pos)) - - local damage = (4 / dist) * radius - if obj:is_player() then - -- currently the engine has no method to set - -- player velocity. See #2960 - -- instead, we knock the player back 1.0 node, and slightly upwards - local dir = vector.normalize(vector.subtract(obj_pos, pos)) - local moveoff = vector.multiply(dir, dist + 1.0) - local newpos = vector.add(pos, moveoff) - newpos = vector.add(newpos, {x = 0, y = 0.2, z = 0}) - obj:setpos(newpos) - - obj:set_hp(obj:get_hp() - damage) - else - local do_damage = true - local do_knockback = true - local entity_drops = {} - local luaobj = obj:get_luaentity() - local objdef = minetest.registered_entities[luaobj.name] - - if objdef and objdef.on_blast then - do_damage, do_knockback, entity_drops = objdef.on_blast(luaobj, damage) - end - - if do_knockback then - local obj_vel = obj:getvelocity() - obj:setvelocity(calc_velocity(pos, obj_pos, - obj_vel, radius * 10)) - end - if do_damage then - if not obj:get_armor_groups().immortal then - obj:punch(obj, 1.0, { - full_punch_interval = 1.0, - damage_groups = {fleshy = damage}, - }, nil) - end - end - for _, item in pairs(entity_drops) do - add_drop(drops, item) - end - end - end -end - function mock_tnt.boom(pos, def) minetest.sound_play("tnt_explode", {pos = pos, gain = 1.5, max_hear_distance = 2*64}) @@ -392,6 +425,8 @@ function mock_tnt.register_tnt(def) local tnt_bottom = def.tiles.bottom or def.name .. "_bottom.png" local tnt_side = def.tiles.side or def.name .. "_side.png" local tnt_burning = def.tiles.burning or def.name .. "_top_burning_animated.png" + local all_tiles = { tnt_top, tnt_bottom, tnt_side } + if def.all_tiles then all_tiles = def.all_tiles end if not def.damage_radius then def.damage_radius = def.radius * 2 end -- if "not" since only make fake if real does not exist: @@ -399,7 +434,7 @@ function mock_tnt.register_tnt(def) -- if not enable_tnt then minetest.register_node(":" .. name, { description = def.description, - tiles = { tnt_top, tnt_bottom, tnt_side }, + tiles = all_tiles, is_ground_content = false, groups = {dig_immediate = 2, mesecon = 2, tnt = 1, flammable = 5}, sounds = default.node_sound_sand_defaults(), @@ -459,12 +494,48 @@ function mock_tnt.register_tnt(def) }) end + +-- minetest.register_node( "mock_tnt:mock_tnt", { +-- description = "Unknown Explosive", +-- tiles = { "mock_tnt_top.png", "mock_tnt_sides.png", "mock_tnt_sides.png", "mock_tnt_sides.png", "mock_tnt_sides.png", "mock_tnt_sides.png" }, +-- is_ground_content = true, +-- groups = {cracky = 1, level = 2}, +-- sounds = default.node_sound_sand_defaults(), +-- }) + mock_tnt.register_tnt({ name = "mock_tnt:mock_tnt", description = "Unknown Explosive", radius = tnt_radius, + -- all_tiles = { "mock_tnt_top.png", "mock_tnt_bottom.png", "mock_tnt_side-blank.png", "mock_tnt_side-blank.png", "mock_tnt_side.png", "mock_tnt_side.png" }, + -- could also be top,bottom,east,east,north,north + -- or top,bottom,side }) +-- Only when "not" to not overlap tnt mod: +if not enable_tnt then + minetest.register_alias("tnt:tnt", "mock_tnt:mock_tnt") + minetest.register_craft({ + output = "mock_tnt:mock_tnt", + recipe = { + {"group:wood", "tnt:gunpowder", "group:wood"}, + {"tnt:gunpowder", "tnt:gunpowder", "tnt:gunpowder"}, + {"group:wood", "tnt:gunpowder", "group:wood"} + } + }) + + minetest.register_abm({ + label = "mock_tnt ignition", + nodenames = {"group:tnt", "tnt:gunpowder"}, + neighbors = {"fire:basic_flame", "default:lava_source", "default:lava_flowing", "default:torch", "fire:permanent_flame"}, + interval = 4, + chance = 1, + action = function(pos, node) + mock_tnt.burn(pos, node.name) + end, + }) +end + -- ALREADY DONE by minetest_game tnt mod even if tnt_enable is false: