diff --git a/Content.Server/GameTicking/Rules/Components/XenoborgsRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/XenoborgsRuleComponent.cs index 4a018d7e6c6..d08364fea96 100644 --- a/Content.Server/GameTicking/Rules/Components/XenoborgsRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/XenoborgsRuleComponent.cs @@ -1,3 +1,4 @@ +using Content.Server.RoundEnd; // DeltaV using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.GameTicking.Rules.Components; @@ -43,4 +44,17 @@ public sealed partial class XenoborgsRuleComponent : Component /// [DataField] public bool XenoborgShuttleCalled = false; + + + /// + /// DeltaV - The behavior of the round if the mothership core is deleted. + /// + [DataField] + public RoundEndBehavior XenoborgRoundEndBehavior = RoundEndBehavior.BecomeSurvival; + + /// + /// DeltaV - The amount of time before the evac shuttle will arrive if the XenoborgRoundEndBehavior is set to ShuttleCall. + /// + [DataField] + public TimeSpan XenoborgShuttleDelay = TimeSpan.FromMinutes(10); } diff --git a/Content.Server/GameTicking/Rules/Components/ZombieRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/ZombieRuleComponent.cs index 5fa81098ab0..863c72ce506 100644 --- a/Content.Server/GameTicking/Rules/Components/ZombieRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/ZombieRuleComponent.cs @@ -30,10 +30,20 @@ public sealed partial class ZombieRuleComponent : Component /// /// DeltaV - The behavior of the round if all zombies are defeated. /// + [DataField] public RoundEndBehavior ZombieRoundEndBehavior = RoundEndBehavior.BecomeSurvival; /// /// DeltaV - The amount of time before the evac shuttle will arrive if the ZombieRoundEndBehavior is set to ShuttleCall. /// + [DataField] public TimeSpan ZombieShuttleDelay = TimeSpan.FromMinutes(10); + + /// + /// DeltaV - If true, ZombieRuleSystem will do the ZombieRoundEndBehavior if zombies are defeated. + /// This is needed because ZombieOutbreak uses the ZombieRuleComponent but the system won't know if + /// it was roundstart or not. + /// + [DataField] + public bool IsRoundStartZombies = false; } diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index 34342de9285..70d6f732fe1 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -520,18 +520,17 @@ public sealed class NukeopsRuleSystem : GameRuleSystem // BEGIN DeltaV - Detect Nukie Failure Better // We need to use a EntityQueryEnumerator instead of a EntityQuery, because we need the uid to check for cuffs - var operatives = new List>(); - var operativesEnumerator = EntityQueryEnumerator(); - while (operativesEnumerator.MoveNext(out var uid, out var nukeOp, out var mobState, out var transform)) + var operatives = new List>(); + var operativesEnumerator = EntityQueryEnumerator(); + while (operativesEnumerator.MoveNext(out var uid, out var nukeOp, out var mobState)) { - operatives.Add((uid, nukeOp, mobState, transform)); + operatives.Add((uid, nukeOp, mobState)); } var operativesAlive = operatives - .Where(op => op.Comp3.MapID == shuttleMapId - || op.Comp3.MapID == targetStationMap) - .Any(op => op.Comp2.CurrentState == MobState.Alive && op.Comp1.Running && - !TryComp(op, out _)); // in the case the crew keeps one alive + .Any(op => op.Comp1.Running + && op.Comp2.CurrentState == MobState.Alive + && TryComp(op, out var cuffable) && cuffable.CuffedHandCount == 0); // in the case the crew keeps one alive // END DeltaV if (operativesAlive) diff --git a/Content.Server/GameTicking/Rules/XenoborgsRuleSystem.cs b/Content.Server/GameTicking/Rules/XenoborgsRuleSystem.cs index 0b6a700d110..b9923c161e7 100644 --- a/Content.Server/GameTicking/Rules/XenoborgsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/XenoborgsRuleSystem.cs @@ -42,6 +42,14 @@ public sealed class XenoborgsRuleSystem : GameRuleSystem colorOverride: AnnouncmentColor); ent.Comp.MothershipCoreDeathAnnouncmentSent = true; + + // BEGIN DeltaV - Convert to Survival + if (ent.Comp.XenoborgRoundEndBehavior != RoundEndBehavior.Nothing) + { + _roundEnd.DoRoundEndBehavior(ent.Comp.XenoborgRoundEndBehavior, ent.Comp.XenoborgShuttleDelay); + ent.Comp.XenoborgRoundEndBehavior = RoundEndBehavior.Nothing; + } + // END DeltaV } // TODO: Refactor the end of round text diff --git a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs index b5590e878b0..b3dd9b5ede3 100644 --- a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs @@ -115,29 +115,30 @@ public sealed class ZombieRuleSystem : GameRuleSystem /// private void CheckRoundEnd(ZombieRuleComponent zombieRuleComponent) { - // BEGIN DeltaV - Change mode to survival if zombies die - // Zombies have failed to launch and the mode has been switched to survival - if (zombieRuleComponent.ZombieRoundEndBehavior == RoundEndBehavior.Nothing) - return; - // END DeltaV - var healthy = GetHealthyHumans(); if (healthy.Count == 1) // Only one human left. spooky _popup.PopupEntity(Loc.GetString("zombie-alone"), healthy[0], healthy[0]); - // BEGIN DeltaV - Change mode to survival if zombies die - var anyInitialInfectedAlive = EntityQuery(false) - .Any(x => x.Item2.CurrentState != MobState.Dead); - var anyLivingZombies = EntityQuery(false) - .Any(x => x.Item2.CurrentState != MobState.Dead); - var anyPendingZombies = EntityQuery(false).Any(); - - // All II turned/dead, all entities that have turned are dead, and there are no more pending zombies - if (!anyInitialInfectedAlive && !anyLivingZombies && !anyPendingZombies) + if (zombieRuleComponent.IsRoundStartZombies) { - _roundEnd.DoRoundEndBehavior(zombieRuleComponent.ZombieRoundEndBehavior, zombieRuleComponent.ZombieShuttleDelay); - zombieRuleComponent.ZombieRoundEndBehavior = RoundEndBehavior.Nothing; // stop this check in the future + // Zombies have failed to launch and the mode has been switched to survival + if (zombieRuleComponent.ZombieRoundEndBehavior == RoundEndBehavior.Nothing) + return; + + // BEGIN DeltaV - Change mode to survival if zombies die + var anyInitialInfectedAlive = EntityQuery(false) + .Any(x => x.Item2.CurrentState != MobState.Dead); + var anyLivingZombies = EntityQuery(false) + .Any(x => x.Item2.CurrentState != MobState.Dead); + var anyPendingZombies = EntityQuery(false).Any(); + + // All II turned/dead, all entities that have turned are dead, and there are no more pending zombies + if (!anyInitialInfectedAlive && !anyLivingZombies && !anyPendingZombies) + { + _roundEnd.DoRoundEndBehavior(zombieRuleComponent.ZombieRoundEndBehavior, zombieRuleComponent.ZombieShuttleDelay); + zombieRuleComponent.ZombieRoundEndBehavior = RoundEndBehavior.Nothing; // stop this check in the future + } } // END DeltaV diff --git a/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs b/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs index 214638895c4..4961fa3f459 100644 --- a/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs +++ b/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs @@ -41,7 +41,7 @@ namespace Content.Server.StationEvents if (TryComp(uid, out var nextEventComponent) && _event.TryGenerateRandomEvent(component.ScheduledGameRules, TimeSpan.FromSeconds(component.TimeUntilNextEvent)) is {} firstEvent) { - _chatManager.SendAdminAlert(Loc.GetString("station-event-system-run-event-delayed", ("eventName", firstEvent), ("seconds", (int)component.TimeUntilNextEvent))); + _chatManager.SendAdminAlert(Loc.GetString("station-event-system-run-event-delayed", ("eventName", firstEvent), ("time", nextEventTime.ToString(@"hh\:mm\:ss")))); _next.UpdateNextEvent(nextEventComponent, firstEvent, GameTicker.RoundDuration() + TimeSpan.FromSeconds(component.TimeUntilNextEvent)); } // End DeltaV Additions @@ -81,7 +81,7 @@ namespace Content.Server.StationEvents if (_event.TryGenerateRandomEvent(eventScheduler.ScheduledGameRules, nextEventTime) is not {} generatedEvent) continue; - _chatManager.SendAdminAlert(Loc.GetString("station-event-system-run-event-delayed", ("eventName", generatedEvent), ("seconds", (int)eventScheduler.TimeUntilNextEvent))); + _chatManager.SendAdminAlert(Loc.GetString("station-event-system-run-event-delayed", ("eventName", generatedEvent), ("time", nextEventTime.ToString(@"hh\:mm\:ss")))); // Cycle the stashed event with the new generated event and time. var storedEvent = _next.UpdateNextEvent(nextEventComponent, generatedEvent, nextEventTime); if (string.IsNullOrEmpty(storedEvent)) //If there was no stored event don't try to run it. diff --git a/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs b/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs index 6f96dcf130d..ae220150489 100644 --- a/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs +++ b/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs @@ -14,9 +14,12 @@ public sealed class RampingStationEventSchedulerSystem : GameRuleSystem /// Returns the ChaosModifier which increases as round time increases to a point. @@ -50,7 +53,8 @@ public sealed class RampingStationEventSchedulerSystem : GameRuleSystem(uid, out var nextEventComponent) && _event.TryGenerateRandomEvent(component.ScheduledGameRules, TimeSpan.FromSeconds(component.TimeUntilNextEvent)) is {} firstEvent) { - _chatManager.SendAdminAlert(Loc.GetString("station-event-system-run-event-delayed", ("eventName", firstEvent), ("seconds", (int)component.TimeUntilNextEvent))); + var nextEventTime = GameTicker.RoundDuration() + TimeSpan.FromSeconds(component.TimeUntilNextEvent); + _chatManager.SendAdminAlert(Loc.GetString("station-event-system-run-event-delayed", ("eventName", firstEvent), ("time", nextEventTime.ToString(@"hh\:mm\:ss")))); _next.UpdateNextEvent(nextEventComponent, firstEvent, GameTicker.RoundDuration() + TimeSpan.FromSeconds(component.TimeUntilNextEvent)); } // End DeltaV Additions: init NextEventComp @@ -83,7 +87,7 @@ public sealed class RampingStationEventSchedulerSystem : GameRuleSystem(uid, out var gameRule)) + { + ruleActivated = gameRule.ActivatedAt; + } + + var ruleTime = _timing.CurTime.Subtract(ruleActivated); + +#if DEBUG + _chatManager.SendAdminAlert(Loc.GetString("station-event-system-debug-round-time", ("time", _gameTicker.RoundDuration()))); + _chatManager.SendAdminAlert(Loc.GetString("station-event-system-debug-ramping-time", ("time", ruleActivated))); + // This will be what the keypoint system looks at to determine where to start ramping + _chatManager.SendAdminAlert(Loc.GetString("station-event-system-debug-keypoint-time", ("time", ruleTime))); + _chatManager.SendAdminAlert("_______________"); // Easier to read +#endif + + var absoluteTimePoint = 0f; foreach (var point in component.TimeKeyPoints) { absoluteTimePoint += point.X; - if (roundTime >= absoluteTimePoint) + if (ruleTime.TotalMinutes >= absoluteTimePoint) averageTimeUntilNextEvent = point.Y; } diff --git a/Content.Server/_DV/GameTicking/GameTicker.BecomeSurvival.cs b/Content.Server/_DV/GameTicking/GameTicker.BecomeSurvival.cs index 0cecced2bc2..5762fe3cf76 100644 --- a/Content.Server/_DV/GameTicking/GameTicker.BecomeSurvival.cs +++ b/Content.Server/_DV/GameTicking/GameTicker.BecomeSurvival.cs @@ -33,7 +33,7 @@ public sealed partial class GameTicker public bool ConvertRoundToSurvival() { // Ramping scheduler is already added. Do nothing. - if (IsGameRuleActive(RampingSchedulerProto)) + if (IsGameRuleAdded(RampingSchedulerProto)) { _chatManager.SendAdminAlert("RampingStationEventScheduler detected. No rules added."); return true; @@ -44,7 +44,7 @@ public sealed partial class GameTicker var rampingSchedulerStart = _gameTiming.CurTime.Add(GracePeriod); EnsureComp(rampingScheduler).RuleStartTime = rampingSchedulerStart; - _chatManager.SendAdminAlert($"Major antag defeated. Converting to survival at {rampingSchedulerStart}."); + _chatManager.SendAdminAlert($"Major antag defeated. Converting to survival at {(RoundDuration() + GracePeriod).ToString(@"hh\:mm\:ss")}."); // End Basic Rules var basicRules = EntityQueryEnumerator(); diff --git a/Resources/Locale/en-US/_DV/station-events/station-event-system.ftl b/Resources/Locale/en-US/_DV/station-events/station-event-system.ftl index fa9ba45a048..689dc2e6b4d 100644 --- a/Resources/Locale/en-US/_DV/station-events/station-event-system.ftl +++ b/Resources/Locale/en-US/_DV/station-events/station-event-system.ftl @@ -1,4 +1,10 @@ -station-event-system-run-event-delayed = Running event {$eventName} in {$seconds} seconds +station-event-system-run-event-delayed = Running event {$eventName} @ {$time} station-event-system-meteor-swarm-starting = {$count} waves of meteors will target the area between {$targetCorner1} and {$targetCorner2} station-event-system-meteors-spawned = {$count} meteors inbound; impact in {$impactSeconds} seconds + + +# Local debugging +station-event-system-debug-round-time = Round Time @ {$time} +station-event-system-debug-ramping-time = Ramping Rule Added @ {$time} +station-event-system-debug-keypoint-time = Keypoint Time: {$time} diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index 085629169fa..9e529398424 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -441,6 +441,7 @@ min: 600 max: 900 - type: ZombieRule + isRoundStartZombies: true # DeltaV - convert to survival if they all die - type: DelayedRule # DeltaV: Grace period of 5 minutes before you can turn, to avoid a random passenger ruining your plan delay: 300 delayedComponents: diff --git a/Resources/Prototypes/game_presets.yml b/Resources/Prototypes/game_presets.yml index f0824be6ed1..028e0c8f261 100644 --- a/Resources/Prototypes/game_presets.yml +++ b/Resources/Prototypes/game_presets.yml @@ -245,7 +245,6 @@ - MeteorSwarmScheduler - SpaceTrafficControlEventScheduler - BasicRoundstartVariation - - RampingStationEventScheduler # DeltaV - GlimmerEventScheduler # DeltaV - type: gamePreset