Merge branch 'master' into 2020-08-19-firelocks

This commit is contained in:
Víctor Aguilera Puerto
2020-08-21 16:51:50 +02:00
212 changed files with 3718 additions and 462 deletions

View File

@@ -247,13 +247,17 @@ namespace Content.Client.Chat
case OOCAlias:
{
var conInput = text.Substring(1);
if (string.IsNullOrWhiteSpace(conInput))
return;
_console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\"");
break;
}
case AdminChatAlias:
{
var conInput = text.Substring(1);
if(_groupController.CanCommand("asay")){
if (string.IsNullOrWhiteSpace(conInput))
return;
if (_groupController.CanCommand("asay")){
_console.ProcessCommand($"asay \"{CommandParsing.Escape(conInput)}\"");
}
else
@@ -265,6 +269,8 @@ namespace Content.Client.Chat
case MeAlias:
{
var conInput = text.Substring(1);
if (string.IsNullOrWhiteSpace(conInput))
return;
_console.ProcessCommand($"me \"{CommandParsing.Escape(conInput)}\"");
break;
}

View File

@@ -106,13 +106,13 @@ namespace Content.Client.Chat
}
// Lerp to our new vertical offset if it's been modified.
if (FloatMath.CloseTo(_verticalOffsetAchieved - VerticalOffset, 0, 0.1))
if (MathHelper.CloseTo(_verticalOffsetAchieved - VerticalOffset, 0, 0.1))
{
_verticalOffsetAchieved = VerticalOffset;
}
else
{
_verticalOffsetAchieved = FloatMath.Lerp(_verticalOffsetAchieved, VerticalOffset, 10 * args.DeltaSeconds);
_verticalOffsetAchieved = MathHelper.Lerp(_verticalOffsetAchieved, VerticalOffset, 10 * args.DeltaSeconds);
}
var worldPos = _senderEntity.Transform.WorldPosition;
@@ -122,7 +122,7 @@ namespace Content.Client.Chat
var screenPos = lowerCenter - (Width / 2, ContentHeight + _verticalOffsetAchieved);
LayoutContainer.SetPosition(this, screenPos);
var height = FloatMath.Clamp(lowerCenter.Y - screenPos.Y, 0, ContentHeight);
var height = MathHelper.Clamp(lowerCenter.Y - screenPos.Y, 0, ContentHeight);
LayoutContainer.SetSize(this, (Size.X, height));
}

View File

@@ -33,7 +33,7 @@ namespace Content.Client.GameObjects.Components.Body
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession? session = null)
{
if (!Owner.TryGetComponent(out ISpriteComponent sprite))
if (!Owner.TryGetComponent(out ISpriteComponent? sprite))
{
return;
}
@@ -50,7 +50,7 @@ namespace Content.Client.GameObjects.Components.Body
if (!partRemoved.Dropped.HasValue ||
!_entityManager.TryGetEntity(partRemoved.Dropped.Value, out var entity) ||
!entity.TryGetComponent(out ISpriteComponent droppedSprite))
!entity.TryGetComponent(out ISpriteComponent? droppedSprite))
{
break;
}

View File

