using Content.Server.Chat.Systems;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Events;
using Content.Shared._CP14.Respawn;
using Content.Shared.Administration.Managers;
using Content.Shared.GameTicking;
using Content.Shared.Ghost;
using Content.Shared.Preferences;
using JetBrains.Annotations;
using Robust.Shared.Audio;
using Robust.Shared.Network;
using Robust.Shared.Player;
namespace Content.Server._CP14.Respawn;
public sealed partial class CP14RespawnSystem : EntitySystem
{
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly ISharedAdminManager _admin = default!;
///
/// We keep a list of all characters connected in a round to prevent the same character from re-entering the round.
/// Of course, we only check by character name, and this is easy to circumvent by renaming the character,
/// but the main goal here is to make the player understand that this is not the right thing to do.
/// If a player abuses the ability to re-enter a round, the administration will take care of it.
///
private Dictionary> _usedCharacters = new();
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(OnRespawnAction);
SubscribeLocalEvent(OnBeforePlayerSpawn);
SubscribeLocalEvent(OnRoundEnd);
}
private void OnRoundEnd(RoundStartingEvent ev)
{
_usedCharacters.Clear();
}
private void OnBeforePlayerSpawn(CP14PlayerSpawnAttemptEvent ev)
{
if (_admin.IsAdmin(ev.Player, true))
return;
if (!_usedCharacters.TryGetValue(ev.Player.UserId, out var usedCharacters))
{
usedCharacters = [];
_usedCharacters[ev.Player.UserId] = usedCharacters;
}
if (usedCharacters.Contains(ev.Profile.Name))
{
var filter = Filter.Empty().AddPlayer(ev.Player);
_chat.DispatchFilteredAnnouncement(
filter,
Loc.GetString("cp14-respawn-same-char-bloked"),
colorOverride: Color.Red,
announcementSound: new SoundPathSpecifier("/Audio/Effects/beep1.ogg"),
sender: "Server");
ev.Cancel();
return;
}
usedCharacters.Add(ev.Profile.Name);
}
private void OnRespawnAction(Entity ent, ref CP14RespawnAction args)
{
if (!TryComp(ent, out var actor))
return;
_gameTicker.Respawn(actor.PlayerSession);
}
}
///
/// Called before a player spawns for a specific character. Can be canceled by prohibiting connection for that character.
///
[PublicAPI]
public sealed class CP14PlayerSpawnAttemptEvent(
ICommonSession player,
HumanoidCharacterProfile profile,
string? jobId,
bool lateJoin,
EntityUid station)
: CancellableEntityEventArgs
{
public ICommonSession Player { get; } = player;
public HumanoidCharacterProfile Profile { get; } = profile;
public string? JobId { get; } = jobId;
public bool LateJoin { get; } = lateJoin;
public EntityUid Station { get; } = station;
}