345 lines
13 KiB
C#
345 lines
13 KiB
C#
using Content.Client.Popups;
|
|
using Content.Client.UserInterface.Controls;
|
|
using Content.Shared.Access.Systems;
|
|
using Content.Shared.Holopad;
|
|
using Content.Shared.Telephone;
|
|
using Robust.Client.AutoGenerated;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.Player;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.XAML;
|
|
using Robust.Shared.Timing;
|
|
using Robust.Shared.Utility;
|
|
using System.Linq;
|
|
|
|
namespace Content.Client.Holopad;
|
|
|
|
[GenerateTypedNameReferences]
|
|
public sealed partial class HolopadWindow : FancyWindow
|
|
{
|
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
[Dependency] private readonly IGameTiming _timing = default!;
|
|
|
|
private readonly SharedHolopadSystem _holopadSystem = default!;
|
|
private readonly SharedTelephoneSystem _telephoneSystem = default!;
|
|
private readonly AccessReaderSystem _accessReaderSystem = default!;
|
|
private readonly PopupSystem _popupSystem = default!;
|
|
|
|
private EntityUid? _owner = null;
|
|
private HolopadUiKey _currentUiKey;
|
|
private TelephoneState _currentState;
|
|
private TelephoneState _previousState;
|
|
private TimeSpan _buttonUnlockTime;
|
|
private float _updateTimer = 0.25f;
|
|
|
|
private const float UpdateTime = 0.25f;
|
|
private TimeSpan _buttonUnlockDelay = TimeSpan.FromSeconds(0.5f);
|
|
|
|
public event Action<NetEntity>? SendHolopadStartNewCallMessageAction;
|
|
public event Action? SendHolopadAnswerCallMessageAction;
|
|
public event Action? SendHolopadEndCallMessageAction;
|
|
public event Action? SendHolopadStartBroadcastMessageAction;
|
|
public event Action? SendHolopadActivateProjectorMessageAction;
|
|
public event Action? SendHolopadRequestStationAiMessageAction;
|
|
|
|
public HolopadWindow()
|
|
{
|
|
RobustXamlLoader.Load(this);
|
|
IoCManager.InjectDependencies(this);
|
|
|
|
_holopadSystem = _entManager.System<SharedHolopadSystem>();
|
|
_telephoneSystem = _entManager.System<SharedTelephoneSystem>();
|
|
_accessReaderSystem = _entManager.System<AccessReaderSystem>();
|
|
_popupSystem = _entManager.System<PopupSystem>();
|
|
|
|
_buttonUnlockTime = _timing.CurTime + _buttonUnlockDelay;
|
|
|
|
// Assign button actions
|
|
AnswerCallButton.OnPressed += args => { OnHolopadAnswerCallMessage(); };
|
|
EndCallButton.OnPressed += args => { OnHolopadEndCallMessage(); };
|
|
StartBroadcastButton.OnPressed += args => { OnHolopadStartBroadcastMessage(); };
|
|
ActivateProjectorButton.OnPressed += args => { OnHolopadActivateProjectorMessage(); };
|
|
RequestStationAiButton.OnPressed += args => { OnHolopadRequestStationAiMessage(); };
|
|
|
|
// XML formatting
|
|
AnswerCallButton.AddStyleClass("ButtonAccept");
|
|
EndCallButton.AddStyleClass("Caution");
|
|
StartBroadcastButton.AddStyleClass("Caution");
|
|
|
|
HolopadContactListPanel.PanelOverride = new StyleBoxFlat
|
|
{
|
|
BackgroundColor = new Color(47, 47, 59) * Color.DarkGray,
|
|
BorderColor = new Color(82, 82, 82), //new Color(70, 73, 102),
|
|
BorderThickness = new Thickness(2),
|
|
};
|
|
|
|
HolopadContactListHeaderPanel.PanelOverride = new StyleBoxFlat
|
|
{
|
|
BackgroundColor = new Color(82, 82, 82),
|
|
};
|
|
|
|
EmergencyBroadcastText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-emergency-broadcast-in-progress")));
|
|
SubtitleText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-subtitle")));
|
|
OptionsText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-options")));
|
|
}
|
|
|
|
#region: Button actions
|
|
|
|
private void OnSendHolopadStartNewCallMessage(NetEntity receiver)
|
|
{
|
|
SendHolopadStartNewCallMessageAction?.Invoke(receiver);
|
|
}
|
|
|
|
private void OnHolopadAnswerCallMessage()
|
|
{
|
|
SendHolopadAnswerCallMessageAction?.Invoke();
|
|
}
|
|
|
|
private void OnHolopadEndCallMessage()
|
|
{
|
|
SendHolopadEndCallMessageAction?.Invoke();
|
|
|
|
if (_currentUiKey == HolopadUiKey.AiRequestWindow)
|
|
Close();
|
|
}
|
|
|
|
private void OnHolopadStartBroadcastMessage()
|
|
{
|
|
if (_playerManager.LocalSession?.AttachedEntity == null || _owner == null)
|
|
return;
|
|
|
|
var player = _playerManager.LocalSession.AttachedEntity;
|
|
|
|
if (!_accessReaderSystem.IsAllowed(player.Value, _owner.Value))
|
|
{
|
|
_popupSystem.PopupClient(Loc.GetString("holopad-window-access-denied"), _owner.Value, player.Value);
|
|
return;
|
|
}
|
|
|
|
SendHolopadStartBroadcastMessageAction?.Invoke();
|
|
}
|
|
|
|
private void OnHolopadActivateProjectorMessage()
|
|
{
|
|
SendHolopadActivateProjectorMessageAction?.Invoke();
|
|
}
|
|
|
|
private void OnHolopadRequestStationAiMessage()
|
|
{
|
|
SendHolopadRequestStationAiMessageAction?.Invoke();
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void SetState(EntityUid owner, HolopadUiKey uiKey)
|
|
{
|
|
_owner = owner;
|
|
_currentUiKey = uiKey;
|
|
|
|
// Determines what UI containers are available to the user.
|
|
// Components of these will be toggled on and off when
|
|
// UpdateAppearance() is called
|
|
|
|
switch (uiKey)
|
|
{
|
|
case HolopadUiKey.InteractionWindow:
|
|
RequestStationAiContainer.Visible = true;
|
|
HolopadContactListContainer.Visible = true;
|
|
StartBroadcastContainer.Visible = true;
|
|
break;
|
|
|
|
case HolopadUiKey.InteractionWindowForAi:
|
|
ActivateProjectorContainer.Visible = true;
|
|
StartBroadcastContainer.Visible = true;
|
|
break;
|
|
|
|
case HolopadUiKey.AiActionWindow:
|
|
HolopadContactListContainer.Visible = true;
|
|
StartBroadcastContainer.Visible = true;
|
|
break;
|
|
|
|
case HolopadUiKey.AiRequestWindow:
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void UpdateState(Dictionary<NetEntity, string> holopads)
|
|
{
|
|
if (_owner == null || !_entManager.TryGetComponent<TelephoneComponent>(_owner.Value, out var telephone))
|
|
return;
|
|
|
|
// Caller ID text
|
|
var callerId = _telephoneSystem.GetFormattedCallerIdForEntity(telephone.LastCallerId.Item1, telephone.LastCallerId.Item2, Color.LightGray, "Default", 11);
|
|
var holoapdId = _telephoneSystem.GetFormattedDeviceIdForEntity(telephone.LastCallerId.Item3, Color.LightGray, "Default", 11);
|
|
|
|
CallerIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(callerId));
|
|
HolopadIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(holoapdId));
|
|
LockOutIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(callerId));
|
|
|
|
// Sort holopads alphabetically
|
|
var holopadArray = holopads.ToArray();
|
|
Array.Sort(holopadArray, AlphabeticalSort);
|
|
|
|
// Clear excess children from the contact list
|
|
while (ContactsList.ChildCount > holopadArray.Length)
|
|
ContactsList.RemoveChild(ContactsList.GetChild(ContactsList.ChildCount - 1));
|
|
|
|
// Make / update required children
|
|
for (int i = 0; i < holopadArray.Length; i++)
|
|
{
|
|
var (netEntity, label) = holopadArray[i];
|
|
|
|
if (i >= ContactsList.ChildCount)
|
|
{
|
|
var newContactButton = new HolopadContactButton();
|
|
newContactButton.OnPressed += args => { OnSendHolopadStartNewCallMessage(newContactButton.NetEntity); };
|
|
|
|
ContactsList.AddChild(newContactButton);
|
|
}
|
|
|
|
var child = ContactsList.GetChild(i);
|
|
|
|
if (child is not HolopadContactButton)
|
|
continue;
|
|
|
|
var contactButton = (HolopadContactButton)child;
|
|
contactButton.UpdateValues(netEntity, label);
|
|
}
|
|
|
|
// Update buttons
|
|
UpdateAppearance();
|
|
}
|
|
|
|
private void UpdateAppearance()
|
|
{
|
|
if (_owner == null || !_entManager.TryGetComponent<TelephoneComponent>(_owner.Value, out var telephone))
|
|
return;
|
|
|
|
if (_owner == null || !_entManager.TryGetComponent<HolopadComponent>(_owner.Value, out var holopad))
|
|
return;
|
|
|
|
var hasBroadcastAccess = !_holopadSystem.IsHolopadBroadcastOnCoolDown((_owner.Value, holopad));
|
|
var localPlayer = _playerManager.LocalSession?.AttachedEntity;
|
|
|
|
ControlsLockOutContainer.Visible = _holopadSystem.IsHolopadControlLocked((_owner.Value, holopad), localPlayer);
|
|
ControlsContainer.Visible = !ControlsLockOutContainer.Visible;
|
|
|
|
// Temporarily disable the interface buttons when the call state changes to prevent any misclicks
|
|
if (_currentState != telephone.CurrentState)
|
|
{
|
|
_previousState = _currentState;
|
|
_currentState = telephone.CurrentState;
|
|
_buttonUnlockTime = _timing.CurTime + _buttonUnlockDelay;
|
|
}
|
|
|
|
var lockButtons = _timing.CurTime < _buttonUnlockTime;
|
|
|
|
// Make / update required children
|
|
foreach (var child in ContactsList.Children)
|
|
{
|
|
if (child is not HolopadContactButton contactButton)
|
|
continue;
|
|
|
|
var passesFilter = string.IsNullOrEmpty(SearchLineEdit.Text) ||
|
|
contactButton.Text?.Contains(SearchLineEdit.Text, StringComparison.CurrentCultureIgnoreCase) == true;
|
|
|
|
contactButton.Visible = passesFilter;
|
|
contactButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
|
|
}
|
|
|
|
// Update control text
|
|
var cooldown = _holopadSystem.GetHolopadBroadcastCoolDown((_owner.Value, holopad));
|
|
var cooldownString = $"{cooldown.Minutes:00}:{cooldown.Seconds:00}";
|
|
|
|
StartBroadcastButton.Text = _holopadSystem.IsHolopadBroadcastOnCoolDown((_owner.Value, holopad)) ?
|
|
Loc.GetString("holopad-window-emergency-broadcast-with-countdown", ("countdown", cooldownString)) :
|
|
Loc.GetString("holopad-window-emergency-broadcast");
|
|
|
|
var lockout = _holopadSystem.GetHolopadControlLockedPeriod((_owner.Value, holopad));
|
|
var lockoutString = $"{lockout.Minutes:00}:{lockout.Seconds:00}";
|
|
|
|
LockOutCountDownText.Text = Loc.GetString("holopad-window-controls-unlock-countdown", ("countdown", lockoutString));
|
|
|
|
switch (_currentState)
|
|
{
|
|
case TelephoneState.Idle:
|
|
CallStatusText.Text = Loc.GetString("holopad-window-no-calls-in-progress"); break;
|
|
|
|
case TelephoneState.Calling:
|
|
CallStatusText.Text = Loc.GetString("holopad-window-outgoing-call"); break;
|
|
|
|
case TelephoneState.Ringing:
|
|
CallStatusText.Text = (_currentUiKey == HolopadUiKey.AiRequestWindow) ?
|
|
Loc.GetString("holopad-window-ai-request") : Loc.GetString("holopad-window-incoming-call"); break;
|
|
|
|
case TelephoneState.InCall:
|
|
CallStatusText.Text = Loc.GetString("holopad-window-call-in-progress"); break;
|
|
|
|
case TelephoneState.EndingCall:
|
|
if (_previousState == TelephoneState.Calling || _previousState == TelephoneState.Idle)
|
|
CallStatusText.Text = Loc.GetString("holopad-window-call-rejected");
|
|
else
|
|
CallStatusText.Text = Loc.GetString("holopad-window-call-ending");
|
|
break;
|
|
}
|
|
|
|
// Update control disability
|
|
AnswerCallButton.Disabled = (_currentState != TelephoneState.Ringing || lockButtons);
|
|
EndCallButton.Disabled = (_currentState == TelephoneState.Idle || _currentState == TelephoneState.EndingCall || lockButtons);
|
|
StartBroadcastButton.Disabled = (_currentState != TelephoneState.Idle || !hasBroadcastAccess || lockButtons);
|
|
RequestStationAiButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
|
|
ActivateProjectorButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
|
|
|
|
// Update control visibility
|
|
FetchingAvailableHolopadsContainer.Visible = (ContactsList.ChildCount == 0);
|
|
ActiveCallControlsContainer.Visible = (_currentState != TelephoneState.Idle || _currentUiKey == HolopadUiKey.AiRequestWindow);
|
|
CallPlacementControlsContainer.Visible = !ActiveCallControlsContainer.Visible;
|
|
CallerIdContainer.Visible = (_currentState == TelephoneState.Ringing);
|
|
AnswerCallButton.Visible = (_currentState == TelephoneState.Ringing);
|
|
}
|
|
|
|
protected override void FrameUpdate(FrameEventArgs args)
|
|
{
|
|
base.FrameUpdate(args);
|
|
|
|
_updateTimer += args.DeltaSeconds;
|
|
|
|
if (_updateTimer >= UpdateTime)
|
|
{
|
|
_updateTimer -= UpdateTime;
|
|
UpdateAppearance();
|
|
}
|
|
}
|
|
|
|
private sealed class HolopadContactButton : Button
|
|
{
|
|
public NetEntity NetEntity;
|
|
|
|
public HolopadContactButton()
|
|
{
|
|
HorizontalExpand = true;
|
|
SetHeight = 32;
|
|
Margin = new Thickness(0f, 1f, 0f, 1f);
|
|
ReservesSpace = false;
|
|
}
|
|
|
|
public void UpdateValues(NetEntity netEntity, string label)
|
|
{
|
|
NetEntity = netEntity;
|
|
Text = Loc.GetString("holopad-window-contact-label", ("label", label));
|
|
}
|
|
}
|
|
|
|
private int AlphabeticalSort(KeyValuePair<NetEntity, string> x, KeyValuePair<NetEntity, string> y)
|
|
{
|
|
if (string.IsNullOrEmpty(x.Value))
|
|
return -1;
|
|
|
|
if (string.IsNullOrEmpty(y.Value))
|
|
return 1;
|
|
|
|
return x.Value.CompareTo(y.Value);
|
|
}
|
|
}
|