local S = minetest.get_translator("arena_lib") local function override_hotbar() end local function set_spectator() end local players_in_spectate_mode = {} -- KEY: player name, VALUE: {(string) minigame, (int) arenaID, (string) spectating} local players_spectated = {} -- KEY: player name, VALUE: {(string) spectator(s) = true} local spectate_temp_storage = {} -- KEY: player_name, VALUE: {(table) camera_offset} function arena_lib.enter_spectate_mode(p_name, arena) local mod = arena_lib.get_mod_by_player(p_name) -- se non supporta la spettatore if not arena_lib.mods[mod].spectate_mode then minetest.chat_send_player(p_name, minetest.colorize("#e6482e", S("[!] Spectate mode not supported!"))) return end -- se l'arena non è abilitata if not arena.enabled then minetest.chat_send_player(p_name, minetest.colorize("#e6482e", S("[!] The arena is not enabled!"))) return end -- se non è in corso if not arena.in_game then minetest.chat_send_player(p_name, minetest.colorize("#e6482e", S("[!] No ongoing game!"))) return end local arena_ID = arena_lib.get_arenaID_by_player(p_name) local team_ID = #arena.teams > 1 and 1 or nil players_in_spectate_mode[p_name] = { minigame = mod, arenaID = arena_ID, teamID = team_ID} arena.spectators[p_name] = true arena.players_and_spectators[p_name] = true arena.spectators_amount = arena.spectators_amount + 1 local player = minetest.get_player_by_name(p_name) -- applico mano finta player:get_inventory():set_size("hand", 1) player:get_inventory():add_item("hand", "arena_lib:spectate_hand") -- se il giocatore non è mai entrato in partita, lo salvo nello spazio di archiviazione temporaneo if not arena.past_present_players_inside[p_name] then spectate_temp_storage[p_name] = {} spectate_temp_storage[p_name].camera_offset = player:get_eye_offset() end -- applicazione parametri vari local current_properties = table.copy(player:get_properties()) players_in_spectate_mode[p_name].properties = current_properties player:set_properties({ visual_size = {x = 0, y = 0}, makes_footstep_sound = false, collisionbox = {0}, pointable = false }) player:set_eye_offset({x = 0, y = -2, z = -25}, {x=0, y=0, z=0}) player:set_nametag_attributes({color = {a = 0}}) -- inizia a seguire arena_lib.find_and_spectate_player(p_name) override_hotbar(player, mod, arena) return true end function arena_lib.leave_spectate_mode(p_name, to_join_match) local arena = arena_lib.get_arena_by_player(p_name) if to_join_match then --TODO-TEMP: 5.4, aspettare o dà problemi con after minetest.chat_send_player(p_name, "[!] SoonTM!") return --TODO: questi check ha senso ridurli in un luogo unico per quando si prova a entrare, dato che appaiono pure sui cartelli --[[ -- se è piena if arena.players_amount == arena.max_players * #arena.teams then minetest.chat_send_player(p_name, minetest.colorize("#e6482e", S("[!] The arena is already full!"))) return end -- se è in celebrazione if arena.in_celebration then minetest.chat_send_player(p_name, minetest.colorize("#e6482e", S("[!] The arena is loading, try again in a few seconds!"))) return end ]] else arena.players_and_spectators[p_name] = nil end arena.spectators[p_name] = nil arena.spectators_amount = arena.spectators_amount -1 local player = minetest.get_player_by_name(p_name) -- rimuovo mano finta player:get_inventory():set_size("hand", 0) -- se il giocatore non è mai entrato in partita, riassegno le proprietà salvate qui if not arena.past_present_players_inside[p_name] then player:set_eye_offset(spectate_temp_storage[p_name].camera_offset[1], spectate_temp_storage[p_name].camera_offset[2]) spectate_temp_storage[p_name] = nil else player:set_eye_offset({x=0, y=0, z=0}, {x=0, y=0, z=0}) end player:set_detach() player:set_properties(players_in_spectate_mode[p_name].properties) player:get_meta():set_int("arenalib_watchID", 0) arena_lib.HUD_hide("hotbar", p_name) local target = players_in_spectate_mode[p_name].spectating -- rimuovo dal database locale players_spectated[target][p_name] = nil players_in_spectate_mode[p_name] = nil end ---------------------------------------------- --------------------UTILS--------------------- ---------------------------------------------- function arena_lib.is_player_spectating(sp_name) return players_in_spectate_mode[sp_name] ~= nil end function arena_lib.is_player_spectated(p_name) return players_spectated[p_name] ~= nil end function arena_lib.find_and_spectate_player(sp_name, change_team) local spectator = minetest.get_player_by_name(sp_name) local arena = arena_lib.get_arena_by_player(sp_name) local prev_spectated = players_in_spectate_mode[sp_name].spectating local watching_ID = spectator:get_meta():get_int("arenalib_watchID") local team_ID = players_in_spectate_mode[sp_name].teamID local players_amount -- se l'ultimo rimasto ha abbandonato (es. alt+f4), rispedisco subito fuori senza che cada all'infinito con rischio di crash if arena.players_amount == 0 then arena_lib.remove_player_from_arena(sp_name, 3) return end -- se c'è rimasto solo un giocatore e già lo si seguiva, annullo if arena.players_amount == 1 and prev_spectated and arena.players[prev_spectated] then return end -- calcolo giocatori massimi tra cui ruotare -- squadre: if #arena.teams > 1 then -- se è l'unico rimasto nella squadra e già lo si seguiva, annullo if arena.players_amount_per_team[team_ID] == 1 and not change_team and prev_spectated and arena.players[prev_spectated] then return end -- se il giocatore seguito era l'ultimo membro della sua squadra, la imposto da cambiare if arena.players_amount_per_team[team_ID] == 0 then change_team = true end -- eventuale cambio squadra sul quale eseguire il calcolo if change_team then arena.spectators_amount_per_team[team_ID] = arena.spectators_amount_per_team[team_ID] - 1 local active_teams = arena_lib.get_active_teams(arena) if team_ID >= active_teams[#active_teams] then team_ID = active_teams[1] else for i = team_ID + 1, #arena.teams do if arena.players_amount_per_team[i] ~= 0 then team_ID = i break end end end players_in_spectate_mode[sp_name].teamID = team_ID arena.spectators_amount_per_team[team_ID] = arena.spectators_amount_per_team[team_ID] + 1 end players_amount = arena.players_amount_per_team[team_ID] -- no squadre: else players_amount = arena.players_amount end local new_ID = players_amount <= watching_ID and 1 or watching_ID + 1 local i = 0 -- trovo il giocatore da seguire -- squadre: if #arena.teams > 1 then for _, pl_name in pairs(arena_lib.get_players_in_team(arena, team_ID)) do i = i + 1 if i == new_ID then set_spectator(spectator, pl_name, i, prev_spectated) return true end end -- no squadre: else for pl_name, _ in pairs(arena.players) do i = i + 1 if i == new_ID then set_spectator(spectator, pl_name, i, prev_spectated) return true end end end end ---------------------------------------------- -----------------GETTERS---------------------- ---------------------------------------------- function arena_lib.get_player_spectators(p_name) return players_spectated[p_name] end function arena_lib.get_player_spectated(sp_name) if arena_lib.is_player_spectating(sp_name) then return players_in_spectate_mode[sp_name].spectating end end ---------------------------------------------- ---------------FUNZIONI LOCALI---------------- ---------------------------------------------- function set_spectator(spectator, p_name, i, prev_spectated) local sp_name = spectator:get_player_name() -- se stava già seguendo qualcuno, lo rimuovo da questo if prev_spectated then players_spectated[prev_spectated][sp_name] = nil if not next(players_spectated[prev_spectated]) then players_spectated[prev_spectated] = nil end end if not arena_lib.is_player_spectated(p_name) then players_spectated[p_name] = {} end players_spectated[p_name][sp_name] = true players_in_spectate_mode[sp_name].spectating = p_name local target = minetest.get_player_by_name(p_name) spectator:set_attach(target, "", {x=0, y=-5, z=-20}, {x=0, y=0, z=0}) spectator:get_meta():set_int("arenalib_watchID", i) arena_lib.HUD_send_msg("hotbar", sp_name, S("Currently spectating: @1", p_name)) end function override_hotbar(player, mod, arena) player:get_inventory():set_list("main", {}) player:get_inventory():set_list("craft",{}) local mod_ref = arena_lib.mods[mod] local tools = { "arena_lib:spectate_changeplayer", "arena_lib:spectate_quit" } if #arena.teams > 1 then table.insert(tools, 2, "arena_lib:spectate_changeteam") end if mod_ref.join_while_in_progress then table.insert(tools, #tools, "arena_lib:spectate_join") end minetest.after(0, function() player:hud_set_hotbar_image("arenalib_gui_hotbar" .. #tools .. ".png") player:hud_set_hotbar_itemcount(#tools) player:get_inventory():set_list("main", tools) end) end