ECSatize AlertsSystem (#5559)
This commit is contained in:
@@ -1,226 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Content.Client.Alerts.UI;
|
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.Player;
|
|
||||||
using Robust.Client.UserInterface;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Input;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
|
||||||
|
|
||||||
namespace Content.Client.Alerts
|
|
||||||
{
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(SharedAlertsComponent))]
|
|
||||||
public sealed class ClientAlertsComponent : SharedAlertsComponent
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
||||||
|
|
||||||
private AlertsUI? _ui;
|
|
||||||
private AlertOrderPrototype? _alertOrder;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
private readonly Dictionary<AlertKey, AlertControl> _alertControls
|
|
||||||
= new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Allows calculating if we need to act due to this component being controlled by the current mob
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
private bool CurrentlyControlled => _playerManager.LocalPlayer != null && _playerManager.LocalPlayer.ControlledEntity == Owner;
|
|
||||||
|
|
||||||
protected override void Shutdown()
|
|
||||||
{
|
|
||||||
base.Shutdown();
|
|
||||||
PlayerDetached();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
|
||||||
{
|
|
||||||
base.HandleComponentState(curState, nextState);
|
|
||||||
|
|
||||||
if (curState is not AlertsComponentState)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateAlertsControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PlayerAttached()
|
|
||||||
{
|
|
||||||
if (!CurrentlyControlled || _ui != null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_alertOrder = IoCManager.Resolve<IPrototypeManager>().EnumeratePrototypes<AlertOrderPrototype>().FirstOrDefault();
|
|
||||||
if (_alertOrder == null)
|
|
||||||
{
|
|
||||||
Logger.ErrorS("alert", "no alertOrder prototype found, alerts will be in random order");
|
|
||||||
}
|
|
||||||
|
|
||||||
_ui = new AlertsUI();
|
|
||||||
IoCManager.Resolve<IUserInterfaceManager>().StateRoot.AddChild(_ui);
|
|
||||||
|
|
||||||
UpdateAlertsControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PlayerDetached()
|
|
||||||
{
|
|
||||||
foreach (var alertControl in _alertControls.Values)
|
|
||||||
{
|
|
||||||
alertControl.OnPressed -= AlertControlOnPressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_ui != null)
|
|
||||||
{
|
|
||||||
IoCManager.Resolve<IUserInterfaceManager>().StateRoot.RemoveChild(_ui);
|
|
||||||
_ui = null;
|
|
||||||
}
|
|
||||||
_alertControls.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the displayed alerts based on current state of Alerts, performing
|
|
||||||
/// a diff to ensure we only change what's changed (this avoids active tooltips disappearing any
|
|
||||||
/// time state changes)
|
|
||||||
/// </summary>
|
|
||||||
private void UpdateAlertsControls()
|
|
||||||
{
|
|
||||||
if (!CurrentlyControlled || _ui == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove any controls with keys no longer present
|
|
||||||
var toRemove = new List<AlertKey>();
|
|
||||||
foreach (var existingKey in _alertControls.Keys)
|
|
||||||
{
|
|
||||||
if (!IsShowingAlert(existingKey))
|
|
||||||
{
|
|
||||||
toRemove.Add(existingKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var alertKeyToRemove in toRemove)
|
|
||||||
{
|
|
||||||
_alertControls.Remove(alertKeyToRemove, out var control);
|
|
||||||
if (control == null) return;
|
|
||||||
_ui.AlertContainer.Children.Remove(control);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now we know that alertControls contains alerts that should still exist but
|
|
||||||
// may need to updated,
|
|
||||||
// also there may be some new alerts we need to show.
|
|
||||||
// further, we need to ensure they are ordered w.r.t their configured order
|
|
||||||
foreach (var (alertKey, alertState) in EnumerateAlertStates())
|
|
||||||
{
|
|
||||||
if (!alertKey.AlertType.HasValue)
|
|
||||||
{
|
|
||||||
Logger.WarningS("alert", "found alertkey without alerttype," +
|
|
||||||
" alert keys should never be stored without an alerttype set: {0}", alertKey);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var alertType = alertKey.AlertType.Value;
|
|
||||||
if (!AlertManager.TryGet(alertType, out var newAlert))
|
|
||||||
{
|
|
||||||
Logger.ErrorS("alert", "Unrecognized alertType {0}", alertType);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_alertControls.TryGetValue(newAlert.AlertKey, out var existingAlertControl) &&
|
|
||||||
existingAlertControl.Alert.AlertType == newAlert.AlertType)
|
|
||||||
{
|
|
||||||
// key is the same, simply update the existing control severity / cooldown
|
|
||||||
existingAlertControl.SetSeverity(alertState.Severity);
|
|
||||||
existingAlertControl.Cooldown = alertState.Cooldown;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (existingAlertControl != null)
|
|
||||||
{
|
|
||||||
_ui.AlertContainer.Children.Remove(existingAlertControl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is a new alert + alert key or just a different alert with the same
|
|
||||||
// key, create the control and add it in the appropriate order
|
|
||||||
var newAlertControl = CreateAlertControl(newAlert, alertState);
|
|
||||||
if (_alertOrder != null)
|
|
||||||
{
|
|
||||||
var added = false;
|
|
||||||
foreach (var alertControl in _ui.AlertContainer.Children)
|
|
||||||
{
|
|
||||||
if (_alertOrder.Compare(newAlert, ((AlertControl) alertControl).Alert) < 0)
|
|
||||||
{
|
|
||||||
var idx = alertControl.GetPositionInParent();
|
|
||||||
_ui.AlertContainer.Children.Add(newAlertControl);
|
|
||||||
newAlertControl.SetPositionInParent(idx);
|
|
||||||
added = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!added)
|
|
||||||
{
|
|
||||||
_ui.AlertContainer.Children.Add(newAlertControl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_ui.AlertContainer.Children.Add(newAlertControl);
|
|
||||||
}
|
|
||||||
|
|
||||||
_alertControls[newAlert.AlertKey] = newAlertControl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private AlertControl CreateAlertControl(AlertPrototype alert, AlertState alertState)
|
|
||||||
{
|
|
||||||
var alertControl = new AlertControl(alert, alertState.Severity)
|
|
||||||
{
|
|
||||||
Cooldown = alertState.Cooldown
|
|
||||||
};
|
|
||||||
alertControl.OnPressed += AlertControlOnPressed;
|
|
||||||
return alertControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AlertControlOnPressed(ButtonEventArgs args)
|
|
||||||
{
|
|
||||||
if (args.Button is not AlertControl control)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AlertPressed(args, control);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AlertPressed(ButtonEventArgs args, AlertControl alert)
|
|
||||||
{
|
|
||||||
if (args.Event.Function != EngineKeyFunctions.UIClick)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma warning disable 618
|
|
||||||
SendNetworkMessage(new ClickAlertMessage(alert.Alert.AlertType));
|
|
||||||
#pragma warning restore 618
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void AfterShowAlert()
|
|
||||||
{
|
|
||||||
UpdateAlertsControls();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void AfterClearAlert()
|
|
||||||
{
|
|
||||||
UpdateAlertsControls();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,115 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Shared.Alert;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.Alerts
|
namespace Content.Client.Alerts;
|
||||||
|
|
||||||
|
[UsedImplicitly]
|
||||||
|
internal class ClientAlertsSystem : AlertsSystem
|
||||||
{
|
{
|
||||||
internal class ClientAlertsSystem : EntitySystem
|
public AlertOrderPrototype? AlertOrder { get; set; }
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<ClientAlertsComponent, PlayerAttachedEvent>((_, component, _) => component.PlayerAttached());
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
SubscribeLocalEvent<ClientAlertsComponent, PlayerDetachedEvent>((_, component, _) => component.PlayerDetached());
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
|
public event EventHandler? ClearAlerts;
|
||||||
|
public event EventHandler<IReadOnlyDictionary<AlertKey, AlertState>>? SyncAlerts;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<AlertsComponent, PlayerAttachedEvent>((_, component, _) => PlayerAttached(component));
|
||||||
|
SubscribeLocalEvent<AlertsComponent, PlayerDetachedEvent>((_, _, _) => PlayerDetached());
|
||||||
|
|
||||||
|
SubscribeLocalEvent<AlertsComponent, ComponentHandleState>(ClientAlertsHandleState);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadPrototypes()
|
||||||
|
{
|
||||||
|
base.LoadPrototypes();
|
||||||
|
|
||||||
|
AlertOrder = _prototypeManager.EnumeratePrototypes<AlertOrderPrototype>().FirstOrDefault();
|
||||||
|
if (AlertOrder == null)
|
||||||
|
Logger.ErrorS("alert", "no alertOrder prototype found, alerts will be in random order");
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<AlertKey, AlertState>? ActiveAlerts
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var ent = _playerManager.LocalPlayer?.ControlledEntity;
|
||||||
|
return ent is not null
|
||||||
|
? GetActiveAlerts(ent.Value)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void AfterShowAlert(AlertsComponent alertsComponent)
|
||||||
|
{
|
||||||
|
if (!CurControlled(alertsComponent.Owner, _playerManager))
|
||||||
|
return;
|
||||||
|
|
||||||
|
SyncAlerts?.Invoke(this, alertsComponent.Alerts);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AfterClearAlert(AlertsComponent alertsComponent)
|
||||||
|
{
|
||||||
|
if (!CurControlled(alertsComponent.Owner, _playerManager))
|
||||||
|
return;
|
||||||
|
|
||||||
|
SyncAlerts?.Invoke(this, alertsComponent.Alerts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClientAlertsHandleState(EntityUid uid, AlertsComponent component, ref ComponentHandleState args)
|
||||||
|
{
|
||||||
|
var componentAlerts = (args.Current as AlertsComponentState)?.Alerts;
|
||||||
|
if (componentAlerts == null) return;
|
||||||
|
|
||||||
|
//TODO: Do we really want to send alerts for non-attached entity?
|
||||||
|
component.Alerts = componentAlerts;
|
||||||
|
if (!CurControlled(component.Owner, _playerManager)) return;
|
||||||
|
|
||||||
|
SyncAlerts?.Invoke(this, componentAlerts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayerAttached(AlertsComponent clientAlertsComponent)
|
||||||
|
{
|
||||||
|
if (!CurControlled(clientAlertsComponent.Owner, _playerManager)) return;
|
||||||
|
SyncAlerts?.Invoke(this, clientAlertsComponent.Alerts);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void HandleComponentShutdown(EntityUid uid)
|
||||||
|
{
|
||||||
|
base.HandleComponentShutdown(uid);
|
||||||
|
|
||||||
|
PlayerDetached();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayerDetached()
|
||||||
|
{
|
||||||
|
ClearAlerts?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AlertClicked(AlertType alertType)
|
||||||
|
{
|
||||||
|
RaiseNetworkEvent(new ClickAlertEvent(alertType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allows calculating if we need to act due to this component being controlled by the current mob
|
||||||
|
/// </summary>
|
||||||
|
private static bool CurControlled(EntityUid entity, IPlayerManager playerManager)
|
||||||
|
{
|
||||||
|
return playerManager.LocalPlayer != null && playerManager.LocalPlayer.ControlledEntity == entity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,79 +1,344 @@
|
|||||||
using Content.Client.Chat.Managers;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Client.Chat.Managers;
|
||||||
using Content.Client.Chat.UI;
|
using Content.Client.Chat.UI;
|
||||||
|
using Content.Shared.Alert;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Input;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
|
||||||
namespace Content.Client.Alerts.UI
|
namespace Content.Client.Alerts.UI;
|
||||||
|
|
||||||
|
public class AlertsFramePresenter : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
[Dependency] private readonly IEntitySystemManager _systemManager = default!;
|
||||||
/// The status effects display on the right side of the screen.
|
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||||
/// </summary>
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[GenerateTypedNameReferences]
|
|
||||||
public sealed partial class AlertsUI : Control
|
private IAlertsFrameView _alertsFrame;
|
||||||
|
private ClientAlertsSystem? _alertsSystem;
|
||||||
|
|
||||||
|
public AlertsFramePresenter()
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
// This is a lot easier than a factory
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
public const float ChatSeparation = 38f;
|
_alertsFrame = new AlertsUI(_chatManager);
|
||||||
|
_userInterfaceManager.StateRoot.AddChild((AlertsUI) _alertsFrame);
|
||||||
|
|
||||||
public AlertsUI()
|
// This is required so that if we load after the system is initialized, we can bind to it immediately
|
||||||
|
if (_systemManager.TryGetEntitySystem<ClientAlertsSystem>(out var alertsSystem))
|
||||||
|
SystemBindingChanged(alertsSystem);
|
||||||
|
|
||||||
|
_systemManager.SystemLoaded += OnSystemLoaded;
|
||||||
|
_systemManager.SystemUnloaded += OnSystemUnloaded;
|
||||||
|
|
||||||
|
_alertsFrame.AlertPressed += OnAlertPressed;
|
||||||
|
|
||||||
|
// initially populate the frame if system is available
|
||||||
|
var alerts = alertsSystem?.ActiveAlerts;
|
||||||
|
if (alerts != null)
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
SystemOnSyncAlerts(alertsSystem, alerts);
|
||||||
RobustXamlLoader.Load(this);
|
|
||||||
|
|
||||||
LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.Begin);
|
|
||||||
LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.End);
|
|
||||||
LayoutContainer.SetAnchorTop(this, 0f);
|
|
||||||
LayoutContainer.SetAnchorRight(this, 1f);
|
|
||||||
LayoutContainer.SetAnchorBottom(this, 1f);
|
|
||||||
LayoutContainer.SetMarginBottom(this, -180);
|
|
||||||
LayoutContainer.SetMarginTop(this, 250);
|
|
||||||
LayoutContainer.SetMarginRight(this, -10);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void EnteredTree()
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_userInterfaceManager.StateRoot.RemoveChild((AlertsUI) _alertsFrame);
|
||||||
|
_alertsFrame.Dispose();
|
||||||
|
_alertsFrame = null!;
|
||||||
|
|
||||||
|
SystemBindingChanged(null);
|
||||||
|
_systemManager.SystemLoaded -= OnSystemLoaded;
|
||||||
|
_systemManager.SystemUnloaded -= OnSystemUnloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAlertPressed(object? sender, AlertType e)
|
||||||
|
{
|
||||||
|
_alertsSystem?.AlertClicked(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SystemOnClearAlerts(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_alertsFrame.ClearAllControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SystemOnSyncAlerts(object? sender, IReadOnlyDictionary<AlertKey, AlertState> e)
|
||||||
|
{
|
||||||
|
if (sender is ClientAlertsSystem system)
|
||||||
|
_alertsFrame.SyncControls(system, system.AlertOrder, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: This system binding boilerplate seems to be duplicated between every presenter
|
||||||
|
// prob want to pull it out into a generic object with callbacks for Onbind/OnUnbind
|
||||||
|
#region System Binding
|
||||||
|
|
||||||
|
private void OnSystemLoaded(object? sender, SystemChangedArgs args)
|
||||||
|
{
|
||||||
|
if (args.System is ClientAlertsSystem system) SystemBindingChanged(system);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSystemUnloaded(object? sender, SystemChangedArgs args)
|
||||||
|
{
|
||||||
|
if (args.System is ClientAlertsSystem) SystemBindingChanged(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SystemBindingChanged(ClientAlertsSystem? newSystem)
|
||||||
|
{
|
||||||
|
if (newSystem is null)
|
||||||
{
|
{
|
||||||
base.EnteredTree();
|
if (_alertsSystem is null)
|
||||||
_chatManager.OnChatBoxResized += OnChatResized;
|
return;
|
||||||
OnChatResized(new ChatResizedEventArgs(HudChatBox.InitialChatBottom));
|
|
||||||
|
UnbindFromSystem();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
protected override void ExitedTree()
|
|
||||||
{
|
{
|
||||||
base.ExitedTree();
|
if (_alertsSystem is null)
|
||||||
_chatManager.OnChatBoxResized -= OnChatResized;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnChatResized(ChatResizedEventArgs chatResizedEventArgs)
|
|
||||||
{
|
|
||||||
// resize us to fit just below the chatbox
|
|
||||||
if (_chatManager.CurrentChatBox != null)
|
|
||||||
{
|
{
|
||||||
LayoutContainer.SetMarginTop(this, chatResizedEventArgs.NewBottom + ChatSeparation);
|
BindToSystem(newSystem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnbindFromSystem();
|
||||||
|
BindToSystem(newSystem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BindToSystem(ClientAlertsSystem system)
|
||||||
|
{
|
||||||
|
_alertsSystem = system;
|
||||||
|
system.SyncAlerts += SystemOnSyncAlerts;
|
||||||
|
system.ClearAlerts += SystemOnClearAlerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnbindFromSystem()
|
||||||
|
{
|
||||||
|
var system = _alertsSystem;
|
||||||
|
|
||||||
|
if (system is null)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
system.SyncAlerts -= SystemOnSyncAlerts;
|
||||||
|
system.ClearAlerts -= SystemOnClearAlerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is the frame of vertical set of alerts that show up on the HUD.
|
||||||
|
/// </summary>
|
||||||
|
public interface IAlertsFrameView : IDisposable
|
||||||
|
{
|
||||||
|
event EventHandler<AlertType>? AlertPressed;
|
||||||
|
|
||||||
|
void SyncControls(AlertsSystem alertsSystem, AlertOrderPrototype? alertOrderPrototype,
|
||||||
|
IReadOnlyDictionary<AlertKey, AlertState> alertStates);
|
||||||
|
void ClearAllControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The status effects display on the right side of the screen.
|
||||||
|
/// </summary>
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class AlertsUI : Control, IAlertsFrameView
|
||||||
|
{
|
||||||
|
// also known as Control.Children?
|
||||||
|
private readonly Dictionary<AlertKey, AlertControl> _alertControls = new();
|
||||||
|
|
||||||
|
public AlertsUI(IChatManager chatManager)
|
||||||
|
{
|
||||||
|
_chatManager = chatManager;
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
|
LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.Begin);
|
||||||
|
LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.End);
|
||||||
|
LayoutContainer.SetAnchorTop(this, 0f);
|
||||||
|
LayoutContainer.SetAnchorRight(this, 1f);
|
||||||
|
LayoutContainer.SetAnchorBottom(this, 1f);
|
||||||
|
LayoutContainer.SetMarginBottom(this, -180);
|
||||||
|
LayoutContainer.SetMarginTop(this, 250);
|
||||||
|
LayoutContainer.SetMarginRight(this, -10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SyncControls(AlertsSystem alertsSystem, AlertOrderPrototype? alertOrderPrototype,
|
||||||
|
IReadOnlyDictionary<AlertKey, AlertState> alertStates)
|
||||||
|
{
|
||||||
|
// remove any controls with keys no longer present
|
||||||
|
if (SyncRemoveControls(alertStates)) return;
|
||||||
|
|
||||||
|
// now we know that alertControls contains alerts that should still exist but
|
||||||
|
// may need to updated,
|
||||||
|
// also there may be some new alerts we need to show.
|
||||||
|
// further, we need to ensure they are ordered w.r.t their configured order
|
||||||
|
SyncUpdateControls(alertsSystem, alertOrderPrototype, alertStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearAllControls()
|
||||||
|
{
|
||||||
|
foreach (var alertControl in _alertControls.Values)
|
||||||
|
{
|
||||||
|
alertControl.OnPressed -= AlertControlPressed;
|
||||||
|
alertControl.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_alertControls.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<AlertType>? AlertPressed;
|
||||||
|
|
||||||
|
//TODO: This control caring about it's layout relative to other controls in the tree is terrible
|
||||||
|
// the presenters or gamescreen should be dealing with this
|
||||||
|
// probably want to tackle this after chatbox gets MVP'd
|
||||||
|
#region Spaghetti
|
||||||
|
|
||||||
|
public const float ChatSeparation = 38f;
|
||||||
|
private readonly IChatManager _chatManager;
|
||||||
|
|
||||||
|
protected override void EnteredTree()
|
||||||
|
{
|
||||||
|
base.EnteredTree();
|
||||||
|
_chatManager.OnChatBoxResized += OnChatResized;
|
||||||
|
OnChatResized(new ChatResizedEventArgs(HudChatBox.InitialChatBottom));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ExitedTree()
|
||||||
|
{
|
||||||
|
base.ExitedTree();
|
||||||
|
_chatManager.OnChatBoxResized -= OnChatResized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnChatResized(ChatResizedEventArgs chatResizedEventArgs)
|
||||||
|
{
|
||||||
|
// resize us to fit just below the chat box
|
||||||
|
if (_chatManager.CurrentChatBox != null)
|
||||||
|
LayoutContainer.SetMarginTop(this, chatResizedEventArgs.NewBottom + ChatSeparation);
|
||||||
|
else
|
||||||
|
LayoutContainer.SetMarginTop(this, 250);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// This makes no sense but I'm leaving it in place in case I break anything by removing it.
|
||||||
|
protected override void Resized()
|
||||||
|
{
|
||||||
|
// TODO: Can rework this once https://github.com/space-wizards/RobustToolbox/issues/1392 is done,
|
||||||
|
// this is here because there isn't currently a good way to allow the grid to adjust its height based
|
||||||
|
// on constraints, otherwise we would use anchors to lay it out
|
||||||
|
base.Resized();
|
||||||
|
AlertContainer.MaxGridHeight = Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UIScaleChanged()
|
||||||
|
{
|
||||||
|
AlertContainer.MaxGridHeight = Height;
|
||||||
|
base.UIScaleChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SyncRemoveControls(IReadOnlyDictionary<AlertKey, AlertState> alertStates)
|
||||||
|
{
|
||||||
|
var toRemove = new List<AlertKey>();
|
||||||
|
foreach (var existingKey in _alertControls.Keys)
|
||||||
|
{
|
||||||
|
if (!alertStates.ContainsKey(existingKey)) toRemove.Add(existingKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var alertKeyToRemove in toRemove)
|
||||||
|
{
|
||||||
|
_alertControls.Remove(alertKeyToRemove, out var control);
|
||||||
|
if (control == null) return true;
|
||||||
|
AlertContainer.Children.Remove(control);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SyncUpdateControls(AlertsSystem alertsSystem, AlertOrderPrototype? alertOrderPrototype,
|
||||||
|
IReadOnlyDictionary<AlertKey, AlertState> alertStates)
|
||||||
|
{
|
||||||
|
foreach (var (alertKey, alertState) in alertStates)
|
||||||
|
{
|
||||||
|
if (!alertKey.AlertType.HasValue)
|
||||||
|
{
|
||||||
|
Logger.WarningS("alert", "found alertkey without alerttype," +
|
||||||
|
" alert keys should never be stored without an alerttype set: {0}", alertKey);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var alertType = alertKey.AlertType.Value;
|
||||||
|
if (!alertsSystem.TryGet(alertType, out var newAlert))
|
||||||
|
{
|
||||||
|
Logger.ErrorS("alert", "Unrecognized alertType {0}", alertType);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_alertControls.TryGetValue(newAlert.AlertKey, out var existingAlertControl) &&
|
||||||
|
existingAlertControl.Alert.AlertType == newAlert.AlertType)
|
||||||
|
{
|
||||||
|
// key is the same, simply update the existing control severity / cooldown
|
||||||
|
existingAlertControl.SetSeverity(alertState.Severity);
|
||||||
|
existingAlertControl.Cooldown = alertState.Cooldown;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LayoutContainer.SetMarginTop(this, 250);
|
if (existingAlertControl != null) AlertContainer.Children.Remove(existingAlertControl);
|
||||||
|
|
||||||
|
// this is a new alert + alert key or just a different alert with the same
|
||||||
|
// key, create the control and add it in the appropriate order
|
||||||
|
var newAlertControl = CreateAlertControl(newAlert, alertState);
|
||||||
|
|
||||||
|
//TODO: Can the presenter sort the states before giving it to us?
|
||||||
|
if (alertOrderPrototype != null)
|
||||||
|
{
|
||||||
|
var added = false;
|
||||||
|
foreach (var alertControl in AlertContainer.Children)
|
||||||
|
{
|
||||||
|
if (alertOrderPrototype.Compare(newAlert, ((AlertControl) alertControl).Alert) >= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var idx = alertControl.GetPositionInParent();
|
||||||
|
AlertContainer.Children.Add(newAlertControl);
|
||||||
|
newAlertControl.SetPositionInParent(idx);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!added) AlertContainer.Children.Add(newAlertControl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
AlertContainer.Children.Add(newAlertControl);
|
||||||
|
|
||||||
|
_alertControls[newAlert.AlertKey] = newAlertControl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This makes no sense but I'm leaving it in place in case I break anything by removing it.
|
private AlertControl CreateAlertControl(AlertPrototype alert, AlertState alertState)
|
||||||
|
{
|
||||||
protected override void Resized()
|
var alertControl = new AlertControl(alert, alertState.Severity)
|
||||||
{
|
{
|
||||||
// TODO: Can rework this once https://github.com/space-wizards/RobustToolbox/issues/1392 is done,
|
Cooldown = alertState.Cooldown
|
||||||
// this is here because there isn't currently a good way to allow the grid to adjust its height based
|
};
|
||||||
// on constraints, otherwise we would use anchors to lay it out
|
alertControl.OnPressed += AlertControlPressed;
|
||||||
base.Resized();
|
return alertControl;
|
||||||
AlertContainer.MaxGridHeight = Height;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UIScaleChanged()
|
private void AlertControlPressed(BaseButton.ButtonEventArgs args)
|
||||||
{
|
{
|
||||||
AlertContainer.MaxGridHeight = Height;
|
if (args.Button is not AlertControl control)
|
||||||
base.UIScaleChanged();
|
return;
|
||||||
}
|
|
||||||
|
if (args.Event.Function != EngineKeyFunctions.UIClick)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AlertPressed?.Invoke(this, control.Alert.AlertType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,7 +190,6 @@ namespace Content.Client.Entry
|
|||||||
IoCManager.Resolve<IClientPreferencesManager>().Initialize();
|
IoCManager.Resolve<IClientPreferencesManager>().Initialize();
|
||||||
IoCManager.Resolve<IStationEventManager>().Initialize();
|
IoCManager.Resolve<IStationEventManager>().Initialize();
|
||||||
IoCManager.Resolve<EuiManager>().Initialize();
|
IoCManager.Resolve<EuiManager>().Initialize();
|
||||||
IoCManager.Resolve<AlertManager>().Initialize();
|
|
||||||
IoCManager.Resolve<ActionManager>().Initialize();
|
IoCManager.Resolve<ActionManager>().Initialize();
|
||||||
IoCManager.Resolve<IVoteManager>().Initialize();
|
IoCManager.Resolve<IVoteManager>().Initialize();
|
||||||
IoCManager.Resolve<IGamePrototypeLoadManager>().Initialize();
|
IoCManager.Resolve<IGamePrototypeLoadManager>().Initialize();
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ using Content.Client.Viewport;
|
|||||||
using Content.Client.Voting;
|
using Content.Client.Voting;
|
||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Content.Shared.Module;
|
using Content.Shared.Module;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
@@ -41,7 +40,6 @@ namespace Content.Client.IoC
|
|||||||
IoCManager.Register<IScreenshotHook, ScreenshotHook>();
|
IoCManager.Register<IScreenshotHook, ScreenshotHook>();
|
||||||
IoCManager.Register<IClickMapManager, ClickMapManager>();
|
IoCManager.Register<IClickMapManager, ClickMapManager>();
|
||||||
IoCManager.Register<IStationEventManager, StationEventManager>();
|
IoCManager.Register<IStationEventManager, StationEventManager>();
|
||||||
IoCManager.Register<AlertManager, AlertManager>();
|
|
||||||
IoCManager.Register<ActionManager, ActionManager>();
|
IoCManager.Register<ActionManager, ActionManager>();
|
||||||
IoCManager.Register<IClientAdminManager, ClientAdminManager>();
|
IoCManager.Register<IClientAdminManager, ClientAdminManager>();
|
||||||
IoCManager.Register<EuiManager, EuiManager>();
|
IoCManager.Register<EuiManager, EuiManager>();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Client.Administration.Managers;
|
using Content.Client.Alerts.UI;
|
||||||
using Content.Client.Chat;
|
using Content.Client.Chat;
|
||||||
using Content.Client.Chat.Managers;
|
using Content.Client.Chat.Managers;
|
||||||
using Content.Client.Chat.UI;
|
using Content.Client.Chat.UI;
|
||||||
@@ -38,6 +38,7 @@ namespace Content.Client.Viewport
|
|||||||
|
|
||||||
[ViewVariables] private ChatBox? _gameChat;
|
[ViewVariables] private ChatBox? _gameChat;
|
||||||
private ConstructionMenuPresenter? _constructionMenu;
|
private ConstructionMenuPresenter? _constructionMenu;
|
||||||
|
private AlertsFramePresenter? _alertsFramePresenter;
|
||||||
|
|
||||||
private FpsCounter _fpsCounter = default!;
|
private FpsCounter _fpsCounter = default!;
|
||||||
|
|
||||||
@@ -107,6 +108,10 @@ namespace Content.Client.Viewport
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void SetupPresenters()
|
private void SetupPresenters()
|
||||||
{
|
{
|
||||||
|
// HUD
|
||||||
|
_alertsFramePresenter = new AlertsFramePresenter();
|
||||||
|
|
||||||
|
// Windows
|
||||||
_constructionMenu = new ConstructionMenuPresenter(_gameHud);
|
_constructionMenu = new ConstructionMenuPresenter(_gameHud);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +120,11 @@ namespace Content.Client.Viewport
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void DisposePresenters()
|
private void DisposePresenters()
|
||||||
{
|
{
|
||||||
|
// Windows
|
||||||
_constructionMenu?.Dispose();
|
_constructionMenu?.Dispose();
|
||||||
|
|
||||||
|
// HUD
|
||||||
|
_alertsFramePresenter?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void FocusChat(ChatBox chat)
|
internal static void FocusChat(ChatBox chat)
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Client.Alerts;
|
|
||||||
using Content.Client.Alerts.UI;
|
using Content.Client.Alerts.UI;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Server.Player;
|
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
|
namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[TestOf(typeof(ClientAlertsComponent))]
|
[TestOf(typeof(AlertsComponent))]
|
||||||
[TestOf(typeof(ServerAlertsComponent))]
|
|
||||||
public class AlertsComponentTests : ContentIntegrationTest
|
public class AlertsComponentTests : ContentIntegrationTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
@@ -26,17 +23,18 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
|
|||||||
await client.WaitIdleAsync();
|
await client.WaitIdleAsync();
|
||||||
|
|
||||||
var serverPlayerManager = server.ResolveDependency<IPlayerManager>();
|
var serverPlayerManager = server.ResolveDependency<IPlayerManager>();
|
||||||
|
var alertsSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<AlertsSystem>();
|
||||||
|
|
||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
{
|
{
|
||||||
var playerEnt = serverPlayerManager.Sessions.Single().AttachedEntity.GetValueOrDefault();
|
var playerEnt = serverPlayerManager.Sessions.Single().AttachedEntity.GetValueOrDefault();
|
||||||
Assert.That(playerEnt != default);
|
Assert.That(playerEnt != default);
|
||||||
var alertsComponent = IoCManager.Resolve<IEntityManager>().GetComponent<ServerAlertsComponent>(playerEnt);
|
var alertsComponent = IoCManager.Resolve<IEntityManager>().GetComponent<AlertsComponent>(playerEnt);
|
||||||
Assert.NotNull(alertsComponent);
|
Assert.NotNull(alertsComponent);
|
||||||
|
|
||||||
// show 2 alerts
|
// show 2 alerts
|
||||||
alertsComponent.ShowAlert(AlertType.Debug1);
|
alertsSystem.ShowAlert(alertsComponent.Owner, AlertType.Debug1, null, null);
|
||||||
alertsComponent.ShowAlert(AlertType.Debug2);
|
alertsSystem.ShowAlert(alertsComponent.Owner, AlertType.Debug2, null, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.WaitRunTicks(5);
|
await server.WaitRunTicks(5);
|
||||||
@@ -51,7 +49,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
|
|||||||
Assert.NotNull(local);
|
Assert.NotNull(local);
|
||||||
var controlled = local.ControlledEntity;
|
var controlled = local.ControlledEntity;
|
||||||
Assert.NotNull(controlled);
|
Assert.NotNull(controlled);
|
||||||
var alertsComponent = IoCManager.Resolve<IEntityManager>().GetComponent<ClientAlertsComponent>(controlled.Value);
|
var alertsComponent = IoCManager.Resolve<IEntityManager>().GetComponent<AlertsComponent>(controlled.Value);
|
||||||
Assert.NotNull(alertsComponent);
|
Assert.NotNull(alertsComponent);
|
||||||
|
|
||||||
// find the alertsui
|
// find the alertsui
|
||||||
@@ -71,10 +69,10 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
|
|||||||
{
|
{
|
||||||
var playerEnt = serverPlayerManager.Sessions.Single().AttachedEntity.GetValueOrDefault();
|
var playerEnt = serverPlayerManager.Sessions.Single().AttachedEntity.GetValueOrDefault();
|
||||||
Assert.That(playerEnt, Is.Not.EqualTo(default));
|
Assert.That(playerEnt, Is.Not.EqualTo(default));
|
||||||
var alertsComponent = IoCManager.Resolve<IEntityManager>().GetComponent<ServerAlertsComponent>(playerEnt);
|
var alertsComponent = IoCManager.Resolve<IEntityManager>().GetComponent<AlertsComponent>(playerEnt);
|
||||||
Assert.NotNull(alertsComponent);
|
Assert.NotNull(alertsComponent);
|
||||||
|
|
||||||
alertsComponent.ClearAlert(AlertType.Debug1);
|
alertsSystem.ClearAlert(alertsComponent.Owner, AlertType.Debug1);
|
||||||
});
|
});
|
||||||
await server.WaitRunTicks(5);
|
await server.WaitRunTicks(5);
|
||||||
await client.WaitRunTicks(5);
|
await client.WaitRunTicks(5);
|
||||||
@@ -86,7 +84,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
|
|||||||
Assert.NotNull(local);
|
Assert.NotNull(local);
|
||||||
var controlled = local.ControlledEntity;
|
var controlled = local.ControlledEntity;
|
||||||
Assert.NotNull(controlled);
|
Assert.NotNull(controlled);
|
||||||
var alertsComponent = IoCManager.Resolve<IEntityManager>().GetComponent<ClientAlertsComponent>(controlled.Value);
|
var alertsComponent = IoCManager.Resolve<IEntityManager>().GetComponent<AlertsComponent>(controlled.Value);
|
||||||
Assert.NotNull(alertsComponent);
|
Assert.NotNull(alertsComponent);
|
||||||
|
|
||||||
// find the alertsui
|
// find the alertsui
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Gravity;
|
using Content.Server.Gravity;
|
||||||
using Content.Server.Gravity.EntitySystems;
|
using Content.Server.Gravity.EntitySystems;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
@@ -42,9 +42,9 @@ namespace Content.IntegrationTests.Tests.Gravity
|
|||||||
|
|
||||||
var mapManager = server.ResolveDependency<IMapManager>();
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
var alertsSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<AlertsSystem>();
|
||||||
|
|
||||||
EntityUid human = default;
|
EntityUid human = default;
|
||||||
SharedAlertsComponent alerts = null;
|
|
||||||
|
|
||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
{
|
{
|
||||||
@@ -52,7 +52,7 @@ namespace Content.IntegrationTests.Tests.Gravity
|
|||||||
var coordinates = grid.ToCoordinates();
|
var coordinates = grid.ToCoordinates();
|
||||||
human = entityManager.SpawnEntity("HumanDummy", coordinates);
|
human = entityManager.SpawnEntity("HumanDummy", coordinates);
|
||||||
|
|
||||||
Assert.True(entityManager.TryGetComponent(human, out alerts));
|
Assert.True(entityManager.TryGetComponent(human, out AlertsComponent alerts));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Let WeightlessSystem and GravitySystem tick
|
// Let WeightlessSystem and GravitySystem tick
|
||||||
@@ -61,7 +61,7 @@ namespace Content.IntegrationTests.Tests.Gravity
|
|||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
{
|
{
|
||||||
// No gravity without a gravity generator
|
// No gravity without a gravity generator
|
||||||
Assert.True(alerts.IsShowingAlert(AlertType.Weightless));
|
Assert.True(alertsSystem.IsShowingAlert(human, AlertType.Weightless));
|
||||||
|
|
||||||
entityManager.SpawnEntity("GravityGeneratorDummy", entityManager.GetComponent<TransformComponent>(human).Coordinates);
|
entityManager.SpawnEntity("GravityGeneratorDummy", entityManager.GetComponent<TransformComponent>(human).Coordinates);
|
||||||
});
|
});
|
||||||
@@ -71,7 +71,7 @@ namespace Content.IntegrationTests.Tests.Gravity
|
|||||||
|
|
||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
{
|
{
|
||||||
Assert.False(alerts.IsShowingAlert(AlertType.Weightless));
|
Assert.False(alertsSystem.IsShowingAlert(human, AlertType.Weightless));
|
||||||
|
|
||||||
// TODO: Re-add gravity generator breaking when Vera is done with construction stuff.
|
// TODO: Re-add gravity generator breaking when Vera is done with construction stuff.
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ namespace Content.Server.Alert.Click
|
|||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public class RemoveCuffs : IAlertClick
|
public class RemoveCuffs : IAlertClick
|
||||||
{
|
{
|
||||||
public void AlertClicked(ClickAlertEventArgs args)
|
public void AlertClicked(EntityUid player)
|
||||||
{
|
{
|
||||||
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(args.Player, out CuffableComponent? cuffableComponent))
|
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(player, out CuffableComponent? cuffableComponent))
|
||||||
{
|
{
|
||||||
cuffableComponent.TryUncuff(args.Player);
|
cuffableComponent.TryUncuff(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.Atmos.Components;
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@@ -15,11 +15,11 @@ namespace Content.Server.Alert.Click
|
|||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public class ResistFire : IAlertClick
|
public class ResistFire : IAlertClick
|
||||||
{
|
{
|
||||||
public void AlertClicked(ClickAlertEventArgs args)
|
public void AlertClicked(EntityUid player)
|
||||||
{
|
{
|
||||||
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(args.Player, out FlammableComponent? flammable))
|
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(player, out FlammableComponent? flammable))
|
||||||
{
|
{
|
||||||
EntitySystem.Get<FlammableSystem>().Resist(args.Player, flammable);
|
EntitySystem.Get<FlammableSystem>().Resist(player, flammable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ namespace Content.Server.Alert.Click
|
|||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public class StopBeingPulled : IAlertClick
|
public class StopBeingPulled : IAlertClick
|
||||||
{
|
{
|
||||||
public void AlertClicked(ClickAlertEventArgs args)
|
public void AlertClicked(EntityUid player)
|
||||||
{
|
{
|
||||||
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(args.Player))
|
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(player))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (IoCManager.Resolve<IEntityManager>().TryGetComponent<SharedPullableComponent?>(args.Player, out var playerPullable))
|
if (IoCManager.Resolve<IEntityManager>().TryGetComponent<SharedPullableComponent?>(player, out var playerPullable))
|
||||||
{
|
{
|
||||||
EntitySystem.Get<SharedPullingSystem>().TryStopPull(playerPullable);
|
EntitySystem.Get<SharedPullingSystem>().TryStopPull(playerPullable);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.Shuttles;
|
using Content.Server.Shuttles;
|
||||||
using Content.Server.Shuttles.EntitySystems;
|
using Content.Server.Shuttles.EntitySystems;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Shuttles;
|
using Content.Shared.Shuttles;
|
||||||
@@ -17,9 +17,9 @@ namespace Content.Server.Alert.Click
|
|||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public class StopPiloting : IAlertClick
|
public class StopPiloting : IAlertClick
|
||||||
{
|
{
|
||||||
public void AlertClicked(ClickAlertEventArgs args)
|
public void AlertClicked(EntityUid player)
|
||||||
{
|
{
|
||||||
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(args.Player, out PilotComponent? pilotComponent) &&
|
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(player, out PilotComponent? pilotComponent) &&
|
||||||
pilotComponent.Console != null)
|
pilotComponent.Console != null)
|
||||||
{
|
{
|
||||||
EntitySystem.Get<ShuttleConsoleSystem>().RemovePilot(pilotComponent);
|
EntitySystem.Get<ShuttleConsoleSystem>().RemovePilot(pilotComponent);
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ namespace Content.Server.Alert.Click
|
|||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public class StopPulling : IAlertClick
|
public class StopPulling : IAlertClick
|
||||||
{
|
{
|
||||||
public void AlertClicked(ClickAlertEventArgs args)
|
public void AlertClicked(EntityUid player)
|
||||||
{
|
{
|
||||||
var ps = EntitySystem.Get<SharedPullingSystem>();
|
var ps = EntitySystem.Get<SharedPullingSystem>();
|
||||||
var playerTarget = ps.GetPulled(args.Player);
|
var playerTarget = ps.GetPulled(player);
|
||||||
if (playerTarget != default && IoCManager.Resolve<IEntityManager>().TryGetComponent(playerTarget, out SharedPullableComponent playerPullable))
|
if (playerTarget != default && IoCManager.Resolve<IEntityManager>().TryGetComponent(playerTarget, out SharedPullableComponent playerPullable))
|
||||||
{
|
{
|
||||||
ps.TryStopPull(playerPullable);
|
ps.TryStopPull(playerPullable);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.Buckle.Components;
|
using Content.Server.Buckle.Components;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -14,11 +14,11 @@ namespace Content.Server.Alert.Click
|
|||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public class Unbuckle : IAlertClick
|
public class Unbuckle : IAlertClick
|
||||||
{
|
{
|
||||||
public void AlertClicked(ClickAlertEventArgs args)
|
public void AlertClicked(EntityUid player)
|
||||||
{
|
{
|
||||||
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(args.Player, out BuckleComponent? buckle))
|
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(player, out BuckleComponent? buckle))
|
||||||
{
|
{
|
||||||
buckle.TryUnbuckle(args.Player);
|
buckle.TryUnbuckle(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,21 +34,21 @@ namespace Content.Server.Alert.Commands
|
|||||||
if (!CommandUtils.TryGetAttachedEntityByUsernameOrId(shell, target, player, out attachedEntity)) return;
|
if (!CommandUtils.TryGetAttachedEntityByUsernameOrId(shell, target, player, out attachedEntity)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(attachedEntity, out ServerAlertsComponent? alertsComponent))
|
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(attachedEntity, out AlertsComponent? alertsComponent))
|
||||||
{
|
{
|
||||||
shell.WriteLine("user has no alerts component");
|
shell.WriteLine("user has no alerts component");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var alertType = args[0];
|
var alertType = args[0];
|
||||||
var alertMgr = IoCManager.Resolve<AlertManager>();
|
var alertsSystem = EntitySystem.Get<AlertsSystem>();
|
||||||
if (!alertMgr.TryGet(Enum.Parse<AlertType>(alertType), out var alert))
|
if (!alertsSystem.TryGet(Enum.Parse<AlertType>(alertType), out var alert))
|
||||||
{
|
{
|
||||||
shell.WriteLine("unrecognized alertType " + alertType);
|
shell.WriteLine("unrecognized alertType " + alertType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
alertsComponent.ClearAlert(alert.AlertType);
|
alertsSystem.ClearAlert(attachedEntity, alert.AlertType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace Content.Server.Alert.Commands
|
|||||||
if (!CommandUtils.TryGetAttachedEntityByUsernameOrId(shell, target, player, out attachedEntity)) return;
|
if (!CommandUtils.TryGetAttachedEntityByUsernameOrId(shell, target, player, out attachedEntity)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(attachedEntity, out ServerAlertsComponent? alertsComponent))
|
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(attachedEntity, out AlertsComponent? alertsComponent))
|
||||||
{
|
{
|
||||||
shell.WriteLine("user has no alerts component");
|
shell.WriteLine("user has no alerts component");
|
||||||
return;
|
return;
|
||||||
@@ -42,8 +42,8 @@ namespace Content.Server.Alert.Commands
|
|||||||
|
|
||||||
var alertType = args[0];
|
var alertType = args[0];
|
||||||
var severity = args[1];
|
var severity = args[1];
|
||||||
var alertMgr = IoCManager.Resolve<AlertManager>();
|
var alertsSystem = EntitySystem.Get<AlertsSystem>();
|
||||||
if (!alertMgr.TryGet(Enum.Parse<AlertType>(alertType), out var alert))
|
if (!alertsSystem.TryGet(Enum.Parse<AlertType>(alertType), out var alert))
|
||||||
{
|
{
|
||||||
shell.WriteLine("unrecognized alertType " + alertType);
|
shell.WriteLine("unrecognized alertType " + alertType);
|
||||||
return;
|
return;
|
||||||
@@ -53,7 +53,9 @@ namespace Content.Server.Alert.Commands
|
|||||||
shell.WriteLine("invalid severity " + sevint);
|
shell.WriteLine("invalid severity " + sevint);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
alertsComponent.ShowAlert(alert.AlertType, sevint == -1 ? null : sevint);
|
|
||||||
|
short? severity1 = sevint == -1 ? null : sevint;
|
||||||
|
alertsSystem.ShowAlert(attachedEntity, alert.AlertType, severity1, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Content.Server.Gravity.EntitySystems;
|
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Network;
|
|
||||||
using Robust.Shared.Players;
|
|
||||||
|
|
||||||
namespace Content.Server.Alert
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(SharedAlertsComponent))]
|
|
||||||
public sealed class ServerAlertsComponent : SharedAlertsComponent
|
|
||||||
{
|
|
||||||
|
|
||||||
protected override void Startup()
|
|
||||||
{
|
|
||||||
base.Startup();
|
|
||||||
|
|
||||||
if (EntitySystem.TryGet<WeightlessSystem>(out var weightlessSystem))
|
|
||||||
{
|
|
||||||
weightlessSystem.AddAlert(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.WarningS("alert", "weightlesssystem not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnRemove()
|
|
||||||
{
|
|
||||||
if (EntitySystem.TryGet<WeightlessSystem>(out var weightlessSystem))
|
|
||||||
{
|
|
||||||
weightlessSystem.RemoveAlert(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.WarningS("alert", $"{nameof(WeightlessSystem)} not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnRemove();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
|
|
||||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession? session = null)
|
|
||||||
{
|
|
||||||
base.HandleNetworkMessage(message, netChannel, session);
|
|
||||||
|
|
||||||
if (session == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(session));
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (message)
|
|
||||||
{
|
|
||||||
case ClickAlertMessage msg:
|
|
||||||
{
|
|
||||||
var player = session.AttachedEntity.GetValueOrDefault();
|
|
||||||
|
|
||||||
if (player != Owner)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsShowingAlert(msg.Type))
|
|
||||||
{
|
|
||||||
Logger.DebugS("alert", "user {0} attempted to" +
|
|
||||||
" click alert {1} which is not currently showing for them",
|
|
||||||
IoCManager.Resolve<IEntityManager>().GetComponent<MetaDataComponent>(player).EntityName, msg.Type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!AlertManager.TryGet(msg.Type, out var alert))
|
|
||||||
{
|
|
||||||
Logger.WarningS("alert", "unrecognized encoded alert {0}", msg.Type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
alert.OnClick?.AlertClicked(new ClickAlertEventArgs(player, alert));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7
Content.Server/Alert/ServerAlertsSystem.cs
Normal file
7
Content.Server/Alert/ServerAlertsSystem.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
using Content.Shared.Alert;
|
||||||
|
|
||||||
|
namespace Content.Server.Alert;
|
||||||
|
|
||||||
|
// The only reason this exists is because the DI system requires the shared AlertsSystem
|
||||||
|
// to be abstract.
|
||||||
|
internal class ServerAlertsSystem : AlertsSystem { }
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Server.Atmos.Components;
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
@@ -16,11 +15,11 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
||||||
|
|
||||||
private const float UpdateTimer = 1f;
|
private const float UpdateTimer = 1f;
|
||||||
|
private float _timer;
|
||||||
private float _timer = 0f;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -72,7 +71,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
_timer -= UpdateTimer;
|
_timer -= UpdateTimer;
|
||||||
|
|
||||||
foreach (var (barotrauma, damageable, transform) in EntityManager.EntityQuery<BarotraumaComponent, DamageableComponent, TransformComponent>(false))
|
foreach (var (barotrauma, damageable, transform) in EntityManager.EntityQuery<BarotraumaComponent, DamageableComponent, TransformComponent>())
|
||||||
{
|
{
|
||||||
var totalDamage = FixedPoint2.Zero;
|
var totalDamage = FixedPoint2.Zero;
|
||||||
foreach (var (barotraumaDamageType, _) in barotrauma.Damage.DamageDict)
|
foreach (var (barotraumaDamageType, _) in barotrauma.Damage.DamageDict)
|
||||||
@@ -84,28 +83,24 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
if (totalDamage >= barotrauma.MaxDamage)
|
if (totalDamage >= barotrauma.MaxDamage)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var uid = barotrauma.Owner;
|
|
||||||
|
|
||||||
var status = EntityManager.GetComponentOrNull<ServerAlertsComponent>(barotrauma.Owner);
|
|
||||||
|
|
||||||
var pressure = 1f;
|
var pressure = 1f;
|
||||||
|
|
||||||
if (_atmosphereSystem.GetTileMixture(transform.Coordinates) is { } mixture)
|
if (_atmosphereSystem.GetTileMixture(transform.Coordinates) is { } mixture)
|
||||||
{
|
{
|
||||||
pressure = MathF.Max(mixture.Pressure, 1f);;
|
pressure = MathF.Max(mixture.Pressure, 1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (pressure)
|
switch (pressure)
|
||||||
{
|
{
|
||||||
// Low pressure.
|
// Low pressure.
|
||||||
case <= Atmospherics.WarningLowPressure:
|
case <= Atmospherics.WarningLowPressure:
|
||||||
pressure = GetFeltLowPressure(uid, pressure);
|
pressure = GetFeltLowPressure(barotrauma.Owner, pressure);
|
||||||
|
|
||||||
if (pressure > Atmospherics.WarningLowPressure)
|
if (pressure > Atmospherics.WarningLowPressure)
|
||||||
goto default;
|
goto default;
|
||||||
|
|
||||||
// Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear.
|
// Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear.
|
||||||
_damageableSystem.TryChangeDamage(uid, barotrauma.Damage * Atmospherics.LowPressureDamage, true, false);
|
_damageableSystem.TryChangeDamage(barotrauma.Owner, barotrauma.Damage * Atmospherics.LowPressureDamage, true, false);
|
||||||
|
|
||||||
if (!barotrauma.TakingDamage)
|
if (!barotrauma.TakingDamage)
|
||||||
{
|
{
|
||||||
@@ -113,20 +108,18 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
_logSystem.Add(LogType.Barotrauma, $"{ToPrettyString(barotrauma.Owner):entity} started taking low pressure damage");
|
_logSystem.Add(LogType.Barotrauma, $"{ToPrettyString(barotrauma.Owner):entity} started taking low pressure damage");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == null) break;
|
|
||||||
|
|
||||||
if (pressure <= Atmospherics.HazardLowPressure)
|
if (pressure <= Atmospherics.HazardLowPressure)
|
||||||
{
|
{
|
||||||
status.ShowAlert(AlertType.LowPressure, 2);
|
_alertsSystem.ShowAlert(barotrauma.Owner, AlertType.LowPressure, 2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
status.ShowAlert(AlertType.LowPressure, 1);
|
_alertsSystem.ShowAlert(barotrauma.Owner, AlertType.LowPressure, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// High pressure.
|
// High pressure.
|
||||||
case >= Atmospherics.WarningHighPressure:
|
case >= Atmospherics.WarningHighPressure:
|
||||||
pressure = GetFeltHighPressure(uid, pressure);
|
pressure = GetFeltHighPressure(barotrauma.Owner, pressure);
|
||||||
|
|
||||||
if(pressure < Atmospherics.WarningHighPressure)
|
if(pressure < Atmospherics.WarningHighPressure)
|
||||||
goto default;
|
goto default;
|
||||||
@@ -134,7 +127,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
var damageScale = MathF.Min((pressure / Atmospherics.HazardHighPressure) * Atmospherics.PressureDamageCoefficient, Atmospherics.MaxHighPressureDamage);
|
var damageScale = MathF.Min((pressure / Atmospherics.HazardHighPressure) * Atmospherics.PressureDamageCoefficient, Atmospherics.MaxHighPressureDamage);
|
||||||
|
|
||||||
// Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear.
|
// Deal damage and ignore resistances. Resistance to pressure damage should be done via pressure protection gear.
|
||||||
_damageableSystem.TryChangeDamage(uid, barotrauma.Damage * damageScale, true, false);
|
_damageableSystem.TryChangeDamage(barotrauma.Owner, barotrauma.Damage * damageScale, true, false);
|
||||||
|
|
||||||
if (!barotrauma.TakingDamage)
|
if (!barotrauma.TakingDamage)
|
||||||
{
|
{
|
||||||
@@ -142,15 +135,13 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
_logSystem.Add(LogType.Barotrauma, $"{ToPrettyString(barotrauma.Owner):entity} started taking high pressure damage");
|
_logSystem.Add(LogType.Barotrauma, $"{ToPrettyString(barotrauma.Owner):entity} started taking high pressure damage");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == null) break;
|
|
||||||
|
|
||||||
if (pressure >= Atmospherics.HazardHighPressure)
|
if (pressure >= Atmospherics.HazardHighPressure)
|
||||||
{
|
{
|
||||||
status.ShowAlert(AlertType.HighPressure, 2);
|
_alertsSystem.ShowAlert(barotrauma.Owner, AlertType.HighPressure, 2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
status.ShowAlert(AlertType.HighPressure, 1);
|
_alertsSystem.ShowAlert(barotrauma.Owner, AlertType.HighPressure, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Normal pressure.
|
// Normal pressure.
|
||||||
@@ -160,7 +151,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
barotrauma.TakingDamage = false;
|
barotrauma.TakingDamage = false;
|
||||||
_logSystem.Add(LogType.Barotrauma, $"{ToPrettyString(barotrauma.Owner):entity} stopped taking pressure damage");
|
_logSystem.Add(LogType.Barotrauma, $"{ToPrettyString(barotrauma.Owner):entity} stopped taking pressure damage");
|
||||||
}
|
}
|
||||||
status?.ClearAlertCategory(AlertCategory.Pressure);
|
_alertsSystem.ClearAlertCategory(barotrauma.Owner, AlertCategory.Pressure);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Server.Atmos.Components;
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Server.Stunnable;
|
using Content.Server.Stunnable;
|
||||||
using Content.Server.Temperature.Systems;
|
using Content.Server.Temperature.Systems;
|
||||||
@@ -28,6 +27,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
[Dependency] private readonly StunSystem _stunSystem = default!;
|
[Dependency] private readonly StunSystem _stunSystem = default!;
|
||||||
[Dependency] private readonly TemperatureSystem _temperatureSystem = default!;
|
[Dependency] private readonly TemperatureSystem _temperatureSystem = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
||||||
|
|
||||||
private const float MinimumFireStacks = -10f;
|
private const float MinimumFireStacks = -10f;
|
||||||
@@ -167,10 +167,9 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Resist(EntityUid uid,
|
public void Resist(EntityUid uid,
|
||||||
FlammableComponent? flammable = null,
|
FlammableComponent? flammable = null)
|
||||||
ServerAlertsComponent? alerts = null)
|
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref flammable, ref alerts))
|
if (!Resolve(uid, ref flammable))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!flammable.OnFire || !_actionBlockerSystem.CanInteract(flammable.Owner) || flammable.Resisting)
|
if (!flammable.OnFire || !_actionBlockerSystem.CanInteract(flammable.Owner) || flammable.Resisting)
|
||||||
@@ -179,7 +178,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
flammable.Resisting = true;
|
flammable.Resisting = true;
|
||||||
|
|
||||||
flammable.Owner.PopupMessage(Loc.GetString("flammable-component-resist-message"));
|
flammable.Owner.PopupMessage(Loc.GetString("flammable-component-resist-message"));
|
||||||
_stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(2f), true, alerts: alerts);
|
_stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(2f), true);
|
||||||
|
|
||||||
// TODO FLAMMABLE: Make this not use TimerComponent...
|
// TODO FLAMMABLE: Make this not use TimerComponent...
|
||||||
flammable.Owner.SpawnTimer(2000, () =>
|
flammable.Owner.SpawnTimer(2000, () =>
|
||||||
@@ -224,15 +223,13 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
flammable.FireStacks = MathF.Min(0, flammable.FireStacks + 1);
|
flammable.FireStacks = MathF.Min(0, flammable.FireStacks + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityManager.TryGetComponent(flammable.Owner, out ServerAlertsComponent? status);
|
|
||||||
|
|
||||||
if (!flammable.OnFire)
|
if (!flammable.OnFire)
|
||||||
{
|
{
|
||||||
status?.ClearAlert(AlertType.Fire);
|
_alertsSystem.ClearAlert(uid, AlertType.Fire);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
status?.ShowAlert(AlertType.Fire);
|
_alertsSystem.ShowAlert(uid, AlertType.Fire, null, null);
|
||||||
|
|
||||||
if (flammable.FireStacks > 0)
|
if (flammable.FireStacks > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Server.Atmos;
|
using Content.Server.Atmos;
|
||||||
using Content.Server.Body.Components;
|
using Content.Server.Body.Components;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
@@ -24,6 +23,7 @@ namespace Content.Server.Body.Systems
|
|||||||
[Dependency] private readonly AdminLogSystem _logSys = default!;
|
[Dependency] private readonly AdminLogSystem _logSys = default!;
|
||||||
[Dependency] private readonly BodySystem _bodySystem = default!;
|
[Dependency] private readonly BodySystem _bodySystem = default!;
|
||||||
[Dependency] private readonly LungSystem _lungSystem = default!;
|
[Dependency] private readonly LungSystem _lungSystem = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
@@ -199,10 +199,7 @@ namespace Content.Server.Body.Systems
|
|||||||
|
|
||||||
respirator.Suffocating = true;
|
respirator.Suffocating = true;
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(uid, out ServerAlertsComponent? alertsComponent))
|
_alertsSystem.ShowAlert(uid, AlertType.LowOxygen);
|
||||||
{
|
|
||||||
alertsComponent.ShowAlert(AlertType.LowOxygen);
|
|
||||||
}
|
|
||||||
|
|
||||||
_damageableSys.TryChangeDamage(uid, respirator.Damage, true, false);
|
_damageableSys.TryChangeDamage(uid, respirator.Damage, true, false);
|
||||||
}
|
}
|
||||||
@@ -214,10 +211,7 @@ namespace Content.Server.Body.Systems
|
|||||||
|
|
||||||
respirator.Suffocating = false;
|
respirator.Suffocating = false;
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(uid, out ServerAlertsComponent? alertsComponent))
|
_alertsSystem.ClearAlert(uid, AlertType.LowOxygen);
|
||||||
{
|
|
||||||
alertsComponent.ClearAlert(AlertType.LowOxygen);
|
|
||||||
}
|
|
||||||
|
|
||||||
_damageableSys.TryChangeDamage(uid, respirator.DamageRecovery, true);
|
_damageableSys.TryChangeDamage(uid, respirator.DamageRecovery, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Pulling;
|
using Content.Server.Pulling;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
@@ -36,7 +35,6 @@ namespace Content.Server.Buckle.Components
|
|||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
|
||||||
[ComponentDependency] public readonly AppearanceComponent? Appearance = null;
|
[ComponentDependency] public readonly AppearanceComponent? Appearance = null;
|
||||||
[ComponentDependency] private readonly ServerAlertsComponent? _serverAlerts = null;
|
|
||||||
[ComponentDependency] private readonly MobStateComponent? _mobState = null;
|
[ComponentDependency] private readonly MobStateComponent? _mobState = null;
|
||||||
|
|
||||||
[DataField("size")]
|
[DataField("size")]
|
||||||
@@ -94,18 +92,14 @@ namespace Content.Server.Buckle.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateBuckleStatus()
|
private void UpdateBuckleStatus()
|
||||||
{
|
{
|
||||||
if (_serverAlerts == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Buckled)
|
if (Buckled)
|
||||||
{
|
{
|
||||||
_serverAlerts.ShowAlert(BuckledTo?.BuckledAlertType ?? AlertType.Buckled);
|
AlertType alertType = BuckledTo?.BuckledAlertType ?? AlertType.Buckled;
|
||||||
|
EntitySystem.Get<AlertsSystem>().ShowAlert(Owner, alertType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_serverAlerts.ClearAlertCategory(AlertCategory.Buckled);
|
EntitySystem.Get<AlertsSystem>().ClearAlertCategory(Owner, AlertCategory.Buckled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,15 @@ using Content.Shared.Movement.EntitySystems;
|
|||||||
using Content.Shared.Slippery;
|
using Content.Shared.Slippery;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
|
|
||||||
namespace Content.Server.Clothing
|
namespace Content.Server.Clothing
|
||||||
{
|
{
|
||||||
public sealed class MagbootsSystem : EntitySystem
|
public sealed class MagbootsSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -35,16 +38,13 @@ namespace Content.Server.Clothing
|
|||||||
movedByPressure.Enabled = state;
|
movedByPressure.Enabled = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp(parent, out ServerAlertsComponent? alerts))
|
if (state)
|
||||||
{
|
{
|
||||||
if (state)
|
_alertsSystem.ShowAlert(parent, AlertType.Magboots);
|
||||||
{
|
}
|
||||||
alerts.ShowAlert(AlertType.Magboots);
|
else
|
||||||
}
|
{
|
||||||
else
|
_alertsSystem.ClearAlert(parent, AlertType.Magboots);
|
||||||
{
|
|
||||||
alerts.ClearAlert(AlertType.Magboots);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Server.DoAfter;
|
using Content.Server.DoAfter;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
@@ -158,16 +157,13 @@ namespace Content.Server.Cuffs.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateAlert()
|
private void UpdateAlert()
|
||||||
{
|
{
|
||||||
if (_entMan.TryGetComponent(Owner, out ServerAlertsComponent? status))
|
if (CanStillInteract)
|
||||||
{
|
{
|
||||||
if (CanStillInteract)
|
EntitySystem.Get<AlertsSystem>().ClearAlert(Owner, AlertType.Handcuffed);
|
||||||
{
|
}
|
||||||
status.ClearAlert(AlertType.Handcuffed);
|
else
|
||||||
}
|
{
|
||||||
else
|
EntitySystem.Get<AlertsSystem>().ShowAlert(Owner, AlertType.Handcuffed);
|
||||||
{
|
|
||||||
status.ShowAlert(AlertType.Handcuffed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using Content.Server.Power.Components;
|
|||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Server.Power.NodeGroups;
|
using Content.Server.Power.NodeGroups;
|
||||||
using Content.Server.Window;
|
using Content.Server.Window;
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Damage.Prototypes;
|
using Content.Shared.Damage.Prototypes;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
@@ -109,8 +108,10 @@ namespace Content.Server.Electrocution
|
|||||||
|
|
||||||
var actual = _damageableSystem.TryChangeDamage(finished.Electrocuting, damage);
|
var actual = _damageableSystem.TryChangeDamage(finished.Electrocuting, damage);
|
||||||
if (actual != null)
|
if (actual != null)
|
||||||
|
{
|
||||||
_logSystem.Add(LogType.Electrocution,
|
_logSystem.Add(LogType.Electrocution,
|
||||||
$"{ToPrettyString(finished.Owner):entity} received {actual.Total:damage} powered electrocution damage");
|
$"{ToPrettyString(finished.Owner):entity} received {actual.Total:damage} powered electrocution damage");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityManager.DeleteEntity(uid);
|
EntityManager.DeleteEntity(uid);
|
||||||
@@ -232,10 +233,10 @@ namespace Content.Server.Electrocution
|
|||||||
|
|
||||||
Node? TryNode(string? id)
|
Node? TryNode(string? id)
|
||||||
{
|
{
|
||||||
if (id != null && nodeContainer.TryGetNode<Node>(id, out var node)
|
if (id != null && nodeContainer.TryGetNode<Node>(id, out var tryNode)
|
||||||
&& node.NodeGroup is IBasePowerNet { NetworkNode: { LastAvailableSupplySum: >0 } })
|
&& tryNode.NodeGroup is IBasePowerNet { NetworkNode: { LastAvailableSupplySum: >0 } })
|
||||||
{
|
{
|
||||||
return node;
|
return tryNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -245,11 +246,10 @@ namespace Content.Server.Electrocution
|
|||||||
/// <returns>Whether the entity <see cref="uid"/> was stunned by the shock.</returns>
|
/// <returns>Whether the entity <see cref="uid"/> was stunned by the shock.</returns>
|
||||||
public bool TryDoElectrocution(
|
public bool TryDoElectrocution(
|
||||||
EntityUid uid, EntityUid? sourceUid, int shockDamage, TimeSpan time, bool refresh, float siemensCoefficient = 1f,
|
EntityUid uid, EntityUid? sourceUid, int shockDamage, TimeSpan time, bool refresh, float siemensCoefficient = 1f,
|
||||||
StatusEffectsComponent? statusEffects = null,
|
StatusEffectsComponent? statusEffects = null)
|
||||||
SharedAlertsComponent? alerts = null)
|
|
||||||
{
|
{
|
||||||
if (!DoCommonElectrocutionAttempt(uid, sourceUid, ref siemensCoefficient)
|
if (!DoCommonElectrocutionAttempt(uid, sourceUid, ref siemensCoefficient)
|
||||||
|| !DoCommonElectrocution(uid, sourceUid, shockDamage, time, refresh, siemensCoefficient, statusEffects, alerts))
|
|| !DoCommonElectrocution(uid, sourceUid, shockDamage, time, refresh, siemensCoefficient, statusEffects))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient));
|
RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient));
|
||||||
@@ -266,7 +266,6 @@ namespace Content.Server.Electrocution
|
|||||||
bool refresh,
|
bool refresh,
|
||||||
float siemensCoefficient = 1f,
|
float siemensCoefficient = 1f,
|
||||||
StatusEffectsComponent? statusEffects = null,
|
StatusEffectsComponent? statusEffects = null,
|
||||||
SharedAlertsComponent? alerts = null,
|
|
||||||
TransformComponent? sourceTransform = null)
|
TransformComponent? sourceTransform = null)
|
||||||
{
|
{
|
||||||
if (!DoCommonElectrocutionAttempt(uid, sourceUid, ref siemensCoefficient))
|
if (!DoCommonElectrocutionAttempt(uid, sourceUid, ref siemensCoefficient))
|
||||||
@@ -274,9 +273,9 @@ namespace Content.Server.Electrocution
|
|||||||
|
|
||||||
// Coefficient needs to be higher than this to do a powered electrocution!
|
// Coefficient needs to be higher than this to do a powered electrocution!
|
||||||
if(siemensCoefficient <= 0.5f)
|
if(siemensCoefficient <= 0.5f)
|
||||||
return DoCommonElectrocution(uid, sourceUid, shockDamage, time, refresh, siemensCoefficient, statusEffects, alerts);
|
return DoCommonElectrocution(uid, sourceUid, shockDamage, time, refresh, siemensCoefficient, statusEffects);
|
||||||
|
|
||||||
if (!DoCommonElectrocution(uid, sourceUid, null, time, refresh, siemensCoefficient, statusEffects, alerts))
|
if (!DoCommonElectrocution(uid, sourceUid, null, time, refresh, siemensCoefficient, statusEffects))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!Resolve(sourceUid, ref sourceTransform)) // This shouldn't really happen, but just in case...
|
if (!Resolve(sourceUid, ref sourceTransform)) // This shouldn't really happen, but just in case...
|
||||||
@@ -318,8 +317,7 @@ namespace Content.Server.Electrocution
|
|||||||
|
|
||||||
private bool DoCommonElectrocution(EntityUid uid, EntityUid? sourceUid,
|
private bool DoCommonElectrocution(EntityUid uid, EntityUid? sourceUid,
|
||||||
int? shockDamage, TimeSpan time, bool refresh, float siemensCoefficient = 1f,
|
int? shockDamage, TimeSpan time, bool refresh, float siemensCoefficient = 1f,
|
||||||
StatusEffectsComponent? statusEffects = null,
|
StatusEffectsComponent? statusEffects = null)
|
||||||
SharedAlertsComponent? alerts = null)
|
|
||||||
{
|
{
|
||||||
if (siemensCoefficient <= 0)
|
if (siemensCoefficient <= 0)
|
||||||
return false;
|
return false;
|
||||||
@@ -332,21 +330,18 @@ namespace Content.Server.Electrocution
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional component.
|
|
||||||
Resolve(uid, ref alerts, false);
|
|
||||||
|
|
||||||
if (!Resolve(uid, ref statusEffects, false) ||
|
if (!Resolve(uid, ref statusEffects, false) ||
|
||||||
!_statusEffectsSystem.CanApplyEffect(uid, StatusEffectKey, statusEffects))
|
!_statusEffectsSystem.CanApplyEffect(uid, StatusEffectKey, statusEffects))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!_statusEffectsSystem.TryAddStatusEffect<ElectrocutedComponent>(uid, StatusEffectKey, time, refresh,
|
if (!_statusEffectsSystem.TryAddStatusEffect<ElectrocutedComponent>(uid, StatusEffectKey, time, refresh,
|
||||||
statusEffects, alerts))
|
statusEffects))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var shouldStun = siemensCoefficient > 0.5f;
|
var shouldStun = siemensCoefficient > 0.5f;
|
||||||
|
|
||||||
if (shouldStun)
|
if (shouldStun)
|
||||||
_stunSystem.TryParalyze(uid, time * ParalyzeTimeMultiplier, refresh, statusEffects, alerts);
|
_stunSystem.TryParalyze(uid, time * ParalyzeTimeMultiplier, refresh, statusEffects);
|
||||||
|
|
||||||
// TODO: Sparks here.
|
// TODO: Sparks here.
|
||||||
|
|
||||||
@@ -356,13 +351,15 @@ namespace Content.Server.Electrocution
|
|||||||
new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>(DamageType), dmg));
|
new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>(DamageType), dmg));
|
||||||
|
|
||||||
if (actual != null)
|
if (actual != null)
|
||||||
|
{
|
||||||
_logSystem.Add(LogType.Electrocution,
|
_logSystem.Add(LogType.Electrocution,
|
||||||
$"{ToPrettyString(statusEffects.Owner):entity} received {actual.Total:damage} powered electrocution damage");
|
$"{ToPrettyString(statusEffects.Owner):entity} received {actual.Total:damage} powered electrocution damage");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_stutteringSystem.DoStutter(uid, time * StutteringTimeMultiplier, refresh, statusEffects, alerts);
|
_stutteringSystem.DoStutter(uid, time * StutteringTimeMultiplier, refresh, statusEffects);
|
||||||
_jitteringSystem.DoJitter(uid, time * JitterTimeMultiplier, refresh, JitterAmplitude, JitterFrequency, true,
|
_jitteringSystem.DoJitter(uid, time * JitterTimeMultiplier, refresh, JitterAmplitude, JitterFrequency, true,
|
||||||
statusEffects, alerts);
|
statusEffects);
|
||||||
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-player"), uid,
|
_popupSystem.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-player"), uid,
|
||||||
Filter.Entities(uid).Unpredicted());
|
Filter.Entities(uid).Unpredicted());
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ namespace Content.Server.Entry
|
|||||||
|
|
||||||
IoCManager.Resolve<ISandboxManager>().Initialize();
|
IoCManager.Resolve<ISandboxManager>().Initialize();
|
||||||
IoCManager.Resolve<RecipeManager>().Initialize();
|
IoCManager.Resolve<RecipeManager>().Initialize();
|
||||||
IoCManager.Resolve<AlertManager>().Initialize();
|
|
||||||
IoCManager.Resolve<ActionManager>().Initialize();
|
IoCManager.Resolve<ActionManager>().Initialize();
|
||||||
IoCManager.Resolve<BlackboardManager>().Initialize();
|
IoCManager.Resolve<BlackboardManager>().Initialize();
|
||||||
IoCManager.Resolve<ConsiderationsManager>().Initialize();
|
IoCManager.Resolve<ConsiderationsManager>().Initialize();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Gravity;
|
using Content.Shared.Gravity;
|
||||||
@@ -15,8 +14,9 @@ namespace Content.Server.Gravity.EntitySystems
|
|||||||
public class WeightlessSystem : EntitySystem
|
public class WeightlessSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
|
||||||
private readonly Dictionary<GridId, List<ServerAlertsComponent>> _alerts = new();
|
private readonly Dictionary<GridId, List<AlertsComponent>> _alerts = new();
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -25,6 +25,7 @@ namespace Content.Server.Gravity.EntitySystems
|
|||||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
||||||
SubscribeLocalEvent<GravityChangedMessage>(GravityChanged);
|
SubscribeLocalEvent<GravityChangedMessage>(GravityChanged);
|
||||||
SubscribeLocalEvent<EntParentChangedMessage>(EntParentChanged);
|
SubscribeLocalEvent<EntParentChangedMessage>(EntParentChanged);
|
||||||
|
SubscribeLocalEvent<AlertsComponent, AlertSyncEvent>(HandleAlertSyncEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset(RoundRestartCleanupEvent ev)
|
public void Reset(RoundRestartCleanupEvent ev)
|
||||||
@@ -32,7 +33,7 @@ namespace Content.Server.Gravity.EntitySystems
|
|||||||
_alerts.Clear();
|
_alerts.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddAlert(ServerAlertsComponent status)
|
public void AddAlert(AlertsComponent status)
|
||||||
{
|
{
|
||||||
var gridId = EntityManager.GetComponent<TransformComponent>(status.Owner).GridID;
|
var gridId = EntityManager.GetComponent<TransformComponent>(status.Owner).GridID;
|
||||||
var alerts = _alerts.GetOrNew(gridId);
|
var alerts = _alerts.GetOrNew(gridId);
|
||||||
@@ -43,16 +44,16 @@ namespace Content.Server.Gravity.EntitySystems
|
|||||||
{
|
{
|
||||||
if (EntityManager.GetComponent<GravityComponent>(grid.GridEntityId).Enabled)
|
if (EntityManager.GetComponent<GravityComponent>(grid.GridEntityId).Enabled)
|
||||||
{
|
{
|
||||||
RemoveWeightless(status);
|
RemoveWeightless(status.Owner);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddWeightless(status);
|
AddWeightless(status.Owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAlert(ServerAlertsComponent status)
|
public void RemoveAlert(AlertsComponent status)
|
||||||
{
|
{
|
||||||
var grid = EntityManager.GetComponent<TransformComponent>(status.Owner).GridID;
|
var grid = EntityManager.GetComponent<TransformComponent>(status.Owner).GridID;
|
||||||
if (!_alerts.TryGetValue(grid, out var statuses))
|
if (!_alerts.TryGetValue(grid, out var statuses))
|
||||||
@@ -74,31 +75,31 @@ namespace Content.Server.Gravity.EntitySystems
|
|||||||
{
|
{
|
||||||
foreach (var status in statuses)
|
foreach (var status in statuses)
|
||||||
{
|
{
|
||||||
RemoveWeightless(status);
|
RemoveWeightless(status.Owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var status in statuses)
|
foreach (var status in statuses)
|
||||||
{
|
{
|
||||||
AddWeightless(status);
|
AddWeightless(status.Owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddWeightless(ServerAlertsComponent status)
|
private void AddWeightless(EntityUid euid)
|
||||||
{
|
{
|
||||||
status.ShowAlert(AlertType.Weightless);
|
_alertsSystem.ShowAlert(euid, AlertType.Weightless);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveWeightless(ServerAlertsComponent status)
|
private void RemoveWeightless(EntityUid euid)
|
||||||
{
|
{
|
||||||
status.ClearAlert(AlertType.Weightless);
|
_alertsSystem.ClearAlert(euid, AlertType.Weightless);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EntParentChanged(ref EntParentChangedMessage ev)
|
private void EntParentChanged(ref EntParentChangedMessage ev)
|
||||||
{
|
{
|
||||||
if (!EntityManager.TryGetComponent(ev.Entity, out ServerAlertsComponent? status))
|
if (!EntityManager.TryGetComponent(ev.Entity, out AlertsComponent? status))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -119,5 +120,18 @@ namespace Content.Server.Gravity.EntitySystems
|
|||||||
|
|
||||||
newStatuses.Add(status);
|
newStatuses.Add(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleAlertSyncEvent(EntityUid uid, AlertsComponent component, AlertSyncEvent args)
|
||||||
|
{
|
||||||
|
switch (component.LifeStage)
|
||||||
|
{
|
||||||
|
case ComponentLifeStage.Starting:
|
||||||
|
AddAlert(component);
|
||||||
|
break;
|
||||||
|
case ComponentLifeStage.Removing:
|
||||||
|
RemoveAlert(component);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ using Content.Server.AI.WorldState;
|
|||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
using Content.Server.Connection;
|
using Content.Server.Connection;
|
||||||
using Content.Server.Database;
|
using Content.Server.Database;
|
||||||
using Content.Server.DeviceNetwork;
|
|
||||||
using Content.Server.EUI;
|
using Content.Server.EUI;
|
||||||
using Content.Server.Holiday;
|
|
||||||
using Content.Server.Holiday.Interfaces;
|
|
||||||
using Content.Server.Info;
|
using Content.Server.Info;
|
||||||
using Content.Server.Maps;
|
using Content.Server.Maps;
|
||||||
using Content.Server.Module;
|
using Content.Server.Module;
|
||||||
@@ -20,11 +17,9 @@ using Content.Server.Objectives;
|
|||||||
using Content.Server.Objectives.Interfaces;
|
using Content.Server.Objectives.Interfaces;
|
||||||
using Content.Server.Preferences.Managers;
|
using Content.Server.Preferences.Managers;
|
||||||
using Content.Server.Sandbox;
|
using Content.Server.Sandbox;
|
||||||
using Content.Server.Speech;
|
|
||||||
using Content.Server.Voting.Managers;
|
using Content.Server.Voting.Managers;
|
||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Content.Shared.Kitchen;
|
using Content.Shared.Kitchen;
|
||||||
using Content.Shared.Module;
|
using Content.Shared.Module;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -43,7 +38,6 @@ namespace Content.Server.IoC
|
|||||||
IoCManager.Register<IServerPreferencesManager, ServerPreferencesManager>();
|
IoCManager.Register<IServerPreferencesManager, ServerPreferencesManager>();
|
||||||
IoCManager.Register<IServerDbManager, ServerDbManager>();
|
IoCManager.Register<IServerDbManager, ServerDbManager>();
|
||||||
IoCManager.Register<RecipeManager, RecipeManager>();
|
IoCManager.Register<RecipeManager, RecipeManager>();
|
||||||
IoCManager.Register<AlertManager, AlertManager>();
|
|
||||||
IoCManager.Register<ActionManager, ActionManager>();
|
IoCManager.Register<ActionManager, ActionManager>();
|
||||||
IoCManager.Register<INodeGroupFactory, NodeGroupFactory>();
|
IoCManager.Register<INodeGroupFactory, NodeGroupFactory>();
|
||||||
IoCManager.Register<BlackboardManager, BlackboardManager>();
|
IoCManager.Register<BlackboardManager, BlackboardManager>();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.Alert;
|
using System;
|
||||||
using Content.Server.Stunnable;
|
using Content.Server.Stunnable;
|
||||||
using Content.Server.Stunnable.Components;
|
using Content.Server.Stunnable.Components;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
@@ -17,10 +17,7 @@ namespace Content.Server.MobState.States
|
|||||||
{
|
{
|
||||||
base.EnterState(uid, entityManager);
|
base.EnterState(uid, entityManager);
|
||||||
|
|
||||||
if (entityManager.TryGetComponent(uid, out ServerAlertsComponent? status))
|
EntitySystem.Get<AlertsSystem>().ShowAlert(uid, AlertType.HumanDead);
|
||||||
{
|
|
||||||
status.ShowAlert(AlertType.HumanDead);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entityManager.TryGetComponent(uid, out StatusEffectsComponent? stun))
|
if (entityManager.TryGetComponent(uid, out StatusEffectsComponent? stun))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.Alert;
|
using System;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
@@ -19,11 +19,6 @@ namespace Content.Server.MobState.States
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entityManager.TryGetComponent(entity, out ServerAlertsComponent? alerts))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!entityManager.TryGetComponent(entity, out MobStateComponent? stateComponent))
|
if (!entityManager.TryGetComponent(entity, out MobStateComponent? stateComponent))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -36,7 +31,7 @@ namespace Content.Server.MobState.States
|
|||||||
modifier = (short) (damageable.TotalDamage / (earliestThreshold / 7f));
|
modifier = (short) (damageable.TotalDamage / (earliestThreshold / 7f));
|
||||||
}
|
}
|
||||||
|
|
||||||
alerts.ShowAlert(AlertType.HumanHealth, modifier);
|
EntitySystem.Get<AlertsSystem>().ShowAlert(entity, AlertType.HumanHealth, modifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
@@ -95,15 +94,13 @@ namespace Content.Server.Nutrition.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update UI
|
// Update UI
|
||||||
_entMan.TryGetComponent(Owner, out ServerAlertsComponent? alertsComponent);
|
|
||||||
|
|
||||||
if (HungerThresholdAlertTypes.TryGetValue(_currentHungerThreshold, out var alertId))
|
if (HungerThresholdAlertTypes.TryGetValue(_currentHungerThreshold, out var alertId))
|
||||||
{
|
{
|
||||||
alertsComponent?.ShowAlert(alertId);
|
EntitySystem.Get<AlertsSystem>().ShowAlert(Owner, alertId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
alertsComponent?.ClearAlertCategory(AlertCategory.Hunger);
|
EntitySystem.Get<AlertsSystem>().ClearAlertCategory(Owner, AlertCategory.Hunger);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_currentHungerThreshold)
|
switch (_currentHungerThreshold)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
@@ -94,15 +93,13 @@ namespace Content.Server.Nutrition.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update UI
|
// Update UI
|
||||||
_entMan.TryGetComponent(Owner, out ServerAlertsComponent? alertsComponent);
|
|
||||||
|
|
||||||
if (ThirstThresholdAlertTypes.TryGetValue(_currentThirstThreshold, out var alertId))
|
if (ThirstThresholdAlertTypes.TryGetValue(_currentThirstThreshold, out var alertId))
|
||||||
{
|
{
|
||||||
alertsComponent?.ShowAlert(alertId);
|
EntitySystem.Get<AlertsSystem>().ShowAlert(Owner, alertId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
alertsComponent?.ClearAlertCategory(AlertCategory.Thirst);
|
EntitySystem.Get<AlertsSystem>().ClearAlertCategory(Owner, AlertCategory.Thirst);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_currentThirstThreshold)
|
switch (_currentThirstThreshold)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.Alert;
|
using System;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
@@ -18,6 +18,7 @@ namespace Content.Server.Shuttles.EntitySystems
|
|||||||
internal sealed class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
internal sealed class ShuttleConsoleSystem : SharedShuttleConsoleSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -141,10 +142,7 @@ namespace Content.Server.Shuttles.EntitySystems
|
|||||||
|
|
||||||
component.SubscribedPilots.Add(pilotComponent);
|
component.SubscribedPilots.Add(pilotComponent);
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(entity, out ServerAlertsComponent? alertsComponent))
|
_alertsSystem.ShowAlert(entity, AlertType.PilotingShuttle);
|
||||||
{
|
|
||||||
alertsComponent.ShowAlert(AlertType.PilotingShuttle);
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.PopupMessage(Loc.GetString("shuttle-pilot-start"));
|
entity.PopupMessage(Loc.GetString("shuttle-pilot-start"));
|
||||||
pilotComponent.Console = component;
|
pilotComponent.Console = component;
|
||||||
@@ -163,10 +161,7 @@ namespace Content.Server.Shuttles.EntitySystems
|
|||||||
|
|
||||||
if (!helmsman.SubscribedPilots.Remove(pilotComponent)) return;
|
if (!helmsman.SubscribedPilots.Remove(pilotComponent)) return;
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(pilotComponent.Owner, out ServerAlertsComponent? alertsComponent))
|
_alertsSystem.ClearAlert(pilotComponent.Owner, AlertType.PilotingShuttle);
|
||||||
{
|
|
||||||
alertsComponent.ClearAlert(AlertType.PilotingShuttle);
|
|
||||||
}
|
|
||||||
|
|
||||||
pilotComponent.Owner.PopupMessage(Loc.GetString("shuttle-pilot-end"));
|
pilotComponent.Owner.PopupMessage(Loc.GetString("shuttle-pilot-end"));
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Server.Speech.Components;
|
using Content.Server.Speech.Components;
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Content.Shared.Speech.EntitySystems;
|
using Content.Shared.Speech.EntitySystems;
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffect;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -28,12 +26,12 @@ namespace Content.Server.Speech.EntitySystems
|
|||||||
SubscribeLocalEvent<StutteringAccentComponent, AccentGetEvent>(OnAccent);
|
SubscribeLocalEvent<StutteringAccentComponent, AccentGetEvent>(OnAccent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DoStutter(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent? status = null, SharedAlertsComponent? alerts = null)
|
public override void DoStutter(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent? status = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_statusEffectsSystem.TryAddStatusEffect<StutteringAccentComponent>(uid, StutterKey, time, refresh, status, alerts);
|
_statusEffectsSystem.TryAddStatusEffect<StutteringAccentComponent>(uid, StutterKey, time, refresh, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAccent(EntityUid uid, StutteringAccentComponent component, AccentGetEvent args)
|
private void OnAccent(EntityUid uid, StutteringAccentComponent component, AccentGetEvent args)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Server.Stunnable.Components;
|
using Content.Server.Stunnable.Components;
|
||||||
using Content.Shared.Standing;
|
using Content.Shared.Standing;
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffect;
|
||||||
@@ -27,20 +26,19 @@ namespace Content.Server.Stunnable
|
|||||||
|
|
||||||
if (EntityManager.TryGetComponent<StatusEffectsComponent>(otherUid, out var status))
|
if (EntityManager.TryGetComponent<StatusEffectsComponent>(otherUid, out var status))
|
||||||
{
|
{
|
||||||
ServerAlertsComponent? alerts = null;
|
|
||||||
StandingStateComponent? standingState = null;
|
StandingStateComponent? standingState = null;
|
||||||
AppearanceComponent? appearance = null;
|
AppearanceComponent? appearance = null;
|
||||||
|
|
||||||
// Let the actual methods log errors for these.
|
// Let the actual methods log errors for these.
|
||||||
Resolve(otherUid, ref alerts, ref standingState, ref appearance, false);
|
Resolve(otherUid, ref standingState, ref appearance, false);
|
||||||
|
|
||||||
_stunSystem.TryStun(otherUid, TimeSpan.FromSeconds(component.StunAmount), true, status, alerts);
|
_stunSystem.TryStun(otherUid, TimeSpan.FromSeconds(component.StunAmount), true, status);
|
||||||
|
|
||||||
_stunSystem.TryKnockdown(otherUid, TimeSpan.FromSeconds(component.KnockdownAmount), true,
|
_stunSystem.TryKnockdown(otherUid, TimeSpan.FromSeconds(component.KnockdownAmount), true,
|
||||||
status, alerts);
|
status);
|
||||||
|
|
||||||
_stunSystem.TrySlowdown(otherUid, TimeSpan.FromSeconds(component.SlowdownAmount), true,
|
_stunSystem.TrySlowdown(otherUid, TimeSpan.FromSeconds(component.SlowdownAmount), true,
|
||||||
component.WalkSpeedMultiplier, component.RunSpeedMultiplier, status, alerts);
|
component.WalkSpeedMultiplier, component.RunSpeedMultiplier, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,12 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Alert;
|
|
||||||
using Content.Server.Atmos.Components;
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.Temperature.Components;
|
using Content.Server.Temperature.Components;
|
||||||
using Content.Shared.Administration.Logs;
|
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.FixedPoint;
|
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
@@ -20,6 +17,7 @@ namespace Content.Server.Temperature.Systems
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -31,13 +29,13 @@ namespace Content.Server.Temperature.Systems
|
|||||||
|
|
||||||
public float UpdateInterval = 1.0f;
|
public float UpdateInterval = 1.0f;
|
||||||
|
|
||||||
private float _accumulatedFrametime = 0.0f;
|
private float _accumulatedFrametime;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<TemperatureComponent, OnTemperatureChangeEvent>(EnqueueDamage);
|
SubscribeLocalEvent<TemperatureComponent, OnTemperatureChangeEvent>(EnqueueDamage);
|
||||||
SubscribeLocalEvent<TemperatureComponent, AtmosExposedUpdateEvent>(OnAtmosExposedUpdate);
|
SubscribeLocalEvent<TemperatureComponent, AtmosExposedUpdateEvent>(OnAtmosExposedUpdate);
|
||||||
SubscribeLocalEvent<ServerAlertsComponent, OnTemperatureChangeEvent>(ServerAlert);
|
SubscribeLocalEvent<AlertsComponent, OnTemperatureChangeEvent>(ServerAlert);
|
||||||
SubscribeLocalEvent<TemperatureProtectionComponent, ModifyChangedTemperatureEvent>(OnTemperatureChangeAttempt);
|
SubscribeLocalEvent<TemperatureProtectionComponent, ModifyChangedTemperatureEvent>(OnTemperatureChangeAttempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,43 +101,43 @@ namespace Content.Server.Temperature.Systems
|
|||||||
ChangeHeat(uid, heat * temperature.AtmosTemperatureTransferEfficiency, temperature: temperature );
|
ChangeHeat(uid, heat * temperature.AtmosTemperatureTransferEfficiency, temperature: temperature );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ServerAlert(EntityUid uid, ServerAlertsComponent status, OnTemperatureChangeEvent args)
|
private void ServerAlert(EntityUid uid, AlertsComponent status, OnTemperatureChangeEvent args)
|
||||||
{
|
{
|
||||||
switch (args.CurrentTemperature)
|
switch (args.CurrentTemperature)
|
||||||
{
|
{
|
||||||
// Cold strong.
|
// Cold strong.
|
||||||
case <= 260:
|
case <= 260:
|
||||||
status.ShowAlert(AlertType.Cold, 3);
|
_alertsSystem.ShowAlert(uid, AlertType.Cold, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Cold mild.
|
// Cold mild.
|
||||||
case <= 280 and > 260:
|
case <= 280 and > 260:
|
||||||
status.ShowAlert(AlertType.Cold, 2);
|
_alertsSystem.ShowAlert(uid, AlertType.Cold, 2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Cold weak.
|
// Cold weak.
|
||||||
case <= 292 and > 280:
|
case <= 292 and > 280:
|
||||||
status.ShowAlert(AlertType.Cold, 1);
|
_alertsSystem.ShowAlert(uid, AlertType.Cold, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Safe.
|
// Safe.
|
||||||
case <= 327 and > 292:
|
case <= 327 and > 292:
|
||||||
status.ClearAlertCategory(AlertCategory.Temperature);
|
_alertsSystem.ClearAlertCategory(uid, AlertCategory.Temperature);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Heat weak.
|
// Heat weak.
|
||||||
case <= 335 and > 327:
|
case <= 335 and > 327:
|
||||||
status.ShowAlert(AlertType.Hot, 1);
|
_alertsSystem.ShowAlert(uid, AlertType.Hot, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Heat mild.
|
// Heat mild.
|
||||||
case <= 360 and > 335:
|
case <= 360 and > 335:
|
||||||
status.ShowAlert(AlertType.Hot, 2);
|
_alertsSystem.ShowAlert(uid, AlertType.Hot, 2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Heat strong.
|
// Heat strong.
|
||||||
case > 360:
|
case > 360:
|
||||||
status.ShowAlert(AlertType.Hot, 3);
|
_alertsSystem.ShowAlert(uid, AlertType.Hot, 3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,7 +149,7 @@ namespace Content.Server.Temperature.Systems
|
|||||||
|
|
||||||
private void ChangeDamage(EntityUid uid, TemperatureComponent temperature)
|
private void ChangeDamage(EntityUid uid, TemperatureComponent temperature)
|
||||||
{
|
{
|
||||||
if (!EntityManager.TryGetComponent<DamageableComponent>(uid, out var damage))
|
if (!EntityManager.HasComponent<DamageableComponent>(uid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// See this link for where the scaling func comes from:
|
// See this link for where the scaling func comes from:
|
||||||
|
|||||||
16
Content.Shared/Alert/AlertCategory.cs
Normal file
16
Content.Shared/Alert/AlertCategory.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace Content.Shared.Alert;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Every category of alert. Corresponds to category field in alert prototypes defined in YML
|
||||||
|
/// </summary>
|
||||||
|
public enum AlertCategory
|
||||||
|
{
|
||||||
|
Pressure,
|
||||||
|
Temperature,
|
||||||
|
Breathing,
|
||||||
|
Buckled,
|
||||||
|
Health,
|
||||||
|
Piloting,
|
||||||
|
Hunger,
|
||||||
|
Thirst
|
||||||
|
}
|
||||||
62
Content.Shared/Alert/AlertKey.cs
Normal file
62
Content.Shared/Alert/AlertKey.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.Manager;
|
||||||
|
|
||||||
|
namespace Content.Shared.Alert;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Key for an alert which is unique (for equality and hashcode purposes) w.r.t category semantics.
|
||||||
|
/// I.e., entirely defined by the category, if a category was specified, otherwise
|
||||||
|
/// falls back to the id.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public struct AlertKey : ISerializationHooks, IPopulateDefaultValues
|
||||||
|
{
|
||||||
|
public AlertType? AlertType { get; private set; }
|
||||||
|
public readonly AlertCategory? AlertCategory;
|
||||||
|
|
||||||
|
/// NOTE: if the alert has a category you must pass the category for this to work
|
||||||
|
/// properly as a key. I.e. if the alert has a category and you pass only the alert type, and you
|
||||||
|
/// compare this to another AlertKey that has both the category and the same alert type, it will not consider them equal.
|
||||||
|
public AlertKey(AlertType? alertType, AlertCategory? alertCategory)
|
||||||
|
{
|
||||||
|
AlertCategory = alertCategory;
|
||||||
|
AlertType = alertType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(AlertKey other)
|
||||||
|
{
|
||||||
|
// compare only on alert category if we have one
|
||||||
|
if (AlertCategory.HasValue)
|
||||||
|
{
|
||||||
|
return other.AlertCategory == AlertCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AlertType == other.AlertType && AlertCategory == other.AlertCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is AlertKey other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
// use only alert category if we have one
|
||||||
|
if (AlertCategory.HasValue) return AlertCategory.GetHashCode();
|
||||||
|
return AlertType.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PopulateDefaultValues()
|
||||||
|
{
|
||||||
|
AlertType = Alert.AlertType.Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="category">alert category, must not be null</param>
|
||||||
|
/// <returns>An alert key for the provided alert category. This must only be used for
|
||||||
|
/// queries and never storage, as it is lacking an alert type.</returns>
|
||||||
|
public static AlertKey ForCategory(AlertCategory category)
|
||||||
|
{
|
||||||
|
return new(null, category);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Shared.Alert
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides access to all configured alerts by alert type.
|
|
||||||
/// </summary>
|
|
||||||
public class AlertManager
|
|
||||||
{
|
|
||||||
[Dependency]
|
|
||||||
private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
|
|
||||||
private readonly Dictionary<AlertType, AlertPrototype> _typeToAlert = new();
|
|
||||||
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
foreach (var alert in _prototypeManager.EnumeratePrototypes<AlertPrototype>())
|
|
||||||
{
|
|
||||||
if (!_typeToAlert.TryAdd(alert.AlertType, alert))
|
|
||||||
{
|
|
||||||
Logger.ErrorS("alert",
|
|
||||||
"Found alert with duplicate alertType {0} - all alerts must have" +
|
|
||||||
" a unique alerttype, this one will be skipped", alert.AlertType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tries to get the alert of the indicated type
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>true if found</returns>
|
|
||||||
public bool TryGet(AlertType alertType, [NotNullWhen(true)] out AlertPrototype? alert)
|
|
||||||
{
|
|
||||||
return _typeToAlert.TryGetValue(alertType, out alert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ using System.Globalization;
|
|||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Serialization.Manager;
|
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
@@ -142,61 +141,4 @@ namespace Content.Shared.Alert
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Key for an alert which is unique (for equality and hashcode purposes) w.r.t category semantics.
|
|
||||||
/// I.e., entirely defined by the category, if a category was specified, otherwise
|
|
||||||
/// falls back to the id.
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public struct AlertKey : ISerializationHooks, IPopulateDefaultValues
|
|
||||||
{
|
|
||||||
public AlertType? AlertType { get; private set; }
|
|
||||||
public readonly AlertCategory? AlertCategory;
|
|
||||||
|
|
||||||
/// NOTE: if the alert has a category you must pass the category for this to work
|
|
||||||
/// properly as a key. I.e. if the alert has a category and you pass only the alert type, and you
|
|
||||||
/// compare this to another AlertKey that has both the category and the same alert type, it will not consider them equal.
|
|
||||||
public AlertKey(AlertType? alertType, AlertCategory? alertCategory)
|
|
||||||
{
|
|
||||||
AlertCategory = alertCategory;
|
|
||||||
AlertType = alertType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(AlertKey other)
|
|
||||||
{
|
|
||||||
// compare only on alert category if we have one
|
|
||||||
if (AlertCategory.HasValue)
|
|
||||||
{
|
|
||||||
return other.AlertCategory == AlertCategory;
|
|
||||||
}
|
|
||||||
|
|
||||||
return AlertType == other.AlertType && AlertCategory == other.AlertCategory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
return obj is AlertKey other && Equals(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
// use only alert category if we have one
|
|
||||||
if (AlertCategory.HasValue) return AlertCategory.GetHashCode();
|
|
||||||
return AlertType.GetHashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PopulateDefaultValues()
|
|
||||||
{
|
|
||||||
AlertType = Alert.AlertType.Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <param name="category">alert category, must not be null</param>
|
|
||||||
/// <returns>An alert key for the provided alert category. This must only be used for
|
|
||||||
/// queries and never storage, as it is lacking an alert type.</returns>
|
|
||||||
public static AlertKey ForCategory(AlertCategory category)
|
|
||||||
{
|
|
||||||
return new(null, category);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
12
Content.Shared/Alert/AlertState.cs
Normal file
12
Content.Shared/Alert/AlertState.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Alert;
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public struct AlertState
|
||||||
|
{
|
||||||
|
public short? Severity;
|
||||||
|
public (TimeSpan, TimeSpan)? Cooldown;
|
||||||
|
public AlertType Type;
|
||||||
|
}
|
||||||
16
Content.Shared/Alert/AlertSyncEvent.cs
Normal file
16
Content.Shared/Alert/AlertSyncEvent.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Shared.Alert;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when the AlertSystem needs alert sources to recalculate their alert states and set them.
|
||||||
|
/// </summary>
|
||||||
|
public class AlertSyncEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid Euid { get; }
|
||||||
|
|
||||||
|
public AlertSyncEvent(EntityUid euid)
|
||||||
|
{
|
||||||
|
Euid = euid;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,5 @@
|
|||||||
namespace Content.Shared.Alert
|
namespace Content.Shared.Alert
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Every category of alert. Corresponds to category field in alert prototypes defined in YML
|
|
||||||
/// </summary>
|
|
||||||
public enum AlertCategory
|
|
||||||
{
|
|
||||||
Pressure,
|
|
||||||
Temperature,
|
|
||||||
Breathing,
|
|
||||||
Buckled,
|
|
||||||
Health,
|
|
||||||
Piloting,
|
|
||||||
Hunger,
|
|
||||||
Thirst
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Every kind of alert. Corresponds to alertType field in alert prototypes defined in YML
|
/// Every kind of alert. Corresponds to alertType field in alert prototypes defined in YML
|
||||||
/// NOTE: Using byte for a compact encoding when sending this in messages, can upgrade
|
/// NOTE: Using byte for a compact encoding when sending this in messages, can upgrade
|
||||||
|
|||||||
18
Content.Shared/Alert/AlertsComponent.cs
Normal file
18
Content.Shared/Alert/AlertsComponent.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Shared.Alert;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the icons on the right side of the screen.
|
||||||
|
/// Should only be used for player-controlled entities.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
[NetworkedComponent]
|
||||||
|
[ComponentProtoName("Alerts")]
|
||||||
|
public class AlertsComponent : Component
|
||||||
|
{
|
||||||
|
[ViewVariables] public Dictionary<AlertKey, AlertState> Alerts = new();
|
||||||
|
}
|
||||||
17
Content.Shared/Alert/AlertsComponentState.cs
Normal file
17
Content.Shared/Alert/AlertsComponentState.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Alert;
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class AlertsComponentState : ComponentState
|
||||||
|
{
|
||||||
|
public Dictionary<AlertKey, AlertState> Alerts;
|
||||||
|
|
||||||
|
public AlertsComponentState(Dictionary<AlertKey, AlertState> alerts)
|
||||||
|
{
|
||||||
|
Alerts = alerts;
|
||||||
|
}
|
||||||
|
}
|
||||||
237
Content.Shared/Alert/AlertsSystem.cs
Normal file
237
Content.Shared/Alert/AlertsSystem.cs
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Alert;
|
||||||
|
|
||||||
|
public abstract class AlertsSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency]
|
||||||
|
private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
|
private readonly Dictionary<AlertType, AlertPrototype> _typeToAlert = new();
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<AlertKey, AlertState>? GetActiveAlerts(EntityUid euid)
|
||||||
|
{
|
||||||
|
return EntityManager.TryGetComponent(euid, out AlertsComponent comp)
|
||||||
|
? comp.Alerts
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsShowingAlert(EntityUid euid, AlertType alertType)
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(euid, out AlertsComponent alertsComponent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (TryGet(alertType, out var alert))
|
||||||
|
{
|
||||||
|
return alertsComponent.Alerts.ContainsKey(alert.AlertKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.DebugS("alert", "unknown alert type {0}", alertType);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <returns>true iff an alert of the indicated alert category is currently showing</returns>
|
||||||
|
public bool IsShowingAlertCategory(EntityUid euid, AlertCategory alertCategory)
|
||||||
|
{
|
||||||
|
return EntityManager.TryGetComponent(euid, out AlertsComponent alertsComponent)
|
||||||
|
&& alertsComponent.Alerts.ContainsKey(AlertKey.ForCategory(alertCategory));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetAlertState(EntityUid euid, AlertKey key, out AlertState alertState)
|
||||||
|
{
|
||||||
|
if (EntityManager.TryGetComponent(euid, out AlertsComponent alertsComponent))
|
||||||
|
return alertsComponent.Alerts.TryGetValue(key, out alertState);
|
||||||
|
|
||||||
|
alertState = default;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the alert. If the alert or another alert of the same category is already showing,
|
||||||
|
/// it will be updated / replaced with the specified values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="euid"></param>
|
||||||
|
/// <param name="alertType">type of the alert to set</param>
|
||||||
|
/// <param name="severity">severity, if supported by the alert</param>
|
||||||
|
/// <param name="cooldown">cooldown start and end, if null there will be no cooldown (and it will
|
||||||
|
/// be erased if there is currently a cooldown for the alert)</param>
|
||||||
|
public void ShowAlert(EntityUid euid, AlertType alertType, short? severity = null, (TimeSpan, TimeSpan)? cooldown = null)
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(euid, out AlertsComponent alertsComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (TryGet(alertType, out var alert))
|
||||||
|
{
|
||||||
|
// Check whether the alert category we want to show is already being displayed, with the same type,
|
||||||
|
// severity, and cooldown.
|
||||||
|
if (alertsComponent.Alerts.TryGetValue(alert.AlertKey, out var alertStateCallback) &&
|
||||||
|
alertStateCallback.Type == alertType &&
|
||||||
|
alertStateCallback.Severity == severity &&
|
||||||
|
alertStateCallback.Cooldown == cooldown)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the case we're changing the alert type but not the category, we need to remove it first.
|
||||||
|
alertsComponent.Alerts.Remove(alert.AlertKey);
|
||||||
|
|
||||||
|
alertsComponent.Alerts[alert.AlertKey] = new AlertState
|
||||||
|
{ Cooldown = cooldown, Severity = severity, Type = alertType };
|
||||||
|
|
||||||
|
AfterShowAlert(alertsComponent);
|
||||||
|
|
||||||
|
alertsComponent.Dirty();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.ErrorS("alert", "Unable to show alert {0}, please ensure this alertType has" +
|
||||||
|
" a corresponding YML alert prototype",
|
||||||
|
alertType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear the alert with the given category, if one is currently showing.
|
||||||
|
/// </summary>
|
||||||
|
public void ClearAlertCategory(EntityUid euid, AlertCategory category)
|
||||||
|
{
|
||||||
|
if(!EntityManager.TryGetComponent(euid, out AlertsComponent alertsComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var key = AlertKey.ForCategory(category);
|
||||||
|
if (!alertsComponent.Alerts.Remove(key))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterClearAlert(alertsComponent);
|
||||||
|
|
||||||
|
alertsComponent.Dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear the alert of the given type if it is currently showing.
|
||||||
|
/// </summary>
|
||||||
|
public void ClearAlert(EntityUid euid, AlertType alertType)
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(euid, out AlertsComponent alertsComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (TryGet(alertType, out var alert))
|
||||||
|
{
|
||||||
|
if (!alertsComponent.Alerts.Remove(alert.AlertKey))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterClearAlert(alertsComponent);
|
||||||
|
|
||||||
|
alertsComponent.Dirty();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.ErrorS("alert", "unable to clear alert, unknown alertType {0}", alertType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked after showing an alert prior to dirtying the component
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="alertsComponent"></param>
|
||||||
|
protected virtual void AfterShowAlert(AlertsComponent alertsComponent) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked after clearing an alert prior to dirtying the component
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="alertsComponent"></param>
|
||||||
|
protected virtual void AfterClearAlert(AlertsComponent alertsComponent) { }
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<AlertsComponent, ComponentStartup>((uid, _, _) => RaiseLocalEvent(uid, new AlertSyncEvent(uid)));
|
||||||
|
SubscribeLocalEvent<AlertsComponent, ComponentShutdown>((uid, _, _) => HandleComponentShutdown(uid));
|
||||||
|
|
||||||
|
SubscribeLocalEvent<AlertsComponent, ComponentGetState>(ClientAlertsGetState);
|
||||||
|
SubscribeNetworkEvent<ClickAlertEvent>(HandleClickAlert);
|
||||||
|
|
||||||
|
LoadPrototypes();
|
||||||
|
_prototypeManager.PrototypesReloaded += HandlePrototypesReloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void HandleComponentShutdown(EntityUid uid)
|
||||||
|
{
|
||||||
|
RaiseLocalEvent(uid, new AlertSyncEvent(uid));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
_prototypeManager.PrototypesReloaded -= HandlePrototypesReloaded;
|
||||||
|
|
||||||
|
base.Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandlePrototypesReloaded(PrototypesReloadedEventArgs obj)
|
||||||
|
{
|
||||||
|
LoadPrototypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void LoadPrototypes()
|
||||||
|
{
|
||||||
|
_typeToAlert.Clear();
|
||||||
|
foreach (var alert in _prototypeManager.EnumeratePrototypes<AlertPrototype>())
|
||||||
|
{
|
||||||
|
if (!_typeToAlert.TryAdd(alert.AlertType, alert))
|
||||||
|
{
|
||||||
|
Logger.ErrorS("alert",
|
||||||
|
"Found alert with duplicate alertType {0} - all alerts must have" +
|
||||||
|
" a unique alerttype, this one will be skipped", alert.AlertType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to get the alert of the indicated type
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if found</returns>
|
||||||
|
public bool TryGet(AlertType alertType, [NotNullWhen(true)] out AlertPrototype? alert)
|
||||||
|
{
|
||||||
|
return _typeToAlert.TryGetValue(alertType, out alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleClickAlert(ClickAlertEvent msg, EntitySessionEventArgs args)
|
||||||
|
{
|
||||||
|
var player = args.SenderSession.AttachedEntity;
|
||||||
|
if (player is null || !EntityManager.TryGetComponent<AlertsComponent>(player, out var alertComp)) return;
|
||||||
|
|
||||||
|
if (!IsShowingAlert(player.Value, msg.Type))
|
||||||
|
{
|
||||||
|
Logger.DebugS("alert", "user {0} attempted to" +
|
||||||
|
" click alert {1} which is not currently showing for them",
|
||||||
|
EntityManager.GetComponent<MetaDataComponent>(player.Value).EntityName, msg.Type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGet(msg.Type, out var alert))
|
||||||
|
{
|
||||||
|
Logger.WarningS("alert", "unrecognized encoded alert {0}", msg.Type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
alert.OnClick?.AlertClicked(player.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ClientAlertsGetState(EntityUid uid, AlertsComponent component, ref ComponentGetState args)
|
||||||
|
{
|
||||||
|
args.State = new AlertsComponentState(component.Alerts);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Content.Shared/Alert/ClickAlertEvent.cs
Normal file
19
Content.Shared/Alert/ClickAlertEvent.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Alert;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A message that calls the click interaction on a alert
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class ClickAlertEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public readonly AlertType Type;
|
||||||
|
|
||||||
|
public ClickAlertEvent(AlertType alertType)
|
||||||
|
{
|
||||||
|
Type = alertType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Shared.Alert
|
namespace Content.Shared.Alert
|
||||||
{
|
{
|
||||||
@@ -11,25 +10,7 @@ namespace Content.Shared.Alert
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked on server side when user clicks an alert.
|
/// Invoked on server side when user clicks an alert.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="args"></param>
|
/// <param name="player"></param>
|
||||||
void AlertClicked(ClickAlertEventArgs args);
|
void AlertClicked(EntityUid player);
|
||||||
}
|
|
||||||
|
|
||||||
public class ClickAlertEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Player clicking the alert
|
|
||||||
/// </summary>
|
|
||||||
public readonly EntityUid Player;
|
|
||||||
/// <summary>
|
|
||||||
/// Alert that was clicked
|
|
||||||
/// </summary>
|
|
||||||
public readonly AlertPrototype Alert;
|
|
||||||
|
|
||||||
public ClickAlertEventArgs(EntityUid player, AlertPrototype alert)
|
|
||||||
{
|
|
||||||
Player = player;
|
|
||||||
Alert = alert;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Players;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Shared.Alert
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Handles the icons on the right side of the screen.
|
|
||||||
/// Should only be used for player-controlled entities.
|
|
||||||
/// </summary>
|
|
||||||
[NetworkedComponent()]
|
|
||||||
public abstract class SharedAlertsComponent : Component
|
|
||||||
{
|
|
||||||
[Dependency]
|
|
||||||
protected readonly AlertManager AlertManager = default!;
|
|
||||||
|
|
||||||
public override string Name => "Alerts";
|
|
||||||
|
|
||||||
[ViewVariables] private Dictionary<AlertKey, AlertState> _alerts = new();
|
|
||||||
|
|
||||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
|
||||||
{
|
|
||||||
base.HandleComponentState(curState, nextState);
|
|
||||||
|
|
||||||
if (curState is not AlertsComponentState state)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_alerts = state.Alerts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ComponentState GetComponentState()
|
|
||||||
{
|
|
||||||
return new AlertsComponentState(_alerts);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <returns>true iff an alert of the indicated alert category is currently showing</returns>
|
|
||||||
public bool IsShowingAlertCategory(AlertCategory alertCategory)
|
|
||||||
{
|
|
||||||
return IsShowingAlert(AlertKey.ForCategory(alertCategory));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <returns>true iff an alert of the indicated id is currently showing</returns>
|
|
||||||
public bool IsShowingAlert(AlertType alertType)
|
|
||||||
{
|
|
||||||
if (AlertManager.TryGet(alertType, out var alert))
|
|
||||||
{
|
|
||||||
return IsShowingAlert(alert.AlertKey);
|
|
||||||
}
|
|
||||||
Logger.DebugS("alert", "unknown alert type {0}", alertType);
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <returns>true iff an alert of the indicated key is currently showing</returns>
|
|
||||||
protected bool IsShowingAlert(AlertKey alertKey)
|
|
||||||
{
|
|
||||||
return _alerts.ContainsKey(alertKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected IEnumerable<KeyValuePair<AlertKey, AlertState>> EnumerateAlertStates()
|
|
||||||
{
|
|
||||||
return _alerts;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool TryGetAlertState(AlertKey key, out AlertState alertState)
|
|
||||||
{
|
|
||||||
return _alerts.TryGetValue(key, out alertState);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Shows the alert. If the alert or another alert of the same category is already showing,
|
|
||||||
/// it will be updated / replaced with the specified values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="alertType">type of the alert to set</param>
|
|
||||||
/// <param name="severity">severity, if supported by the alert</param>
|
|
||||||
/// <param name="cooldown">cooldown start and end, if null there will be no cooldown (and it will
|
|
||||||
/// be erased if there is currently a cooldown for the alert)</param>
|
|
||||||
public void ShowAlert(AlertType alertType, short? severity = null, (TimeSpan, TimeSpan)? cooldown = null)
|
|
||||||
{
|
|
||||||
if (AlertManager.TryGet(alertType, out var alert))
|
|
||||||
{
|
|
||||||
// Check whether the alert category we want to show is already being displayed, with the same type,
|
|
||||||
// severity, and cooldown.
|
|
||||||
if (_alerts.TryGetValue(alert.AlertKey, out var alertStateCallback) &&
|
|
||||||
alertStateCallback.Type == alertType &&
|
|
||||||
alertStateCallback.Severity == severity &&
|
|
||||||
alertStateCallback.Cooldown == cooldown)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the case we're changing the alert type but not the category, we need to remove it first.
|
|
||||||
_alerts.Remove(alert.AlertKey);
|
|
||||||
|
|
||||||
_alerts[alert.AlertKey] = new AlertState
|
|
||||||
{Cooldown = cooldown, Severity = severity, Type=alertType};
|
|
||||||
|
|
||||||
AfterShowAlert();
|
|
||||||
|
|
||||||
Dirty();
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.ErrorS("alert", "Unable to show alert {0}, please ensure this alertType has" +
|
|
||||||
" a corresponding YML alert prototype",
|
|
||||||
alertType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clear the alert with the given category, if one is currently showing.
|
|
||||||
/// </summary>
|
|
||||||
public void ClearAlertCategory(AlertCategory category)
|
|
||||||
{
|
|
||||||
var key = AlertKey.ForCategory(category);
|
|
||||||
if (!_alerts.Remove(key))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AfterClearAlert();
|
|
||||||
|
|
||||||
Dirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clear the alert of the given type if it is currently showing.
|
|
||||||
/// </summary>
|
|
||||||
public void ClearAlert(AlertType alertType)
|
|
||||||
{
|
|
||||||
if (AlertManager.TryGet(alertType, out var alert))
|
|
||||||
{
|
|
||||||
if (!_alerts.Remove(alert.AlertKey))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AfterClearAlert();
|
|
||||||
|
|
||||||
Dirty();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.ErrorS("alert", "unable to clear alert, unknown alertType {0}", alertType);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked after showing an alert prior to dirtying the component
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void AfterShowAlert() { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked after clearing an alert prior to dirtying the component
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void AfterClearAlert() { }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public class AlertsComponentState : ComponentState
|
|
||||||
{
|
|
||||||
public Dictionary<AlertKey, AlertState> Alerts;
|
|
||||||
|
|
||||||
public AlertsComponentState(Dictionary<AlertKey, AlertState> alerts)
|
|
||||||
{
|
|
||||||
Alerts = alerts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A message that calls the click interaction on a alert
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
#pragma warning disable 618
|
|
||||||
public class ClickAlertMessage : ComponentMessage
|
|
||||||
#pragma warning restore 618
|
|
||||||
{
|
|
||||||
public readonly AlertType Type;
|
|
||||||
|
|
||||||
public ClickAlertMessage(AlertType alertType)
|
|
||||||
{
|
|
||||||
Directed = true;
|
|
||||||
Type = alertType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public struct AlertState
|
|
||||||
{
|
|
||||||
public short? Severity;
|
|
||||||
public (TimeSpan, TimeSpan)? Cooldown;
|
|
||||||
public AlertType Type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffect;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
@@ -58,10 +56,8 @@ namespace Content.Shared.Jittering
|
|||||||
/// <param name="frequency">Frequency for jittering. See <see cref="MaxFrequency"/> and <see cref="MinFrequency"/>.</param>
|
/// <param name="frequency">Frequency for jittering. See <see cref="MaxFrequency"/> and <see cref="MinFrequency"/>.</param>
|
||||||
/// <param name="forceValueChange">Whether to change any existing jitter value even if they're greater than the ones we're setting.</param>
|
/// <param name="forceValueChange">Whether to change any existing jitter value even if they're greater than the ones we're setting.</param>
|
||||||
/// <param name="status">The status effects component to modify.</param>
|
/// <param name="status">The status effects component to modify.</param>
|
||||||
/// <param name="alerts">The alerts component.</param>
|
|
||||||
public void DoJitter(EntityUid uid, TimeSpan time, bool refresh, float amplitude = 10f, float frequency = 4f, bool forceValueChange = false,
|
public void DoJitter(EntityUid uid, TimeSpan time, bool refresh, float amplitude = 10f, float frequency = 4f, bool forceValueChange = false,
|
||||||
StatusEffectsComponent? status = null,
|
StatusEffectsComponent? status = null)
|
||||||
SharedAlertsComponent? alerts = null)
|
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return;
|
return;
|
||||||
@@ -69,7 +65,7 @@ namespace Content.Shared.Jittering
|
|||||||
amplitude = Math.Clamp(amplitude, MinAmplitude, MaxAmplitude);
|
amplitude = Math.Clamp(amplitude, MinAmplitude, MaxAmplitude);
|
||||||
frequency = Math.Clamp(frequency, MinFrequency, MaxFrequency);
|
frequency = Math.Clamp(frequency, MinFrequency, MaxFrequency);
|
||||||
|
|
||||||
if (StatusEffects.TryAddStatusEffect<JitteringComponent>(uid, "Jitter", time, refresh, status, alerts))
|
if (StatusEffects.TryAddStatusEffect<JitteringComponent>(uid, "Jitter", time, refresh, status))
|
||||||
{
|
{
|
||||||
var jittering = EntityManager.GetComponent<JitteringComponent>(uid);
|
var jittering = EntityManager.GetComponent<JitteringComponent>(uid);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using Content.Shared.MobState.State;
|
|||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Players;
|
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
@@ -69,10 +68,7 @@ namespace Content.Shared.MobState.Components
|
|||||||
|
|
||||||
protected override void OnRemove()
|
protected override void OnRemove()
|
||||||
{
|
{
|
||||||
if (_entMan.TryGetComponent(Owner, out SharedAlertsComponent? status))
|
EntitySystem.Get<AlertsSystem>().ClearAlert(Owner, AlertType.HumanHealth);
|
||||||
{
|
|
||||||
status.ClearAlert(AlertType.HumanHealth);
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnRemove();
|
base.OnRemove();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Standing;
|
using Content.Shared.Standing;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
@@ -15,10 +15,7 @@ namespace Content.Shared.MobState.State
|
|||||||
{
|
{
|
||||||
base.EnterState(uid, entityManager);
|
base.EnterState(uid, entityManager);
|
||||||
|
|
||||||
if (entityManager.TryGetComponent(uid, out SharedAlertsComponent? status))
|
EntitySystem.Get<AlertsSystem>().ShowAlert(uid, AlertType.HumanCrit); // TODO: combine humancrit-0 and humancrit-1 into a gif and display it
|
||||||
{
|
|
||||||
status.ShowAlert(AlertType.HumanCrit); // TODO: combine humancrit-0 and humancrit-1 into a gif and display it
|
|
||||||
}
|
|
||||||
|
|
||||||
EntitySystem.Get<StandingStateSystem>().Down(uid);
|
EntitySystem.Get<StandingStateSystem>().Down(uid);
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace Content.Shared.Pulling.Systems
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly SharedPullingSystem _pullSystem = default!;
|
[Dependency] private readonly SharedPullingSystem _pullSystem = default!;
|
||||||
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!;
|
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -47,8 +48,7 @@ namespace Content.Shared.Pulling.Systems
|
|||||||
if (args.Puller.Owner != uid)
|
if (args.Puller.Owner != uid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(component.Owner, out SharedAlertsComponent? alerts))
|
_alertsSystem.ShowAlert(component.Owner, AlertType.Pulling);
|
||||||
alerts.ShowAlert(AlertType.Pulling);
|
|
||||||
|
|
||||||
RefreshMovementSpeed(component);
|
RefreshMovementSpeed(component);
|
||||||
}
|
}
|
||||||
@@ -61,8 +61,8 @@ namespace Content.Shared.Pulling.Systems
|
|||||||
if (args.Puller.Owner != uid)
|
if (args.Puller.Owner != uid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(component.Owner, out SharedAlertsComponent? alerts))
|
var euid = component.Owner;
|
||||||
alerts.ClearAlert(AlertType.Pulling);
|
_alertsSystem.ClearAlert(euid, AlertType.Pulling);
|
||||||
|
|
||||||
RefreshMovementSpeed(component);
|
RefreshMovementSpeed(component);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ namespace Content.Shared.Pulling
|
|||||||
public abstract partial class SharedPullingSystem : EntitySystem
|
public abstract partial class SharedPullingSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedPullingStateManagementSystem _pullSm = default!;
|
[Dependency] private readonly SharedPullingStateManagementSystem _pullSm = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A mapping of pullers to the entity that they are pulling.
|
/// A mapping of pullers to the entity that they are pulling.
|
||||||
@@ -105,9 +106,8 @@ namespace Content.Shared.Pulling
|
|||||||
{
|
{
|
||||||
if (args.Pulled.Owner != uid)
|
if (args.Pulled.Owner != uid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(component.Owner, out SharedAlertsComponent? alerts))
|
_alertsSystem.ShowAlert(component.Owner, AlertType.Pulled);
|
||||||
alerts.ShowAlert(AlertType.Pulled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PullableHandlePullStopped(EntityUid uid, SharedPullableComponent component, PullStoppedMessage args)
|
private void PullableHandlePullStopped(EntityUid uid, SharedPullableComponent component, PullStoppedMessage args)
|
||||||
@@ -115,8 +115,7 @@ namespace Content.Shared.Pulling
|
|||||||
if (args.Pulled.Owner != uid)
|
if (args.Pulled.Owner != uid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(component.Owner, out SharedAlertsComponent? alerts))
|
_alertsSystem.ClearAlert(component.Owner, AlertType.Pulled);
|
||||||
alerts.ClearAlert(AlertType.Pulled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffect;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
@@ -8,7 +7,7 @@ namespace Content.Shared.Speech.EntitySystems
|
|||||||
public abstract class SharedStutteringSystem : EntitySystem
|
public abstract class SharedStutteringSystem : EntitySystem
|
||||||
{
|
{
|
||||||
// For code in shared... I imagine we ain't getting accent prediction anytime soon so let's not bother.
|
// For code in shared... I imagine we ain't getting accent prediction anytime soon so let's not bother.
|
||||||
public virtual void DoStutter(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent? status = null, SharedAlertsComponent? alerts = null)
|
public virtual void DoStutter(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent? status = null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -15,6 +15,7 @@ namespace Content.Shared.StatusEffect
|
|||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IComponentFactory _componentFactory = default!;
|
[Dependency] private readonly IComponentFactory _componentFactory = default!;
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -80,20 +81,16 @@ namespace Content.Shared.StatusEffect
|
|||||||
/// <param name="time">How long the effect should last for.</param>
|
/// <param name="time">How long the effect should last for.</param>
|
||||||
/// <param name="refresh">The status effect cooldown should be refreshed (true) or accumulated (false).</param>
|
/// <param name="refresh">The status effect cooldown should be refreshed (true) or accumulated (false).</param>
|
||||||
/// <param name="status">The status effects component to change, if you already have it.</param>
|
/// <param name="status">The status effects component to change, if you already have it.</param>
|
||||||
/// <param name="alerts">The alerts component to modify, if the status effect has an alert.</param>
|
|
||||||
/// <returns>False if the effect could not be added or the component already exists, true otherwise.</returns>
|
/// <returns>False if the effect could not be added or the component already exists, true otherwise.</returns>
|
||||||
/// <typeparam name="T">The component type to add and remove from the entity.</typeparam>
|
/// <typeparam name="T">The component type to add and remove from the entity.</typeparam>
|
||||||
public bool TryAddStatusEffect<T>(EntityUid uid, string key, TimeSpan time, bool refresh,
|
public bool TryAddStatusEffect<T>(EntityUid uid, string key, TimeSpan time, bool refresh,
|
||||||
StatusEffectsComponent? status=null,
|
StatusEffectsComponent? status = null)
|
||||||
SharedAlertsComponent? alerts=null)
|
|
||||||
where T: Component, new()
|
where T: Component, new()
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Resolve(uid, ref alerts, false);
|
if (TryAddStatusEffect(uid, key, time, refresh, status))
|
||||||
|
|
||||||
if (TryAddStatusEffect(uid, key, time, refresh, status, alerts))
|
|
||||||
{
|
{
|
||||||
// If they already have the comp, we just won't bother updating anything.
|
// If they already have the comp, we just won't bother updating anything.
|
||||||
if (!EntityManager.HasComponent<T>(uid))
|
if (!EntityManager.HasComponent<T>(uid))
|
||||||
@@ -108,15 +105,12 @@ namespace Content.Shared.StatusEffect
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, string component,
|
public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, string component,
|
||||||
StatusEffectsComponent? status = null,
|
StatusEffectsComponent? status = null)
|
||||||
SharedAlertsComponent? alerts = null)
|
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Resolve(uid, ref alerts, false);
|
if (TryAddStatusEffect(uid, key, time, refresh, status))
|
||||||
|
|
||||||
if (TryAddStatusEffect(uid, key, time, refresh, status, alerts))
|
|
||||||
{
|
{
|
||||||
// If they already have the comp, we just won't bother updating anything.
|
// If they already have the comp, we just won't bother updating anything.
|
||||||
if (!EntityManager.HasComponent(uid, _componentFactory.GetRegistration(component).Type))
|
if (!EntityManager.HasComponent(uid, _componentFactory.GetRegistration(component).Type))
|
||||||
@@ -142,26 +136,22 @@ namespace Content.Shared.StatusEffect
|
|||||||
/// <param name="time">How long the effect should last for.</param>
|
/// <param name="time">How long the effect should last for.</param>
|
||||||
/// <param name="refresh">The status effect cooldown should be refreshed (true) or accumulated (false).</param>
|
/// <param name="refresh">The status effect cooldown should be refreshed (true) or accumulated (false).</param>
|
||||||
/// <param name="status">The status effects component to change, if you already have it.</param>
|
/// <param name="status">The status effects component to change, if you already have it.</param>
|
||||||
/// <param name="alerts">The alerts component to modify, if the status effect has an alert.</param>
|
|
||||||
/// <returns>False if the effect could not be added, or if the effect already existed.</returns>
|
/// <returns>False if the effect could not be added, or if the effect already existed.</returns>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This obviously does not add any actual 'effects' on its own. Use the generic overload,
|
/// This obviously does not add any actual 'effects' on its own. Use the generic overload,
|
||||||
/// which takes in a component type, if you want to automatically add and remove a component.
|
/// which takes in a component type, if you want to automatically add and remove a component.
|
||||||
///
|
///
|
||||||
/// If the effect already exists, it will simply replace the cooldown with the new one given.
|
/// If the effect already exists, it will simply replace the cooldown with the new one given.
|
||||||
/// If you want special 'effect merging' behavior, do it your own damn self!
|
/// If you want special 'effect merging' behavior, do it your own damn self!
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh,
|
public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh,
|
||||||
StatusEffectsComponent? status=null,
|
StatusEffectsComponent? status=null)
|
||||||
SharedAlertsComponent? alerts=null)
|
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return false;
|
return false;
|
||||||
if (!CanApplyEffect(uid, key, status))
|
if (!CanApplyEffect(uid, key, status))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Resolve(uid, ref alerts, false);
|
|
||||||
|
|
||||||
// we already checked if it has the index in CanApplyEffect so a straight index and not tryindex here
|
// we already checked if it has the index in CanApplyEffect so a straight index and not tryindex here
|
||||||
// is fine
|
// is fine
|
||||||
var proto = _prototypeManager.Index<StatusEffectPrototype>(key);
|
var proto = _prototypeManager.Index<StatusEffectPrototype>(key);
|
||||||
@@ -191,9 +181,10 @@ namespace Content.Shared.StatusEffect
|
|||||||
status.ActiveEffects.Add(key, new StatusEffectState(cooldown, refresh, null));
|
status.ActiveEffects.Add(key, new StatusEffectState(cooldown, refresh, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proto.Alert != null && alerts != null)
|
if (proto.Alert != null)
|
||||||
{
|
{
|
||||||
alerts.ShowAlert(proto.Alert.Value, cooldown: GetAlertCooldown(uid, proto.Alert.Value, status));
|
var cooldown1 = GetAlertCooldown(uid, proto.Alert.Value, status);
|
||||||
|
_alertsSystem.ShowAlert(uid, proto.Alert.Value, null, cooldown1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status.Dirty();
|
status.Dirty();
|
||||||
@@ -233,15 +224,13 @@ namespace Content.Shared.StatusEffect
|
|||||||
/// <param name="uid">The entity to remove an effect from.</param>
|
/// <param name="uid">The entity to remove an effect from.</param>
|
||||||
/// <param name="key">The effect ID to remove.</param>
|
/// <param name="key">The effect ID to remove.</param>
|
||||||
/// <param name="status">The status effects component to change, if you already have it.</param>
|
/// <param name="status">The status effects component to change, if you already have it.</param>
|
||||||
/// <param name="alerts">The alerts component to modify, if the status effect has an alert.</param>
|
|
||||||
/// <returns>False if the effect could not be removed, true otherwise.</returns>
|
/// <returns>False if the effect could not be removed, true otherwise.</returns>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Obviously this doesn't automatically clear any effects a status effect might have.
|
/// Obviously this doesn't automatically clear any effects a status effect might have.
|
||||||
/// That's up to the removed component to handle itself when it's removed.
|
/// That's up to the removed component to handle itself when it's removed.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public bool TryRemoveStatusEffect(EntityUid uid, string key,
|
public bool TryRemoveStatusEffect(EntityUid uid, string key,
|
||||||
StatusEffectsComponent? status=null,
|
StatusEffectsComponent? status=null)
|
||||||
SharedAlertsComponent? alerts=null)
|
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return false;
|
return false;
|
||||||
@@ -250,8 +239,6 @@ namespace Content.Shared.StatusEffect
|
|||||||
if (!_prototypeManager.TryIndex<StatusEffectPrototype>(key, out var proto))
|
if (!_prototypeManager.TryIndex<StatusEffectPrototype>(key, out var proto))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Resolve(uid, ref alerts, false);
|
|
||||||
|
|
||||||
var state = status.ActiveEffects[key];
|
var state = status.ActiveEffects[key];
|
||||||
|
|
||||||
// There are cases where a status effect component might be server-only, so TryGetRegistration...
|
// There are cases where a status effect component might be server-only, so TryGetRegistration...
|
||||||
@@ -267,9 +254,9 @@ namespace Content.Shared.StatusEffect
|
|||||||
EntityManager.RemoveComponent(uid, type);
|
EntityManager.RemoveComponent(uid, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proto.Alert != null && alerts != null)
|
if (proto.Alert != null)
|
||||||
{
|
{
|
||||||
alerts.ClearAlert(proto.Alert.Value);
|
_alertsSystem.ClearAlert(uid, proto.Alert.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
status.ActiveEffects.Remove(key);
|
status.ActiveEffects.Remove(key);
|
||||||
@@ -284,21 +271,17 @@ namespace Content.Shared.StatusEffect
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="uid">The entity to remove effects from.</param>
|
/// <param name="uid">The entity to remove effects from.</param>
|
||||||
/// <param name="status">The status effects component to change, if you already have it.</param>
|
/// <param name="status">The status effects component to change, if you already have it.</param>
|
||||||
/// <param name="alerts">The alerts component to modify, if the status effect has an alert.</param>
|
|
||||||
/// <returns>False if any status effects failed to be removed, true if they all did.</returns>
|
/// <returns>False if any status effects failed to be removed, true if they all did.</returns>
|
||||||
public bool TryRemoveAllStatusEffects(EntityUid uid,
|
public bool TryRemoveAllStatusEffects(EntityUid uid,
|
||||||
StatusEffectsComponent? status = null,
|
StatusEffectsComponent? status = null)
|
||||||
SharedAlertsComponent? alerts = null)
|
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Resolve(uid, ref alerts, false);
|
|
||||||
|
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
foreach (var effect in status.ActiveEffects)
|
foreach (var effect in status.ActiveEffects)
|
||||||
{
|
{
|
||||||
if(!TryRemoveStatusEffect(uid, effect.Key, status, alerts))
|
if(!TryRemoveStatusEffect(uid, effect.Key, status))
|
||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,14 +333,11 @@ namespace Content.Shared.StatusEffect
|
|||||||
/// <param name="time">The amount of time to add.</param>
|
/// <param name="time">The amount of time to add.</param>
|
||||||
/// <param name="status">The status effect component, should you already have it.</param>
|
/// <param name="status">The status effect component, should you already have it.</param>
|
||||||
public bool TryAddTime(EntityUid uid, string key, TimeSpan time,
|
public bool TryAddTime(EntityUid uid, string key, TimeSpan time,
|
||||||
StatusEffectsComponent? status=null,
|
StatusEffectsComponent? status=null)
|
||||||
SharedAlertsComponent? alert=null)
|
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Resolve(uid, ref alert, false);
|
|
||||||
|
|
||||||
if (!HasStatusEffect(uid, key, status))
|
if (!HasStatusEffect(uid, key, status))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -366,11 +346,10 @@ namespace Content.Shared.StatusEffect
|
|||||||
status.ActiveEffects[key].Cooldown = timer;
|
status.ActiveEffects[key].Cooldown = timer;
|
||||||
|
|
||||||
if (_prototypeManager.TryIndex<StatusEffectPrototype>(key, out var proto)
|
if (_prototypeManager.TryIndex<StatusEffectPrototype>(key, out var proto)
|
||||||
&& alert != null
|
|
||||||
&& proto.Alert != null)
|
&& proto.Alert != null)
|
||||||
{
|
{
|
||||||
alert.ShowAlert(proto.Alert.Value, cooldown: GetAlertCooldown(uid, proto.Alert.Value, status));
|
(TimeSpan, TimeSpan)? cooldown = GetAlertCooldown(uid, proto.Alert.Value, status);
|
||||||
|
_alertsSystem.ShowAlert(uid, proto.Alert.Value, null, cooldown);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -384,14 +363,11 @@ namespace Content.Shared.StatusEffect
|
|||||||
/// <param name="time">The amount of time to add.</param>
|
/// <param name="time">The amount of time to add.</param>
|
||||||
/// <param name="status">The status effect component, should you already have it.</param>
|
/// <param name="status">The status effect component, should you already have it.</param>
|
||||||
public bool TryRemoveTime(EntityUid uid, string key, TimeSpan time,
|
public bool TryRemoveTime(EntityUid uid, string key, TimeSpan time,
|
||||||
StatusEffectsComponent? status=null,
|
StatusEffectsComponent? status=null)
|
||||||
SharedAlertsComponent? alert=null)
|
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Resolve(uid, ref alert, false);
|
|
||||||
|
|
||||||
if (!HasStatusEffect(uid, key, status))
|
if (!HasStatusEffect(uid, key, status))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -405,11 +381,10 @@ namespace Content.Shared.StatusEffect
|
|||||||
status.ActiveEffects[key].Cooldown = timer;
|
status.ActiveEffects[key].Cooldown = timer;
|
||||||
|
|
||||||
if (_prototypeManager.TryIndex<StatusEffectPrototype>(key, out var proto)
|
if (_prototypeManager.TryIndex<StatusEffectPrototype>(key, out var proto)
|
||||||
&& alert != null
|
|
||||||
&& proto.Alert != null)
|
&& proto.Alert != null)
|
||||||
{
|
{
|
||||||
alert.ShowAlert(proto.Alert.Value, cooldown: GetAlertCooldown(uid, proto.Alert.Value, status));
|
(TimeSpan, TimeSpan)? cooldown = GetAlertCooldown(uid, proto.Alert.Value, status);
|
||||||
|
_alertsSystem.ShowAlert(uid, proto.Alert.Value, null, cooldown);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
@@ -119,8 +118,7 @@ namespace Content.Shared.Stunnable
|
|||||||
/// Stuns the entity, disallowing it from doing many interactions temporarily.
|
/// Stuns the entity, disallowing it from doing many interactions temporarily.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryStun(EntityUid uid, TimeSpan time, bool refresh,
|
public bool TryStun(EntityUid uid, TimeSpan time, bool refresh,
|
||||||
StatusEffectsComponent? status = null,
|
StatusEffectsComponent? status = null)
|
||||||
SharedAlertsComponent? alerts = null)
|
|
||||||
{
|
{
|
||||||
if (time <= TimeSpan.Zero)
|
if (time <= TimeSpan.Zero)
|
||||||
return false;
|
return false;
|
||||||
@@ -128,17 +126,14 @@ namespace Content.Shared.Stunnable
|
|||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Resolve(uid, ref alerts, false);
|
return _statusEffectSystem.TryAddStatusEffect<StunnedComponent>(uid, "Stun", time, refresh);
|
||||||
|
|
||||||
return _statusEffectSystem.TryAddStatusEffect<StunnedComponent>(uid, "Stun", time, refresh, alerts: alerts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Knocks down the entity, making it fall to the ground.
|
/// Knocks down the entity, making it fall to the ground.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryKnockdown(EntityUid uid, TimeSpan time, bool refresh,
|
public bool TryKnockdown(EntityUid uid, TimeSpan time, bool refresh,
|
||||||
StatusEffectsComponent? status = null,
|
StatusEffectsComponent? status = null)
|
||||||
SharedAlertsComponent? alerts = null)
|
|
||||||
{
|
{
|
||||||
if (time <= TimeSpan.Zero)
|
if (time <= TimeSpan.Zero)
|
||||||
return false;
|
return false;
|
||||||
@@ -146,25 +141,19 @@ namespace Content.Shared.Stunnable
|
|||||||
if (!Resolve(uid, ref status, false))
|
if (!Resolve(uid, ref status, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Resolve(uid, ref alerts, false);
|
return _statusEffectSystem.TryAddStatusEffect<KnockedDownComponent>(uid, "KnockedDown", time, refresh);
|
||||||
|
|
||||||
return _statusEffectSystem.TryAddStatusEffect<KnockedDownComponent>(uid, "KnockedDown", time, refresh, alerts: alerts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies knockdown and stun to the entity temporarily.
|
/// Applies knockdown and stun to the entity temporarily.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryParalyze(EntityUid uid, TimeSpan time, bool refresh,
|
public bool TryParalyze(EntityUid uid, TimeSpan time, bool refresh,
|
||||||
StatusEffectsComponent? status = null,
|
StatusEffectsComponent? status = null)
|
||||||
SharedAlertsComponent? alerts = null)
|
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status))
|
if (!Resolve(uid, ref status))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Optional component.
|
return TryKnockdown(uid, time, refresh, status) && TryStun(uid, time, refresh, status);
|
||||||
Resolve(uid, ref alerts, false);
|
|
||||||
|
|
||||||
return TryKnockdown(uid, time, refresh, status, alerts) && TryStun(uid, time, refresh, status, alerts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -172,19 +161,15 @@ namespace Content.Shared.Stunnable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TrySlowdown(EntityUid uid, TimeSpan time, bool refresh,
|
public bool TrySlowdown(EntityUid uid, TimeSpan time, bool refresh,
|
||||||
float walkSpeedMultiplier = 1f, float runSpeedMultiplier = 1f,
|
float walkSpeedMultiplier = 1f, float runSpeedMultiplier = 1f,
|
||||||
StatusEffectsComponent? status = null,
|
StatusEffectsComponent? status = null)
|
||||||
SharedAlertsComponent? alerts = null)
|
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref status))
|
if (!Resolve(uid, ref status))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// "Optional" component.
|
|
||||||
Resolve(uid, ref alerts, false);
|
|
||||||
|
|
||||||
if (time <= TimeSpan.Zero)
|
if (time <= TimeSpan.Zero)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_statusEffectSystem.TryAddStatusEffect<SlowedDownComponent>(uid, "SlowedDown", time, refresh, status, alerts))
|
if (_statusEffectSystem.TryAddStatusEffect<SlowedDownComponent>(uid, "SlowedDown", time, refresh, status))
|
||||||
{
|
{
|
||||||
var slowed = EntityManager.GetComponent<SlowedDownComponent>(uid);
|
var slowed = EntityManager.GetComponent<SlowedDownComponent>(uid);
|
||||||
// Doesn't make much sense to have the "TrySlowdown" method speed up entities now does it?
|
// Doesn't make much sense to have the "TrySlowdown" method speed up entities now does it?
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NUnit.Framework.Interfaces;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Reflection;
|
||||||
using Robust.Shared.Serialization.Manager;
|
using Robust.Shared.Serialization.Manager;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Tests.Shared.Alert
|
namespace Content.Tests.Shared.Alert
|
||||||
{
|
{
|
||||||
[TestFixture, TestOf(typeof(AlertManager))]
|
[TestFixture, TestOf(typeof(AlertsSystem))]
|
||||||
public class AlertManagerTests : ContentUnitTest
|
public class AlertManagerTests : ContentUnitTest
|
||||||
{
|
{
|
||||||
const string PROTOTYPES = @"
|
const string PROTOTYPES = @"
|
||||||
@@ -24,23 +27,26 @@ namespace Content.Tests.Shared.Alert
|
|||||||
";
|
";
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
[Ignore("There is no way to load extra Systems in a unit test, fixing RobustUnitTest is out of scope.")]
|
||||||
public void TestAlertManager()
|
public void TestAlertManager()
|
||||||
{
|
{
|
||||||
IoCManager.Resolve<ISerializationManager>().Initialize();
|
IoCManager.Resolve<ISerializationManager>().Initialize();
|
||||||
|
|
||||||
|
var reflection = IoCManager.Resolve<IReflectionManager>();
|
||||||
|
reflection.LoadAssemblies();
|
||||||
|
|
||||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||||
prototypeManager.Initialize();
|
prototypeManager.Initialize();
|
||||||
prototypeManager.LoadFromStream(new StringReader(PROTOTYPES));
|
prototypeManager.LoadFromStream(new StringReader(PROTOTYPES));
|
||||||
var alertManager = IoCManager.Resolve<AlertManager>();
|
|
||||||
alertManager.Initialize();
|
|
||||||
|
|
||||||
Assert.That(alertManager.TryGet(AlertType.LowPressure, out var lowPressure));
|
Assert.That(EntitySystem.Get<AlertsSystem>().TryGet(AlertType.LowPressure, out var lowPressure));
|
||||||
Assert.That(lowPressure.Icon, Is.EqualTo(new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/Alerts/Pressure/lowpressure.png"))));
|
Assert.That(lowPressure.Icon, Is.EqualTo(new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/Alerts/Pressure/lowpressure.png"))));
|
||||||
Assert.That(alertManager.TryGet(AlertType.HighPressure, out var highPressure));
|
Assert.That(EntitySystem.Get<AlertsSystem>().TryGet(AlertType.HighPressure, out var highPressure));
|
||||||
Assert.That(highPressure.Icon, Is.EqualTo(new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/Alerts/Pressure/highpressure.png"))));
|
Assert.That(highPressure.Icon, Is.EqualTo(new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/Alerts/Pressure/highpressure.png"))));
|
||||||
|
|
||||||
Assert.That(alertManager.TryGet(AlertType.LowPressure, out lowPressure));
|
Assert.That(EntitySystem.Get<AlertsSystem>().TryGet(AlertType.LowPressure, out lowPressure));
|
||||||
Assert.That(lowPressure.Icon, Is.EqualTo(new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/Alerts/Pressure/lowpressure.png"))));
|
Assert.That(lowPressure.Icon, Is.EqualTo(new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/Alerts/Pressure/lowpressure.png"))));
|
||||||
Assert.That(alertManager.TryGet(AlertType.HighPressure, out highPressure));
|
Assert.That(EntitySystem.Get<AlertsSystem>().TryGet(AlertType.HighPressure, out highPressure));
|
||||||
Assert.That(highPressure.Icon, Is.EqualTo(new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/Alerts/Pressure/highpressure.png"))));
|
Assert.That(highPressure.Icon, Is.EqualTo(new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/Alerts/Pressure/highpressure.png"))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.IO;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using Content.Server.Alert;
|
using Content.Server.Alert;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
@@ -7,10 +8,10 @@ using Robust.Shared.IoC;
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.Manager;
|
using Robust.Shared.Serialization.Manager;
|
||||||
|
|
||||||
namespace Content.Tests.Server.GameObjects.Components.Mobs
|
namespace Content.Tests.Shared.Alert
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
[TestOf(typeof(ServerAlertsComponent))]
|
[TestOf(typeof(AlertsComponent))]
|
||||||
public class ServerAlertsComponentTests : ContentUnitTest
|
public class ServerAlertsComponentTests : ContentUnitTest
|
||||||
{
|
{
|
||||||
const string PROTOTYPES = @"
|
const string PROTOTYPES = @"
|
||||||
@@ -28,6 +29,7 @@ namespace Content.Tests.Server.GameObjects.Components.Mobs
|
|||||||
";
|
";
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
[Ignore("There is no way to load extra Systems in a unit test, fixing RobustUnitTest is out of scope.")]
|
||||||
public void ShowAlerts()
|
public void ShowAlerts()
|
||||||
{
|
{
|
||||||
// this is kind of unnecessary because there's integration test coverage of Alert components
|
// this is kind of unnecessary because there's integration test coverage of Alert components
|
||||||
@@ -38,31 +40,31 @@ namespace Content.Tests.Server.GameObjects.Components.Mobs
|
|||||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||||
prototypeManager.Initialize();
|
prototypeManager.Initialize();
|
||||||
var factory = IoCManager.Resolve<IComponentFactory>();
|
var factory = IoCManager.Resolve<IComponentFactory>();
|
||||||
factory.RegisterClass<ServerAlertsComponent>();
|
factory.RegisterClass<AlertsComponent>();
|
||||||
prototypeManager.LoadFromStream(new StringReader(PROTOTYPES));
|
prototypeManager.LoadFromStream(new StringReader(PROTOTYPES));
|
||||||
prototypeManager.Resync();
|
prototypeManager.Resync();
|
||||||
var alertManager = IoCManager.Resolve<AlertManager>();
|
|
||||||
alertManager.Initialize();
|
|
||||||
|
|
||||||
|
var entSys = IoCManager.Resolve<IEntitySystemManager>();
|
||||||
|
entSys.LoadExtraSystemType<ServerAlertsSystem>();
|
||||||
|
|
||||||
var alertsComponent = new ServerAlertsComponent();
|
var alertsComponent = new AlertsComponent();
|
||||||
alertsComponent = IoCManager.InjectDependencies(alertsComponent);
|
alertsComponent = IoCManager.InjectDependencies(alertsComponent);
|
||||||
|
|
||||||
Assert.That(alertManager.TryGet(AlertType.LowPressure, out var lowpressure));
|
Assert.That(EntitySystem.Get<AlertsSystem>().TryGet(AlertType.LowPressure, out var lowpressure));
|
||||||
Assert.That(alertManager.TryGet(AlertType.HighPressure, out var highpressure));
|
Assert.That(EntitySystem.Get<AlertsSystem>().TryGet(AlertType.HighPressure, out var highpressure));
|
||||||
|
|
||||||
alertsComponent.ShowAlert(AlertType.LowPressure);
|
EntitySystem.Get<AlertsSystem>().ShowAlert(alertsComponent.Owner, AlertType.LowPressure, null, null);
|
||||||
var alertState = alertsComponent.GetComponentState() as AlertsComponentState;
|
var alertState = alertsComponent.GetComponentState() as AlertsComponentState;
|
||||||
Assert.NotNull(alertState);
|
Assert.NotNull(alertState);
|
||||||
Assert.That(alertState.Alerts.Count, Is.EqualTo(1));
|
Assert.That(alertState.Alerts.Count, Is.EqualTo(1));
|
||||||
Assert.That(alertState.Alerts.ContainsKey(lowpressure.AlertKey));
|
Assert.That(alertState.Alerts.ContainsKey(lowpressure.AlertKey));
|
||||||
|
|
||||||
alertsComponent.ShowAlert(AlertType.HighPressure);
|
EntitySystem.Get<AlertsSystem>().ShowAlert(alertsComponent.Owner, AlertType.HighPressure, null, null);
|
||||||
alertState = alertsComponent.GetComponentState() as AlertsComponentState;
|
alertState = alertsComponent.GetComponentState() as AlertsComponentState;
|
||||||
Assert.That(alertState.Alerts.Count, Is.EqualTo(1));
|
Assert.That(alertState.Alerts.Count, Is.EqualTo(1));
|
||||||
Assert.That(alertState.Alerts.ContainsKey(highpressure.AlertKey));
|
Assert.That(alertState.Alerts.ContainsKey(highpressure.AlertKey));
|
||||||
|
|
||||||
alertsComponent.ClearAlertCategory(AlertCategory.Pressure);
|
EntitySystem.Get<AlertsSystem>().ClearAlertCategory(alertsComponent.Owner, AlertCategory.Pressure);
|
||||||
alertState = alertsComponent.GetComponentState() as AlertsComponentState;
|
alertState = alertsComponent.GetComponentState() as AlertsComponentState;
|
||||||
Assert.That(alertState.Alerts.Count, Is.EqualTo(0));
|
Assert.That(alertState.Alerts.Count, Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user