diff --git a/minetest.conf b/minetest.conf index 390c63c..72fbb29 100644 --- a/minetest.conf +++ b/minetest.conf @@ -9,9 +9,11 @@ ctf.allocate_mode = 3 ctf.diplomacy = false ctf.players_can_change_team = false ctf.node_ownership = false -ctf.newgame.teams = red, red, 15, 7, 39; blue, blue, -9, 9, -43 -ctf.newgame.clear_inv = true -ctf.endgame.destroy_team = true -ctf.endgame.reset_on_winner = true +ctf.match = true +ctf.match.teams = red, red, 15, 7, 39; blue, blue, -9, 9, -43 +ctf.match.clear_inv = true +ctf.match.destroy_team = true +ctf.match.reset_on_winner = true ctf.remove_player_on_leave = true ctf.autoalloc_on_joinplayer = true +ctf.matchmap_reset_limit = 160 diff --git a/mods/ctf_match/chat.lua b/mods/ctf_match/chat.lua new file mode 100644 index 0000000..c86bb3e --- /dev/null +++ b/mods/ctf_match/chat.lua @@ -0,0 +1,9 @@ +minetest.register_chatcommand("ctf_next", { + description = "Skip to the next match", + privs = { + ctf_admin = true + }, + func = function(name, param) + ctf_match.next() + end +}) diff --git a/mods/ctf_match/depends.txt b/mods/ctf_match/depends.txt new file mode 100644 index 0000000..0620afe --- /dev/null +++ b/mods/ctf_match/depends.txt @@ -0,0 +1,3 @@ +ctf +ctf_flag +vote diff --git a/mods/ctf_match/init.lua b/mods/ctf_match/init.lua new file mode 100644 index 0000000..b3ea932 --- /dev/null +++ b/mods/ctf_match/init.lua @@ -0,0 +1,154 @@ +ctf.register_on_init(function() + ctf._set("match", false) + ctf._set("match.destroy_team", false) + ctf._set("match.break_alliances", true) + ctf._set("match.teams", "") + ctf._set("match.clear_inv", false) + ctf._set("match.map_reset_limit", 0) +end) + +ctf_match = {} + +-- Load next match +function ctf_match.next() + 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() + ctf.reset() + end) + end) + else + ctf.reset() + end + + -- Note: ctf.reset calls register_on_new_game, below. +end + +-- Check for winner +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! + ctf.action("match", winner .. " won!") + minetest.chat_send_all("Team " .. winner .. " won!") + if ctf.setting("match") then + ctf_match.next() + end +end + +ctf.register_on_new_game(function() + local function safe_place(pos, node) + ctf.log("match", "attempting to place...") + minetest.get_voxel_manip(pos, { x = pos.x + 1, y = pos.y + 1, z = pos.z + 1}) + minetest.set_node(pos, node) + if minetest.get_node(pos).name ~= node.name then + ctf.error("match", "failed to place node, retrying...") + minetest.after(0.5, function() + safe_place(pos, node) + end) + end + end + + local teams = ctf.setting("match.teams") + if teams:trim() == "" then + return + end + ctf.log("match", "Setting up new game!") + + teams = teams:split(";") + local pos = {} + for i, v in pairs(teams) do + local team = v:split(",") + if #team == 5 then + local name = team[1]:trim() + local color = team[2]:trim() + local x = tonumber(team[3]:trim()) + local y = tonumber(team[4]:trim()) + local z = tonumber(team[5]:trim()) + pos[name] = { + x = x, + y = y, + z = z + } + + ctf.team({ + name = name, + color = color, + add_team = true + }) + + ctf_flag.add(name, pos[name]) + else + ctf.warning("match", "Invalid team setup: " .. dump(v)) + end + end + + minetest.after(0, function() + for name, p in pairs(pos) do + safe_place(p, {name = "ctf_flag:flag"}) + ctf_flag.update(p) + end + end) + + for i, player in pairs(minetest.get_connected_players()) do + local name = player:get_player_name() + local alloc_mode = tonumber(ctf.setting("allocate_mode")) + local team = ctf.autoalloc(name, alloc_mode) + + if alloc_mode ~= 0 and team then + ctf.log("autoalloc", name .. " was allocated to " .. team) + ctf.join(name, team) + end + + team = ctf.player(name).team + if ctf.team(team) then + local spawn = ctf.get_spawn(team) + if spawn then + player:moveto(spawn, false) + end + end + + if ctf.setting("match.clear_inv") then + local inv = player:get_inventory() + inv:set_list("main", {}) + inv:set_list("craft", {}) + give_initial_stuff(player) + end + + player:set_hp(20) + end + minetest.chat_send_all("Next round!") +end) + +ctf_flag.register_on_capture(function(attname, flag) + if not ctf.setting("match.destroy_team") then + return + end + + local fl_team = ctf.team(flag.team) + if fl_team and #fl_team.flags == 0 then + ctf.action("match", flag.team .. " was defeated.") + ctf.remove_team(flag.team) + minetest.chat_send_all(flag.team .. " has been defeated!") + end + + ctf_match.check_for_winner() +end) + +local claimed = ctf_flag.collect_claimed() +for i, flag in pairs(claimed) do + flag.claimed = nil +end + +dofile(minetest.get_modpath("ctf_match") .. "/chat.lua") +dofile(minetest.get_modpath("ctf_match") .. "/vote.lua") diff --git a/mods/ctf_match/vote.lua b/mods/ctf_match/vote.lua new file mode 100644 index 0000000..1f5427d --- /dev/null +++ b/mods/ctf_match/vote.lua @@ -0,0 +1,28 @@ +minetest.register_chatcommand("vote_next", { + privs = { + interact = true + }, + func = function(name, param) + vote.new_vote(name, { + description = "Skip to next map", + help = "/yes, /no or /abstain", + duration = 60, + perc_needed = 0.5, + unanimous = 5, + + on_result = function(self, result, results) + if result == "yes" then + ctf_match.next() + else + minetest.chat_send_all("Vote to skip map failed, " .. + #results.yes .. " to " .. #results.no) + end + end, + + on_vote = function(self, name, value) + minetest.chat_send_all(name .. " voted " .. value .. " to '" .. + self.description .. "'") + end + }) + end +}) diff --git a/mods/ctf_pvp_engine b/mods/ctf_pvp_engine index 9d15991..17e7a2b 160000 --- a/mods/ctf_pvp_engine +++ b/mods/ctf_pvp_engine @@ -1 +1 @@ -Subproject commit 9d159917682aae47239b8df8292fde927c3ba871 +Subproject commit 17e7a2b529e1a10c866a2b588f0971daf7931946 diff --git a/mods/vote/README.md b/mods/vote/README.md new file mode 100644 index 0000000..c69dabb --- /dev/null +++ b/mods/vote/README.md @@ -0,0 +1,96 @@ +# Vote +A mod for Minetest adding an API to allow voting on servers. + +Version 0.1 + +Created by [rubenwardy](http://rubenwardy.com) +Copyright (c) 2015, no rights reserved +Licensed under WTFPL or CC0 (you choose) + +# Settings + +* vote.maximum_active - maximum votes running at a time, votes are queued if it + reaches this. Defaults to 1. + +# Example + +```lua +minetest.register_chatcommand("vote_kick", { + privs = { + interact = true + }, + func = function(name, param) + if not minetest.get_player_by_name(param) then + minetest.chat_send_player(name, "There is no player called '" .. + param .. "'") + end + + vote.new_vote(name, { + description = "Kick player " .. param, + help = "/yes, /no or /abstain", + name = param, + duration = 60, + + on_result = function(self, result, results) + if result == "yes" then + minetest.chat_send_all("Vote passed, " .. + #results.yes .. " to " .. #results.no .. ", " .. + self.name .. " will be kicked.") + minetest.kick_player(self.name, "The vote to kick you passed") + else + minetest.chat_send_all("Vote failed, " .. + #results.yes .. " to " .. #results.no .. ", " .. + self.name .. " remains ingame.") + end + end, + + on_vote = function(self, name, value) + minetest.chat_send_all(name .. " voted " .. value .. " to '" .. + self.description .. "'") + end + }) + end +}) +``` + +# API + +## Results + +* voted - a key-value table. voted[name] = true if a player called name voted. +* abstain - a list of the names of players who abstained. +*