@@ -37,7 +37,7 @@ namespace Content.Client.GameObjects.Components
/// <returns>True if the click worked, false otherwise.</returns>
public bool CheckClick(Vector2 worldPos, out int drawDepth, out uint renderOrder)
{
if (!Owner.TryGetComponent(out ISpriteComponent sprite) || !sprite.Visible)
if (!Owner.TryGetComponent(out ISpriteComponent? sprite) || !sprite.Visible)
{
drawDepth = default;
renderOrder = default;

View File

@@ -0,0 +1,67 @@
#nullable enable
using JetBrains.Annotations;
using Robust.Client.GameObjects.Components.UserInterface;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.Localization;
using static Content.Shared.GameObjects.Components.Disposal.SharedDisposalRouterComponent;
namespace Content.Client.GameObjects.Components.Disposal
{
/// <summary>
/// Initializes a <see cref="DisposalRouterWindow"/> and updates it when new server messages are received.
/// </summary>
[UsedImplicitly]
public class DisposalRouterBoundUserInterface : BoundUserInterface
{
private DisposalRouterWindow? _window;
public DisposalRouterBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = new DisposalRouterWindow();
_window.OpenCentered();
_window.OnClose += Close;
_window.Confirm.OnPressed += _ => ButtonPressed(UiAction.Ok, _window.TagInput.Text);
_window.TagInput.OnTextEntered += args => ButtonPressed(UiAction.Ok, args.Text);
}
private void ButtonPressed(UiAction action, string tag)
{
SendMessage(new UiActionMessage(action, tag));
_window?.Close();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (!(state is DisposalRouterUserInterfaceState cast))
{
return;
}
_window?.UpdateState(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window?.Dispose();
}
}
}
}

View File

@@ -0,0 +1,51 @@
using Content.Shared.GameObjects.Components.Disposal;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using static Content.Shared.GameObjects.Components.Disposal.SharedDisposalRouterComponent;
namespace Content.Client.GameObjects.Components.Disposal
{
/// <summary>
/// Client-side UI used to control a <see cref="SharedDisposalRouterComponent"/>
/// </summary>
public class DisposalRouterWindow : SS14Window
{
public readonly LineEdit TagInput;
public readonly Button Confirm;
protected override Vector2? CustomSize => (400, 80);
public DisposalRouterWindow()
{
Title = Loc.GetString("Disposal Router");
Contents.AddChild(new VBoxContainer
{
Children =
{
new Label {Text = Loc.GetString("Tags:")},
new Control {CustomMinimumSize = (0, 10)},
new HBoxContainer
{
Children =
{
(TagInput = new LineEdit {SizeFlagsHorizontal = SizeFlags.Expand, CustomMinimumSize = (320, 0),
ToolTip = Loc.GetString("A comma separated list of tags"), IsValid = tags => TagRegex.IsMatch(tags)}),
new Control {CustomMinimumSize = (10, 0)},
(Confirm = new Button {Text = Loc.GetString("Confirm")})
}
}
}
});
}
public void UpdateState(DisposalRouterUserInterfaceState state)
{
TagInput.Text = state.Tags;
}
}
}

View File

@@ -0,0 +1,67 @@
#nullable enable
using JetBrains.Annotations;
using Robust.Client.GameObjects.Components.UserInterface;
using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.Localization;
using static Content.Shared.GameObjects.Components.Disposal.SharedDisposalTaggerComponent;
namespace Content.Client.GameObjects.Components.Disposal
{
/// <summary>
/// Initializes a <see cref="DisposalTaggerWindow"/> and updates it when new server messages are received.
/// </summary>
[UsedImplicitly]
public class DisposalTaggerBoundUserInterface : BoundUserInterface
{
private DisposalTaggerWindow? _window;
public DisposalTaggerBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = new DisposalTaggerWindow();
_window.OpenCentered();
_window.OnClose += Close;
_window.Confirm.OnPressed += _ => ButtonPressed(UiAction.Ok, _window.TagInput.Text);
_window.TagInput.OnTextEntered += args => ButtonPressed(UiAction.Ok, args.Text);
}
private void ButtonPressed(UiAction action, string tag)
{
SendMessage(new UiActionMessage(action, tag));
_window?.Close();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (!(state is DisposalTaggerUserInterfaceState cast))
{
return;
}
_window?.UpdateState(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window?.Dispose();
}
}
}
}

View File

@@ -0,0 +1,51 @@
using Content.Shared.GameObjects.Components.Disposal;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using static Content.Shared.GameObjects.Components.Disposal.SharedDisposalTaggerComponent;
namespace Content.Client.GameObjects.Components.Disposal
{
/// <summary>
/// Client-side UI used to control a <see cref="SharedDisposalTaggerComponent"/>
/// </summary>
public class DisposalTaggerWindow : SS14Window
{
public readonly LineEdit TagInput;
public readonly Button Confirm;
protected override Vector2? CustomSize => (400, 80);
public DisposalTaggerWindow()
{
Title = Loc.GetString("Disposal Tagger");
Contents.AddChild(new VBoxContainer
{
Children =
{
new Label {Text = Loc.GetString("Tag:")},
new Control {CustomMinimumSize = (0, 10)},
new HBoxContainer
{
Children =
{
(TagInput = new LineEdit {SizeFlagsHorizontal = SizeFlags.Expand, CustomMinimumSize = (320, 0),
IsValid = tag => TagRegex.IsMatch(tag)}),
new Control {CustomMinimumSize = (10, 0)},
(Confirm = new Button {Text = Loc.GetString("Confirm")})
}
}
}
});
}
public void UpdateState(DisposalTaggerUserInterfaceState state)
{
TagInput.Text = state.Tag;
}
}
}

