Allow more than two teams in a match at once (#724)

* Fix bugs with more than two teams

* Fix team allocation

* Fix bugz

* Fix crash

* Fix crash with crash fix
This commit is contained in:
LoneWolfHT 2020-12-25 10:37:02 -08:00 committed by GitHub
parent 0ef16edb23
commit fbf0126599
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 87 additions and 30 deletions

View file

@ -116,6 +116,8 @@ function ctf.chat_send_team(team, msg)
team = ctf.team(team) team = ctf.team(team)
end end
if not team then return end
for pname, _ in pairs(team.players) do for pname, _ in pairs(team.players) do
minetest.chat_send_player(pname, msg) minetest.chat_send_player(pname, msg)
end end
@ -199,6 +201,7 @@ function ctf.join(name, team, force, by)
end end
end end
local prevteam = player.team
player.team = team player.team = team
team_data.players[player.name] = player team_data.players[player.name] = player
ctf.player_last_team[name] = team ctf.player_last_team[name] = team
@ -219,7 +222,7 @@ function ctf.join(name, team, force, by)
minetest.log("action", name .. " joined team " .. team) minetest.log("action", name .. " joined team " .. team)
for i = 1, #ctf.registered_on_join_team do for i = 1, #ctf.registered_on_join_team do
ctf.registered_on_join_team[i](name, team) ctf.registered_on_join_team[i](name, team, prevteam)
end end
return true return true
end end
@ -421,6 +424,7 @@ minetest.register_on_joinplayer(function(player)
local name = player:get_player_name() local name = player:get_player_name()
if ctf.team(ctf.player(name).team) then if ctf.team(ctf.player(name).team) then
minetest.log("action", name.." already in team so not allocating")
return return
end end

View file

@ -52,11 +52,13 @@ local function update_lowest()
-- Update lowest.score and lowest.team -- Update lowest.score and lowest.team
lowest = {} lowest = {}
for tname, score in pairs(scores) do for tname, score in pairs(scores) do
if tname == "red" or tname == "blue" then
if not lowest.score or score <= lowest.score then if not lowest.score or score <= lowest.score then
lowest.score = score lowest.score = score
lowest.team = tname lowest.team = tname
end end
end end
end
end end
local function calc_scores() local function calc_scores()

View file

@ -75,7 +75,7 @@ minetest.register_chatcommand("team", {
string.match(create, "([%a%b_]-)") string.match(create, "([%a%b_]-)")
and create ~= "" and create ~= ""
and create ~= nil and create ~= nil
and ctf.team({name=create, add_team=true}) and ctf.team({name=create, add_team=true, color=create, allow_joins=false})
) then ) then
return true, "Added team '"..create.."'" return true, "Added team '"..create.."'"
else else

View file

@ -52,12 +52,6 @@ function ctf_classes.register_on_changed(func)
table.insert(registered_on_changed, func) table.insert(registered_on_changed, func)
end end
function ctf_classes.set_skin(player, color, class)
player:set_properties({
textures = {"ctf_classes_skin_" .. class.name .. "_" .. (color or "blue") .. ".png"}
})
end
function ctf_classes.get(player) function ctf_classes.get(player)
if type(player) == "string" then if type(player) == "string" then
player = minetest.get_player_by_name(player) player = minetest.get_player_by_name(player)

View file

@ -48,9 +48,17 @@ minetest.register_chatcommand("class", {
end end
}) })
ctf_colors.set_skin = function(player, color) local old_set_skin = ctf_colors.set_skin
ctf_classes.set_skin(player, color, ctf_classes.get(player)) ctf_colors.set_skin = function(player, color, ...)
if color == "blue" or color == "red" then
player:set_properties({
textures = {"ctf_classes_skin_" .. ctf_classes.get(player).name .. "_" .. (color or "blue") .. ".png"}
})
elseif color then
old_set_skin(player, color, ...)
end
end end
ctf_classes.set_skin = ctf_colors.set_skin
ctf_classes.register_on_changed(function(player, old, new) ctf_classes.register_on_changed(function(player, old, new)
if not old then if not old then

View file

@ -11,6 +11,9 @@ local function regen_update()
local pname = player:get_player_name() local pname = player:get_player_name()
local class = get(player) local class = get(player)
local tname = ctf.player(pname).team local tname = ctf.player(pname).team
if medic_by_team[tname] == nil then return end
tnames[pname] = tname tnames[pname] = tname
if class.properties.nearby_hpregen then if class.properties.nearby_hpregen then
if tname then if tname then

View file

@ -55,11 +55,11 @@ function ctf_colors.update(player, name, tplayer)
local tcolor = ctf_colors.get_color(tplayer) local tcolor = ctf_colors.get_color(tplayer)
if ctf.setting("colors.hudtint") then if ctf.setting("colors.hudtint") then
if tcolor.text == "red" or tcolor.text == "blue" then if tcolor.css then
player:hud_set_hotbar_image("ctf_colors_hotbar_" .. tcolor.text .. ".png") player:hud_set_hotbar_image("gui_hotbar.png^[colorize:"..tcolor.css..":180")
player:hud_set_hotbar_selected_image("ctf_colors_hotbar_selected_" .. tcolor.text .. ".png") player:hud_set_hotbar_selected_image("gui_hotbar_selected.png^[colorize:"..tcolor.css..":180")
else else
ctf.error("ctf_colors", "Hint color not supported for " .. tcolor.text) ctf.error("ctf_colors", "css color not found!")
end end
end end

View file

@ -237,8 +237,9 @@ if minetest.get_modpath("ctf") then
for _, player in pairs(minetest.get_connected_players()) do for _, player in pairs(minetest.get_connected_players()) do
if ctf_map.get_team_relative_z(player) < 0 and not ctf_map.can_cross(player) then if ctf_map.get_team_relative_z(player) < 0 and not ctf_map.can_cross(player) then
local name = player:get_player_name() local name = player:get_player_name()
if ctf.move_to_spawn(name) then
minetest.chat_send_player(name, "Match hasn't started yet!") minetest.chat_send_player(name, "Match hasn't started yet!")
ctf.move_to_spawn(name) end
end end
end end

View file

@ -89,6 +89,8 @@ ctf_flag.register_on_prepick_up(function(name, flag)
minetest.chat_send_player(name, "Match hasn't started yet!") minetest.chat_send_player(name, "Match hasn't started yet!")
ctf.move_to_spawn(name) ctf.move_to_spawn(name)
return false return false
elseif not ctf.get_spawn(ctf.player(name).team) then
return false
else else
return true return true
end end

View file

@ -51,7 +51,7 @@ end
local game_won = false local game_won = false
function ctf_match.check_for_winner() function ctf_match.check_for_winner()
local winner local winner
for name, team in pairs(ctf.teams) do for name, team in pairs({red = ctf.teams.red, blue = ctf.teams.blue}) do
if winner then if winner then
return return
end end

View file

@ -0,0 +1,23 @@
minetest.register_on_respawnplayer(function(player)
local name = player:get_player_name()
if not ctf.get_spawn(ctf.player(name).team) then
local pos
if math.random(1, 2) == 1 then
local team = ctf.team("red")
if team and team.flags[1] then
pos = vector.new(team.flags[1])
end
else
local team = ctf.team("blue")
if team and team.flags[1] then
pos = vector.new(team.flags[1])
end
end
if pos then
player:set_pos(pos)
end
end
end)

View file

@ -0,0 +1,2 @@
name = ctf_otherteams
depends = ctf

View file

@ -210,7 +210,15 @@ function ctf_stats.is_pro(name)
return stats.score >= 10000 and kd >= 1.5 return stats.score >= 10000 and kd >= 1.5
end end
ctf.register_on_join_team(function(name, tname) ctf.register_on_join_team(function(name, tname, oldteam)
if not ctf_stats.current[tname] then
ctf_stats.current[tname] = {}
end
if oldteam and ctf_stats.current[oldteam] then
ctf_stats.current[oldteam][name] = nil
end
ctf_stats.current[tname][name] = ctf_stats.current[tname][name] or { ctf_stats.current[tname][name] = ctf_stats.current[tname][name] or {
kills = 0, kills = 0,
kills_since_death = 0, kills_since_death = 0,
@ -368,6 +376,8 @@ end
local function calculateKillReward(victim, killer) local function calculateKillReward(victim, killer)
local vmain, victim_match = ctf_stats.player(victim) local vmain, victim_match = ctf_stats.player(victim)
if not vmain or not victim_match then return 5 end
-- +5 for every kill they've made since last death in this match. -- +5 for every kill they've made since last death in this match.
local reward = victim_match.kills_since_death * 5 local reward = victim_match.kills_since_death * 5
ctf.log("ctf_stats", "Player " .. victim .. " has made " .. reward .. ctf.log("ctf_stats", "Player " .. victim .. " has made " .. reward ..

View file

@ -153,11 +153,14 @@ function _doors.door_toggle(pos, node, clicker)
-- If team door, check clicker's team -- If team door, check clicker's team
if node.name:find("doors:door_steel") then if node.name:find("doors:door_steel") then
local tname = ctf.player(clicker:get_player_name()).team local tname = ctf.player(clicker:get_player_name()).team
if tname == "red" or tname == "blue" then
local owner_team = meta:get_string("owner_team") local owner_team = meta:get_string("owner_team")
if clicker and tname ~= owner_team then if clicker and tname ~= owner_team then
return false return false
end end
end end
end
-- until Lua-5.2 we have no bitwise operators :( -- until Lua-5.2 we have no bitwise operators :(
if state % 2 == 1 then if state % 2 == 1 then
@ -303,6 +306,11 @@ function doors.register(name, def)
-- Get placer's team -- Get placer's team
local tname = ctf.player(pn).team or "" local tname = ctf.player(pn).team or ""
if tname ~= "red" and tname ~= "blue" then
minetest.chat_send_player(pn, "Your team can't place doors!")
return itemstack
end
-- Prevent door placement if within 40 nodes of enemy base -- Prevent door placement if within 40 nodes of enemy base
local enemy_team = tname == "red" and "blue" or "red" local enemy_team = tname == "red" and "blue" or "red"
local enemy_base = ctf_map.map.teams[enemy_team].pos local enemy_base = ctf_map.map.teams[enemy_team].pos