Alert level rework (#424)

* start

* stage

* delete trash

* cleanup

* comments

* fix

* code rabbit review

* review changes

review by Pupchansky
This commit is contained in:
JrInventor05Next
2025-12-15 05:03:54 +08:00
committed by GitHub
parent 19ac035544
commit cc510eecff
17 changed files with 336 additions and 256 deletions

View File

@@ -53,7 +53,7 @@
<RichTextLabel Name="CountdownLabel"/>
<Button Name="EmergencyShuttleButton"
Access="Public"
Access="Public"
Text="Placeholder Text"
ToolTip="{Loc 'comms-console-menu-emergency-shuttle-button-tooltip'}"/>
</BoxContainer>

View File

@@ -6,6 +6,10 @@ using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
// WL-Changes-start: Alert Level Rework
using Robust.Shared.Prototypes;
using Content.Shared.AlertLevel;
// WL-Changes-end
namespace Content.Client.Communications.UI
{
@@ -15,6 +19,7 @@ namespace Content.Client.Communications.UI
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ILocalizationManager _loc = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; // Wl-Changes: Alert Level Rework
public bool CanAnnounce;
public bool CanBroadcast;
@@ -91,10 +96,17 @@ namespace Content.Client.Communications.UI
if (alerts == null)
{
var name = currentAlert;
if (_loc.TryGetString($"alert-level-{currentAlert}", out var locName))
// Wl-Changes-start: Alert Level Rework
if (!_prototypeManager.TryIndex<AlertLevelPrototype>(currentAlert, out var index))
return;
if (_loc.TryGetString($"alert-level-{currentAlert.ToLower()}", out var locName))
{
name = locName;
}
else if (!string.IsNullOrEmpty(index.SetName))
name = index.SetName;
// WL-Changes-end
AlertLevelButton.AddItem(name);
AlertLevelButton.SetItemMetadata(AlertLevelButton.ItemCount - 1, currentAlert);
}
@@ -103,12 +115,20 @@ namespace Content.Client.Communications.UI
foreach (var alert in alerts)
{
var name = alert;
if (_loc.TryGetString($"alert-level-{alert}", out var locName))
// WL-Changes-start: Alert Level Rework
if (_prototypeManager.TryIndex<AlertLevelPrototype>(alert, out var index))
{
name = locName;
if (_loc.TryGetString($"alert-level-{alert.ToLower()}", out var locName))
{
name = locName;
}
else if (!string.IsNullOrEmpty(index.SetName))
name = index.SetName;
AlertLevelButton.AddItem(name);
AlertLevelButton.SetItemMetadata(AlertLevelButton.ItemCount - 1, alert);
}
AlertLevelButton.AddItem(name);
AlertLevelButton.SetItemMetadata(AlertLevelButton.ItemCount - 1, alert);
// WL-Changes-end
if (alert == currentAlert)
{
AlertLevelButton.Select(AlertLevelButton.ItemCount - 1);

View File

@@ -125,7 +125,7 @@ namespace Content.Client.Entry
_prototypeManager.RegisterIgnore("instantSpell");
_prototypeManager.RegisterIgnore("roundAnnouncement");
_prototypeManager.RegisterIgnore("wireLayout");
_prototypeManager.RegisterIgnore("alertLevels");
_prototypeManager.RegisterIgnore("alertLevelsList"); // Wl-Changes: Alert Level Rework // alertLevels -> alertLevelsList
_prototypeManager.RegisterIgnore("nukeopsRole");
_prototypeManager.RegisterIgnore("stationGoal"); // Corvax-StationGoal
_prototypeManager.RegisterIgnore("ghostRoleRaffleDecider");

View File

@@ -117,7 +117,7 @@ namespace Content.Client.PDA
StationTimeButton.OnPressed += _ =>
{
var stationTime = _gameTiming.CurTime.Subtract(_gameTicker.RoundStartTimeSpan);
_clipboard.SetText((stationTime.ToString("hh\\:mm\\:ss")));
_clipboard.SetText(stationTime.ToString("hh\\:mm\\:ss"));
};
StationAlertLevelInstructionsButton.OnPressed += _ =>
@@ -132,6 +132,7 @@ namespace Content.Client.PDA
ToHomeScreen();
}
// WL-Changes-start: Loc -> _locMan
public void UpdateState(PdaUpdateState state)
{
FlashLightToggleButton.IsActive = state.FlashlightEnabled;
@@ -139,7 +140,7 @@ namespace Content.Client.PDA
if (state.PdaOwnerInfo.ActualOwnerName != null)
{
_pdaOwner = state.PdaOwnerInfo.ActualOwnerName;
PdaOwnerLabel.SetMarkup(Loc.GetString("comp-pda-ui-owner",
PdaOwnerLabel.SetMarkup(_locMan.GetString("comp-pda-ui-owner",
("actualOwnerName", _pdaOwner)));
PdaOwnerLabel.Visible = true;
}
@@ -151,42 +152,41 @@ namespace Content.Client.PDA
if (state.PdaOwnerInfo.IdOwner != null || state.PdaOwnerInfo.JobTitle != null)
{
_owner = state.PdaOwnerInfo.IdOwner ?? Loc.GetString("comp-pda-ui-unknown");
_jobTitle = state.PdaOwnerInfo.JobTitle ?? Loc.GetString("comp-pda-ui-unassigned");
IdInfoLabel.SetMarkup(Loc.GetString("comp-pda-ui",
_owner = state.PdaOwnerInfo.IdOwner ?? _locMan.GetString("comp-pda-ui-unknown");
_jobTitle = state.PdaOwnerInfo.JobTitle ?? _locMan.GetString("comp-pda-ui-unassigned");
IdInfoLabel.SetMarkup(_locMan.GetString("comp-pda-ui",
("owner", _owner),
("jobTitle", _jobTitle)));
}
else
{
IdInfoLabel.SetMarkup(Loc.GetString("comp-pda-ui-blank"));
IdInfoLabel.SetMarkup(_locMan.GetString("comp-pda-ui-blank"));
}
_stationName = state.StationName ?? Loc.GetString("comp-pda-ui-unknown");
StationNameLabel.SetMarkup(Loc.GetString("comp-pda-ui-station",
_stationName = state.StationName ?? _locMan.GetString("comp-pda-ui-unknown");
StationNameLabel.SetMarkup(_locMan.GetString("comp-pda-ui-station",
("station", _stationName)));
var stationTime = _gameTiming.CurTime.Subtract(_gameTicker.RoundStartTimeSpan);
StationTimeLabel.SetMarkup(Loc.GetString("comp-pda-ui-station-time",
StationTimeLabel.SetMarkup(_locMan.GetString("comp-pda-ui-station-time",
("time", stationTime.ToString("hh\\:mm\\:ss"))));
var alertLevel = state.PdaOwnerInfo.StationAlertLevel;
var alertColor = state.PdaOwnerInfo.StationAlertColor;
var alertName = state.PdaOwnerInfo.StationAlertName;
// WL-Changes-start: custom alert instructions in PDA
var alertInstructions = state.PdaOwnerInfo.StationAlertInstructions;
if (alertLevel != null)
{
if (_locMan.TryGetString($"alert-level-{alertLevel}", out var locName))
_alertLevel = locName;
else
_alertLevel = alertLevel;
}
if (alertLevel != null
&& _locMan.TryGetString($"alert-level-{alertLevel.ToLower()}", out var locName))
_alertLevel = locName;
else if (!string.IsNullOrEmpty(alertName))
_alertLevel = alertName;
else
_alertLevel = Loc.GetString("alert-level-unknown");
_alertLevel = _locMan.GetString("alert-level-unknown");
StationAlertLevelLabel.SetMarkup(Loc.GetString(
StationAlertLevelLabel.SetMarkup(_locMan.GetString(
"comp-pda-ui-station-alert-level",
("color", alertColor),
("level", _alertLevel)
@@ -194,13 +194,13 @@ namespace Content.Client.PDA
if (!string.IsNullOrEmpty(alertInstructions))
_instructions = alertInstructions;
else if (alertLevel != null && _locMan.TryGetString($"alert-level-{alertLevel}-instructions", out var locInstruction))
else if (alertLevel != null && _locMan.TryGetString($"alert-level-{alertLevel.ToLower()}-instructions", out var locInstruction))
_instructions = locInstruction;
else
_instructions = Loc.GetString("alert-level-unknown-instructions");
_instructions = _locMan.GetString("alert-level-unknown-instructions");
// WL-Changes-end
StationAlertLevelInstructions.SetMarkup(Loc.GetString(
StationAlertLevelInstructions.SetMarkup(_locMan.GetString(
"comp-pda-ui-station-alert-level-instructions",
("instructions", _instructions))
);
@@ -223,7 +223,7 @@ namespace Content.Client.PDA
{
ProgramList.AddChild(new Label()
{
Text = Loc.GetString("comp-pda-io-no-programs-available"),
Text = _locMan.GetString("comp-pda-io-no-programs-available"),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
VerticalExpand = true
@@ -256,17 +256,17 @@ namespace Content.Client.PDA
{
case InstallationStatus.Cartridge:
item.InstallButton.Visible = true;
item.InstallButton.Text = Loc.GetString("cartridge-bound-user-interface-install-button");
item.InstallButton.Text = _locMan.GetString("cartridge-bound-user-interface-install-button");
item.InstallButton.OnPressed += _ => OnInstallButtonPressed?.Invoke(uid);
break;
case InstallationStatus.Installed:
item.InstallButton.Visible = true;
item.InstallButton.Text = Loc.GetString("cartridge-bound-user-interface-uninstall-button");
item.InstallButton.Text = _locMan.GetString("cartridge-bound-user-interface-uninstall-button");
item.InstallButton.OnPressed += _ => OnUninstallButtonPressed?.Invoke(uid);
break;
}
item.ProgramName.Text = Loc.GetString(component.ProgramName);
item.ProgramName.Text = _locMan.GetString(component.ProgramName);
item.SetHeight = 20;
row.AddChild(item);
@@ -360,8 +360,9 @@ namespace Content.Client.PDA
var stationTime = _gameTiming.CurTime.Subtract(_gameTicker.RoundStartTimeSpan);
StationTimeLabel.SetMarkup(Loc.GetString("comp-pda-ui-station-time",
StationTimeLabel.SetMarkup(_locMan.GetString("comp-pda-ui-station-time",
("time", stationTime.ToString("hh\\:mm\\:ss"))));
}
// WL-Changes-end: Loc -> _locMan
}
}

View File

@@ -1,4 +1,7 @@
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
// WL-Changes-start: Alert Level Rework
using Content.Shared.AlertLevel;
using Robust.Shared.Prototypes;
// WL-Changes-end
namespace Content.Server.AlertLevel;
@@ -13,11 +16,13 @@ public sealed partial class AlertLevelComponent : Component
/// The current set of alert levels on the station.
/// </summary>
[ViewVariables]
public AlertLevelPrototype? AlertLevels;
// WL-Changes-start: Alert Level Rework
public AlertLevelsListPrototype? AlertLevels;
// Once stations are a prototype, this should be used.
[DataField("alertLevelPrototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<AlertLevelPrototype>))]
public string AlertLevelPrototype = default!;
[DataField(required: true)]
public ProtoId<AlertLevelsListPrototype> AlertLevelsListPrototype;
// WL-Changes-end
/// <summary>
/// The current level on the station.
@@ -40,11 +45,12 @@ public sealed partial class AlertLevelComponent : Component
{
get
{
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
if (AlertLevels == null
|| !AlertLevels.Levels.TryGetValue(CurrentLevel, out var level))
{
// WL-Changes-start: Alert Level Rework
|| !prototypeManager.TryIndex<AlertLevelPrototype>(CurrentLevel, out var level)) // TryGetValue -> TryIndex
return false;
}
// WL-Changes-end
return level.Selectable && !level.DisableSelection && !IsLevelLocked;
}

View File

@@ -1,82 +0,0 @@
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server.AlertLevel;
[Prototype("alertLevels")]
public sealed partial class AlertLevelPrototype : IPrototype
{
[IdDataField] public string ID { get; private set; } = default!;
/// <summary>
/// Dictionary of alert levels. Keyed by string - the string key is the most important
/// part here. Visualizers will use this in order to dictate what alert level to show on
/// client side sprites, and localization uses each key to dictate the alert level name.
/// </summary>
[DataField("levels")] public Dictionary<string, AlertLevelDetail> Levels = new();
/// <summary>
/// Default level that the station is on upon initialization.
/// If this isn't in the dictionary, this will default to whatever .First() gives.
/// </summary>
[DataField("defaultLevel")] public string DefaultLevel { get; private set; } = default!;
}
/// <summary>
/// Alert level detail. Does not contain an ID, that is handled by
/// the Levels field in AlertLevelPrototype.
/// </summary>
[DataDefinition]
public sealed partial class AlertLevelDetail
{
/// <summary>
/// What is announced upon this alert level change. Can be a localized string.
/// </summary>
[DataField("announcement")] public string Announcement { get; private set; } = string.Empty;
// WL-Changes-start: custom alert instructions in PDA
/// <summary>
/// Instruction of alert level in pda
/// </summary>
[DataField("instruction")] public string AlertLevelInstruction { get; private set; } = string.Empty;
// WL-Changes-end
/// <summary>
/// Whether this alert level is selectable from a communications console.
/// </summary>
[DataField("selectable")] public bool Selectable { get; private set; } = true;
/// <summary>
/// If this alert level disables user selection while it is active. Beware -
/// setting this while something is selectable will disable selection permanently!
/// This should only apply to entities or gamemodes that auto-select an alert level,
/// such as a nuclear bomb being set to active.
/// </summary>
[DataField("disableSelection")] public bool DisableSelection { get; private set; }
/// <summary>
/// The sound that this alert level will play in-game once selected.
/// </summary>
[DataField("sound")] public SoundSpecifier? Sound { get; private set; }
/// <summary>
/// The color that this alert level will show in-game in chat.
/// </summary>
[DataField("color")] public Color Color { get; private set; } = Color.White;
/// <summary>
/// The color to turn emergency lights on this station when they are active.
/// </summary>
[DataField("emergencyLightColor")] public Color EmergencyLightColor { get; private set; } = Color.FromHex("#FF4020");
/// <summary>
/// Will this alert level force emergency lights on for the station that's active?
/// </summary>
[DataField("forceEnableEmergencyLights")] public bool ForceEnableEmergencyLights { get; private set; } = false;
/// <summary>
/// How long it takes for the shuttle to arrive when called.
/// </summary>
[DataField("shuttleTime")] public TimeSpan ShuttleTime { get; private set; } = TimeSpan.FromMinutes(5);
}

View File

@@ -1,8 +1,8 @@
using System.Linq;
using Content.Server.Chat.Systems;
using Content.Server.Station.Systems;
using Content.Shared.AlertLevel; // WL-Changes: Alert Level Rework
using Content.Shared.CCVar;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
@@ -51,7 +51,7 @@ public sealed class AlertLevelSystem : EntitySystem
if (!TryComp<AlertLevelComponent>(args.Station, out var alertLevelComponent))
return;
if (!_prototypeManager.TryIndex(alertLevelComponent.AlertLevelPrototype, out AlertLevelPrototype? alerts))
if (!_prototypeManager.TryIndex(alertLevelComponent.AlertLevelsListPrototype, out AlertLevelsListPrototype? alerts)) // WL-Changes: Alert Level Rework
{
return;
}
@@ -61,7 +61,7 @@ public sealed class AlertLevelSystem : EntitySystem
var defaultLevel = alertLevelComponent.AlertLevels.DefaultLevel;
if (string.IsNullOrEmpty(defaultLevel))
{
defaultLevel = alertLevelComponent.AlertLevels.Levels.Keys.First();
defaultLevel = alertLevelComponent.AlertLevels.Levels.First(); // WL-Changes: Alert Level Rework
}
SetLevel(args.Station, defaultLevel, false, false, true);
@@ -69,31 +69,34 @@ public sealed class AlertLevelSystem : EntitySystem
private void OnPrototypeReload(PrototypesReloadedEventArgs args)
{
if (!args.ByType.TryGetValue(typeof(AlertLevelPrototype), out var alertPrototypes)
|| !alertPrototypes.Modified.TryGetValue(DefaultAlertLevelSet, out var alertObject)
|| alertObject is not AlertLevelPrototype alerts)
{
// WL-Changes-start: Alert Level Rework
if (!args.ByType.TryGetValue(typeof(AlertLevelsListPrototype), out var alertListPrototypes)
|| !alertListPrototypes.Modified.TryGetValue(DefaultAlertLevelSet, out var alertObject)
|| alertObject is not AlertLevelsListPrototype alerts)
return;
}
// WL-Changes-end
var query = EntityQueryEnumerator<AlertLevelComponent>();
while (query.MoveNext(out var uid, out var comp))
{
comp.AlertLevels = alerts;
if (!comp.AlertLevels.Levels.ContainsKey(comp.CurrentLevel))
if (!comp.AlertLevels.Levels.Contains(comp.CurrentLevel)) // WL-Changes: Alert Level Rework
{
var defaultLevel = comp.AlertLevels.DefaultLevel;
if (string.IsNullOrEmpty(defaultLevel))
{
defaultLevel = comp.AlertLevels.Levels.Keys.First();
}
if (string.IsNullOrEmpty(defaultLevel)
// WL-Changes-start: Alert Level Rework
&& comp.AlertLevels.Levels.Count > 0)
defaultLevel = comp.AlertLevels.Levels.First();
else
continue;
// WL-Changes-end
SetLevel(uid, defaultLevel, true, true, true);
}
}
RaiseLocalEvent(new AlertLevelPrototypeReloadedEvent());
RaiseLocalEvent(new AlertLevelsListPrototypeReloadedEvent()); // WL-Changes: Alert Level Rework
}
public string GetLevel(EntityUid station, AlertLevelComponent? alert = null)
@@ -116,13 +119,6 @@ public sealed class AlertLevelSystem : EntitySystem
return alert.CurrentDelay;
}
//WL-Changes-start
public string GetLevelLocString(string level)
{
return Loc.GetString($"alert-level-{level}");
}
//WL-Changes-end
/// <summary>
/// Get the default alert level for a station entity.
/// Returns an empty string if the station has no alert levels defined.
@@ -151,15 +147,17 @@ public sealed class AlertLevelSystem : EntitySystem
{
if (!Resolve(station, ref component, ref dataComponent)
|| component.AlertLevels == null
|| !component.AlertLevels.Levels.TryGetValue(level, out var detail)
|| component.CurrentLevel == level)
{
// WL-Changes: Alert Level Rework
|| component.CurrentLevel == level
|| !component.AlertLevels.Levels.Contains(level)
|| !_prototypeManager.TryIndex<AlertLevelPrototype>(level, out var prototype)
|| prototype == null)
return;
}
// WL-Changes-end
if (!force)
{
if (!detail.Selectable
if (!prototype.Selectable // WL-Changes: Alert Level Rework
|| component.CurrentDelay > 0
|| component.IsLevelLocked)
{
@@ -175,20 +173,22 @@ public sealed class AlertLevelSystem : EntitySystem
var stationName = dataComponent.EntityName;
var name = level.ToLower();
// WL-Changes-start: Alert Level Rework
var name = level;
if (Loc.TryGetString($"alert-level-{level}", out var locName))
{
name = locName.ToLower();
}
if (Loc.TryGetString($"alert-level-{level.ToLower()}", out var locId))
name = locId.ToLower();
else if (!string.IsNullOrEmpty(prototype.SetName))
name = prototype.SetName.ToLower();
else
name = Loc.GetString("alert-level-unknown").ToLower();
// Announcement text. Is passed into announcementFull.
var announcement = detail.Announcement;
var announcement = prototype.Announcement;
if (Loc.TryGetString(detail.Announcement, out var locAnnouncement))
{
if (Loc.TryGetString(prototype.Announcement, out var locAnnouncement))
announcement = locAnnouncement;
}
// WL-Changes-end
// The full announcement to be spat out into chat.
var announcementFull = Loc.GetString("alert-level-announcement", ("name", name), ("announcement", announcement));
@@ -196,10 +196,10 @@ public sealed class AlertLevelSystem : EntitySystem
var playDefault = false;
if (playSound)
{
if (detail.Sound != null)
if (prototype.Sound != null) // WL-Changes: Alert Level Rework
{
var filter = _stationSystem.GetInOwningStation(station);
_audio.PlayGlobal(detail.Sound, filter, true, detail.Sound.Params);
_audio.PlayGlobal(prototype.Sound, filter, true, prototype.Sound.Params); // WL-Changes: Alert Level Rework
}
else
{
@@ -210,7 +210,7 @@ public sealed class AlertLevelSystem : EntitySystem
if (announce)
{
_chatSystem.DispatchStationAnnouncement(station, announcementFull, playDefaultSound: playDefault,
colorOverride: detail.Color, sender: stationName);
colorOverride: prototype.Color, sender: stationName); // WL-Changes: Alert Level Rework
}
RaiseLocalEvent(new AlertLevelChangedEvent(station, level));
@@ -220,7 +220,7 @@ public sealed class AlertLevelSystem : EntitySystem
public sealed class AlertLevelDelayFinishedEvent : EntityEventArgs
{}
public sealed class AlertLevelPrototypeReloadedEvent : EntityEventArgs
public sealed class AlertLevelsListPrototypeReloadedEvent : EntityEventArgs // WL-Changes: Alert Level Rework
{}
public sealed class AlertLevelChangedEvent : EntityEventArgs

View File

@@ -78,12 +78,12 @@ namespace Content.Server.AlertLevel.Commands
private string[] GetStationLevelNames(EntityUid station)
{
if (!EntityManager.TryGetComponent<AlertLevelComponent>(station, out var alertLevelComp))
return new string[]{};
return [];
if (alertLevelComp.AlertLevels == null)
return new string[]{};
return [];
return alertLevelComp.AlertLevels.Levels.Keys.ToArray();
return alertLevelComp.AlertLevels.Levels.Select(protoId => protoId.ToString()).ToArray(); // WL-Changes: Alert Level Rework
}
}
}

View File

@@ -19,6 +19,7 @@ using Content.Shared.IdentityManagement;
using Content.Shared.Popups;
using Robust.Server.GameObjects;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes; // WL-Changes: Alert Level Rework
namespace Content.Server.Communications
{
@@ -35,6 +36,7 @@ namespace Content.Server.Communications
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; // WL-Changes: Alert Level Rework
private const float UIUpdateInterval = 5.0f;
@@ -144,13 +146,16 @@ namespace Content.Server.Communications
if (alertComp.IsSelectable)
{
levels = new();
foreach (var (id, detail) in alertComp.AlertLevels.Levels)
// WL-Changes-start: Alert Level Rework
foreach (var protoId in alertComp.AlertLevels.Levels) // (id, detail) -> protoId
{
if (detail.Selectable)
if (_prototypeManager.TryIndex(protoId, out var prototype)
&& prototype.Selectable)
{
levels.Add(id);
levels.Add(prototype.ID); // id -> prototype.ID
}
}
// WL-Changes-end
}
currentLevel = alertComp.CurrentLevel;

View File

@@ -12,6 +12,7 @@ using Content.Shared.Power.Components;
using Content.Shared.Station.Components;
using Robust.Server.GameObjects;
using Color = Robust.Shared.Maths.Color;
using Robust.Shared.Prototypes; // WL-Changes: Alert Level Rework
namespace Content.Server.Light.EntitySystems;
@@ -22,6 +23,7 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
[Dependency] private readonly PointLightSystem _pointLight = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; // WL-Changes: Alert Level Rework
public override void Initialize()
{
@@ -66,8 +68,9 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
var name = alerts.CurrentLevel;
var color = Color.White;
if (alerts.AlertLevels.Levels.TryGetValue(alerts.CurrentLevel, out var details))
color = details.Color;
if (alerts.AlertLevels.Levels.TryGetValue(alerts.CurrentLevel, out var details)
&& _prototypeManager.TryIndex(details, out var alertPrototype)) // WL-Changes: Alert Level Rework
color = alertPrototype.Color;
args.PushMarkup(
Loc.GetString("emergency-light-component-on-examine-alert",
@@ -98,7 +101,9 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
if (!TryComp<AlertLevelComponent>(ev.Station, out var alert))
return;
if (alert.AlertLevels == null || !alert.AlertLevels.Levels.TryGetValue(ev.AlertLevel, out var details))
if (alert.AlertLevels == null
|| !alert.AlertLevels.Levels.TryGetValue(ev.AlertLevel, out var details)
|| !_prototypeManager.TryIndex(details, out var alertPrototype)) // WL-Changes: Alert Level Rework
return;
var query = EntityQueryEnumerator<EmergencyLightComponent, PointLightComponent, AppearanceComponent, TransformComponent>();
@@ -107,15 +112,17 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
if (CompOrNull<StationMemberComponent>(xform.GridUid)?.Station != ev.Station)
continue;
_pointLight.SetColor(uid, details.EmergencyLightColor, pointLight);
_appearance.SetData(uid, EmergencyLightVisuals.Color, details.EmergencyLightColor, appearance);
// WL-Changes-start: Alert Level Rework // details -> alertPrototype
_pointLight.SetColor(uid, alertPrototype.EmergencyLightColor, pointLight);
_appearance.SetData(uid, EmergencyLightVisuals.Color, alertPrototype.EmergencyLightColor, appearance);
if (details.ForceEnableEmergencyLights && !light.ForciblyEnabled)
if (alertPrototype.ForceEnableEmergencyLights && !light.ForciblyEnabled)
{
light.ForciblyEnabled = true;
TurnOn((uid, light));
}
else if (!details.ForceEnableEmergencyLights && light.ForciblyEnabled)
else if (!alertPrototype.ForceEnableEmergencyLights && light.ForciblyEnabled)
// WL-Changes-end
{
// Previously forcibly enabled, and we went down an alert level.
light.ForciblyEnabled = false;
@@ -177,7 +184,9 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
if (!TryComp<AlertLevelComponent>(_station.GetOwningStation(entity.Owner), out var alerts))
return;
if (alerts.AlertLevels == null || !alerts.AlertLevels.Levels.TryGetValue(alerts.CurrentLevel, out var details))
if (alerts.AlertLevels == null
|| !alerts.AlertLevels.Levels.TryGetValue(alerts.CurrentLevel, out var details)
|| !_prototypeManager.TryIndex(details, out var alertPrototype)) // WL-Changes: Alert Level Rework
{
TurnOff(entity, Color.Red); // if no alert, default to off red state
return;
@@ -186,7 +195,7 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
if (receiver.Powered && !entity.Comp.ForciblyEnabled) // Green alert
{
receiver.Load = (int) Math.Abs(entity.Comp.Wattage);
TurnOff(entity, details.Color);
TurnOff(entity, alertPrototype.Color); // WL-Changes: Alert Level Rework // details -> alertPrototype
SetState(entity.Owner, entity.Comp, EmergencyLightState.Charging);
}
else if (!receiver.Powered) // If internal battery runs out it will end in off red state
@@ -196,7 +205,7 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
}
else // Powered and enabled
{
TurnOn(entity, details.Color);
TurnOn(entity, alertPrototype.Color); // WL-Changes: Alert Level Rework // details -> alertPrototype
SetState(entity.Owner, entity.Comp, EmergencyLightState.On);
}
}

View File

@@ -21,6 +21,7 @@ using Robust.Server.Containers;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
using Robust.Shared.Player;
using Robust.Shared.Prototypes; // WL-Changes: Alert Level Rework
using Robust.Shared.Utility;
namespace Content.Server.PDA
@@ -37,6 +38,7 @@ namespace Content.Server.PDA
[Dependency] private readonly UnpoweredFlashlightSystem _unpoweredFlashlight = default!;
[Dependency] private readonly ContainerSystem _containerSystem = default!;
[Dependency] private readonly IdCardSystem _idCard = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; // WL-Changes: Alert Level Rework
public override void Initialize()
{
@@ -213,7 +215,8 @@ namespace Content.Server.PDA
JobTitle = id?.LocalizedJobTitle,
StationAlertLevel = pda.StationAlertLevel,
StationAlertColor = pda.StationAlertColor,
StationAlertInstructions = pda.StationAlertInstructions // WL-Changes: custom alert instructions in PDA
StationAlertInstructions = pda.StationAlertInstructions, // WL-Changes: custom alert instructions in PDA
StationAlertName = pda.StationAlertName // WL-Changes: Alert Level Rework
},
pda.StationName,
showUplink,
@@ -309,10 +312,14 @@ namespace Content.Server.PDA
pda.StationAlertLevel = alertComp.CurrentLevel;
if (alertComp.AlertLevels.Levels.TryGetValue(alertComp.CurrentLevel, out var details))
{
// WL-Changes-start: custom alert instructions in PDA
pda.StationAlertColor = details.Color;
if (details != null)
pda.StationAlertInstructions = details.AlertLevelInstruction;
// WL-Changes-start: Alert Level Rework
if (_prototypeManager.TryIndex(details, out var index))
{
pda.StationAlertColor = index.Color;
pda.StationAlertInstructions = index.Instruction;
if (!string.IsNullOrEmpty(index.SetName))
pda.StationAlertName = index.SetName;
}
// WL-Changes-end
}
}

View File

@@ -10,6 +10,7 @@ using Content.Server.Screens.Components;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Systems;
using Content.Server.Station.Systems;
using Content.Shared.AlertLevel; // WL-Changes: Alert Level Rework
using Content.Shared.Database;
using Content.Shared.DeviceNetwork;
using Content.Shared.GameTicking;
@@ -135,8 +136,10 @@ namespace Content.Server.RoundEnd
if (TryComp<AlertLevelComponent>(stationUid, out var alertLevel))
{
duration = _protoManager
.Index<AlertLevelPrototype>(AlertLevelSystem.DefaultAlertLevelSet)
.Levels[alertLevel.CurrentLevel].ShuttleTime;
// WL-Changes-start: Alert Level Rework
.Index<AlertLevelPrototype>(alertLevel.CurrentLevel)
.ShuttleTime;
// WL-Changes-end
}
}

View File

@@ -0,0 +1,83 @@
// WL-Changes-start: Alert Level Rework
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Shared.AlertLevel;
[Prototype("alertLevelsList")]
public sealed class AlertLevelsListPrototype : IPrototype
{
[IdDataField] public string ID { get; private set; } = default!;
/// <summary>
/// Set of allowed alert levels.
/// </summary>
[DataField] public HashSet<ProtoId<AlertLevelPrototype>> Levels = new();
/// <summary>
/// Default level that the station is on upon initialization.
/// If this isn't in the hashSet, this will default to whatever .First() gives.
/// </summary>
[DataField] public string DefaultLevel { get; private set; } = default!;
}
/// <summary>
/// Alert level detail.
/// </summary>
[Prototype("alertLevel")]
public sealed class AlertLevelPrototype : IPrototype
{
[IdDataField] public string ID { get; private set; } = default!;
[DataField("name")] public string? SetName { get; private set; }
/// <summary>
/// What is announced upon this alert level change. Can be a localized string.
/// </summary>
[DataField] public string Announcement { get; private set; } = string.Empty;
// WL-Changes-start: custom alert instructions in PDA
/// <summary>
/// Instruction of alert level in pda
/// </summary>
[DataField] public string Instruction { get; private set; } = string.Empty;
// WL-Changes-end
/// <summary>
/// Whether this alert level is selectable from a communications console.
/// </summary>
[DataField] public bool Selectable { get; private set; } = true;
/// <summary>
/// If this alert level disables user selection while it is active. Beware -
/// setting this while something is selectable will disable selection permanently!
/// This should only apply to entities or gamemodes that auto-select an alert level,
/// such as a nuclear bomb being set to active.
/// </summary>
[DataField] public bool DisableSelection { get; private set; }
/// <summary>
/// The sound that this alert level will play in-game once selected.
/// </summary>
[DataField] public SoundSpecifier? Sound { get; private set; }
/// <summary>
/// The color that this alert level will show in-game in chat.
/// </summary>
[DataField] public Color Color { get; private set; } = Color.White;
/// <summary>
/// The color to turn emergency lights on this station when they are active.
/// </summary>
[DataField] public Color EmergencyLightColor { get; private set; } = Color.FromHex("#FF4020");
/// <summary>
/// Will this alert level force emergency lights on for the station that's active?
/// </summary>
[DataField] public bool ForceEnableEmergencyLights { get; private set; } = false;
/// <summary>
/// How long it takes for the shuttle to arrive when called.
/// </summary>
[DataField] public TimeSpan ShuttleTime { get; private set; } = TimeSpan.FromMinutes(5);
}
// WL-Changes-end

View File

@@ -39,5 +39,6 @@ namespace Content.Shared.PDA
[ViewVariables] public string? StationAlertLevel;
[ViewVariables] public Color StationAlertColor = Color.White;
[ViewVariables] public string? StationAlertInstructions; // WL-Changes: custom alert instructions in PDA
[ViewVariables] public string? StationAlertName; // WL-Changes: Alert Level Rework
}
}

View File

@@ -50,5 +50,6 @@ namespace Content.Shared.PDA
public string? StationAlertLevel;
public Color StationAlertColor;
public string? StationAlertInstructions; // WL-Changes: custom alert instructions in PDA
public string? StationAlertName; // WL-Changes: Alert Level Rework
}
}

View File

@@ -1,73 +1,99 @@
- type: alertLevels
# WL-Changes-start: Alert Level Rework
- type: alertLevelsList
id: stationAlerts
defaultLevel: green
defaultLevel: Green
levels:
green:
announcement: alert-level-green-announcement
sound: /Audio/Corvax/Misc/green_down.ogg # Corvax-Announcements
color: Green
emergencyLightColor: LawnGreen
shuttleTime: 600
blue:
announcement: alert-level-blue-announcement
sound: /Audio/Corvax/Misc/blue.ogg # Corvax-Announcements #base:/Audio/Misc/bluealert.ogg
color: DodgerBlue
forceEnableEmergencyLights: true
emergencyLightColor: DodgerBlue
shuttleTime: 600
violet:
announcement: alert-level-violet-announcement
sound: /Audio/Misc/notice1.ogg
color: Violet
emergencyLightColor: Violet
forceEnableEmergencyLights: true
shuttleTime: 600
yellow:
announcement: alert-level-yellow-announcement
sound: /Audio/Misc/notice1.ogg
color: Yellow
emergencyLightColor: Goldenrod
forceEnableEmergencyLights: true
shuttleTime: 600
red:
announcement: alert-level-red-announcement
sound: /Audio/Corvax/Misc/red.ogg # Corvax-Announcements #base:/Audio/Misc/redalert.ogg
color: Red
emergencyLightColor: Red
forceEnableEmergencyLights: true
shuttleTime: 600 #No reduction in time as we don't have swiping for red alert like in /tg/. Shuttle times are intended to create friction, so having a way to brainlessly bypass that would be dumb.
gamma:
announcement: alert-level-gamma-announcement
selectable: false
sound:
path: /Audio/Corvax/Misc/siren.ogg # Corvax: Return of the old siren sound
params:
volume: -2
disableSelection: true
color: PaleVioletRed
emergencyLightColor: PaleVioletRed
forceEnableEmergencyLights: true
delta:
announcement: alert-level-delta-announcement
selectable: false
sound:
path: /Audio/Corvax/Misc/delta.ogg # Corvax-Announcements #base:/Audio/Misc/delta.ogg
params:
volume: -6 # Corvax: Reduce sound volume
disableSelection: true
color: DarkRed
emergencyLightColor: Orange
forceEnableEmergencyLights: true
shuttleTime: 1200
epsilon:
announcement: alert-level-epsilon-announcement
selectable: false
sound:
path: /Audio/Misc/epsilon.ogg
params:
volume: -2
disableSelection: true
color: DarkViolet
emergencyLightColor: DarkViolet
forceEnableEmergencyLights: true
shuttleTime: 1200
- Green
- Blue
- Violet
- Yellow
- Red
- Gamma
- Delta
- Epsilon
- type: alertLevel
id: Green
announcement: alert-level-green-announcement
sound: /Audio/Corvax/Misc/green_down.ogg # Corvax-Announcements
color: Green
emergencyLightColor: LawnGreen
shuttleTime: 600
- type: alertLevel
id: Blue
announcement: alert-level-blue-announcement
sound: /Audio/Corvax/Misc/blue.ogg # Corvax-Announcements #base:/Audio/Misc/bluealert.ogg
color: DodgerBlue
forceEnableEmergencyLights: true
emergencyLightColor: DodgerBlue
shuttleTime: 600
- type: alertLevel
id: Violet
announcement: alert-level-violet-announcement
sound: /Audio/Misc/notice1.ogg
color: Violet
emergencyLightColor: Violet
forceEnableEmergencyLights: true
shuttleTime: 600
- type: alertLevel
id: Yellow
announcement: alert-level-yellow-announcement
sound: /Audio/Misc/notice1.ogg
color: Yellow
emergencyLightColor: Goldenrod
forceEnableEmergencyLights: true
shuttleTime: 600
- type: alertLevel
id: Red
announcement: alert-level-red-announcement
sound: /Audio/Corvax/Misc/red.ogg # Corvax-Announcements #base:/Audio/Misc/redalert.ogg
color: Red
emergencyLightColor: Red
forceEnableEmergencyLights: true
shuttleTime: 600 #No reduction in time as we don't have swiping for red alert like in /tg/. Shuttle times are intended to create friction, so having a way to brainlessly bypass that would be dumb.
- type: alertLevel
id: Gamma
announcement: alert-level-gamma-announcement
selectable: false
sound:
path: /Audio/Corvax/Misc/siren.ogg # Corvax: Return of the old siren sound
params:
volume: -2
disableSelection: true
color: PaleVioletRed
emergencyLightColor: PaleVioletRed
forceEnableEmergencyLights: true
- type: alertLevel
id: Delta
announcement: alert-level-delta-announcement
selectable: false
sound:
path: /Audio/Corvax/Misc/delta.ogg # Corvax-Announcements #base:/Audio/Misc/delta.ogg
params:
volume: -6 # Corvax: Reduce sound volume
disableSelection: true
color: DarkRed
emergencyLightColor: Orange
forceEnableEmergencyLights: true
shuttleTime: 1200
- type: alertLevel
id: Epsilon
announcement: alert-level-epsilon-announcement
selectable: false
sound:
path: /Audio/Misc/epsilon.ogg
params:
volume: -2
disableSelection: true
color: DarkViolet
emergencyLightColor: DarkViolet
forceEnableEmergencyLights: true
shuttleTime: 1200
# WL-Changes-end

View File

@@ -140,7 +140,7 @@
abstract: true
components:
- type: AlertLevel
alertLevelPrototype: stationAlerts
alertLevelsListPrototype: stationAlerts # WL-Changes: Alert Level Rework
- type: entity
id: BaseStationExpeditions