View File

@@ -113,12 +113,12 @@ namespace Content.Client.GameObjects.Components.Disposal
if (normalized <= leftSideSize)
{
normalized /= leftSideSize; // Adjust range to 0.0 to 1.0
finalHue = FloatMath.Lerp(leftHue, middleHue, normalized);
finalHue = MathHelper.Lerp(leftHue, middleHue, normalized);
}
else
{
normalized = (normalized - leftSideSize) / rightSideSize; // Adjust range to 0.0 to 1.0.
finalHue = FloatMath.Lerp(middleHue, rightHue, normalized);
finalHue = MathHelper.Lerp(middleHue, rightHue, normalized);
}
// Check if null first to avoid repeatedly creating this.

View File

@@ -78,7 +78,7 @@ namespace Content.Client.GameObjects.Components
int level;
if (FloatMath.CloseTo(charge, 0))
if (MathHelper.CloseTo(charge, 0))
{
level = 0;
}

View File

@@ -148,7 +148,7 @@ namespace Content.Client.GameObjects.Components.Items
return;
}
if (!entity.TryGetComponent(out ItemComponent item)) return;
if (!entity.TryGetComponent(out ItemComponent? item)) return;
var maybeInHands = item.GetInHandStateInfo(hand.Location);

View File

@@ -243,7 +243,7 @@ namespace Content.Client.GameObjects.Components
if (int.TryParse(ev.Text, out var result))
{
result = FloatMath.Clamp(result, 0, byte.MaxValue);
result = MathHelper.Clamp(result, 0, byte.MaxValue);
_ignoreEvents = true;
_colorValue = (byte) result;

View File

@@ -22,6 +22,7 @@ namespace Content.Client.GameObjects.Components.MedicalScanner
Title = Owner.Owner.Name,
};
_window.OnClose += Close;
_window.ScanButton.OnPressed += _ => SendMessage(new UiButtonPressedMessage(UiButton.ScanDNA));
_window.OpenCentered();
}

View File

@@ -12,18 +12,38 @@ namespace Content.Client.GameObjects.Components.MedicalScanner
{
public class MedicalScannerWindow : SS14Window
{
public readonly Button ScanButton;
private readonly Label _diagnostics;
protected override Vector2? CustomSize => (485, 90);
public MedicalScannerWindow()
{
Contents.AddChild(new VBoxContainer
{
Children =
{
(ScanButton = new Button
{
Text = "Scan and Save DNA"
}),
(_diagnostics = new Label
{
Text = ""
})
}
});
}
public void Populate(MedicalScannerBoundUserInterfaceState state)
{
Contents.RemoveAllChildren();
var text = new StringBuilder();
if (!state.Entity.HasValue ||
!state.HasDamage() ||
!IoCManager.Resolve<IEntityManager>().TryGetEntity(state.Entity.Value, out var entity))
{
text.Append(Loc.GetString("No patient data."));
_diagnostics.Text = Loc.GetString("No patient data.");
ScanButton.Disabled = true;
}
else
{
@@ -45,9 +65,10 @@ namespace Content.Client.GameObjects.Components.MedicalScanner
text.Append("\n");
}
}
Contents.AddChild(new Label() {Text = text.ToString()});
_diagnostics.Text = text.ToString();
ScanButton.Disabled = state.IsScanned;
}
}
}
}

View File

