mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-09-21 17:04:00 +00:00
Merge branch 'main' into feature/remove-warnings
This commit is contained in:
@@ -5,7 +5,7 @@ Adds a commands that allow admins to jail and unjail
|
||||
local Commands = require("modules/exp_commands")
|
||||
local format_player_name = Commands.format_player_name_locale
|
||||
|
||||
local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail
|
||||
local Jail = require("modules/exp_scenario/control/jail")
|
||||
|
||||
--- Puts a player into jail and removes all other roles.
|
||||
Commands.new("jail", { "exp-commands_jail.description" })
|
||||
|
||||
@@ -12,10 +12,9 @@ local Commands = require("modules/exp_commands")
|
||||
local format_player_name = Commands.format_player_name_locale
|
||||
|
||||
local Roles = require("modules/exp_roles")
|
||||
local EntityProtection = require("modules.exp_legacy.modules.control.protection") --- @dep modules.control.protection
|
||||
|
||||
local format_string = string.format
|
||||
local floor = math.floor
|
||||
local EntityProtection = require("modules/exp_scenario/control/protection")
|
||||
local get_entity_key = EntityProtection.get_entity_key
|
||||
local get_area_key = EntityProtection.get_area_key
|
||||
|
||||
local Selection = require("modules/exp_util/selection")
|
||||
local SelectEntities = Selection.connect("ExpCommand_ProtectEntity")
|
||||
@@ -28,21 +27,6 @@ Storage.register({
|
||||
renders = tbl.renders
|
||||
end)
|
||||
|
||||
--- Get the key used in protected_entities
|
||||
--- @param entity LuaEntity
|
||||
--- @return string
|
||||
local function get_entity_key(entity)
|
||||
return format_string("%i,%i", floor(entity.position.x), floor(entity.position.y))
|
||||
end
|
||||
|
||||
--- Get the key used in protected_areas
|
||||
--- TODO expose this from EntityProtection
|
||||
--- @param area BoundingBox.struct
|
||||
--- @return string
|
||||
local function get_area_key(area)
|
||||
return format_string("%i,%i", floor(area.left_top.x), floor(area.left_top.y))
|
||||
end
|
||||
|
||||
--- Show a protected entity to a player
|
||||
--- @param player LuaPlayer
|
||||
--- @param entity LuaEntity
|
||||
@@ -232,6 +216,6 @@ end
|
||||
|
||||
return {
|
||||
events = {
|
||||
[EntityProtection.events.on_repeat_violation] = on_repeat_violation,
|
||||
[EntityProtection.on_repeat_violation] = on_repeat_violation,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ Adds commands relating to spectate and follow
|
||||
]]
|
||||
|
||||
local Commands = require("modules/exp_commands")
|
||||
local Spectate = require("modules.exp_legacy.modules.control.spectate") --- @dep modules.control.spectate
|
||||
local Spectate = require("modules/exp_scenario/control/spectate")
|
||||
|
||||
--- Toggles spectator mode for the caller
|
||||
Commands.new("spectate", { "exp-commands_spectate.description-spectate" })
|
||||
|
||||
@@ -59,11 +59,13 @@ add(require("modules/exp_scenario/control/inventory_clear"))
|
||||
add(require("modules/exp_scenario/control/mine_depletion"))
|
||||
add(require("modules/exp_scenario/control/nuke_protection"))
|
||||
add(require("modules/exp_scenario/control/pollution_grading"))
|
||||
add(require("modules/exp_scenario/control/protection"))
|
||||
add(require("modules/exp_scenario/control/protection_jail"))
|
||||
add(require("modules/exp_scenario/control/report_jail"))
|
||||
add(require("modules/exp_scenario/control/research"))
|
||||
add(require("modules/exp_scenario/control/roles"))
|
||||
add(require("modules/exp_scenario/control/spawn_area"))
|
||||
add(require("modules/exp_scenario/control/spectate"))
|
||||
add(require("modules/exp_scenario/control/station_auto_name"))
|
||||
|
||||
--- Guis
|
||||
|
||||
@@ -81,8 +81,8 @@ end
|
||||
|
||||
--- Repeated protected entity mining
|
||||
if config.entity_protection then
|
||||
local EntityProtection = require("modules.exp_legacy.modules.control.protection")
|
||||
events[EntityProtection.events.on_repeat_violation] = function(event)
|
||||
local EntityProtection = require("modules/exp_scenario/control/protection")
|
||||
events[EntityProtection.on_repeat_violation] = function(event)
|
||||
local player_name = get_player_name(event)
|
||||
emit_event{
|
||||
title = "Entity Protection",
|
||||
@@ -133,8 +133,8 @@ end
|
||||
|
||||
--- When a player is jailed or unjailed
|
||||
if config.player_jail then
|
||||
local Jail = require("modules.exp_legacy.modules.control.jail")
|
||||
events[Jail.events.on_player_jailed] = function(event)
|
||||
local Jail = require("modules/exp_scenario/control/jail")
|
||||
events[Jail.on_player_jailed] = function(event)
|
||||
local player_name, by_player_name = get_player_name(event)
|
||||
emit_event{
|
||||
title = "Jail",
|
||||
@@ -147,7 +147,7 @@ if config.player_jail then
|
||||
},
|
||||
}
|
||||
end
|
||||
events[Jail.events.on_player_unjailed] = function(event)
|
||||
events[Jail.on_player_unjailed] = function(event)
|
||||
local player_name, by_player_name = get_player_name(event)
|
||||
emit_event{
|
||||
title = "Unjail",
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
--[[-- Control - Jail
|
||||
Adds a way to jail players, the jail role suppresses all of their other roles
|
||||
]]
|
||||
|
||||
local Roles = require("modules/exp_roles")
|
||||
|
||||
--- @class ExpScenario_Jail
|
||||
local Jail = {
|
||||
--- Raised when a player is put into jail
|
||||
--- @type EventData.ExpScenario_Jail.on_player_jailed
|
||||
on_player_jailed = script.generate_event_name(),
|
||||
--- Raised when a player is taken out of jail
|
||||
--- @type EventData.ExpScenario_Jail.on_player_unjailed
|
||||
on_player_unjailed = script.generate_event_name(),
|
||||
}
|
||||
|
||||
--- @class EventData.ExpScenario_Jail.on_player_jailed : EventData
|
||||
--- @field player_index uint
|
||||
--- @field by_player_name string
|
||||
--- @field reason string
|
||||
|
||||
--- @class EventData.ExpScenario_Jail.on_player_unjailed : EventData
|
||||
--- @field player_index uint
|
||||
--- @field by_player_name string
|
||||
|
||||
--- The role given to jailed players, it has a higher priority than every other role
|
||||
--- @return ExpRoles.Role
|
||||
local function get_jail_role()
|
||||
return (assert(Roles.get_role_by_name("Jail"), "The Jail role does not exist"))
|
||||
end
|
||||
|
||||
--- Check if a player is in jail
|
||||
--- @param player LuaPlayer
|
||||
--- @return boolean
|
||||
function Jail.is_jailed(player)
|
||||
return get_jail_role():has_player(player)
|
||||
end
|
||||
|
||||
--- Put a player into jail, which suppresses all of their other roles
|
||||
--- @param player LuaPlayer
|
||||
--- @param by_player_name string
|
||||
--- @param reason string
|
||||
--- @return boolean # False when the player was already in jail
|
||||
function Jail.jail_player(player, by_player_name, reason)
|
||||
local role = get_jail_role()
|
||||
if role:has_player(player) then return false end
|
||||
|
||||
-- Stop whatever the player is doing, the jail permission group stops them from starting again
|
||||
player.walking_state = { walking = false, direction = player.walking_state.direction }
|
||||
player.riding_state = { acceleration = defines.riding.acceleration.nothing, direction = player.riding_state.direction }
|
||||
player.mining_state = { mining = false }
|
||||
player.shooting_state = { state = defines.shooting.not_shooting, position = player.shooting_state.position }
|
||||
player.picking_state = false
|
||||
player.repair_state = { repairing = false, position = player.repair_state.position }
|
||||
|
||||
role:assign(player, { by_player_name = by_player_name, silent = true })
|
||||
|
||||
script.raise_event(Jail.on_player_jailed, {
|
||||
player_index = player.index,
|
||||
by_player_name = by_player_name,
|
||||
reason = reason,
|
||||
})
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Take a player out of jail, which restores all of their other roles
|
||||
--- @param player LuaPlayer
|
||||
--- @param by_player_name string
|
||||
--- @return boolean # False when the player was not in jail
|
||||
function Jail.unjail_player(player, by_player_name)
|
||||
local role = get_jail_role()
|
||||
if not role:has_player(player) then return false end
|
||||
|
||||
role:unassign(player, { by_player_name = by_player_name, silent = true })
|
||||
|
||||
script.raise_event(Jail.on_player_unjailed, {
|
||||
player_index = player.index,
|
||||
by_player_name = by_player_name,
|
||||
})
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return Jail
|
||||
@@ -0,0 +1,237 @@
|
||||
--[[-- Control - Protection
|
||||
Protects entities and areas from being mined by players other than the one who placed them
|
||||
]]
|
||||
|
||||
local Storage = require("modules/exp_util/storage")
|
||||
local Roles = require("modules/exp_roles")
|
||||
local config = require("modules.exp_legacy.config.protection")
|
||||
|
||||
local format_string = string.format
|
||||
local floor = math.floor
|
||||
|
||||
--- @class ExpScenario_Protection
|
||||
local Protection = {
|
||||
--- Raised when a player mines a protected entity
|
||||
--- @type EventData.ExpScenario_Protection.on_player_mined_protected
|
||||
on_player_mined_protected = script.generate_event_name(),
|
||||
--- Raised when a player mines protected entities repeatedly, or one which always counts as repeated
|
||||
--- @type EventData.ExpScenario_Protection.on_repeat_violation
|
||||
on_repeat_violation = script.generate_event_name(),
|
||||
--- Names of entities which are always protected
|
||||
--- @type string[]
|
||||
protected_entity_names = config.always_protected_names,
|
||||
--- Types of entities which are always protected
|
||||
--- @type string[]
|
||||
protected_entity_types = config.always_protected_types,
|
||||
--- @package
|
||||
events = {},
|
||||
--- @package
|
||||
on_nth_tick = {},
|
||||
}
|
||||
|
||||
--- @class EventData.ExpScenario_Protection.on_player_mined_protected : EventData.on_pre_player_mined_item
|
||||
--- @class EventData.ExpScenario_Protection.on_repeat_violation : EventData.on_pre_player_mined_item
|
||||
|
||||
--- @class ExpScenario_Protection.Repeat
|
||||
--- @field last uint Tick of the last protected removal
|
||||
--- @field count number Protected removals since the last repeat violation
|
||||
|
||||
--- @param values string[]
|
||||
--- @return table<string, true>
|
||||
local function to_set(values)
|
||||
local set = {}
|
||||
for _, value in ipairs(values) do
|
||||
set[value] = true
|
||||
end
|
||||
return set
|
||||
end
|
||||
|
||||
local always_protected_names = to_set(config.always_protected_names)
|
||||
local always_protected_types = to_set(config.always_protected_types)
|
||||
local always_trigger_repeat_names = to_set(config.always_trigger_repeat_names)
|
||||
local always_trigger_repeat_types = to_set(config.always_trigger_repeat_types)
|
||||
|
||||
local protected_entities = {} --- @type table<uint, table<string, LuaEntity>> Keyed by surface index then entity key
|
||||
local protected_areas = {} --- @type table<uint, table<string, BoundingBox>> Keyed by surface index then area key
|
||||
local repeats = {} --- @type table<string, ExpScenario_Protection.Repeat> Keyed by player name
|
||||
|
||||
Storage.register({
|
||||
protected_entities = protected_entities,
|
||||
protected_areas = protected_areas,
|
||||
repeats = repeats,
|
||||
}, function(tbl)
|
||||
protected_entities = tbl.protected_entities
|
||||
protected_areas = tbl.protected_areas
|
||||
repeats = tbl.repeats
|
||||
end)
|
||||
|
||||
--- Get the key an entity is stored under
|
||||
--- @param entity LuaEntity
|
||||
--- @return string
|
||||
function Protection.get_entity_key(entity)
|
||||
return format_string("%i,%i", floor(entity.position.x), floor(entity.position.y))
|
||||
end
|
||||
|
||||
--- Get the key an area is stored under
|
||||
--- @param area BoundingBox
|
||||
--- @return string
|
||||
function Protection.get_area_key(area)
|
||||
return format_string("%i,%i", floor(area.left_top.x), floor(area.left_top.y))
|
||||
end
|
||||
|
||||
--- Protect an entity
|
||||
--- @param entity LuaEntity
|
||||
function Protection.add_entity(entity)
|
||||
local entities = protected_entities[entity.surface.index]
|
||||
if not entities then
|
||||
entities = {}
|
||||
protected_entities[entity.surface.index] = entities
|
||||
end
|
||||
entities[Protection.get_entity_key(entity)] = entity
|
||||
end
|
||||
|
||||
--- Remove the protection from an entity
|
||||
--- @param entity LuaEntity
|
||||
function Protection.remove_entity(entity)
|
||||
local entities = protected_entities[entity.surface.index]
|
||||
if not entities then return end
|
||||
entities[Protection.get_entity_key(entity)] = nil
|
||||
end
|
||||
|
||||
--- Get the protected entities on a surface, always protected entities are not included
|
||||
--- @param surface LuaSurface
|
||||
--- @return table<string, LuaEntity>
|
||||
function Protection.get_entities(surface)
|
||||
return protected_entities[surface.index] or {}
|
||||
end
|
||||
|
||||
--- Check if an entity is protected, either directly or by its name or type
|
||||
--- @param entity LuaEntity
|
||||
--- @return boolean
|
||||
function Protection.is_entity_protected(entity)
|
||||
if always_protected_names[entity.name] or always_protected_types[entity.type] then return true end
|
||||
local entities = protected_entities[entity.surface.index]
|
||||
if not entities then return false end
|
||||
return entities[Protection.get_entity_key(entity)] == entity
|
||||
end
|
||||
|
||||
--- Protect every position within an area
|
||||
--- @param surface LuaSurface
|
||||
--- @param area BoundingBox
|
||||
function Protection.add_area(surface, area)
|
||||
local areas = protected_areas[surface.index]
|
||||
if not areas then
|
||||
areas = {}
|
||||
protected_areas[surface.index] = areas
|
||||
end
|
||||
areas[Protection.get_area_key(area)] = area
|
||||
end
|
||||
|
||||
--- Remove the protection from an area
|
||||
--- @param surface LuaSurface
|
||||
--- @param area BoundingBox
|
||||
function Protection.remove_area(surface, area)
|
||||
local areas = protected_areas[surface.index]
|
||||
if not areas then return end
|
||||
areas[Protection.get_area_key(area)] = nil
|
||||
end
|
||||
|
||||
--- Get the protected areas on a surface
|
||||
--- @param surface LuaSurface
|
||||
--- @return table<string, BoundingBox>
|
||||
function Protection.get_areas(surface)
|
||||
return protected_areas[surface.index] or {}
|
||||
end
|
||||
|
||||
--- Check if a position is within a protected area
|
||||
--- @param surface LuaSurface
|
||||
--- @param position MapPosition
|
||||
--- @return boolean
|
||||
function Protection.is_position_protected(surface, position)
|
||||
local areas = protected_areas[surface.index]
|
||||
if not areas then return false end
|
||||
for _, area in pairs(areas) do
|
||||
if area.left_top.x <= position.x and area.left_top.y <= position.y
|
||||
and area.right_bottom.x >= position.x and area.right_bottom.y >= position.y
|
||||
then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Players are never checked against their own entities, and can be excluded by permission or admin status
|
||||
--- @param player LuaPlayer
|
||||
--- @param entity LuaEntity
|
||||
--- @return boolean
|
||||
local function is_ignored(player, entity)
|
||||
if config.ignore_admins and player.admin then return true end
|
||||
if entity.last_user == nil or entity.last_user.index == player.index then return true end
|
||||
if config.ignore_permission and Roles.player_has_permission(player, config.ignore_permission) then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Raise the protection events, the event data is reused with the name replaced
|
||||
--- @param event EventData.on_pre_player_mined_item
|
||||
--- @param player LuaPlayer
|
||||
local function raise_violation(event, player)
|
||||
local player_repeats = repeats[player.name]
|
||||
if not player_repeats then
|
||||
player_repeats = { last = game.tick, count = 0 }
|
||||
repeats[player.name] = player_repeats
|
||||
end
|
||||
player_repeats.last = game.tick
|
||||
player_repeats.count = player_repeats.count + 1
|
||||
|
||||
script.raise_event(Protection.on_player_mined_protected, event)
|
||||
|
||||
local entity = event.entity
|
||||
local always_repeat = always_trigger_repeat_names[entity.name] or always_trigger_repeat_types[entity.type]
|
||||
if always_repeat or player_repeats.count >= config.repeat_count then
|
||||
player_repeats.count = 0
|
||||
script.raise_event(Protection.on_repeat_violation, event)
|
||||
end
|
||||
end
|
||||
|
||||
--- Raise the protection events when a protected entity is mined, then forget the entity
|
||||
--- @param event EventData.on_pre_player_mined_item
|
||||
local function on_pre_player_mined_item(event)
|
||||
local entity = event.entity
|
||||
local player = game.players[event.player_index]
|
||||
if
|
||||
not is_ignored(player, entity)
|
||||
and (Protection.is_entity_protected(entity) or Protection.is_position_protected(entity.surface, entity.position))
|
||||
then
|
||||
raise_violation(event, player)
|
||||
end
|
||||
|
||||
Protection.remove_entity(entity)
|
||||
end
|
||||
|
||||
--- Forget an entity once it no longer exists
|
||||
--- @param event { entity: LuaEntity }
|
||||
local function on_entity_removed(event)
|
||||
Protection.remove_entity(event.entity)
|
||||
end
|
||||
|
||||
--- Forget protected removals older than the repeat lifetime
|
||||
local function clear_old_repeats()
|
||||
local old = game.tick - config.repeat_lifetime
|
||||
for player_name, player_repeats in pairs(repeats) do
|
||||
if player_repeats.last <= old then
|
||||
repeats[player_name] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local e = defines.events
|
||||
|
||||
Protection.events[e.on_pre_player_mined_item] = on_pre_player_mined_item
|
||||
Protection.events[e.on_space_platform_pre_mined] = on_entity_removed
|
||||
Protection.events[e.on_robot_pre_mined] = on_entity_removed
|
||||
Protection.events[e.on_entity_died] = on_entity_removed
|
||||
Protection.events[e.script_raised_destroy] = on_entity_removed
|
||||
Protection.on_nth_tick[config.refresh_rate] = clear_old_repeats
|
||||
|
||||
return Protection
|
||||
@@ -4,8 +4,8 @@ When a player triggers protection multiple times they are automatically jailed
|
||||
|
||||
local ExpUtil = require("modules/exp_util")
|
||||
local Storage = require("modules/exp_util/storage")
|
||||
local Jail = require("modules.exp_legacy.modules.control.jail")
|
||||
local Protection = require("modules.exp_legacy.modules.control.protection")
|
||||
local Jail = require("modules/exp_scenario/control/jail")
|
||||
local Protection = require("modules/exp_scenario/control/protection")
|
||||
|
||||
local format_player_name = ExpUtil.format_player_name_locale
|
||||
|
||||
@@ -41,7 +41,7 @@ local e = defines.events
|
||||
|
||||
return {
|
||||
events = {
|
||||
[Protection.events.on_repeat_violation] = on_repeat_violation,
|
||||
[Protection.on_repeat_violation] = on_repeat_violation,
|
||||
[e.on_player_left_game] = on_player_left_game,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ When a player is reported, the player is automatically jailed if the combined pl
|
||||
]]
|
||||
|
||||
local ExpUtil = require("modules/exp_util")
|
||||
local Jail = require("modules.exp_legacy.modules.control.jail")
|
||||
local Jail = require("modules/exp_scenario/control/jail")
|
||||
local Reports = require("modules.exp_legacy.modules.control.reports")
|
||||
|
||||
local max = math.max
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
--[[-- Control - Spectate
|
||||
Lets players spectate without losing their character, and follow other players or entities
|
||||
]]
|
||||
|
||||
local Storage = require("modules/exp_util/storage")
|
||||
local Gui = require("modules/exp_gui")
|
||||
|
||||
--- @class ExpScenario_Spectate
|
||||
local Spectate = {
|
||||
--- @package
|
||||
events = {},
|
||||
}
|
||||
|
||||
--- @class ExpScenario_Spectate.Following
|
||||
--- @field player LuaPlayer
|
||||
--- @field target LuaPlayer | LuaEntity
|
||||
--- @field position MapPosition Where the player was after the last update, moving away stops following
|
||||
--- @field started_spectate boolean True when start_follow put the player into spectator mode
|
||||
--- @field stop boolean? Set when following must end on the next tick
|
||||
|
||||
local following = {} --- @type table<uint, ExpScenario_Spectate.Following> Keyed by player index
|
||||
local spectating = {} --- @type table<uint, LuaEntity> The character a player returns to, keyed by player index
|
||||
|
||||
Storage.register({
|
||||
following = following,
|
||||
spectating = spectating,
|
||||
}, function(tbl)
|
||||
following = tbl.following
|
||||
spectating = tbl.spectating
|
||||
end)
|
||||
|
||||
--- Label shown while following, clicking it or pressing escape stops following
|
||||
--- @class ExpScenario_Spectate.follow_label: ExpElement
|
||||
--- @overload fun(parent: LuaGuiElement, target: LuaPlayer | LuaEntity): LuaGuiElement
|
||||
local follow_label = Gui.define("spectate/follow_label")
|
||||
:draw(function(_, parent, target)
|
||||
Gui.destroy_if_valid(parent.follow_label)
|
||||
|
||||
local label = parent.add{
|
||||
type = "label",
|
||||
name = "follow_label",
|
||||
style = "frame_title",
|
||||
caption = { "exp_spectate.follow-label", target.name },
|
||||
}
|
||||
|
||||
local player = Gui.get_player(parent)
|
||||
local res = player.display_resolution
|
||||
label.location = { 0, res.height - 150 }
|
||||
label.style.width = res.width
|
||||
label.style.horizontal_align = "center"
|
||||
player.opened = label
|
||||
|
||||
return label
|
||||
end)
|
||||
:on_click(function(_, player)
|
||||
Spectate.stop_follow(player)
|
||||
end)
|
||||
:on_closed(function(_, player)
|
||||
-- set_controller can not be called during on_gui_closed, so the next update stops following
|
||||
local data = following[player.index]
|
||||
if data then data.stop = true end
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Check if a player is in spectator mode
|
||||
--- @param player LuaPlayer
|
||||
--- @return boolean
|
||||
function Spectate.is_spectating(player)
|
||||
return player.controller_type == defines.controllers.spectator
|
||||
end
|
||||
|
||||
--- Put a player into spectator mode while keeping their character
|
||||
--- @param player LuaPlayer
|
||||
--- @return boolean # False when the player was already spectating or has no character
|
||||
function Spectate.start_spectate(player)
|
||||
if spectating[player.index] or not player.character then return false end
|
||||
local character = player.character
|
||||
local opened = player.opened
|
||||
|
||||
player.set_controller{ type = defines.controllers.spectator }
|
||||
player.associate_character(character)
|
||||
spectating[player.index] = character
|
||||
|
||||
if opened then player.opened = opened end -- Changing controller closes the opened gui
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Return a player to their character, or respawn them if it was killed
|
||||
--- @param player LuaPlayer
|
||||
function Spectate.stop_spectate(player)
|
||||
local character = spectating[player.index]
|
||||
spectating[player.index] = nil
|
||||
|
||||
if character and character.valid then
|
||||
local opened = player.opened
|
||||
player.teleport(character.position, character.surface)
|
||||
player.set_controller{ type = defines.controllers.character, character = character }
|
||||
if opened then player.opened = opened end -- Changing controller closes the opened gui
|
||||
else
|
||||
player.ticks_to_respawn = 300
|
||||
end
|
||||
end
|
||||
|
||||
--- Check if a player is following something
|
||||
--- @param player LuaPlayer
|
||||
--- @return boolean
|
||||
function Spectate.is_following(player)
|
||||
return following[player.index] ~= nil
|
||||
end
|
||||
|
||||
--- Put a player into spectator mode and keep their camera on a target as it moves
|
||||
--- @param player LuaPlayer
|
||||
--- @param target LuaPlayer | LuaEntity
|
||||
function Spectate.start_follow(player, target)
|
||||
local started_spectate = Spectate.start_spectate(player)
|
||||
|
||||
follow_label(player.gui.screen, target)
|
||||
player.teleport(target.position, target.surface)
|
||||
following[player.index] = {
|
||||
player = player,
|
||||
target = target,
|
||||
position = player.position,
|
||||
started_spectate = started_spectate,
|
||||
}
|
||||
end
|
||||
|
||||
--- Give a player their camera back, returning them to their character if start_follow took it
|
||||
--- @param player LuaPlayer
|
||||
function Spectate.stop_follow(player)
|
||||
local data = following[player.index]
|
||||
if data and data.started_spectate and Spectate.is_spectating(player) then
|
||||
Spectate.stop_spectate(player)
|
||||
end
|
||||
|
||||
Gui.destroy_if_valid(player.gui.screen.follow_label)
|
||||
following[player.index] = nil
|
||||
end
|
||||
|
||||
--- Move a following player onto their target, or stop following when they have moved away or regained a character
|
||||
--- @param data ExpScenario_Spectate.Following
|
||||
local function update_following(data)
|
||||
local player, target = data.player, data.target
|
||||
local position = player.position
|
||||
if
|
||||
data.stop
|
||||
or player.character
|
||||
or not target.valid
|
||||
or position.x ~= data.position.x
|
||||
or position.y ~= data.position.y
|
||||
then
|
||||
Spectate.stop_follow(player)
|
||||
else
|
||||
player.teleport(target.position, target.surface)
|
||||
data.position = player.position
|
||||
end
|
||||
end
|
||||
|
||||
local function on_tick()
|
||||
for _, data in pairs(following) do
|
||||
update_following(data)
|
||||
end
|
||||
end
|
||||
|
||||
--- Stop following when a player leaves, and stop anyone who was following them
|
||||
--- @param event EventData.on_pre_player_left_game
|
||||
local function on_pre_player_left_game(event)
|
||||
local player = game.players[event.player_index]
|
||||
Spectate.stop_follow(player)
|
||||
for _, data in pairs(following) do
|
||||
if data.target == player then
|
||||
Spectate.stop_follow(data.player)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local e = defines.events
|
||||
|
||||
Spectate.events[e.on_tick] = on_tick
|
||||
Spectate.events[e.on_pre_player_left_game] = on_pre_player_left_game
|
||||
|
||||
return Spectate
|
||||
@@ -557,3 +557,6 @@ chat-jailed=__1__ was jailed because they removed too many protected entities. P
|
||||
|
||||
[exp_report-jail]
|
||||
chat-jailed=__1__ was jailed because they were reported too many times. Please wait for a moderator.
|
||||
|
||||
[exp_spectate]
|
||||
follow-label=Following __1__.\nClick here or press escape to stop following.
|
||||
|
||||
Reference in New Issue
Block a user