diff --git a/.gitignore b/.gitignore index a2fb451..75ff29d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ tags *.vim debug.txt +mods/ctf_map/maps/*/ ## Files related to minetest development cycle *.patch diff --git a/minetest.conf b/minetest.conf index f280535..4dbbd8e 100644 --- a/minetest.conf +++ b/minetest.conf @@ -1,16 +1,12 @@ give_initial_stuff = true enable_pvp = true -fixed_map_seed = 13389864206935783704 -mg_name = v7 -mg_flags = nocaves,nodungeons,light,decorations +mg_name = singlenode map_generation_limit = 160 vote.kick_vote = false barrier = 106 regen_interval = 6 regen_amount = 1 random_messages_interval = 60 -water_level = 38 -sprint_stamina = 5 # # CTF_PVP_ENGINE diff --git a/mods/ctf_barrier/depends.txt b/mods/ctf_barrier/depends.txt deleted file mode 100644 index bce8197..0000000 --- a/mods/ctf_barrier/depends.txt +++ /dev/null @@ -1,3 +0,0 @@ -default -ctf -ctf_match diff --git a/mods/ctf_barrier/init.lua b/mods/ctf_barrier/init.lua deleted file mode 100644 index 7a45b5f..0000000 --- a/mods/ctf_barrier/init.lua +++ /dev/null @@ -1,236 +0,0 @@ -minetest.register_node("ctf_barrier:ind_glass", { - description = "You cheater you!", - drawtype = "glasslike_framed_optional", - tiles = {"default_glass.png", "default_glass_detail.png"}, - inventory_image = minetest.inventorycube("default_glass.png"), - paramtype = "light", - sunlight_propagates = true, - is_ground_content = false, - walkable = true, - buildable_to = false, - pointable = false, - groups = {immortal = 1}, - sounds = default.node_sound_glass_defaults() -}) - -minetest.register_node("ctf_barrier:ind_stone", { - description = "Cheater!", - groups = {immortal = 1}, - tiles = {"default_stone.png"}, - is_ground_content = false -}) - -minetest.register_node("ctf_barrier:ind_glass_red", { - description = "You cheater you!", - drawtype = "glasslike", - tiles = {"ctf_barrier_red.png"}, - inventory_image = minetest.inventorycube("default_glass.png"), - paramtype = "light", - sunlight_propagates = true, - is_ground_content = false, - walkable = true, - buildable_to = false, - use_texture_alpha = false, - alpha = 0, - pointable = false, - groups = {immortal = 1}, - sounds = default.node_sound_glass_defaults() -}) - -local c_stone = minetest.get_content_id("ctf_barrier:ind_stone") -local c_glass = minetest.get_content_id("ctf_barrier:ind_glass") -local c_glass_red = minetest.get_content_id("ctf_barrier:ind_glass_red") -local c_water = minetest.get_content_id("default:water_source") -local c_water_f = minetest.get_content_id("default:water_flowing") -local c_air = minetest.get_content_id("air") -local r = tonumber(minetest.setting_get("barrier")) -minetest.register_on_generated(function(minp, maxp, seed) - if not ((minp.x <= -r and maxp.x >= -r) - or (minp.x <= r and maxp.x >= r) - or (minp.y <= -r and maxp.x >= -r) - or (minp.y <= r and maxp.x >= r) - or (minp.z <= -r and maxp.z >= -r) - or (minp.z <= 0 and maxp.z >= 0) - or (minp.z <= r and maxp.z >= r and ctf_match.build_timer > 0)) then - return - end - - -- Set up voxel manip - local t1 = os.clock() - local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") - local a = VoxelArea:new{ - MinEdge={x=emin.x, y=emin.y, z=emin.z}, - MaxEdge={x=emax.x, y=emax.y, z=emax.z}, - } - local data = vm:get_data() - - -- Left - if minp.x <= -r and maxp.x >= -r then - local x = -r - for z = minp.z, maxp.z do - for y = minp.y, maxp.y do - local vi = a:index(x, y, z) - - if data[vi] == c_air or data[vi] == c_glass then - data[vi] = c_glass - else - data[vi] = c_stone - end - end - end - end - - -- Right - if minp.x <= r and maxp.x >= r then - local x = r - for z = minp.z, maxp.z do - for y = minp.y, maxp.y do - local vi = a:index(x, y, z) - if data[vi] == c_air or data[vi] == c_glass then - data[vi] = c_glass - else - data[vi] = c_stone - end - end - end - end - - -- Front - if minp.z <= -r and maxp.z >= -r then - local z = -r - for x = minp.x, maxp.x do - for y = minp.y, maxp.y do - local vi = a:index(x, y, z) - if data[vi] == c_air or data[vi] == c_glass then - data[vi] = c_glass - else - data[vi] = c_stone - end - end - end - end - - -- Back - if minp.z <= r and maxp.z >= r then - local z = r - for x = minp.x, maxp.x do - for y = minp.y, maxp.y do - local vi = a:index(x, y, z) - if data[vi] == c_air or data[vi] == c_glass then - data[vi] = c_glass - else - data[vi] = c_stone - end - end - end - end - - -- Barrier - if minp.z <= 0 and maxp.z >= 0 and ctf_match.build_timer > 0 then - local z = 0 - local x1 = minp.x - if x1 < -r then x1 = -r end - local x2 = maxp.x - if x2 > r then x2 = r end - for x = x1, x2 do - for y = minp.y, maxp.y do - local vi = a:index(x, y, z) - local node = data[vi] - if node == c_air or node == c_glass_red or - node == c_water or node == c_water_f then - data[vi] = c_glass_red - end - end - end - end - - vm:set_data(data) - vm:write_to_map(data) -end) - -ctf_match.register_on_build_time_end(function() - local min = { - x = -r + 1, - y = -r, - z = -1 - } - local max = { - x = r - 1, - y = r, - z = 1 - } - - local vm = minetest.get_voxel_manip() - local emin, emax = vm:read_from_map(min, max) - local a = VoxelArea:new{ - MinEdge = emin, - MaxEdge = emax - } - local data = vm:get_data() - for x = min.x, max.x do - for y = min.y, max.y do - local vi = a:index(x, y, 0) - if data[vi] == c_glass_red then - data[vi] = c_air - end - end - end - - vm:set_data(data) - vm:write_to_map(data) - vm:update_map() -end) - ---[[minetest.register_abm({ - nodenames = {"ctf_barrier:ind_glass_red"}, - interval = 10.0, -- Run every 10 seconds - chance = 2, -- Select every 1 in 50 nodes - action = function(pos, node, active_object_count, active_object_count_wider) - if ctf_match.build_timer > 0 then - return - end - - minetest.set_node(pos, {name = "air"}) - end -})]] - -local old_is_protected = minetest.is_protected -function minetest.is_protected(pos, name) - if ctf_match.build_timer <= 0 then - return old_is_protected(pos, name) - end - - local tname = ctf.player(name).team - if tname and - (tname == "blue" and pos.z >= 0) or (tname == "red" and pos.z <= 0) then - minetest.chat_send_player(name, "Can't dig beyond the barrier!") - return true - else - return old_is_protected(pos, name) - end -end - -local function pos_check() - if ctf_match.build_timer <= 0 then - return - end - - for _, player in pairs(minetest.get_connected_players()) do - local name = player:get_player_name() - local tname = ctf.player(name).team - local pos = player:getpos() - if tname and - (tname == "blue" and pos.z >= 0) or (tname == "red" and pos.z <= 0) then - minetest.chat_send_player(name, "Match hasn't started yet!") - ctf.move_to_spawn(name) - end - end - - if ctf_match.build_timer > 0.2 then - minetest.after(0.2, pos_check) - end -end - -ctf_match.register_on_build_time_start(function() - minetest.after(0.2, pos_check) -end) diff --git a/mods/ctf_inventory/give_initial_stuff.lua b/mods/ctf_inventory/give_initial_stuff.lua deleted file mode 100644 index 87b2309..0000000 --- a/mods/ctf_inventory/give_initial_stuff.lua +++ /dev/null @@ -1,17 +0,0 @@ -function give_initial_stuff(player) - if minetest.setting_getbool("give_initial_stuff") then - minetest.log("action", "Giving initial stuff to player "..player:get_player_name()) - local inv = player:get_inventory() - inv:set_list("main", {}) - inv:set_list("craft", {}) - inv:add_item('main', 'default:pick_wood') - inv:add_item('main', 'default:sword_wood') - inv:add_item('main', 'default:torch 3') - end -end - -minetest.register_on_joinplayer(function(player) - player:set_hp(20) - give_initial_stuff(player) -end) -minetest.register_on_respawnplayer(give_initial_stuff) diff --git a/mods/ctf_inventory/init.lua b/mods/ctf_inventory/init.lua index c593098..ca362e6 100644 --- a/mods/ctf_inventory/init.lua +++ b/mods/ctf_inventory/init.lua @@ -44,5 +44,3 @@ sfinv.register_page("ctf_inventory:help", { return sfinv.make_formspec(player, context, fs, false) end }) - -dofile(minetest.get_modpath("ctf_inventory") .. "/give_initial_stuff.lua") diff --git a/mods/ctf_map/README.md b/mods/ctf_map/README.md new file mode 100644 index 0000000..7767c3f --- /dev/null +++ b/mods/ctf_map/README.md @@ -0,0 +1,51 @@ +# CTF Map + +This mod handles multiple maps. + +# Creating a new map + +## 1. Dependencies + +* Minetest 0.4.16 or later. +* Mods + * ctf_map (by copying the folder from this game to `minetest/mods`) + * worldedit and worldedit_commands. + +## 2. Find an area + +* Can use Minetest Game and any mapgen. +* It must be a cube, and the barrier will be in the exact center. +* It should be around 230x230 in surface area, but this can vary. +* Feel free to modify the area to your needs. + +## 3. Select the area + +There are multiple ways do this, this is the simplist in most cases. + +* If you haven't modified the map at all, do the following to speed up barrier placement: + * Stop Minetest. + * Open up the world's world.mt + * Set backend to "dummy". + * Save. +* Using worldedit, select the area. +* Type /gui, and click "From WE" then "To WE". +* Check that the center location is the right place for the barrier to go. +* Check that the bounds extend far enough. + +## 4. Place barriers + +* Set the middle barrier direction. The barrier is a plane defined by a co-ordinate = 0. + If the barrier is X=0, then it will placed with every node of the barrier having X=0. + If the barrier is Z=0, then it will placed with every node of the barrier having Z=0. +* Click "place barrier". Note that this command does not have an undo. + +## 5. Meta data + +* Set the meta data + +## 6. Export + +* Click export, and wait until completion. +* Copy the two files from `worlddir/schemes/` to `ctf_map/maps/`. +* Rename the files so the two prefixed numbers are consistent to existing maps. +* Profit! diff --git a/mods/ctf_map/barrier.lua b/mods/ctf_map/barrier.lua new file mode 100644 index 0000000..d88ccb6 --- /dev/null +++ b/mods/ctf_map/barrier.lua @@ -0,0 +1,228 @@ +local c_stone = minetest.get_content_id("ctf_map:ind_stone") +local c_stone_red = minetest.get_content_id("ctf_map:ind_stone_red") +local c_glass = minetest.get_content_id("ctf_map:ind_glass") +local c_glass_red = minetest.get_content_id("ctf_map:ind_glass_red") +local c_map_ignore = minetest.get_content_id("ctf_map:ignore") +local c_actual_st = minetest.get_content_id("default:stone") +local c_water = minetest.get_content_id("default:water_source") +local c_water_f = minetest.get_content_id("default:water_flowing") +local c_air = minetest.get_content_id("air") + +function ctf_map.remove_middle_barrier() + minetest.log("error", "Removing middle barrier!") + + local r = ctf_map.map.r + local h = ctf_map.map.h + + local min = { + x = -r + 1, + y = -h / 2, + z = -1 + } + local max = { + x = r - 1, + y = h / 2, + z = 1 + } + + local vm = minetest.get_voxel_manip() + local emin, emax = vm:read_from_map(min, max) + local a = VoxelArea:new{ + MinEdge = emin, + MaxEdge = emax + } + local data = vm:get_data() + for x = min.x, max.x do + for y = min.y, max.y do + local vi = a:index(x, y, 0) + if data[vi] == c_glass_red then + data[vi] = c_air + elseif data[vi] == c_stone_red then + data[vi] = c_actual_st + end + end + end + + vm:set_data(data) + vm:write_to_map(data) + vm:update_map() +end + +function ctf_map.place_middle_barrier(center, r, h, direction) + assert(direction == "x" or direction == "z") + + local min = { + x = -r + 1, + y = -h / 2 + 1, + z = -r + 1, + } + local max = { + x = r - 1, + y = h / 2 - 1, + z = r - 1, + } + + local other = "z" + if direction == "z" then + other = "x" + end + + min[direction] = -1 + max[direction] = 1 + min = vector.add(center, min) + max = vector.add(center, max) + + + local vm = minetest.get_voxel_manip() + local emin, emax = vm:read_from_map(min, max) + local a = VoxelArea:new{ + MinEdge = emin, + MaxEdge = emax + } + + local data = vm:get_data() + for x = min[other], max[other] do + for y = min.y, max.y do + local vi + if other == "x" then + vi = a:index(x, y, center.z) + else + vi = a:index(center.x, y, x) + end + if data[vi] == c_air then + data[vi] = c_glass_red + end + end + end + + vm:set_data(data) + vm:write_to_map(data) + vm:update_map() +end + + +function ctf_map.place_outer_barrier(center, r, h) + local minp = vector.subtract(center, r) + local maxp = vector.add(center, r) + minp.y = center.y - h / 2 + maxp.y = center.y + h / 2 + + print("Loading data into LVM") + + local vm = minetest.get_voxel_manip() + local emin, emax = vm:read_from_map(minp, maxp) + local a = VoxelArea:new{ + MinEdge = emin, + MaxEdge = emax + } + local data = vm:get_data() + + print("Placing left wall") + + -- Left + local x = center.x - r + for z = minp.z, maxp.z do + for y = minp.y, maxp.y do + local vi = a:index(x, y, z) + if data[vi] == c_air or data[vi] == c_glass or data[vi] == c_map_ignore then + data[vi] = c_glass + else + data[vi] = c_stone + end + end + end + + print("Placing right wall") + + -- Right + local x = center.x + r + for z = minp.z, maxp.z do + for y = minp.y, maxp.y do + local vi = a:index(x, y, z) + if data[vi] == c_air or data[vi] == c_glass or data[vi] == c_map_ignore then + data[vi] = c_glass + else + data[vi] = c_stone + end + end + end + + print("Placing front wall") + + -- Front + local z = center.z - r + for x = minp.x, maxp.x do + for y = minp.y, maxp.y do + local vi = a:index(x, y, z) + if data[vi] == c_air or data[vi] == c_glass or data[vi] == c_map_ignore then + data[vi] = c_glass + else + data[vi] = c_stone + end + end + end + + print("Placing back wall") + + -- Back + local z = center.z + r + for x = minp.x, maxp.x do + for y = minp.y, maxp.y do + local vi = a:index(x, y, z) + if data[vi] == c_air or data[vi] == c_glass or data[vi] == c_map_ignore then + data[vi] = c_glass + else + data[vi] = c_stone + end + end + end + + print("Writing to engine!") + + vm:set_data(data) + vm:write_to_map(data) + vm:update_map() +end + +if minetest.get_modpath("ctf") then + local old_is_protected = minetest.is_protected + function minetest.is_protected(pos, name) + if ctf_match.build_timer <= 0 then + return old_is_protected(pos, name) + end + + local tname = ctf.player(name).team + if tname and + (tname == "blue" and pos.z >= 0) or (tname == "red" and pos.z <= 0) then + minetest.chat_send_player(name, "Can't dig beyond the barrier!") + return true + else + return old_is_protected(pos, name) + end + end + + local function pos_check() + if ctf_match.build_timer <= 0 then + return + end + + for _, player in pairs(minetest.get_connected_players()) do + local name = player:get_player_name() + local tname = ctf.player(name).team + local pos = player:get_pos() + if tname and + (tname == "blue" and pos.z >= 0) or (tname == "red" and pos.z <= 0) then + minetest.chat_send_player(name, "Match hasn't started yet!") + ctf.move_to_spawn(name) + end + end + + if ctf_match.build_timer > 0.2 then + minetest.after(0.2, pos_check) + end + end + + ctf_match.register_on_build_time_start(function() + minetest.after(0.2, pos_check) + end) +end diff --git a/mods/ctf_map/depends.txt b/mods/ctf_map/depends.txt new file mode 100644 index 0000000..dbb1d69 --- /dev/null +++ b/mods/ctf_map/depends.txt @@ -0,0 +1,5 @@ +default +ctf_team_base? +ctf? +ctf_match? +worldedit? diff --git a/mods/ctf_map/emerge.lua b/mods/ctf_map/emerge.lua new file mode 100644 index 0000000..2d45854 --- /dev/null +++ b/mods/ctf_map/emerge.lua @@ -0,0 +1,31 @@ + +local function emergeblocks_callback(pos, action, num_calls_remaining, ctx) + if ctx.total_blocks == 0 then + ctx.total_blocks = num_calls_remaining + 1 + ctx.current_blocks = 0 + end + ctx.current_blocks = ctx.current_blocks + 1 + + if ctx.current_blocks == ctx.total_blocks then + minetest.chat_send_player(ctx.name, + string.format("Finished emerging %d blocks in %.2fms.", + ctx.total_blocks, (os.clock() - ctx.start_time) * 1000)) + + ctx:callback() + else + ctx:progress() + end +end + +function ctf_map.emerge_with_callbacks(name, pos1, pos2, callback, progress) + local context = { + current_blocks = 0, + total_blocks = 0, + start_time = os.clock(), + name = name, + callback = callback, + progress = progress + } + + minetest.emerge_area(pos1, pos2, emergeblocks_callback, context) +end diff --git a/mods/ctf_map/give_initial_stuff.lua b/mods/ctf_map/give_initial_stuff.lua new file mode 100644 index 0000000..c8d9a21 --- /dev/null +++ b/mods/ctf_map/give_initial_stuff.lua @@ -0,0 +1,22 @@ +function give_initial_stuff(player) + minetest.log("action", "Giving initial stuff to player "..player:get_player_name()) + local inv = player:get_inventory() + inv:set_list("main", {}) + inv:set_list("craft", {}) + + local items = ctf_map.map and ctf_map.map.initial_stuff or { + "default:pick_wood", + "default:sword_wood", + "default:torch 3", + } + + for _, item in pairs(items) do + inv:add_item("main", item) + end +end + +minetest.register_on_joinplayer(function(player) + player:set_hp(20) + give_initial_stuff(player) +end) +minetest.register_on_respawnplayer(give_initial_stuff) diff --git a/mods/ctf_map/init.lua b/mods/ctf_map/init.lua new file mode 100644 index 0000000..e264cf6 --- /dev/null +++ b/mods/ctf_map/init.lua @@ -0,0 +1,16 @@ +ctf_map = {} + +dofile(minetest.get_modpath("ctf_map") .. "/nodes.lua") +dofile(minetest.get_modpath("ctf_map") .. "/emerge.lua") +dofile(minetest.get_modpath("ctf_map") .. "/barrier.lua") + + +if minetest.get_modpath("ctf") then + dofile(minetest.get_modpath("ctf_map") .. "/schem_map.lua") + dofile(minetest.get_modpath("ctf_map") .. "/give_initial_stuff.lua") + + assert(ctf_match) + ctf_match.register_on_build_time_end(ctf_map.remove_middle_barrier) +else + dofile(minetest.get_modpath("ctf_map") .. "/map_maker.lua") +end diff --git a/mods/ctf_map/map_maker.lua b/mods/ctf_map/map_maker.lua new file mode 100644 index 0000000..bee8288 --- /dev/null +++ b/mods/ctf_map/map_maker.lua @@ -0,0 +1,220 @@ +minetest.register_on_joinplayer(function(player) + minetest.after(1, function(name) + minetest.chat_send_player(name, "*** CTF_MAP IS IN MAP MAKER MODE ***") + end, player:get_player_name()) +end) + +assert(minetest.get_modpath("worldedit") and + minetest.get_modpath("worldedit_commands"), + "worldedit and worldedit_commands are required!") + +local center = { x = 0, y = 0, z = 0, r = 115, h = 140 } +local function to_2pos() + return { + x = center.x - center.r, + y = center.y - center.h / 2, + z = center.z - center.r, + }, { + x = center.x + center.r, + y = center.y + center.h / 2, + z = center.z + center.r, + } +end + +local function max(a, b) + if a > b then + return a + else + return b + end +end + +local function we_select(name) + local pos1, pos2 = to_2pos() + worldedit.pos1[name] = pos1 + worldedit.mark_pos1(name) + worldedit.player_notify(name, "position 1 set to " .. minetest.pos_to_string(pos1)) + worldedit.pos2[name] = pos2 + worldedit.mark_pos2(name) + worldedit.player_notify(name, "position 2 set to " .. minetest.pos_to_string(pos2)) +end + +local function we_import(name) + local pos1 = worldedit.pos1[name] + local pos2 = worldedit.pos2[name] + if pos1 and pos2 then + local size = vector.subtract(pos2, pos1) + local r = max(size.x, size.z) / 2 + center = vector.divide(vector.add(pos1, pos2), 2) + center.r = r + center.h = size.y + end +end + + +local randint = math.random(100) +local barrier_r = 110 +local mapname = "ctf_" .. randint +local maptitle = "Untitled Map " .. randint +local mapauthor = nil +local center_barrier_rot = 1 +local function show_gui(name) + mapauthor = mapauthor or name + + local formspec = { + "size[8,9.5]", + "bgcolor[#080808BB;true]", + default.gui_bg, + default.gui_bg_img, + + "label[0,0;1. Select Area]", + "field[0.4,1;1,1;posx;X;", center.x, "]", + "field[1.4,1;1,1;posy;Y;", center.y, "]", + "field[2.4,1;1,1;posz;Z;", center.z, "]", + "field[0.4,2;1,1;posr;R;", center.r, "]", + "field[1.4,2;1,1;posh;H;", center.h, "]", + "button[4.3,0.7;1.5,1;set_center;Player Pos]", + "button[5.8,0.7;1.1,1;towe;To WE]", + "button[6.9,0.7;1.1,1;fromwe;From WE]", + "button[4.3,1.7;1.5,1;emerge;Emerge Area]", + + "label[0,3;2. Place Barriers]", + "label[0,3.5;This may take a few minutes.]", + "field[0.4,4.5;1,1;barrier_r;R;", barrier_r, "]", + "dropdown[1.15,4.25;1,1;center_barrier_rot;X=0,Z=0;", center_barrier_rot + 1, "]", + "button[2.3,4.2;2,1;place_barrier;Place Barriers]", + + "label[0,5.5;3. Meta Data]", + "field[0.4,6.5;7.5,1;title;Title;" , minetest.formspec_escape(maptitle), "]", + "field[0.4,7.8;3.75,1;name;File Name;" , minetest.formspec_escape(mapname), "]", + "field[4.15,7.8;3.75,1;author;Author;", minetest.formspec_escape(mapauthor), "]", + + "button_exit[0.8,8.8;3,1;close;Close]", + "button_exit[3.8,8.8;3,1;export;Export]", + } + + formspec = table.concat(formspec, "") + minetest.show_formspec(name, "ctf_map:tool", formspec) +end + +local function show_progress_formspec(name, text) + minetest.show_formspec(name, "ctf_map:progress", + "size[6,1]bgcolor[#080808BB;true]" .. + default.gui_bg .. + default.gui_bg_img .. "label[0,0;" .. + minetest.formspec_escape(text) .. "]") +end + +local function emerge_progress(ctx) + show_progress_formspec(ctx.name, string.format("Emerging Area - %d/%d blocks emerged (%.1f%%)", + ctx.current_blocks, ctx.total_blocks, + (ctx.current_blocks / ctx.total_blocks) * 100)) +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + if formname ~= "ctf_map:tool" then + return + end + + if fields.posx then + center.x = tonumber(fields.posx) + center.y = tonumber(fields.posy) + center.z = tonumber(fields.posz) + center.r = tonumber(fields.posr) + center.h = tonumber(fields.posh) + barrier_r = tonumber(fields.barrier_r) + maptitle = fields.title + mapauthor = fields.author + mapname = fields.name + end + + if fields.center_barrier_rot and fields.center_barrier_rot ~= "" then + center_barrier_rot = fields.center_barrier_rot == "X=0" and 0 or 1 + end + + if fields.set_center then + local r = center.r + local h = center.h + center = vector.floor(player:get_pos()) + center.r = r + center.h = h + end + + local player_name = player:get_player_name() + + if fields.emerge then + local pos1, pos2 = to_2pos() + show_progress_formspec(player_name, "Emerging area...") + ctf_map.emerge_with_callbacks(player_name, pos1, pos2, function() + show_gui(player_name) + end, emerge_progress) + return true + end + + if fields.place_barrier then + local pos1, pos2 = to_2pos() + show_progress_formspec(player_name, "Emerging area...") + ctf_map.emerge_with_callbacks(player_name, pos1, pos2, function() + show_progress_formspec(player_name, "Placing center barrier, this may take a while...") + + minetest.after(0.1, function() + ctf_map.place_middle_barrier(center, barrier_r, center.h, (center_barrier_rot == 0) and "x" or "z") + show_progress_formspec(player_name, "Placing outer barriers, this may take a while...") + minetest.after(0.1, function() + ctf_map.place_outer_barrier(center, barrier_r, center.h) + show_gui(player_name) + end) + end) + end, emerge_progress) + return true + end + + if fields.towe then + we_select(player_name) + end + + if fields.fromwe then + we_import(player_name) + end + + if fields.export then + we_select(player_name) + show_progress_formspec(player_name, "Exporting...") + + local path = minetest.get_worldpath() .. "/schems/" + minetest.mkdir(path) + + local meta = Settings(path .. mapname .. ".conf") + meta:set("name", maptitle) + meta:set("author", mapauthor) + meta:set("rotation", center_barrier_rot == 0 and "x" or "z") + meta:set("r", center.r) + meta:set("h", center.h) + meta:write() + + minetest.after(0.1, function() + local filepath = path .. mapname .. ".mts" + if minetest.create_schematic(worldedit.pos1[player_name], + worldedit.pos2[player_name], worldedit.prob_list[player_name], + filepath) then + minetest.chat_send_all("Exported " .. mapname .. " to " .. path) + minetest.close_formspec(player_name, "") + else + minetest.chat_send_all("Failed!") + show_gui(player_name) + end + end) + return + end + + if not fields.quit then + show_gui(player_name) + end +end) + +minetest.register_chatcommand("gui", { + func = function(name) + show_gui(name) + return true + end +}) diff --git a/mods/ctf_map/maps/01_two_hills.conf b/mods/ctf_map/maps/01_two_hills.conf new file mode 100644 index 0000000..c9f7ab0 --- /dev/null +++ b/mods/ctf_map/maps/01_two_hills.conf @@ -0,0 +1,11 @@ +name = Two Hills and Two Lakes +author = rubenwardy +rotation = z +r = 115 +h = 140 +team.1 = red +team.1.color = red +team.1.pos = 7,27,93 +team.2 = blue +team.2.color = blue +team.2.pos = -22,28,-78 diff --git a/mods/ctf_map/maps/01_two_hills.mts b/mods/ctf_map/maps/01_two_hills.mts new file mode 100644 index 0000000..91c7885 Binary files /dev/null and b/mods/ctf_map/maps/01_two_hills.mts differ diff --git a/mods/ctf_map/maps/02_bridge.conf b/mods/ctf_map/maps/02_bridge.conf new file mode 100644 index 0000000..38e8558 --- /dev/null +++ b/mods/ctf_map/maps/02_bridge.conf @@ -0,0 +1,11 @@ +name = The Bridge +author = rubenwardy +rotation = x +r = 115 +h = 140 +team.1 = red +team.1.color = red +team.1.pos = -57,-20,93 +team.2 = blue +team.2.color = blue +team.2.pos = -74,-16,-70 diff --git a/mods/ctf_map/maps/02_bridge.mts b/mods/ctf_map/maps/02_bridge.mts new file mode 100644 index 0000000..e5b8da5 Binary files /dev/null and b/mods/ctf_map/maps/02_bridge.mts differ diff --git a/mods/ctf_map/nodes.lua b/mods/ctf_map/nodes.lua new file mode 100644 index 0000000..5e0bf26 --- /dev/null +++ b/mods/ctf_map/nodes.lua @@ -0,0 +1,59 @@ +minetest.register_node("ctf_map:ignore", { + description = "MyAir (you hacker you!)", + drawtype = "airlike", + paramtype = "light", + sunlight_propagates = true, + walkable = true, + pointable = false, + diggable = false, + buildable_to = false, + air_equivalent = true, + drop = "", + groups = {not_in_creative_inventory=1} +}) + +minetest.register_node("ctf_map:ind_glass", { + description = "You cheater you!", + drawtype = "glasslike_framed_optional", + tiles = {"default_glass.png", "default_glass_detail.png"}, + inventory_image = minetest.inventorycube("default_glass.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = false, + walkable = true, + buildable_to = false, + pointable = false, + groups = {immortal = 1}, + sounds = default.node_sound_glass_defaults() +}) + +minetest.register_node("ctf_map:ind_stone", { + description = "Cheater!", + groups = {immortal = 1}, + tiles = {"default_stone.png"}, + is_ground_content = false +}) + +minetest.register_node("ctf_map:ind_stone_red", { + description = "Cheater!", + groups = {immortal = 1}, + tiles = {"ctf_map_stone_red.png"}, + is_ground_content = false +}) + +minetest.register_node("ctf_map:ind_glass_red", { + description = "You cheater you!", + drawtype = "glasslike", + tiles = {"ctf_map_glass_red.png"}, + inventory_image = minetest.inventorycube("default_glass.png"), + paramtype = "light", + sunlight_propagates = true, + is_ground_content = false, + walkable = true, + buildable_to = false, + use_texture_alpha = false, + alpha = 0, + pointable = false, + groups = {immortal = 1}, + sounds = default.node_sound_glass_defaults() +}) diff --git a/mods/ctf_map/schem_map.lua b/mods/ctf_map/schem_map.lua new file mode 100644 index 0000000..556acab --- /dev/null +++ b/mods/ctf_map/schem_map.lua @@ -0,0 +1,170 @@ +assert(minetest.get_mapgen_setting("mg_name") == "singlenode", "singlenode mapgen is required.") + +minetest.register_alias("mapgen_singlenode", "ctf_map:ignore") + + +local max_r = 120 +local mapdir = minetest.get_modpath("ctf_map") .. "/maps/" +ctf_map.map = nil + + +do + local files_hash = {} + + local dirs = minetest.get_dir_list(mapdir, true) + table.insert(dirs, ".") + for _, dir in pairs(dirs) do + local files = minetest.get_dir_list(mapdir .. dir, false) + -- if dir ~= "" then + -- dir = dir .. "/" + -- end + for i=1, #files do + files_hash[dir .. "/" .. files[i]:split(".")[1]] = true + end + end + + ctf_map.available_maps = {} + for key, _ in pairs(files_hash) do + table.insert(ctf_map.available_maps, key) + end +end + + +function ctf_map.place_map(map) + local r = map.r + local h = map.h + minetest.emerge_area(map.pos1, map.pos2) + + local schempath = mapdir .. map.schematic + local res = minetest.place_schematic(map.pos1, schempath, + map.rotation == "z" and "0" or "90") + + if res ~= nil then + local seed = minetest.get_mapgen_setting("seed") + for _, value in pairs(ctf_map.map.teams) do + place_chests(value.chests.from, value.chests.to, seed, value.chests.n) + minetest.log("error", "Placing " .. value.chests.n .. " chests from " .. + minetest.pos_to_string(value.chests.from) .. " to ".. + minetest.pos_to_string(value.chests.to)) + + ctf_team_base.place(value.color, value.pos) + end + end + + return res ~= nil +end + +function ctf_match.load_map_meta(idx, name) + local offset = vector.new(600 * (idx - 1), 0, 0) + local meta = Settings(mapdir .. name .. ".conf") + + local initial_stuff = meta:get("initial_stuff") + local map = { + idx = idx, + name = meta:get("name"), + author = meta:get("author"), + rotation = meta:get("rotation"), + schematic = name .. ".mts", + r = tonumber(meta:get("r")), + h = tonumber(meta:get("h")), + teams = {}, + initial_stuff = initial_stuff and initial_stuff:split(","), + } + + assert(map.r <= max_r) + + map.pos1 = vector.add(offset, { x = -map.r, y = -map.h / 2, z = -map.r }) + map.pos2 = vector.add(offset, { x = map.r, y = map.h / 2, z = map.r }) + + local i = 1 + while meta:get("team." .. i) do + local tname = meta:get("team." .. i) + local tcolor = meta:get("team." .. i .. ".color") + local tpos = minetest.string_to_pos(meta:get("team." .. i .. ".pos")) + + local chests1 = meta:get("team." .. i .. ".chests1") + if chests1 then + chests1 = vector.add(offset, minetest.string_to_pos(chests1)) + elseif i == 1 then + chests1 = vector.add(offset, { x = -map.r, y = -map.h / 2, z = 0 }) + elseif i == 2 then + chests1 = map.pos1 + end + + local chests2 = meta:get("team." .. i .. ".chests2") + if chests2 then + chests2 = vector.add(offset, minetest.string_to_pos(chests2)) + elseif i == 1 then + chests2 = map.pos2 + elseif i == 2 then + chests2 = vector.add(offset, { x = map.r, y = map.h / 2, z = 0 }) + end + + + map.teams[tname] = { + color = tcolor, + pos = vector.add(offset, tpos), + chests = { + from = chests1, + to = chests2, + n = tonumber(meta:get("team." .. i .. ".num_chests") or "18"), + }, + } + + i = i + 1 + end + + return map +end + +ctf_match.register_on_new_match(function() + -- Choose next map index, but don't select the same one again + local idx + if ctf_map.map then + idx = math.random(#ctf_map.available_maps - 1) + if idx == ctf_map.map.idx then + idx = idx + 1 + end + else + idx = math.random(#ctf_map.available_maps) + end + + -- Load meta data + local name = ctf_map.available_maps[idx] + ctf_map.map = ctf_match.load_map_meta(idx, name) + + -- Place map + ctf_map.place_map(ctf_map.map) + + -- Fixes + minetest.after(10, function() + minetest.fix_light(ctf_map.map.pos1, ctf_map.map.pos2) + end) +end) + +function ctf_match.create_teams() + local number = ctf.setting("match.teams") + + for key, value in pairs(ctf_map.map.teams) do + local name = key + local color = value.color + local flag = value.pos + + if name and color and flag then + print(" - creating " .. key) + ctf.team({ + name = name, + color = color, + add_team = true + }) + + ctf_flag.add(name, flag) + + minetest.after(0, function() + ctf_flag.assert_flag(flag) + end) + else + minetest.log("error", " - Failed to create " .. key) + end + end +end diff --git a/mods/ctf_barrier/textures/ctf_barrier_red.png b/mods/ctf_map/textures/ctf_map_glass_red.png similarity index 100% rename from mods/ctf_barrier/textures/ctf_barrier_red.png rename to mods/ctf_map/textures/ctf_map_glass_red.png diff --git a/mods/ctf_map/textures/ctf_map_stone_red.png b/mods/ctf_map/textures/ctf_map_stone_red.png new file mode 100644 index 0000000..ff72d3e Binary files /dev/null and b/mods/ctf_map/textures/ctf_map_stone_red.png differ diff --git a/mods/ctf_match/init.lua b/mods/ctf_match/init.lua index 4ed46c4..13334dc 100644 --- a/mods/ctf_match/init.lua +++ b/mods/ctf_match/init.lua @@ -7,7 +7,6 @@ end dofile(minetest.get_modpath("ctf_match") .. "/matches.lua") dofile(minetest.get_modpath("ctf_match") .. "/buildtime.lua") -dofile(minetest.get_modpath("ctf_match") .. "/reset.lua") dofile(minetest.get_modpath("ctf_match") .. "/chat.lua") dofile(minetest.get_modpath("ctf_match") .. "/vote.lua") diff --git a/mods/ctf_match/matches.lua b/mods/ctf_match/matches.lua index b83c143..28aba10 100644 --- a/mods/ctf_match/matches.lua +++ b/mods/ctf_match/matches.lua @@ -36,65 +36,7 @@ function ctf_match.next() end ctf.reset() - -- Note: ctf.reset calls register_on_new_game, below. -end --- Check for winner -local game_won = false -function ctf_match.check_for_winner() - local winner - for name, team in pairs(ctf.teams) do - if winner then - return - end - winner = name - end - - -- There is a winner! - if not game_won then - game_won = true - ctf.action("match", winner .. " won!") - minetest.chat_send_all("Team " .. winner .. " won!") - for i = 1, #ctf_match.registered_on_winner do - ctf_match.registered_on_winner[i](winner) - end - minetest.after(2, function() - game_won = false - if ctf.setting("match") then - ctf_match.next() - end - end) - end -end - -function ctf_match.create_teams() - local number = ctf.setting("match.teams") - - for i = 1, number do - print("Creating team #" .. i) - local name = ctf.setting("match.team." .. i) - local color = ctf.setting("match.team." .. i .. ".color") - local pos = ctf.setting("match.team." .. i .. ".pos") - local flag = minetest.string_to_pos(pos) - - if name and color and pos and flag then - print(" - Success in getting settings") - ctf.team({ - name = name, - color = color, - add_team = true - }) - - ctf_flag.add(name, flag) - - minetest.after(0, function() - ctf_flag.assert_flag(flag) - end) - end - end -end - -ctf.register_on_new_game(function() ctf_match.create_teams() for i, player in pairs(minetest.get_connected_players()) do @@ -125,7 +67,40 @@ ctf.register_on_new_game(function() if minetest.global_exists("chatplus") then chatplus.log("Next round!") end -end) +end + +-- Check for winner +local game_won = false +function ctf_match.check_for_winner() + local winner + for name, team in pairs(ctf.teams) do + if winner then + return + end + winner = name + end + + -- There is a winner! + if not game_won then + game_won = true + ctf.action("match", winner .. " won!") + minetest.chat_send_all("Team " .. winner .. " won!") + for i = 1, #ctf_match.registered_on_winner do + ctf_match.registered_on_winner[i](winner) + end + minetest.after(2, function() + game_won = false + if ctf.setting("match") then + ctf_match.next() + end + end) + end +end + +-- This is overriden by ctf_map +function ctf_match.create_teams() + error("Error! Unimplemented") +end ctf_flag.register_on_capture(function(attname, flag) if not ctf.setting("match.destroy_team") then diff --git a/mods/ctf_match/reset.lua b/mods/ctf_match/reset.lua deleted file mode 100644 index d244fe6..0000000 --- a/mods/ctf_match/reset.lua +++ /dev/null @@ -1,34 +0,0 @@ -ctf.register_on_init(function() - ctf._set("match.map_reset_limit", 0) -end) - -function ctf_match.next() - for i = 1, #ctf_match.registered_on_new_match do - ctf_match.registered_on_new_match[i]() - end - - local r = ctf.setting("match.map_reset_limit") - if r > 0 then - minetest.chat_send_all("Resetting the map, this may take a few moments...") - minetest.after(0.5, function() - minetest.delete_area(vector.new(-r, -r, -r), vector.new(r, r, r)) - - minetest.after(1, function() - minetest.clear_objects() - ctf.reset() - if vote then - vote.active = {} - vote.queue = {} - vote.update_all_hud() - end - end) - end) - else - ctf.reset() - if vote then - vote.active = {} - vote.queue = {} - vote.update_all_hud() - end - end -end diff --git a/mods/ctf_pvp_engine b/mods/ctf_pvp_engine index 87d0438..e2a59ce 160000 --- a/mods/ctf_pvp_engine +++ b/mods/ctf_pvp_engine @@ -1 +1 @@ -Subproject commit 87d0438db65a41780d02431aee5a286d65a86059 +Subproject commit e2a59cef6eba80464af5414d89c4e1c6fbfd597c diff --git a/mods/ctf_team_base/depends.txt b/mods/ctf_team_base/depends.txt index a0d3d36..1882da9 100644 --- a/mods/ctf_team_base/depends.txt +++ b/mods/ctf_team_base/depends.txt @@ -1,5 +1,4 @@ ctf ctf_flag ctf_match -ctf_barrier ctf_stats diff --git a/mods/ctf_team_base/init.lua b/mods/ctf_team_base/init.lua index fbdb14b..cd902b3 100644 --- a/mods/ctf_team_base/init.lua +++ b/mods/ctf_team_base/init.lua @@ -187,55 +187,48 @@ minetest.register_abm({ end }) -minetest.register_on_generated(function(minp, maxp, seed) - for tname, team in pairs(ctf.teams) do - for _, flag in pairs(team.flags) do - if minp.x <= flag.x and maxp.x >= flag.x and - minp.y <= flag.y and maxp.y >= flag.y and - minp.z <= flag.z and maxp.z >= flag.z then - -- Spawn ind base - for x = flag.x - 2, flag.x + 2 do - for z = flag.z - 2, flag.z + 2 do - minetest.set_node({ x = x, y = flag.y - 1, z = z}, - {name = "default:cobble"}) - end - end - minetest.set_node({ x = flag.x, y = flag.y - 1, z = flag.z}, - {name = "ctf_barrier:ind_stone"}) +ctf_team_base = {} +function ctf_team_base.place(color, pos) + -- Spawn ind base + for x = pos.x - 2, pos.x + 2 do + for z = pos.z - 2, pos.z + 2 do + minetest.set_node({ x = x, y = pos.y - 1, z = z}, + {name = "default:cobble"}) + end + end + minetest.set_node({ x = pos.x, y = pos.y - 1, z = pos.z}, + {name = "ctf_barrier:ind_stone"}) - -- Check for trees - for y = flag.y, flag.y + 3 do - for x = flag.x - 3, flag.x + 3 do - for z = flag.z - 3, flag.z + 3 do - local pos = {x=x, y=y, z=z} - if minetest.get_node(pos).name == "default:tree" then - minetest.set_node(pos, {name="air"}) - end - end - end + -- Check for trees + for y = pos.y, pos.y + 3 do + for x = pos.x - 3, pos.x + 3 do + for z = pos.z - 3, pos.z + 3 do + local pos = {x=x, y=y, z=z} + if minetest.get_node(pos).name == "default:tree" then + minetest.set_node(pos, {name="air"}) end - - -- Spawn chest - local chest = {name = "ctf_team_base:chest_" .. team.data.color} - local dz = 2 - if flag.z < 0 then - dz = -2 - chest.param2 = minetest.dir_to_facedir({x=0,y=0,z=-1}) - end - local pos = { - x = flag.x, - y = flag.y, - z = flag.z + dz - } - minetest.set_node(pos, chest) - local inv = minetest.get_meta(pos):get_inventory() - inv:add_item("main", ItemStack("default:cobble 99")) - inv:add_item("main", ItemStack("default:cobble 99")) - inv:add_item("main", ItemStack("default:cobble 99")) - inv:add_item("main", ItemStack("default:wood 99")) - inv:add_item("main", ItemStack("default:glass 5")) - inv:add_item("main", ItemStack("default:torch 10")) end end end -end) + + -- Spawn chest + local chest = {name = "ctf_team_base:chest_" .. color} + local dz = 2 + if pos.z < 0 then + dz = -2 + chest.param2 = minetest.dir_to_facedir({x=0,y=0,z=-1}) + end + local pos = { + x = pos.x, + y = pos.y, + z = pos.z + dz + } + minetest.set_node(pos, chest) + local inv = minetest.get_meta(pos):get_inventory() + inv:add_item("main", ItemStack("default:cobble 99")) + inv:add_item("main", ItemStack("default:cobble 99")) + inv:add_item("main", ItemStack("default:cobble 99")) + inv:add_item("main", ItemStack("default:wood 99")) + inv:add_item("main", ItemStack("default:glass 5")) + inv:add_item("main", ItemStack("default:torch 10")) +end diff --git a/mods/ctf_treasure/init.lua b/mods/ctf_treasure/init.lua index b5e49c7..08e7ec4 100644 --- a/mods/ctf_treasure/init.lua +++ b/mods/ctf_treasure/init.lua @@ -2,6 +2,7 @@ treasurer.register_treasure("default:ladder",0.3,5,{1,20}) treasurer.register_treasure("default:torch",0.3,5,{1,20}) treasurer.register_treasure("default:cobble",0.4,5,{45,99}) treasurer.register_treasure("default:apple",0.3,5,{1,8}) +treasurer.register_treasure("default:wood",0.3,5,{30,60}) treasurer.register_treasure("doors:door_steel",0.3,5,{1,3}) treasurer.register_treasure("default:pick_steel",0.5,5,{1,10}) diff --git a/mods/tsm_chests/init.lua b/mods/tsm_chests/init.lua index 015cf45..d0941d0 100755 --- a/mods/tsm_chests/init.lua +++ b/mods/tsm_chests/init.lua @@ -78,13 +78,11 @@ minetest.register_node("tsm_chests:chest", { --[[ here are some configuration variables ]] -local chests_per_chunk = 13 -- number of chests per chunk. 15 is a bit high, an actual mod might have a lower number -local h_min = -1 -- minimum chest spawning height, relative to water_level -local h_max = 64-43 -- maximum chest spawning height, relative to water_level +local h_min = -65 -- minimum chest spawning height, relative to water_level +local h_max = 40 -- maximum chest spawning height, relative to water_level local t_min = 3 -- minimum amount of treasures found in a chest local t_max = 6 -- maximum amount of treasures found in a chest -local r_max = tonumber(minetest.setting_get("barrier")) local water_level = tonumber(minetest.setting_get("water_level")) local get_node = minetest.get_node local env = minetest.env @@ -173,23 +171,10 @@ end --[[ here comes the generation code the interesting part which involes treasurer comes way below ]] -minetest.register_on_generated(function(minp, maxp, seed) +function place_chests(minp, maxp, seed, number_chests) minp = {x=minp.x, y=minp.y, z=minp.z} maxp = {x=maxp.x, y=maxp.y, z=maxp.z} - if minp.x <= -r_max then - minp.x = -r_max + 1 - end - if minp.z <= -r_max then - minp.z = -r_max + 1 - end - if minp.x >= r_max then - minp.x = r_max - 1 - end - if minp.z >= r_max then - minp.z = r_max - 1 - end - -- chests minimum and maximum spawn height local height_min = water_level + h_min local height_max = water_level + h_max @@ -201,7 +186,7 @@ minetest.register_on_generated(function(minp, maxp, seed) local y_max = math.min(maxp.y, height_max) local attempts = 0 local chests_placed = 0 - while chests_placed < chests_per_chunk and attempts < chests_per_chunk + 6 do + while chests_placed < number_chests and attempts < number_chests + 12 do attempts = attempts + 1 local pos = { x = math.random(minp.x, maxp.x), @@ -229,4 +214,4 @@ minetest.register_on_generated(function(minp, maxp, seed) end print("Spawned " .. chests_placed .. " chests after " .. attempts .. " attempts!") -end) +end