Allow multiple players and multiple teams to win a match

This introduces a compatibility issue for minigames with teams when a team wins by being the only one left; however, considering that the only minigame with teams not developed by me or friends is Gems and that the current code is way better than before, I prefer warn Gems developer and give the possibility to everyone to use such a feature
master
Zughy 2022-01-23 23:57:49 +01:00
parent 2d667236db
commit dcc8f945e7
5 changed files with 142 additions and 40 deletions

View File

@ -117,8 +117,8 @@ To customise your mod even more, there are a few empty callbacks you can use. Th
* `arena_lib.on_disable(mod, function(arena, p_name)`: use it to run more checks before disabling an arena. Must return true if all conditions are met
* `arena_lib.on_load(mod, function(arena)`: see [2.3 Arena phases](#23-arena-phases)
* `arena_lib.on_start(mod, function(arena))`: same as above
* `arena_lib.on_celebration(mod, function(arena, winner_name)`: same as above
* `arena_lib.on_end(mod, function(arena, players, winner_name, spectators, is_forced))`: same as above. Players and spectators are given here because `end_arena` deleted them already - hence these are a copy. `is_forced` returns `true` when the match has been forcibly terminated (via `force_arena_ending`)
* `arena_lib.on_celebration(mod, function(arena, winners)`: same as above
* `arena_lib.on_end(mod, function(arena, players, winners, spectators, is_forced))`: same as above. Players and spectators are given here because `end_arena` deleted them already - hence these are a copy. `is_forced` returns `true` when the match has been forcibly terminated (via `force_arena_ending`)
* `arena_lib.on_join(mod, function(p_name, arena, as_spectator))`: called when a player joins an ongoing match. If `as_spectator` is true, they'll be added as such
* `arena_lib.on_death(mod, function(arena, p_name, reason))`: called when a player dies
* `arena_lib.on_time_tick(mod, function(arena))`: called every second if `time_mode` is different from `"none"`
@ -451,8 +451,9 @@ An arena comes in 4 phases, each one of them linked to a specific function:
The 4 functions, intertwined with the previously mentioned phases are:
* `arena_lib.load_arena(mod, arena_ID)`: between the waiting and the loading phase. Called when the queue timer reaches 0, it teleports people inside.
* `arena_lib.start_arena(mod_ref, arena)`: between the loading and the fighting phase. Called when the loading phase timer reaches 0.
* `arena_lib.load_celebration(mod, arena, winner_name)`: between the fighting and the celebration phase. Called when the winning conditions are met. `winner_name` can be both a string and a table (in case of teams)
* `arena_lib.end_arena(mod_ref, mod, arena, winner_name, as_spectator)`: at the very end of the celebration phase. It teleports people outside the arena. `winner_name` is taken by `load_celebration(...)`
* `arena_lib.load_celebration(mod, arena, winners)`: between the fighting and the celebration phase. Called when the winning conditions are met.
* `winners` can be a string (name of a player), an integer (ID of the winning team), a table of strings (more players) or a table of integers (more teams)
* `arena_lib.end_arena(mod_ref, mod, arena, winners, as_spectator)`: at the very end of the celebration phase. It teleports people outside the arena. `winners` is taken by `load_celebration(...)`
Overriding these functions is **not** recommended. Instead, use the 4 respective callbacks made specifically to customise the behaviour of the formers, sharing (almost) the same variables. They are called *after* the function they're associated with and by default they are empty, so feel free to override them. They are `on_load`, `on_start`, `on_celebration` and `on_end`.

View File

@ -56,6 +56,8 @@ Arena @1 successfully enabled=Arena @1 abilitata con successo
Arena @1 successfully disabled=Arena @1 disabilitata con successo
@1 wins the game=@1 ha vinto la partita
Team @1 wins the game=La squadra @1 ha vinto la partita
@1 win the game=@1 hanno vinto la partita
Teams @1 win the game=Le squadre @1 hanno vinto la partita
[!] This minigame doesn't exist!=[!] Questo minigioco non esiste!
[!] This arena doesn't exist!=[!] Quest'arena non esiste!
[!] No ongoing game!=[!] Nessuna partita in corso!

View File

@ -56,6 +56,8 @@ Arena @1 successfully enabled=
Arena @1 successfully disabled=
@1 wins the game=
Team @1 wins the game=
@1 win the game=
Teams @1 win the game=
[!] This minigame doesn't exist!=
[!] This arena doesn't exist!=
[!] No ongoing game!=

View File

@ -17,6 +17,7 @@ local function update_storage() end
local function check_for_properties() end
local function next_available_ID() end
local function is_arena_name_allowed() end
local function warn_deprecated_set_sign() end
local arena_default = {
name = "",
@ -1362,7 +1363,7 @@ function arena_lib.send_message_players_in_arena(arena, msg, teamID, except_team
arena_lib.send_message_in_arena(arena, "players", msg, teamID, except_teamID)
end
local function warn_deprecated_set_sign(sender)
function warn_deprecated_set_sign(sender)
minetest.log("warning", "[ARENA_LIB] set_sign(sender, <pos>, <remove>, mod, arena_name) is deprecated. Please use set_sign(sender, mod, arena_name, pos, <remove>) instead")
minetest.chat_send_player(sender, "[ARENA_LIB] set_sign(sender, pos, remove, mod, arena_name) is deprecated and pos now mandatory. Watch the log, aborting...")
end

View File

@ -5,8 +5,10 @@ local function operations_before_entering_arena() end
local function operations_before_playing_arena() end
local function operations_before_leaving_arena() end
local function handle_leaving_callbacks() end
local function victory_particles() end
local function show_victory_particles() end
local function time_start() end
local function deprecated_winning_team_celebration() end
local players_in_game = {} -- KEY: player name, VALUE: {(string) minigame, (int) arenaID}
local players_in_queue = {} -- KEY: player name, VALUE: {(string) minigame, (int) arenaID}
@ -170,8 +172,8 @@ end
-- a partita finita.
-- winner_name può essere stringa (no team) o tabella di nomi (team)
function arena_lib.load_celebration(mod, arena, winner_name)
-- winners può essere stringa (giocatore singolo), intero (squadra) o tabella di uno di questi (più giocatori o squadre)
function arena_lib.load_celebration(mod, arena, winners)
-- se era già in celebrazione
if arena.in_celebration then
@ -191,11 +193,34 @@ function arena_lib.load_celebration(mod, arena, winner_name)
local winning_message = ""
-- determino il messaggio da inviare
if type(winner_name) == "string" then
winning_message = S("@1 wins the game", winner_name)
elseif type(winner_name) == "table" then
local winner_team_ID = arena.players[winner_name[1]].teamID
winning_message = S("Team @1 wins the game", arena.teams[winner_team_ID].name)
-- se è stringa, è giocatore singolo
if type(winners) == "string" then
winning_message = S("@1 wins the game", winners)
-- se è un ID è una squadra
elseif type(winners) == "number" then
winning_message = S("Team @1 wins the game", arena.teams[winners].name)
-- se è una tabella, può essere o più giocatori singoli, o più squadre
elseif type(winners) == "table" then
-- v DEPRECATED, da rimuovere in 6.0 ----- v
if arena.teams_enabled and type(winners[1]) == "string" then
winning_message = deprecated_winning_team_celebration(mod, arena, winners)
-- ^ -------------------------------------^
elseif type(winners[1]) == "string" then
for _, pl_name in pairs(winners) do
winning_message = winning_message .. pl_name .. ", "
end
winning_message = S("@1 win the game", winning_message:sub(1, -3))
else
for _, team_ID in pairs(winners) do
winning_message = winning_message .. arena.teams[team_ID].name .. ", "
end
winning_message = S("Teams @1 win the game", winning_message:sub(1, -3))
end
end
local mod_ref = arena_lib.mods[mod]
@ -204,19 +229,19 @@ function arena_lib.load_celebration(mod, arena, winner_name)
-- eventuale codice aggiuntivo
if mod_ref.on_celebration then
mod_ref.on_celebration(arena, winner_name)
mod_ref.on_celebration(arena, winners)
end
-- l'arena finisce dopo tot secondi
minetest.after(mod_ref.celebration_time, function()
arena_lib.end_arena(mod_ref, mod, arena, winner_name)
arena_lib.end_arena(mod_ref, mod, arena, winners)
end)
end
function arena_lib.end_arena(mod_ref, mod, arena, winner_name, is_forced)
function arena_lib.end_arena(mod_ref, mod, arena, winners, is_forced)
-- copie da passare a on_end
local spectators = {}
@ -274,27 +299,11 @@ function arena_lib.end_arena(mod_ref, mod, arena, winner_name, is_forced)
end
end
-- effetto particellare
if type(winner_name) == "string" then
local winner = minetest.get_player_by_name(winner_name)
if winner then
show_victory_particles(winner:get_pos())
end
elseif type(winner_name) == "table" then
for _, pl_name in pairs(winner_name) do
local winner = minetest.get_player_by_name(pl_name)
if winner then
show_victory_particles(winner:get_pos())
end
end
end
victory_particles(arena, players, winners)
-- eventuale codice aggiuntivo
if mod_ref.on_end then
mod_ref.on_end(arena, players, winner_name, spectators, is_forced)
mod_ref.on_end(arena, players, winners, spectators, is_forced)
end
arena.in_loading = false -- nel caso venga forzata mentre sta caricando, sennò rimane a caricare all'infinito
@ -494,17 +503,14 @@ function arena_lib.remove_player_from_arena(p_name, reason, executioner)
if arena.players_amount == 0 then
arena_lib.end_arena(mod_ref, mod, arena)
-- se l'arena ha i team e sono rimasti solo i giocatori di un team, il loro team vince
-- se l'arena è a squadre e sono rimasti solo i giocatori di una squadra, la loro squadra vince
elseif arena.teams_enabled and #arena_lib.get_active_teams(arena) == 1 then
local winners
for _, pl_stats in pairs(arena.players) do
winners = arena_lib.get_players_in_team(arena, pl_stats.teamID)
break
end
local winning_team_id = arena_lib.get_active_teams(arena)[1]
arena_lib.send_message_in_arena(arena, "players", mod_ref.prefix .. S("There are no other teams left, you win!"))
arena_lib.load_celebration(mod, arena, winners)
arena_lib.load_celebration(mod, arena, winning_team_id)
-- se invece erano rimasti solo 2 giocatori in partita, l'altro vince
elseif arena.players_amount == 1 then
@ -956,6 +962,80 @@ end
function victory_particles(arena, players, winners)
-- singolo giocatore
if type(winners) == "string" then
local winner = minetest.get_player_by_name(winners)
if winner then
show_victory_particles(winner:get_pos())
end
-- singola squadra
elseif type(winners) == "number" then
for pl_name, pl_stats in pairs(players) do
if pl_stats.teamID == winners then
local winner = minetest.get_player_by_name(pl_name)
if winner then
show_victory_particles(winner:get_pos())
end
end
end
-- più vincitori
elseif type(winners) == "table" then
-- v DEPRECATED, da rimuovere in 6.0 ----- v
if arena.teams_enabled and type(winners[1]) == "string" then
local teamID = 0
for pl_name, pl_stats in pairs(players) do
if pl_name == winners[1] then
teamID = pl_stats.teamID
break
end
end
for pl_name, pl_stats in pairs(players) do
if pl_stats.teamID == winners then
local winner = minetest.get_player_by_name(pl_name)
if winner then
show_victory_particles(winner:get_pos())
end
end
end
-- ^ -------------------------------------^
-- singoli giocatori
elseif type(winners[1]) == "string" then
for _, pl_name in pairs(winners) do
local winner = minetest.get_player_by_name(pl_name)
if winner then
show_victory_particles(winner:get_pos())
end
end
-- squadre
else
for _, team_ID in pairs(winners) do
local team = arena.teams[team_ID]
for pl_name, pl_stats in pairs(players) do
if pl_stats.teamID == team_ID then
local winner = minetest.get_player_by_name(pl_name)
if winner then
show_victory_particles(winner:get_pos())
end
end
end
end
end
end
end
function show_victory_particles(p_pos)
minetest.add_particlespawner({
amount = 50,
@ -994,3 +1074,19 @@ function time_start(mod_ref, arena)
time_start(mod_ref, arena)
end)
end
----------------------------------------------
------------------DEPRECATED------------------
----------------------------------------------
-- to remove in 6.0
function deprecated_winning_team_celebration(mod, arena, winners)
minetest.log("warning", debug.traceback("[ARENA_LIB - " .. mod .. "] passing a single winning team as a table made of one of its players is deprecated, "
.. "please pass the (integer) team ID instead"))
local winner = arena.players[winners[1]].teamID
return S("Team @1 wins the game", arena.teams[winner].name)
end