@@ -23,7 +23,7 @@ namespace Content.Client.GameObjects.Components.Mobs
private const float RestoreRateRamp = 0.1f;
// The maximum magnitude of the kick applied to the camera at any point.
private const float KickMagnitudeMax = 5f;
private const float KickMagnitudeMax = 2f;
private Vector2 _currentKick;
private float _lastKickTime;
@@ -87,7 +87,7 @@ namespace Content.Client.GameObjects.Components.Mobs
// Continually restore camera to 0.
var normalized = _currentKick.Normalized;
_lastKickTime += frameTime;
var restoreRate = FloatMath.Lerp(RestoreRateMin, RestoreRateMax, Math.Min(1, _lastKickTime/RestoreRateRamp));
var restoreRate = MathHelper.Lerp(RestoreRateMin, RestoreRateMax, Math.Min(1, _lastKickTime/RestoreRateRamp));
var restore = normalized * restoreRate * frameTime;
var (x, y) = _currentKick - restore;
if (Math.Sign(x) != Math.Sign(_currentKick.X))

View File

@@ -152,7 +152,7 @@ namespace Content.Client.GameObjects.Components.Mobs
var progress = (_gameTiming.CurTime - start).TotalSeconds / length;
var ratio = (progress <= 1 ? (1 - progress) : (_gameTiming.CurTime - end).TotalSeconds * -5);
cooldownGraphic.Progress = FloatMath.Clamp((float)ratio, -1, 1);
cooldownGraphic.Progress = MathHelper.Clamp((float)ratio, -1, 1);
cooldownGraphic.Visible = ratio > -1f;
}
}

View File

@@ -34,7 +34,7 @@ namespace Content.Client.GameObjects.Components.Mobs
WalkModifierOverride = state.WalkModifierOverride;
RunModifierOverride = state.RunModifierOverride;
if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement))
if (Owner.TryGetComponent(out MovementSpeedModifierComponent? movement))
{
movement.RefreshMovementSpeedModifiers();
}

View File

@@ -0,0 +1,12 @@
using Robust.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Movement;
namespace Content.Client.GameObjects.Components.Movement
{
[RegisterComponent]
[ComponentReference(typeof(IClimbable))]
public class ClimbableComponent : SharedClimbableComponent
{
}
}

View File

@@ -0,0 +1,34 @@
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Content.Shared.GameObjects.Components.Movement;
using Content.Client.Interfaces.GameObjects.Components.Interaction;
using Content.Shared.Physics;
namespace Content.Client.GameObjects.Components.Movement
{
[RegisterComponent]
public class ClimbingComponent : SharedClimbingComponent, IClientDraggable
{
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
if (!(curState is ClimbModeComponentState climbModeState) || Body == null)
{
return;
}
IsClimbing = climbModeState.Climbing;
}
public override bool IsClimbing { get; set; }
bool IClientDraggable.ClientCanDropOn(CanDropEventArgs eventArgs)
{
return eventArgs.Target.HasComponent<IClimbable>();
}
bool IClientDraggable.ClientCanDrag(CanDragEventArgs eventArgs)
{
return true;
}
}
}

View File

@@ -20,7 +20,7 @@ namespace Content.Client.GameObjects.Components.Nutrition
_currentHungerThreshold = hunger.CurrentThreshold;
if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement))
if (Owner.TryGetComponent(out MovementSpeedModifierComponent? movement))
{
movement.RefreshMovementSpeedModifiers();
}

View File

@@ -20,7 +20,7 @@ namespace Content.Client.GameObjects.Components.Nutrition
_currentThirstThreshold = thirst.CurrentThreshold;
if (Owner.TryGetComponent(out MovementSpeedModifierComponent movement))
if (Owner.TryGetComponent(out MovementSpeedModifierComponent? movement))
{
movement.RefreshMovementSpeedModifiers();
}

View File

@@ -1,4 +1,4 @@
using Content.Shared.GameObjects.Components.PDA;
using Content.Shared.GameObjects.Components.PDA;
using Robust.Client.GameObjects;
using Robust.Client.Interfaces.GameObjects.Components;
@@ -10,7 +10,7 @@ namespace Content.Client.GameObjects.Components.PDA
private enum PDAVisualLayers
{
Base,
Unlit
Flashlight
}
@@ -22,13 +22,13 @@ namespace Content.Client.GameObjects.Components.PDA
return;
}
var sprite = component.Owner.GetComponent<ISpriteComponent>();
sprite.LayerSetVisible(PDAVisualLayers.Unlit, false);
if(!component.TryGetData<bool>(PDAVisuals.ScreenLit, out var isScreenLit))
sprite.LayerSetVisible(PDAVisualLayers.Flashlight, false);
if(!component.TryGetData<bool>(PDAVisuals.FlashlightLit, out var isScreenLit))
{
return;
}
sprite.LayerSetState(PDAVisualLayers.Unlit, "unlit_pda_screen");
sprite.LayerSetVisible(PDAVisualLayers.Unlit, isScreenLit);
sprite.LayerSetState(PDAVisualLayers.Flashlight, "light_overlay");
sprite.LayerSetVisible(PDAVisualLayers.Flashlight, isScreenLit);
}

