mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-29 15:47:26 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69b6463898 | ||
|
|
2dc3f61cd8 | ||
|
|
164b9be1f9 | ||
|
|
eb95b25eaa |
@@ -1,3 +1,4 @@
|
||||
using Content.Server.RoundEnd; // DeltaV
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -25,4 +26,29 @@ public sealed partial class ZombieRuleComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float ZombieShuttleCallPercentage = 0.7f;
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - The behavior of the round if all zombies are defeated.
|
||||
/// </summary>
|
||||
public RoundEndBehavior ZombieRoundEndBehavior = RoundEndBehavior.ShuttleCall;
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - The amount of time before the evac shuttle will arrive if the ZombieRoundEndBehavior is set to ShuttleCall.
|
||||
/// </summary>
|
||||
public TimeSpan EvacShuttleTime = TimeSpan.FromMinutes(5);
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - The announcement sender when calling the shuttle.
|
||||
/// </summary>
|
||||
public LocId RoundEndTextSender = "comms-console-announcement-title-centcom";
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - The announcement text when calling a shuttle.
|
||||
/// </summary>
|
||||
public LocId RoundEndTextShuttleCall = "zombie-no-more-threat-announcement-shuttle-call";
|
||||
|
||||
/// <summary>
|
||||
/// DeltaV - The announcement text when a shuttle is already called.
|
||||
/// </summary>
|
||||
public LocId RoundEndTextAnnouncement = "zombie-no-more-threat-announcement";
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ using System.Linq;
|
||||
using Content.Shared.Station.Components;
|
||||
using Content.Shared.Store.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Cuffs.Components; // DeltaV
|
||||
|
||||
namespace Content.Server.GameTicking.Rules;
|
||||
|
||||
@@ -500,12 +501,23 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
||||
// Check if there are nuke operatives still alive on the same map as the shuttle,
|
||||
// or on the same map as the station.
|
||||
// If there are, the round can continue.
|
||||
var operatives = EntityQuery<NukeOperativeComponent, MobStateComponent, TransformComponent>(true);
|
||||
|
||||
// BEGIN DeltaV - End Rounds Better
|
||||
// We need to use a EntityQueryEnumerator instead of a EntityQuery, because we need the uid to check for cuffs
|
||||
var operatives = new List<Entity<NukeOperativeComponent, MobStateComponent, TransformComponent>>();
|
||||
var operativesEnumerator = EntityQueryEnumerator<NukeOperativeComponent, MobStateComponent, TransformComponent>();
|
||||
while (operativesEnumerator.MoveNext(out var uid, out var nukeOp, out var mobState, out var transform))
|
||||
{
|
||||
operatives.Add((uid, nukeOp, mobState, transform));
|
||||
}
|
||||
|
||||
var operativesAlive = operatives
|
||||
.Where(op =>
|
||||
op.Item3.MapID == shuttleMapId
|
||||
|| op.Item3.MapID == targetStationMap)
|
||||
.Any(op => op.Item2.CurrentState == MobState.Alive && op.Item1.Running);
|
||||
op.Comp3.MapID == shuttleMapId
|
||||
|| op.Comp3.MapID == targetStationMap)
|
||||
.Any(op => op.Comp2.CurrentState == MobState.Alive && op.Comp1.Running &&
|
||||
!TryComp<CuffableComponent>(op, out _)); // in the case the crew keeps one alive
|
||||
// END DeltaV
|
||||
|
||||
if (operativesAlive)
|
||||
return; // There are living operatives than can access the shuttle, or are still on the station's map.
|
||||
|
||||
@@ -3,7 +3,7 @@ using Content.Server.Chat.Systems;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Roles;
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Server.RoundEnd; // DeltaV
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.Zombies;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
@@ -114,11 +114,31 @@ public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
|
||||
/// </summary>
|
||||
private void CheckRoundEnd(ZombieRuleComponent zombieRuleComponent)
|
||||
{
|
||||
// BEGIN DeltaV - End Rounds Better
|
||||
// Zombies have failed, time to go home
|
||||
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]);
|
||||
|
||||
if (GetInfectedFraction(false) > zombieRuleComponent.ZombieShuttleCallPercentage && !_roundEnd.IsRoundEndRequested())
|
||||
|
||||
// BEGIN DeltaV - End Rounds Better
|
||||
var infectedPercent = GetInfectedFraction(false);
|
||||
if (Math.Round(infectedPercent, 0) == 0) // All zombies defeated
|
||||
{
|
||||
_roundEnd.DoRoundEndBehavior(zombieRuleComponent.ZombieRoundEndBehavior,
|
||||
zombieRuleComponent.EvacShuttleTime,
|
||||
zombieRuleComponent.RoundEndTextSender,
|
||||
zombieRuleComponent.RoundEndTextShuttleCall,
|
||||
zombieRuleComponent.RoundEndTextAnnouncement);
|
||||
zombieRuleComponent.ZombieRoundEndBehavior = RoundEndBehavior.Nothing; // stop this check in the future
|
||||
}
|
||||
// END DeltaV
|
||||
|
||||
if (infectedPercent > zombieRuleComponent.ZombieShuttleCallPercentage && !_roundEnd.IsRoundEndRequested()) // DeltaV - Move GetInfectedFraction to var
|
||||
{
|
||||
foreach (var station in _station.GetStations())
|
||||
{
|
||||
|
||||
@@ -351,7 +351,7 @@ namespace Content.Server.RoundEnd
|
||||
else
|
||||
{
|
||||
RequestRoundEnd(time, null, false, textCall,
|
||||
Loc.GetString(sender));
|
||||
Loc.GetString(sender), cantRecall: true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,39 @@ public sealed partial class CosmicCultRuleComponent : Component
|
||||
[DataField]
|
||||
public TimeSpan EvacShuttleTime = TimeSpan.FromMinutes(5);
|
||||
|
||||
#region Progress Checking
|
||||
/// <summary>
|
||||
/// The next time the monument should check the progress of the cult.
|
||||
/// </summary>
|
||||
public TimeSpan NextProgressCheck = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of time between progress checks.
|
||||
/// </summary>
|
||||
public TimeSpan TimeBetweenProgressChecks = TimeSpan.FromMinutes(15);
|
||||
|
||||
/// <summary>
|
||||
/// The progress value of the monument last time it was checked.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int LastProgress = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The number of times the the progress check as failed. Resets after some progress.
|
||||
/// </summary>
|
||||
public int ConsecutiveProgressFails = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The number of times the progress check has to fail for the round to start to end.
|
||||
/// </summary>
|
||||
public int ProgressFailureTolerance = 3;
|
||||
|
||||
public LocId ProgressFailTextShuttleCall = "cosmiccult-progress-fail-shuttle-call";
|
||||
|
||||
public LocId ProgressFailTextAnnouncement = "cosmiccult-progress-fail-announcement";
|
||||
|
||||
#endregion
|
||||
|
||||
[DataField]
|
||||
public HashSet<EntityUid> Cultists = [];
|
||||
|
||||
|
||||
@@ -62,13 +62,15 @@ using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Content.Shared.StatusIcon;
|
||||
using Content.Shared.SSDIndicator;
|
||||
|
||||
namespace Content.Server._DV.CosmicCult;
|
||||
|
||||
/// <summary>
|
||||
/// Where all the main stuff for Cosmic Cultists happens.
|
||||
/// </summary>
|
||||
public sealed class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRuleComponent>
|
||||
public sealed partial class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly ActionsSystem _actions = default!;
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
@@ -172,6 +174,28 @@ public sealed class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRuleComponen
|
||||
component.StewardVoteTimer = null;
|
||||
StewardVote();
|
||||
}
|
||||
|
||||
// Progress check. Is the cult trying to progress at all?
|
||||
if (component.MonumentPlaced && _timing.CurTime > component.NextProgressCheck)
|
||||
{
|
||||
// We're going to assume one monument.
|
||||
var monument = EntityQuery<MonumentComponent>().First();
|
||||
if (component.LastProgress == monument.CurrentProgress)
|
||||
component.ConsecutiveProgressFails++;
|
||||
else
|
||||
component.ConsecutiveProgressFails = 0;
|
||||
|
||||
// They haven't progressed enough in X checks, end the round.
|
||||
if (component.ConsecutiveProgressFails >= component.ProgressFailureTolerance) {
|
||||
SetWinType((uid, component), WinType.CrewMinor);
|
||||
_roundEnd.DoRoundEndBehavior(component.RoundEndBehavior, component.EvacShuttleTime, component.RoundEndTextSender, component.ProgressFailTextShuttleCall, component.ProgressFailTextAnnouncement);
|
||||
component.RoundEndBehavior = RoundEndBehavior.Nothing;
|
||||
}
|
||||
|
||||
component.LastProgress = monument.CurrentProgress;
|
||||
component.NextProgressCheck = _timing.CurTime + component.TimeBetweenProgressChecks;
|
||||
}
|
||||
|
||||
if (component.ExtraRiftTimer is { } riftTimer && _timing.CurTime >= riftTimer && !component.RiftStop)
|
||||
{
|
||||
component.ExtraRiftTimer = _timing.CurTime + _rand.Next(TimeSpan.FromSeconds(230), TimeSpan.FromSeconds(360)); //3min50 to 6min between new rifts. Seconds instead of minutes for granularity.
|
||||
@@ -442,17 +466,19 @@ public sealed class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRuleComponen
|
||||
}
|
||||
}
|
||||
|
||||
private bool CultistsAlive()
|
||||
private int GetCultistsAlive()
|
||||
{
|
||||
var query = EntityQueryEnumerator<CosmicCultComponent, MobStateComponent>();
|
||||
int cultistsAlive = 0;
|
||||
while (query.MoveNext(out var ent, out _, out var mobComp))
|
||||
{
|
||||
if (TryComp<CuffableComponent>(ent, out var cuffed) && cuffed.CuffedHandCount > 0) continue;
|
||||
if (TryComp<SSDIndicatorComponent>(ent, out var ssd) && ssd.IsSSD) continue; // TODO: Maybe check how long.
|
||||
if (mobComp.Running && mobComp.CurrentState != MobState.Dead)
|
||||
return true;
|
||||
cultistsAlive++;
|
||||
}
|
||||
|
||||
return false;
|
||||
return cultistsAlive;
|
||||
}
|
||||
|
||||
private void OnMobStateChanged(Entity<CosmicCultComponent> ent, ref MobStateChangedEvent args)
|
||||
@@ -467,14 +493,19 @@ public sealed class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRuleComponen
|
||||
|
||||
private void CheckForActiveCultists()
|
||||
{
|
||||
if (CultistsAlive())
|
||||
// A lone cultist can't do anything, so check for more than one.
|
||||
if (GetCultistsAlive() > 1)
|
||||
return;
|
||||
|
||||
var query = QueryActiveRules();
|
||||
List<Entity<CosmicCultRuleComponent>> cosCultRules = new();
|
||||
|
||||
// ConfirmWinState needs to be outside the query, because it might add an active rule
|
||||
while (query.MoveNext(out var ruleUid, out _, out var ruleComp, out _))
|
||||
{
|
||||
ConfirmWinState((ruleUid, ruleComp));
|
||||
cosCultRules.Add((ruleUid, ruleComp));
|
||||
}
|
||||
cosCultRules.ForEach(ConfirmWinState);
|
||||
}
|
||||
|
||||
private void ConfirmWinState(Entity<CosmicCultRuleComponent> ent)
|
||||
@@ -504,8 +535,6 @@ public sealed class CosmicCultRuleSystem : GameRuleSystem<CosmicCultRuleComponen
|
||||
else
|
||||
SetWinType(ent, WinType.Neutral); //The monument wasn't completed, no cultists escaped to midpoint. Some cultists still remain on the station, though.
|
||||
|
||||
if (CultistsAlive()) return; //If there are no cultists alive, ignore all previous checks, crew alreay won.
|
||||
|
||||
if (tier <= 1) //Prevent the cult getting cooked by accident before anyone even knows there's a cult.
|
||||
{
|
||||
SetWinType(ent, WinType.CrewMinor); //If we somehow get here at the end of the round, we'll still count this as a crew minor.
|
||||
|
||||
@@ -62,9 +62,11 @@ cosmiccult-summary-crewminor = The Monument did not reach full power.
|
||||
cosmiccult-summary-crewmajor = All cosmic cultists were eliminated.
|
||||
cosmiccult-summary-crewcomplete = All cosmic cultists were deconverted!
|
||||
|
||||
cosmiccult-elimination-shuttle-call = Based on scans from our long-range sensors, the Λ-CDM anomaly has subsided. We thank you for your prudence. An emergency shuttle has been automatically called to the station for decontamination and debriefing procedures. ETA: {$time} {$units}. Please note, if the psychological impact of the anomaly is negligible, you may recall the shuttle to extend the shift.
|
||||
cosmiccult-elimination-announcement = Based on scans from our long-range sensors, the Λ-CDM anomaly has subsided. We thank you for your prudence. An emergency shuttle is already inbound. Return to CentComm safely for decontamination and debriefing procedures.
|
||||
cosmiccult-elimination-shuttle-call = Based on scans from our long-range sensors, the Λ-CDM anomaly has subsided. We thank you for your prudence. An emergency shuttle has been automatically called to the station for decontamination and debriefing procedures. ETA: {$time} {$units}.
|
||||
cosmiccult-elimination-announcement = Based on scans from our long-range sensors, the Λ-CDM anomaly has subsided. We thank you for your prudence. An emergency shuttle is already inbound. Return to Midpoint safely for decontamination and debriefing procedures.
|
||||
|
||||
cosmiccult-progress-fail-shuttle-call = Due to sustained Λ-CDM activity on you station, an emergency shuttle has been automatically called so that the station may be decontaminated as soon as possible. We thank you for your cooperation.
|
||||
cosmiccult-progress-fail-announcement = Due to sustained Λ-CDM activity on you station, an emergency shuttle is already inbound. Please ensure as much of the station is ready and accessible for the decontamination team. We thank you for your cooperation.
|
||||
|
||||
## BRIEFINGS
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
zombie-no-more-threat-announcement-shuttle-call = Long-range sensors indicate that you station has dealt with a biohazardous threat involving Romerol. Station decontamination required. The emergency shuttle has been called. ETA: {$time} {$units}.
|
||||
zombie-no-more-threat-announcement = Long-range sensors indicate that you station has dealt with a biohazardous threat involving Romerol. Station decontamination required. The emergency shuttle is already en route.
|
||||
@@ -1,2 +1,2 @@
|
||||
nuke-ops-no-more-threat-announcement-shuttle-call = Long-range sensors indicate the nuclear threat has been eliminated. The emergency shuttle has been called. ETA: {$time} {$units}. You may recall the shuttle to extend the shift.
|
||||
nuke-ops-no-more-threat-announcement-shuttle-call = Long-range sensors indicate the nuclear threat has been eliminated. The emergency shuttle has been called. ETA: {$time} {$units}.
|
||||
nuke-ops-no-more-threat-announcement = Long-range sensors indicate the nuclear threat has been eliminated. The emergency shuttle is already en route.
|
||||
|
||||
Reference in New Issue
Block a user