using Content.Server.NPC.Components;
+using Content.Server.RoundEnd;
using Content.Server.StationEvents.Events;
using Content.Shared.Dataset;
using Content.Shared.Roles;
public int MaxOperatives = 5;
/// <summary>
- /// Whether or not all of the nuclear operatives dying will end the round. Used by LoneOpsSpawn event.
+ /// What will happen if all of the nuclear operatives will die. Used by LoneOpsSpawn event.
/// </summary>
- [DataField("endsRound")]
- public bool EndsRound = true;
+ [DataField("roundEndBehavior")]
+ public RoundEndBehavior RoundEndBehavior = RoundEndBehavior.ShuttleCall;
+
+ /// <summary>
+ /// Text for shuttle call if RoundEndBehavior is ShuttleCall.
+ /// </summary>
+ [DataField("roundEndTextSender")]
+ public string RoundEndTextSender = "comms-console-announcement-title-centcom";
+
+ /// <summary>
+ /// Text for shuttle call if RoundEndBehavior is ShuttleCall.
+ /// </summary>
+ [DataField("roundEndTextShuttleCall")]
+ public string RoundEndTextShuttleCall = "nuke-ops-no-more-threat-announcement-shuttle-call";
+
+ /// <summary>
+ /// Text for announcement if RoundEndBehavior is ShuttleCall. Used if shuttle is already called
+ /// </summary>
+ [DataField("roundEndTextAnnouncement")]
+ public string RoundEndTextAnnouncement = "nuke-ops-no-more-threat-announcement";
+
+ /// <summary>
+ /// Time to emergency shuttle to arrive if RoundEndBehavior is ShuttleCall.
+ /// </summary>
+ [DataField("evacShuttleTime")]
+ public TimeSpan EvacShuttleTime = TimeSpan.FromMinutes(10);
/// <summary>
/// Whether or not to spawn the nuclear operative outpost. Used by LoneOpsSpawn event.
}
}
- private void SetWinType(EntityUid uid, WinType type, NukeopsRuleComponent? component = null)
+ private void SetWinType(EntityUid uid, WinType type, NukeopsRuleComponent? component = null, bool endRound = true)
{
if (!Resolve(uid, ref component))
return;
component.WinType = type;
- if (type == WinType.CrewMajor || type == WinType.OpsMajor)
+ if (endRound && (type == WinType.CrewMajor || type == WinType.OpsMajor))
_roundEndSystem.EndRound();
}
if (!GameTicker.IsGameRuleAdded(uid, gameRule))
continue;
- if (!nukeops.EndsRound || nukeops.WinType == WinType.CrewMajor || nukeops.WinType == WinType.OpsMajor)
+ if (nukeops.RoundEndBehavior == RoundEndBehavior.Nothing || nukeops.WinType == WinType.CrewMajor || nukeops.WinType == WinType.OpsMajor)
continue;
// If there are any nuclear bombs that are active, immediately return. We're not over yet.
? WinCondition.NukiesAbandoned
: WinCondition.AllNukiesDead);
- SetWinType(uid, WinType.CrewMajor, nukeops);
+ SetWinType(uid, WinType.CrewMajor, nukeops, false);
+ _roundEndSystem.DoRoundEndBehavior(
+ nukeops.RoundEndBehavior, nukeops.EvacShuttleTime, nukeops.RoundEndTextSender, nukeops.RoundEndTextShuttleCall, nukeops.RoundEndTextAnnouncement);
+
+ // prevent it called multiple times
+ nukeops.RoundEndBehavior = RoundEndBehavior.Nothing;
}
}
foreach (var (nukeops, gameRule) in EntityQuery<NukeopsRuleComponent, GameRuleComponent>())
{
- if (nukeops.OperativeMindPendingData.TryGetValue(uid, out var role) || !nukeops.SpawnOutpost || !nukeops.EndsRound)
+ if (nukeops.OperativeMindPendingData.TryGetValue(uid, out var role) || !nukeops.SpawnOutpost || nukeops.RoundEndBehavior == RoundEndBehavior.Nothing)
{
role ??= nukeops.OperativeRoleProto;
_roles.MindAddRole(mindId, new NukeopsRoleComponent { PrototypeId = role });
return _cooldownTokenSource == null;
}
- public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, bool autoCall = false)
+ public bool IsRoundEndRequested()
+ {
+ return _countdownTokenSource != null;
+ }
+
+ public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "Station")
{
var duration = DefaultCountdownDuration;
}
}
- RequestRoundEnd(duration, requester, checkCooldown, autoCall);
+ RequestRoundEnd(duration, requester, checkCooldown, text, name);
}
- public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, bool autoCall = false)
+ public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "Station")
{
if (_gameTicker.RunLevel != GameRunLevel.InRound) return;
units = "eta-units-minutes";
}
- if (autoCall)
- {
- _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("round-end-system-shuttle-auto-called-announcement",
- ("time", time),
- ("units", Loc.GetString(units))),
- Loc.GetString("Station"),
- false,
- null,
- Color.Gold);
- }
- else
- {
- _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("round-end-system-shuttle-called-announcement",
- ("time", time),
- ("units", Loc.GetString(units))),
- Loc.GetString("Station"),
- false,
- null,
- Color.Gold);
- }
+ _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(text,
+ ("time", time),
+ ("units", Loc.GetString(units))),
+ name,
+ false,
+ null,
+ Color.Gold);
SoundSystem.Play("/Audio/Announcements/shuttlecalled.ogg", Filter.Broadcast());
Timer.Spawn(countdownTime.Value, AfterEndRoundRestart, _countdownTokenSource.Token);
}
+ public void DoRoundEndBehavior(RoundEndBehavior behavior, TimeSpan time, string sender, string textCall, string textAnnounce)
+ {
+ switch (behavior)
+ {
+ case RoundEndBehavior.InstantEnd:
+ EndRound();
+ break;
+ case RoundEndBehavior.ShuttleCall:
+ // Check is shuttle called or not. We should only dispatch announcement if it's already called
+ if (IsRoundEndRequested())
+ {
+ _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(textAnnounce),
+ Loc.GetString(sender),
+ colorOverride: Color.Gold);
+ }
+ else
+ {
+ RequestRoundEnd(time, null, false, textCall,
+ Loc.GetString(sender));
+ }
+ break;
+ }
+ }
+
private void AfterEndRoundRestart()
{
if (_gameTicker.RunLevel != GameRunLevel.PostRound) return;
{
if (!_shuttle.EmergencyShuttleArrived && ExpectedCountdownEnd is null)
{
- RequestRoundEnd(null, false, true);
+ RequestRoundEnd(null, false, "round-end-system-shuttle-auto-called-announcement");
AutoCalledBefore = true;
}
{
public static RoundEndSystemChangedEvent Default { get; } = new();
}
+
+ public enum RoundEndBehavior : byte
+{
+ /// <summary>
+ /// Instantly end round
+ /// </summary>
+ InstantEnd,
+
+ /// <summary>
+ /// Call shuttle with custom announcement
+ /// </summary>
+ ShuttleCall,
+
+ /// <summary>
+ /// Do nothing
+ /// </summary>
+ Nothing
+}
}
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.StationEvents.Components;
+using Content.Server.RoundEnd;
namespace Content.Server.StationEvents.Events;
component.AdditionalRule = nukeopsEntity;
var nukeopsComp = EntityManager.GetComponent<NukeopsRuleComponent>(nukeopsEntity);
nukeopsComp.SpawnOutpost = false;
- nukeopsComp.EndsRound = false;
+ nukeopsComp.RoundEndBehavior = RoundEndBehavior.Nothing;
_gameTicker.StartGameRule(nukeopsEntity);
}
--- /dev/null
+nuke-ops-no-more-threat-announcement-shuttle-call = Based on our scans from our long-range sensors, the nuclear threat is now eliminated. We will call emergency shuttle that will arrive shortly. ETA: {$time} {$units}. You can recall the shuttle to extend the shift.
+nuke-ops-no-more-threat-announcement = Based on our scans from our long-range sensors, the nuclear threat is now eliminated. Shuttle is already called.
\ No newline at end of file