using Content.Shared.Destructible.Thresholds; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.GameTicking.Components; /// /// Component attached to all gamerule entities. /// Used to both track the entity as well as store basic data /// [RegisterComponent, EntityCategory("GameRules")] public sealed partial class GameRuleComponent : Component { /// /// Game time when game rule was activated /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] public TimeSpan ActivatedAt; /// /// The minimum amount of players needed for this game rule. /// [DataField] public int MinPlayers; /// /// If true, this rule not having enough players will cancel the preset selection. /// If false, it will simply not run silently. /// [DataField] public bool CancelPresetOnTooFewPlayers = true; /// /// Marks a gamerule as "Silent" meaning that it will run and then proceed to delete itself without logging. /// This WILL throw a debug assert if it still exists when it's supposed to start! /// [DataField] public bool Silent; /// /// A delay for when the rule the is started and when the starting logic actually runs. /// [DataField] public MinMax? Delay; } /// /// Raised when a rule is added but hasn't formally begun yet. /// Good for announcing station events and other such things. /// [ByRefEvent] public readonly record struct GameRuleAddedEvent(Entity Rule); /// /// Raised when the rule actually begins. /// Player-facing logic should begin here. /// [ByRefEvent] public readonly record struct GameRuleStartedEvent(Entity Rule, EntProtoId? RuleId); /// /// Raised when the rule ends. /// Do cleanup and other such things here. /// [ByRefEvent] public readonly record struct GameRuleEndedEvent(EntityUid Rule); /// /// A simple struct to keep track of the Lifespan of a Gamerule in an organized fashion. /// /// Time that this game rule was added, or started /// EntityUid of the game rule /// Current lifetime of the game rule. [Access(typeof(GameTicker))] public record struct GameRule(TimeSpan StartTime, EntityUid Uid, GameRuleLifeStage LifeStage = GameRuleLifeStage.Added) : IComparable, IComparable { /// /// The time that this rule has started, or was added if it hasn't started yet! /// public TimeSpan StartTime { get; private set; } = StartTime; /// /// EntityUid for this GameRule, it's cheaper memory wise to store an int over the whole ass ProtoId, which is available through MetaDataComp lookup... /// public readonly EntityUid Uid = Uid; /// /// The time that this rule has started, or was added if it hasn't started yet! /// public GameRuleLifeStage LifeStage { get; private set; } = LifeStage; /// /// Marks that this GameRule has been started. /// /// Timespan which we started the rule. /// True if the game rule successfully started, false if was already started or ended. public bool StartRule(TimeSpan time) { if (LifeStage > GameRuleLifeStage.Added) return false; LifeStage = GameRuleLifeStage.Started; StartTime = time; return true; } /// /// Marks that this GameRule has ended. /// public bool EndRule() { if (LifeStage == GameRuleLifeStage.Ended) return false; LifeStage = GameRuleLifeStage.Ended; return true; } public int CompareTo(GameRule other) { return CompareTo(other.LifeStage); } public int CompareTo(GameRuleLifeStage other) { return LifeStage.CompareTo(other); } public static implicit operator GameRule((TimeSpan Time, EntityUid Rule) tuple) { return new GameRule(tuple.Time, tuple.Rule); } public static implicit operator GameRule((TimeSpan Time, EntityUid Rule, GameRuleLifeStage Stage) tuple) { return new GameRule(tuple.Time, tuple.Rule, tuple.Stage); } public readonly void Deconstruct(out TimeSpan time, out EntityUid rule) { time = StartTime; rule = Uid; } public readonly void Deconstruct(out TimeSpan time, out EntityUid rule, out GameRuleLifeStage stage) { time = StartTime; rule = Uid; stage = LifeStage; } } public enum GameRuleLifeStage : byte { Added = 0, Started = 1, Ended = 2, }