View File

@@ -86,12 +86,12 @@ namespace Content.Client.GameObjects.Components.Power
if (normalizedCharge <= leftSideSize)
{
normalizedCharge /= leftSideSize; // Adjust range to 0.0 to 1.0
finalHue = FloatMath.Lerp(leftHue, middleHue, normalizedCharge);
finalHue = MathHelper.Lerp(leftHue, middleHue, normalizedCharge);
}
else
{
normalizedCharge = (normalizedCharge - leftSideSize) / rightSideSize; // Adjust range to 0.0 to 1.0.
finalHue = FloatMath.Lerp(middleHue, rightHue, normalizedCharge);
finalHue = MathHelper.Lerp(middleHue, rightHue, normalizedCharge);
}
// Check if null first to avoid repeatedly creating this.

View File

@@ -141,7 +141,7 @@ namespace Content.Client.GameObjects.Components.Weapons
const float xOffset = 0.0f;
// Overkill but easy to adjust if you want to mess around with the design
var result = (float) FloatMath.Clamp(slope * (float) Math.Pow(ratio - xOffset, exponent) + yOffset, 0.0, 1.0);
var result = (float) MathHelper.Clamp(slope * (float) Math.Pow(ratio - xOffset, exponent) + yOffset, 0.0, 1.0);
DebugTools.Assert(!float.IsNaN(result));
return result;
}

View File

