using System.Linq; using Content.Shared.Roles; using Robust.Shared.Network; using Robust.Shared.Prototypes; using Robust.Shared.Replays; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Markdown.Mapping; using Robust.Shared.Serialization.Markdown.Value; using Robust.Shared.Timing; using Robust.Shared.Audio; using Robust.Shared.Utility; using Content.Shared._NF.Shipyard.Prototypes; // Frontier namespace Content.Shared.GameTicking { public abstract class SharedGameTicker : EntitySystem { [Dependency] private readonly IReplayRecordingManager _replay = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; // See ideally these would be pulled from the job definition or something. // But this is easier, and at least it isn't hardcoded. //TODO: Move these, they really belong in StationJobsSystem or a cvar. [ValidatePrototypeId] public const string FallbackOverflowJob = "Contractor"; // Frontier: Passenger events) { if (RoundId != 0) { metadata["roundId"] = new ValueDataNode(RoundId.ToString()); } } public TimeSpan RoundDuration() { return _gameTiming.CurTime.Subtract(RoundStartTimeSpan); } } [Serializable, NetSerializable] public sealed class TickerJoinLobbyEvent : EntityEventArgs { } [Serializable, NetSerializable] public sealed class TickerJoinGameEvent : EntityEventArgs { } [Serializable, NetSerializable] public sealed class TickerLateJoinStatusEvent : EntityEventArgs { // TODO: Make this a replicated CVar, honestly. public bool Disallowed { get; } public TickerLateJoinStatusEvent(bool disallowed) { Disallowed = disallowed; } } [Serializable, NetSerializable] public sealed class TickerConnectionStatusEvent : EntityEventArgs { public TimeSpan RoundStartTimeSpan { get; } public TickerConnectionStatusEvent(TimeSpan roundStartTimeSpan) { RoundStartTimeSpan = roundStartTimeSpan; } } [Serializable, NetSerializable] public sealed class TickerLobbyStatusEvent : EntityEventArgs { public bool IsRoundStarted { get; } public string? LobbyBackground { get; } public bool YouAreReady { get; } // UTC. public TimeSpan StartTime { get; } public TimeSpan RoundStartTimeSpan { get; } public bool Paused { get; } public TickerLobbyStatusEvent(bool isRoundStarted, string? lobbyBackground, bool youAreReady, TimeSpan startTime, TimeSpan preloadTime, TimeSpan roundStartTimeSpan, bool paused) { IsRoundStarted = isRoundStarted; LobbyBackground = lobbyBackground; YouAreReady = youAreReady; StartTime = startTime; RoundStartTimeSpan = roundStartTimeSpan; Paused = paused; } } [Serializable, NetSerializable] public sealed class TickerLobbyInfoEvent : EntityEventArgs { public string TextBlob { get; } public TickerLobbyInfoEvent(string textBlob) { TextBlob = textBlob; } } [Serializable, NetSerializable] public sealed class TickerLobbyCountdownEvent : EntityEventArgs { /// /// The game time that the game will start at. /// public TimeSpan StartTime { get; } /// /// Whether or not the countdown is paused /// public bool Paused { get; } public TickerLobbyCountdownEvent(TimeSpan startTime, bool paused) { StartTime = startTime; Paused = paused; } } // Frontier: station job info, optional structs /// /// General job information for each station-like entity (both stations and shuttles) /// /// The name of the station. /// A dictionary of job prototypes and the number of jobs positions available for it. /// If true, this entity is a station, and not a player ship (displayed under the "Crew" tab). [Serializable, NetSerializable] public sealed class StationJobInformation( string stationName, Dictionary, int?> jobsAvailable, bool isLateJoinStation, StationDisplayInformation? stationDisplayInfo, VesselDisplayInformation? vesselDisplayInfo ) { public string StationName { get; } = stationName; public Dictionary, int?> JobsAvailable { get; } = jobsAvailable; public bool IsLateJoinStation { get; } = isLateJoinStation; public StationDisplayInformation? StationDisplayInfo { get; } = stationDisplayInfo; public VesselDisplayInformation? VesselDisplayInformation { get; } = vesselDisplayInfo; } /// /// Additional optional station-specific fields. /// /// The subtext that is shown under the station name. /// A longer description of the station, describing what the player can /// do there /// The icon that represents the station and is shown next to the name. /// The order in which this station should be displayed in the station picker. [Serializable, NetSerializable] public sealed class StationDisplayInformation( LocId? stationSubtext, LocId? stationDescription, ResPath? stationIcon, int lobbySortOrder ) { public LocId? StationSubtext { get; } = stationSubtext; public LocId? StationDescription { get; } = stationDescription; public ResPath? StationIcon { get; } = stationIcon; public int LobbySortOrder { get; } = lobbySortOrder; } /// /// Additional optional vessel-specific fields. /// /// A player-input string advertising the ship to other players. /// The prototype ID for the vessel this ship is. /// If true, this vessel should be hidden when there are no open jobs on it. [Serializable, NetSerializable] public sealed class VesselDisplayInformation( string vesselAdvertisement, ProtoId? vessel, bool hiddenIfNoJobs ) { public string VesselAdvertisement { get; } = vesselAdvertisement; public ProtoId? Vessel { get; } = vessel; public bool HiddenIfNoJobs { get; } = hiddenIfNoJobs; } // End Frontier: station job info, optional structs [Serializable, NetSerializable] public sealed class TickerJobsAvailableEvent( Dictionary stationJobList // Frontier addition, replaced with StationJobInformation ) : EntityEventArgs { public Dictionary StationJobList { get; } = stationJobList; } [Serializable, NetSerializable, DataDefinition] public sealed partial class RoundEndMessageEvent : EntityEventArgs { [Serializable, NetSerializable, DataDefinition] public partial struct RoundEndPlayerInfo { [DataField] public string PlayerOOCName; [DataField] public string? PlayerICName; [DataField, NonSerialized] public NetUserId? PlayerGuid; public string Role; [DataField, NonSerialized] public string[] JobPrototypes; [DataField, NonSerialized] public string[] AntagPrototypes; public NetEntity? PlayerNetEntity; [DataField] public bool Antag; [DataField] public bool Observer; public bool Connected; } public string GamemodeTitle { get; } public string RoundEndText { get; } public TimeSpan RoundDuration { get; } public int RoundId { get; } public int PlayerCount { get; } public RoundEndPlayerInfo[] AllPlayersEndInfo { get; } /// /// Sound gets networked due to how entity lifecycle works between client / server and to avoid clipping. /// public ResolvedSoundSpecifier? RestartSound; // Frontier: custom objectives public string CustomObjectiveText; // End Frontier public RoundEndMessageEvent( string gamemodeTitle, string roundEndText, TimeSpan roundDuration, int roundId, int playerCount, RoundEndPlayerInfo[] allPlayersEndInfo, ResolvedSoundSpecifier? restartSound, string customObjectiveText) // Frontier { GamemodeTitle = gamemodeTitle; RoundEndText = roundEndText; RoundDuration = roundDuration; RoundId = roundId; PlayerCount = playerCount; AllPlayersEndInfo = allPlayersEndInfo; RestartSound = restartSound; CustomObjectiveText = customObjectiveText; // Frontier } } [Serializable, NetSerializable] public enum PlayerGameStatus : sbyte { NotReadyToPlay = 0, ReadyToPlay, JoinedGame, } }