diff --git a/mods/ctf/ctf_landmine/init.lua b/mods/ctf/ctf_landmine/init.lua new file mode 100644 index 0000000000..d6be751615 --- /dev/null +++ b/mods/ctf/ctf_landmine/init.lua @@ -0,0 +1,202 @@ +local landmines = { + -- core.hash_node_position(pos) -> true/false + -- like landmines[core.hash_node_position(pos)] = true +} + +local number_of_landmines = 0 + +local add_landmine = function(pos) + landmines[core.hash_node_position(pos)] = true + number_of_landmines = number_of_landmines + 1 +end + +local clear_landmines = function() + landmines = {} + number_of_landmines = 0 +end + +local remove_landmine = function(pos) + landmines[core.hash_node_position(pos)] = false + number_of_landmines = number_of_landmines - 1 +end + +local landmine_globalstep_counter = 0.0 +local LANDMINE_COUNTER_THRESHOLD = 0.025 + +local function is_self_landmine(object_ref, pos) + local meta = core.get_meta(pos) + local team = meta:get_string("pteam") + local placer = meta:get_string("placer") + local pname = object_ref:get_player_name() + if pname == "" then + return nil -- the object ref is not a player + end + if pname == placer then + return true -- it's self landmine + end + if ctf_teams.get(object_ref) == team then + return true -- it's self landmine + end + + return false -- it's someone else's landmine +end + +local function landmine_explode(pos) + local near_objs = core.get_objects_inside_radius(pos, 3) + local meta = core.get_meta(pos) + local placer = meta:get_string("placer") + local placerobj = placer and core.get_player_by_name(placer) + + core.add_particlespawner({ + amount = 20, + time = 0.5, + minpos = vector.subtract(pos, 3), + maxpos = vector.add(pos, 3), + minvel = {x = 0, y = 5, z = 0}, + maxvel = {x = 0, y = 7, z = 0}, + minacc = {x = 0, y = 1, z = 0}, + maxacc = {x = 0, y = 1, z = 0}, + minexptime = 0.3, + maxexptime = 0.6, + minsize = 7, + maxsize = 10, + collisiondetection = true, + collision_removal = false, + vertical = false, + texture = "grenades_smoke.png", + }) + + core.add_particle({ + pos = pos, + velocity = {x=0, y=0, z=0}, + acceleration = {x=0, y=0, z=0}, + expirationtime = 0.3, + size = 15, + collisiondetection = false, + collision_removal = false, + object_collision = false, + vertical = false, + texture = "grenades_boom.png", + glow = 10 + }) + + core.sound_play("grenades_explode", { + pos = pos, + gain = 1.0, + max_hear_distance = 64, + }) + + for _, obj in pairs(near_objs) do + if is_self_landmine(obj, pos) == false then + if placerobj then + obj:punch( + placerobj, + 1, + { + damage_groups = { + fleshy = 15, + landmine = 1 + } + } + ) + else + local chp = obj:get_hp() + obj:set_hp(chp - 15) + end + end + end + core.remove_node(pos) + remove_landmine(pos) +end + +core.register_node("ctf_landmine:landmine", { + description = "Landmine", + drawtype = "nodebox", + tiles = { + "ctf_landmine_landmine.png", + "ctf_landmine_landmine.png^[transformFY" + }, + inventory_image = "ctf_landmine_landmine.png", + paramtype = "light", + sunlight_propagates = true, + walkable = true, + groups = {cracky=1, level=2}, + node_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -0.4, 0.5}, + }, + selection_box = { + type = "fixed", + fixed = {-0.5, -0.5, -0.5, 0.5, -0.4, 0.5}, + }, + after_place_node = function(pos, placer, itemstack, pointed_thing) + local meta = core.get_meta(pos) + local name = placer:get_player_name() + local pteam = ctf_teams.get(placer) + + meta:set_string("placer", name) + meta:set_string("pteam", pteam) + add_landmine(pos) + end, + on_punch = function(pos, _node, puncher, pointed_thing) + if not is_self_landmine(puncher, pos) then + landmine_explode(pos) + end + end +}) + + + + +core.register_globalstep(function(dtime) + landmine_globalstep_counter = landmine_globalstep_counter + dtime + if landmine_globalstep_counter < LANDMINE_COUNTER_THRESHOLD then + return + end + landmine_globalstep_counter = 0.0 + if number_of_landmines == 0 then + return + end + local start_time = core.get_gametime() + local players_n = #core.get_connected_players() + local landmines_n = number_of_landmines + for _idx, obj in ipairs(core.get_connected_players()) do + local pos = { + x = math.ceil(obj:get_pos().x), + y = math.ceil(obj:get_pos().y), + z = math.ceil(obj:get_pos().z) + } + local positions_to_check = { + pos, + vector.add(pos, { x = 0, y = 0, z = 1}), + vector.add(pos, { x = 1, y = 0, z = 0}), + vector.add(pos, { x = 0, y = 0, z = -1}), + vector.add(pos, { x = -1, y = 0, z = 0}), + vector.add(pos, { x = 0, y = 1, z = 0}), + } + local landmine_positions = {} + for _idx2, pos2 in ipairs(positions_to_check) do + if landmines[core.hash_node_position(pos2)] then + table.insert(landmine_positions, pos2) + end + end + -- explode them! + for _idx2, pos2 in ipairs(landmine_positions) do + if not is_self_landmine(obj, pos2) then + landmine_explode(pos2) + end + end + end + core.debug( + string.format( + "[CTF Landmine] Used %f of server time for %d landmines and %d players", + core.get_gametime() - start_time, + landmines_n, + players_n + ) + ) +end) + +ctf_api.register_on_match_end(function() + clear_landmines() +end) diff --git a/mods/ctf/ctf_landmine/mod.conf b/mods/ctf/ctf_landmine/mod.conf new file mode 100644 index 0000000000..029b88b3e2 --- /dev/null +++ b/mods/ctf/ctf_landmine/mod.conf @@ -0,0 +1,2 @@ +name = ctf_landmine +depends = ctf_teams, grenades, default, ctf_api diff --git a/mods/ctf/ctf_landmine/textures/ctf_landmine_landmine.png b/mods/ctf/ctf_landmine/textures/ctf_landmine_landmine.png new file mode 100644 index 0000000000..7a5540b954 Binary files /dev/null and b/mods/ctf/ctf_landmine/textures/ctf_landmine_landmine.png differ diff --git a/mods/ctf/ctf_modebase/crafting.lua b/mods/ctf/ctf_modebase/crafting.lua index 92483dc184..253993a467 100644 --- a/mods/ctf/ctf_modebase/crafting.lua +++ b/mods/ctf/ctf_modebase/crafting.lua @@ -173,3 +173,9 @@ crafting.register_recipe({ items = { "default:cobble 6", "default:steel_ingot" }, always_known = false, }) + +crafting.register_recipe({ + output = "ctf_map:landmine", + items = { "default:steel_ingot 4", "grenades:frag" }, + always_known = false, +}) diff --git a/mods/ctf/ctf_modebase/features.lua b/mods/ctf/ctf_modebase/features.lua index e309070c42..acc03e1ef7 100644 --- a/mods/ctf/ctf_modebase/features.lua +++ b/mods/ctf/ctf_modebase/features.lua @@ -206,6 +206,7 @@ local damage_group_textures = { knockback_grenade = "ctf_mode_nade_fight_knockback_grenade.png", black_hole_grenade = "ctf_mode_nade_fight_black_hole_grenade.png", damage_cobble = "ctf_map_damage_cobble.png", + landmine = "ctf_landmine_landmine.png", } local function get_weapon_image(hitter, tool_capabilities) diff --git a/mods/ctf/ctf_modes/ctf_mode_classes/init.lua b/mods/ctf/ctf_modes/ctf_mode_classes/init.lua index c449cb833a..2797343085 100644 --- a/mods/ctf/ctf_modes/ctf_mode_classes/init.lua +++ b/mods/ctf/ctf_modes/ctf_mode_classes/init.lua @@ -57,6 +57,7 @@ ctf_modebase.register_mode("classes", { ["ctf_map:spike" ] = {min_count = 1, max_count = 5, max_stacks = 2, rarity = 0.2}, ["ctf_map:damage_cobble" ] = {min_count = 5, max_count = 20, max_stacks = 2, rarity = 0.2}, ["ctf_map:reinforced_cobble"] = {min_count = 5, max_count = 25, max_stacks = 2, rarity = 0.2}, + ["ctf_map:landmine" ] = {min_count = 1, max_count = 5, max_stacks = 1, rarity = 0.2}, ["ctf_ranged:ammo" ] = {min_count = 3, max_count = 10, rarity = 0.3 , max_stacks = 2}, ["ctf_healing:medkit" ] = { rarity = 0.08 , max_stacks = 2}, @@ -67,7 +68,7 @@ ctf_modebase.register_mode("classes", { }, crafts = { "ctf_ranged:ammo", "default:axe_mese", "default:axe_diamond", "default:shovel_mese", "default:shovel_diamond", - "ctf_map:damage_cobble", "ctf_map:spike", "ctf_map:reinforced_cobble 2", + "ctf_map:damage_cobble", "ctf_map:spike", "ctf_map:reinforced_cobble 2", "ctf_map:landmine", }, physics = {sneak_glitch = true, new_move = true}, blacklisted_nodes = {"default:apple"}, diff --git a/mods/ctf/ctf_modes/ctf_mode_nade_fight/init.lua b/mods/ctf/ctf_modes/ctf_mode_nade_fight/init.lua index 2c913e0114..f34f57201a 100644 --- a/mods/ctf/ctf_modes/ctf_mode_nade_fight/init.lua +++ b/mods/ctf/ctf_modes/ctf_mode_nade_fight/init.lua @@ -39,6 +39,7 @@ ctf_modebase.register_mode("nade_fight", { ["ctf_map:spike" ] = {min_count = 1, max_count = 5, max_stacks = 3, rarity = 0.2}, ["ctf_map:damage_cobble" ] = {min_count = 5, max_count = 20, max_stacks = 2, rarity = 0.2}, ["ctf_map:reinforced_cobble"] = {min_count = 5, max_count = 25, max_stacks = 2, rarity = 0.2}, + ["ctf_map:landmine" ] = {min_count = 1, max_count = 3, max_stacks = 1, rarity = 0.2}, ["ctf_ranged:ammo" ] = {min_count = 3, max_count = 10, rarity = 0.3 , max_stacks = 2}, ["ctf_healing:medkit" ] = { rarity = 0.1 , max_stacks = 2}, @@ -51,6 +52,7 @@ ctf_modebase.register_mode("nade_fight", { "ctf_map:damage_cobble", "ctf_map:spike", "ctf_map:reinforced_cobble 2", + "ctf_map:landmine", }, physics = {sneak_glitch = true, new_move = true}, blacklisted_nodes = {"default:apple"},