@@ -143,7 +143,7 @@ namespace Content.Client.GameObjects.EntitySystems.DoAfter
{
base.FrameUpdate(args);
if (AttachedEntity?.IsValid() != true || !AttachedEntity.TryGetComponent(out DoAfterComponent doAfterComponent))
if (AttachedEntity?.IsValid() != true || !AttachedEntity.TryGetComponent(out DoAfterComponent? doAfterComponent))
{
return;
}

View File

@@ -67,7 +67,7 @@ namespace Content.Client.GameObjects.EntitySystems.DoAfter
Gui ??= new DoAfterGui();
Gui.AttachedEntity = entity;
if (entity.TryGetComponent(out DoAfterComponent doAfterComponent))
if (entity.TryGetComponent(out DoAfterComponent? doAfterComponent))
{
foreach (var (_, doAfter) in doAfterComponent.DoAfters)
{
@@ -87,7 +87,7 @@ namespace Content.Client.GameObjects.EntitySystems.DoAfter
return;
}
if (!_player.TryGetComponent(out DoAfterComponent doAfterComponent))
if (!_player.TryGetComponent(out DoAfterComponent? doAfterComponent))
{
return;
}

View File

@@ -25,7 +25,7 @@ namespace Content.Client.GameObjects.EntitySystems
{
var playerEnt = _playerManager.LocalPlayer?.ControlledEntity;
if (playerEnt == null || !playerEnt.TryGetComponent(out IMoverComponent mover))
if (playerEnt == null || !playerEnt.TryGetComponent(out IMoverComponent? mover))
{
return;
}

View File

@@ -207,11 +207,10 @@ namespace Content.Client.GameObjects.EntitySystems
//Get verbs, component dependent.
foreach (var (component, verb) in VerbUtility.GetVerbs(entity))
{
if (verb.RequireInteractionRange && !VerbUtility.InVerbUseRange(user, entity))
continue;
if (verb.BlockedByContainers && !user.IsInSameOrNoContainer(entity))
if (!VerbUtility.VerbAccessChecks(user, entity, verb))
{
continue;
}
var verbData = verb.GetData(user, component);
@@ -232,11 +231,10 @@ namespace Content.Client.GameObjects.EntitySystems
//Get global verbs. Visible for all entities regardless of their components.
foreach (var globalVerb in VerbUtility.GetGlobalVerbs(Assembly.GetExecutingAssembly()))
{
if (globalVerb.RequireInteractionRange && !VerbUtility.InVerbUseRange(user, entity))
continue;
if (globalVerb.BlockedByContainers && !user.IsInSameOrNoContainer(entity))
if (!VerbUtility.VerbAccessChecks(user, entity, globalVerb))
{
continue;
}
var verbData = globalVerb.GetData(user, entity);

View File

@@ -26,14 +26,16 @@ namespace Content.Client.GameTicking
[ViewVariables] public bool AreWeReady { get; private set; }
[ViewVariables] public bool IsGameStarted { get; private set; }
[ViewVariables] public bool DisallowedLateJoin { get; private set; }
[ViewVariables] public string ServerInfoBlob { get; private set; }
[ViewVariables] public DateTime StartTime { get; private set; }
[ViewVariables] public bool Paused { get; private set; }
[ViewVariables] public Dictionary<NetSessionId, bool> Ready { get; private set; }
[ViewVariables] public Dictionary<NetSessionId, PlayerStatus> Status { get; private set; }
public event Action InfoBlobUpdated;
public event Action LobbyStatusUpdated;
public event Action LobbyReadyUpdated;
public event Action LobbyLateJoinStatusUpdated;
public void Initialize()
{
@@ -50,11 +52,17 @@ namespace Content.Client.GameTicking
{
IoCManager.Resolve<IClyde>().RequestWindowAttention();
});
_netManager.RegisterNetMessage<MsgTickerLateJoinStatus>(nameof(MsgTickerLateJoinStatus), LateJoinStatus);
Ready = new Dictionary<NetSessionId, bool>();
Status = new Dictionary<NetSessionId, PlayerStatus>();
_initialized = true;
}
private void LateJoinStatus(MsgTickerLateJoinStatus message)
{
DisallowedLateJoin = message.Disallowed;
LobbyLateJoinStatusUpdated?.Invoke();
}
private void JoinLobby(MsgTickerJoinLobby message)
@@ -69,7 +77,7 @@ namespace Content.Client.GameTicking
AreWeReady = message.YouAreReady;
Paused = message.Paused;
if (IsGameStarted)
Ready.Clear();
Status.Clear();
LobbyStatusUpdated?.Invoke();
}
@@ -95,9 +103,9 @@ namespace Content.Client.GameTicking
private void LobbyReady(MsgTickerLobbyReady message)
{
// Merge the Dictionaries
foreach (var p in message.PlayerReady)
foreach (var p in message.PlayerStatus)
{
Ready[p.Key] = p.Value;
Status[p.Key] = p.Value;
}
LobbyReadyUpdated?.Invoke();
}
@@ -105,7 +113,7 @@ namespace Content.Client.GameTicking
private void RoundEnd(MsgRoundEndMessage message)
{
//This is not ideal at all, but I don't see an immediately better fit anywhere else.
var roundEnd = new RoundEndSummaryWindow(message.GamemodeTitle, message.RoundDuration, message.AllPlayersEndInfo);
var roundEnd = new RoundEndSummaryWindow(message.GamemodeTitle, message.RoundEndText, message.RoundDuration, message.AllPlayersEndInfo);
}
}

View File

@@ -142,6 +142,8 @@
"Listening",
"Radio",
"DisposalHolder",
"DisposalTagger",
"DisposalRouter",
"DisposalTransit",
"DisposalEntry",
"DisposalJunction",

View File

@@ -1,6 +1,7 @@
using Robust.Shared.Network;
using System;
using System.Collections.Generic;
using static Content.Shared.SharedGameTicker;
namespace Content.Client.Interfaces
{
@@ -9,13 +10,15 @@ namespace Content.Client.Interfaces
bool IsGameStarted { get; }
string ServerInfoBlob { get; }
bool AreWeReady { get; }
bool DisallowedLateJoin { get; }
DateTime StartTime { get; }
bool Paused { get; }
Dictionary<NetSessionId, bool> Ready { get; }
Dictionary<NetSessionId, PlayerStatus> Status { get; }
void Initialize();
event Action InfoBlobUpdated;
event Action LobbyStatusUpdated;
event Action LobbyReadyUpdated;
event Action LobbyLateJoinStatusUpdated;
}
}

View File

@@ -18,6 +18,7 @@ using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables;
using static Content.Shared.SharedGameTicker;
namespace Content.Client.State
{
@@ -101,13 +102,18 @@ namespace Content.Client.State
_clientGameTicker.InfoBlobUpdated += UpdateLobbyUi;
_clientGameTicker.LobbyStatusUpdated += LobbyStatusUpdated;
_clientGameTicker.LobbyReadyUpdated += LobbyReadyUpdated;
_clientGameTicker.LobbyLateJoinStatusUpdated += LobbyLateJoinStatusUpdated;
}
public override void Shutdown()
{
_playerManager.PlayerListUpdated -= PlayerManagerOnPlayerListUpdated;
_clientGameTicker.InfoBlobUpdated -= UpdateLobbyUi;
_clientGameTicker.LobbyStatusUpdated -= UpdateLobbyUi;
_clientGameTicker.LobbyStatusUpdated -= LobbyStatusUpdated;
_clientGameTicker.LobbyReadyUpdated -= LobbyReadyUpdated;
_clientGameTicker.LobbyLateJoinStatusUpdated -= LobbyLateJoinStatusUpdated;
_clientGameTicker.Status.Clear();
_lobby.Dispose();
_characterSetup.Dispose();
@@ -153,11 +159,14 @@ namespace Content.Client.State
private void PlayerManagerOnPlayerListUpdated(object sender, EventArgs e)
{
// Remove disconnected sessions from the Ready Dict
foreach (var p in _clientGameTicker.Ready)
foreach (var p in _clientGameTicker.Status)
{
if (!_playerManager.SessionsDict.TryGetValue(p.Key, out _))
{
_clientGameTicker.Ready.Remove(p.Key);
// This is a shitty fix. Observers can rejoin because they are already in the game.
// So we don't delete them, but keep them if they decide to rejoin
if (p.Value != PlayerStatus.Observer)
_clientGameTicker.Status.Remove(p.Key);
}
}
UpdatePlayerList();
@@ -170,6 +179,11 @@ namespace Content.Client.State
UpdateLobbyUi();
}
private void LobbyLateJoinStatusUpdated()
{
_lobby.ReadyButton.Disabled = _clientGameTicker.DisallowedLateJoin;
}
private void UpdateLobbyUi()
{
if (_lobby == null)
@@ -188,6 +202,7 @@ namespace Content.Client.State
_lobby.StartTime.Text = "";
_lobby.ReadyButton.Text = Loc.GetString("Ready Up");
_lobby.ReadyButton.ToggleMode = true;
_lobby.ReadyButton.Disabled = false;
_lobby.ReadyButton.Pressed = _clientGameTicker.AreWeReady;
}
@@ -207,12 +222,19 @@ namespace Content.Client.State
// Don't show ready state if we're ingame
if (!_clientGameTicker.IsGameStarted)
{
var ready = false;
var status = PlayerStatus.NotReady;
if (session.SessionId == _playerManager.LocalPlayer.SessionId)
ready = _clientGameTicker.AreWeReady;
status = _clientGameTicker.AreWeReady ? PlayerStatus.Ready : PlayerStatus.NotReady;
else
_clientGameTicker.Ready.TryGetValue(session.SessionId, out ready);
readyState = ready ? Loc.GetString("Ready") : Loc.GetString("Not Ready");
_clientGameTicker.Status.TryGetValue(session.SessionId, out status);
readyState = status switch
{
PlayerStatus.NotReady => Loc.GetString("Not Ready"),
PlayerStatus.Ready => Loc.GetString("Ready"),
PlayerStatus.Observer => Loc.GetString("Observer"),
_ => "",
};
}
_lobby.PlayerReadyList.AddItem(readyState, null, false);
}

View File

@@ -30,6 +30,7 @@ namespace Content.Client.UserInterface
protected override void Draw(DrawingHandleScreen handle)
{
Span<float> x = stackalloc float[10];
Color color;
var lerp = 1f - MathF.Abs(Progress); // for future bikeshedding purposes
@@ -41,7 +42,7 @@ namespace Content.Client.UserInterface
}
else
{
var alpha = FloatMath.Clamp(0.5f * lerp, 0f, 0.5f);
var alpha = MathHelper.Clamp(0.5f * lerp, 0f, 0.5f);
color = new Color(1f, 1f, 1f, alpha);
}

View File

@@ -107,7 +107,7 @@ namespace Content.Client.UserInterface
var progress = (_gameTiming.CurTime - start).TotalSeconds / length;
var ratio = (progress <= 1 ? (1 - progress) : (_gameTiming.CurTime - end).TotalSeconds * -5);
cooldownDisplay.Progress = FloatMath.Clamp((float)ratio, -1, 1);
cooldownDisplay.Progress = MathHelper.Clamp((float)ratio, -1, 1);
if (ratio > -1f)
{

View File

@@ -82,6 +82,8 @@ namespace Content.Client.UserInterface
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_preferencesManager.OnServerDataLoaded -= UpdateUI;
if (!disposing) return;
_previewDummy.Delete();
_previewDummy = null;

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Content.Client.Utility;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Localization;
@@ -17,7 +18,7 @@ namespace Content.Client.UserInterface
private TabContainer RoundEndWindowTabs { get; }
protected override Vector2? CustomSize => (520, 580);
public RoundEndSummaryWindow(string gm, TimeSpan roundTimeSpan, List<RoundEndPlayerInfo> info )
public RoundEndSummaryWindow(string gm, string roundEnd, TimeSpan roundTimeSpan, List<RoundEndPlayerInfo> info)
{
Title = Loc.GetString("Round End Summary");
@@ -49,6 +50,14 @@ namespace Content.Client.UserInterface
gamemodeLabel.SetMarkup(Loc.GetString("Round of [color=white]{0}[/color] has ended.", gm));
RoundEndSummaryTab.AddChild(gamemodeLabel);
//Round end text
if (!string.IsNullOrEmpty(roundEnd))
{
var roundendLabel = new RichTextLabel();
roundendLabel.SetMarkup(Loc.GetString(roundEnd));
RoundEndSummaryTab.AddChild(roundendLabel);
}
//Duration
var roundTimeLabel = new RichTextLabel();
roundTimeLabel.SetMarkup(Loc.GetString("It lasted for [color=yellow]{0} hours, {1} minutes, and {2} seconds.",
@@ -65,30 +74,40 @@ namespace Content.Client.UserInterface
//Create labels for each player info.
foreach (var plyinfo in manifestSortedList)
{
var playerInfoText = new RichTextLabel()
{
SizeFlagsVertical = SizeFlags.Fill
SizeFlagsVertical = SizeFlags.Fill,
};
//TODO: On Hover display a popup detailing more play info.
//For example: their antag goals and if they completed them sucessfully.
var icNameColor = plyinfo.Antag ? "red" : "white";
playerInfoText.SetMarkup(
Loc.GetString($"[color=gray]{plyinfo.PlayerOOCName}[/color] was [color={icNameColor}]{plyinfo.PlayerICName}[/color] playing role of [color=orange]{plyinfo.Role}[/color]."));
Loc.GetString("[color=gray]{0}[/color] was [color={1}]{2}[/color] playing role of [color=orange]{3}[/color].",
plyinfo.PlayerOOCName, icNameColor, plyinfo.PlayerICName, Loc.GetString(plyinfo.Role)));
innerScrollContainer.AddChild(playerInfoText);
}
scrollContainer.AddChild(innerScrollContainer);
//Attach the entire ScrollContainer that holds all the playerinfo.
PlayerManifestoTab.AddChild(scrollContainer);
// TODO: 1240 Overlap, remove once it's fixed. Temp Hack to make the lines not overlap
PlayerManifestoTab.OnVisibilityChanged += PlayerManifestoTab_OnVisibilityChanged;
//Finally, display the window.
OpenCentered();
MoveToFront();
}
private void PlayerManifestoTab_OnVisibilityChanged(Control obj)
{
if (obj.Visible)
{
// For some reason the lines get not properly drawn with the right height
// so we just force a update
ForceRunLayoutUpdate();
}
}
}
}