1084 lines
32 KiB
Lua
Executable File
1084 lines
32 KiB
Lua
Executable File
local S = minetest.get_translator("arena_lib")
|
|
|
|
local function assign_team_spawner() end
|
|
local function operations_before_entering_arena() end
|
|
local function operations_before_playing_arena() end
|
|
local function operations_before_leaving_arena() end
|
|
local function eliminate_player() 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_temp_storage = {} -- KEY: player_name, VALUE: {(int) hotbar_slots, (string) hotbar_background_image, (string) hotbar_selected_image,
|
|
-- (int) bgm_handle, (int) fov, (table) camera_offset, (table) armor_groups}
|
|
|
|
|
|
|
|
|
|
-- per tutti i giocatori quando finisce la coda
|
|
function arena_lib.load_arena(mod, arena_ID)
|
|
|
|
-- my child, let's talk about some black magic: in order to teleport players in their team spawners, first of all I need to
|
|
-- sort them by team. Once it's done, I need to skip every spawner of that team if the maximum number of players is not reached:
|
|
-- otherwise, people will find theirselves in the wrong team (and you don't want that to happen). So I use this int to prevent it,
|
|
-- which increases by 1 or more every time I look for a spawner, comparing the 'team' spawner value to the player's. This happens
|
|
-- in assign_team_spawner, which also returns the new value for team_count
|
|
local team_count = 1
|
|
|
|
local count = 1
|
|
local mod_ref = arena_lib.mods[mod]
|
|
local arena = mod_ref.arenas[arena_ID]
|
|
|
|
arena.in_loading = true
|
|
arena_lib.update_sign(arena)
|
|
|
|
local shuffled_spawners = table.copy(arena.spawn_points)
|
|
local sorted_team_players = {}
|
|
|
|
-- aggiungo eventuali proprietà temporanee
|
|
for temp_property, v in pairs(mod_ref.temp_properties) do
|
|
if type(v) == "table" then
|
|
arena[temp_property] = table.copy(v)
|
|
else
|
|
arena[temp_property] = v
|
|
end
|
|
end
|
|
|
|
-- randomizzo gli spawner se non è a squadre
|
|
if not arena.teams_enabled then
|
|
for i = #shuffled_spawners, 2, -1 do
|
|
local j = math.random(i)
|
|
shuffled_spawners[i], shuffled_spawners[j] = shuffled_spawners[j], shuffled_spawners[i]
|
|
end
|
|
-- sennò ordino i giocatori per squadra
|
|
else
|
|
local j = 1
|
|
for i = 1, #arena.teams do
|
|
for pl_name, pl_stats in pairs(arena.players) do
|
|
if pl_stats.teamID == i then
|
|
sorted_team_players[j] = {name = pl_name, teamID = pl_stats.teamID}
|
|
j = j +1
|
|
end
|
|
end
|
|
|
|
-- e aggiungo eventuali proprietà per ogni squadra
|
|
for k, v in pairs(mod_ref.team_properties) do
|
|
arena.teams[i][k] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
-- per ogni giocatore...
|
|
for pl_name, _ in pairs(arena.players) do
|
|
|
|
operations_before_entering_arena(mod_ref, mod, arena, arena_ID, pl_name)
|
|
|
|
-- teletrasporto i giocatori
|
|
if not arena.teams_enabled then
|
|
minetest.get_player_by_name(pl_name):set_pos(shuffled_spawners[count].pos)
|
|
else
|
|
team_count = assign_team_spawner(arena.spawn_points, team_count, sorted_team_players[count].name, sorted_team_players[count].teamID)
|
|
end
|
|
|
|
count = count +1
|
|
end
|
|
|
|
-- se supporta la spettatore, inizializzo le varie tabelle
|
|
if mod_ref.spectate_mode then
|
|
arena.spectate_entities_amount = 0
|
|
arena.spectate_areas_amount = 0
|
|
arena_lib.init_spectate_containers(mod, arena.name)
|
|
end
|
|
|
|
-- eventuale codice aggiuntivo
|
|
if mod_ref.on_load then
|
|
mod_ref.on_load(arena)
|
|
end
|
|
|
|
for _, callback in ipairs(arena_lib.registered_on_load) do
|
|
callback(mod_ref, arena)
|
|
end
|
|
|
|
-- avvio la partita dopo tot secondi
|
|
minetest.after(mod_ref.load_time, function()
|
|
arena_lib.start_arena(mod_ref, arena)
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
function arena_lib.start_arena(mod_ref, arena)
|
|
|
|
-- nel caso sia terminata durante la fase di caricamento
|
|
if arena.in_celebration or not arena.in_game then return end
|
|
|
|
arena.in_loading = false
|
|
arena_lib.update_sign(arena)
|
|
|
|
-- parte l'eventuale tempo
|
|
if mod_ref.time_mode ~= "none" then
|
|
arena.current_time = arena.initial_time
|
|
minetest.after(1, function()
|
|
time_start(mod_ref, arena)
|
|
end)
|
|
end
|
|
|
|
-- eventuale codice aggiuntivo
|
|
if mod_ref.on_start then
|
|
mod_ref.on_start(arena)
|
|
end
|
|
|
|
for _, callback in ipairs(arena_lib.registered_on_start) do
|
|
callback(mod_ref, arena)
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- per il giocatore singolo a match iniziato
|
|
function arena_lib.join_arena(mod, p_name, arena_ID, as_spectator)
|
|
|
|
local mod_ref = arena_lib.mods[mod]
|
|
local arena = mod_ref.arenas[arena_ID]
|
|
|
|
-- se prova a entrare come spettatore
|
|
if as_spectator then
|
|
-- aggiungo temporaneamente, sennò non trova l'arena quando va a cercare lo spettatore
|
|
players_in_game[p_name] = {minigame = mod, arenaID = arena_ID}
|
|
|
|
-- se passa i controlli, lo inserisco e notifico i giocatori
|
|
if arena_lib.enter_spectate_mode(p_name, arena) then
|
|
operations_before_entering_arena(mod_ref, mod, arena, arena_ID, p_name, true)
|
|
arena_lib.send_message_in_arena(arena, "both", minetest.colorize("#cfc6b8", ">>> " .. p_name .. " (" .. S("spectator") .. ")"))
|
|
|
|
-- sennò annullo
|
|
else
|
|
players_in_game[p_name] = nil
|
|
return
|
|
end
|
|
|
|
-- se entra come giocatore
|
|
else
|
|
if arena_lib.is_player_spectating(p_name) then -- se lo fa mentre è spettatore, controllo che ci sia spazio ecc.
|
|
if not arena_lib.leave_spectate_mode(p_name, true) then return end
|
|
operations_before_playing_arena(mod_ref, arena, p_name)
|
|
else
|
|
operations_before_entering_arena(mod_ref, mod, arena, arena_ID, p_name) -- sennò entra normalmente
|
|
end
|
|
|
|
local player = minetest.get_player_by_name(p_name)
|
|
|
|
-- notifico e teletrasporto
|
|
arena_lib.send_message_in_arena(arena, "both", minetest.colorize("#c6f154", " >>> " .. p_name))
|
|
player:set_pos(arena_lib.get_random_spawner(arena, arena.players[p_name].teamID))
|
|
end
|
|
|
|
-- eventuale codice aggiuntivo
|
|
if mod_ref.on_join then
|
|
mod_ref.on_join(p_name, arena, as_spectator)
|
|
end
|
|
|
|
for _, callback in ipairs(arena_lib.registered_on_join) do
|
|
callback(mod_ref, arena, p_name, as_spectator)
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- a partita finita
|
|
-- `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
|
|
minetest.log("error", debug.traceback("[" .. mod .. "] There has been an attempt to call the celebration phase whilst already in it. This shall not be done, aborting..."))
|
|
return end
|
|
|
|
arena.in_celebration = true
|
|
arena_lib.update_sign(arena)
|
|
|
|
-- ripristino HP e visibilità nome di ogni giocatore
|
|
for pl_name, stats in pairs(arena.players) do
|
|
local player = minetest.get_player_by_name(pl_name)
|
|
|
|
player:set_nametag_attributes({color = {a = 255, r = 255, g = 255, b = 255}})
|
|
end
|
|
|
|
local winning_message = ""
|
|
|
|
-- determino il messaggio da inviare
|
|
-- 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]
|
|
|
|
arena_lib.HUD_send_msg_all("title", arena, winning_message, mod_ref.celebration_time)
|
|
|
|
-- eventuale codice aggiuntivo
|
|
if mod_ref.on_celebration then
|
|
mod_ref.on_celebration(arena, winners)
|
|
end
|
|
|
|
for _, callback in ipairs(arena_lib.registered_on_celebration) do
|
|
callback(mod_ref, arena, winners)
|
|
end
|
|
|
|
-- l'arena finisce dopo tot secondi
|
|
minetest.after(mod_ref.celebration_time, function()
|
|
arena_lib.end_arena(mod_ref, mod, arena, winners)
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
function arena_lib.end_arena(mod_ref, mod, arena, winners, is_forced)
|
|
|
|
-- copie da passare a on_end
|
|
local spectators = {}
|
|
local players = {}
|
|
|
|
-- rimozione spettatori
|
|
for sp_name, sp_stats in pairs(arena.spectators) do
|
|
|
|
spectators[sp_name] = sp_stats
|
|
arena_lib.leave_spectate_mode(sp_name)
|
|
players_in_game[sp_name] = nil
|
|
|
|
operations_before_leaving_arena(mod_ref, arena, sp_name)
|
|
end
|
|
|
|
-- rimozione giocatori
|
|
for pl_name, stats in pairs(arena.players) do
|
|
|
|
players[pl_name] = stats
|
|
arena.players[pl_name] = nil
|
|
players_in_game[pl_name] = nil
|
|
|
|
operations_before_leaving_arena(mod_ref, arena, pl_name)
|
|
end
|
|
|
|
-- dealloca eventuale modalità spettatore
|
|
if mod_ref.spectate_mode then
|
|
arena.spectate_entities_amount = nil
|
|
arena.spectate_areas_amount = nil
|
|
arena_lib.unload_spectate_containers(mod, arena.name)
|
|
end
|
|
|
|
-- azzerramento giocatori e spettatori
|
|
arena.past_present_players = {}
|
|
arena.players_and_spectators = {}
|
|
arena.past_present_players_inside = {}
|
|
|
|
arena.players_amount = 0
|
|
if arena.teams_enabled then
|
|
for i = 1, #arena.teams do
|
|
arena.players_amount_per_team[i] = 0
|
|
if mod_ref.spectate_mode then
|
|
arena.spectators_amount_per_team[i] = 0
|
|
end
|
|
end
|
|
end
|
|
|
|
-- azzero il timer
|
|
arena.current_time = nil
|
|
|
|
-- rimuovo eventuali proprietà temporanee
|
|
for temp_property, v in pairs(mod_ref.temp_properties) do
|
|
arena[temp_property] = nil
|
|
end
|
|
|
|
-- e quelle eventuali di squadra
|
|
if arena.teams_enabled then
|
|
for i = 1, #arena.teams do
|
|
for t_property, _ in pairs(mod_ref.team_properties) do
|
|
arena.teams[i][t_property] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
victory_particles(arena, players, winners)
|
|
|
|
-- eventuale codice aggiuntivo
|
|
if mod_ref.on_end then
|
|
mod_ref.on_end(arena, players, winners, spectators, is_forced)
|
|
end
|
|
|
|
for _, callback in ipairs(arena_lib.registered_on_end) do
|
|
callback(mod_ref, arena, players, winners, spectators, is_forced)
|
|
end
|
|
|
|
arena.in_loading = false -- nel caso venga forzata mentre sta caricando, sennò rimane a caricare all'infinito
|
|
arena.in_celebration = false
|
|
arena.in_game = false
|
|
|
|
arena_lib.update_sign(arena)
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
----------------------------------------------
|
|
--------------------UTILS---------------------
|
|
----------------------------------------------
|
|
|
|
-- mod è opzionale
|
|
function arena_lib.is_player_in_arena(p_name, mod)
|
|
|
|
if not players_in_game[p_name] then
|
|
return false
|
|
else
|
|
|
|
-- se il campo mod è specificato, controllo che sia lo stesso
|
|
if mod ~= nil then
|
|
if players_in_game[p_name].minigame == mod then return true
|
|
else return false
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
end
|
|
|
|
|
|
|
|
function arena_lib.remove_player_from_arena(p_name, reason, executioner)
|
|
-- reason 0 = has disconnected
|
|
-- reason 1 = has been eliminated
|
|
-- reason 2 = has been kicked
|
|
-- reason 3 = has quit the arena
|
|
assert(reason, "[ARENA_LIB] 'remove_player_from_arena': A reason must be specified!")
|
|
|
|
-- se il giocatore non è in partita, annullo
|
|
if not arena_lib.is_player_in_arena(p_name) then return end
|
|
|
|
local mod = arena_lib.get_mod_by_player(p_name)
|
|
local mod_ref = arena_lib.mods[mod]
|
|
local arena = arena_lib.get_arena_by_player(p_name)
|
|
|
|
-- se il giocatore era in spettatore
|
|
if mod_ref.spectate_mode and arena_lib.is_player_spectating(p_name) then
|
|
arena_lib.leave_spectate_mode(p_name)
|
|
operations_before_leaving_arena(mod_ref, arena, p_name, reason)
|
|
arena.past_present_players_inside[p_name] = nil
|
|
|
|
handle_leaving_callbacks(mod_ref, arena, p_name, reason, executioner, true)
|
|
players_in_game[p_name] = nil
|
|
return
|
|
|
|
-- sennò...
|
|
else
|
|
|
|
-- rimuovo
|
|
arena.players_amount = arena.players_amount - 1
|
|
if arena.teams_enabled then
|
|
local p_team_ID = arena.players[p_name].teamID
|
|
arena.players_amount_per_team[p_team_ID] = arena.players_amount_per_team[p_team_ID] - 1
|
|
end
|
|
arena.players[p_name] = nil
|
|
|
|
-- se ha abbandonato mentre aveva degli spettatori, li riassegno
|
|
if arena_lib.is_player_spectated(p_name) then
|
|
for sp_name, _ in pairs(arena_lib.get_player_spectators(p_name)) do
|
|
arena_lib.find_and_spectate_player(sp_name)
|
|
end
|
|
end
|
|
|
|
-- se è stato eliminato e c'è la spettatore, non va rimosso, bensì solo spostato in spettatore
|
|
if reason == 1 and mod_ref.spectate_mode and arena.players_amount > 0 then
|
|
eliminate_player(mod_ref, arena, p_name, executioner)
|
|
arena_lib.enter_spectate_mode(p_name, arena)
|
|
|
|
-- sennò procedo a rimuoverlo normalmente
|
|
else
|
|
operations_before_leaving_arena(mod_ref, arena, p_name, reason)
|
|
arena.players_and_spectators[p_name] = nil
|
|
arena.past_present_players_inside[p_name] = nil
|
|
players_in_game[p_name] = nil
|
|
|
|
handle_leaving_callbacks(mod_ref, arena, p_name, reason, executioner)
|
|
end
|
|
end
|
|
|
|
-- se è già in celebrazione, non c'è bisogno di andare oltre
|
|
if arena.in_celebration then return end
|
|
|
|
-- se l'ultimo rimasto abbandona con alt+f4, evito il crash
|
|
if arena.players_amount == 0 then
|
|
arena_lib.end_arena(mod_ref, mod, arena)
|
|
|
|
-- 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 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, winning_team_id)
|
|
|
|
|
|
-- se invece erano rimasti solo 2 giocatori in partita, l'altro vince
|
|
elseif arena.players_amount == 1 then
|
|
|
|
if reason == 1 then
|
|
arena_lib.send_message_in_arena(arena, "players", mod_ref.prefix .. S("You're the last player standing: you win!"))
|
|
else
|
|
arena_lib.send_message_in_arena(arena, "players", mod_ref.prefix .. S("You win the game due to not enough players"))
|
|
end
|
|
|
|
for pl_name, stats in pairs(arena.players) do
|
|
arena_lib.load_celebration(mod, arena, pl_name)
|
|
end
|
|
end
|
|
|
|
arena_lib.update_sign(arena)
|
|
end
|
|
|
|
|
|
|
|
function arena_lib.force_arena_ending(mod, arena, sender)
|
|
|
|
local mod_ref = arena_lib.mods[mod]
|
|
|
|
-- se il minigioco non esiste, annullo
|
|
if not mod_ref then
|
|
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] This minigame doesn't exist!")))
|
|
return end
|
|
|
|
-- se l'arena non esiste, annullo
|
|
if not arena then
|
|
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] This arena doesn't exist!")))
|
|
return end
|
|
|
|
-- se l'arena non è in partita, annullo
|
|
if not arena.in_game then
|
|
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] No ongoing game!")))
|
|
return end
|
|
|
|
arena_lib.send_message_in_arena(arena, "both", minetest.colorize("#d69298", S("The arena has been forcibly terminated by @1", sender)))
|
|
arena_lib.end_arena(mod_ref, mod, arena, nil, true)
|
|
return true
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
----------------------------------------------
|
|
-----------------GETTERS----------------------
|
|
----------------------------------------------
|
|
|
|
function arena_lib.get_mod_by_player(p_name)
|
|
if arena_lib.is_player_in_arena(p_name) then
|
|
return players_in_game[p_name].minigame
|
|
elseif arena_lib.is_player_in_queue(p_name) then
|
|
return arena_lib.get_mod_by_queuing_player(p_name)
|
|
end
|
|
end
|
|
|
|
|
|
|
|
function arena_lib.get_arena_by_player(p_name)
|
|
if arena_lib.is_player_in_arena(p_name) then -- è in partita
|
|
local mod = players_in_game[p_name].minigame
|
|
local arenaID = players_in_game[p_name].arenaID
|
|
|
|
return arena_lib.mods[mod].arenas[arenaID]
|
|
elseif arena_lib.is_player_in_queue(p_name) then -- è in coda
|
|
return arena_lib.get_arena_by_queuing_player(p_name)
|
|
end
|
|
end
|
|
|
|
|
|
|
|
function arena_lib.get_arenaID_by_player(p_name)
|
|
if players_in_game[p_name] then
|
|
return players_in_game[p_name].arenaID
|
|
end
|
|
end
|
|
|
|
|
|
|
|
function arena_lib.get_players_in_game()
|
|
return players_in_game
|
|
end
|
|
|
|
|
|
|
|
function arena_lib.get_players_in_minigame(mod, to_player)
|
|
local players_in_minigame = {}
|
|
|
|
if to_player then
|
|
for pl_name, info in pairs(players_in_game) do
|
|
if mod == info.minigame then
|
|
table.insert(players_in_minigame, minetest.get_player_by_name(pl_name))
|
|
end
|
|
end
|
|
else
|
|
for pl_name, info in pairs(players_in_game) do
|
|
if mod == info.minigame then
|
|
table.insert(players_in_minigame, pl_name)
|
|
end
|
|
end
|
|
end
|
|
|
|
return players_in_minigame
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
----------------------------------------------
|
|
---------------FUNZIONI LOCALI----------------
|
|
----------------------------------------------
|
|
|
|
function assign_team_spawner(spawn_points, ID, p_name, p_team_ID)
|
|
|
|
for i = ID, #spawn_points do
|
|
if p_team_ID == spawn_points[i].teamID then
|
|
minetest.get_player_by_name(p_name):set_pos(spawn_points[i].pos)
|
|
return i+1
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
function operations_before_entering_arena(mod_ref, mod, arena, arena_ID, p_name)
|
|
|
|
players_temp_storage[p_name] = {}
|
|
|
|
-- applico eventuale musica di sottofondo
|
|
if arena.bgm then
|
|
players_temp_storage[p_name].bgm_handle = minetest.sound_play(arena.bgm.track, {
|
|
gain = arena.bgm.gain,
|
|
pitch = arena.bgm.pitch,
|
|
to_player = p_name,
|
|
loop = true,
|
|
})
|
|
end
|
|
|
|
local player = minetest.get_player_by_name(p_name)
|
|
|
|
-- cambio eventuale illuminazione
|
|
if arena.lighting then
|
|
players_temp_storage[p_name].lighting = {
|
|
light = player:get_day_night_ratio()
|
|
}
|
|
|
|
local lighting = arena.lighting
|
|
if lighting.light then
|
|
player:override_day_night_ratio(lighting.light)
|
|
end
|
|
|
|
--TODO MT 5.6: set_lighting (shadows)
|
|
end
|
|
|
|
-- cambio eventuale volta celeste
|
|
if arena.celestial_vault then
|
|
local celvault = arena.celestial_vault
|
|
|
|
if celvault.sky then
|
|
players_temp_storage[p_name].celvault_sky = arena_lib.temp.get_sky(player)
|
|
player:set_sky(celvault.sky)
|
|
end
|
|
|
|
if celvault.sun then
|
|
players_temp_storage[p_name].celvault_sun = player:get_sun()
|
|
player:set_sun(celvault.sun)
|
|
end
|
|
|
|
if celvault.moon then
|
|
players_temp_storage[p_name].celvault_moon = player:get_moon()
|
|
player:set_moon(celvault.moon)
|
|
end
|
|
|
|
if celvault.stars then
|
|
players_temp_storage[p_name].celvault_stars = player:get_stars()
|
|
player:set_stars(celvault.stars)
|
|
end
|
|
|
|
if celvault.clouds then
|
|
players_temp_storage[p_name].celvault_clouds = player:get_clouds()
|
|
player:set_clouds(celvault.clouds)
|
|
end
|
|
end
|
|
|
|
-- nascondo i nomi se l'opzione è abilitata
|
|
if not mod_ref.show_nametags then
|
|
player:set_nametag_attributes({color = {a = 0, r = 255, g = 255, b = 255}})
|
|
end
|
|
|
|
-- disattivo eventualmente la minimappa
|
|
if not mod_ref.show_minimap then
|
|
player:hud_set_flags({minimap = false})
|
|
end
|
|
|
|
-- chiudo eventuali formspec
|
|
minetest.close_formspec(p_name, "")
|
|
|
|
-- svuoto eventualmente l'inventario, decidendo se e come salvarlo
|
|
if not mod_ref.keep_inventory then
|
|
arena_lib.store_inventory(player)
|
|
end
|
|
|
|
-- salvo la hotbar se c'è la spettatore o la hotbar personalizzata
|
|
if mod_ref.spectate_mode or mod_ref.hotbar then
|
|
players_temp_storage[p_name].hotbar_slots = player:hud_get_hotbar_itemcount()
|
|
players_temp_storage[p_name].hotbar_background_image = player:hud_get_hotbar_image()
|
|
players_temp_storage[p_name].hotbar_selected_image = player:hud_get_hotbar_selected_image()
|
|
end
|
|
|
|
if not arena_lib.is_player_spectating(p_name) then
|
|
operations_before_playing_arena(mod_ref, arena, p_name)
|
|
end
|
|
|
|
-- registro giocatori nella tabella apposita
|
|
players_in_game[p_name] = {minigame = mod, arenaID = arena_ID}
|
|
end
|
|
|
|
|
|
|
|
function operations_before_playing_arena(mod_ref, arena, p_name)
|
|
|
|
arena.past_present_players[p_name] = true
|
|
arena.past_present_players_inside[p_name] = true
|
|
|
|
-- aggiungo eventuale contenitore mod spettatore
|
|
if mod_ref.spectate_mode then
|
|
arena_lib.add_spectate_p_container(p_name)
|
|
end
|
|
|
|
local player = minetest.get_player_by_name(p_name)
|
|
|
|
-- applico eventuale fov
|
|
if mod_ref.fov then
|
|
players_temp_storage[p_name].fov = player:get_fov()
|
|
player:set_fov(mod_ref.fov)
|
|
end
|
|
|
|
-- applico eventuale scostamento camera
|
|
if mod_ref.camera_offset then
|
|
players_temp_storage[p_name].camera_offset = {player:get_eye_offset()}
|
|
player:set_eye_offset(mod_ref.camera_offset[1], mod_ref.camera_offset[2])
|
|
end
|
|
|
|
-- cambio eventuale colore texture (richiede i team)
|
|
if arena.teams_enabled and mod_ref.teams_color_overlay then
|
|
player:set_properties({
|
|
textures = {player:get_properties().textures[1] .. "^[colorize:" .. mod_ref.teams_color_overlay[arena.players[p_name].teamID] .. ":85"}
|
|
})
|
|
end
|
|
|
|
-- cambio l'eventuale hotbar
|
|
if mod_ref.hotbar then
|
|
local hotbar = mod_ref.hotbar
|
|
|
|
if hotbar.slots then
|
|
player:hud_set_hotbar_itemcount(hotbar.slots)
|
|
end
|
|
|
|
if hotbar.background_image then
|
|
player:hud_set_hotbar_image(hotbar.background_image)
|
|
end
|
|
|
|
if hotbar.selected_image then
|
|
player:hud_set_hotbar_selected_image(hotbar.selected_image)
|
|
end
|
|
end
|
|
|
|
-- imposto eventuale fisica personalizzata
|
|
if mod_ref.in_game_physics then
|
|
player:set_physics_override(mod_ref.in_game_physics)
|
|
end
|
|
|
|
-- li sgancio da eventuali entità (non lo faccio agli spettatori perché sono già
|
|
-- agganciati al giocatore, sennò cadono nel vuoto)
|
|
player:set_detach()
|
|
|
|
-- se il danno da caduta è disabilitato, disattivo il flash all'impatto
|
|
if table.indexof(mod_ref.disabled_damage_types, "fall") > 0 then
|
|
players_temp_storage[p_name].armor_groups = player:get_armor_groups()
|
|
|
|
local armor_groups = player:get_armor_groups()
|
|
|
|
armor_groups.fall_damage_add_percent = -100
|
|
player:set_armor_groups(armor_groups)
|
|
end
|
|
|
|
-- li curo
|
|
player:set_hp(minetest.PLAYER_MAX_HP_DEFAULT)
|
|
|
|
-- assegno eventuali proprietà giocatori
|
|
for k, v in pairs(mod_ref.player_properties) do
|
|
if type(v) == "table" then
|
|
arena.players[p_name][k] = table.copy(v)
|
|
else
|
|
arena.players[p_name][k] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- reason parametro opzionale che passo solo quando potrebbe essersi disconnesso
|
|
function operations_before_leaving_arena(mod_ref, arena, p_name, reason)
|
|
|
|
-- disattivo eventuale musica di sottofondo
|
|
if arena.bgm then
|
|
minetest.sound_stop(players_temp_storage[p_name].bgm_handle)
|
|
end
|
|
|
|
local player = minetest.get_player_by_name(p_name)
|
|
|
|
-- reimposto eventuale illuminazione
|
|
if arena.lighting then
|
|
player:override_day_night_ratio(players_temp_storage[p_name].lighting.light)
|
|
end
|
|
|
|
-- reimposto eventuale volta celeste
|
|
if arena.celestial_vault then
|
|
local celvault = arena.celestial_vault
|
|
|
|
if celvault.sky then
|
|
player:set_sky(players_temp_storage[p_name].celvault_sky)
|
|
end
|
|
if celvault.sun then
|
|
player:set_sun(players_temp_storage[p_name].celvault_sun)
|
|
end
|
|
if celvault.moon then
|
|
player:set_moon(players_temp_storage[p_name].celvault_moon)
|
|
end
|
|
if celvault.stars then
|
|
player:set_stars(players_temp_storage[p_name].celvault_stars)
|
|
end
|
|
if celvault.clouds then
|
|
player:set_clouds(players_temp_storage[p_name].celvault_clouds)
|
|
end
|
|
end
|
|
|
|
-- svuoto eventualmente l'inventario e ripristino gli oggetti
|
|
if not mod_ref.keep_inventory then
|
|
player:get_inventory():set_list("main", {})
|
|
player:get_inventory():set_list("craft",{})
|
|
|
|
if arena_lib.STORE_INVENTORY_MODE ~= "none" then
|
|
arena_lib.restore_inventory(p_name)
|
|
end
|
|
end
|
|
|
|
local armor_groups = players_temp_storage[p_name].armor_groups
|
|
|
|
-- riassegno eventuali gruppi armatura (per il flash da impatto caduta)
|
|
if armor_groups then
|
|
player:set_armor_groups(armor_groups)
|
|
end
|
|
|
|
-- ripristino gli HP
|
|
player:set_hp(minetest.PLAYER_MAX_HP_DEFAULT)
|
|
|
|
-- teletrasporto con un po' di rumore
|
|
local clean_pos = mod_ref.settings.hub_spawn_point
|
|
local noise_x = math.random(-1.5, 1.5)
|
|
local noise_z = math.random(-1.5, 1.5)
|
|
local noise_pos = {x = clean_pos.x + noise_x, y = clean_pos.y, z = clean_pos.z + noise_z}
|
|
player:set_pos(noise_pos)
|
|
-- TEMP: waiting for https://github.com/minetest/minetest/issues/12092 to be fixed. Forcing the teleport twice on two different steps
|
|
minetest.after(0.1, function()
|
|
if not minetest.get_player_by_name(p_name) then return end
|
|
player:set_pos(noise_pos)
|
|
end)
|
|
|
|
-- se si è disconnesso, salta il resto
|
|
if reason == 0 then
|
|
players_temp_storage[p_name] = nil
|
|
return
|
|
end
|
|
|
|
-- se ha partecipato come giocatore
|
|
if arena.past_present_players_inside[p_name] then
|
|
|
|
-- rimuovo eventuale contenitore mod spettatore
|
|
if mod_ref.spectate_mode then
|
|
arena_lib.remove_spectate_p_container(p_name)
|
|
end
|
|
|
|
-- ripristino eventuali texture
|
|
if arena.teams_enabled and mod_ref.teams_color_overlay then
|
|
player:set_properties({
|
|
textures = {string.match(player:get_properties().textures[1], "(.*)^%[")}
|
|
})
|
|
end
|
|
|
|
-- ripristino eventuale fov
|
|
if mod_ref.fov then
|
|
player:set_fov(players_temp_storage[p_name].fov)
|
|
end
|
|
|
|
-- ripristino eventuale camera
|
|
if mod_ref.camera_offset then
|
|
player:set_eye_offset(players_temp_storage[p_name].camera_offset[1], players_temp_storage[p_name].camera_offset[2])
|
|
end
|
|
end
|
|
|
|
-- se c'è la spettatore o l'hotbar personalizzata, la ripristino
|
|
if mod_ref.spectate_mode or mod_ref.hotbar then
|
|
player:hud_set_hotbar_itemcount(players_temp_storage[p_name].hotbar_slots)
|
|
player:hud_set_hotbar_image(players_temp_storage[p_name].hotbar_background_image)
|
|
player:hud_set_hotbar_selected_image(players_temp_storage[p_name].hotbar_selected_image)
|
|
end
|
|
|
|
-- se ho hub_manager, restituisco gli oggetti e imposto fisica della lobby
|
|
if minetest.get_modpath("hub_manager") then
|
|
hub_manager.set_items(player)
|
|
hub_manager.set_hub_physics(player)
|
|
else
|
|
player:set_physics_override(arena_lib.SERVER_PHYSICS)
|
|
end
|
|
|
|
-- riattivo la minimappa eventualmente disattivata
|
|
player:hud_set_flags({minimap = true})
|
|
|
|
-- ripristino nomi
|
|
player:set_nametag_attributes({color = {a = 255, r = 255, g = 255, b = 255}})
|
|
|
|
-- svuoto lo storage temporaneo
|
|
players_temp_storage[p_name] = nil
|
|
end
|
|
|
|
|
|
|
|
function eliminate_player(mod_ref, arena, p_name, executioner)
|
|
if executioner then
|
|
arena_lib.send_message_in_arena(arena, "both", minetest.colorize("#f16a54", "<<< " .. S("@1 has been eliminated by @2", p_name, executioner)))
|
|
else
|
|
arena_lib.send_message_in_arena(arena, "both", minetest.colorize("#f16a54", "<<< " .. S("@1 has been eliminated", p_name)))
|
|
end
|
|
|
|
if mod_ref.on_eliminate then
|
|
mod_ref.on_eliminate(arena, p_name)
|
|
end
|
|
|
|
for _, callback in ipairs(arena_lib.registered_on_eliminate) do
|
|
callback(mod_ref, arena, p_name)
|
|
end
|
|
end
|
|
|
|
|
|
|
|
function handle_leaving_callbacks(mod_ref, arena, p_name, reason, executioner, is_spectator)
|
|
|
|
local msg_color = reason < 3 and "#f16a54" or "#d69298"
|
|
local spect_str = ""
|
|
|
|
if is_spectator then
|
|
msg_color = "#cfc6b8"
|
|
spect_str = " (" .. S("spectator") .. ")"
|
|
end
|
|
|
|
-- se si è disconnesso
|
|
if reason == 0 then
|
|
arena_lib.send_message_in_arena(arena, "both", minetest.colorize(msg_color, "<<< " .. p_name .. spect_str))
|
|
|
|
-- DEPRECATED: remove in 6.0
|
|
if mod_ref.on_disconnect then
|
|
minetest.log("warning", "[ARENA_LIB] on_kick is deprecated. Please use on_quit with reason `0` instead")
|
|
mod_ref.on_disconnect(arena, p_name, is_spectator)
|
|
end
|
|
|
|
-- se è stato eliminato (no spettatore, quindi viene rimosso dall'arena)
|
|
elseif reason == 1 then
|
|
eliminate_player(mod_ref, arena, p_name, executioner)
|
|
|
|
-- se è stato cacciato
|
|
elseif reason == 2 then
|
|
if executioner then
|
|
arena_lib.send_message_in_arena(arena, "both", minetest.colorize(msg_color, "<<< " .. S("@1 has been kicked by @2", p_name, executioner) .. spect_str))
|
|
else
|
|
arena_lib.send_message_in_arena(arena, "both", minetest.colorize(msg_color, "<<< " .. S("@1 has been kicked", p_name) .. spect_str))
|
|
end
|
|
|
|
-- DEPRECATED: remove in 6.0
|
|
if mod_ref.on_kick then
|
|
minetest.log("warning", "[ARENA_LIB] on_kick is deprecated. Please use on_quit with reason `2` instead")
|
|
mod_ref.on_kick(arena, p_name, is_spectator)
|
|
end
|
|
|
|
-- se ha abbandonato
|
|
elseif reason == 3 then
|
|
arena_lib.send_message_in_arena(arena, "both", minetest.colorize(msg_color, "<<< " .. S("@1 has quit the match", p_name) .. spect_str))
|
|
end
|
|
|
|
if mod_ref.on_quit then
|
|
mod_ref.on_quit(arena, p_name, is_spectator, reason)
|
|
end
|
|
|
|
for _, callback in ipairs(arena_lib.registered_on_quit) do
|
|
callback(mod_ref, arena, p_name, is_spectator, reason)
|
|
end
|
|
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,
|
|
time = 0.6,
|
|
minpos = p_pos,
|
|
maxpos = p_pos,
|
|
minvel = {x=-2, y=-2, z=-2},
|
|
maxvel = {x=2, y=2, z=2},
|
|
minsize = 1,
|
|
maxsize = 3,
|
|
texture = "arenalib_winparticle.png"
|
|
})
|
|
end
|
|
|
|
|
|
|
|
function time_start(mod_ref, arena)
|
|
|
|
if arena.on_celebration or not arena.in_game then return end
|
|
|
|
if mod_ref.time_mode == "incremental" then
|
|
arena.current_time = arena.current_time + 1
|
|
else
|
|
arena.current_time = arena.current_time - 1
|
|
end
|
|
|
|
if arena.current_time <= 0 then
|
|
assert(mod_ref.on_timeout, "[ARENA_LIB] " .. S("[!] on_timeout callback must be declared to properly use a decreasing timer!"))
|
|
mod_ref.on_timeout(arena)
|
|
return
|
|
elseif mod_ref.on_time_tick then
|
|
mod_ref.on_time_tick(arena)
|
|
end
|
|
|
|
minetest.after(1, function()
|
|
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
|