Merge remote-tracking branch 'upstream/master' into 20-10-30-admins
This commit is contained in:
@@ -13,6 +13,7 @@ using Content.Client.UserInterface.AdminMenu;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Alert;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Client
|
||||
@@ -37,6 +38,7 @@ namespace Content.Client
|
||||
IoCManager.Register<IClickMapManager, ClickMapManager>();
|
||||
IoCManager.Register<IStationEventManager, StationEventManager>();
|
||||
IoCManager.Register<IAdminMenuManager, AdminMenuManager>();
|
||||
IoCManager.Register<AlertManager, AlertManager>();
|
||||
IoCManager.Register<IClientAdminManager, ClientAdminManager>();
|
||||
IoCManager.Register<EuiManager, EuiManager>();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -14,10 +15,13 @@ namespace Content.Client.Commands
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
var _configurationManager = IoCManager.Resolve<IConfigurationManager>();
|
||||
var old = _configurationManager.GetCVar<bool>("outline.enabled");
|
||||
_configurationManager.SetCVar("outline.enabled", !old);
|
||||
console.AddLine($"Draw outlines set to: {_configurationManager.GetCVar<bool>("outline.enabled")}");
|
||||
var configurationManager = IoCManager.Resolve<IConfigurationManager>();
|
||||
var cvar = CCVars.OutlineEnabled;
|
||||
var old = configurationManager.GetCVar(cvar);
|
||||
|
||||
configurationManager.SetCVar(cvar, !old);
|
||||
console.AddLine($"Draw outlines set to: {configurationManager.GetCVar(cvar)}");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ using Content.Shared.GameObjects.Components.Power.AME;
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
using Content.Shared.GameObjects.Components.VendingMachines;
|
||||
using Content.Shared.Kitchen;
|
||||
using Content.Shared.Alert;
|
||||
using Robust.Client;
|
||||
using Robust.Client.Interfaces;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
@@ -104,8 +105,6 @@ namespace Content.Client
|
||||
{
|
||||
IoCManager.Resolve<IMapManager>().CreateNewMapEntity(MapId.Nullspace);
|
||||
};
|
||||
|
||||
_configurationManager.RegisterCVar("outline.enabled", true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -156,6 +155,7 @@ namespace Content.Client
|
||||
IoCManager.Resolve<IStationEventManager>().Initialize();
|
||||
IoCManager.Resolve<IAdminMenuManager>().Initialize();
|
||||
IoCManager.Resolve<EuiManager>().Initialize();
|
||||
IoCManager.Resolve<AlertManager>().Initialize();
|
||||
|
||||
_baseClient.RunLevelChanged += (sender, args) =>
|
||||
{
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Body.Mechanism
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedHeartBehaviorComponent))]
|
||||
public class HeartBehaviorComponent : SharedHeartBehaviorComponent
|
||||
{
|
||||
public override void Update(float frameTime) { }
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,7 @@ namespace Content.Client.GameObjects.Components.Wires
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
_menu.OnClose -= Close;
|
||||
_menu.Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using Namotion.Reflection;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
@@ -142,7 +141,7 @@ namespace Content.Client.GameObjects.Components.Wires
|
||||
|
||||
private void OnConfirm(ButtonEventArgs args)
|
||||
{
|
||||
var config = GenerateDictionary<string, LineEdit>(_inputs, "Text");
|
||||
var config = GenerateDictionary(_inputs, "Text");
|
||||
|
||||
Owner.SendConfiguration(config);
|
||||
Close();
|
||||
@@ -153,13 +152,13 @@ namespace Content.Client.GameObjects.Components.Wires
|
||||
return Owner.Validation == null || Owner.Validation.IsMatch(value);
|
||||
}
|
||||
|
||||
private Dictionary<string, TConfig> GenerateDictionary<TConfig, TInput>(List<(string name, TInput input)> inputs, string propertyName) where TInput : Control
|
||||
private Dictionary<string, string> GenerateDictionary(IEnumerable<(string name, LineEdit input)> inputs, string propertyName)
|
||||
{
|
||||
var dictionary = new Dictionary<string, TConfig>();
|
||||
var dictionary = new Dictionary<string, string>();
|
||||
|
||||
foreach (var input in inputs)
|
||||
{
|
||||
var value = input.input.TryGetPropertyValue<TConfig>(propertyName);
|
||||
dictionary.Add(input.name, value);
|
||||
dictionary.Add(input.name, input.input.Text);
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
|
||||
93
Content.Client/GameObjects/Components/Mobs/AlertControl.cs
Normal file
93
Content.Client/GameObjects/Components/Mobs/AlertControl.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.Alert;
|
||||
using OpenToolkit.Mathematics;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
public class AlertControl : BaseButton
|
||||
{
|
||||
public AlertPrototype Alert { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Total duration of the cooldown in seconds. Null if no duration / cooldown.
|
||||
/// </summary>
|
||||
public int? TotalDuration { get; set; }
|
||||
|
||||
private short? _severity;
|
||||
private readonly TextureRect _icon;
|
||||
private CooldownGraphic _cooldownGraphic;
|
||||
|
||||
private readonly IResourceCache _resourceCache;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates an alert control reflecting the indicated alert + state
|
||||
/// </summary>
|
||||
/// <param name="alert">alert to display</param>
|
||||
/// <param name="severity">severity of alert, null if alert doesn't have severity levels</param>
|
||||
/// <param name="resourceCache">resourceCache to use to load alert icon textures</param>
|
||||
public AlertControl(AlertPrototype alert, short? severity, IResourceCache resourceCache)
|
||||
{
|
||||
_resourceCache = resourceCache;
|
||||
Alert = alert;
|
||||
_severity = severity;
|
||||
var texture = _resourceCache.GetTexture(alert.GetIconPath(_severity));
|
||||
_icon = new TextureRect
|
||||
{
|
||||
TextureScale = (2, 2),
|
||||
Texture = texture
|
||||
};
|
||||
|
||||
Children.Add(_icon);
|
||||
_cooldownGraphic = new CooldownGraphic();
|
||||
Children.Add(_cooldownGraphic);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change the alert severity, changing the displayed icon
|
||||
/// </summary>
|
||||
public void SetSeverity(short? severity)
|
||||
{
|
||||
if (_severity != severity)
|
||||
{
|
||||
_severity = severity;
|
||||
_icon.Texture = _resourceCache.GetTexture(Alert.GetIconPath(_severity));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the displayed cooldown amount, doing nothing if alertCooldown is null
|
||||
/// </summary>
|
||||
/// <param name="alertCooldown">cooldown start and end</param>
|
||||
/// <param name="curTime">current game time</param>
|
||||
public void UpdateCooldown((TimeSpan Start, TimeSpan End)? alertCooldown, in TimeSpan curTime)
|
||||
{
|
||||
if (!alertCooldown.HasValue)
|
||||
{
|
||||
_cooldownGraphic.Progress = 0;
|
||||
_cooldownGraphic.Visible = false;
|
||||
TotalDuration = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var start = alertCooldown.Value.Start;
|
||||
var end = alertCooldown.Value.End;
|
||||
|
||||
var length = (end - start).TotalSeconds;
|
||||
var progress = (curTime - start).TotalSeconds / length;
|
||||
var ratio = (progress <= 1 ? (1 - progress) : (curTime - end).TotalSeconds * -5);
|
||||
|
||||
TotalDuration = (int?) Math.Round(length);
|
||||
_cooldownGraphic.Progress = MathHelper.Clamp((float)ratio, -1, 1);
|
||||
_cooldownGraphic.Visible = ratio > -1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Serilog;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedAlertsComponent))]
|
||||
public sealed class ClientAlertsComponent : SharedAlertsComponent
|
||||
{
|
||||
private static readonly float TooltipTextMaxWidth = 265;
|
||||
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
private AlertsUI _ui;
|
||||
private PanelContainer _tooltip;
|
||||
private RichTextLabel _stateName;
|
||||
private RichTextLabel _stateDescription;
|
||||
private RichTextLabel _stateCooldown;
|
||||
private AlertOrderPrototype _alertOrder;
|
||||
private bool _tooltipReady;
|
||||
|
||||
[ViewVariables]
|
||||
private Dictionary<AlertKey, AlertControl> _alertControls
|
||||
= new Dictionary<AlertKey, AlertControl>();
|
||||
|
||||
/// <summary>
|
||||
/// Allows calculating if we need to act due to this component being controlled by the current mob
|
||||
/// TODO: should be revisited after space-wizards/RobustToolbox#1255
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private bool CurrentlyControlled => _playerManager.LocalPlayer != null && _playerManager.LocalPlayer.ControlledEntity == Owner;
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
PlayerDetached();
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, IComponent component)
|
||||
{
|
||||
base.HandleMessage(message, component);
|
||||
switch (message)
|
||||
{
|
||||
case PlayerAttachedMsg _:
|
||||
PlayerAttached();
|
||||
break;
|
||||
case PlayerDetachedMsg _:
|
||||
PlayerDetached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
|
||||
if (!(curState is AlertsComponentState state))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// update the dict of states based on the array we got in the message
|
||||
SetAlerts(state.Alerts);
|
||||
|
||||
UpdateAlertsControls();
|
||||
}
|
||||
|
||||
private 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<IClyde>());
|
||||
var uiManager = IoCManager.Resolve<IUserInterfaceManager>();
|
||||
uiManager.StateRoot.AddChild(_ui);
|
||||
|
||||
_tooltip = new PanelContainer
|
||||
{
|
||||
Visible = false,
|
||||
StyleClasses = { StyleNano.StyleClassTooltipPanel }
|
||||
};
|
||||
var tooltipVBox = new VBoxContainer
|
||||
{
|
||||
RectClipContent = true
|
||||
};
|
||||
_tooltip.AddChild(tooltipVBox);
|
||||
_stateName = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleNano.StyleClassTooltipAlertTitle }
|
||||
};
|
||||
tooltipVBox.AddChild(_stateName);
|
||||
_stateDescription = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleNano.StyleClassTooltipAlertDescription }
|
||||
};
|
||||
tooltipVBox.AddChild(_stateDescription);
|
||||
_stateCooldown = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleNano.StyleClassTooltipAlertCooldown }
|
||||
};
|
||||
tooltipVBox.AddChild(_stateCooldown);
|
||||
|
||||
uiManager.PopupRoot.AddChild(_tooltip);
|
||||
|
||||
UpdateAlertsControls();
|
||||
}
|
||||
|
||||
private void PlayerDetached()
|
||||
{
|
||||
_ui?.Dispose();
|
||||
_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)
|
||||
{
|
||||
// remove and dispose the control
|
||||
_alertControls.Remove(alertKeyToRemove, out var control);
|
||||
control?.Dispose();
|
||||
}
|
||||
|
||||
// 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 alertStatus in EnumerateAlertStates())
|
||||
{
|
||||
if (!AlertManager.TryDecode(alertStatus.AlertEncoded, out var newAlert))
|
||||
{
|
||||
Logger.ErrorS("alert", "Unable to decode alert {0}", alertStatus.AlertEncoded);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_alertControls.TryGetValue(newAlert.AlertKey, out var existingAlertControl) &&
|
||||
existingAlertControl.Alert.AlertType == newAlert.AlertType)
|
||||
{
|
||||
// id is the same, simply update the existing control severity
|
||||
existingAlertControl.SetSeverity(alertStatus.Severity);
|
||||
}
|
||||
else
|
||||
{
|
||||
existingAlertControl?.Dispose();
|
||||
|
||||
// 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, alertStatus);
|
||||
if (_alertOrder != null)
|
||||
{
|
||||
var added = false;
|
||||
foreach (var alertControl in _ui.Grid.Children)
|
||||
{
|
||||
if (_alertOrder.Compare(newAlert, ((AlertControl) alertControl).Alert) < 0)
|
||||
{
|
||||
var idx = alertControl.GetPositionInParent();
|
||||
_ui.Grid.Children.Add(newAlertControl);
|
||||
newAlertControl.SetPositionInParent(idx);
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!added)
|
||||
{
|
||||
_ui.Grid.Children.Add(newAlertControl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_ui.Grid.Children.Add(newAlertControl);
|
||||
}
|
||||
|
||||
_alertControls[newAlert.AlertKey] = newAlertControl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AlertControl CreateAlertControl(AlertPrototype alert, AlertState alertState)
|
||||
{
|
||||
|
||||
var alertControl = new AlertControl(alert, alertState.Severity, _resourceCache);
|
||||
// show custom tooltip for the status control
|
||||
alertControl.OnShowTooltip += AlertOnOnShowTooltip;
|
||||
alertControl.OnHideTooltip += AlertOnOnHideTooltip;
|
||||
|
||||
alertControl.OnPressed += AlertControlOnPressed;
|
||||
|
||||
return alertControl;
|
||||
}
|
||||
|
||||
private void AlertControlOnPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
AlertPressed(args, args.Button as AlertControl);
|
||||
}
|
||||
|
||||
private void AlertOnOnHideTooltip(object sender, EventArgs e)
|
||||
{
|
||||
_tooltipReady = false;
|
||||
_tooltip.Visible = false;
|
||||
}
|
||||
|
||||
private void AlertOnOnShowTooltip(object sender, EventArgs e)
|
||||
{
|
||||
var alertControl = (AlertControl) sender;
|
||||
_stateName.SetMessage(alertControl.Alert.Name);
|
||||
_stateDescription.SetMessage(alertControl.Alert.Description);
|
||||
// check for a cooldown
|
||||
if (alertControl.TotalDuration != null && alertControl.TotalDuration > 0)
|
||||
{
|
||||
_stateCooldown.SetMessage(FormattedMessage.FromMarkup("[color=#776a6a]" +
|
||||
alertControl.TotalDuration +
|
||||
" sec cooldown[/color]"));
|
||||
_stateCooldown.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stateCooldown.Visible = false;
|
||||
}
|
||||
// TODO: Text display of cooldown
|
||||
Tooltips.PositionTooltip(_tooltip);
|
||||
// if we set it visible here the size of the previous tooltip will flicker for a frame,
|
||||
// so instead we wait until FrameUpdate to make it visible
|
||||
_tooltipReady = true;
|
||||
}
|
||||
|
||||
private void AlertPressed(BaseButton.ButtonEventArgs args, AlertControl alert)
|
||||
{
|
||||
if (args.Event.Function != EngineKeyFunctions.UIClick)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (AlertManager.TryEncode(alert.Alert, out var encoded))
|
||||
{
|
||||
SendNetworkMessage(new ClickAlertMessage(encoded));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.ErrorS("alert", "unable to encode alert {0}", alert.Alert.AlertType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void FrameUpdate(float frameTime)
|
||||
{
|
||||
if (_tooltipReady)
|
||||
{
|
||||
_tooltipReady = false;
|
||||
_tooltip.Visible = true;
|
||||
}
|
||||
foreach (var (alertKey, alertControl) in _alertControls)
|
||||
{
|
||||
// reconcile all alert controls with their current cooldowns
|
||||
if (TryGetAlertState(alertKey, out var alertState))
|
||||
{
|
||||
alertControl.UpdateCooldown(alertState.Cooldown, _gameTiming.CurTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.WarningS("alert", "coding error - no alert state for alert {0} " +
|
||||
"even though we had an AlertControl for it, this" +
|
||||
" should never happen", alertControl.Alert.AlertType);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected override void AfterClearAlert()
|
||||
{
|
||||
UpdateAlertsControls();
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
foreach (var alertControl in _alertControls.Values)
|
||||
{
|
||||
alertControl.OnShowTooltip -= AlertOnOnShowTooltip;
|
||||
alertControl.OnHideTooltip -= AlertOnOnHideTooltip;
|
||||
alertControl.OnPressed -= AlertControlOnPressed;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedStatusEffectsComponent))]
|
||||
public sealed class ClientStatusEffectsComponent : SharedStatusEffectsComponent
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
private StatusEffectsUI _ui;
|
||||
[ViewVariables]
|
||||
private Dictionary<StatusEffect, StatusEffectStatus> _status = new Dictionary<StatusEffect, StatusEffectStatus>();
|
||||
[ViewVariables]
|
||||
private Dictionary<StatusEffect, CooldownGraphic> _cooldown = new Dictionary<StatusEffect, CooldownGraphic>();
|
||||
|
||||
public override IReadOnlyDictionary<StatusEffect, StatusEffectStatus> Statuses => _status;
|
||||
|
||||
/// <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 HandleMessage(ComponentMessage message, IComponent component)
|
||||
{
|
||||
base.HandleMessage(message, component);
|
||||
switch (message)
|
||||
{
|
||||
case PlayerAttachedMsg _:
|
||||
PlayerAttached();
|
||||
break;
|
||||
case PlayerDetachedMsg _:
|
||||
PlayerDetached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
|
||||
if (!(curState is StatusEffectComponentState state) || _status == state.StatusEffects)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_status = state.StatusEffects;
|
||||
UpdateStatusEffects();
|
||||
}
|
||||
|
||||
private void PlayerAttached()
|
||||
{
|
||||
if (!CurrentlyControlled || _ui != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_ui = new StatusEffectsUI();
|
||||
_userInterfaceManager.StateRoot.AddChild(_ui);
|
||||
UpdateStatusEffects();
|
||||
}
|
||||
|
||||
private void PlayerDetached()
|
||||
{
|
||||
_ui?.Dispose();
|
||||
_ui = null;
|
||||
_cooldown.Clear();
|
||||
}
|
||||
|
||||
public override void ChangeStatusEffectIcon(StatusEffect effect, string icon)
|
||||
{
|
||||
if (_status.TryGetValue(effect, out var value) &&
|
||||
value.Icon == icon)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_status[effect] = new StatusEffectStatus
|
||||
{
|
||||
Icon = icon,
|
||||
Cooldown = value.Cooldown
|
||||
};
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void UpdateStatusEffects()
|
||||
{
|
||||
if (!CurrentlyControlled || _ui == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_cooldown.Clear();
|
||||
_ui.VBox.DisposeAllChildren();
|
||||
|
||||
foreach (var (key, effect) in _status.OrderBy(x => (int) x.Key))
|
||||
{
|
||||
var texture = _resourceCache.GetTexture(effect.Icon);
|
||||
var status = new StatusControl(key, texture)
|
||||
{
|
||||
ToolTip = key.ToString()
|
||||
};
|
||||
|
||||
if (effect.Cooldown.HasValue)
|
||||
{
|
||||
var cooldown = new CooldownGraphic();
|
||||
status.Children.Add(cooldown);
|
||||
_cooldown[key] = cooldown;
|
||||
}
|
||||
|
||||
status.OnPressed += args => StatusPressed(args, status);
|
||||
|
||||
_ui.VBox.AddChild(status);
|
||||
}
|
||||
}
|
||||
|
||||
private void StatusPressed(BaseButton.ButtonEventArgs args, StatusControl status)
|
||||
{
|
||||
if (args.Event.Function != EngineKeyFunctions.UIClick)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendNetworkMessage(new ClickStatusMessage(status.Effect));
|
||||
}
|
||||
|
||||
public override void RemoveStatusEffect(StatusEffect effect)
|
||||
{
|
||||
if (!_status.Remove(effect))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateStatusEffects();
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void FrameUpdate(float frameTime)
|
||||
{
|
||||
foreach (var (effect, cooldownGraphic) in _cooldown)
|
||||
{
|
||||
var status = _status[effect];
|
||||
if (!status.Cooldown.HasValue)
|
||||
{
|
||||
cooldownGraphic.Progress = 0;
|
||||
cooldownGraphic.Visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
var start = status.Cooldown.Value.Item1;
|
||||
var end = status.Cooldown.Value.Item2;
|
||||
|
||||
var length = (end - start).TotalSeconds;
|
||||
var progress = (_gameTiming.CurTime - start).TotalSeconds / length;
|
||||
var ratio = (progress <= 1 ? (1 - progress) : (_gameTiming.CurTime - end).TotalSeconds * -5);
|
||||
|
||||
cooldownGraphic.Progress = MathHelper.Clamp((float)ratio, -1, 1);
|
||||
cooldownGraphic.Visible = ratio > -1f;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ChangeStatusEffect(StatusEffect effect, string icon, (TimeSpan, TimeSpan)? cooldown)
|
||||
{
|
||||
_status[effect] = new StatusEffectStatus()
|
||||
{
|
||||
Icon = icon,
|
||||
Cooldown = cooldown
|
||||
};
|
||||
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -39,15 +39,6 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
offset *= (ResetTime - _time) / ResetTime;
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out CameraRecoilComponent recoilComponent))
|
||||
{
|
||||
recoilComponent.BaseOffset = offset;
|
||||
}
|
||||
else if (Owner.TryGetComponent(out EyeComponent eyeComponent))
|
||||
{
|
||||
eyeComponent.Offset = offset;
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out ISpriteComponent spriteComponent))
|
||||
{
|
||||
// We have to account for rotation so the offset still checks out.
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#nullable enable
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
public class StatusControl : BaseButton
|
||||
{
|
||||
public readonly StatusEffect Effect;
|
||||
|
||||
public StatusControl(StatusEffect effect, Texture? texture)
|
||||
{
|
||||
Effect = effect;
|
||||
|
||||
var item = new TextureRect
|
||||
{
|
||||
TextureScale = (2, 2),
|
||||
Texture = texture
|
||||
};
|
||||
|
||||
Children.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,12 +44,14 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
|
||||
if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) return;
|
||||
|
||||
sprite.LayerSetState(
|
||||
CrematoriumVisualLayers.Base,
|
||||
component.GetData<bool>(MorgueVisuals.Open)
|
||||
? _stateOpen
|
||||
: _stateClosed
|
||||
);
|
||||
if (component.TryGetData(MorgueVisuals.Open, out bool open))
|
||||
{
|
||||
sprite.LayerSetState(CrematoriumVisualLayers.Base, open ? _stateOpen : _stateClosed);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.LayerSetState(CrematoriumVisualLayers.Base, _stateClosed);
|
||||
}
|
||||
|
||||
var lightState = "";
|
||||
if (component.TryGetData(MorgueVisuals.HasContents, out bool hasContents) && hasContents) lightState = _lightContents;
|
||||
|
||||
@@ -49,12 +49,14 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
|
||||
if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) return;
|
||||
|
||||
sprite.LayerSetState(
|
||||
MorgueVisualLayers.Base,
|
||||
component.GetData<bool>(MorgueVisuals.Open)
|
||||
? _stateOpen
|
||||
: _stateClosed
|
||||
);
|
||||
if (component.TryGetData(MorgueVisuals.Open, out bool open))
|
||||
{
|
||||
sprite.LayerSetState(MorgueVisualLayers.Base, open ? _stateOpen : _stateClosed);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.LayerSetState(MorgueVisualLayers.Base, _stateClosed);
|
||||
}
|
||||
|
||||
var lightState = "";
|
||||
if (component.TryGetData(MorgueVisuals.HasContents, out bool hasContents) && hasContents) lightState = _lightContents;
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Content.Client.GameObjects.Components.PDA
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
|
||||
private PDAMenu _menu;
|
||||
private PDAMenuPopup failPopup;
|
||||
private PDAMenuPopup _failPopup;
|
||||
|
||||
public PDABoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
@@ -47,6 +47,11 @@ namespace Content.Client.GameObjects.Components.PDA
|
||||
SendMessage(new PDAEjectIDMessage());
|
||||
};
|
||||
|
||||
_menu.EjectPenButton.OnPressed += args =>
|
||||
{
|
||||
SendMessage(new PDAEjectPenMessage());
|
||||
};
|
||||
|
||||
_menu.MasterTabContainer.OnTabChanged += i =>
|
||||
{
|
||||
var tab = _menu.MasterTabContainer.GetChild(i);
|
||||
@@ -60,12 +65,12 @@ namespace Content.Client.GameObjects.Components.PDA
|
||||
{
|
||||
if (_menu.CurrentLoggedInAccount.DataBalance < listing.Price)
|
||||
{
|
||||
failPopup = new PDAMenuPopup(Loc.GetString("Insufficient funds!"));
|
||||
_userInterfaceManager.ModalRoot.AddChild(failPopup);
|
||||
failPopup.Open(UIBox2.FromDimensions(_menu.Position.X + 150, _menu.Position.Y + 60, 156, 24));
|
||||
_failPopup = new PDAMenuPopup(Loc.GetString("Insufficient funds!"));
|
||||
_userInterfaceManager.ModalRoot.AddChild(_failPopup);
|
||||
_failPopup.Open(UIBox2.FromDimensions(_menu.Position.X + 150, _menu.Position.Y + 60, 156, 24));
|
||||
_menu.OnClose += () =>
|
||||
{
|
||||
failPopup.Dispose();
|
||||
_failPopup.Dispose();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -106,6 +111,7 @@ namespace Content.Client.GameObjects.Components.PDA
|
||||
}
|
||||
|
||||
_menu.EjectIDButton.Visible = msg.PDAOwnerInfo.IdOwner != null;
|
||||
_menu.EjectPenButton.Visible = msg.HasPen;
|
||||
if (msg.Account != null)
|
||||
{
|
||||
_menu.CurrentLoggedInAccount = msg.Account;
|
||||
@@ -220,6 +226,7 @@ namespace Content.Client.GameObjects.Components.PDA
|
||||
|
||||
public Button FlashLightToggleButton { get; }
|
||||
public Button EjectIDButton { get; }
|
||||
public Button EjectPenButton { get; }
|
||||
|
||||
public TabContainer MasterTabContainer;
|
||||
|
||||
@@ -288,13 +295,20 @@ namespace Content.Client.GameObjects.Components.PDA
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter
|
||||
};
|
||||
EjectPenButton = new Button
|
||||
{
|
||||
Text = Loc.GetString("Eject Pen"),
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter
|
||||
};
|
||||
|
||||
var innerHBoxContainer = new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
IDInfoLabel,
|
||||
EjectIDButton
|
||||
EjectIDButton,
|
||||
EjectPenButton
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Shared.AI;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
@@ -178,7 +179,7 @@ namespace Content.Client.GameObjects.EntitySystems.AI
|
||||
|
||||
var panel = new PanelContainer
|
||||
{
|
||||
StyleClasses = {"tooltipBox"},
|
||||
StyleClasses = { StyleNano.StyleClassTooltipPanel },
|
||||
Children = {vBox},
|
||||
MouseFilter = Control.MouseFilterMode.Ignore,
|
||||
ModulateSelfOverride = Color.White.WithAlpha(0.75f),
|
||||
|
||||
@@ -5,7 +5,7 @@ using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Client.GameObjects.EntitySystems
|
||||
{
|
||||
public class StatusEffectsSystem : EntitySystem
|
||||
public class AlertsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
@@ -16,9 +16,9 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
if (!_gameTiming.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
foreach (var clientStatusEffectsComponent in EntityManager.ComponentManager.EntityQuery<ClientStatusEffectsComponent>())
|
||||
foreach (var clientAlertsComponent in EntityManager.ComponentManager.EntityQuery<ClientAlertsComponent>())
|
||||
{
|
||||
clientStatusEffectsComponent.FrameUpdate(frameTime);
|
||||
clientAlertsComponent.FrameUpdate(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,9 +70,6 @@ namespace Content.Client.GameObjects.EntitySystems.DoAfter
|
||||
private const int XPixelDiff = 20 * DoAfterBarScale;
|
||||
|
||||
public const byte DoAfterBarScale = 2;
|
||||
private static readonly Color StartColor = new Color(0.8f, 0.0f, 0.2f); // red
|
||||
private static readonly Color EndColor = new Color(0.92f, 0.77f, 0.34f); // yellow
|
||||
private static readonly Color CompletedColor = new Color(0.0f, 0.8f, 0.27f); // green
|
||||
|
||||
public DoAfterBar()
|
||||
{
|
||||
@@ -111,16 +108,13 @@ namespace Content.Client.GameObjects.EntitySystems.DoAfter
|
||||
}
|
||||
else if (Ratio >= 1.0f)
|
||||
{
|
||||
color = CompletedColor;
|
||||
color = new Color(0f, 1f, 0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// lerp
|
||||
color = new Color(
|
||||
StartColor.R + (EndColor.R - StartColor.R) * Ratio,
|
||||
StartColor.G + (EndColor.G - StartColor.G) * Ratio,
|
||||
StartColor.B + (EndColor.B - StartColor.B) * Ratio,
|
||||
StartColor.A);
|
||||
var hue = (5f / 18f) * Ratio;
|
||||
color = Color.FromHsv((hue, 1f, 0.75f, 1f));
|
||||
}
|
||||
|
||||
handle.UseShader(_shader);
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
"Drink",
|
||||
"Food",
|
||||
"FoodContainer",
|
||||
"Stomach",
|
||||
"Rotatable",
|
||||
"MagicMirror",
|
||||
"FloorTile",
|
||||
@@ -180,10 +179,8 @@
|
||||
"BreakableConstruction",
|
||||
"GasCanister",
|
||||
"GasCanisterPort",
|
||||
"Lung",
|
||||
"Cleanable",
|
||||
"Configuration",
|
||||
"Brain",
|
||||
"PlantHolder",
|
||||
"SeedExtractor",
|
||||
"Produce",
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Client.Interfaces.Parallax;
|
||||
using Content.Shared;
|
||||
using Nett;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
@@ -34,12 +35,12 @@ namespace Content.Client.Parallax
|
||||
|
||||
public async void LoadParallax()
|
||||
{
|
||||
if (!_configurationManager.GetCVar<bool>("parallax.enabled"))
|
||||
if (!_configurationManager.GetCVar(CCVars.ParallaxEnabled))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var debugParallax = _configurationManager.GetCVar<bool>("parallax.debug");
|
||||
var debugParallax = _configurationManager.GetCVar(CCVars.ParallaxDebug);
|
||||
string contents;
|
||||
TomlTable table;
|
||||
// Load normal config into memory
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace Content.Client.Sandbox
|
||||
public Button ToggleSubfloorButton;
|
||||
public Button ShowMarkersButton; //Shows spawn points
|
||||
public Button ShowBbButton; //Shows bounding boxes
|
||||
public Button MachineLinkingButton; // Enables/disables machine linking mode.
|
||||
|
||||
public SandboxWindow()
|
||||
{
|
||||
@@ -77,6 +78,9 @@ namespace Content.Client.Sandbox
|
||||
|
||||
ShowBbButton = new Button { Text = Loc.GetString("Show Bb"), ToggleMode = true };
|
||||
vBox.AddChild(ShowBbButton);
|
||||
|
||||
MachineLinkingButton = new Button { Text = Loc.GetString("Link machines"), ToggleMode = true };
|
||||
vBox.AddChild(MachineLinkingButton);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,6 +190,7 @@ namespace Content.Client.Sandbox
|
||||
_window.ToggleSubfloorButton.OnPressed += OnToggleSubfloorButtonClicked;
|
||||
_window.ShowMarkersButton.OnPressed += OnShowMarkersButtonClicked;
|
||||
_window.ShowBbButton.OnPressed += OnShowBbButtonClicked;
|
||||
_window.MachineLinkingButton.OnPressed += OnMachineLinkingButtonClicked;
|
||||
|
||||
_window.OpenCentered();
|
||||
}
|
||||
@@ -241,6 +246,10 @@ namespace Content.Client.Sandbox
|
||||
{
|
||||
ShowBb();
|
||||
}
|
||||
private void OnMachineLinkingButtonClicked(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
LinkMachines();
|
||||
}
|
||||
|
||||
private void OnGiveAdminAccessButtonClicked(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
@@ -318,5 +327,10 @@ namespace Content.Client.Sandbox
|
||||
{
|
||||
_console.ProcessCommand("showbb");
|
||||
}
|
||||
|
||||
private void LinkMachines()
|
||||
{
|
||||
_console.ProcessCommand("signallink");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.Components;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.Interfaces.GameObjects;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
@@ -71,7 +72,7 @@ namespace Content.Client.State
|
||||
}
|
||||
|
||||
InteractionOutlineComponent outline;
|
||||
if(!ConfigurationManager.GetCVar<bool>("outline.enabled"))
|
||||
if(!ConfigurationManager.GetCVar(CCVars.OutlineEnabled))
|
||||
{
|
||||
if(entityToClick != null && entityToClick.TryGetComponent(out outline))
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -111,10 +112,10 @@ namespace Content.Client.State
|
||||
return;
|
||||
}
|
||||
|
||||
var configName = _configurationManager.GetCVar<string>("player.name");
|
||||
var configName = _configurationManager.GetCVar(CVars.PlayerName);
|
||||
if (_mainMenuControl.UserNameBox.Text != configName)
|
||||
{
|
||||
_configurationManager.SetCVar("player.name", inputName);
|
||||
_configurationManager.SetCVar(CVars.PlayerName, inputName);
|
||||
_configurationManager.SaveToFile();
|
||||
}
|
||||
|
||||
@@ -248,7 +249,7 @@ namespace Content.Client.State
|
||||
vBox.AddChild(userNameHBox);
|
||||
userNameHBox.AddChild(new Label {Text = "Username:"});
|
||||
|
||||
var currentUserName = _configurationManager.GetCVar<string>("player.name");
|
||||
var currentUserName = _configurationManager.GetCVar(CVars.PlayerName);
|
||||
UserNameBox = new LineEdit
|
||||
{
|
||||
Text = currentUserName, PlaceHolder = "Username",
|
||||
|
||||
73
Content.Client/UserInterface/AlertsUI.cs
Normal file
73
Content.Client/UserInterface/AlertsUI.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.UserInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// The status effects display on the right side of the screen.
|
||||
/// </summary>
|
||||
public sealed class AlertsUI : Control
|
||||
{
|
||||
public GridContainer Grid { get; }
|
||||
|
||||
private readonly IClyde _clyde;
|
||||
|
||||
public AlertsUI(IClyde clyde)
|
||||
{
|
||||
_clyde = clyde;
|
||||
var panelContainer = new PanelContainer
|
||||
{
|
||||
StyleClasses = {StyleNano.StyleClassTransparentBorderedWindowPanel},
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
};
|
||||
AddChild(panelContainer);
|
||||
|
||||
Grid = new GridContainer
|
||||
{
|
||||
MaxHeight = CalcMaxHeight(clyde.ScreenSize),
|
||||
ExpandBackwards = true
|
||||
};
|
||||
panelContainer.AddChild(Grid);
|
||||
clyde.OnWindowResized += ClydeOnOnWindowResized;
|
||||
|
||||
LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.Begin);
|
||||
LayoutContainer.SetAnchorAndMarginPreset(this, LayoutContainer.LayoutPreset.TopRight, margin: 10);
|
||||
LayoutContainer.SetMarginTop(this, 250);
|
||||
}
|
||||
|
||||
protected override void UIScaleChanged()
|
||||
{
|
||||
Grid.MaxHeight = CalcMaxHeight(_clyde.ScreenSize);
|
||||
base.UIScaleChanged();
|
||||
}
|
||||
|
||||
private void ClydeOnOnWindowResized(WindowResizedEventArgs obj)
|
||||
{
|
||||
// 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
|
||||
Grid.MaxHeight = CalcMaxHeight(obj.NewSize);;
|
||||
}
|
||||
|
||||
private float CalcMaxHeight(Vector2i screenSize)
|
||||
{
|
||||
return Math.Max(((screenSize.Y) / UIScale) - 420, 1);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_clyde.OnWindowResized -= ClydeOnOnWindowResized;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ namespace Content.Client.UserInterface
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = StyleNano.NanoGold},
|
||||
CustomMinimumSize = (2, 0)
|
||||
});
|
||||
_humanoidProfileEditor = new HumanoidProfileEditor(preferencesManager, prototypeManager);
|
||||
_humanoidProfileEditor = new HumanoidProfileEditor(preferencesManager, prototypeManager, entityManager);
|
||||
_humanoidProfileEditor.OnProfileChanged += newProfile => { UpdateUI(); };
|
||||
hBox.AddChild(_humanoidProfileEditor);
|
||||
|
||||
@@ -158,6 +158,15 @@ namespace Content.Client.UserInterface
|
||||
preferencesManager.OnServerDataLoaded += UpdateUI;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
_preferencesManager.OnServerDataLoaded -= UpdateUI;
|
||||
}
|
||||
|
||||
public void Save() => _humanoidProfileEditor.Save();
|
||||
|
||||
private void UpdateUI()
|
||||
@@ -283,7 +292,9 @@ namespace Content.Client.UserInterface
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
_previewDummy.Delete();
|
||||
_previewDummy = null;
|
||||
}
|
||||
|
||||
@@ -27,29 +27,23 @@ namespace Content.Client.UserInterface
|
||||
/// Possible values range from 1 to -1, where 1 to 0 is a depleting circle animation and 0 to -1 is a blink animation.
|
||||
/// </summary>
|
||||
public float Progress { get; set; }
|
||||
private static readonly Color StartColor = new Color(0.8f, 0.0f, 0.2f); // red
|
||||
private static readonly Color EndColor = new Color(0.92f, 0.77f, 0.34f); // yellow
|
||||
private static readonly Color CompletedColor = new Color(0.0f, 0.8f, 0.27f); // green
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
Span<float> x = stackalloc float[10];
|
||||
Span<float> x = new float[10];
|
||||
Color color;
|
||||
|
||||
var lerp = 1f - MathF.Abs(Progress); // for future bikeshedding purposes
|
||||
|
||||
if (Progress >= 0f)
|
||||
{
|
||||
color = new Color(
|
||||
EndColor.R + (StartColor.R - EndColor.R) * Progress,
|
||||
EndColor.G + (StartColor.G - EndColor.G) * Progress,
|
||||
EndColor.B + (StartColor.B - EndColor.B) * Progress,
|
||||
EndColor.A);
|
||||
var hue = (5f / 18f) * lerp;
|
||||
color = Color.FromHsv((hue, 0.75f, 0.75f, 0.50f));
|
||||
}
|
||||
else
|
||||
{
|
||||
var alpha = MathHelper.Clamp(0.5f * lerp, 0f, 0.5f);
|
||||
color = CompletedColor.WithAlpha(alpha);
|
||||
color = new Color(1f, 1f, 1f, alpha);
|
||||
}
|
||||
|
||||
_shader.SetParameter("progress", Progress);
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.Components;
|
||||
using Content.Client.GameObjects.Components;
|
||||
using Content.Client.GameObjects.Components.Mobs;
|
||||
using Content.Client.Interfaces;
|
||||
using Content.Shared;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Client.UserInterface
|
||||
{
|
||||
@@ -43,17 +46,25 @@ namespace Content.Client.UserInterface
|
||||
private readonly OptionButton _preferenceUnavailableButton;
|
||||
private readonly List<AntagPreferenceSelector> _antagPreferences;
|
||||
|
||||
private readonly IEntity _previewDummy;
|
||||
private readonly SpriteView _previewSprite;
|
||||
private readonly SpriteView _previewSpriteSide;
|
||||
|
||||
private bool _isDirty;
|
||||
public int CharacterSlot;
|
||||
public HumanoidCharacterProfile Profile;
|
||||
public event Action<HumanoidCharacterProfile> OnProfileChanged;
|
||||
|
||||
public HumanoidProfileEditor(IClientPreferencesManager preferencesManager, IPrototypeManager prototypeManager)
|
||||
public HumanoidProfileEditor(IClientPreferencesManager preferencesManager, IPrototypeManager prototypeManager, IEntityManager entityManager)
|
||||
{
|
||||
_random = IoCManager.Resolve<IRobustRandom>();
|
||||
|
||||
_preferencesManager = preferencesManager;
|
||||
|
||||
var hbox = new HBoxContainer();
|
||||
AddChild(hbox);
|
||||
|
||||
#region Left
|
||||
var margin = new MarginContainer
|
||||
{
|
||||
MarginTopOverride = 10,
|
||||
@@ -61,7 +72,7 @@ namespace Content.Client.UserInterface
|
||||
MarginLeftOverride = 10,
|
||||
MarginRightOverride = 10
|
||||
};
|
||||
AddChild(margin);
|
||||
hbox.AddChild(margin);
|
||||
|
||||
var vBox = new VBoxContainer();
|
||||
margin.AddChild(vBox);
|
||||
@@ -410,6 +421,71 @@ namespace Content.Client.UserInterface
|
||||
|
||||
#endregion Save
|
||||
|
||||
#endregion
|
||||
|
||||
#region Right
|
||||
|
||||
margin = new MarginContainer
|
||||
{
|
||||
MarginTopOverride = 10,
|
||||
MarginBottomOverride = 10,
|
||||
MarginLeftOverride = 10,
|
||||
MarginRightOverride = 10
|
||||
};
|
||||
hbox.AddChild(margin);
|
||||
|
||||
vBox = new VBoxContainer()
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
};
|
||||
hbox.AddChild(vBox);
|
||||
|
||||
#region Preview
|
||||
|
||||
_previewDummy = entityManager.SpawnEntity("HumanMob_Dummy", MapCoordinates.Nullspace);
|
||||
var sprite = _previewDummy.GetComponent<SpriteComponent>();
|
||||
|
||||
// Front
|
||||
var box = new Control()
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.Fill,
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsStretchRatio = 1f,
|
||||
};
|
||||
vBox.AddChild(box);
|
||||
_previewSprite = new SpriteView
|
||||
{
|
||||
Sprite = sprite,
|
||||
Scale = (6, 6),
|
||||
OverrideDirection = Direction.South,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsStretchRatio = 1
|
||||
};
|
||||
box.AddChild(_previewSprite);
|
||||
|
||||
// Side
|
||||
box = new Control()
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.Fill,
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsStretchRatio = 1f,
|
||||
};
|
||||
vBox.AddChild(box);
|
||||
_previewSpriteSide = new SpriteView
|
||||
{
|
||||
Sprite = sprite,
|
||||
Scale = (6, 6),
|
||||
OverrideDirection = Direction.East,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsStretchRatio = 1
|
||||
};
|
||||
box.AddChild(_previewSpriteSide);
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
if (preferencesManager.ServerDataLoaded)
|
||||
{
|
||||
LoadServerData();
|
||||
@@ -420,6 +496,16 @@ namespace Content.Client.UserInterface
|
||||
IsDirty = false;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
_previewDummy.Delete();
|
||||
_preferencesManager.OnServerDataLoaded -= LoadServerData;
|
||||
}
|
||||
|
||||
private void LoadServerData()
|
||||
{
|
||||
Profile = (HumanoidCharacterProfile) _preferencesManager.Preferences.SelectedCharacter;
|
||||
@@ -458,6 +544,7 @@ namespace Content.Client.UserInterface
|
||||
set
|
||||
{
|
||||
_isDirty = value;
|
||||
UpdatePreview();
|
||||
UpdateSaveButton();
|
||||
}
|
||||
}
|
||||
@@ -503,6 +590,15 @@ namespace Content.Client.UserInterface
|
||||
_saveButton.Disabled = Profile is null || !IsDirty;
|
||||
}
|
||||
|
||||
private void UpdatePreview()
|
||||
{
|
||||
if (Profile is null)
|
||||
return;
|
||||
|
||||
_previewDummy.GetComponent<HumanoidAppearanceComponent>().UpdateFromProfile(Profile);
|
||||
LobbyCharacterPreviewPanel.GiveDummyJobClothes(_previewDummy, Profile);
|
||||
}
|
||||
|
||||
public void UpdateControls()
|
||||
{
|
||||
if (Profile is null) return;
|
||||
@@ -514,6 +610,8 @@ namespace Content.Client.UserInterface
|
||||
UpdateJobPriorities();
|
||||
UpdateAntagPreferences();
|
||||
|
||||
UpdatePreview();
|
||||
|
||||
_preferenceUnavailableButton.SelectId((int) Profile.PreferenceUnavailable);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Robust.Client.Graphics;
|
||||
using Content.Shared;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
@@ -121,7 +123,7 @@ namespace Content.Client.UserInterface
|
||||
});
|
||||
ApplyButton.OnPressed += OnApplyButtonPressed;
|
||||
|
||||
VSyncCheckBox.Pressed = _cfg.GetCVar<bool>("display.vsync");
|
||||
VSyncCheckBox.Pressed = _cfg.GetCVar(CVars.DisplayVSync);
|
||||
FullscreenCheckBox.Pressed = ConfigIsFullscreen;
|
||||
LightingPresetOption.SelectId(GetConfigLightingQuality());
|
||||
_uiScaleOption.SelectId(GetConfigUIScalePreset(ConfigUIScale));
|
||||
@@ -137,11 +139,11 @@ namespace Content.Client.UserInterface
|
||||
|
||||
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
_cfg.SetCVar("display.vsync", VSyncCheckBox.Pressed);
|
||||
_cfg.SetCVar(CVars.DisplayVSync, VSyncCheckBox.Pressed);
|
||||
SetConfigLightingQuality(LightingPresetOption.SelectedId);
|
||||
_cfg.SetCVar("display.windowmode",
|
||||
_cfg.SetCVar(CVars.DisplayWindowMode,
|
||||
(int) (FullscreenCheckBox.Pressed ? WindowMode.Fullscreen : WindowMode.Windowed));
|
||||
_cfg.SetCVar("display.uiScale", UIScaleOptions[_uiScaleOption.SelectedId]);
|
||||
_cfg.SetCVar(CVars.DisplayUIScale, UIScaleOptions[_uiScaleOption.SelectedId]);
|
||||
_cfg.SaveToFile();
|
||||
UpdateApplyButton();
|
||||
}
|
||||
@@ -159,7 +161,7 @@ namespace Content.Client.UserInterface
|
||||
|
||||
private void UpdateApplyButton()
|
||||
{
|
||||
var isVSyncSame = VSyncCheckBox.Pressed == _cfg.GetCVar<bool>("display.vsync");
|
||||
var isVSyncSame = VSyncCheckBox.Pressed == _cfg.GetCVar(CVars.DisplayVSync);
|
||||
var isFullscreenSame = FullscreenCheckBox.Pressed == ConfigIsFullscreen;
|
||||
var isLightingQualitySame = LightingPresetOption.SelectedId == GetConfigLightingQuality();
|
||||
var isUIScaleSame = MathHelper.CloseTo(UIScaleOptions[_uiScaleOption.SelectedId], ConfigUIScale);
|
||||
@@ -167,14 +169,14 @@ namespace Content.Client.UserInterface
|
||||
}
|
||||
|
||||
private bool ConfigIsFullscreen =>
|
||||
_cfg.GetCVar<int>("display.windowmode") == (int) WindowMode.Fullscreen;
|
||||
_cfg.GetCVar(CVars.DisplayWindowMode) == (int) WindowMode.Fullscreen;
|
||||
|
||||
private float ConfigUIScale => _cfg.GetCVar<float>("display.uiScale");
|
||||
private float ConfigUIScale => _cfg.GetCVar(CVars.DisplayUIScale);
|
||||
|
||||
private int GetConfigLightingQuality()
|
||||
{
|
||||
var val = _cfg.GetCVar<int>("display.lightmapdivider");
|
||||
var soft = _cfg.GetCVar<bool>("display.softshadows");
|
||||
var val = _cfg.GetCVar(CVars.DisplayLightMapDivider);
|
||||
var soft = _cfg.GetCVar(CVars.DisplaySoftShadows);
|
||||
if (val >= 8)
|
||||
{
|
||||
return 0;
|
||||
@@ -198,20 +200,20 @@ namespace Content.Client.UserInterface
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
_cfg.SetCVar("display.lightmapdivider", 8);
|
||||
_cfg.SetCVar("display.softshadows", false);
|
||||
_cfg.SetCVar(CVars.DisplayLightMapDivider, 8);
|
||||
_cfg.SetCVar(CVars.DisplaySoftShadows, false);
|
||||
break;
|
||||
case 1:
|
||||
_cfg.SetCVar("display.lightmapdivider", 2);
|
||||
_cfg.SetCVar("display.softshadows", false);
|
||||
_cfg.SetCVar(CVars.DisplayLightMapDivider, 2);
|
||||
_cfg.SetCVar(CVars.DisplaySoftShadows, false);
|
||||
break;
|
||||
case 2:
|
||||
_cfg.SetCVar("display.lightmapdivider", 2);
|
||||
_cfg.SetCVar("display.softshadows", true);
|
||||
_cfg.SetCVar(CVars.DisplayLightMapDivider, 2);
|
||||
_cfg.SetCVar(CVars.DisplaySoftShadows, true);
|
||||
break;
|
||||
case 3:
|
||||
_cfg.SetCVar("display.lightmapdivider", 1);
|
||||
_cfg.SetCVar("display.softshadows", true);
|
||||
_cfg.SetCVar(CVars.DisplayLightMapDivider, 1);
|
||||
_cfg.SetCVar(CVars.DisplaySoftShadows, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Content.Client.UserInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// The status effects display on the right side of the screen.
|
||||
/// </summary>
|
||||
public sealed class StatusEffectsUI : Control
|
||||
{
|
||||
public VBoxContainer VBox { get; }
|
||||
|
||||
public StatusEffectsUI()
|
||||
{
|
||||
VBox = new VBoxContainer();
|
||||
AddChild(VBox);
|
||||
|
||||
LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.Begin);
|
||||
LayoutContainer.SetAnchorAndMarginPreset(this, LayoutContainer.LayoutPreset.TopRight, margin: 10);
|
||||
LayoutContainer.SetMarginTop(this, 250);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,13 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
{
|
||||
public sealed class StyleNano : StyleBase
|
||||
{
|
||||
public const string StyleClassBorderedWindowPanel = "BorderedWindowPanel";
|
||||
public const string StyleClassTransparentBorderedWindowPanel = "TransparentBorderedWindowPanel";
|
||||
public const string StyleClassTooltipPanel = "tooltipBox";
|
||||
public const string StyleClassTooltipAlertTitle = "tooltipAlertTitle";
|
||||
public const string StyleClassTooltipAlertDescription = "tooltipAlertDesc";
|
||||
public const string StyleClassTooltipAlertCooldown = "tooltipAlertCooldown";
|
||||
|
||||
public const string StyleClassSliderRed = "Red";
|
||||
public const string StyleClassSliderGreen = "Green";
|
||||
public const string StyleClassSliderBlue = "Blue";
|
||||
@@ -55,6 +62,7 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
var notoSansDisplayBold14 = resCache.GetFont("/Fonts/NotoSansDisplay/NotoSansDisplay-Bold.ttf", 14);
|
||||
var notoSans16 = resCache.GetFont("/Fonts/NotoSans/NotoSans-Regular.ttf", 16);
|
||||
var notoSansBold16 = resCache.GetFont("/Fonts/NotoSans/NotoSans-Bold.ttf", 16);
|
||||
var notoSansBold18 = resCache.GetFont("/Fonts/NotoSans/NotoSans-Bold.ttf", 18);
|
||||
var notoSansBold20 = resCache.GetFont("/Fonts/NotoSans/NotoSans-Bold.ttf", 20);
|
||||
var textureCloseButton = resCache.GetTexture("/Textures/Interface/Nano/cross.svg.png");
|
||||
var windowHeaderTex = resCache.GetTexture("/Textures/Interface/Nano/window_header.png");
|
||||
@@ -73,6 +81,20 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
windowBackground.SetPatchMargin(StyleBox.Margin.Horizontal | StyleBox.Margin.Bottom, 2);
|
||||
windowBackground.SetExpandMargin(StyleBox.Margin.Horizontal | StyleBox.Margin.Bottom, 2);
|
||||
|
||||
var borderedWindowBackgroundTex = resCache.GetTexture("/Textures/Interface/Nano/window_background_bordered.png");
|
||||
var borderedWindowBackground = new StyleBoxTexture
|
||||
{
|
||||
Texture = borderedWindowBackgroundTex,
|
||||
};
|
||||
borderedWindowBackground.SetPatchMargin(StyleBox.Margin.All, 2);
|
||||
|
||||
var borderedTransparentWindowBackgroundTex = resCache.GetTexture("/Textures/Interface/Nano/transparent_window_background_bordered.png");
|
||||
var borderedTransparentWindowBackground = new StyleBoxTexture
|
||||
{
|
||||
Texture = borderedTransparentWindowBackgroundTex,
|
||||
};
|
||||
borderedTransparentWindowBackground.SetPatchMargin(StyleBox.Margin.All, 2);
|
||||
|
||||
var textureInvertedTriangle = resCache.GetTexture("/Textures/Interface/Nano/inverted_triangle.svg.png");
|
||||
|
||||
var lineEditTex = resCache.GetTexture("/Textures/Interface/Nano/lineedit.png");
|
||||
@@ -147,7 +169,7 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
Texture = tooltipTexture,
|
||||
};
|
||||
tooltipBox.SetPatchMargin(StyleBox.Margin.All, 2);
|
||||
tooltipBox.SetContentMarginOverride(StyleBox.Margin.Horizontal, 5);
|
||||
tooltipBox.SetContentMarginOverride(StyleBox.Margin.Horizontal, 7);
|
||||
|
||||
// Placeholder
|
||||
var placeholderTexture = resCache.GetTexture("/Textures/Interface/Nano/placeholder.png");
|
||||
@@ -245,6 +267,19 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
{
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, windowBackground),
|
||||
}),
|
||||
// bordered window background
|
||||
new StyleRule(
|
||||
new SelectorElement(null, new[] {StyleClassBorderedWindowPanel}, null, null),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, borderedWindowBackground),
|
||||
}),
|
||||
new StyleRule(
|
||||
new SelectorElement(null, new[] {StyleClassTransparentBorderedWindowPanel}, null, null),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, borderedTransparentWindowBackground),
|
||||
}),
|
||||
// Window header.
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(PanelContainer), new[] {SS14Window.StyleClassWindowHeader}, null, null),
|
||||
@@ -464,7 +499,7 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox)
|
||||
}),
|
||||
|
||||
new StyleRule(new SelectorElement(typeof(PanelContainer), new[] {"tooltipBox"}, null, null), new[]
|
||||
new StyleRule(new SelectorElement(typeof(PanelContainer), new [] { StyleClassTooltipPanel }, null, null), new[]
|
||||
{
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox)
|
||||
}),
|
||||
@@ -482,6 +517,20 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
new StyleProperty("font", notoSansItalic12),
|
||||
}),
|
||||
|
||||
// alert tooltip
|
||||
new StyleRule(new SelectorElement(typeof(RichTextLabel), new[] {StyleClassTooltipAlertTitle}, null, null), new[]
|
||||
{
|
||||
new StyleProperty("font", notoSansBold18)
|
||||
}),
|
||||
new StyleRule(new SelectorElement(typeof(RichTextLabel), new[] {StyleClassTooltipAlertDescription}, null, null), new[]
|
||||
{
|
||||
new StyleProperty("font", notoSans16)
|
||||
}),
|
||||
new StyleRule(new SelectorElement(typeof(RichTextLabel), new[] {StyleClassTooltipAlertCooldown}, null, null), new[]
|
||||
{
|
||||
new StyleProperty("font", notoSans16)
|
||||
}),
|
||||
|
||||
// Entity tooltip
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(PanelContainer), new[] {ExamineSystem.StyleClassEntityTooltip}, null,
|
||||
|
||||
@@ -20,7 +20,7 @@ using Robust.Shared.Maths;
|
||||
namespace Content.IntegrationTests.Tests.Body
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(LungBehaviorComponent))]
|
||||
[TestOf(typeof(LungBehavior))]
|
||||
public class LungTest : ContentIntegrationTest
|
||||
{
|
||||
[Test]
|
||||
@@ -39,7 +39,7 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
var human = entityManager.SpawnEntity("HumanMob_Content", MapCoordinates.Nullspace);
|
||||
|
||||
Assert.That(human.TryGetComponent(out IBody body));
|
||||
Assert.That(body.TryGetMechanismBehaviors(out List<LungBehaviorComponent> lungs));
|
||||
Assert.That(body.TryGetMechanismBehaviors(out List<LungBehavior> lungs));
|
||||
Assert.That(lungs.Count, Is.EqualTo(1));
|
||||
Assert.That(human.TryGetComponent(out BloodstreamComponent bloodstream));
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
human = entityManager.SpawnEntity("HumanMob_Content", coordinates);
|
||||
|
||||
Assert.True(human.TryGetComponent(out IBody body));
|
||||
Assert.True(body.HasMechanismBehavior<LungBehaviorComponent>());
|
||||
Assert.True(body.HasMechanismBehavior<LungBehavior>());
|
||||
Assert.True(human.TryGetComponent(out metabolism));
|
||||
Assert.False(metabolism.Suffocating);
|
||||
});
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#nullable enable
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects.Components.Body.Behavior;
|
||||
using Content.Shared.GameObjects.Components.Body;
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Content.Shared.GameObjects.Components.Body.Mechanism;
|
||||
using Content.Shared.GameObjects.Components.Body.Part;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -18,14 +18,11 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
[TestOf(typeof(SharedBodyComponent))]
|
||||
[TestOf(typeof(SharedBodyPartComponent))]
|
||||
[TestOf(typeof(SharedMechanismComponent))]
|
||||
[TestOf(typeof(MechanismBehaviorComponent))]
|
||||
[TestOf(typeof(MechanismBehavior))]
|
||||
public class MechanismBehaviorEventsTest : ContentIntegrationTest
|
||||
{
|
||||
[RegisterComponent]
|
||||
private class TestBehaviorComponent : MechanismBehaviorComponent
|
||||
private class TestMechanismBehavior : MechanismBehavior
|
||||
{
|
||||
public override string Name => nameof(MechanismBehaviorEventsTest) + "TestBehavior";
|
||||
|
||||
public bool WasAddedToBody;
|
||||
public bool WasAddedToPart;
|
||||
public bool WasAddedToPartInBody;
|
||||
@@ -33,8 +30,6 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
public bool WasRemovedFromPart;
|
||||
public bool WasRemovedFromPartInBody;
|
||||
|
||||
public override void Update(float frameTime) { }
|
||||
|
||||
public bool NoAdded()
|
||||
{
|
||||
return !WasAddedToBody && !WasAddedToPart && !WasAddedToPartInBody;
|
||||
@@ -111,13 +106,7 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
[Test]
|
||||
public async Task EventsTest()
|
||||
{
|
||||
var server = StartServerDummyTicker(new ServerContentIntegrationOption
|
||||
{
|
||||
ContentBeforeIoC = () =>
|
||||
{
|
||||
IoCManager.Resolve<IComponentFactory>().Register<TestBehaviorComponent>();
|
||||
}
|
||||
});
|
||||
var server = StartServerDummyTicker();
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
@@ -141,68 +130,68 @@ namespace Content.IntegrationTests.Tests.Body
|
||||
var mechanism = centerPart!.Mechanisms.First();
|
||||
Assert.NotNull(mechanism);
|
||||
|
||||
var component = mechanism.Owner.AddComponent<TestBehaviorComponent>();
|
||||
Assert.False(component.WasAddedToBody);
|
||||
Assert.False(component.WasAddedToPart);
|
||||
Assert.That(component.WasAddedToPartInBody);
|
||||
Assert.That(component.NoRemoved);
|
||||
mechanism.EnsureBehavior<TestMechanismBehavior>(out var behavior);
|
||||
Assert.False(behavior.WasAddedToBody);
|
||||
Assert.False(behavior.WasAddedToPart);
|
||||
Assert.That(behavior.WasAddedToPartInBody);
|
||||
Assert.That(behavior.NoRemoved);
|
||||
|
||||
component.ResetAll();
|
||||
behavior.ResetAll();
|
||||
|
||||
Assert.That(component.NoAdded);
|
||||
Assert.That(component.NoRemoved);
|
||||
Assert.That(behavior.NoAdded);
|
||||
Assert.That(behavior.NoRemoved);
|
||||
|
||||
centerPart.RemoveMechanism(mechanism);
|
||||
|
||||
Assert.That(component.NoAdded);
|
||||
Assert.False(component.WasRemovedFromBody);
|
||||
Assert.False(component.WasRemovedFromPart);
|
||||
Assert.That(component.WasRemovedFromPartInBody);
|
||||
Assert.That(behavior.NoAdded);
|
||||
Assert.False(behavior.WasRemovedFromBody);
|
||||
Assert.False(behavior.WasRemovedFromPart);
|
||||
Assert.That(behavior.WasRemovedFromPartInBody);
|
||||
|
||||
component.ResetAll();
|
||||
behavior.ResetAll();
|
||||
|
||||
centerPart.TryAddMechanism(mechanism, true);
|
||||
|
||||
Assert.False(component.WasAddedToBody);
|
||||
Assert.False(component.WasAddedToPart);
|
||||
Assert.That(component.WasAddedToPartInBody);
|
||||
Assert.That(component.NoRemoved());
|
||||
Assert.False(behavior.WasAddedToBody);
|
||||
Assert.False(behavior.WasAddedToPart);
|
||||
Assert.That(behavior.WasAddedToPartInBody);
|
||||
Assert.That(behavior.NoRemoved());
|
||||
|
||||
component.ResetAll();
|
||||
behavior.ResetAll();
|
||||
|
||||
body.RemovePart(centerPart);
|
||||
|
||||
Assert.That(component.NoAdded);
|
||||
Assert.That(component.WasRemovedFromBody);
|
||||
Assert.False(component.WasRemovedFromPart);
|
||||
Assert.False(component.WasRemovedFromPartInBody);
|
||||
Assert.That(behavior.NoAdded);
|
||||
Assert.That(behavior.WasRemovedFromBody);
|
||||
Assert.False(behavior.WasRemovedFromPart);
|
||||
Assert.False(behavior.WasRemovedFromPartInBody);
|
||||
|
||||
component.ResetAll();
|
||||
behavior.ResetAll();
|
||||
|
||||
centerPart.RemoveMechanism(mechanism);
|
||||
|
||||
Assert.That(component.NoAdded);
|
||||
Assert.False(component.WasRemovedFromBody);
|
||||
Assert.That(component.WasRemovedFromPart);
|
||||
Assert.False(component.WasRemovedFromPartInBody);
|
||||
Assert.That(behavior.NoAdded);
|
||||
Assert.False(behavior.WasRemovedFromBody);
|
||||
Assert.That(behavior.WasRemovedFromPart);
|
||||
Assert.False(behavior.WasRemovedFromPartInBody);
|
||||
|
||||
component.ResetAll();
|
||||
behavior.ResetAll();
|
||||
|
||||
centerPart.TryAddMechanism(mechanism, true);
|
||||
|
||||
Assert.False(component.WasAddedToBody);
|
||||
Assert.That(component.WasAddedToPart);
|
||||
Assert.False(component.WasAddedToPartInBody);
|
||||
Assert.That(component.NoRemoved);
|
||||
Assert.False(behavior.WasAddedToBody);
|
||||
Assert.That(behavior.WasAddedToPart);
|
||||
Assert.False(behavior.WasAddedToPartInBody);
|
||||
Assert.That(behavior.NoRemoved);
|
||||
|
||||
component.ResetAll();
|
||||
behavior.ResetAll();
|
||||
|
||||
body.TryAddPart(centerSlot!, centerPart, true);
|
||||
|
||||
Assert.That(component.WasAddedToBody);
|
||||
Assert.False(component.WasAddedToPart);
|
||||
Assert.False(component.WasAddedToPartInBody);
|
||||
Assert.That(component.NoRemoved);
|
||||
Assert.That(behavior.WasAddedToBody);
|
||||
Assert.False(behavior.WasAddedToPart);
|
||||
Assert.False(behavior.WasAddedToPartInBody);
|
||||
Assert.That(behavior.NoRemoved);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
human.Transform.LocalPosition += (100, 0);
|
||||
});
|
||||
|
||||
await WaitUntil(server, () => !buckle.Buckled, maxTicks: 10);
|
||||
await WaitUntil(server, () => !buckle.Buckled, 10);
|
||||
|
||||
Assert.False(buckle.Buckled);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Shared;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
@@ -31,7 +32,7 @@ namespace Content.IntegrationTests.Tests.Commands
|
||||
|
||||
server.Assert(() =>
|
||||
{
|
||||
configManager.SetCVar("game.lobbyenabled", lobbyEnabled);
|
||||
configManager.SetCVar(CCVars.GameLobbyEnabled, lobbyEnabled);
|
||||
|
||||
Assert.That(gameTicker.RunLevel, Is.EqualTo(GameRunLevel.InRound));
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Client.GameObjects.Components.Mobs;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Shared.Alert;
|
||||
using NUnit.Framework;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs
|
||||
{
|
||||
[TestFixture]
|
||||
[TestOf(typeof(ClientAlertsComponent))]
|
||||
[TestOf(typeof(ServerAlertsComponent))]
|
||||
public class AlertsComponentTests : ContentIntegrationTest
|
||||
{
|
||||
|
||||
[Test]
|
||||
public async Task AlertsTest()
|
||||
{
|
||||
var (client, server) = await StartConnectedServerClientPair();
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
await client.WaitIdleAsync();
|
||||
|
||||
var serverPlayerManager = server.ResolveDependency<Robust.Server.Interfaces.Player.IPlayerManager>();
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var player = serverPlayerManager.GetAllPlayers().Single();
|
||||
var playerEnt = player.AttachedEntity;
|
||||
Assert.NotNull(playerEnt);
|
||||
var alertsComponent = playerEnt.GetComponent<ServerAlertsComponent>();
|
||||
Assert.NotNull(alertsComponent);
|
||||
|
||||
// show 2 alerts
|
||||
alertsComponent.ShowAlert(AlertType.Debug1);
|
||||
alertsComponent.ShowAlert(AlertType.Debug2);
|
||||
});
|
||||
|
||||
await server.WaitRunTicks(5);
|
||||
await client.WaitRunTicks(5);
|
||||
|
||||
var clientPlayerMgr = client.ResolveDependency<IPlayerManager>();
|
||||
var clientUIMgr = client.ResolveDependency<IUserInterfaceManager>();
|
||||
await client.WaitAssertion(() =>
|
||||
{
|
||||
|
||||
var local = clientPlayerMgr.LocalPlayer;
|
||||
Assert.NotNull(local);
|
||||
var controlled = local.ControlledEntity;
|
||||
Assert.NotNull(controlled);
|
||||
var alertsComponent = controlled.GetComponent<ClientAlertsComponent>();
|
||||
Assert.NotNull(alertsComponent);
|
||||
|
||||
// find the alertsui
|
||||
var alertsUI =
|
||||
clientUIMgr.StateRoot.Children.FirstOrDefault(c => c is AlertsUI) as AlertsUI;
|
||||
Assert.NotNull(alertsUI);
|
||||
|
||||
// we should be seeing 3 alerts - our health, and the 2 debug alerts, in a specific order.
|
||||
Assert.That(alertsUI.Grid.ChildCount, Is.EqualTo(3));
|
||||
var alertControls = alertsUI.Grid.Children.Select(c => c as AlertControl);
|
||||
var alertIDs = alertControls.Select(ac => ac.Alert.AlertType).ToArray();
|
||||
var expectedIDs = new [] {AlertType.HumanHealth, AlertType.Debug1, AlertType.Debug2};
|
||||
Assert.That(alertIDs, Is.EqualTo(expectedIDs));
|
||||
});
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var player = serverPlayerManager.GetAllPlayers().Single();
|
||||
var playerEnt = player.AttachedEntity;
|
||||
Assert.NotNull(playerEnt);
|
||||
var alertsComponent = playerEnt.GetComponent<ServerAlertsComponent>();
|
||||
Assert.NotNull(alertsComponent);
|
||||
|
||||
alertsComponent.ClearAlert(AlertType.Debug1);
|
||||
});
|
||||
await server.WaitRunTicks(5);
|
||||
await client.WaitRunTicks(5);
|
||||
|
||||
await client.WaitAssertion(() =>
|
||||
{
|
||||
|
||||
var local = clientPlayerMgr.LocalPlayer;
|
||||
Assert.NotNull(local);
|
||||
var controlled = local.ControlledEntity;
|
||||
Assert.NotNull(controlled);
|
||||
var alertsComponent = controlled.GetComponent<ClientAlertsComponent>();
|
||||
Assert.NotNull(alertsComponent);
|
||||
|
||||
// find the alertsui
|
||||
var alertsUI =
|
||||
clientUIMgr.StateRoot.Children.FirstOrDefault(c => c is AlertsUI) as AlertsUI;
|
||||
Assert.NotNull(alertsUI);
|
||||
|
||||
// we should be seeing only 2 alerts now because one was cleared
|
||||
Assert.That(alertsUI.Grid.ChildCount, Is.EqualTo(2));
|
||||
var alertControls = alertsUI.Grid.Children.Select(c => c as AlertControl);
|
||||
var alertIDs = alertControls.Select(ac => ac.Alert.AlertType).ToArray();
|
||||
var expectedIDs = new [] {AlertType.HumanHealth, AlertType.Debug2};
|
||||
Assert.That(alertIDs, Is.EqualTo(expectedIDs));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects.Components.Gravity;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Gravity;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
@@ -32,7 +33,7 @@ namespace Content.IntegrationTests.Tests.Gravity
|
||||
var tileDefinitionManager = server.ResolveDependency<ITileDefinitionManager>();
|
||||
|
||||
IEntity human = null;
|
||||
SharedStatusEffectsComponent statusEffects = null;
|
||||
SharedAlertsComponent alerts = null;
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
@@ -57,7 +58,7 @@ namespace Content.IntegrationTests.Tests.Gravity
|
||||
|
||||
human = entityManager.SpawnEntity("HumanMob_Content", coordinates);
|
||||
|
||||
Assert.True(human.TryGetComponent(out statusEffects));
|
||||
Assert.True(human.TryGetComponent(out alerts));
|
||||
});
|
||||
|
||||
// Let WeightlessSystem and GravitySystem tick
|
||||
@@ -68,7 +69,7 @@ namespace Content.IntegrationTests.Tests.Gravity
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
// No gravity without a gravity generator
|
||||
Assert.True(statusEffects.Statuses.ContainsKey(StatusEffect.Weightless));
|
||||
Assert.True(alerts.IsShowingAlert(AlertType.Weightless));
|
||||
|
||||
gravityGenerator = human.EnsureComponent<GravityGeneratorComponent>();
|
||||
});
|
||||
@@ -78,7 +79,7 @@ namespace Content.IntegrationTests.Tests.Gravity
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
Assert.False(statusEffects.Statuses.ContainsKey(StatusEffect.Weightless));
|
||||
Assert.False(alerts.IsShowingAlert(AlertType.Weightless));
|
||||
|
||||
// Disable the gravity generator
|
||||
var args = new BreakageEventArgs {Owner = human};
|
||||
@@ -89,7 +90,7 @@ namespace Content.IntegrationTests.Tests.Gravity
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
Assert.False(statusEffects.Statuses.ContainsKey(StatusEffect.Weightless));
|
||||
Assert.False(alerts.IsShowingAlert(AlertType.Weightless));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,9 +38,7 @@ namespace Content.IntegrationTests.Tests.Lobby
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var lobbyCvar = CCVars.GameLobbyEnabled;
|
||||
serverConfig.SetCVar(lobbyCvar.Name, true);
|
||||
|
||||
serverConfig.SetCVar(CCVars.GameLobbyEnabled, true);
|
||||
serverTicker.RestartRound();
|
||||
});
|
||||
|
||||
|
||||
66
Content.Server/Commands/CommandUtils.cs
Normal file
66
Content.Server/Commands/CommandUtils.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using Robust.Server.Interfaces.Console;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Server.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Utilities for writing commands
|
||||
/// </summary>
|
||||
public static class CommandUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the player session for the player with the indicated id,
|
||||
/// sending a failure to the performer if unable to.
|
||||
/// </summary>
|
||||
public static bool TryGetSessionByUsernameOrId(IConsoleShell shell,
|
||||
string usernameOrId, IPlayerSession performer, out IPlayerSession session)
|
||||
{
|
||||
var plyMgr = IoCManager.Resolve<IPlayerManager>();
|
||||
if (plyMgr.TryGetSessionByUsername(usernameOrId, out session)) return true;
|
||||
if (Guid.TryParse(usernameOrId, out var targetGuid))
|
||||
{
|
||||
if (plyMgr.TryGetSessionById(new NetUserId(targetGuid), out session)) return true;
|
||||
shell.SendText(performer, "Unable to find user with that name/id.");
|
||||
return false;
|
||||
}
|
||||
|
||||
shell.SendText(performer, "Unable to find user with that name/id.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attached entity for the player session with the indicated id,
|
||||
/// sending a failure to the performer if unable to.
|
||||
/// </summary>
|
||||
public static bool TryGetAttachedEntityByUsernameOrId(IConsoleShell shell,
|
||||
string usernameOrId, IPlayerSession performer, out IEntity attachedEntity)
|
||||
{
|
||||
attachedEntity = null;
|
||||
if (!TryGetSessionByUsernameOrId(shell, usernameOrId, performer, out var session)) return false;
|
||||
if (session.AttachedEntity == null)
|
||||
{
|
||||
shell.SendText(performer, "User has no attached entity.");
|
||||
return false;
|
||||
}
|
||||
|
||||
attachedEntity = session.AttachedEntity;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if attached entity is null, returning false and sending a message
|
||||
/// to performer if not.
|
||||
/// </summary>
|
||||
public static bool ValidateAttachedEntity(IConsoleShell shell, IPlayerSession performer, IEntity attachedEntity)
|
||||
{
|
||||
if (attachedEntity != null) return true;
|
||||
shell.SendText(performer, "User has no attached entity.");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
39
Content.Server/Commands/Hungry.cs
Normal file
39
Content.Server/Commands/Hungry.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
#nullable enable
|
||||
using Content.Server.GameObjects.Components.Nutrition;
|
||||
using Content.Shared.GameObjects.Components.Nutrition;
|
||||
using Robust.Server.Interfaces.Console;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
|
||||
namespace Content.Server.Commands
|
||||
{
|
||||
public class Hungry : IClientCommand
|
||||
{
|
||||
public string Command => "hungry";
|
||||
public string Description => "Makes you hungry.";
|
||||
public string Help => $"{Command}";
|
||||
|
||||
public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
|
||||
{
|
||||
if (player == null)
|
||||
{
|
||||
shell.SendText(player, "You cannot use this command unless you are a player.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.AttachedEntity == null)
|
||||
{
|
||||
shell.SendText(player, "You cannot use this command without an entity.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.AttachedEntity.TryGetComponent(out HungerComponent? hunger))
|
||||
{
|
||||
shell.SendText(player, $"Your entity does not have a {nameof(HungerComponent)} component.");
|
||||
return;
|
||||
}
|
||||
|
||||
var hungryThreshold = hunger.HungerThresholds[HungerThreshold.Starving];
|
||||
hunger.CurrentHunger = hungryThreshold;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Interfaces;
|
||||
using System;
|
||||
using Content.Server.Interfaces;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
using System.Collections.Generic;
|
||||
@@ -11,7 +12,8 @@ namespace Content.Server.GameObjects.EntitySystems.DeviceNetwork
|
||||
{
|
||||
private const int PACKAGES_PER_TICK = 30;
|
||||
|
||||
private readonly IRobustRandom _random = IoCManager.Resolve<IRobustRandom>();
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private readonly Dictionary<int, List<NetworkDevice>> _devices = new Dictionary<int, List<NetworkDevice>>();
|
||||
private readonly Queue<NetworkPackage> _packages = new Queue<NetworkPackage>();
|
||||
|
||||
@@ -40,11 +42,9 @@ namespace Content.Server.GameObjects.EntitySystems.DeviceNetwork
|
||||
|
||||
public void Update()
|
||||
{
|
||||
var i = PACKAGES_PER_TICK;
|
||||
while (_packages.Count > 0 && i > 0)
|
||||
var count = Math.Min(PACKAGES_PER_TICK, _packages.Count);
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
i--;
|
||||
|
||||
var package = _packages.Dequeue();
|
||||
|
||||
if (package.Broadcast)
|
||||
@@ -132,7 +132,7 @@ namespace Content.Server.GameObjects.EntitySystems.DeviceNetwork
|
||||
{
|
||||
var devices = DevicesForFrequency(netId, frequency);
|
||||
|
||||
var device = devices.Find(device => device.Address == address);
|
||||
var device = devices.Find(dvc => dvc.Address == address);
|
||||
|
||||
return device;
|
||||
}
|
||||
@@ -192,7 +192,6 @@ namespace Content.Server.GameObjects.EntitySystems.DeviceNetwork
|
||||
public IReadOnlyDictionary<string, string> Data { get; set; }
|
||||
public Metadata Metadata;
|
||||
public string Sender;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@ namespace Content.Server.GameObjects.EntitySystems.DeviceNetwork
|
||||
private readonly int _netId;
|
||||
|
||||
[ViewVariables]
|
||||
public bool Open { get; internal set; }
|
||||
public bool Open { get; private set; }
|
||||
[ViewVariables]
|
||||
public string Address { get; internal set; }
|
||||
public string Address { get; private set; }
|
||||
[ViewVariables]
|
||||
public int Frequency { get; internal set; }
|
||||
public int Frequency { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public bool RecieveAll
|
||||
public bool ReceiveAll
|
||||
{
|
||||
get => _network.GetDeviceReceiveAll(_netId, Frequency, Address);
|
||||
set => _network.SetDeviceReceiveAll(_netId, Frequency, Address, value);
|
||||
|
||||
@@ -11,6 +11,7 @@ using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Server.Interfaces.PDA;
|
||||
using Content.Server.Sandbox;
|
||||
using Content.Shared.Kitchen;
|
||||
using Content.Shared.Alert;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.ContentPack;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
@@ -78,6 +79,7 @@ namespace Content.Server
|
||||
|
||||
_gameTicker.Initialize();
|
||||
IoCManager.Resolve<RecipeManager>().Initialize();
|
||||
IoCManager.Resolve<AlertManager>().Initialize();
|
||||
IoCManager.Resolve<BlackboardManager>().Initialize();
|
||||
IoCManager.Resolve<ConsiderationsManager>().Initialize();
|
||||
IoCManager.Resolve<IPDAUplinkManager>().Initialize();
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.EntitySystems.DoAfter;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.ActionBlocking;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
@@ -115,7 +116,7 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
|
||||
CanStillInteract = _hands.Hands.Count() > CuffedHandCount;
|
||||
|
||||
OnCuffedStateChanged.Invoke();
|
||||
UpdateStatusEffect();
|
||||
UpdateAlert();
|
||||
UpdateHeldItems();
|
||||
Dirty();
|
||||
}
|
||||
@@ -181,17 +182,17 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
|
||||
/// <summary>
|
||||
/// Updates the status effect indicator on the HUD.
|
||||
/// </summary>
|
||||
private void UpdateStatusEffect()
|
||||
private void UpdateAlert()
|
||||
{
|
||||
if (Owner.TryGetComponent(out ServerStatusEffectsComponent status))
|
||||
if (Owner.TryGetComponent(out ServerAlertsComponent status))
|
||||
{
|
||||
if (CanStillInteract)
|
||||
{
|
||||
status.RemoveStatusEffect(StatusEffect.Cuffed);
|
||||
status.ClearAlert(AlertType.Handcuffed);
|
||||
}
|
||||
else
|
||||
{
|
||||
status.ChangeStatusEffectIcon(StatusEffect.Cuffed, "/Textures/Interface/StatusEffects/Handcuffed/Handcuffed.png");
|
||||
status.ShowAlert(AlertType.Handcuffed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -282,7 +283,7 @@ namespace Content.Server.GameObjects.Components.ActionBlocking
|
||||
|
||||
CanStillInteract = _hands.Hands.Count() > CuffedHandCount;
|
||||
OnCuffedStateChanged.Invoke();
|
||||
UpdateStatusEffect();
|
||||
UpdateAlert();
|
||||
Dirty();
|
||||
|
||||
if (CuffedHandCount == 0)
|
||||
|
||||
@@ -299,6 +299,7 @@ namespace Content.Server.GameObjects.Components.Arcade
|
||||
_component = component;
|
||||
_allBlockGamePieces = (BlockGamePieceType[]) Enum.GetValues(typeof(BlockGamePieceType));
|
||||
_internalNextPiece = GetRandomBlockGamePiece(_component._random);
|
||||
InitializeNewBlock();
|
||||
}
|
||||
|
||||
private void SendHighscoreUpdate()
|
||||
@@ -315,8 +316,6 @@ namespace Content.Server.GameObjects.Components.Arcade
|
||||
|
||||
public void StartGame()
|
||||
{
|
||||
InitializeNewBlock();
|
||||
|
||||
_component.UserInterface?.SendMessage(new BlockGameMessages.BlockGameSetScreenMessage(BlockGameMessages.BlockGameScreen.Game));
|
||||
|
||||
FullUpdate();
|
||||
@@ -569,10 +568,10 @@ namespace Content.Server.GameObjects.Components.Arcade
|
||||
break;
|
||||
case BlockGamePlayerAction.Pause:
|
||||
_running = false;
|
||||
_component.UserInterface?.SendMessage(new BlockGameMessages.BlockGameSetScreenMessage(BlockGameMessages.BlockGameScreen.Pause));
|
||||
_component.UserInterface?.SendMessage(new BlockGameMessages.BlockGameSetScreenMessage(BlockGameMessages.BlockGameScreen.Pause, _started));
|
||||
break;
|
||||
case BlockGamePlayerAction.Unpause:
|
||||
if (!_gameOver)
|
||||
if (!_gameOver && _started)
|
||||
{
|
||||
_running = true;
|
||||
_component.UserInterface?.SendMessage(new BlockGameMessages.BlockGameSetScreenMessage(BlockGameMessages.BlockGameScreen.Game));
|
||||
@@ -583,7 +582,7 @@ namespace Content.Server.GameObjects.Components.Arcade
|
||||
break;
|
||||
case BlockGamePlayerAction.ShowHighscores:
|
||||
_running = false;
|
||||
_component.UserInterface?.SendMessage(new BlockGameMessages.BlockGameSetScreenMessage(BlockGameMessages.BlockGameScreen.Highscores));
|
||||
_component.UserInterface?.SendMessage(new BlockGameMessages.BlockGameSetScreenMessage(BlockGameMessages.BlockGameScreen.Highscores, _started));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -654,6 +653,7 @@ namespace Content.Server.GameObjects.Components.Arcade
|
||||
}
|
||||
|
||||
private bool IsGameOver => _field.Any(block => block.Position.Y == 0);
|
||||
|
||||
private void InvokeGameover()
|
||||
{
|
||||
_running = false;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
@@ -22,7 +23,7 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
public void Update(float airPressure)
|
||||
{
|
||||
if (!Owner.TryGetComponent(out IDamageableComponent damageable)) return;
|
||||
Owner.TryGetComponent(out ServerStatusEffectsComponent status);
|
||||
Owner.TryGetComponent(out ServerAlertsComponent status);
|
||||
|
||||
var highPressureMultiplier = 1f;
|
||||
var lowPressureMultiplier = 1f;
|
||||
@@ -50,11 +51,11 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
|
||||
if (pressure <= Atmospherics.HazardLowPressure)
|
||||
{
|
||||
status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/lowpressure2.png", null);
|
||||
status.ShowAlert(AlertType.LowPressure, 2);
|
||||
break;
|
||||
}
|
||||
|
||||
status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/lowpressure1.png", null);
|
||||
status.ShowAlert(AlertType.LowPressure, 1);
|
||||
break;
|
||||
|
||||
// High pressure.
|
||||
@@ -72,16 +73,16 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
|
||||
if (pressure >= Atmospherics.HazardHighPressure)
|
||||
{
|
||||
status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/highpressure2.png", null);
|
||||
status.ShowAlert(AlertType.HighPressure, 2);
|
||||
break;
|
||||
}
|
||||
|
||||
status.ChangeStatusEffect(StatusEffect.Pressure, "/Textures/Interface/StatusEffects/Pressure/highpressure1.png", null);
|
||||
status.ShowAlert(AlertType.HighPressure, 1);
|
||||
break;
|
||||
|
||||
// Normal pressure.
|
||||
default:
|
||||
status?.RemoveStatusEffect(StatusEffect.Pressure);
|
||||
status?.ClearAlertCategory(AlertCategory.Pressure);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,11 +44,6 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
AutoClose = false;
|
||||
Safety = false;
|
||||
|
||||
if (Occludes && Owner.TryGetComponent(out OccluderComponent occluder))
|
||||
{
|
||||
occluder.Enabled = false;
|
||||
}
|
||||
|
||||
State = DoorState.Open;
|
||||
SetAppearance(DoorVisualState.Open);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Server.Atmos;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Temperature;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Damage;
|
||||
@@ -93,15 +94,15 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
FireStacks = MathF.Min(0, FireStacks + 1);
|
||||
}
|
||||
|
||||
Owner.TryGetComponent(out ServerStatusEffectsComponent status);
|
||||
Owner.TryGetComponent(out ServerAlertsComponent status);
|
||||
|
||||
if (!OnFire)
|
||||
{
|
||||
status?.RemoveStatusEffect(StatusEffect.Fire);
|
||||
status?.ClearAlert(AlertType.Fire);
|
||||
return;
|
||||
}
|
||||
|
||||
status?.ChangeStatusEffect(StatusEffect.Fire, "/Textures/Interface/StatusEffects/Fire/fire.png", null);
|
||||
status.ShowAlert(AlertType.Fire, onClickAlert: OnClickAlert);
|
||||
|
||||
if (FireStacks > 0)
|
||||
{
|
||||
@@ -153,6 +154,14 @@ namespace Content.Server.GameObjects.Components.Atmos
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClickAlert(ClickAlertEventArgs args)
|
||||
{
|
||||
if (args.Player.TryGetComponent(out FlammableComponent flammable))
|
||||
{
|
||||
flammable.Resist();
|
||||
}
|
||||
}
|
||||
|
||||
public void CollideWith(IEntity collidedWith)
|
||||
{
|
||||
if (!collidedWith.TryGetComponent(out FlammableComponent otherFlammable))
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
#nullable enable
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Body;
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Content.Shared.GameObjects.Components.Body.Part;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.ComponentDependencies;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class BrainBehaviorComponent : MechanismBehaviorComponent
|
||||
public class BrainBehavior : MechanismBehavior
|
||||
{
|
||||
public override string Name => "Brain";
|
||||
|
||||
protected override void OnAddedToBody(IBody body)
|
||||
{
|
||||
base.OnAddedToBody(body);
|
||||
@@ -66,9 +58,5 @@ namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
|
||||
oldMind.Mind?.TransferTo(newEntity);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,17 @@
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Content.Shared.GameObjects.Components.Body.Networks;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedHeartBehaviorComponent))]
|
||||
public class HeartBehaviorComponent : SharedHeartBehaviorComponent
|
||||
public class HeartBehavior : MechanismBehavior
|
||||
{
|
||||
private float _accumulatedFrameTime;
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
// TODO BODY do between pre and metabolism
|
||||
if (Mechanism?.Body == null ||
|
||||
!Mechanism.Body.Owner.HasComponent<SharedBloodstreamComponent>())
|
||||
if (Parent.Body == null ||
|
||||
!Parent.Body.Owner.HasComponent<SharedBloodstreamComponent>())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -8,19 +8,15 @@ using Content.Server.GameObjects.Components.Body.Respiratory;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedLungBehaviorComponent))]
|
||||
public class LungBehaviorComponent : SharedLungBehaviorComponent
|
||||
public class LungBehavior : MechanismBehavior
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
@@ -30,18 +26,24 @@ namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
|
||||
[ViewVariables] public GasMixture Air { get; set; } = default!;
|
||||
|
||||
[ViewVariables] public override float Temperature => Air.Temperature;
|
||||
[ViewVariables] public float Temperature => Air.Temperature;
|
||||
|
||||
[ViewVariables] public override float Volume => Air.Volume;
|
||||
[ViewVariables] public float Volume => Air.Volume;
|
||||
|
||||
[ViewVariables] public TimeSpan GaspPopupCooldown { get; private set; }
|
||||
|
||||
[ViewVariables] public LungStatus Status { get; set; }
|
||||
|
||||
[ViewVariables] public float CycleDelay { get; set; }
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
Air = new GasMixture {Temperature = Atmospherics.NormalBodyTemperature};
|
||||
|
||||
serializer.DataField(this, l => l.CycleDelay, "cycleDelay", 2);
|
||||
|
||||
serializer.DataReadWriteFunction(
|
||||
"volume",
|
||||
6,
|
||||
@@ -61,7 +63,7 @@ namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
() => GaspPopupCooldown.TotalSeconds);
|
||||
}
|
||||
|
||||
public override void Gasp()
|
||||
public void Gasp()
|
||||
{
|
||||
if (_gameTiming.CurTime >= _lastGaspPopupTime + GaspPopupCooldown)
|
||||
{
|
||||
@@ -148,7 +150,7 @@ namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
_accumulatedFrameTime = absoluteTime - delay;
|
||||
}
|
||||
|
||||
public override void Inhale(float frameTime)
|
||||
public void Inhale(float frameTime)
|
||||
{
|
||||
if (Body != null && Body.Owner.TryGetComponent(out InternalsComponent? internals)
|
||||
&& internals.BreathToolEntity != null && internals.GasTankEntity != null
|
||||
@@ -176,7 +178,7 @@ namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
ToBloodstream(Air);
|
||||
}
|
||||
|
||||
public override void Exhale(float frameTime)
|
||||
public void Exhale(float frameTime)
|
||||
{
|
||||
if (!Owner.Transform.Coordinates.TryGetTileAir(out var tileAir))
|
||||
{
|
||||
@@ -218,4 +220,11 @@ namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
Air.Merge(lungRemoved);
|
||||
}
|
||||
}
|
||||
|
||||
public enum LungStatus
|
||||
{
|
||||
None = 0,
|
||||
Inhaling,
|
||||
Exhaling
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,33 @@
|
||||
#nullable enable
|
||||
using Content.Shared.GameObjects.Components.Body;
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Content.Shared.GameObjects.Components.Body.Mechanism;
|
||||
using Content.Shared.GameObjects.Components.Body.Part;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Body.Behavior
|
||||
namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
{
|
||||
public abstract class MechanismBehaviorComponent : Component, IMechanismBehavior
|
||||
public abstract class MechanismBehavior : IMechanismBehavior
|
||||
{
|
||||
public IBody? Body => Part?.Body;
|
||||
|
||||
public IBodyPart? Part => Mechanism?.Part;
|
||||
public IBodyPart? Part => Parent.Part;
|
||||
|
||||
public IMechanism? Mechanism => Owner.GetComponentOrNull<IMechanism>();
|
||||
public IMechanism Parent { get; private set; } = default!;
|
||||
|
||||
protected override void Startup()
|
||||
public IEntity Owner => Parent.Owner;
|
||||
|
||||
public virtual void ExposeData(ObjectSerializer serializer) { }
|
||||
|
||||
public virtual void Initialize(IMechanism parent)
|
||||
{
|
||||
base.Startup();
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
public virtual void Startup()
|
||||
{
|
||||
if (Part == null)
|
||||
{
|
||||
return;
|
||||
@@ -33,8 +43,6 @@ namespace Content.Shared.GameObjects.Components.Body.Behavior
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void Update(float frameTime);
|
||||
|
||||
public void AddedToBody(IBody body)
|
||||
{
|
||||
DebugTools.AssertNotNull(Body);
|
||||
@@ -98,5 +106,7 @@ namespace Content.Shared.GameObjects.Components.Body.Behavior
|
||||
protected virtual void OnRemovedFromPart(IBodyPart old) { }
|
||||
|
||||
protected virtual void OnRemovedFromPartInBody(IBody oldBody, IBodyPart oldPart) { }
|
||||
|
||||
public virtual void Update(float frameTime) { }
|
||||
}
|
||||
}
|
||||
@@ -2,33 +2,29 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.GameObjects.Components.Body;
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Content.Shared.GameObjects.Components.Body.Part;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Body.Mechanism
|
||||
namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
{
|
||||
public static class MechanismExtensions
|
||||
{
|
||||
public static bool HasMechanismBehavior<T>(this IBody body)
|
||||
public static bool HasMechanismBehavior<T>(this IBody body) where T : IMechanismBehavior
|
||||
{
|
||||
return body.Parts.Values.Any(p => p.HasMechanismBehavior<T>());
|
||||
}
|
||||
|
||||
public static bool HasMechanismBehavior<T>(this IBodyPart part)
|
||||
public static bool HasMechanismBehavior<T>(this IBodyPart part) where T : IMechanismBehavior
|
||||
{
|
||||
return part.Mechanisms.Any(m => m.Owner.HasComponent<T>());
|
||||
}
|
||||
|
||||
public static bool HasMechanismBehavior<T>(this IMechanism mechanism)
|
||||
{
|
||||
return mechanism.Owner.HasComponent<T>();
|
||||
return part.Mechanisms.Any(m => m.HasBehavior<T>());
|
||||
}
|
||||
|
||||
public static IEnumerable<IMechanismBehavior> GetMechanismBehaviors(this IBody body)
|
||||
{
|
||||
foreach (var part in body.Parts.Values)
|
||||
foreach (var mechanism in part.Mechanisms)
|
||||
foreach (var behavior in mechanism.Owner.GetAllComponents<IMechanismBehavior>())
|
||||
foreach (var behavior in mechanism.Behaviors.Values)
|
||||
{
|
||||
yield return behavior;
|
||||
}
|
||||
@@ -52,10 +48,11 @@ namespace Content.Shared.GameObjects.Components.Body.Mechanism
|
||||
{
|
||||
foreach (var part in body.Parts.Values)
|
||||
foreach (var mechanism in part.Mechanisms)
|
||||
foreach (var behavior in mechanism.Behaviors.Values)
|
||||
{
|
||||
if (mechanism.Owner.TryGetComponent(out T? behavior))
|
||||
if (behavior is T tBehavior)
|
||||
{
|
||||
yield return behavior;
|
||||
yield return tBehavior;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,23 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Chemistry;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Body.Networks;
|
||||
using Content.Shared.GameObjects.Components.Chemistry;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Body.Behavior
|
||||
namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Where reagents go when ingested. Tracks ingested reagents over time, and
|
||||
/// eventually transfers them to <see cref="SharedBloodstreamComponent"/> once digested.
|
||||
/// </summary>
|
||||
public abstract class SharedStomachBehaviorComponent : MechanismBehaviorComponent
|
||||
public class StomachBehavior : MechanismBehavior
|
||||
{
|
||||
public override string Name => "Stomach";
|
||||
|
||||
private float _accumulatedFrameTime;
|
||||
|
||||
/// <summary>
|
||||
@@ -45,7 +45,7 @@ namespace Content.Shared.GameObjects.Components.Body.Behavior
|
||||
|
||||
_accumulatedFrameTime -= 1;
|
||||
|
||||
if (!Body.Owner.TryGetComponent(out SharedSolutionContainerComponent? solution) ||
|
||||
if (!Owner.TryGetComponent(out SharedSolutionContainerComponent? solution) ||
|
||||
!Body.Owner.TryGetComponent(out SharedBloodstreamComponent? bloodstream))
|
||||
{
|
||||
return;
|
||||
@@ -58,7 +58,7 @@ namespace Content.Shared.GameObjects.Components.Body.Behavior
|
||||
foreach (var delta in _reagentDeltas.ToList())
|
||||
{
|
||||
//Increment lifetime of reagents
|
||||
delta.Increment(frameTime);
|
||||
delta.Increment(1);
|
||||
if (delta.Lifetime > _digestionDelay)
|
||||
{
|
||||
solution.TryRemoveReagent(delta.ReagentId, delta.Quantity);
|
||||
@@ -112,6 +112,18 @@ namespace Content.Shared.GameObjects.Components.Body.Behavior
|
||||
serializer.DataField(ref _digestionDelay, "digestionDelay", 20);
|
||||
}
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
if (!Owner.EnsureComponent(out SolutionContainerComponent solution))
|
||||
{
|
||||
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} didn't have a {nameof(SolutionContainerComponent)}");
|
||||
}
|
||||
|
||||
solution.MaxVolume = InitialMaxVolume;
|
||||
}
|
||||
|
||||
public bool CanTransferSolution(Solution solution)
|
||||
{
|
||||
if (!Owner.TryGetComponent(out SharedSolutionContainerComponent? solutionComponent))
|
||||
@@ -1,24 +0,0 @@
|
||||
using Content.Server.GameObjects.Components.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Log;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Body.Behavior
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedStomachBehaviorComponent))]
|
||||
public class StomachBehaviorComponent : SharedStomachBehaviorComponent
|
||||
{
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
if (!Owner.EnsureComponent(out SolutionContainerComponent solution))
|
||||
{
|
||||
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} didn't have a {nameof(SolutionContainerComponent)}");
|
||||
}
|
||||
|
||||
solution.MaxVolume = InitialMaxVolume;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Content.Server.GameObjects.Components.Mobs.State;
|
||||
using Content.Server.GameObjects.Components.Pulling;
|
||||
using Content.Server.GameObjects.Components.Strap;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Buckle;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Strap;
|
||||
@@ -15,21 +16,16 @@ using Content.Shared.GameObjects.Verbs;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Content.Shared.Utility;
|
||||
using NFluidsynth;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.EntitySystemMessages;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.ComponentDependencies;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
@@ -39,12 +35,10 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
[RegisterComponent]
|
||||
public class BuckleComponent : SharedBuckleComponent, IInteractHand
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystem = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
[ComponentDependency] public readonly AppearanceComponent? AppearanceComponent = null;
|
||||
[ComponentDependency] private readonly ServerStatusEffectsComponent? _serverStatusEffectsComponent = null;
|
||||
[ComponentDependency] private readonly ServerAlertsComponent? _serverAlertsComponent = null;
|
||||
[ComponentDependency] private readonly StunnableComponent? _stunnableComponent = null;
|
||||
[ComponentDependency] private readonly MobStateManagerComponent? _mobStateManagerComponent = null;
|
||||
|
||||
@@ -69,7 +63,10 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
[ViewVariables]
|
||||
private TimeSpan _buckleTime;
|
||||
|
||||
public Vector2? BuckleOffset { get; private set; }
|
||||
/// <summary>
|
||||
/// The position offset that is being applied to this entity if buckled.
|
||||
/// </summary>
|
||||
public Vector2 BuckleOffset { get; private set; }
|
||||
|
||||
private StrapComponent? _buckledTo;
|
||||
|
||||
@@ -91,20 +88,6 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
[ViewVariables]
|
||||
public override bool Buckled => BuckledTo != null;
|
||||
|
||||
/// <summary>
|
||||
/// True if the entity was inserted or removed from a container
|
||||
/// before updating, false otherwise.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private bool ContainerChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the entity was forcefully moved while buckled and should
|
||||
/// unbuckle next update, false otherwise
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private bool Moved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of space that this entity occupies in a
|
||||
/// <see cref="StrapComponent"/>.
|
||||
@@ -116,26 +99,38 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
/// Shows or hides the buckled status effect depending on if the
|
||||
/// entity is buckled or not.
|
||||
/// </summary>
|
||||
private void BuckleStatus()
|
||||
private void UpdateBuckleStatus()
|
||||
{
|
||||
if (_serverStatusEffectsComponent != null)
|
||||
if (_serverAlertsComponent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Buckled)
|
||||
{
|
||||
_serverStatusEffectsComponent.ChangeStatusEffectIcon(StatusEffect.Buckled, BuckledTo!.BuckledIcon);
|
||||
_serverAlertsComponent.ShowAlert(BuckledTo != null ? BuckledTo.BuckledAlertType : AlertType.Buckled,
|
||||
onClickAlert: OnClickAlert);
|
||||
}
|
||||
else
|
||||
{
|
||||
_serverStatusEffectsComponent.RemoveStatusEffect(StatusEffect.Buckled);
|
||||
_serverAlertsComponent.ClearAlertCategory(AlertCategory.Buckled);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClickAlert(ClickAlertEventArgs args)
|
||||
{
|
||||
if (args.Player.TryGetComponent(out BuckleComponent? buckle))
|
||||
{
|
||||
buckle.TryUnbuckle(args.Player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reattaches this entity to the strap, modifying its position and rotation.
|
||||
/// </summary>
|
||||
/// <param name="strap">The strap to reattach to.</param>
|
||||
private void ReAttach(StrapComponent strap)
|
||||
public void ReAttach(StrapComponent strap)
|
||||
{
|
||||
var ownTransform = Owner.Transform;
|
||||
var strapTransform = strap.Owner.Transform;
|
||||
@@ -161,7 +156,7 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
if (strapTransform.WorldRotation.GetCardinalDir() == Direction.North)
|
||||
{
|
||||
BuckleOffset = (0, 0.15f);
|
||||
ownTransform.WorldPosition = strapTransform.WorldPosition + BuckleOffset!.Value;
|
||||
ownTransform.WorldPosition = strapTransform.WorldPosition + BuckleOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -266,8 +261,7 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
return false;
|
||||
}
|
||||
|
||||
_entitySystem.GetEntitySystem<AudioSystem>()
|
||||
.PlayFromEntity(strap.BuckleSound, Owner);
|
||||
EntitySystem.Get<AudioSystem>().PlayFromEntity(strap.BuckleSound, Owner);
|
||||
|
||||
if (!strap.TryAdd(this))
|
||||
{
|
||||
@@ -283,13 +277,10 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
BuckledTo = strap;
|
||||
|
||||
ReAttach(strap);
|
||||
BuckleStatus();
|
||||
UpdateBuckleStatus();
|
||||
|
||||
SendMessage(new BuckleMessage(Owner, to));
|
||||
|
||||
Owner.EntityManager.EventBus.SubscribeEvent<MoveEvent>(EventSource.Local, this, MoveEvent);
|
||||
|
||||
|
||||
if (Owner.TryGetComponent(out PullableComponent? pullableComponent))
|
||||
{
|
||||
if (pullableComponent.Puller != null)
|
||||
@@ -315,12 +306,12 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
/// </returns>
|
||||
public bool TryUnbuckle(IEntity user, bool force = false)
|
||||
{
|
||||
if (!Buckled)
|
||||
if (BuckledTo == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
StrapComponent oldBuckledTo = BuckledTo!;
|
||||
var oldBuckledTo = BuckledTo;
|
||||
|
||||
if (!force)
|
||||
{
|
||||
@@ -360,21 +351,15 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
EntitySystem.Get<StandingStateSystem>().Standing(Owner);
|
||||
}
|
||||
|
||||
if (_mobStateManagerComponent != null)
|
||||
{
|
||||
_mobStateManagerComponent.CurrentMobState.EnterState(Owner);
|
||||
}
|
||||
_mobStateManagerComponent?.CurrentMobState.EnterState(Owner);
|
||||
|
||||
BuckleStatus();
|
||||
UpdateBuckleStatus();
|
||||
|
||||
oldBuckledTo.Remove(this);
|
||||
_entitySystem.GetEntitySystem<AudioSystem>()
|
||||
.PlayFromEntity(oldBuckledTo.UnbuckleSound, Owner);
|
||||
EntitySystem.Get<AudioSystem>().PlayFromEntity(oldBuckledTo.UnbuckleSound, Owner);
|
||||
|
||||
SendMessage(new UnbuckleMessage(Owner, oldBuckledTo.Owner));
|
||||
|
||||
Owner.EntityManager.EventBus.UnsubscribeEvent<MoveEvent>(EventSource.Local, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -402,90 +387,6 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
return TryBuckle(user, to);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a buckled entity should be unbuckled from moving
|
||||
/// too far from its strap.
|
||||
/// </summary>
|
||||
/// <param name="moveEvent">The move event of a buckled entity.</param>
|
||||
private void MoveEvent(MoveEvent moveEvent)
|
||||
{
|
||||
if (moveEvent.Sender != Owner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (BuckledTo == null || !BuckleOffset.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var bucklePosition = BuckledTo.Owner.Transform.Coordinates.Offset(BuckleOffset.Value);
|
||||
|
||||
if (moveEvent.NewPosition.InRange(_entityManager, bucklePosition, 0.2f))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Moved = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the owner is inserted or removed from a container,
|
||||
/// to synchronize the state of buckling.
|
||||
/// </summary>
|
||||
/// <param name="message">The message received</param>
|
||||
private void InsertIntoContainer(ContainerModifiedMessage message)
|
||||
{
|
||||
if (message.Entity != Owner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ContainerChanged = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Synchronizes the state of buckling depending on whether the entity
|
||||
/// was inserted or removed from a container, and whether or not
|
||||
/// its current strap (if there is one) has also been put into or removed
|
||||
/// from the same container as well.
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
if (BuckledTo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Moved)
|
||||
{
|
||||
TryUnbuckle(Owner, true);
|
||||
Moved = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ContainerChanged)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var contained = ContainerHelpers.TryGetContainer(Owner, out var ownContainer);
|
||||
var strapContained = ContainerHelpers.TryGetContainer(BuckledTo.Owner, out var strapContainer);
|
||||
|
||||
if (contained != strapContained || ownContainer != strapContainer)
|
||||
{
|
||||
TryUnbuckle(Owner, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!contained && !strapContained)
|
||||
{
|
||||
ReAttach(BuckledTo);
|
||||
}
|
||||
|
||||
ContainerChanged = false;
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
@@ -499,32 +400,21 @@ namespace Content.Server.GameObjects.Components.Buckle
|
||||
_unbuckleDelay = TimeSpan.FromSeconds(seconds);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_entityManager.EventBus.SubscribeEvent<EntInsertedIntoContainerMessage>(EventSource.Local, this, InsertIntoContainer);
|
||||
_entityManager.EventBus.SubscribeEvent<EntRemovedFromContainerMessage>(EventSource.Local, this, InsertIntoContainer);
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
BuckleStatus();
|
||||
UpdateBuckleStatus();
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
_entityManager.EventBus.UnsubscribeEvents(this);
|
||||
|
||||
BuckledTo?.Remove(this);
|
||||
|
||||
TryUnbuckle(Owner, true);
|
||||
|
||||
_buckleTime = default;
|
||||
BuckleStatus();
|
||||
UpdateBuckleStatus();
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
||||
var trueTarget = target ?? user;
|
||||
|
||||
if (!trueTarget.TryGetComponent(out IBody body) ||
|
||||
!body.TryGetMechanismBehaviors<StomachBehaviorComponent>(out var stomachs))
|
||||
!body.TryGetMechanismBehaviors<StomachBehavior>(out var stomachs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,7 @@ using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
@@ -28,18 +26,24 @@ namespace Content.Server.GameObjects.Components
|
||||
|
||||
private Regex _validation;
|
||||
|
||||
public event Action<Dictionary<string, string>> OnConfigUpdate;
|
||||
|
||||
public override void Initialize()
|
||||
public override void OnAdd()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
base.OnAdd();
|
||||
if (UserInterface != null)
|
||||
{
|
||||
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
if (UserInterface != null)
|
||||
{
|
||||
UserInterface.OnReceiveMessage -= UserInterfaceOnReceiveMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
@@ -48,7 +52,7 @@ namespace Content.Server.GameObjects.Components
|
||||
(list) => FillConfiguration(list, _config, ""),
|
||||
() => _config.Keys.ToList());
|
||||
|
||||
serializer.DataReadFunction("vailidation", "^[a-zA-Z0-9 ]*$", value => _validation = new Regex("^[a-zA-Z0-9 ]*$", RegexOptions.Compiled));
|
||||
serializer.DataReadFunction("validation", "^[a-zA-Z0-9 ]*$", value => _validation = new Regex("^[a-zA-Z0-9 ]*$", RegexOptions.Compiled));
|
||||
}
|
||||
|
||||
public string GetConfig(string name)
|
||||
@@ -90,22 +94,19 @@ namespace Content.Server.GameObjects.Components
|
||||
{
|
||||
var value = msg.Config.GetValueOrDefault(key);
|
||||
|
||||
if (_validation != null && !_validation.IsMatch(value) && value != "")
|
||||
if (value == null || _validation != null && !_validation.IsMatch(value) && value != "")
|
||||
continue;
|
||||
|
||||
_config[key] = value;
|
||||
}
|
||||
|
||||
OnConfigUpdate(_config);
|
||||
SendMessage(new ConfigUpdatedComponentMessage(config));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateUserInterface()
|
||||
{
|
||||
if (UserInterface == null)
|
||||
return;
|
||||
|
||||
UserInterface.SetState(new ConfigurationBoundUserInterfaceState(_config));
|
||||
UserInterface?.SetState(new ConfigurationBoundUserInterfaceState(_config));
|
||||
}
|
||||
|
||||
private static void FillConfiguration<T>(List<string> list, Dictionary<string, T> configuration, T value){
|
||||
|
||||
@@ -13,6 +13,7 @@ using Content.Server.GameObjects.EntitySystems.DoAfter;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.GameObjects.Components.Body;
|
||||
using Content.Shared.GameObjects.Components.Disposal;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
@@ -603,12 +604,7 @@ namespace Content.Server.GameObjects.Components.Disposal
|
||||
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
|
||||
}
|
||||
|
||||
var network = IoCManager.Resolve<IDeviceNetwork>();
|
||||
_connection = new WiredNetworkConnection(OnReceiveNetMessage, false, Owner);
|
||||
|
||||
if (Owner.TryGetComponent<ConfigurationComponent>(out var configuration))
|
||||
configuration.OnConfigUpdate += OnConfigUpdate;
|
||||
|
||||
UpdateInterface();
|
||||
}
|
||||
|
||||
@@ -673,6 +669,9 @@ namespace Content.Server.GameObjects.Components.Disposal
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case SharedConfigurationComponent.ConfigUpdatedComponentMessage msg:
|
||||
OnConfigUpdate(msg.Config);
|
||||
break;
|
||||
case RelayMovementEntityMessage msg:
|
||||
if (!msg.Entity.TryGetComponent(out HandsComponent? hands) ||
|
||||
hands.Count == 0 ||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Utility;
|
||||
@@ -8,6 +9,7 @@ using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Items
|
||||
@@ -33,23 +35,52 @@ namespace Content.Server.GameObjects.Components.Items
|
||||
Owner.EnsureComponent<StackComponent>();
|
||||
}
|
||||
|
||||
private bool HasBaseTurf(ContentTileDefinition tileDef, string baseTurf)
|
||||
{
|
||||
foreach (var tileBaseTurf in tileDef.BaseTurfs)
|
||||
{
|
||||
if (baseTurf == tileBaseTurf)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void PlaceAt(IMapGrid mapGrid, EntityCoordinates location, ushort tileId, float offset = 0)
|
||||
{
|
||||
mapGrid.SetTile(location.Offset(new Vector2(offset, offset)), new Tile(tileId));
|
||||
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/Items/genhit.ogg", location, AudioHelpers.WithVariation(0.125f));
|
||||
}
|
||||
|
||||
public void AfterInteract(AfterInteractEventArgs eventArgs)
|
||||
{
|
||||
if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) return;
|
||||
if (!Owner.TryGetComponent(out StackComponent stack)) return;
|
||||
|
||||
var attacked = eventArgs.Target;
|
||||
var mapGrid = _mapManager.GetGrid(eventArgs.ClickLocation.GetGridId(Owner.EntityManager));
|
||||
var tile = mapGrid.GetTileRef(eventArgs.ClickLocation);
|
||||
var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];
|
||||
var location = eventArgs.ClickLocation.AlignWithClosestGridTile();
|
||||
var locationMap = location.ToMap(Owner.EntityManager);
|
||||
|
||||
if (tileDef.IsSubFloor && attacked == null && stack.Use(1))
|
||||
var desiredTile = (ContentTileDefinition)_tileDefinitionManager[_outputTile];
|
||||
|
||||
if (_mapManager.TryGetGrid(location.GetGridId(Owner.EntityManager), out var mapGrid))
|
||||
{
|
||||
var desiredTile = _tileDefinitionManager[_outputTile];
|
||||
mapGrid.SetTile(eventArgs.ClickLocation, new Tile(desiredTile.TileId));
|
||||
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/Items/genhit.ogg", eventArgs.ClickLocation);
|
||||
}
|
||||
var tile = mapGrid.GetTileRef(location);
|
||||
var baseTurf = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];
|
||||
|
||||
if (HasBaseTurf(desiredTile, baseTurf.Name) && eventArgs.Target == null && stack.Use(1))
|
||||
{
|
||||
PlaceAt(mapGrid, location, desiredTile.TileId);
|
||||
}
|
||||
}
|
||||
else if(HasBaseTurf(desiredTile, "space"))
|
||||
{
|
||||
mapGrid = _mapManager.CreateGrid(locationMap.MapId);
|
||||
mapGrid.WorldPosition = locationMap.Position;
|
||||
location = new EntityCoordinates(mapGrid.GridEntityId, Vector2.Zero);
|
||||
PlaceAt(mapGrid, location, desiredTile.TileId, mapGrid.TileSize/2f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace Content.Server.GameObjects.Components.Metabolism
|
||||
return;
|
||||
}
|
||||
|
||||
var lungs = _body.GetMechanismBehaviors<LungBehaviorComponent>().ToArray();
|
||||
var lungs = _body.GetMechanismBehaviors<LungBehavior>().ToArray();
|
||||
|
||||
var needs = NeedsAndDeficit(frameTime);
|
||||
var used = 0f;
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using Content.Server.Commands;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Server.Interfaces.Console;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Mobs
|
||||
{
|
||||
[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");
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
if (EntitySystem.TryGet<WeightlessSystem>(out var weightlessSystem))
|
||||
{
|
||||
weightlessSystem.RemoveAlert(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.WarningS("alert", "weightlesssystem not found");
|
||||
}
|
||||
|
||||
base.OnRemove();
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
return new AlertsComponentState(CreateAlertStatesArray());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (player != Owner)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Implement clicking other status effects in the HUD
|
||||
if (AlertManager.TryDecode(msg.EncodedAlert, out var alert))
|
||||
{
|
||||
PerformAlertClickCallback(alert, player);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.WarningS("alert", "unrecognized encoded alert {0}", msg.EncodedAlert);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ShowAlert : IClientCommand
|
||||
{
|
||||
public string Command => "showalert";
|
||||
public string Description => "Shows an alert for a player, defaulting to current player";
|
||||
public string Help => "showalert <alertType> <severity, -1 if no severity> <name or userID, omit for current player>";
|
||||
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
|
||||
{
|
||||
var attachedEntity = player.AttachedEntity;
|
||||
if (args.Length > 2)
|
||||
{
|
||||
var target = args[2];
|
||||
if (!Commands.CommandUtils.TryGetAttachedEntityByUsernameOrId(shell, target, player, out attachedEntity)) return;
|
||||
}
|
||||
|
||||
if (!CommandUtils.ValidateAttachedEntity(shell, player, attachedEntity)) return;
|
||||
|
||||
|
||||
if (!attachedEntity.TryGetComponent(out ServerAlertsComponent alertsComponent))
|
||||
{
|
||||
shell.SendText(player, "user has no alerts component");
|
||||
return;
|
||||
}
|
||||
|
||||
var alertType = args[0];
|
||||
var severity = args[1];
|
||||
var alertMgr = IoCManager.Resolve<AlertManager>();
|
||||
if (!alertMgr.TryGet(Enum.Parse<AlertType>(alertType), out var alert))
|
||||
{
|
||||
shell.SendText(player, "unrecognized alertType " + alertType);
|
||||
return;
|
||||
}
|
||||
if (!short.TryParse(severity, out var sevint))
|
||||
{
|
||||
shell.SendText(player, "invalid severity " + sevint);
|
||||
return;
|
||||
}
|
||||
alertsComponent.ShowAlert(alert.AlertType, sevint == -1 ? (short?) null : sevint);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ClearAlert : IClientCommand
|
||||
{
|
||||
public string Command => "clearalert";
|
||||
public string Description => "Clears an alert for a player, defaulting to current player";
|
||||
public string Help => "clearalert <alertType> <name or userID, omit for current player>";
|
||||
|
||||
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
|
||||
{
|
||||
var attachedEntity = player.AttachedEntity;
|
||||
if (args.Length > 1)
|
||||
{
|
||||
var target = args[1];
|
||||
if (!CommandUtils.TryGetAttachedEntityByUsernameOrId(shell, target, player, out attachedEntity)) return;
|
||||
}
|
||||
|
||||
if (!CommandUtils.ValidateAttachedEntity(shell, player, attachedEntity)) return;
|
||||
|
||||
if (!attachedEntity.TryGetComponent(out ServerAlertsComponent alertsComponent))
|
||||
{
|
||||
shell.SendText(player, "user has no alerts component");
|
||||
return;
|
||||
}
|
||||
|
||||
var alertType = args[0];
|
||||
var alertMgr = IoCManager.Resolve<AlertManager>();
|
||||
if (!alertMgr.TryGet(Enum.Parse<AlertType>(alertType), out var alert))
|
||||
{
|
||||
shell.SendText(player, "unrecognized alertType " + alertType);
|
||||
return;
|
||||
}
|
||||
|
||||
alertsComponent.ClearAlert(alert.AlertType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.GameObjects.Components.Buckle;
|
||||
using Content.Server.GameObjects.Components.Movement;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Pulling;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Mobs
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedStatusEffectsComponent))]
|
||||
public sealed class ServerStatusEffectsComponent : SharedStatusEffectsComponent
|
||||
{
|
||||
[ViewVariables]
|
||||
private readonly Dictionary<StatusEffect, StatusEffectStatus> _statusEffects = new Dictionary<StatusEffect, StatusEffectStatus>();
|
||||
|
||||
public override IReadOnlyDictionary<StatusEffect, StatusEffectStatus> Statuses => _statusEffects;
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
EntitySystem.Get<WeightlessSystem>().AddStatus(this);
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
EntitySystem.Get<WeightlessSystem>().RemoveStatus(this);
|
||||
|
||||
base.OnRemove();
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
return new StatusEffectComponentState(_statusEffects);
|
||||
}
|
||||
|
||||
public override void ChangeStatusEffectIcon(StatusEffect effect, string icon)
|
||||
{
|
||||
if (_statusEffects.TryGetValue(effect, out var value) && value.Icon == icon)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_statusEffects[effect] = new StatusEffectStatus()
|
||||
{Icon = icon, Cooldown = value.Cooldown};
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void ChangeStatusEffectCooldown(StatusEffect effect, ValueTuple<TimeSpan, TimeSpan> cooldown)
|
||||
{
|
||||
if (_statusEffects.TryGetValue(effect, out var value)
|
||||
&& value.Cooldown == cooldown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_statusEffects[effect] = new StatusEffectStatus()
|
||||
{
|
||||
Icon = value.Icon, Cooldown = cooldown
|
||||
};
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public override void ChangeStatusEffect(StatusEffect effect, string icon, ValueTuple<TimeSpan, TimeSpan>? cooldown)
|
||||
{
|
||||
_statusEffects[effect] = new StatusEffectStatus()
|
||||
{Icon = icon, Cooldown = cooldown};
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public override void RemoveStatusEffect(StatusEffect effect)
|
||||
{
|
||||
if (!_statusEffects.Remove(effect))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
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 ClickStatusMessage msg:
|
||||
{
|
||||
var player = session.AttachedEntity;
|
||||
|
||||
if (player != Owner)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Implement clicking other status effects in the HUD
|
||||
switch (msg.Effect)
|
||||
{
|
||||
case StatusEffect.Buckled:
|
||||
if (!player.TryGetComponent(out BuckleComponent buckle))
|
||||
break;
|
||||
|
||||
buckle.TryUnbuckle(player);
|
||||
break;
|
||||
case StatusEffect.Piloting:
|
||||
if (!player.TryGetComponent(out ShuttleControllerComponent controller))
|
||||
break;
|
||||
|
||||
controller.RemoveController();
|
||||
break;
|
||||
case StatusEffect.Pulling:
|
||||
EntitySystem
|
||||
.Get<SharedPullingSystem>()
|
||||
.GetPulled(player)?
|
||||
.GetComponentOrNull<SharedPullableComponent>()?
|
||||
.TryStopPull();
|
||||
|
||||
break;
|
||||
case StatusEffect.Fire:
|
||||
if (!player.TryGetComponent(out FlammableComponent flammable))
|
||||
break;
|
||||
|
||||
flammable.Resist();
|
||||
break;
|
||||
default:
|
||||
player.PopupMessage(msg.Effect.ToString());
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Mobs.State;
|
||||
@@ -17,10 +18,9 @@ namespace Content.Server.GameObjects.Components.Mobs.State
|
||||
appearance.SetData(DamageStateVisuals.State, DamageState.Critical);
|
||||
}
|
||||
|
||||
if (entity.TryGetComponent(out ServerStatusEffectsComponent status))
|
||||
if (entity.TryGetComponent(out ServerAlertsComponent status))
|
||||
{
|
||||
status.ChangeStatusEffectIcon(StatusEffect.Health,
|
||||
"/Textures/Interface/StatusEffects/Human/humancrit-0.png"); //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
|
||||
}
|
||||
|
||||
if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlay))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Mobs.State;
|
||||
@@ -18,10 +19,9 @@ namespace Content.Server.GameObjects.Components.Mobs.State
|
||||
appearance.SetData(DamageStateVisuals.State, DamageState.Dead);
|
||||
}
|
||||
|
||||
if (entity.TryGetComponent(out ServerStatusEffectsComponent status))
|
||||
if (entity.TryGetComponent(out ServerAlertsComponent status))
|
||||
{
|
||||
status.ChangeStatusEffectIcon(StatusEffect.Health,
|
||||
"/Textures/Interface/StatusEffects/Human/humandead.png");
|
||||
status.ShowAlert(AlertType.HumanDead);
|
||||
}
|
||||
|
||||
if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlayComponent))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Mobs.State;
|
||||
@@ -51,9 +52,9 @@ namespace Content.Server.GameObjects.Components.Mobs.State
|
||||
// TODO: Might want to add an OnRemove() to IMobState since those are where these components are being used
|
||||
base.OnRemove();
|
||||
|
||||
if (Owner.TryGetComponent(out ServerStatusEffectsComponent status))
|
||||
if (Owner.TryGetComponent(out ServerAlertsComponent status))
|
||||
{
|
||||
status.RemoveStatusEffect(StatusEffect.Health);
|
||||
status.ClearAlert(AlertType.HumanHealth);
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out ServerOverlayEffectsComponent overlay))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Damage;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Mobs.State;
|
||||
@@ -27,15 +28,14 @@ namespace Content.Server.GameObjects.Components.Mobs.State
|
||||
|
||||
public override void UpdateState(IEntity entity)
|
||||
{
|
||||
if (!entity.TryGetComponent(out ServerStatusEffectsComponent status))
|
||||
if (!entity.TryGetComponent(out ServerAlertsComponent status))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!entity.TryGetComponent(out IDamageableComponent damageable))
|
||||
{
|
||||
status.ChangeStatusEffectIcon(StatusEffect.Health,
|
||||
"/Textures/Interface/StatusEffects/Human/human0.png");
|
||||
status.ShowAlert(AlertType.HumanHealth, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,10 +49,9 @@ namespace Content.Server.GameObjects.Components.Mobs.State
|
||||
return;
|
||||
}
|
||||
|
||||
var modifier = (int) (ruinable.TotalDamage / (threshold / 7f));
|
||||
var modifier = (short) (ruinable.TotalDamage / (threshold / 7f));
|
||||
|
||||
status.ChangeStatusEffectIcon(StatusEffect.Health,
|
||||
"/Textures/Interface/StatusEffects/Human/human" + modifier + ".png");
|
||||
status.ShowAlert(AlertType.HumanHealth, modifier);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -63,10 +62,9 @@ namespace Content.Server.GameObjects.Components.Mobs.State
|
||||
return;
|
||||
}
|
||||
|
||||
var modifier = (int) (damageable.TotalDamage / (threshold / 7f));
|
||||
var modifier = (short) (damageable.TotalDamage / (threshold / 7f));
|
||||
|
||||
status.ChangeStatusEffectIcon(StatusEffect.Health,
|
||||
"/Textures/Interface/StatusEffects/Human/human" + modifier + ".png");
|
||||
status.ShowAlert(AlertType.HumanHealth, modifier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Movement;
|
||||
@@ -89,7 +90,7 @@ namespace Content.Server.GameObjects.Components.Mobs
|
||||
}
|
||||
|
||||
if (!StunStart.HasValue || !StunEnd.HasValue ||
|
||||
!Owner.TryGetComponent(out ServerStatusEffectsComponent status))
|
||||
!Owner.TryGetComponent(out ServerAlertsComponent status))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -102,7 +103,7 @@ namespace Content.Server.GameObjects.Components.Mobs
|
||||
|
||||
if (progress >= length)
|
||||
{
|
||||
Owner.SpawnTimer(250, () => status.RemoveStatusEffect(StatusEffect.Stun), StatusRemoveCancellation.Token);
|
||||
Owner.SpawnTimer(250, () => status.ClearAlert(AlertType.Stun), StatusRemoveCancellation.Token);
|
||||
LastStun = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Shared.GameObjects.Components.Morgue;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Verbs;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -52,9 +53,20 @@ namespace Content.Server.GameObjects.Components.Morgue
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanOpen(IEntity user, bool silent = false)
|
||||
{
|
||||
if (Cooking)
|
||||
{
|
||||
if (!silent) Owner.PopupMessage(user, Loc.GetString("Safety first, not while it's active!"));
|
||||
return false;
|
||||
}
|
||||
return base.CanOpen(user, silent);
|
||||
}
|
||||
|
||||
public void Cremate()
|
||||
{
|
||||
if (Cooking) return;
|
||||
if (Open) return;
|
||||
|
||||
Appearance?.SetData(CrematoriumVisuals.Burning, true);
|
||||
Cooking = true;
|
||||
@@ -64,6 +76,8 @@ namespace Content.Server.GameObjects.Components.Morgue
|
||||
Appearance?.SetData(CrematoriumVisuals.Burning, false);
|
||||
Cooking = false;
|
||||
|
||||
if (Contents.ContainedEntities.Count > 0)
|
||||
{
|
||||
for (var i = Contents.ContainedEntities.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var item = Contents.ContainedEntities[i];
|
||||
@@ -73,6 +87,7 @@ namespace Content.Server.GameObjects.Components.Morgue
|
||||
|
||||
var ash = Owner.EntityManager.SpawnEntity("Ash", Owner.Transform.Coordinates);
|
||||
Contents.Insert(ash);
|
||||
}
|
||||
|
||||
TryOpenStorage(Owner);
|
||||
|
||||
@@ -85,7 +100,7 @@ namespace Content.Server.GameObjects.Components.Morgue
|
||||
{
|
||||
protected override void GetData(IEntity user, CrematoriumEntityStorageComponent component, VerbData data)
|
||||
{
|
||||
if (!ActionBlockerSystem.CanInteract(user) || component.Cooking)
|
||||
if (!ActionBlockerSystem.CanInteract(user) || component.Cooking || component.Open)
|
||||
{
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using Content.Shared.GameObjects.Components.Movement;
|
||||
#nullable enable
|
||||
using Content.Shared.GameObjects.Components.Buckle;
|
||||
using Content.Shared.GameObjects.Components.Movement;
|
||||
using Content.Shared.Physics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Movement
|
||||
@@ -8,8 +11,8 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
[RegisterComponent]
|
||||
public class ClimbingComponent : SharedClimbingComponent
|
||||
{
|
||||
private bool _isClimbing = false;
|
||||
private ClimbController _climbController = default;
|
||||
private bool _isClimbing;
|
||||
private ClimbController? _climbController;
|
||||
|
||||
public override bool IsClimbing
|
||||
{
|
||||
@@ -29,6 +32,19 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, IComponent? component)
|
||||
{
|
||||
base.HandleMessage(message, component);
|
||||
switch (message)
|
||||
{
|
||||
case BuckleMessage msg:
|
||||
if (msg.Buckled)
|
||||
IsClimbing = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make the owner climb from one point to another
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#nullable enable
|
||||
using Content.Server.GameObjects.Components.Buckle;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Movement;
|
||||
using Content.Shared.GameObjects.Components.Strap;
|
||||
@@ -31,9 +32,9 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
private bool _movingRight;
|
||||
|
||||
/// <summary>
|
||||
/// The icon to be displayed when piloting from this chair.
|
||||
/// ID of the alert to show when piloting
|
||||
/// </summary>
|
||||
private string _pilotingIcon = default!;
|
||||
private AlertType _pilotingAlertType;
|
||||
|
||||
/// <summary>
|
||||
/// The entity that's currently controlling this component.
|
||||
@@ -137,7 +138,7 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
if (_controller != null ||
|
||||
!entity.TryGetComponent(out MindComponent? mind) ||
|
||||
mind.Mind == null ||
|
||||
!Owner.TryGetComponent(out ServerStatusEffectsComponent? status))
|
||||
!Owner.TryGetComponent(out ServerAlertsComponent? status))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -145,7 +146,15 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
mind.Mind.Visit(Owner);
|
||||
_controller = entity;
|
||||
|
||||
status.ChangeStatusEffectIcon(StatusEffect.Piloting, _pilotingIcon);
|
||||
status.ShowAlert(_pilotingAlertType, onClickAlert: OnClickAlert);
|
||||
}
|
||||
|
||||
private void OnClickAlert(ClickAlertEventArgs args)
|
||||
{
|
||||
if (args.Player.TryGetComponent(out ShuttleControllerComponent? controller))
|
||||
{
|
||||
controller.RemoveController();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -177,9 +186,9 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
/// <param name="entity">The entity to update</param>
|
||||
private void UpdateRemovedEntity(IEntity entity)
|
||||
{
|
||||
if (Owner.TryGetComponent(out ServerStatusEffectsComponent? status))
|
||||
if (Owner.TryGetComponent(out ServerAlertsComponent? status))
|
||||
{
|
||||
status.RemoveStatusEffect(StatusEffect.Piloting);
|
||||
status.ClearAlert(_pilotingAlertType);
|
||||
}
|
||||
|
||||
if (entity.TryGetComponent(out MindComponent? mind))
|
||||
@@ -211,13 +220,13 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref _pilotingIcon, "pilotingIcon", "/Textures/Interface/StatusEffects/Buckle/buckled.png");
|
||||
serializer.DataField(ref _pilotingAlertType, "pilotingAlertType", AlertType.PilotingShuttle);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
Owner.EnsureComponent<ServerStatusEffectsComponent>();
|
||||
Owner.EnsureComponent<ServerAlertsComponent>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
@@ -34,8 +31,6 @@ namespace Content.Server.GameObjects.Components.NodeContainer
|
||||
{
|
||||
node.Initialize(Owner);
|
||||
}
|
||||
|
||||
Owner.EntityManager.EventBus.SubscribeEvent<RotateEvent>(EventSource.Local, this, RotateEvent);
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
@@ -55,16 +50,5 @@ namespace Content.Server.GameObjects.Components.NodeContainer
|
||||
}
|
||||
base.OnRemove();
|
||||
}
|
||||
|
||||
private void RotateEvent(RotateEvent ev)
|
||||
{
|
||||
if (ev.Sender != Owner || ev.NewRotation == ev.OldRotation)
|
||||
return;
|
||||
|
||||
foreach (var rotatableNode in Nodes.OfType<IRotatableNode>())
|
||||
{
|
||||
rotatableNode.RotateEvent(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
}
|
||||
|
||||
if (!target.TryGetComponent(out IBody body) ||
|
||||
!body.TryGetMechanismBehaviors<StomachBehaviorComponent>(out var stomachs))
|
||||
!body.TryGetMechanismBehaviors<StomachBehavior>(out var stomachs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Body.Behavior;
|
||||
using Content.Server.GameObjects.Components.Chemistry;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
@@ -133,7 +134,7 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
var trueTarget = target ?? user;
|
||||
|
||||
if (!trueTarget.TryGetComponent(out IBody? body) ||
|
||||
!body.TryGetMechanismBehaviors<SharedStomachBehaviorComponent>(out var stomachs))
|
||||
!body.TryGetMechanismBehaviors<StomachBehavior>(out var stomachs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
@@ -70,11 +71,11 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
}
|
||||
|
||||
|
||||
public static readonly Dictionary<HungerThreshold, string> HungerThresholdImages = new Dictionary<HungerThreshold, string>
|
||||
public static readonly Dictionary<HungerThreshold, AlertType> HungerThresholdAlertTypes = new Dictionary<HungerThreshold, AlertType>
|
||||
{
|
||||
{ HungerThreshold.Overfed, "/Textures/Interface/StatusEffects/Hunger/Overfed.png" },
|
||||
{ HungerThreshold.Peckish, "/Textures/Interface/StatusEffects/Hunger/Peckish.png" },
|
||||
{ HungerThreshold.Starving, "/Textures/Interface/StatusEffects/Hunger/Starving.png" },
|
||||
{ HungerThreshold.Overfed, AlertType.Overfed },
|
||||
{ HungerThreshold.Peckish, AlertType.Peckish },
|
||||
{ HungerThreshold.Starving, AlertType.Starving },
|
||||
};
|
||||
|
||||
public void HungerThresholdEffect(bool force = false)
|
||||
@@ -89,15 +90,15 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
}
|
||||
|
||||
// Update UI
|
||||
Owner.TryGetComponent(out ServerStatusEffectsComponent statusEffectsComponent);
|
||||
Owner.TryGetComponent(out ServerAlertsComponent alertsComponent);
|
||||
|
||||
if (HungerThresholdImages.TryGetValue(_currentHungerThreshold, out var statusTexture))
|
||||
if (HungerThresholdAlertTypes.TryGetValue(_currentHungerThreshold, out var alertId))
|
||||
{
|
||||
statusEffectsComponent?.ChangeStatusEffectIcon(StatusEffect.Hunger, statusTexture);
|
||||
alertsComponent?.ShowAlert(alertId);
|
||||
}
|
||||
else
|
||||
{
|
||||
statusEffectsComponent?.RemoveStatusEffect(StatusEffect.Hunger);
|
||||
alertsComponent?.ClearAlertCategory(AlertCategory.Hunger);
|
||||
}
|
||||
|
||||
switch (_currentHungerThreshold)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
@@ -62,11 +63,11 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
{ThirstThreshold.Dead, 0.0f},
|
||||
};
|
||||
|
||||
public static readonly Dictionary<ThirstThreshold, string> ThirstThresholdImages = new Dictionary<ThirstThreshold, string>
|
||||
public static readonly Dictionary<ThirstThreshold, AlertType> ThirstThresholdAlertTypes = new Dictionary<ThirstThreshold, AlertType>
|
||||
{
|
||||
{ThirstThreshold.OverHydrated, "/Textures/Interface/StatusEffects/Thirst/OverHydrated.png"},
|
||||
{ThirstThreshold.Thirsty, "/Textures/Interface/StatusEffects/Thirst/Thirsty.png"},
|
||||
{ThirstThreshold.Parched, "/Textures/Interface/StatusEffects/Thirst/Parched.png"},
|
||||
{ThirstThreshold.OverHydrated, AlertType.Overhydrated},
|
||||
{ThirstThreshold.Thirsty, AlertType.Thirsty},
|
||||
{ThirstThreshold.Parched, AlertType.Parched},
|
||||
};
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
@@ -87,15 +88,15 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
}
|
||||
|
||||
// Update UI
|
||||
Owner.TryGetComponent(out ServerStatusEffectsComponent statusEffectsComponent);
|
||||
Owner.TryGetComponent(out ServerAlertsComponent alertsComponent);
|
||||
|
||||
if (ThirstThresholdImages.TryGetValue(_currentThirstThreshold, out var statusTexture))
|
||||
if (ThirstThresholdAlertTypes.TryGetValue(_currentThirstThreshold, out var alertId))
|
||||
{
|
||||
statusEffectsComponent?.ChangeStatusEffectIcon(StatusEffect.Thirst, statusTexture);
|
||||
alertsComponent?.ShowAlert(alertId);
|
||||
}
|
||||
else
|
||||
{
|
||||
statusEffectsComponent?.RemoveStatusEffect(StatusEffect.Thirst);
|
||||
alertsComponent?.ClearAlertCategory(AlertCategory.Thirst);
|
||||
}
|
||||
|
||||
switch (_currentThirstThreshold)
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects.Components.Access;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.GameObjects.Components.Paper;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Server.Interfaces.PDA;
|
||||
@@ -39,13 +40,19 @@ namespace Content.Server.GameObjects.Components.PDA
|
||||
[Dependency] private readonly IPDAUplinkManager _uplinkManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
[ViewVariables] private Container _idSlot = default!;
|
||||
[ViewVariables] private ContainerSlot _idSlot = default!;
|
||||
[ViewVariables] private ContainerSlot _penSlot = default!;
|
||||
|
||||
[ViewVariables] private bool _lightOn;
|
||||
[ViewVariables] private string _startingIdCard = default!;
|
||||
[ViewVariables] public bool IdSlotEmpty => _idSlot.ContainedEntities.Count < 1;
|
||||
|
||||
[ViewVariables] private string? _startingIdCard = default!;
|
||||
[ViewVariables] private string? _startingPen = default!;
|
||||
|
||||
[ViewVariables] public string? OwnerName { get; private set; }
|
||||
|
||||
[ViewVariables] public IdCardComponent? ContainedID { get; private set; }
|
||||
[ViewVariables] public bool IdSlotEmpty => _idSlot.ContainedEntity == null;
|
||||
[ViewVariables] public bool PenSlotEmpty => _penSlot.ContainedEntity == null;
|
||||
|
||||
[ViewVariables] private UplinkAccount? _syndicateUplinkAccount;
|
||||
|
||||
@@ -62,22 +69,34 @@ namespace Content.Server.GameObjects.Components.PDA
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
serializer.DataField(ref _startingIdCard, "idCard", "AssistantIDCard");
|
||||
serializer.DataField(ref _startingPen, "pen", "Pen");
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_idSlot = ContainerManagerComponent.Ensure<Container>("pda_entity_container", Owner, out var existed);
|
||||
_idSlot = ContainerManagerComponent.Ensure<ContainerSlot>("pda_entity_container", Owner);
|
||||
_penSlot = ContainerManagerComponent.Ensure<ContainerSlot>("pda_pen_slot", Owner);
|
||||
|
||||
if (UserInterface != null)
|
||||
{
|
||||
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(_startingIdCard))
|
||||
{
|
||||
var idCard = _entityManager.SpawnEntity(_startingIdCard, Owner.Transform.Coordinates);
|
||||
var idCardComponent = idCard.GetComponent<IdCardComponent>();
|
||||
_idSlot.Insert(idCardComponent.Owner);
|
||||
ContainedID = idCardComponent;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(_startingPen))
|
||||
{
|
||||
var pen = _entityManager.SpawnEntity(_startingPen, Owner.Transform.Coordinates);
|
||||
_penSlot.Insert(pen);
|
||||
}
|
||||
|
||||
UpdatePDAAppearance();
|
||||
}
|
||||
|
||||
@@ -85,23 +104,29 @@ namespace Content.Server.GameObjects.Components.PDA
|
||||
{
|
||||
switch (message.Message)
|
||||
{
|
||||
case PDARequestUpdateInterfaceMessage msg:
|
||||
case PDARequestUpdateInterfaceMessage _:
|
||||
{
|
||||
UpdatePDAUserInterface();
|
||||
break;
|
||||
}
|
||||
case PDAToggleFlashlightMessage msg:
|
||||
case PDAToggleFlashlightMessage _:
|
||||
{
|
||||
ToggleLight();
|
||||
break;
|
||||
}
|
||||
|
||||
case PDAEjectIDMessage msg:
|
||||
case PDAEjectIDMessage _:
|
||||
{
|
||||
HandleIDEjection(message.Session.AttachedEntity!);
|
||||
break;
|
||||
}
|
||||
|
||||
case PDAEjectPenMessage _:
|
||||
{
|
||||
HandlePenEjection(message.Session.AttachedEntity!);
|
||||
break;
|
||||
}
|
||||
|
||||
case PDAUplinkBuyListingMessage buyMsg:
|
||||
{
|
||||
if (!_uplinkManager.TryPurchaseItem(_syndicateUplinkAccount, buyMsg.ItemId))
|
||||
@@ -131,11 +156,11 @@ namespace Content.Server.GameObjects.Components.PDA
|
||||
var accData = new UplinkAccountData(_syndicateUplinkAccount.AccountHolder,
|
||||
_syndicateUplinkAccount.Balance);
|
||||
var listings = _uplinkManager.FetchListings.Values.ToArray();
|
||||
UserInterface?.SetState(new PDAUpdateState(_lightOn, ownerInfo, accData, listings));
|
||||
UserInterface?.SetState(new PDAUpdateState(_lightOn, !PenSlotEmpty, ownerInfo, accData, listings));
|
||||
}
|
||||
else
|
||||
{
|
||||
UserInterface?.SetState(new PDAUpdateState(_lightOn, ownerInfo));
|
||||
UserInterface?.SetState(new PDAUpdateState(_lightOn, !PenSlotEmpty, ownerInfo));
|
||||
}
|
||||
|
||||
UpdatePDAAppearance();
|
||||
@@ -150,14 +175,11 @@ namespace Content.Server.GameObjects.Components.PDA
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
|
||||
private bool TryInsertIdCard(InteractUsingEventArgs eventArgs, IdCardComponent idCardComponent)
|
||||
{
|
||||
var item = eventArgs.Using;
|
||||
|
||||
if (!item.TryGetComponent<IdCardComponent>(out var idCardComponent) || _idSlot.Contains(item))
|
||||
{
|
||||
if (_idSlot.Contains(item))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!eventArgs.User.TryGetComponent(out IHandsComponent? hands))
|
||||
{
|
||||
@@ -177,17 +199,70 @@ namespace Content.Server.GameObjects.Components.PDA
|
||||
return true;
|
||||
}
|
||||
|
||||
InsertIdCard(idCardComponent);
|
||||
|
||||
if (swap != null)
|
||||
{
|
||||
eventArgs.User.GetComponent<HandsComponent>().PutInHand(swap.GetComponent<ItemComponent>());
|
||||
hands.PutInHand(swap.GetComponent<ItemComponent>());
|
||||
}
|
||||
|
||||
InsertIdCard(idCardComponent);
|
||||
|
||||
UpdatePDAUserInterface();
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryInsertPen(InteractUsingEventArgs eventArgs)
|
||||
{
|
||||
var item = eventArgs.Using;
|
||||
if (_penSlot.Contains(item))
|
||||
return false;
|
||||
|
||||
if (!eventArgs.User.TryGetComponent(out IHandsComponent? hands))
|
||||
{
|
||||
Owner.PopupMessage(eventArgs.User, Loc.GetString("You have no hands!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
IEntity? swap = null;
|
||||
if (!PenSlotEmpty)
|
||||
{
|
||||
// Swap
|
||||
swap = _penSlot.ContainedEntities[0];
|
||||
}
|
||||
|
||||
if (!hands.Drop(item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (swap != null)
|
||||
{
|
||||
hands.PutInHand(swap.GetComponent<ItemComponent>());
|
||||
}
|
||||
|
||||
// Insert Pen
|
||||
_penSlot.Insert(item);
|
||||
|
||||
UpdatePDAUserInterface();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
|
||||
{
|
||||
var item = eventArgs.Using;
|
||||
|
||||
if (item.TryGetComponent<IdCardComponent>(out var idCardComponent))
|
||||
{
|
||||
return TryInsertIdCard(eventArgs, idCardComponent);
|
||||
}
|
||||
|
||||
if (item.HasComponent<WriteComponent>())
|
||||
{
|
||||
return TryInsertPen(eventArgs);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||
{
|
||||
if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
|
||||
@@ -273,6 +348,21 @@ namespace Content.Server.GameObjects.Components.PDA
|
||||
UpdatePDAUserInterface();
|
||||
}
|
||||
|
||||
private void HandlePenEjection(IEntity pdaUser)
|
||||
{
|
||||
if (PenSlotEmpty)
|
||||
return;
|
||||
|
||||
var pen = _penSlot.ContainedEntities[0];
|
||||
_penSlot.Remove(pen);
|
||||
|
||||
var hands = pdaUser.GetComponent<HandsComponent>();
|
||||
var itemComponent = pen.GetComponent<ItemComponent>();
|
||||
hands.PutInHandOrDrop(itemComponent);
|
||||
|
||||
UpdatePDAUserInterface();
|
||||
}
|
||||
|
||||
[Verb]
|
||||
public sealed class EjectIDVerb : Verb<PDAComponent>
|
||||
{
|
||||
@@ -294,6 +384,28 @@ namespace Content.Server.GameObjects.Components.PDA
|
||||
}
|
||||
}
|
||||
|
||||
[Verb]
|
||||
public sealed class EjectPenVerb : Verb<PDAComponent>
|
||||
{
|
||||
protected override void GetData(IEntity user, PDAComponent component, VerbData data)
|
||||
{
|
||||
if (!ActionBlockerSystem.CanInteract(user))
|
||||
{
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
}
|
||||
|
||||
data.Text = Loc.GetString("Eject Pen");
|
||||
data.Visibility = component.PenSlotEmpty ? VerbVisibility.Invisible : VerbVisibility.Visible;
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, PDAComponent component)
|
||||
{
|
||||
component.HandlePenEjection(user);
|
||||
}
|
||||
}
|
||||
|
||||
[Verb]
|
||||
public sealed class ToggleFlashlightVerb : Verb<PDAComponent>
|
||||
{
|
||||
protected override void GetData(IEntity user, PDAComponent component, VerbData data)
|
||||
|
||||
@@ -6,6 +6,8 @@ using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Rotatable
|
||||
{
|
||||
@@ -14,9 +16,21 @@ namespace Content.Server.GameObjects.Components.Rotatable
|
||||
{
|
||||
public override string Name => "Rotatable";
|
||||
|
||||
/// <summary>
|
||||
/// If true, this entity can be rotated even while anchored.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool RotateWhileAnchored { get; private set; }
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
serializer.DataField(this, x => x.RotateWhileAnchored, "rotateWhileAnchored", false);
|
||||
}
|
||||
|
||||
private void TryRotate(IEntity user, Angle angle)
|
||||
{
|
||||
if (Owner.TryGetComponent(out IPhysicsComponent physics))
|
||||
if (!RotateWhileAnchored && Owner.TryGetComponent(out IPhysicsComponent physics))
|
||||
{
|
||||
if (physics.Anchored)
|
||||
{
|
||||
@@ -33,7 +47,7 @@ namespace Content.Server.GameObjects.Components.Rotatable
|
||||
{
|
||||
protected override void GetData(IEntity user, RotatableComponent component, VerbData data)
|
||||
{
|
||||
if (!ActionBlockerSystem.CanInteract(user))
|
||||
if (!ActionBlockerSystem.CanInteract(user) || (!component.RotateWhileAnchored && component.Owner.TryGetComponent(out IPhysicsComponent physics) && physics.Anchored))
|
||||
{
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
@@ -55,7 +69,7 @@ namespace Content.Server.GameObjects.Components.Rotatable
|
||||
{
|
||||
protected override void GetData(IEntity user, RotatableComponent component, VerbData data)
|
||||
{
|
||||
if (!ActionBlockerSystem.CanInteract(user))
|
||||
if (!ActionBlockerSystem.CanInteract(user) || (!component.RotateWhileAnchored && component.Owner.TryGetComponent(out IPhysicsComponent physics) && physics.Anchored))
|
||||
{
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Buckle;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Strap;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Verbs;
|
||||
@@ -27,7 +28,7 @@ namespace Content.Server.GameObjects.Components.Strap
|
||||
private StrapPosition _position;
|
||||
private string _buckleSound = null!;
|
||||
private string _unbuckleSound = null!;
|
||||
private string _buckledIcon = null!;
|
||||
private AlertType _buckledAlertType;
|
||||
|
||||
/// <summary>
|
||||
/// The angle in degrees to rotate the player by when they get strapped
|
||||
@@ -65,10 +66,10 @@ namespace Content.Server.GameObjects.Components.Strap
|
||||
public string UnbuckleSound => _unbuckleSound;
|
||||
|
||||
/// <summary>
|
||||
/// The icon to be displayed as a status when buckled
|
||||
/// ID of the alert to show when buckled
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public string BuckledIcon => _buckledIcon;
|
||||
public AlertType BuckledAlertType => _buckledAlertType;
|
||||
|
||||
/// <summary>
|
||||
/// The sum of the sizes of all the buckled entities in this strap
|
||||
@@ -137,7 +138,7 @@ namespace Content.Server.GameObjects.Components.Strap
|
||||
serializer.DataField(ref _position, "position", StrapPosition.None);
|
||||
serializer.DataField(ref _buckleSound, "buckleSound", "/Audio/Effects/buckle.ogg");
|
||||
serializer.DataField(ref _unbuckleSound, "unbuckleSound", "/Audio/Effects/unbuckle.ogg");
|
||||
serializer.DataField(ref _buckledIcon, "buckledIcon", "/Textures/Interface/StatusEffects/Buckle/buckled.png");
|
||||
serializer.DataField(ref _buckledAlertType, "buckledAlertType", AlertType.Buckled);
|
||||
serializer.DataField(ref _rotation, "rotation", 0);
|
||||
|
||||
var defaultSize = 100;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
@@ -74,43 +75,43 @@ namespace Content.Server.GameObjects.Components.Temperature
|
||||
damageType = DamageType.Cold;
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out ServerStatusEffectsComponent status))
|
||||
if (Owner.TryGetComponent(out ServerAlertsComponent status))
|
||||
{
|
||||
switch(CurrentTemperature)
|
||||
{
|
||||
// Cold strong.
|
||||
case var t when t <= 260:
|
||||
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/cold3.png", null);
|
||||
status.ShowAlert(AlertType.Cold, 3);
|
||||
break;
|
||||
|
||||
// Cold mild.
|
||||
case var t when t <= 280 && t > 260:
|
||||
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/cold2.png", null);
|
||||
status.ShowAlert(AlertType.Cold, 2);
|
||||
break;
|
||||
|
||||
// Cold weak.
|
||||
case var t when t <= 292 && t > 280:
|
||||
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/cold1.png", null);
|
||||
status.ShowAlert(AlertType.Cold, 1);
|
||||
break;
|
||||
|
||||
// Safe.
|
||||
case var t when t <= 327 && t > 292:
|
||||
status.RemoveStatusEffect(StatusEffect.Temperature);
|
||||
status.ClearAlertCategory(AlertCategory.Temperature);
|
||||
break;
|
||||
|
||||
// Heat weak.
|
||||
case var t when t <= 335 && t > 327:
|
||||
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/hot1.png", null);
|
||||
status.ShowAlert(AlertType.Hot, 1);
|
||||
break;
|
||||
|
||||
// Heat mild.
|
||||
case var t when t <= 345 && t > 335:
|
||||
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/hot2.png", null);
|
||||
status.ShowAlert(AlertType.Hot, 2);
|
||||
break;
|
||||
|
||||
// Heat strong.
|
||||
case var t when t > 345:
|
||||
status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/hot3.png", null);
|
||||
status.ShowAlert(AlertType.Hot, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Access;
|
||||
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.VendingMachines;
|
||||
@@ -16,6 +17,7 @@ using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Timers;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -146,7 +148,7 @@ namespace Content.Server.GameObjects.Components.VendingMachines
|
||||
switch (message)
|
||||
{
|
||||
case VendingMachineEjectMessage msg:
|
||||
TryEject(msg.ID);
|
||||
TryEject(msg.ID, serverMsg.Session.AttachedEntity);
|
||||
break;
|
||||
case InventorySyncRequestMessage _:
|
||||
UserInterface?.SendMessage(new VendingMachineInventoryMessage(Inventory));
|
||||
@@ -195,6 +197,19 @@ namespace Content.Server.GameObjects.Components.VendingMachines
|
||||
EntitySystem.Get<AudioSystem>().PlayFromEntity(_soundVend, Owner, AudioParams.Default.WithVolume(-2f));
|
||||
}
|
||||
|
||||
private void TryEject(string id, IEntity? sender)
|
||||
{
|
||||
if (Owner.TryGetComponent<AccessReader>(out var accessReader))
|
||||
{
|
||||
if (sender == null || !accessReader.IsAllowed(sender))
|
||||
{
|
||||
FlickDenyAnimation();
|
||||
return;
|
||||
}
|
||||
}
|
||||
TryEject(id);
|
||||
}
|
||||
|
||||
private void FlickDenyAnimation()
|
||||
{
|
||||
TrySetVisualState(VendingMachineVisualState.Deny);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.GameObjects.Components.Movement;
|
||||
using Content.Shared;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.GameObjects.Components.Movement;
|
||||
using JetBrains.Annotations;
|
||||
@@ -44,7 +44,6 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_configurationManager.RegisterCVar("ai.maxupdates", 64);
|
||||
SubscribeLocalEvent<SleepAiMessage>(HandleAiSleep);
|
||||
|
||||
var processors = _reflectionManager.GetAllChildren<AiLogicProcessor>();
|
||||
@@ -60,7 +59,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI
|
||||
/// <inheritdoc />
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
var cvarMaxUpdates = _configurationManager.GetCVar<int>("ai.maxupdates");
|
||||
var cvarMaxUpdates = _configurationManager.GetCVar(CCVars.AIMaxUpdates);
|
||||
if (cvarMaxUpdates <= 0)
|
||||
return;
|
||||
|
||||
|
||||
@@ -328,9 +328,16 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
|
||||
return;
|
||||
}
|
||||
|
||||
var newGridId = moveEvent.NewPosition.GetGridId(_entityManager);
|
||||
if (newGridId == GridId.Invalid)
|
||||
{
|
||||
HandleEntityRemove(moveEvent.Sender);
|
||||
return;
|
||||
}
|
||||
|
||||
// The pathfinding graph is tile-based so first we'll check if they're on a different tile and if we need to update.
|
||||
// If you get entities bigger than 1 tile wide you'll need some other system so god help you.
|
||||
var newTile = _mapManager.GetGrid(moveEvent.NewPosition.GetGridId(_entityManager)).GetTileRef(moveEvent.NewPosition);
|
||||
var newTile = _mapManager.GetGrid(newGridId).GetTileRef(moveEvent.NewPosition);
|
||||
|
||||
if (oldNode == null || oldNode.TileRef == newTile)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Shared;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.GameObjects.EntitySystems.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
@@ -47,7 +48,6 @@ namespace Content.Server.GameObjects.EntitySystems.Atmos
|
||||
|
||||
_atmosphereSystem = Get<AtmosphereSystem>();
|
||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
_configManager.RegisterCVar("net.atmosdbgoverlaytickrate", 3.0f);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
@@ -89,7 +89,7 @@ namespace Content.Server.GameObjects.EntitySystems.Atmos
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
AccumulatedFrameTime += frameTime;
|
||||
_updateCooldown = 1 / _configManager.GetCVar<float>("net.atmosdbgoverlaytickrate");
|
||||
_updateCooldown = 1 / _configManager.GetCVar(CCVars.NetAtmosDebugOverlayTickRate);
|
||||
|
||||
if (AccumulatedFrameTime < _updateCooldown)
|
||||
{
|
||||
|
||||
@@ -4,12 +4,14 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Content.Server.GameObjects.Components.Atmos;
|
||||
using Content.Shared;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.GameObjects.EntitySystems.Atmos;
|
||||
using Content.Shared.GameTicking;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
@@ -65,7 +67,6 @@ namespace Content.Server.GameObjects.EntitySystems.Atmos
|
||||
_atmosphereSystem = Get<AtmosphereSystem>();
|
||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
_mapManager.OnGridRemoved += OnGridRemoved;
|
||||
_configManager.RegisterCVar("net.gasoverlaytickrate", 3.0f);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
@@ -228,14 +229,14 @@ namespace Content.Server.GameObjects.EntitySystems.Atmos
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
AccumulatedFrameTime += frameTime;
|
||||
_updateCooldown = 1 / _configManager.GetCVar<float>("net.gasoverlaytickrate");
|
||||
_updateCooldown = 1 / _configManager.GetCVar(CCVars.NetGasOverlayTickRate);
|
||||
|
||||
if (AccumulatedFrameTime < _updateCooldown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_updateRange = _configManager.GetCVar<float>("net.maxupdaterange") + RangeOffset;
|
||||
_updateRange = _configManager.GetCVar(CVars.NetMaxUpdateRange) + RangeOffset;
|
||||
|
||||
// TODO: So in the worst case scenario we still have to send a LOT of tile data per tick if there's a fire.
|
||||
// If we go with say 15 tile radius then we have up to 900 tiles to update per tick.
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
using Content.Server.GameObjects.Components.Buckle;
|
||||
#nullable enable
|
||||
using Content.Server.GameObjects.Components.Buckle;
|
||||
using Content.Server.GameObjects.Components.Strap;
|
||||
using Content.Server.GameObjects.EntitySystems.Click;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects.EntitySystemMessages;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
@@ -15,13 +20,84 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
UpdatesAfter.Add(typeof(InteractionSystem));
|
||||
UpdatesAfter.Add(typeof(InputSystem));
|
||||
|
||||
SubscribeLocalEvent<MoveEvent>(MoveEvent);
|
||||
SubscribeLocalEvent<EntInsertedIntoContainerMessage>(ContainerModified);
|
||||
SubscribeLocalEvent<EntRemovedFromContainerMessage>(ContainerModified);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
public override void Shutdown()
|
||||
{
|
||||
foreach (var buckle in ComponentManager.EntityQuery<BuckleComponent>())
|
||||
base.Shutdown();
|
||||
|
||||
UnsubscribeLocalEvent<MoveEvent>();
|
||||
}
|
||||
|
||||
private void MoveEvent(MoveEvent ev)
|
||||
{
|
||||
buckle.Update();
|
||||
if (!ev.Sender.TryGetComponent(out BuckleComponent? buckle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var strap = buckle.BuckledTo;
|
||||
|
||||
if (strap == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var strapPosition = strap.Owner.Transform.Coordinates.Offset(buckle.BuckleOffset);
|
||||
|
||||
if (ev.NewPosition.InRange(EntityManager, strapPosition, 0.2f))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
buckle.TryUnbuckle(buckle.Owner, true);
|
||||
}
|
||||
|
||||
private void ContainerModified(ContainerModifiedMessage message)
|
||||
{
|
||||
// Not returning is necessary in case an entity has both a buckle and strap component
|
||||
if (message.Entity.TryGetComponent(out BuckleComponent? buckle))
|
||||
{
|
||||
ContainerModifiedReAttach(buckle, buckle.BuckledTo);
|
||||
}
|
||||
|
||||
if (message.Entity.TryGetComponent(out StrapComponent? strap))
|
||||
{
|
||||
foreach (var buckledEntity in strap.BuckledEntities)
|
||||
{
|
||||
if (!buckledEntity.TryGetComponent(out BuckleComponent? buckled))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ContainerModifiedReAttach(buckled, strap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ContainerModifiedReAttach(BuckleComponent buckle, StrapComponent? strap)
|
||||
{
|
||||
if (strap == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var contained = ContainerHelpers.TryGetContainer(buckle.Owner, out var ownContainer);
|
||||
var strapContained = ContainerHelpers.TryGetContainer(strap.Owner, out var strapContainer);
|
||||
|
||||
if (contained != strapContained || ownContainer != strapContainer)
|
||||
{
|
||||
buckle.TryUnbuckle(buckle.Owner, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!contained)
|
||||
{
|
||||
buckle.ReAttach(strap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click
|
||||
private bool HandleWideAttack(ICommonSession session, EntityCoordinates coords, EntityUid uid)
|
||||
{
|
||||
// client sanitization
|
||||
if (!_mapManager.GridExists(coords.GetGridId(_entityManager)))
|
||||
if (!coords.IsValid(_entityManager))
|
||||
{
|
||||
Logger.InfoS("system.interaction", $"Invalid Coordinates: client={session}, coords={coords}");
|
||||
return true;
|
||||
@@ -211,7 +211,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click
|
||||
private bool HandleClientUseItemInHand(ICommonSession session, EntityCoordinates coords, EntityUid uid)
|
||||
{
|
||||
// client sanitization
|
||||
if (!_mapManager.GridExists(coords.GetGridId(_entityManager)))
|
||||
if (!coords.IsValid(_entityManager))
|
||||
{
|
||||
Logger.InfoS("system.interaction", $"Invalid Coordinates: client={session}, coords={coords}");
|
||||
return true;
|
||||
@@ -242,7 +242,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click
|
||||
private bool HandleTryPullObject(ICommonSession session, EntityCoordinates coords, EntityUid uid)
|
||||
{
|
||||
// client sanitization
|
||||
if (!_mapManager.GridExists(coords.GetGridId(_entityManager)))
|
||||
if (!coords.IsValid(_entityManager))
|
||||
{
|
||||
Logger.InfoS("system.interaction", $"Invalid Coordinates for pulling: client={session}, coords={coords}");
|
||||
return false;
|
||||
@@ -303,7 +303,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click
|
||||
}
|
||||
|
||||
// Verify player is on the same map as the entity he clicked on
|
||||
if (_mapManager.GetGrid(coordinates.GetGridId(EntityManager)).ParentMapId != playerTransform.MapID)
|
||||
if (coordinates.GetMapId(_entityManager) != playerTransform.MapID)
|
||||
{
|
||||
Logger.WarningS("system.interaction",
|
||||
$"Player named {player.Name} clicked on a map he isn't located on");
|
||||
|
||||
@@ -20,6 +20,7 @@ using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -306,8 +307,18 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
private async void HandleStartItemConstruction(TryStartItemConstructionMessage ev, EntitySessionEventArgs args)
|
||||
{
|
||||
var constructionPrototype = _prototypeManager.Index<ConstructionPrototype>(ev.PrototypeName);
|
||||
var constructionGraph = _prototypeManager.Index<ConstructionGraphPrototype>(constructionPrototype.Graph);
|
||||
if (!_prototypeManager.TryIndex(ev.PrototypeName, out ConstructionPrototype constructionPrototype))
|
||||
{
|
||||
Logger.Error($"Tried to start construction of invalid recipe '{ev.PrototypeName}'!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_prototypeManager.TryIndex(constructionPrototype.Graph, out ConstructionGraphPrototype constructionGraph))
|
||||
{
|
||||
Logger.Error($"Invalid construction graph '{constructionPrototype.Graph}' in recipe '{ev.PrototypeName}'!");
|
||||
return;
|
||||
}
|
||||
|
||||
var startNode = constructionGraph.Nodes[constructionPrototype.StartNode];
|
||||
var targetNode = constructionGraph.Nodes[constructionPrototype.TargetNode];
|
||||
var pathFind = constructionGraph.Path(startNode.Name, targetNode.Name);
|
||||
@@ -352,8 +363,20 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
private async void HandleStartStructureConstruction(TryStartStructureConstructionMessage ev, EntitySessionEventArgs args)
|
||||
{
|
||||
var constructionPrototype = _prototypeManager.Index<ConstructionPrototype>(ev.PrototypeName);
|
||||
var constructionGraph = _prototypeManager.Index<ConstructionGraphPrototype>(constructionPrototype.Graph);
|
||||
if (!_prototypeManager.TryIndex(ev.PrototypeName, out ConstructionPrototype constructionPrototype))
|
||||
{
|
||||
Logger.Error($"Tried to start construction of invalid recipe '{ev.PrototypeName}'!");
|
||||
RaiseNetworkEvent(new AckStructureConstructionMessage(ev.Ack));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_prototypeManager.TryIndex(constructionPrototype.Graph, out ConstructionGraphPrototype constructionGraph))
|
||||
{
|
||||
Logger.Error($"Invalid construction graph '{constructionPrototype.Graph}' in recipe '{ev.PrototypeName}'!");
|
||||
RaiseNetworkEvent(new AckStructureConstructionMessage(ev.Ack));
|
||||
return;
|
||||
}
|
||||
|
||||
var startNode = constructionGraph.Nodes[constructionPrototype.StartNode];
|
||||
var targetNode = constructionGraph.Nodes[constructionPrototype.TargetNode];
|
||||
var pathFind = constructionGraph.Path(startNode.Name, targetNode.Name);
|
||||
|
||||
@@ -1,27 +1,16 @@
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems.DeviceNetwork
|
||||
{
|
||||
public class DeviceNetworkSystem : EntitySystem
|
||||
internal sealed class DeviceNetworkSystem : EntitySystem
|
||||
{
|
||||
private IDeviceNetwork _network;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_network = IoCManager.Resolve<IDeviceNetwork>();
|
||||
}
|
||||
[Dependency] private readonly IDeviceNetwork _network = default!;
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
if (_network == null)
|
||||
return;
|
||||
//(ノ°Д°)ノ︵ ┻━┻
|
||||
_network.Update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class HeartSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
UpdatesBefore.Add(typeof(MetabolismSystem));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var heart in ComponentManager.EntityQuery<SharedHeartBehaviorComponent>())
|
||||
{
|
||||
heart.Update(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using Content.Shared.GameObjects.Components.Body.Behavior;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class LungSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
UpdatesBefore.Add(typeof(MetabolismSystem));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var lung in ComponentManager.EntityQuery<SharedLungBehaviorComponent>())
|
||||
{
|
||||
lung.Update(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.NodeContainer;
|
||||
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class NodeContainerSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<RotateEvent>(RotateEvent);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
UnsubscribeLocalEvent<RotateEvent>();
|
||||
}
|
||||
|
||||
private void RotateEvent(RotateEvent ev)
|
||||
{
|
||||
if (!ev.Sender.TryGetComponent(out NodeContainerComponent container))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev.NewRotation == ev.OldRotation)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var rotatableNode in container.Nodes.OfType<IRotatableNode>())
|
||||
{
|
||||
rotatableNode.RotateEvent(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using Content.Server.Players;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Utility;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects.Components;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
@@ -75,9 +76,9 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
public bool InRange(EntityCoordinates from, EntityCoordinates to)
|
||||
public bool InRange(IEntity pointer, EntityCoordinates coordinates)
|
||||
{
|
||||
return from.InRange(EntityManager, to, 15);
|
||||
return pointer.InRangeUnOccluded(coordinates, 15, e => e == pointer);
|
||||
}
|
||||
|
||||
public bool TryPoint(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
|
||||
@@ -100,7 +101,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!InRange(coords, player.Transform.Coordinates))
|
||||
if (!InRange(player, coords))
|
||||
{
|
||||
player.PopupMessage(Loc.GetString("You can't reach there!"));
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.GameObjects.Components.MachineLinking;
|
||||
using Content.Server.GameObjects.EntitySystems.Click;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.Interfaces.Console;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
@@ -27,7 +28,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
_transmitters = new Dictionary<NetUserId, SignalTransmitterComponent>();
|
||||
}
|
||||
|
||||
public void SignalLinkerKeybind(NetUserId id, bool? enable)
|
||||
public bool SignalLinkerKeybind(NetUserId id, bool? enable)
|
||||
{
|
||||
if (enable == null)
|
||||
{
|
||||
@@ -38,13 +39,13 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
if (_transmitters.ContainsKey(id))
|
||||
{
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_transmitters.Count == 0)
|
||||
{
|
||||
CommandBinds.Builder
|
||||
.Bind(EngineKeyFunctions.Use, new PointerInputCmdHandler(HandleUse))
|
||||
.BindBefore(EngineKeyFunctions.Use, new PointerInputCmdHandler(HandleUse), typeof(InteractionSystem))
|
||||
.Register<SignalLinkerSystem>();
|
||||
}
|
||||
|
||||
@@ -55,7 +56,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
if (!_transmitters.ContainsKey(id))
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
_transmitters.Remove(id);
|
||||
@@ -64,6 +65,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
CommandBinds.Unregister<SignalLinkerSystem>();
|
||||
}
|
||||
}
|
||||
return enable == true;
|
||||
}
|
||||
|
||||
private bool HandleUse(ICommonSession session, EntityCoordinates coords, EntityUid uid)
|
||||
@@ -132,7 +134,8 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
return;
|
||||
}
|
||||
|
||||
system.SignalLinkerKeybind(player.UserId, enable);
|
||||
var ret = system.SignalLinkerKeybind(player.UserId, enable);
|
||||
shell.SendText(player, ret ? "Enabled" : "Disabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@ using System.Text;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Server.StationEvents;
|
||||
using Content.Shared;
|
||||
using Content.Shared.GameTicking;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.Console;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.Configuration;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
@@ -23,6 +25,7 @@ namespace Content.Server.GameObjects.EntitySystems.StationEvents
|
||||
// Somewhat based off of TG's implementation of events
|
||||
public sealed class StationEventSystem : EntitySystem, IResettingEntitySystem
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
[Dependency] private readonly IServerNetManager _netManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
||||
@@ -164,6 +167,9 @@ namespace Content.Server.GameObjects.EntitySystems.StationEvents
|
||||
_stationEvents.Add(stationEvent);
|
||||
}
|
||||
|
||||
// Can't just check debug / release for a default given mappers need to use release mode
|
||||
// As such we'll always pause it by default.
|
||||
_configurationManager.OnValueChanged(CCVars.EventsEnabled, value => Enabled = value, true);
|
||||
_netManager.RegisterNetMessage<MsgGetStationEvents>(nameof(MsgGetStationEvents), GetEventReceived);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.EntitySystemMessages.Gravity;
|
||||
using Content.Shared.GameTicking;
|
||||
@@ -19,7 +20,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
|
||||
private readonly Dictionary<GridId, List<ServerStatusEffectsComponent>> _statuses = new Dictionary<GridId, List<ServerStatusEffectsComponent>>();
|
||||
private readonly Dictionary<GridId, List<ServerAlertsComponent>> _alerts = new Dictionary<GridId, List<ServerAlertsComponent>>();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -31,15 +32,15 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_statuses.Clear();
|
||||
_alerts.Clear();
|
||||
}
|
||||
|
||||
public void AddStatus(ServerStatusEffectsComponent status)
|
||||
public void AddAlert(ServerAlertsComponent status)
|
||||
{
|
||||
var gridId = status.Owner.Transform.GridID;
|
||||
var statuses = _statuses.GetOrNew(gridId);
|
||||
var alerts = _alerts.GetOrNew(gridId);
|
||||
|
||||
statuses.Add(status);
|
||||
alerts.Add(status);
|
||||
|
||||
if (_mapManager.TryGetGrid(status.Owner.Transform.GridID, out var grid))
|
||||
{
|
||||
@@ -54,10 +55,10 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveStatus(ServerStatusEffectsComponent status)
|
||||
public void RemoveAlert(ServerAlertsComponent status)
|
||||
{
|
||||
var grid = status.Owner.Transform.GridID;
|
||||
if (!_statuses.TryGetValue(grid, out var statuses))
|
||||
if (!_alerts.TryGetValue(grid, out var statuses))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -67,7 +68,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
private void GravityChanged(GravityChangedMessage ev)
|
||||
{
|
||||
if (!_statuses.TryGetValue(ev.Grid.Index, out var statuses))
|
||||
if (!_alerts.TryGetValue(ev.Grid.Index, out var statuses))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -88,19 +89,19 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
private void AddWeightless(ServerStatusEffectsComponent status)
|
||||
private void AddWeightless(ServerAlertsComponent status)
|
||||
{
|
||||
status.ChangeStatusEffect(StatusEffect.Weightless, "/Textures/Interface/StatusEffects/Weightless/weightless.png", null);
|
||||
status.ShowAlert(AlertType.Weightless);
|
||||
}
|
||||
|
||||
private void RemoveWeightless(ServerStatusEffectsComponent status)
|
||||
private void RemoveWeightless(ServerAlertsComponent status)
|
||||
{
|
||||
status.RemoveStatusEffect(StatusEffect.Weightless);
|
||||
status.ClearAlert(AlertType.Weightless);
|
||||
}
|
||||
|
||||
private void EntParentChanged(EntParentChangedMessage ev)
|
||||
{
|
||||
if (!ev.Entity.TryGetComponent(out ServerStatusEffectsComponent status))
|
||||
if (!ev.Entity.TryGetComponent(out ServerAlertsComponent status))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -110,14 +111,14 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
var oldGrid = mapGrid.GridIndex;
|
||||
|
||||
if (_statuses.TryGetValue(oldGrid, out var oldStatuses))
|
||||
if (_alerts.TryGetValue(oldGrid, out var oldStatuses))
|
||||
{
|
||||
oldStatuses.Remove(status);
|
||||
}
|
||||
}
|
||||
|
||||
var newGrid = ev.Entity.Transform.GridID;
|
||||
var newStatuses = _statuses.GetOrNew(newGrid);
|
||||
var newStatuses = _alerts.GetOrNew(newGrid);
|
||||
|
||||
newStatuses.Add(status);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Content.Server.Interfaces.Chat;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Server.Mobs.Roles.Suspicion;
|
||||
using Content.Server.Players;
|
||||
using Content.Shared;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.GameObjects.Components.PDA;
|
||||
using Content.Shared.Roles;
|
||||
@@ -44,20 +45,12 @@ namespace Content.Server.GameTicking.GamePresets
|
||||
private static string TraitorID = "SuspicionTraitor";
|
||||
private static string InnocentID = "SuspicionInnocent";
|
||||
|
||||
public static void RegisterCVars(IConfigurationManager cfg)
|
||||
{
|
||||
cfg.RegisterCVar("game.suspicion_min_players", 5);
|
||||
cfg.RegisterCVar("game.suspicion_min_traitors", 2);
|
||||
cfg.RegisterCVar("game.suspicion_players_per_traitor", 5);
|
||||
cfg.RegisterCVar("game.suspicion_starting_balance", 20);
|
||||
}
|
||||
|
||||
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers, bool force = false)
|
||||
{
|
||||
MinPlayers = _cfg.GetCVar<int>("game.suspicion_min_players");
|
||||
MinTraitors = _cfg.GetCVar<int>("game.suspicion_min_traitors");
|
||||
PlayersPerTraitor = _cfg.GetCVar<int>("game.suspicion_players_per_traitor");
|
||||
TraitorStartingBalance = _cfg.GetCVar<int>("game.suspicion_starting_balance");
|
||||
MinPlayers = _cfg.GetCVar(CCVars.GameSuspicionMinPlayers);
|
||||
MinTraitors = _cfg.GetCVar(CCVars.GameSuspicionMinTraitors);
|
||||
PlayersPerTraitor = _cfg.GetCVar(CCVars.GameSuspicionPlayersPerTraitor);
|
||||
TraitorStartingBalance = _cfg.GetCVar(CCVars.GameSuspicionStartingBalance);
|
||||
|
||||
if (!force && readyPlayers.Count < MinPlayers)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Threading;
|
||||
using Content.Server.Interfaces.Chat;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Shared;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Server.Player;
|
||||
@@ -56,7 +57,7 @@ namespace Content.Server.GameTicking.GameRules
|
||||
{
|
||||
_checkTimerCancel = null;
|
||||
|
||||
if (!_cfg.GetCVar<bool>("game.enablewin"))
|
||||
if (!_cfg.GetCVar(CCVars.GameLobbyEnableWin))
|
||||
return;
|
||||
|
||||
IPlayerSession winner = null;
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Server.Interfaces.Chat;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Server.Mobs.Roles.Suspicion;
|
||||
using Content.Server.Players;
|
||||
using Content.Shared;
|
||||
using Content.Shared.GameObjects.Components.Damage;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
@@ -58,7 +59,7 @@ namespace Content.Server.GameTicking.GameRules
|
||||
|
||||
private void _checkWinConditions()
|
||||
{
|
||||
if (!_cfg.GetCVar<bool>("game.enablewin"))
|
||||
if (!_cfg.GetCVar(CCVars.GameLobbyEnableWin))
|
||||
return;
|
||||
|
||||
var traitorsAlive = 0;
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace Content.Server.GameTicking
|
||||
|
||||
[ViewVariables] private bool DisallowLateJoin { get; set; } = false;
|
||||
|
||||
[ViewVariables] private bool LobbyEnabled => _configurationManager.GetCVar<bool>("game.lobbyenabled");
|
||||
[ViewVariables] private bool LobbyEnabled => _configurationManager.GetCVar(CCVars.GameLobbyEnabled);
|
||||
|
||||
[ViewVariables] private bool _updateOnRoundEnd;
|
||||
private CancellationTokenSource _updateShutdownCts;
|
||||
@@ -120,7 +120,7 @@ namespace Content.Server.GameTicking
|
||||
public event Action<GameRuleAddedEventArgs> OnRuleAdded;
|
||||
|
||||
private TimeSpan LobbyDuration =>
|
||||
TimeSpan.FromSeconds(_configurationManager.GetCVar<int>("game.lobbyduration"));
|
||||
TimeSpan.FromSeconds(_configurationManager.GetCVar(CCVars.GameLobbyDuration));
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -128,8 +128,6 @@ namespace Content.Server.GameTicking
|
||||
|
||||
DebugTools.Assert(!_initialized);
|
||||
|
||||
PresetSuspicion.RegisterCVars(_configurationManager);
|
||||
|
||||
_netManager.RegisterNetMessage<MsgTickerJoinLobby>(nameof(MsgTickerJoinLobby));
|
||||
_netManager.RegisterNetMessage<MsgTickerJoinGame>(nameof(MsgTickerJoinGame));
|
||||
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus));
|
||||
@@ -287,9 +285,9 @@ namespace Content.Server.GameTicking
|
||||
|
||||
if (!preset.Start(assignedJobs.Keys.ToList(), force))
|
||||
{
|
||||
if (_configurationManager.GetCVar<bool>("game.fallbackenabled"))
|
||||
if (_configurationManager.GetCVar(CCVars.GameLobbyFallbackEnabled))
|
||||
{
|
||||
SetStartPreset(_configurationManager.GetCVar<string>("game.fallbackpreset"));
|
||||
SetStartPreset(_configurationManager.GetCVar(CCVars.GameLobbyFallbackPreset));
|
||||
var newPreset = MakeGamePreset(profiles);
|
||||
_chatManager.DispatchServerAnnouncement(
|
||||
$"Failed to start {preset.ModeTitle} mode! Defaulting to {newPreset.ModeTitle}...");
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Content.Server.GlobalVerbs
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EntitySystem.Get<PointingSystem>().InRange(user.Transform.Coordinates, target.Transform.Coordinates))
|
||||
if (!EntitySystem.Get<PointingSystem>().InRange(user, target.Transform.Coordinates))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.Chat;
|
||||
using Content.Shared;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Newtonsoft.Json;
|
||||
using Robust.Server.Interfaces.ServerStatus;
|
||||
@@ -27,9 +28,6 @@ namespace Content.Server
|
||||
|
||||
void IPostInjectInit.PostInject()
|
||||
{
|
||||
_configurationManager.RegisterCVar<string>("status.mommiurl", null);
|
||||
_configurationManager.RegisterCVar<string>("status.mommipassword", null);
|
||||
|
||||
_statusHost.AddHandler(_handleChatPost);
|
||||
}
|
||||
|
||||
@@ -46,8 +44,8 @@ namespace Content.Server
|
||||
|
||||
private async Task _sendMessageInternal(string type, object messageObject)
|
||||
{
|
||||
var url = _configurationManager.GetCVar<string>("status.mommiurl");
|
||||
var password = _configurationManager.GetCVar<string>("status.mommipassword");
|
||||
var url = _configurationManager.GetCVar(CCVars.StatusMoMMIUrl);
|
||||
var password = _configurationManager.GetCVar(CCVars.StatusMoMMIPassword);
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
return;
|
||||
@@ -83,7 +81,7 @@ namespace Content.Server
|
||||
return false;
|
||||
}
|
||||
|
||||
var password = _configurationManager.GetCVar<string>("status.mommipassword");
|
||||
var password = _configurationManager.GetCVar(CCVars.StatusMoMMIPassword);
|
||||
|
||||
OOCPostMessage message = null;
|
||||
try
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user