From 244d27237957f613cfcdb0b35223097a110333b4 Mon Sep 17 00:00:00 2001 From: Zughy <4279489-marco_a@users.noreply.gitlab.com> Date: Fri, 27 May 2022 21:12:15 +0000 Subject: [PATCH] Spectate areas implements #101 --- DOCS.md | 21 +- init.lua | 1 + locale/arena_lib.it.tr | 1 + locale/template.txt | 1 + src/api/core.lua | 2 + src/api/in_game.lua | 9 +- src/spectate/spectate_dummy.lua | 13 + src/spectate/spectate_main.lua | 346 ++++++++++++++-------- src/spectate/spectate_tools.lua | 25 +- textures/arenalib_spectate_changearea.png | Bin 0 -> 176 bytes 10 files changed, 289 insertions(+), 130 deletions(-) create mode 100644 src/spectate/spectate_dummy.lua create mode 100644 textures/arenalib_spectate_changearea.png diff --git a/DOCS.md b/DOCS.md index 0dba056..23c4f58 100644 --- a/DOCS.md +++ b/DOCS.md @@ -122,8 +122,10 @@ To customise your mod even more, there are a few empty callbacks you can use. Th * `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_change_spectated_target(mod, function(arena, sp_name, target, prev_target))`: called when a spectator (`sp_name`) changes who or what they're spectating, including when they get assigned someone to spectate at entering the arena. - * `target` can only be the player name for now, the same goes for `prev_target` (if any). Entities and locations will be hopefully added in the future +* `arena_lib.on_change_spectated_target(mod, function(arena, sp_name, t_type, t_name, prev_type, prev_spectated))`: called when a spectator (`sp_name`) changes who or what they're spectating, including when they get assigned someone to spectate at entering the arena. + * `t_type` represents the type of the target (either `"player"`, `"entity"` or `"area"`) + * `t_name` its name. If it's an entity or an area, it'll be the name used to register it through the `arena_lib.add_spectate...` functions + * if they were following someone/something else earlier, `prev_type` and `prev_spectated` follow the same logic of the aforementioned parameters * Beware: as this gets called also when entering, keep in mind that it gets called before the `on_join` callback * `arena_lib.on_time_tick(mod, function(arena))`: called every second if `time_mode` is different from `"none"` * `arena_lib.on_timeout(mod, function(arena))`: called when the timer of an arena, if exists (`time_mode = "decremental"`), reaches 0. Not declaring it will make the server crash when time runs out @@ -236,11 +238,14 @@ There are also some other functions which might turn useful. They are: Default is 0 and these are mostly hardcoded in arena_lib already, so it's advised to not touch it and to use callbacks. The only exception is in case of manual elimination (i.e. in a murder minigame, so reason = 1). Executioner can be passed to tell who removed the player. By default, this happens when someone uses `/arenakick` and `/forceend`, so that these commands can't be abused without consequences for the admin. * `arena_lib.send_message_in_arena(arena, channel, msg, , )`: sends a message to all the players/spectators in that specific arena, according to what `channel` is: `"players"`, `"spectators"` or `"both"`. If `teamID` is specified, it'll be only sent to the players inside that very team. On the contrary, if `except_teamID` is `true`, it'll be sent to every player BUT the ones in the specified team. These last two fields are pointless if `channel` is equal to `"spectators"` -* `arena_lib.add_spectable_target(mod, arena_name, t_type, t_name, target)`: adds to the current ongoing match a spectable target, allowing spectators to spectate more than just players. `t_type` indicates the target type, and for now can only be `"entity"`. `t_name` is the name that will appear in the spectator info hotbar, and `target` is the entity itself. When the entity is removed/unloaded, automatically calls `remove_spectable_target(...)` -* `arena_lib.remove_spectable_target(mod, arena_name, t_type, t_name)`: removes a target from the spectable targets of an ongoing match +* `arena_lib.add_spectate_entity(mod, arena, e_name, entity)`: adds to the current ongoing match a spectatable entity, allowing spectators to spectate more than just players. `e_name` is the name that will appear in the spectator info hotbar, and `entity` the `luaentity` table. When the entity is removed/unloaded, automatically calls `remove_spectate_entity(...)` +* `arena_lib.add_spectate_area(mod, arena, pos_name, pos)`: same as `add_spectate_entity`, but it adds an area instead. `pos` is a table containing the coordinates of the area to spectate +* `arena_lib.remove_spectate_entity(mod, arena, e_name)`: removes an entity from the spectatable entities of an ongoing match +* `arena_lib.remove_spectate_area(mod, arena, pos_name)`: removes an area from the spectatable areas of an ongoing match * `arena_lib.is_player_spectating(sp_name)`: returns whether a player is spectating a match, as a boolean * `arena_lib.is_player_spectated(p_name)`: returns whether a player is being spectated * `arena_lib.is_entity_spectated(mod, arena_name, e_name)`: returns whether an entity is being spectated +* `arena_lib.is_area_spectated(mod, arena_name, pos_name)`: returns whether an area is being spectated * `arena_lib.is_arena_in_edit_mode(arena_name)`: returns whether the arena is in edit mode or not, as a boolean * `arena_lib.is_player_in_edit_mode(p_name)`: returns whether a player is editing an arena, as a boolean @@ -258,8 +263,8 @@ Executioner can be passed to tell who removed the player. By default, this happe * `arena_lib.get_active_teams(arena)`: returns an ordered table having as values the ID of teams that are not empty * `arena_lib.get_player_spectators(p_name)`: returns a list containing all the people currently spectating `p_name`. Format `{sp_name = true}` * `arena_lib.get_player_spectated(sp_name)`: returns the player `sp_name` is currently spectating, if any -* `arena_lib.get_spectable_entities(mod, arena_name)`: returns a table containing all the spectable entities of `arena_name`, if any. Format `{e_name = entity}`, where `e_name` is the name used to register the entity in `add_spectable_target(...)` -* `arena_lib.get_spectable_entities_amount(mod, arena_name)`: returns the amount of spectable entities currently present in `arena_name`, if any +* `arena_lib.get_spectate_entities(mod, arena_name)`: returns a table containing all the spectatable entities of `arena_name`, if any. Format `{e_name = entity}`, where `e_name` is the name used to register the entity in `add_spectate_entity(...)` and `entity` the `luaentity` table +* `arena_lib.get_spectate_areas(mod, arena_name)`: same as in `get_spectate_entities(...)` but for areas. Entities returned in the table are the dummy ObjectRef entities put at the area coordinates * `arena_lib.get_player_in_edit_mode(arena_name)`: returns the name of the player who's editing `arena_name`, if any ### 1.10 Things you don't want to do with a light heart @@ -290,6 +295,8 @@ An arena is a table having as a key an ID and as a value its parameters. They ar * `players_amount_per_team`: (table) separately stores how many players currently are in a given team. Format `{[teamID] = amount}`. If teams are disabled, it's `nil` * `spectators_amount`: (int) separately stores how many spectators are inside the arena * `spectators_amount_per_team`: (table) like `players_amount_per_team`, but for spectators +* `spectate_entities_amount`: (int) the amount of entities that can be currently spectated in an ongoing game. If spectate mode is disabled, it's `nil`. Outside of ongoing games is always `nil` +* `spectate_areas_amount`: (int) like `spectate_entities_amount` but for areas * `spawn_points`: (table) contains information about the spawn points. Format `{[spawnID] = {pos = coords, teamID = team ID}}`. If teams are disabled, `teamID` is `nil` * `max_players`: (string) default is 4. When this value is reached, queue time decreases to 5 if it's not lower already * `min_players`: (string) default is 2. When this value is reached, a queue starts @@ -466,7 +473,7 @@ An arena comes in 4 phases: ### 2.4 Spectate mode Every minigame has this mode enabled by default. As the name suggests, it allows people to spectate a match, and there are two ways to enter this mode: the first is by getting eliminated (`remove_player_from_arena` with `1` as a reason), while the other is through the very sign of the arena. In this last case, users just need to right-click the sign and press the "eye" button to be turned into spectators (a game must be in progress). While in this state, they can't interact in any way with the actual match: neither by hitting entities/blocks, nor by writing in chat. The latter, more precisely, is a separated chat that spectators and spectators only are able to read. Vice versa, they're not able to read the players one. -By default, spectate mode allows to follow players, but it also allows modders to expand it to entities and (not currently implemented) areas. To do that, have a look at `arena_lib.add_spectable_target(...)` +By default, spectate mode allows to follow players, but it also allows modders to expand it to entities and areas. To do that, have a look at `arena_lib.add_spectate_entity(...)` and `arena_lib.add_spectate_area(...)`
## 3. About the author(s) diff --git a/init.lua b/init.lua index 82840d5..d5d772b 100755 --- a/init.lua +++ b/init.lua @@ -28,6 +28,7 @@ dofile(srcpath .. "/editor/tools_sky.lua") dofile(srcpath .. "/editor/tools_spawner.lua") dofile(srcpath .. "/hud/hud_main.lua") dofile(srcpath .. "/hud/hud_waypoints.lua") +dofile(srcpath .. "/spectate/spectate_dummy.lua") dofile(srcpath .. "/spectate/spectate_main.lua") dofile(srcpath .. "/spectate/spectate_hand.lua") dofile(srcpath .. "/spectate/spectate_tools.lua") diff --git a/locale/arena_lib.it.tr b/locale/arena_lib.it.tr index 7165705..dbe9f96 100755 --- a/locale/arena_lib.it.tr +++ b/locale/arena_lib.it.tr @@ -286,4 +286,5 @@ Currently spectating: @1=Stai seguendo: @1 Change player=Cambia giocatore Change team=Cambia squadra Change entity=Cambia entità +Change area=Cambia area Enter the match=Entra in partita diff --git a/locale/template.txt b/locale/template.txt index ff9b27e..cc5e4c1 100755 --- a/locale/template.txt +++ b/locale/template.txt @@ -286,4 +286,5 @@ Currently spectating: @1= Change player= Change team= Change entity= +Change area= Enter the match= diff --git a/src/api/core.lua b/src/api/core.lua index 3d09ee3..0dc4232 100755 --- a/src/api/core.lua +++ b/src/api/core.lua @@ -34,6 +34,8 @@ local arena_default = { players_amount_per_team = nil, spectators_amount = 0, spectators_amount_per_team = nil, + spectate_entities_amount = nil, + spectate_areas_amount = nil, spawn_points = {}, -- KEY: ids, VALUE: {pos, teamID} max_players = 4, min_players = 2, diff --git a/src/api/in_game.lua b/src/api/in_game.lua index 36d788d..6206a8e 100755 --- a/src/api/in_game.lua +++ b/src/api/in_game.lua @@ -88,6 +88,8 @@ function arena_lib.load_arena(mod, arena_ID) -- 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 @@ -272,7 +274,12 @@ function arena_lib.end_arena(mod_ref, mod, arena, winners, is_forced) operations_before_leaving_arena(mod_ref, arena, pl_name) end - arena_lib.unload_spectate_containers(mod, arena.name) + -- 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 = {} diff --git a/src/spectate/spectate_dummy.lua b/src/spectate/spectate_dummy.lua new file mode 100644 index 0000000..355fbdd --- /dev/null +++ b/src/spectate/spectate_dummy.lua @@ -0,0 +1,13 @@ +-- used for areas +local dummy = { + initial_properties = { + physical = false, + visual = "sprite", + visual_size = {x = 0, y = 0, z = 0}, + collisionbox = {0, 0, 0, 0, 0, 0}, + + textures = { "blank.png" } + } +} + +minetest.register_entity("arena_lib:spectate_dummy", dummy) diff --git a/src/spectate/spectate_main.lua b/src/spectate/spectate_main.lua index 6f9891a..3719315 100755 --- a/src/spectate/spectate_main.lua +++ b/src/spectate/spectate_main.lua @@ -6,9 +6,10 @@ local function set_spectator() end local players_in_spectate_mode = {} -- KEY: player name, VALUE: {(string) minigame, (int) arenaID, (string) type, (string) spectating} local spectate_temp_storage = {} -- KEY: player_name, VALUE: {(table) camera_offset} local players_spectated = {} -- KEY: player name, VALUE: {(string) spectator(s) = true} -local entities_spectated = {} -- KEY: [mod][arena][entity name], VALUE: {(string) spectator(s) = true} -local areas_spectated = {} -local entities_storage = {} -- KEY: [mod][arena][entity_name], VALUE: entity +local entities_spectated = {} -- KEY: [mod][arena_name][entity name], VALUE: {(string) spectator(s) = true} +local areas_spectated = {} -- KEY: [mod][arena_name][area_name], VALUE: {(string) spectator(s) = true} +local entities_storage = {} -- KEY: [mod][arena_name][entity_name], VALUE: entity +local areas_storage = {} -- KEY: [mod][arena_name][area_name], VALUE: dummy entity @@ -31,18 +32,29 @@ function arena_lib.init_spectate_containers(mod, arena_name) if not entities_storage[mod] then entities_storage[mod] = {} end + if not areas_storage[mod] then + areas_storage[mod] = {} + end entities_spectated[mod][arena_name] = {} areas_spectated[mod][arena_name] = {} entities_storage[mod][arena_name] = {} + areas_storage[mod][arena_name] = {} end function arena_lib.unload_spectate_containers(mod, arena_name) - entities_spectated[mod][arena_name] = nil -- non c'è bisogno di cancellare X[mod], al massimo rimangono vuote + -- rimuovo tutte le entità fantoccio delle aree + for _, dummy_entity in pairs(arena_lib.get_spectate_areas(mod, arena_name)) do + dummy_entity:remove() + end + + -- non c'è bisogno di cancellare X[mod], al massimo rimangono vuote + entities_spectated[mod][arena_name] = nil areas_spectated[mod][arena_name] = nil entities_storage[mod][arena_name] = nil + areas_storage[mod][arena_name] = nil end @@ -58,10 +70,9 @@ function arena_lib.remove_spectate_p_container(p_name) end - ----------------------------------------------- ----------------------CORE--------------------- ----------------------------------------------- +---------------------------- +-- entering / leaving +---------------------------- function arena_lib.enter_spectate_mode(p_name, arena) @@ -213,94 +224,9 @@ end -function arena_lib.add_spectable_target(mod, arena_name, t_type, t_name, target) - - local arena_ID, arena = arena_lib.get_arena_by_name(mod, arena_name) - - if not arena.in_game then return end - - if t_type == "entity" then - local old_deact = target.on_deactivate - - -- aggiungo sull'on_deactivate la funzione per rimuoverla dalla spettatore - target.on_deactivate = function(...) - local ret = old_deact and old_deact(...) - - arena_lib.remove_spectable_target(mod, arena_name, t_type, t_name) - - return ret - end - - -- la aggiungo - entities_spectated[mod][arena_name][t_name] = {} - entities_storage[mod][arena_name][t_name] = target - - -- se è l'unica entità registrata, aggiungo lo slot per seguire le entità - if arena_lib.get_spectable_entities_amount(mod, arena_name) == 1 then - for sp_name, _ in pairs(arena.spectators) do - override_hotbar(minetest.get_player_by_name(sp_name), mod, arena) - end - end - - elseif t_type == "area" then - -- TODO registrare aree - end - -end - - - -function arena_lib.remove_spectable_target(mod, arena_name, t_type, t_name) - - local arenaID, arena = arena_lib.get_arena_by_name(mod, arena_name) - - -- se l'entità viene rimossa quando la partita è già finita, interrompi o crasha - if not arena.in_game then return end - - if t_type == "entity" then - entities_storage[mod][arena_name][t_name] = nil - - -- se non ci sono più entità, fai sparire l'icona - if not next(entities_storage[mod][arena_name]) then - for sp_name, _ in pairs(arena.spectators) do - local spectator = minetest.get_player_by_name(sp_name) - override_hotbar(spectator, mod, arena) - end - end - - for sp_name, _ in pairs(entities_spectated[mod][arena_name][t_name]) do - arena_lib.find_and_spectate_entity(mod, arena_name, sp_name) - end - elseif t_type == "area" then - --TODO - end -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] and next(players_spectated[p_name]) -end - - - -function arena_lib.is_entity_spectated(mod, arena_name, e_name) - return entities_spectated[mod][arena_name][e_name] and next(entities_spectated[mod][arena_name][e_name]) -end - - +---------------------------- +-- find next spectatatable target +---------------------------- function arena_lib.find_and_spectate_player(sp_name, change_team) @@ -365,6 +291,7 @@ function arena_lib.find_and_spectate_player(sp_name, change_team) local watching_ID = spectator:get_meta():get_int("arenalib_watchID") local new_ID = players_amount <= watching_ID and 1 or watching_ID + 1 + local mod = arena_lib.get_mod_by_player(sp_name) -- trovo il giocatore da seguire -- squadre: @@ -373,7 +300,7 @@ function arena_lib.find_and_spectate_player(sp_name, change_team) for i = 1, #players_team do if i == new_ID then - set_spectator(spectator, "player", players_team[i], i) + set_spectator(mod, arena_name, spectator, "player", players_team[i], i) return true end end @@ -384,7 +311,7 @@ function arena_lib.find_and_spectate_player(sp_name, change_team) for pl_name, _ in pairs(arena.players) do if i == new_ID then - set_spectator(spectator, "player", pl_name, i) + set_spectator(mod, arena.name, spectator, "player", pl_name, i) return true end @@ -395,14 +322,16 @@ end -function arena_lib.find_and_spectate_entity(mod, arena_name, sp_name) +function arena_lib.find_and_spectate_entity(mod, arena, sp_name) + + local e_amount = arena.spectate_entities_amount -- se non ci sono entità da seguire, segui un giocatore - if not next(entities_storage[mod][arena_name]) then + if e_amount == 0 then arena_lib.find_and_spectate_player(sp_name) return end - local e_amount = arena_lib.get_spectable_entities_amount(mod, arena_name) + local arena_name = arena.name local prev_spectated = players_in_spectate_mode[sp_name].spectating -- se è l'unica entità rimasta e la si stava già seguendo @@ -419,10 +348,10 @@ function arena_lib.find_and_spectate_entity(mod, arena_name, sp_name) local new_ID = e_amount <= current_ID and 1 or current_ID + 1 local i = 1 - for en_name, _ in pairs(entities_spectated[mod][arena_name]) do + for en_name, _ in pairs(entities_storage[mod][arena_name]) do if i == new_ID then - set_spectator(spectator, "entity", en_name, i) + set_spectator(mod, arena_name, spectator, "entity", en_name, i) return true end @@ -432,6 +361,183 @@ end +function arena_lib.find_and_spectate_area(mod, arena, sp_name) + + local ar_amount = arena.spectate_areas_amount + + -- se non ci sono aree da seguire, segui un giocatore + if ar_amount == 0 then + arena_lib.find_and_spectate_player(sp_name) + return end + + local arena_name = arena.name + local prev_spectated = players_in_spectate_mode[sp_name].spectating + + -- se è l'unica area rimasta e la si stava già seguendo + if ar_amount == 1 and prev_spectated and next(areas_spectated[mod][arena_name])[sp_name] then + return end + + local spectator = minetest.get_player_by_name(sp_name) + + if players_in_spectate_mode[sp_name].type ~= "area" then + spectator:get_meta():set_int("arenalib_watchID", 0) + end + + local current_ID = spectator:get_meta():get_int("arenalib_watchID") + local new_ID = ar_amount <= current_ID and 1 or current_ID + 1 + local i = 1 + + for pos_name, _ in pairs(areas_storage[mod][arena_name]) do + + if i == new_ID then + set_spectator(mod, arena_name, spectator, "area", pos_name, i) + return true + end + + i = i +1 + end +end + + + + + +---------------------------------------------- +---------------------CORE--------------------- +---------------------------------------------- + + + +function arena_lib.add_spectate_entity(mod, arena, e_name, entity) + + if not arena.in_game then return end + + local arena_name = arena.name + local old_deact = entity.on_deactivate + + -- aggiungo sull'on_deactivate la funzione per rimuoverla dalla spettatore + entity.on_deactivate = function(...) + local ret = old_deact and old_deact(...) + + arena_lib.remove_spectate_entity(mod, arena, e_name) + + return ret + end + + -- la aggiungo + entities_spectated[mod][arena_name][e_name] = {} + entities_storage[mod][arena_name][e_name] = entity + arena.spectate_entities_amount = arena.spectate_entities_amount + 1 + + -- se è l'unica entità registrata, aggiungo lo slot per seguire le entità + if arena.spectate_entities_amount == 1 then + for sp_name, _ in pairs(arena.spectators) do + override_hotbar(minetest.get_player_by_name(sp_name), mod, arena) + end + end +end + + + +function arena_lib.add_spectate_area(mod, arena, pos_name, pos) + + if not arena.in_game then return end + + minetest.forceload_block(pos, true) + + local dummy_entity = minetest.add_entity(pos, "arena_lib:spectate_dummy") + local arena_name = arena.name + + areas_spectated[mod][arena_name][pos_name] = {} + areas_storage[mod][arena_name][pos_name] = dummy_entity + arena.spectate_areas_amount = arena.spectate_areas_amount + 1 + + -- se è l'unica area registrata, aggiungo lo slot per seguire le aree + if arena.spectate_areas_amount == 1 then + for sp_name, _ in pairs(arena.spectators) do + override_hotbar(minetest.get_player_by_name(sp_name), mod, arena) + end + end + +end + + + +function arena_lib.remove_spectate_entity(mod, arena, e_name) + + if not arena.in_game then return end -- nel caso il minigioco si sia scordata di cancellarla, all'ucciderla fuori dalla partita non crasha + local arena_name = arena.name + + entities_storage[mod][arena_name][e_name] = nil + arena.spectate_entities_amount = arena.spectate_entities_amount - 1 + + -- se non ci sono più entità, fai sparire l'icona + if arena.spectate_entities_amount == 0 then + for sp_name, _ in pairs(arena.spectators) do + local spectator = minetest.get_player_by_name(sp_name) + override_hotbar(spectator, mod, arena) + end + end + + for sp_name, _ in pairs(entities_spectated[mod][arena_name][e_name]) do + arena_lib.find_and_spectate_entity(mod, arena, sp_name) + end +end + + + +function arena_lib.remove_spectate_area(mod, arena, pos_name) + + local arena_name = arena.name + + areas_storage[mod][arena_name][pos_name]:remove() + areas_storage[mod][arena_name][pos_name] = nil + arena.spectate_areas_amount = arena.spectate_areas_amount - 1 + + -- se non ci sono più aree, fai sparire l'icona + if arena.spectate_areas_amount == 0 then + for sp_name, _ in pairs(arena.spectators) do + local spectator = minetest.get_player_by_name(sp_name) + override_hotbar(spectator, mod, arena) + end + end + + for sp_name, _ in pairs(areas_spectated[mod][arena_name][pos_name]) do + arena_lib.find_and_spectate_area(mod, arena, sp_name) + end +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] and next(players_spectated[p_name]) +end + + + +function arena_lib.is_entity_spectated(mod, arena_name, e_name) + return entities_spectated[mod][arena_name][e_name] and next(entities_spectated[mod][arena_name][e_name]) +end + + + +function arena_lib.is_area_spectated(mod, arena_name, pos_name) + return areas_spectated[mod][arena_name][pos_name] and next(areas_spectated[mod][arena_name][pos_name]) +end + + + ---------------------------------------------- @@ -452,18 +558,14 @@ end -function arena_lib.get_spectable_entities(mod, arena_name) +function arena_lib.get_spectate_entities(mod, arena_name) return entities_storage[mod][arena_name] end -function arena_lib.get_spectable_entities_amount(mod, arena_name) - local i = 0 - for k, v in pairs(entities_storage[mod][arena_name]) do - i = i + 1 - end - return i +function arena_lib.get_spectate_areas(mod, arena_name) + return areas_storage[mod][arena_name] end @@ -474,16 +576,14 @@ end ---------------FUNZIONI LOCALI---------------- ---------------------------------------------- -function set_spectator(spectator, type, name, i) +function set_spectator(mod, arena_name, spectator, type, name, i) local sp_name = spectator:get_player_name() - local mod = arena_lib.get_mod_by_player(sp_name) - local arena_name = arena_lib.get_arena_by_player(sp_name).name local prev_spectated = players_in_spectate_mode[sp_name].spectating + local prev_type = players_in_spectate_mode[sp_name].type -- se stava già seguendo qualcuno, lo rimuovo da questo if prev_spectated then - local prev_type = players_in_spectate_mode[sp_name].type if prev_type == "player" then players_spectated[prev_spectated][sp_name] = nil elseif prev_type == "entity" then @@ -503,14 +603,18 @@ function set_spectator(spectator, type, name, i) spectator:set_hp(target:get_hp() > 0 and target:get_hp() or 1) elseif type == "entity" then - entities_spectated[mod][arena_name][name][sp_name] = true target = entities_storage[mod][arena_name][name].object spectator:set_attach(target, "", {x=0, y=-5, z=-20}, {x=0, y=0, z=0}) spectator:set_hp(target:get_hp() > 0 and target:get_hp() or 1) + elseif type == "area" then - -- TODO + areas_spectated[mod][arena_name][name][sp_name] = true + target = areas_storage[mod][arena_name][name] + + spectator:set_attach(target, "", {x=0, y=-5, z=-20}, {x=0, y=0, z=0}) + spectator:set_hp(minetest.PLAYER_MAX_HP_DEFAULT) end players_in_spectate_mode[sp_name].spectating = name @@ -524,9 +628,7 @@ function set_spectator(spectator, type, name, i) -- eventuale codice aggiuntivo if mod_ref.on_change_spectated_target then local arena = arena_lib.get_arena_by_player(sp_name) - target = name - local prev_target = prev_spectated - mod_ref.on_change_spectated_target(arena, sp_name, target, prev_target) + mod_ref.on_change_spectated_target(arena, sp_name, type, name, prev_type, prev_spectated) end end @@ -547,10 +649,14 @@ function override_hotbar(player, mod, arena) table.insert(tools, 2, "arena_lib:spectate_changeteam") end - if next(arena_lib.get_spectable_entities(mod, arena.name)) then + if next(arena_lib.get_spectate_entities(mod, arena.name)) then table.insert(tools, #tools, "arena_lib:spectate_changeentity") end + if next(arena_lib.get_spectate_areas(mod, arena.name)) then + table.insert(tools, #tools, "arena_lib:spectate_changearea") + end + if mod_ref.join_while_in_progress then table.insert(tools, #tools, "arena_lib:spectate_join") end diff --git a/src/spectate/spectate_tools.lua b/src/spectate/spectate_tools.lua index 7b299d9..feca312 100755 --- a/src/spectate/spectate_tools.lua +++ b/src/spectate/spectate_tools.lua @@ -53,9 +53,30 @@ minetest.register_tool("arena_lib:spectate_changeentity", { local p_name = user:get_player_name() local mod = arena_lib.get_mod_by_player(p_name) - local arena_name = arena_lib.get_arena_by_player(p_name).name + local arena = arena_lib.get_arena_by_player(p_name) - arena_lib.find_and_spectate_entity(mod, arena_name, p_name) + arena_lib.find_and_spectate_entity(mod, arena, p_name) + end + +}) + + + +minetest.register_tool("arena_lib:spectate_changearea", { + + description = S("Change area"), + inventory_image = "arenalib_spectate_changearea.png", + groups = {not_in_creative_inventory = 1, oddly_breakable_by_hand = "2"}, + on_place = function() end, + on_drop = function() end, + + on_use = function(itemstack, user) + + local p_name = user:get_player_name() + local mod = arena_lib.get_mod_by_player(p_name) + local arena = arena_lib.get_arena_by_player(p_name) + + arena_lib.find_and_spectate_area(mod, arena, p_name) end }) diff --git a/textures/arenalib_spectate_changearea.png b/textures/arenalib_spectate_changearea.png new file mode 100644 index 0000000000000000000000000000000000000000..2b8d235c304aa09fceeeeb8882e6829a85a460fa GIT binary patch literal 176 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPE^3h)VWb=S2q(9wJ5p||a-%}Q(Q zDi^QiE`?KovWz7`e!&b5&u*jvIX<2)jv*Ddk`oTFv9KzdES@xpVTR(8B}+IKv9^RX zi%2#KwJEf1U})a3v2)U-%^MX1Tmn2j1vCyR9C)!r=>W&YWgMmfM+8qLh$I}~X1Jox V`l>~8Nixt}22WQ%mvv4FO#l-2H{k#P literal 0 HcmV?d00001