Compare commits
5 Commits
MagicWands
...
ed-29-09-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb0f7c9632 | ||
|
|
4d8d5d5c82 | ||
|
|
60ca78ed9b | ||
|
|
beb681ce7b | ||
|
|
752d9b8ff4 |
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -19,7 +19,7 @@
|
||||
/Resources/engineCommandPerms.yml @moonheart08 @Chief-Engineer
|
||||
/Resources/clientCommandPerms.yml @moonheart08 @Chief-Engineer
|
||||
|
||||
/Resources/Prototypes/Maps/** @Emisse
|
||||
/Resources/Prototypes/Maps/ @Emisse
|
||||
|
||||
/Resources/Prototypes/Body/ @DrSmugleaf # suffering
|
||||
/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf
|
||||
|
||||
2
.github/labeler.yml
vendored
2
.github/labeler.yml
vendored
@@ -16,7 +16,7 @@
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: '**/*.swsl'
|
||||
|
||||
"Changes: No C#":
|
||||
"No C#":
|
||||
- changed-files:
|
||||
# Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label.
|
||||
- all-globs-to-all-files: "!**/*.cs"
|
||||
|
||||
@@ -16,6 +16,6 @@ jobs:
|
||||
- name: Check for Merge Conflicts
|
||||
uses: eps1lon/actions-label-merge-conflict@v3.0.0
|
||||
with:
|
||||
dirtyLabel: "S: Merge Conflict"
|
||||
dirtyLabel: "Merge Conflict"
|
||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||
commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request."
|
||||
4
.github/workflows/labeler-needsreview.yml
vendored
4
.github/workflows/labeler-needsreview.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
labels: "S: Needs Review"
|
||||
labels: "Status: Needs Review"
|
||||
- uses: actions-ecosystem/action-remove-labels@v1
|
||||
with:
|
||||
labels: "S: Awaiting Changes"
|
||||
labels: "Status: Awaiting Changes"
|
||||
|
||||
23
.github/workflows/labeler-review.yml
vendored
23
.github/workflows/labeler-review.yml
vendored
@@ -1,23 +0,0 @@
|
||||
name: "Labels: Approved"
|
||||
on:
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
jobs:
|
||||
add_label:
|
||||
# Change the repository name after you've made sure the team name is correct for your fork!
|
||||
if: ${{ (github.repository == 'space-wizards/space-station-14') && (github.event.review.state == 'APPROVED') }}
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: tspascoal/get-user-teams-membership@v3
|
||||
id: checkUserMember
|
||||
with:
|
||||
username: ${{ github.actor }}
|
||||
team: "content-maintainers,junior-maintainers"
|
||||
GITHUB_TOKEN: ${{ secrets.LABELER_PAT }}
|
||||
- if: ${{ steps.checkUserMember.outputs.isTeamMember == 'true' }}
|
||||
uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
labels: "S: Approved"
|
||||
20
.github/workflows/labeler-size.yml
vendored
20
.github/workflows/labeler-size.yml
vendored
@@ -1,20 +0,0 @@
|
||||
name: "Labels: Size"
|
||||
on: pull_request_target
|
||||
jobs:
|
||||
size-label:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: size-label
|
||||
uses: "pascalgn/size-label-action@v0.5.5"
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
with:
|
||||
# Custom size configuration
|
||||
sizes: >
|
||||
{
|
||||
"0": "XS",
|
||||
"10": "S",
|
||||
"30": "M",
|
||||
"100": "L",
|
||||
"1000": "XL"
|
||||
}
|
||||
16
.github/workflows/labeler-stable.yml
vendored
16
.github/workflows/labeler-stable.yml
vendored
@@ -1,16 +0,0 @@
|
||||
name: "Labels: Branch stable"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
branches:
|
||||
- 'stable'
|
||||
|
||||
jobs:
|
||||
add_label:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
labels: "Branch: Stable"
|
||||
16
.github/workflows/labeler-staging.yml
vendored
16
.github/workflows/labeler-staging.yml
vendored
@@ -1,16 +0,0 @@
|
||||
name: "Labels: Branch staging"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
branches:
|
||||
- 'staging'
|
||||
|
||||
jobs:
|
||||
add_label:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
labels: "Branch: Staging"
|
||||
4
.github/workflows/labeler-untriaged.yml
vendored
4
.github/workflows/labeler-untriaged.yml
vendored
@@ -3,8 +3,6 @@
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
add_label:
|
||||
@@ -13,4 +11,4 @@ jobs:
|
||||
- uses: actions-ecosystem/action-add-labels@v1
|
||||
if: join(github.event.issue.labels) == ''
|
||||
with:
|
||||
labels: "S: Untriaged"
|
||||
labels: "Status: Untriaged"
|
||||
|
||||
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
@@ -5,8 +5,8 @@ concurrency:
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# schedule:
|
||||
# - cron: '0 10 * * *'
|
||||
schedule:
|
||||
- cron: '0 10 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -258,13 +258,13 @@ namespace Content.Client.Actions
|
||||
|
||||
public void LinkAllActions(ActionsComponent? actions = null)
|
||||
{
|
||||
if (_playerManager.LocalEntity is not { } user ||
|
||||
!Resolve(user, ref actions, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_playerManager.LocalEntity is not { } user ||
|
||||
!Resolve(user, ref actions, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LinkActions?.Invoke(actions);
|
||||
LinkActions?.Invoke(actions);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
|
||||
@@ -22,11 +22,11 @@ namespace Content.Client.Administration.UI.BanPanel;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class BanPanel : DefaultWindow
|
||||
{
|
||||
public event Action<string?, (IPAddress, int)?, bool, ImmutableTypedHwid?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted;
|
||||
public event Action<string?, (IPAddress, int)?, bool, byte[]?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted;
|
||||
public event Action<string>? PlayerChanged;
|
||||
private string? PlayerUsername { get; set; }
|
||||
private (IPAddress, int)? IpAddress { get; set; }
|
||||
private ImmutableTypedHwid? Hwid { get; set; }
|
||||
private byte[]? Hwid { get; set; }
|
||||
private double TimeEntered { get; set; }
|
||||
private uint Multiplier { get; set; }
|
||||
private bool HasBanFlag { get; set; }
|
||||
@@ -371,8 +371,9 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
private void OnHwidChanged()
|
||||
{
|
||||
var hwidString = HwidLine.Text;
|
||||
ImmutableTypedHwid? hwid = null;
|
||||
if (HwidCheckbox.Pressed && !(string.IsNullOrEmpty(hwidString) && LastConnCheckbox.Pressed) && !ImmutableTypedHwid.TryParse(hwidString, out hwid))
|
||||
var length = 3 * (hwidString.Length / 4) - hwidString.TakeLast(2).Count(c => c == '=');
|
||||
Hwid = new byte[length];
|
||||
if (HwidCheckbox.Pressed && !(string.IsNullOrEmpty(hwidString) && LastConnCheckbox.Pressed) && !Convert.TryFromBase64String(hwidString, Hwid, out _))
|
||||
{
|
||||
ErrorLevel |= ErrorLevelEnum.Hwid;
|
||||
HwidLine.ModulateSelfOverride = Color.Red;
|
||||
@@ -389,7 +390,7 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
Hwid = null;
|
||||
return;
|
||||
}
|
||||
Hwid = hwid;
|
||||
Hwid = Convert.FromHexString(hwidString);
|
||||
}
|
||||
|
||||
private void OnTypeChanged()
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<Label Name="ExpiryLabel" Text="{Loc admin-note-editor-expiry-label}" Visible="False" />
|
||||
<HistoryLineEdit Name="ExpiryLineEdit" PlaceHolder="{Loc admin-note-editor-expiry-placeholder}"
|
||||
Visible="False" HorizontalExpand="True" />
|
||||
<OptionButton Name="ExpiryLengthDropdown" Visible="False" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<OptionButton Name="TypeOption" HorizontalAlignment="Center" />
|
||||
|
||||
@@ -17,17 +17,6 @@ public sealed partial class NoteEdit : FancyWindow
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IClientConsoleHost _console = default!;
|
||||
|
||||
private enum Multipliers
|
||||
{
|
||||
Minutes,
|
||||
Hours,
|
||||
Days,
|
||||
Weeks,
|
||||
Months,
|
||||
Years,
|
||||
Centuries
|
||||
}
|
||||
|
||||
public event Action<int, NoteType, string, NoteSeverity?, bool, DateTime?>? SubmitPressed;
|
||||
|
||||
public NoteEdit(SharedAdminNote? note, string playerName, bool canCreate, bool canEdit)
|
||||
@@ -42,20 +31,6 @@ public sealed partial class NoteEdit : FancyWindow
|
||||
|
||||
ResetSubmitButton();
|
||||
|
||||
// It's weird to use minutes as the IDs, but it works and makes sense kind of :)
|
||||
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-minutes"), (int) Multipliers.Minutes);
|
||||
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-hours"), (int) Multipliers.Hours);
|
||||
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-days"), (int) Multipliers.Days);
|
||||
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-weeks"), (int) Multipliers.Weeks);
|
||||
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-months"), (int) Multipliers.Months);
|
||||
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-years"), (int) Multipliers.Years);
|
||||
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-centuries"), (int) Multipliers.Centuries);
|
||||
ExpiryLengthDropdown.OnItemSelected += OnLengthChanged;
|
||||
|
||||
ExpiryLengthDropdown.SelectId((int) Multipliers.Weeks);
|
||||
|
||||
ExpiryLineEdit.OnTextChanged += OnTextChanged;
|
||||
|
||||
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-note"), (int) NoteType.Note);
|
||||
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-message"), (int) NoteType.Message);
|
||||
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-watchlist"), (int) NoteType.Watchlist);
|
||||
@@ -159,7 +134,6 @@ public sealed partial class NoteEdit : FancyWindow
|
||||
SecretCheckBox.Pressed = false;
|
||||
SeverityOption.Disabled = false;
|
||||
PermanentCheckBox.Pressed = true;
|
||||
SubmitButton.Disabled = true;
|
||||
UpdatePermanentCheckboxFields();
|
||||
break;
|
||||
case (int) NoteType.Message: // Message: these are shown to the player when they log on
|
||||
@@ -198,9 +172,8 @@ public sealed partial class NoteEdit : FancyWindow
|
||||
{
|
||||
ExpiryLabel.Visible = !PermanentCheckBox.Pressed;
|
||||
ExpiryLineEdit.Visible = !PermanentCheckBox.Pressed;
|
||||
ExpiryLengthDropdown.Visible = !PermanentCheckBox.Pressed;
|
||||
|
||||
ExpiryLineEdit.Text = !PermanentCheckBox.Pressed ? 1.ToString() : string.Empty;
|
||||
ExpiryLineEdit.Text = !PermanentCheckBox.Pressed ? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") : string.Empty;
|
||||
}
|
||||
|
||||
private void OnSecretPressed(BaseButton.ButtonEventArgs _)
|
||||
@@ -214,16 +187,6 @@ public sealed partial class NoteEdit : FancyWindow
|
||||
SeverityOption.SelectId(args.Id);
|
||||
}
|
||||
|
||||
private void OnLengthChanged(OptionButton.ItemSelectedEventArgs args)
|
||||
{
|
||||
ExpiryLengthDropdown.SelectId(args.Id);
|
||||
}
|
||||
|
||||
private void OnTextChanged(HistoryLineEdit.LineEditEventArgs args)
|
||||
{
|
||||
ParseExpiryTime();
|
||||
}
|
||||
|
||||
private void OnSubmitButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
if (!ParseExpiryTime())
|
||||
@@ -300,24 +263,13 @@ public sealed partial class NoteEdit : FancyWindow
|
||||
return true;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ExpiryLineEdit.Text) || !uint.TryParse(ExpiryLineEdit.Text, out var inputInt))
|
||||
if (string.IsNullOrWhiteSpace(ExpiryLineEdit.Text) || !DateTime.TryParse(ExpiryLineEdit.Text, out var result) || DateTime.UtcNow > result)
|
||||
{
|
||||
ExpiryLineEdit.ModulateSelfOverride = Color.Red;
|
||||
return false;
|
||||
}
|
||||
|
||||
var mult = ExpiryLengthDropdown.SelectedId switch
|
||||
{
|
||||
(int) Multipliers.Minutes => TimeSpan.FromMinutes(1).TotalMinutes,
|
||||
(int) Multipliers.Hours => TimeSpan.FromHours(1).TotalMinutes,
|
||||
(int) Multipliers.Days => TimeSpan.FromDays(1).TotalMinutes,
|
||||
(int) Multipliers.Weeks => TimeSpan.FromDays(7).TotalMinutes,
|
||||
(int) Multipliers.Months => TimeSpan.FromDays(30).TotalMinutes,
|
||||
(int) Multipliers.Years => TimeSpan.FromDays(365).TotalMinutes,
|
||||
(int) Multipliers.Centuries => TimeSpan.FromDays(36525).TotalMinutes,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(ExpiryLengthDropdown.SelectedId), "Multiplier out of range :(")
|
||||
};
|
||||
ExpiryTime = DateTime.UtcNow.AddMinutes(inputInt * mult);
|
||||
ExpiryTime = result.ToUniversalTime();
|
||||
ExpiryLineEdit.ModulateSelfOverride = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ using System.Linq;
|
||||
using Content.Shared.Alert;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -25,7 +24,8 @@ public sealed class ClientAlertsSystem : AlertsSystem
|
||||
|
||||
SubscribeLocalEvent<AlertsComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<AlertsComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
|
||||
SubscribeLocalEvent<AlertsComponent, ComponentHandleState>(OnHandleState);
|
||||
|
||||
SubscribeLocalEvent<AlertsComponent, AfterAutoHandleStateEvent>(ClientAlertsHandleState);
|
||||
}
|
||||
protected override void LoadPrototypes()
|
||||
{
|
||||
@@ -47,16 +47,6 @@ public sealed class ClientAlertsSystem : AlertsSystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHandleState(Entity<AlertsComponent> alerts, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not AlertComponentState cast)
|
||||
return;
|
||||
|
||||
alerts.Comp.Alerts = cast.Alerts;
|
||||
|
||||
UpdateHud(alerts);
|
||||
}
|
||||
|
||||
protected override void AfterShowAlert(Entity<AlertsComponent> alerts)
|
||||
{
|
||||
UpdateHud(alerts);
|
||||
@@ -67,6 +57,11 @@ public sealed class ClientAlertsSystem : AlertsSystem
|
||||
UpdateHud(alerts);
|
||||
}
|
||||
|
||||
private void ClientAlertsHandleState(Entity<AlertsComponent> alerts, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
UpdateHud(alerts);
|
||||
}
|
||||
|
||||
private void UpdateHud(Entity<AlertsComponent> entity)
|
||||
{
|
||||
if (_playerManager.LocalEntity == entity.Owner)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.Atmos.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class PipeColorVisualsComponent : Component;
|
||||
public sealed partial class PipeColorVisualsComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<BoxContainer xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:Content.Client.Stylesheets"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Orientation="Vertical" HorizontalExpand ="True" Margin="0 0 0 3">
|
||||
@@ -61,7 +62,7 @@
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<!-- If the alarm is inactive, this is label is displayed instead -->
|
||||
<!-- If the alarm is inactive, this is label is diplayed instead -->
|
||||
<Label Name="NoDataLabel" Text="{Loc 'atmos-alerts-window-no-data-available'}" HorizontalAlignment="Center" Margin="0 15" FontColorOverride="#a9a9a9" ReservesSpace="False" Visible="False"></Label>
|
||||
|
||||
<!-- Silencing progress bar -->
|
||||
|
||||
@@ -136,9 +136,8 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
|
||||
GasGridContainer.RemoveAllChildren();
|
||||
|
||||
var gasData = focusData.Value.GasData.Where(g => g.Key != Gas.Oxygen);
|
||||
var keyValuePairs = gasData.ToList();
|
||||
|
||||
if (keyValuePairs.Count == 0)
|
||||
if (gasData.Count() == 0)
|
||||
{
|
||||
// No other gases
|
||||
var gasLabel = new Label()
|
||||
@@ -159,11 +158,13 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
|
||||
else
|
||||
{
|
||||
// Add an entry for each gas
|
||||
foreach ((var gas, (var mol, var percent, var alert)) in keyValuePairs)
|
||||
foreach ((var gas, (var mol, var percent, var alert)) in gasData)
|
||||
{
|
||||
FixedPoint2 gasPercent = percent * 100f;
|
||||
var gasPercent = (FixedPoint2)0f;
|
||||
gasPercent = percent * 100f;
|
||||
|
||||
var gasShorthand = _gasShorthands.GetValueOrDefault(gas, "X");
|
||||
if (!_gasShorthands.TryGetValue(gas, out var gasShorthand))
|
||||
gasShorthand = "X";
|
||||
|
||||
var gasLabel = new Label()
|
||||
{
|
||||
|
||||
@@ -14,6 +14,8 @@ public sealed class AtmosAlertsComputerBoundUserInterface : BoundUserInterface
|
||||
_menu = new AtmosAlertsComputerWindow(this, Owner);
|
||||
_menu.OpenCentered();
|
||||
_menu.OnClose += Close;
|
||||
|
||||
EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
@@ -22,6 +24,9 @@ public sealed class AtmosAlertsComputerBoundUserInterface : BoundUserInterface
|
||||
|
||||
var castState = (AtmosAlertsComputerBoundInterfaceState) state;
|
||||
|
||||
if (castState == null)
|
||||
return;
|
||||
|
||||
EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
|
||||
_menu?.UpdateUI(xform?.Coordinates, castState.AirAlarms, castState.FireAlarms, castState.FocusData);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.Pinpointer.UI"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
Title="{Loc 'atmos-alerts-window-title'}"
|
||||
Resizable="False"
|
||||
SetSize="1120 750"
|
||||
|
||||
@@ -23,7 +23,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
||||
{
|
||||
private readonly IEntityManager _entManager;
|
||||
private readonly SpriteSystem _spriteSystem;
|
||||
private readonly SharedNavMapSystem _navMapSystem;
|
||||
|
||||
private EntityUid? _owner;
|
||||
private NetEntity? _trackedEntity;
|
||||
@@ -43,32 +42,19 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
||||
|
||||
private const float SilencingDuration = 2.5f;
|
||||
|
||||
// Colors
|
||||
private Color _wallColor = new Color(64, 64, 64);
|
||||
private Color _tileColor = new Color(28, 28, 28);
|
||||
private Color _monitorBlipColor = Color.Cyan;
|
||||
private Color _untrackedEntColor = Color.DimGray;
|
||||
private Color _regionBaseColor = new Color(154, 154, 154);
|
||||
private Color _inactiveColor = StyleNano.DisabledFore;
|
||||
private Color _statusTextColor = StyleNano.GoodGreenFore;
|
||||
private Color _goodColor = Color.LimeGreen;
|
||||
private Color _warningColor = new Color(255, 182, 72);
|
||||
private Color _dangerColor = new Color(255, 67, 67);
|
||||
|
||||
public AtmosAlertsComputerWindow(AtmosAlertsComputerBoundUserInterface userInterface, EntityUid? owner)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||
_spriteSystem = _entManager.System<SpriteSystem>();
|
||||
_navMapSystem = _entManager.System<SharedNavMapSystem>();
|
||||
|
||||
// Pass the owner to nav map
|
||||
_owner = owner;
|
||||
NavMap.Owner = _owner;
|
||||
|
||||
// Set nav map colors
|
||||
NavMap.WallColor = _wallColor;
|
||||
NavMap.TileColor = _tileColor;
|
||||
NavMap.WallColor = new Color(64, 64, 64);
|
||||
NavMap.TileColor = Color.DimGray * NavMap.WallColor;
|
||||
|
||||
// Set nav map grid uid
|
||||
var stationName = Loc.GetString("atmos-alerts-window-unknown-location");
|
||||
@@ -193,9 +179,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
||||
// Add tracked entities to the nav map
|
||||
foreach (var device in console.AtmosDevices)
|
||||
{
|
||||
if (!device.NetEntity.Valid)
|
||||
continue;
|
||||
|
||||
if (!NavMap.Visible)
|
||||
continue;
|
||||
|
||||
@@ -226,7 +209,7 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
||||
if (consoleCoords != null && consoleUid != null)
|
||||
{
|
||||
var texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")));
|
||||
var blip = new NavMapBlip(consoleCoords.Value, texture, _monitorBlipColor, true, false);
|
||||
var blip = new NavMapBlip(consoleCoords.Value, texture, Color.Cyan, true, false);
|
||||
NavMap.TrackedEntities[consoleUid.Value] = blip;
|
||||
}
|
||||
|
||||
@@ -275,7 +258,7 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
||||
VerticalAlignment = VAlignment.Center,
|
||||
};
|
||||
|
||||
label.SetMarkup(Loc.GetString("atmos-alerts-window-no-active-alerts", ("color", _statusTextColor.ToHexNoAlpha())));
|
||||
label.SetMarkup(Loc.GetString("atmos-alerts-window-no-active-alerts", ("color", StyleNano.GoodGreenFore.ToHexNoAlpha())));
|
||||
|
||||
AlertsTable.AddChild(label);
|
||||
}
|
||||
@@ -287,34 +270,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
||||
else
|
||||
MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-alerts-window-tab-alerts", ("value", activeAlarmCount)));
|
||||
|
||||
// Update sensor regions
|
||||
NavMap.RegionOverlays.Clear();
|
||||
var prioritizedRegionOverlays = new Dictionary<NavMapRegionOverlay, int>();
|
||||
|
||||
if (_owner != null &&
|
||||
_entManager.TryGetComponent<TransformComponent>(_owner, out var xform) &&
|
||||
_entManager.TryGetComponent<NavMapComponent>(xform.GridUid, out var navMap))
|
||||
{
|
||||
var regionOverlays = _navMapSystem.GetNavMapRegionOverlays(_owner.Value, navMap, AtmosAlertsComputerUiKey.Key);
|
||||
|
||||
foreach (var (regionOwner, regionOverlay) in regionOverlays)
|
||||
{
|
||||
var alarmState = GetAlarmState(regionOwner);
|
||||
|
||||
if (!TryGetSensorRegionColor(regionOwner, alarmState, out var regionColor))
|
||||
continue;
|
||||
|
||||
regionOverlay.Color = regionColor;
|
||||
|
||||
var priority = (_trackedEntity == regionOwner) ? 999 : (int)alarmState;
|
||||
prioritizedRegionOverlays.Add(regionOverlay, priority);
|
||||
}
|
||||
|
||||
// Sort overlays according to their priority
|
||||
var sortedOverlays = prioritizedRegionOverlays.OrderBy(x => x.Value).Select(x => x.Key).ToList();
|
||||
NavMap.RegionOverlays = sortedOverlays;
|
||||
}
|
||||
|
||||
// Auto-scroll re-enable
|
||||
if (_autoScrollAwaitsUpdate)
|
||||
{
|
||||
@@ -335,7 +290,7 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
||||
var coords = _entManager.GetCoordinates(metaData.NetCoordinates);
|
||||
|
||||
if (_trackedEntity != null && _trackedEntity != metaData.NetEntity)
|
||||
color *= _untrackedEntColor;
|
||||
color *= Color.DimGray;
|
||||
|
||||
var selectable = true;
|
||||
var blip = new NavMapBlip(coords, _spriteSystem.Frame0(texture), color, _trackedEntity == metaData.NetEntity, selectable);
|
||||
@@ -343,24 +298,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
||||
NavMap.TrackedEntities[metaData.NetEntity] = blip;
|
||||
}
|
||||
|
||||
private bool TryGetSensorRegionColor(NetEntity regionOwner, AtmosAlarmType alarmState, out Color color)
|
||||
{
|
||||
color = Color.White;
|
||||
|
||||
var blip = GetBlipTexture(alarmState);
|
||||
|
||||
if (blip == null)
|
||||
return false;
|
||||
|
||||
// Color the region based on alarm state and entity tracking
|
||||
color = blip.Value.Item2 * _regionBaseColor;
|
||||
|
||||
if (_trackedEntity != null && _trackedEntity != regionOwner)
|
||||
color *= _untrackedEntColor;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateUIEntry(AtmosAlertsComputerEntry entry, int index, Control table, AtmosAlertsComputerComponent console, AtmosAlertsFocusDeviceData? focusData = null)
|
||||
{
|
||||
// Make new UI entry if required
|
||||
@@ -597,13 +534,13 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
||||
switch (alarmState)
|
||||
{
|
||||
case AtmosAlarmType.Invalid:
|
||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), _inactiveColor); break;
|
||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), StyleNano.DisabledFore); break;
|
||||
case AtmosAlarmType.Normal:
|
||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), _goodColor); break;
|
||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), Color.LimeGreen); break;
|
||||
case AtmosAlarmType.Warning:
|
||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), _warningColor); break;
|
||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), new Color(255, 182, 72)); break;
|
||||
case AtmosAlarmType.Danger:
|
||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_square.png")), _dangerColor); break;
|
||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_square.png")), new Color(255, 67, 67)); break;
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
@@ -4,6 +4,8 @@ using Content.Shared.Atmos.Components;
|
||||
using Content.Shared.Atmos.Piping;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||
|
||||
namespace Content.Client.Atmos.EntitySystems;
|
||||
|
||||
@@ -17,7 +19,7 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<PipeAppearanceComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<PipeAppearanceComponent, AppearanceChangeEvent>(OnAppearanceChanged, after: [typeof(SubFloorHideSystem)]);
|
||||
SubscribeLocalEvent<PipeAppearanceComponent, AppearanceChangeEvent>(OnAppearanceChanged, after: new[] { typeof(SubFloorHideSystem) });
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, PipeAppearanceComponent component, ComponentInit args)
|
||||
@@ -82,8 +84,7 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
|
||||
|
||||
layer.Visible &= visible;
|
||||
|
||||
if (!visible)
|
||||
continue;
|
||||
if (!visible) continue;
|
||||
|
||||
layer.Color = color;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Power;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor;
|
||||
|
||||
@@ -22,7 +27,7 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
|
||||
{
|
||||
foreach (var visLayer in component.HideOnDepowered)
|
||||
{
|
||||
if (args.Sprite.LayerMapTryGet(visLayer, out var powerVisibilityLayer))
|
||||
if (args.Sprite.LayerMapTryGet(visLayer, out int powerVisibilityLayer))
|
||||
args.Sprite.LayerSetVisible(powerVisibilityLayer, powered);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +36,7 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
|
||||
{
|
||||
foreach (var (setLayer, powerState) in component.SetOnDepowered)
|
||||
{
|
||||
if (args.Sprite.LayerMapTryGet(setLayer, out var setStateLayer))
|
||||
if (args.Sprite.LayerMapTryGet(setLayer, out int setStateLayer))
|
||||
args.Sprite.LayerSetState(setStateLayer, new RSI.StateId(powerState));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor.UI;
|
||||
|
||||
@@ -74,7 +78,6 @@ public sealed class AirAlarmBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
_window?.Dispose();
|
||||
if (disposing) _window?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using Content.Shared.Atmos.Monitor.Components;
|
||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||
using Content.Shared.Temperature;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
@@ -58,7 +59,7 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
||||
AirAlarmMode.Fill => "air-alarm-ui-mode-fill",
|
||||
AirAlarmMode.Panic => "air-alarm-ui-mode-panic",
|
||||
AirAlarmMode.None => "air-alarm-ui-mode-none",
|
||||
_ => "error",
|
||||
_ => "error"
|
||||
};
|
||||
_modes.AddItem(Loc.GetString(text));
|
||||
}
|
||||
@@ -69,7 +70,7 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
||||
AirAlarmModeChanged!.Invoke((AirAlarmMode) args.Id);
|
||||
};
|
||||
|
||||
_autoMode.OnToggled += _ =>
|
||||
_autoMode.OnToggled += args =>
|
||||
{
|
||||
AutoModeChanged!.Invoke(_autoMode.Pressed);
|
||||
};
|
||||
@@ -175,18 +176,22 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
||||
|
||||
public static Color ColorForThreshold(float amount, AtmosAlarmThreshold threshold)
|
||||
{
|
||||
threshold.CheckThreshold(amount, out var curAlarm);
|
||||
threshold.CheckThreshold(amount, out AtmosAlarmType curAlarm);
|
||||
return ColorForAlarm(curAlarm);
|
||||
}
|
||||
|
||||
public static Color ColorForAlarm(AtmosAlarmType curAlarm)
|
||||
{
|
||||
return curAlarm switch
|
||||
if(curAlarm == AtmosAlarmType.Danger)
|
||||
{
|
||||
AtmosAlarmType.Danger => StyleNano.DangerousRedFore,
|
||||
AtmosAlarmType.Warning => StyleNano.ConcerningOrangeFore,
|
||||
_ => StyleNano.GoodGreenFore,
|
||||
};
|
||||
return StyleNano.DangerousRedFore;
|
||||
}
|
||||
else if(curAlarm == AtmosAlarmType.Warning)
|
||||
{
|
||||
return StyleNano.ConcerningOrangeFore;
|
||||
}
|
||||
|
||||
return StyleNano.GoodGreenFore;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using System;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
||||
|
||||
@@ -21,7 +25,7 @@ public sealed partial class PumpControl : BoxContainer
|
||||
private OptionButton _pressureCheck => CPressureCheck;
|
||||
private FloatSpinBox _externalBound => CExternalBound;
|
||||
private FloatSpinBox _internalBound => CInternalBound;
|
||||
private Button _copySettings => CCopySettings;
|
||||
private Button _copySettings => CCopySettings;
|
||||
|
||||
public PumpControl(GasVentPumpData data, string address)
|
||||
{
|
||||
@@ -82,7 +86,7 @@ public sealed partial class PumpControl : BoxContainer
|
||||
_data.PressureChecks = (VentPressureBound) args.Id;
|
||||
PumpDataChanged?.Invoke(_address, _data);
|
||||
};
|
||||
|
||||
|
||||
_copySettings.OnPressed += _ =>
|
||||
{
|
||||
PumpDataCopied?.Invoke(_data);
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
||||
|
||||
@@ -21,7 +27,7 @@ public sealed partial class ScrubberControl : BoxContainer
|
||||
private OptionButton _pumpDirection => CPumpDirection;
|
||||
private FloatSpinBox _volumeRate => CVolumeRate;
|
||||
private CheckBox _wideNet => CWideNet;
|
||||
private Button _copySettings => CCopySettings;
|
||||
private Button _copySettings => CCopySettings;
|
||||
|
||||
private GridContainer _gases => CGasContainer;
|
||||
private Dictionary<Gas, Button> _gasControls = new();
|
||||
@@ -71,7 +77,7 @@ public sealed partial class ScrubberControl : BoxContainer
|
||||
_data.PumpDirection = (ScrubberPumpDirection) args.Id;
|
||||
ScrubberDataChanged?.Invoke(_address, _data);
|
||||
};
|
||||
|
||||
|
||||
_copySettings.OnPressed += _ =>
|
||||
{
|
||||
ScrubberDataCopied?.Invoke(_data);
|
||||
|
||||
@@ -43,8 +43,7 @@ public sealed partial class SensorInfo : BoxContainer
|
||||
var label = new RichTextLabel();
|
||||
|
||||
var fractionGas = amount / data.TotalMoles;
|
||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
|
||||
("gas", $"{gas}"),
|
||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator", ("gas", $"{gas}"),
|
||||
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
||||
("amount", $"{amount:0.####}"),
|
||||
("percentage", $"{(100 * fractionGas):0.##}")));
|
||||
@@ -54,9 +53,9 @@ public sealed partial class SensorInfo : BoxContainer
|
||||
var threshold = data.GasThresholds[gas];
|
||||
var gasThresholdControl = new ThresholdControl(Loc.GetString($"air-alarm-ui-thresholds-gas-title", ("gas", $"{gas}")), threshold, AtmosMonitorThresholdType.Gas, gas, 100);
|
||||
gasThresholdControl.Margin = new Thickness(20, 2, 2, 2);
|
||||
gasThresholdControl.ThresholdDataChanged += (type, alarmThreshold, arg3) =>
|
||||
gasThresholdControl.ThresholdDataChanged += (type, threshold, arg3) =>
|
||||
{
|
||||
OnThresholdUpdate!(_address, type, alarmThreshold, arg3);
|
||||
OnThresholdUpdate!(_address, type, threshold, arg3);
|
||||
};
|
||||
|
||||
_gasThresholds.Add(gas, gasThresholdControl);
|
||||
@@ -65,8 +64,7 @@ public sealed partial class SensorInfo : BoxContainer
|
||||
|
||||
_pressureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-pressure-title"), data.PressureThreshold, AtmosMonitorThresholdType.Pressure);
|
||||
PressureThresholdContainer.AddChild(_pressureThreshold);
|
||||
_temperatureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-temperature-title"),
|
||||
data.TemperatureThreshold,
|
||||
_temperatureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-temperature-title"), data.TemperatureThreshold,
|
||||
AtmosMonitorThresholdType.Temperature);
|
||||
TemperatureThresholdContainer.AddChild(_temperatureThreshold);
|
||||
|
||||
@@ -105,8 +103,7 @@ public sealed partial class SensorInfo : BoxContainer
|
||||
}
|
||||
|
||||
var fractionGas = amount / data.TotalMoles;
|
||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
|
||||
("gas", $"{gas}"),
|
||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator", ("gas", $"{gas}"),
|
||||
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
||||
("amount", $"{amount:0.####}"),
|
||||
("percentage", $"{(100 * fractionGas):0.##}")));
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using Content.Client.Message;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Temperature;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using System;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
// holy FUCK
|
||||
// this technically works because some of this you can *not* do in XAML but holy FUCK
|
||||
@@ -111,38 +115,29 @@ public sealed partial class ThresholdControl : BoxContainer
|
||||
_enabled.Pressed = !_threshold.Ignore;
|
||||
}
|
||||
|
||||
private string LabelForBound(string boundType) //<todo.eoin Replace this with enums
|
||||
private String LabelForBound(string boundType) //<todo.eoin Replace this with enums
|
||||
{
|
||||
return Loc.GetString($"air-alarm-ui-thresholds-{boundType}");
|
||||
}
|
||||
|
||||
public void UpdateThresholdData(AtmosAlarmThreshold threshold, float currentAmount)
|
||||
{
|
||||
threshold.CheckThreshold(currentAmount, out var alarm, out var bound);
|
||||
threshold.CheckThreshold(currentAmount, out AtmosAlarmType alarm, out AtmosMonitorThresholdBound which);
|
||||
|
||||
var upperDangerState = AtmosAlarmType.Normal;
|
||||
var lowerDangerState = AtmosAlarmType.Normal;
|
||||
var upperWarningState = AtmosAlarmType.Normal;
|
||||
var lowerWarningState = AtmosAlarmType.Normal;
|
||||
|
||||
switch (alarm)
|
||||
if(alarm == AtmosAlarmType.Danger)
|
||||
{
|
||||
case AtmosAlarmType.Danger:
|
||||
{
|
||||
if (bound == AtmosMonitorThresholdBound.Upper)
|
||||
upperDangerState = alarm;
|
||||
else
|
||||
lowerDangerState = alarm;
|
||||
break;
|
||||
}
|
||||
case AtmosAlarmType.Warning:
|
||||
{
|
||||
if (bound == AtmosMonitorThresholdBound.Upper)
|
||||
upperWarningState = alarm;
|
||||
else
|
||||
lowerWarningState = alarm;
|
||||
break;
|
||||
}
|
||||
if(which == AtmosMonitorThresholdBound.Upper) upperDangerState = alarm;
|
||||
else lowerDangerState = alarm;
|
||||
}
|
||||
else if(alarm == AtmosAlarmType.Warning)
|
||||
{
|
||||
if(which == AtmosMonitorThresholdBound.Upper) upperWarningState = alarm;
|
||||
else lowerWarningState = alarm;
|
||||
}
|
||||
|
||||
_upperBoundControl.SetValue(threshold.UpperBound.Value);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client.Atmos.EntitySystems;
|
||||
@@ -102,9 +101,14 @@ public sealed class AtmosDebugOverlay : Overlay
|
||||
else
|
||||
{
|
||||
// Red-Green-Blue interpolation
|
||||
res = interp < 0.5f
|
||||
? Color.InterpolateBetween(Color.Red, Color.LimeGreen, interp * 2)
|
||||
: Color.InterpolateBetween(Color.LimeGreen, Color.Blue, (interp - 0.5f) * 2);
|
||||
if (interp < 0.5f)
|
||||
{
|
||||
res = Color.InterpolateBetween(Color.Red, Color.LimeGreen, interp * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = Color.InterpolateBetween(Color.LimeGreen, Color.Blue, (interp - 0.5f) * 2);
|
||||
}
|
||||
}
|
||||
|
||||
res = res.WithAlpha(0.75f);
|
||||
@@ -177,10 +181,7 @@ public sealed class AtmosDebugOverlay : Overlay
|
||||
handle.DrawCircle(tileCentre, 0.05f, Color.Black);
|
||||
}
|
||||
|
||||
private void CheckAndShowBlockDir(
|
||||
AtmosDebugOverlayData data,
|
||||
DrawingHandleWorld handle,
|
||||
AtmosDirection dir,
|
||||
private void CheckAndShowBlockDir(AtmosDebugOverlayData data, DrawingHandleWorld handle, AtmosDirection dir,
|
||||
Vector2 tileCentre)
|
||||
{
|
||||
if (!data.BlockDirection.HasFlag(dir))
|
||||
@@ -242,7 +243,7 @@ public sealed class AtmosDebugOverlay : Overlay
|
||||
|
||||
var moles = data.Moles == null
|
||||
? "No Air"
|
||||
: data.Moles.Sum().ToString(CultureInfo.InvariantCulture);
|
||||
: data.Moles.Sum().ToString();
|
||||
|
||||
handle.DrawString(_font, pos, $"Moles: {moles}");
|
||||
pos += offset;
|
||||
@@ -262,12 +263,7 @@ public sealed class AtmosDebugOverlay : Overlay
|
||||
private void GetGrids(MapId mapId, Box2Rotated box)
|
||||
{
|
||||
_grids.Clear();
|
||||
_mapManager.FindGridsIntersecting(
|
||||
mapId,
|
||||
box,
|
||||
ref _grids,
|
||||
(EntityUid uid,
|
||||
MapGridComponent grid,
|
||||
_mapManager.FindGridsIntersecting(mapId, box, ref _grids, (EntityUid uid, MapGridComponent grid,
|
||||
ref List<(Entity<MapGridComponent>, DebugMessage)> state) =>
|
||||
{
|
||||
if (_system.TileData.TryGetValue(uid, out var data))
|
||||
|
||||
@@ -43,8 +43,6 @@ public sealed partial class ContentAudioSystem
|
||||
|
||||
private void CP14UpdateAmbientLoops()
|
||||
{
|
||||
return; //DISABLED UNTIL CLIENT ERROR SPAM FIXED
|
||||
|
||||
if (_timing.CurTime <= _nextUpdateTime)
|
||||
return;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ public sealed partial class ContentAudioSystem
|
||||
{
|
||||
[Dependency] private readonly IBaseClient _client = default!;
|
||||
[Dependency] private readonly ClientGameTicker _gameTicker = default!;
|
||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
|
||||
private readonly AudioParams _lobbySoundtrackParams = new(-5f, 1, 0, 0, 0, false, 0f);
|
||||
@@ -70,7 +71,7 @@ public sealed partial class ContentAudioSystem
|
||||
Subs.CVar(_configManager, CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
|
||||
Subs.CVar(_configManager, CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
|
||||
|
||||
_state.OnStateChanged += StateManagerOnStateChanged;
|
||||
_stateManager.OnStateChanged += StateManagerOnStateChanged;
|
||||
|
||||
_client.PlayerLeaveServer += OnLeave;
|
||||
|
||||
@@ -114,7 +115,7 @@ public sealed partial class ContentAudioSystem
|
||||
|
||||
private void LobbyMusicCVarChanged(bool musicEnabled)
|
||||
{
|
||||
if (musicEnabled && _state.CurrentState is LobbyState)
|
||||
if (musicEnabled && _stateManager.CurrentState is LobbyState)
|
||||
{
|
||||
StartLobbyMusic();
|
||||
}
|
||||
@@ -233,7 +234,7 @@ public sealed partial class ContentAudioSystem
|
||||
|
||||
private void ShutdownLobbyMusic()
|
||||
{
|
||||
_state.OnStateChanged -= StateManagerOnStateChanged;
|
||||
_stateManager.OnStateChanged -= StateManagerOnStateChanged;
|
||||
|
||||
_client.PlayerLeaveServer -= OnLeave;
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
using Content.Shared.Timing;
|
||||
using Content.Shared.Cargo.Systems;
|
||||
|
||||
namespace Content.Client.Cargo.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// This handles...
|
||||
/// </summary>
|
||||
public sealed class ClientPriceGunSystem : SharedPriceGunSystem
|
||||
{
|
||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
||||
|
||||
protected override bool GetPriceOrBounty(EntityUid priceGunUid, EntityUid target, EntityUid user)
|
||||
{
|
||||
if (!TryComp(priceGunUid, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((priceGunUid, useDelay)))
|
||||
return false;
|
||||
|
||||
// It feels worse if the cooldown is predicted but the popup isn't! So only do the cooldown reset on the server.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -21,16 +21,6 @@ internal sealed class ChatManager : IChatManager
|
||||
_sawmill.Level = LogLevel.Info;
|
||||
}
|
||||
|
||||
public void SendAdminAlert(string message)
|
||||
{
|
||||
// See server-side manager. This just exists for shared code.
|
||||
}
|
||||
|
||||
public void SendAdminAlert(EntityUid player, string message)
|
||||
{
|
||||
// See server-side manager. This just exists for shared code.
|
||||
}
|
||||
|
||||
public void SendMessage(string text, ChatSelectChannel channel)
|
||||
{
|
||||
var str = text.ToString();
|
||||
|
||||
@@ -2,8 +2,10 @@ using Content.Shared.Chat;
|
||||
|
||||
namespace Content.Client.Chat.Managers
|
||||
{
|
||||
public interface IChatManager : ISharedChatManager
|
||||
public interface IChatManager
|
||||
{
|
||||
void Initialize();
|
||||
|
||||
public void SendMessage(string text, ChatSelectChannel channel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||
/// For some context, im currently refactoring inventory. Part of that is slots not being indexed by a massive enum anymore, but by strings.
|
||||
/// Problem here: Every rsi-state is using the old enum-names in their state. I already used the new inventoryslots ALOT. tldr: its this or another week of renaming files.
|
||||
/// </summary>
|
||||
public static readonly Dictionary<string, string> TemporarySlotMap = new() //CP14 Public
|
||||
private static readonly Dictionary<string, string> TemporarySlotMap = new()
|
||||
{
|
||||
{"head", "HELMET"},
|
||||
{"eyes", "EYES"},
|
||||
@@ -65,7 +65,6 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ClothingComponent, GetEquipmentVisualsEvent>(OnGetVisuals);
|
||||
SubscribeLocalEvent<ClothingComponent, InventoryTemplateUpdated>(OnInventoryTemplateUpdated);
|
||||
|
||||
SubscribeLocalEvent<InventoryComponent, VisualsChangedEvent>(OnVisualsChanged);
|
||||
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
|
||||
@@ -78,7 +77,11 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||
if (args.Sprite == null)
|
||||
return;
|
||||
|
||||
UpdateAllSlots(uid, component);
|
||||
var enumerator = _inventorySystem.GetSlotEnumerator((uid, component));
|
||||
while (enumerator.NextItem(out var item, out var slot))
|
||||
{
|
||||
RenderEquipment(uid, item, slot.Name, component);
|
||||
}
|
||||
|
||||
// No clothing equipped -> make sure the layer is hidden, though this should already be handled by on-unequip.
|
||||
if (args.Sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var layer))
|
||||
@@ -88,23 +91,6 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInventoryTemplateUpdated(Entity<ClothingComponent> ent, ref InventoryTemplateUpdated args)
|
||||
{
|
||||
UpdateAllSlots(ent.Owner, clothing: ent.Comp);
|
||||
}
|
||||
|
||||
private void UpdateAllSlots(
|
||||
EntityUid uid,
|
||||
InventoryComponent? inventoryComponent = null,
|
||||
ClothingComponent? clothing = null)
|
||||
{
|
||||
var enumerator = _inventorySystem.GetSlotEnumerator((uid, inventoryComponent));
|
||||
while (enumerator.NextItem(out var item, out var slot))
|
||||
{
|
||||
RenderEquipment(uid, item, slot.Name, inventoryComponent, clothingComponent: clothing);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGetVisuals(EntityUid uid, ClothingComponent item, GetEquipmentVisualsEvent args)
|
||||
{
|
||||
if (!TryComp(args.Equipee, out InventoryComponent? inventory))
|
||||
@@ -341,8 +327,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||
if (layerData.State is not null && inventory.SpeciesId is not null && layerData.State.EndsWith(inventory.SpeciesId))
|
||||
continue;
|
||||
|
||||
if (_displacement.TryAddDisplacement(displacementData, sprite, index, key, revealedLayers))
|
||||
index++;
|
||||
_displacement.TryAddDisplacement(displacementData, sprite, index, key, revealedLayers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Clothing;
|
||||
|
||||
public sealed class FlippableClothingVisualizerSystem : VisualizerSystem<FlippableClothingVisualsComponent>
|
||||
public sealed class FlippableClothingVisualizerSystem : VisualizerSystem<FlippableClothingVisualsComponent>
|
||||
{
|
||||
[Dependency] private readonly SharedItemSystem _itemSys = default!;
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Overlays;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Prototypes;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Client.Commands;
|
||||
@@ -36,7 +34,7 @@ public sealed class ShowHealthBarsCommand : LocalizedCommands
|
||||
{
|
||||
var showHealthBarsComponent = new ShowHealthBarsComponent
|
||||
{
|
||||
DamageContainers = args.Select(arg => new ProtoId<DamageContainerPrototype>(arg)).ToList(),
|
||||
DamageContainers = args.ToList(),
|
||||
HealthStatusIcon = null,
|
||||
NetSyncEnabled = false
|
||||
};
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" MinWidth="243" Margin="0 0 5 0">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.4" Margin="0 0 5 0">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 0 0 5">
|
||||
<LineEdit Name="SearchBar" PlaceHolder="Search" HorizontalExpand="True"/>
|
||||
<OptionButton Name="OptionCategories" Access="Public" MinSize="130 0"/>
|
||||
</BoxContainer>
|
||||
<ItemList Name="Recipes" Access="Public" SelectMode="Single" VerticalExpand="True"/>
|
||||
<ScrollContainer Name="RecipesGridScrollContainer" VerticalExpand="True" Access="Public" Visible="False">
|
||||
<GridContainer Name="RecipesGrid" Columns="5" Access="Public"/>
|
||||
</ScrollContainer>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Button Name="MenuGridViewButton" ToggleMode="True" Text="{Loc construction-menu-grid-view}"/>
|
||||
<Button Name="FavoriteButton" Visible="false"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.6">
|
||||
<Button Name="FavoriteButton" Visible="false" HorizontalExpand="False"
|
||||
HorizontalAlignment="Right" Margin="0 0 0 15"/>
|
||||
<Control>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="0 0 0 5">
|
||||
<BoxContainer Orientation="Horizontal" Align="Center">
|
||||
|
||||
@@ -25,16 +25,11 @@ namespace Content.Client.Construction.UI
|
||||
OptionButton OptionCategories { get; }
|
||||
|
||||
bool EraseButtonPressed { get; set; }
|
||||
bool GridViewButtonPressed { get; set; }
|
||||
bool BuildButtonPressed { get; set; }
|
||||
|
||||
ItemList Recipes { get; }
|
||||
ItemList RecipeStepList { get; }
|
||||
|
||||
|
||||
ScrollContainer RecipesGridScrollContainer { get; }
|
||||
GridContainer RecipesGrid { get; }
|
||||
|
||||
event EventHandler<(string search, string catagory)> PopulateRecipes;
|
||||
event EventHandler<ItemList.Item?> RecipeSelected;
|
||||
event EventHandler RecipeFavorited;
|
||||
@@ -77,16 +72,9 @@ namespace Content.Client.Construction.UI
|
||||
set => EraseButton.Pressed = value;
|
||||
}
|
||||
|
||||
public bool GridViewButtonPressed
|
||||
{
|
||||
get => MenuGridViewButton.Pressed;
|
||||
set => MenuGridViewButton.Pressed = value;
|
||||
}
|
||||
|
||||
public ConstructionMenu()
|
||||
{
|
||||
SetSize = new Vector2(560, 450);
|
||||
MinSize = new Vector2(560, 320);
|
||||
SetSize = MinSize = new Vector2(720, 320);
|
||||
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
@@ -114,9 +102,6 @@ namespace Content.Client.Construction.UI
|
||||
EraseButton.OnToggled += args => EraseButtonToggled?.Invoke(this, args.Pressed);
|
||||
|
||||
FavoriteButton.OnPressed += args => RecipeFavorited?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
MenuGridViewButton.OnPressed += _ =>
|
||||
PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[OptionCategories.SelectedId]));
|
||||
}
|
||||
|
||||
public event EventHandler? ClearAllGhosts;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Client.UserInterface.Systems.MenuBar.Widgets;
|
||||
using Content.Shared.Construction.Prototypes;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
@@ -12,6 +11,7 @@ using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Graphics;
|
||||
using Robust.Shared.Prototypes;
|
||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
||||
|
||||
@@ -33,12 +33,10 @@ namespace Content.Client.Construction.UI
|
||||
|
||||
private readonly IConstructionMenuView _constructionView;
|
||||
private readonly EntityWhitelistSystem _whitelistSystem;
|
||||
private readonly SpriteSystem _spriteSystem;
|
||||
|
||||
private ConstructionSystem? _constructionSystem;
|
||||
private ConstructionPrototype? _selected;
|
||||
private List<ConstructionPrototype> _favoritedRecipes = [];
|
||||
private Dictionary<string, TextureButton> _recipeButtons = new();
|
||||
private string _selectedCategory = string.Empty;
|
||||
private string _favoriteCatName = "construction-category-favorites";
|
||||
private string _forAllCategoryName = "construction-category-all";
|
||||
@@ -87,7 +85,6 @@ namespace Content.Client.Construction.UI
|
||||
IoCManager.InjectDependencies(this);
|
||||
_constructionView = new ConstructionMenu();
|
||||
_whitelistSystem = _entManager.System<EntityWhitelistSystem>();
|
||||
_spriteSystem = _entManager.System<SpriteSystem>();
|
||||
|
||||
// This is required so that if we load after the system is initialized, we can bind to it immediately
|
||||
if (_systemManager.TryGetEntitySystem<ConstructionSystem>(out var constructionSystem))
|
||||
@@ -153,24 +150,12 @@ namespace Content.Client.Construction.UI
|
||||
PopulateInfo(_selected);
|
||||
}
|
||||
|
||||
private void OnGridViewRecipeSelected(object? sender, ConstructionPrototype? recipe)
|
||||
{
|
||||
if (recipe is null)
|
||||
{
|
||||
_selected = null;
|
||||
_constructionView.ClearRecipeInfo();
|
||||
return;
|
||||
}
|
||||
|
||||
_selected = recipe;
|
||||
if (_placementManager.IsActive && !_placementManager.Eraser) UpdateGhostPlacement();
|
||||
PopulateInfo(_selected);
|
||||
}
|
||||
|
||||
private void OnViewPopulateRecipes(object? sender, (string search, string catagory) args)
|
||||
{
|
||||
var (search, category) = args;
|
||||
var recipesList = _constructionView.Recipes;
|
||||
|
||||
recipesList.Clear();
|
||||
var recipes = new List<ConstructionPrototype>();
|
||||
|
||||
var isEmptyCategory = string.IsNullOrEmpty(category) || category == _forAllCategoryName;
|
||||
@@ -185,7 +170,7 @@ namespace Content.Client.Construction.UI
|
||||
if (recipe.Hide)
|
||||
continue;
|
||||
|
||||
if (!recipe.CrystallPunkAllowed) //CrystallEdge clearing recipes
|
||||
if (!recipe.CrystallPunkAllowed) //CrystallPunk clearing recipes
|
||||
continue;
|
||||
|
||||
if (_playerManager.LocalSession == null
|
||||
@@ -219,73 +204,12 @@ namespace Content.Client.Construction.UI
|
||||
|
||||
recipes.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.InvariantCulture));
|
||||
|
||||
var recipesList = _constructionView.Recipes;
|
||||
recipesList.Clear();
|
||||
|
||||
var recipesGrid = _constructionView.RecipesGrid;
|
||||
recipesGrid.RemoveAllChildren();
|
||||
|
||||
_constructionView.RecipesGridScrollContainer.Visible = _constructionView.GridViewButtonPressed;
|
||||
_constructionView.Recipes.Visible = !_constructionView.GridViewButtonPressed;
|
||||
|
||||
if (_constructionView.GridViewButtonPressed)
|
||||
foreach (var recipe in recipes)
|
||||
{
|
||||
foreach (var recipe in recipes)
|
||||
{
|
||||
var itemButton = new TextureButton
|
||||
{
|
||||
TextureNormal = _spriteSystem.Frame0(recipe.Icon),
|
||||
VerticalAlignment = Control.VAlignment.Center,
|
||||
Name = recipe.Name,
|
||||
ToolTip = recipe.Name,
|
||||
Scale = new Vector2(1.35f),
|
||||
ToggleMode = true,
|
||||
};
|
||||
var itemButtonPanelContainer = new PanelContainer
|
||||
{
|
||||
PanelOverride = new StyleBoxFlat { BackgroundColor = StyleNano.ButtonColorDefault },
|
||||
Children = { itemButton },
|
||||
};
|
||||
|
||||
itemButton.OnToggled += buttonToggledEventArgs =>
|
||||
{
|
||||
SelectGridButton(itemButton, buttonToggledEventArgs.Pressed);
|
||||
|
||||
if (buttonToggledEventArgs.Pressed &&
|
||||
_selected != null &&
|
||||
_recipeButtons.TryGetValue(_selected.Name, out var oldButton))
|
||||
{
|
||||
oldButton.Pressed = false;
|
||||
SelectGridButton(oldButton, false);
|
||||
}
|
||||
|
||||
OnGridViewRecipeSelected(this, buttonToggledEventArgs.Pressed ? recipe : null);
|
||||
};
|
||||
|
||||
recipesGrid.AddChild(itemButtonPanelContainer);
|
||||
_recipeButtons[recipe.Name] = itemButton;
|
||||
var isCurrentButtonSelected = _selected == recipe;
|
||||
itemButton.Pressed = isCurrentButtonSelected;
|
||||
SelectGridButton(itemButton, isCurrentButtonSelected);
|
||||
}
|
||||
recipesList.Add(GetItem(recipe, recipesList));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var recipe in recipes)
|
||||
{
|
||||
recipesList.Add(GetItem(recipe, recipesList));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectGridButton(TextureButton button, bool select)
|
||||
{
|
||||
if (button.Parent is not PanelContainer buttonPanel)
|
||||
return;
|
||||
|
||||
button.Modulate = select ? Color.Green : Color.White;
|
||||
var buttonColor = select ? StyleNano.ButtonColorDefault : Color.Transparent;
|
||||
buttonPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = buttonColor };
|
||||
// There is apparently no way to set which
|
||||
}
|
||||
|
||||
private void PopulateCategories(string? selectCategory = null)
|
||||
@@ -336,10 +260,11 @@ namespace Content.Client.Construction.UI
|
||||
|
||||
private void PopulateInfo(ConstructionPrototype prototype)
|
||||
{
|
||||
var spriteSys = _systemManager.GetEntitySystem<SpriteSystem>();
|
||||
_constructionView.ClearRecipeInfo();
|
||||
|
||||
_constructionView.SetRecipeInfo(
|
||||
prototype.Name, prototype.Description, _spriteSystem.Frame0(prototype.Icon),
|
||||
prototype.Name, prototype.Description, spriteSys.Frame0(prototype.Icon),
|
||||
prototype.Type != ConstructionType.Item,
|
||||
!_favoritedRecipes.Contains(prototype));
|
||||
|
||||
@@ -352,6 +277,7 @@ namespace Content.Client.Construction.UI
|
||||
if (_constructionSystem?.GetGuide(prototype) is not { } guide)
|
||||
return;
|
||||
|
||||
var spriteSys = _systemManager.GetEntitySystem<SpriteSystem>();
|
||||
|
||||
foreach (var entry in guide.Entries)
|
||||
{
|
||||
@@ -367,20 +293,20 @@ namespace Content.Client.Construction.UI
|
||||
// The padding needs to be applied regardless of text length... (See PadLeft documentation)
|
||||
text = text.PadLeft(text.Length + entry.Padding);
|
||||
|
||||
var icon = entry.Icon != null ? _spriteSystem.Frame0(entry.Icon) : Texture.Transparent;
|
||||
var icon = entry.Icon != null ? spriteSys.Frame0(entry.Icon) : Texture.Transparent;
|
||||
stepList.AddItem(text, icon, false);
|
||||
}
|
||||
}
|
||||
|
||||
private ItemList.Item GetItem(ConstructionPrototype recipe, ItemList itemList)
|
||||
private static ItemList.Item GetItem(ConstructionPrototype recipe, ItemList itemList)
|
||||
{
|
||||
return new(itemList)
|
||||
{
|
||||
Metadata = recipe,
|
||||
Text = recipe.Name,
|
||||
Icon = _spriteSystem.Frame0(recipe.Icon),
|
||||
Icon = recipe.Icon.Frame0(),
|
||||
TooltipEnabled = true,
|
||||
TooltipText = recipe.Description,
|
||||
TooltipText = recipe.Description
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Content.Client.Crayon.UI
|
||||
private void PopulateCrayons()
|
||||
{
|
||||
var crayonDecals = _protoManager.EnumeratePrototypes<DecalPrototype>().Where(x => x.Tags.Contains("crayon"));
|
||||
_menu?.Populate(crayonDecals.ToList());
|
||||
_menu?.Populate(crayonDecals);
|
||||
}
|
||||
|
||||
public override void OnProtoReload(PrototypesReloadedEventArgs args)
|
||||
@@ -44,16 +44,6 @@ namespace Content.Client.Crayon.UI
|
||||
PopulateCrayons();
|
||||
}
|
||||
|
||||
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||
{
|
||||
base.ReceiveMessage(message);
|
||||
|
||||
if (_menu is null || message is not CrayonUsedMessage crayonMessage)
|
||||
return;
|
||||
|
||||
_menu.AdvanceState(crayonMessage.DrawnDecal);
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
Title="{Loc 'crayon-window-title'}"
|
||||
MinSize="450 500"
|
||||
SetSize="450 500">
|
||||
MinSize="250 300"
|
||||
SetSize="250 300">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<ColorSelectorSliders Name="ColorSelector" Visible="False" />
|
||||
<LineEdit Name="Search" Margin="0 0 0 8" PlaceHolder="{Loc 'crayon-window-placeholder'}" />
|
||||
<LineEdit Name="Search" />
|
||||
<ScrollContainer VerticalExpand="True">
|
||||
<BoxContainer Name="Grids" Orientation="Vertical">
|
||||
</BoxContainer>
|
||||
<GridContainer Name="Grid" Columns="6">
|
||||
<!-- Crayon decals get added here by code -->
|
||||
</GridContainer>
|
||||
</ScrollContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Crayon;
|
||||
using Content.Shared.Decals;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
@@ -20,12 +18,7 @@ namespace Content.Client.Crayon.UI
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CrayonWindow : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystem = default!;
|
||||
private readonly SpriteSystem _spriteSystem = default!;
|
||||
|
||||
private Dictionary<string, List<(string Name, Texture Texture)>>? _decals;
|
||||
private List<string>? _allDecals;
|
||||
private string? _autoSelected;
|
||||
private Dictionary<string, Texture>? _decals;
|
||||
private string? _selected;
|
||||
private Color _color;
|
||||
|
||||
@@ -35,10 +28,8 @@ namespace Content.Client.Crayon.UI
|
||||
public CrayonWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
_spriteSystem = _entitySystem.GetEntitySystem<SpriteSystem>();
|
||||
|
||||
Search.OnTextChanged += SearchChanged;
|
||||
Search.OnTextChanged += _ => RefreshList();
|
||||
ColorSelector.OnColorChanged += SelectColor;
|
||||
}
|
||||
|
||||
@@ -53,94 +44,51 @@ namespace Content.Client.Crayon.UI
|
||||
private void RefreshList()
|
||||
{
|
||||
// Clear
|
||||
Grids.DisposeAllChildren();
|
||||
|
||||
if (_decals == null || _allDecals == null)
|
||||
Grid.DisposeAllChildren();
|
||||
if (_decals == null)
|
||||
return;
|
||||
|
||||
var filter = Search.Text;
|
||||
var comma = filter.IndexOf(',');
|
||||
var first = (comma == -1 ? filter : filter[..comma]).Trim();
|
||||
|
||||
var names = _decals.Keys.ToList();
|
||||
names.Sort((a, b) => a == "random" ? 1 : b == "random" ? -1 : a.CompareTo(b));
|
||||
|
||||
if (_autoSelected != null && first != _autoSelected && _allDecals.Contains(first))
|
||||
foreach (var (decal, tex) in _decals)
|
||||
{
|
||||
_selected = first;
|
||||
_autoSelected = _selected;
|
||||
OnSelected?.Invoke(_selected);
|
||||
}
|
||||
|
||||
foreach (var categoryName in names)
|
||||
{
|
||||
var locName = Loc.GetString("crayon-category-" + categoryName);
|
||||
var category = _decals[categoryName].Where(d => locName.Contains(first) || d.Name.Contains(first)).ToList();
|
||||
|
||||
if (category.Count == 0)
|
||||
if (!decal.Contains(filter))
|
||||
continue;
|
||||
|
||||
var label = new Label
|
||||
var button = new TextureButton()
|
||||
{
|
||||
Text = locName
|
||||
TextureNormal = tex,
|
||||
Name = decal,
|
||||
ToolTip = decal,
|
||||
Modulate = _color,
|
||||
};
|
||||
|
||||
var grid = new GridContainer
|
||||
button.OnPressed += ButtonOnPressed;
|
||||
if (_selected == decal)
|
||||
{
|
||||
Columns = 6,
|
||||
Margin = new Thickness(0, 0, 0, 16)
|
||||
};
|
||||
|
||||
Grids.AddChild(label);
|
||||
Grids.AddChild(grid);
|
||||
|
||||
foreach (var (name, texture) in category)
|
||||
{
|
||||
var button = new TextureButton()
|
||||
var panelContainer = new PanelContainer()
|
||||
{
|
||||
TextureNormal = texture,
|
||||
Name = name,
|
||||
ToolTip = name,
|
||||
Modulate = _color,
|
||||
Scale = new System.Numerics.Vector2(2, 2)
|
||||
};
|
||||
button.OnPressed += ButtonOnPressed;
|
||||
|
||||
if (_selected == name)
|
||||
{
|
||||
var panelContainer = new PanelContainer()
|
||||
PanelOverride = new StyleBoxFlat()
|
||||
{
|
||||
PanelOverride = new StyleBoxFlat()
|
||||
{
|
||||
BackgroundColor = StyleNano.ButtonColorDefault,
|
||||
},
|
||||
Children =
|
||||
{
|
||||
button,
|
||||
},
|
||||
};
|
||||
grid.AddChild(panelContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.AddChild(button);
|
||||
}
|
||||
BackgroundColor = StyleNano.ButtonColorDefault,
|
||||
},
|
||||
Children =
|
||||
{
|
||||
button,
|
||||
},
|
||||
};
|
||||
Grid.AddChild(panelContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Grid.AddChild(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SearchChanged(LineEdit.LineEditEventArgs obj)
|
||||
{
|
||||
_autoSelected = ""; // Placeholder to kick off the auto-select in refreshlist()
|
||||
RefreshList();
|
||||
}
|
||||
|
||||
private void ButtonOnPressed(ButtonEventArgs obj)
|
||||
{
|
||||
if (obj.Button.Name == null) return;
|
||||
|
||||
_selected = obj.Button.Name;
|
||||
_autoSelected = null;
|
||||
OnSelected?.Invoke(_selected);
|
||||
RefreshList();
|
||||
}
|
||||
@@ -159,38 +107,12 @@ namespace Content.Client.Crayon.UI
|
||||
RefreshList();
|
||||
}
|
||||
|
||||
public void AdvanceState(string drawnDecal)
|
||||
public void Populate(IEnumerable<DecalPrototype> prototypes)
|
||||
{
|
||||
var filter = Search.Text;
|
||||
if (!filter.Contains(',') || !filter.Contains(drawnDecal))
|
||||
return;
|
||||
|
||||
var first = filter[..filter.IndexOf(',')].Trim();
|
||||
|
||||
if (first.Equals(drawnDecal, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
Search.Text = filter[(filter.IndexOf(',') + 1)..].Trim();
|
||||
_autoSelected = first;
|
||||
}
|
||||
|
||||
RefreshList();
|
||||
}
|
||||
|
||||
public void Populate(List<DecalPrototype> prototypes)
|
||||
{
|
||||
_decals = [];
|
||||
_allDecals = [];
|
||||
|
||||
prototypes.Sort((a, b) => a.ID.CompareTo(b.ID));
|
||||
|
||||
_decals = new Dictionary<string, Texture>();
|
||||
foreach (var decalPrototype in prototypes)
|
||||
{
|
||||
var category = "random";
|
||||
if (decalPrototype.Tags.Count > 1 && decalPrototype.Tags[1].StartsWith("crayon-"))
|
||||
category = decalPrototype.Tags[1].Replace("crayon-", "");
|
||||
var list = _decals.GetOrNew(category);
|
||||
list.Add((decalPrototype.ID, _spriteSystem.Frame0(decalPrototype.Sprite)));
|
||||
_allDecals.Add(decalPrototype.ID);
|
||||
_decals.Add(decalPrototype.ID, decalPrototype.Sprite.Frame0());
|
||||
}
|
||||
|
||||
RefreshList();
|
||||
|
||||
@@ -124,10 +124,6 @@ public sealed class ColorFlashEffectSystem : SharedColorFlashEffectSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
var targetEv = new GetFlashEffectTargetEvent(ent);
|
||||
RaiseLocalEvent(ent, ref targetEv);
|
||||
ent = targetEv.Target;
|
||||
|
||||
EnsureComp<ColorFlashEffectComponent>(ent, out comp);
|
||||
comp.NetSyncEnabled = false;
|
||||
comp.Color = sprite.Color;
|
||||
@@ -136,9 +132,3 @@ public sealed class ColorFlashEffectSystem : SharedColorFlashEffectSystem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on an entity to change the target for a color flash effect.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct GetFlashEffectTargetEvent(EntityUid Target);
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
using Content.Shared.Electrocution;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.Electrocution;
|
||||
|
||||
/// <summary>
|
||||
/// Shows the Electrocution HUD to entities with the ShowElectrocutionHUDComponent.
|
||||
/// </summary>
|
||||
public sealed class ElectrocutionHUDVisualizerSystem : VisualizerSystem<ElectrocutionHUDVisualsComponent>
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerMan = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ShowElectrocutionHUDComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<ShowElectrocutionHUDComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<ShowElectrocutionHUDComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<ShowElectrocutionHUDComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
|
||||
}
|
||||
|
||||
private void OnPlayerAttached(Entity<ShowElectrocutionHUDComponent> ent, ref LocalPlayerAttachedEvent args)
|
||||
{
|
||||
ShowHUD();
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(Entity<ShowElectrocutionHUDComponent> ent, ref LocalPlayerDetachedEvent args)
|
||||
{
|
||||
RemoveHUD();
|
||||
}
|
||||
|
||||
private void OnInit(Entity<ShowElectrocutionHUDComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
if (_playerMan.LocalEntity == ent)
|
||||
{
|
||||
ShowHUD();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnShutdown(Entity<ShowElectrocutionHUDComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (_playerMan.LocalEntity == ent)
|
||||
{
|
||||
RemoveHUD();
|
||||
}
|
||||
}
|
||||
|
||||
// Show the HUD to the client.
|
||||
// We have to look for all current entities that can be electrified and toggle the HUD layer on if they are.
|
||||
private void ShowHUD()
|
||||
{
|
||||
var electrifiedQuery = AllEntityQuery<ElectrocutionHUDVisualsComponent, AppearanceComponent, SpriteComponent>();
|
||||
while (electrifiedQuery.MoveNext(out var uid, out var _, out var appearanceComp, out var spriteComp))
|
||||
{
|
||||
if (!AppearanceSystem.TryGetData<bool>(uid, ElectrifiedVisuals.IsElectrified, out var electrified, appearanceComp))
|
||||
continue;
|
||||
|
||||
if (electrified)
|
||||
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, true);
|
||||
else
|
||||
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the HUD from the client.
|
||||
// Find all current entities that can be electrified and hide the HUD layer.
|
||||
private void RemoveHUD()
|
||||
{
|
||||
var electrifiedQuery = AllEntityQuery<ElectrocutionHUDVisualsComponent, AppearanceComponent, SpriteComponent>();
|
||||
while (electrifiedQuery.MoveNext(out var uid, out var _, out var appearanceComp, out var spriteComp))
|
||||
{
|
||||
|
||||
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle the HUD layer if an entity becomes (de-)electrified
|
||||
protected override void OnAppearanceChange(EntityUid uid, ElectrocutionHUDVisualsComponent comp, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (args.Sprite == null)
|
||||
return;
|
||||
|
||||
if (!AppearanceSystem.TryGetData<bool>(uid, ElectrifiedVisuals.IsElectrified, out var electrified, args.Component))
|
||||
return;
|
||||
|
||||
var player = _playerMan.LocalEntity;
|
||||
if (electrified && HasComp<ShowElectrocutionHUDComponent>(player))
|
||||
args.Sprite.LayerSetVisible(ElectrifiedLayers.HUD, true);
|
||||
else
|
||||
args.Sprite.LayerSetVisible(ElectrifiedLayers.HUD, false);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ using Content.Client.Chat.Managers;
|
||||
using Content.Client.DebugMon;
|
||||
using Content.Client.Eui;
|
||||
using Content.Client.Fullscreen;
|
||||
using Content.Client.GameTicking.Managers;
|
||||
using Content.Client.GhostKick;
|
||||
using Content.Client.Guidebook;
|
||||
using Content.Client.Input;
|
||||
@@ -71,8 +70,8 @@ namespace Content.Client.Entry
|
||||
[Dependency] private readonly IResourceManager _resourceManager = default!;
|
||||
[Dependency] private readonly IReplayLoadManager _replayLoad = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly ContentReplayPlaybackManager _replayMan = default!;
|
||||
[Dependency] private readonly DebugMonitorManager _debugMonitorManager = default!;
|
||||
[Dependency] private readonly TitleWindowManager _titleWindowManager = default!;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
@@ -142,12 +141,6 @@ namespace Content.Client.Entry
|
||||
_configManager.SetCVar("interface.resolutionAutoScaleMinimum", 0.5f);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
_titleWindowManager.Shutdown();
|
||||
}
|
||||
|
||||
public override void PostInit()
|
||||
{
|
||||
base.PostInit();
|
||||
@@ -165,10 +158,9 @@ namespace Content.Client.Entry
|
||||
_clientPreferencesManager.Initialize();
|
||||
_euiManager.Initialize();
|
||||
_voteManager.Initialize();
|
||||
_userInterfaceManager.SetDefaultTheme("SS14DefaultTheme");
|
||||
_userInterfaceManager.SetDefaultTheme(_configManager.GetCVar(CCVars.UIDefaultInterfaceTheme));
|
||||
_userInterfaceManager.SetActiveTheme(_configManager.GetCVar(CVars.InterfaceTheme));
|
||||
_documentParsingManager.Initialize();
|
||||
_titleWindowManager.Initialize();
|
||||
|
||||
_baseClient.RunLevelChanged += (_, args) =>
|
||||
{
|
||||
@@ -200,7 +192,7 @@ namespace Content.Client.Entry
|
||||
_resourceManager,
|
||||
ReplayConstants.ReplayZipFolder.ToRootedPath());
|
||||
|
||||
_playbackMan.LastLoad = (null, ReplayConstants.ReplayZipFolder.ToRootedPath());
|
||||
_replayMan.LastLoad = (null, ReplayConstants.ReplayZipFolder.ToRootedPath());
|
||||
_replayLoad.LoadAndStartReplay(reader);
|
||||
}
|
||||
else if (_gameController.LaunchState.FromLauncher)
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Content.Client.Eui
|
||||
/// </summary>
|
||||
protected void SendMessage(EuiMessageBase msg)
|
||||
{
|
||||
var netMsg = new MsgEuiMessage();
|
||||
var netMsg = _netManager.CreateNetMessage<MsgEuiMessage>();
|
||||
netMsg.Id = Id;
|
||||
netMsg.Message = msg;
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Client;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Client.GameTicking.Managers;
|
||||
|
||||
public sealed class TitleWindowManager
|
||||
{
|
||||
[Dependency] private readonly IBaseClient _client = default!;
|
||||
[Dependency] private readonly IClyde _clyde = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IGameController _gameController = default!;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_cfg.OnValueChanged(CVars.GameHostName, OnHostnameChange, true);
|
||||
_cfg.OnValueChanged(CCVars.GameHostnameInTitlebar, OnHostnameTitleChange, true);
|
||||
|
||||
_client.RunLevelChanged += OnRunLevelChangedChange;
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
_cfg.UnsubValueChanged(CVars.GameHostName, OnHostnameChange);
|
||||
_cfg.UnsubValueChanged(CCVars.GameHostnameInTitlebar, OnHostnameTitleChange);
|
||||
}
|
||||
|
||||
private void OnHostnameChange(string hostname)
|
||||
{
|
||||
var defaultWindowTitle = _gameController.GameTitle();
|
||||
|
||||
// Since the game assumes the server name is MyServer and that GameHostnameInTitlebar CCVar is true by default
|
||||
// Lets just... not show anything. This also is used to revert back to just the game title on disconnect.
|
||||
if (_client.RunLevel == ClientRunLevel.Initialize)
|
||||
{
|
||||
_clyde.SetWindowTitle(defaultWindowTitle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_cfg.GetCVar(CCVars.GameHostnameInTitlebar))
|
||||
// If you really dislike the dash I guess change it here
|
||||
_clyde.SetWindowTitle(hostname + " - " + defaultWindowTitle);
|
||||
else
|
||||
_clyde.SetWindowTitle(defaultWindowTitle);
|
||||
}
|
||||
|
||||
// Clients by default assume game.hostname_in_titlebar is true
|
||||
// but we need to clear it as soon as we join and actually receive the servers preference on this.
|
||||
// This will ensure we rerun OnHostnameChange and set the correct title bar name.
|
||||
private void OnHostnameTitleChange(bool colonthree)
|
||||
{
|
||||
OnHostnameChange(_cfg.GetCVar(CVars.GameHostName));
|
||||
}
|
||||
|
||||
// This is just used we can rerun the hostname change function when we disconnect to revert back to just the games title.
|
||||
private void OnRunLevelChangedChange(object? sender, RunLevelChangedEventArgs runLevelChangedEventArgs)
|
||||
{
|
||||
OnHostnameChange(_cfg.GetCVar(CVars.GameHostName));
|
||||
}
|
||||
}
|
||||
@@ -112,12 +112,7 @@ namespace Content.Client.Ghost
|
||||
_actions.RemoveAction(uid, component.ToggleLightingActionEntity);
|
||||
_actions.RemoveAction(uid, component.ToggleFoVActionEntity);
|
||||
_actions.RemoveAction(uid, component.ToggleGhostsActionEntity);
|
||||
//_actions.RemoveAction(uid, component.ToggleGhostHearingActionEntity); //Dont need in CP14
|
||||
//CP14
|
||||
_actions.RemoveAction(uid, component.CP14ZLevelUpActionEntity);
|
||||
_actions.RemoveAction(uid, component.CP14ZLevelDownActionEntity);
|
||||
_actions.RemoveAction(uid, component.CP14ToggleRoofActionEntity);
|
||||
//CP14 end
|
||||
_actions.RemoveAction(uid, component.ToggleGhostHearingActionEntity);
|
||||
|
||||
if (uid != _playerManager.LocalEntity)
|
||||
return;
|
||||
|
||||
@@ -168,8 +168,8 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
|
||||
var parent = forcedRoot == null ? null : AddEntry(forcedRoot.Value, null, addedEntries);
|
||||
foreach (var entry in GetSortedEntries(roots))
|
||||
{
|
||||
if (!entry.CrystallPunkAllowed) continue; //CrystallEdge guidebook filter
|
||||
if (entry.LocFilter is not null && entry.LocFilter != ContentLocalizationManager.Culture) continue; //CrystallEdge guidebook filter
|
||||
if (!entry.CrystallPunkAllowed) continue; //CrystallPunk guidebook filter
|
||||
if (entry.LocFilter is not null && entry.LocFilter != ContentLocalizationManager.Culture) continue; //CrystallPunk guidebook filter
|
||||
|
||||
AddEntry(entry.Id, parent, addedEntries);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed class GuidebookSystem : EntitySystem
|
||||
[Dependency] private readonly RgbLightControllerSystem _rgbLightControllerSystem = default!;
|
||||
[Dependency] private readonly SharedPointLightSystem _pointLightSystem = default!;
|
||||
[Dependency] private readonly TagSystem _tags = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!; //CrystallEdge guidebook filter
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!; //CrystallPunk guidebook filter
|
||||
|
||||
public event Action<List<ProtoId<GuideEntryPrototype>>,
|
||||
List<ProtoId<GuideEntryPrototype>>?,
|
||||
@@ -47,7 +47,7 @@ public sealed class GuidebookSystem : EntitySystem
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<GuideHelpComponent, MapInitEvent>(OnCrystallEdgeMapInit); //CrystallEdge guidebook filter
|
||||
SubscribeLocalEvent<GuideHelpComponent, MapInitEvent>(OnCrystallPunkMapInit); //CrystallPunk guidebook filter
|
||||
SubscribeLocalEvent<GuideHelpComponent, GetVerbsEvent<ExamineVerb>>(OnGetVerbs);
|
||||
SubscribeLocalEvent<GuideHelpComponent, ActivateInWorldEvent>(OnInteract);
|
||||
|
||||
@@ -57,12 +57,12 @@ public sealed class GuidebookSystem : EntitySystem
|
||||
OnGuidebookControlsTestGetAlternateVerbs);
|
||||
}
|
||||
|
||||
//CrystallEdge guidebook filter
|
||||
private void OnCrystallEdgeMapInit(Entity<GuideHelpComponent> ent, ref MapInitEvent args)
|
||||
//CrystallPunk guidebook filter
|
||||
private void OnCrystallPunkMapInit(Entity<GuideHelpComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
foreach (var guide in ent.Comp.Guides)
|
||||
{
|
||||
var guideProto = _proto.Index(guide);
|
||||
var guideProto = _proto.Index<GuideEntryPrototype>(guide);
|
||||
if (!guideProto.CrystallPunkAllowed) //REMOVE unnecessary guidebook
|
||||
{
|
||||
RemComp<GuideHelpComponent>(ent);
|
||||
@@ -70,7 +70,7 @@ public sealed class GuidebookSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
}
|
||||
//CrystallEdge guidebook filter end
|
||||
//CrystallPunk guidebook filter end
|
||||
|
||||
/// <summary>
|
||||
/// Gets a user entity to use for verbs and examinations. If the player has no attached entity, this will use a
|
||||
|
||||
@@ -130,9 +130,9 @@ namespace Content.Client.Hands.Systems
|
||||
OnPlayerHandsAdded?.Invoke(hands);
|
||||
}
|
||||
|
||||
public override void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, HandsComponent? hands = null, bool log = true)
|
||||
public override void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, HandsComponent? hands = null)
|
||||
{
|
||||
base.DoDrop(uid, hand, doDropInteraction, hands, log);
|
||||
base.DoDrop(uid, hand, doDropInteraction, hands);
|
||||
|
||||
if (TryComp(hand.HeldEntity, out SpriteComponent? sprite))
|
||||
sprite.RenderOrder = EntityManager.CurrentTick.Value;
|
||||
|
||||
@@ -34,7 +34,6 @@ namespace Content.Client.Info
|
||||
AddInfoButton("server-info-website-button", CCVars.InfoLinksWebsite);
|
||||
AddInfoButton("server-info-wiki-button", CCVars.InfoLinksWiki);
|
||||
AddInfoButton("server-info-forum-button", CCVars.InfoLinksForum);
|
||||
AddInfoButton("server-info-telegram-button", CCVars.InfoLinksTelegram);
|
||||
|
||||
var guidebookController = UserInterfaceManager.GetUIController<GuidebookUIController>();
|
||||
var guidebookButton = new Button() { Text = Loc.GetString("server-info-guidebook-button") };
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Shared.Localizations;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
@@ -17,10 +16,19 @@ public sealed partial class PlaytimeStatsEntry : ContainerButton
|
||||
|
||||
RoleLabel.Text = role;
|
||||
Playtime = playtime; // store the TimeSpan value directly
|
||||
PlaytimeLabel.Text = ContentLocalizationManager.FormatPlaytime(playtime); // convert to string for display
|
||||
PlaytimeLabel.Text = ConvertTimeSpanToHoursMinutes(playtime); // convert to string for display
|
||||
BackgroundColorPanel.PanelOverride = styleBox;
|
||||
}
|
||||
|
||||
private static string ConvertTimeSpanToHoursMinutes(TimeSpan timeSpan)
|
||||
{
|
||||
var hours = (int)timeSpan.TotalHours;
|
||||
var minutes = timeSpan.Minutes;
|
||||
|
||||
var formattedTimeLoc = Loc.GetString("ui-playtime-time-format", ("hours", hours), ("minutes", minutes));
|
||||
return formattedTimeLoc;
|
||||
}
|
||||
|
||||
public void UpdateShading(StyleBoxFlat styleBox)
|
||||
{
|
||||
BackgroundColorPanel.PanelOverride = styleBox;
|
||||
|
||||
@@ -104,7 +104,8 @@ public sealed partial class PlaytimeStatsWindow : FancyWindow
|
||||
{
|
||||
var overallPlaytime = _jobRequirementsManager.FetchOverallPlaytime();
|
||||
|
||||
OverallPlaytimeLabel.Text = Loc.GetString("ui-playtime-overall", ("time", overallPlaytime));
|
||||
var formattedPlaytime = ConvertTimeSpanToHoursMinutes(overallPlaytime);
|
||||
OverallPlaytimeLabel.Text = Loc.GetString("ui-playtime-overall", ("time", formattedPlaytime));
|
||||
|
||||
var rolePlaytimes = _jobRequirementsManager.FetchPlaytimeByRoles();
|
||||
|
||||
@@ -133,4 +134,13 @@ public sealed partial class PlaytimeStatsWindow : FancyWindow
|
||||
_sawmill.Error($"The provided playtime string '{playtimeString}' is not in the correct format.");
|
||||
}
|
||||
}
|
||||
|
||||
private static string ConvertTimeSpanToHoursMinutes(TimeSpan timeSpan)
|
||||
{
|
||||
var hours = (int) timeSpan.TotalHours;
|
||||
var minutes = timeSpan.Minutes;
|
||||
|
||||
var formattedTimeLoc = Loc.GetString("ui-playtime-time-format", ("hours", hours), ("minutes", minutes));
|
||||
return formattedTimeLoc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,23 +235,9 @@ namespace Content.Client.Inventory
|
||||
EntityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true));
|
||||
}
|
||||
|
||||
protected override void UpdateInventoryTemplate(Entity<InventoryComponent> ent)
|
||||
{
|
||||
base.UpdateInventoryTemplate(ent);
|
||||
|
||||
if (TryComp(ent, out InventorySlotsComponent? inventorySlots))
|
||||
{
|
||||
foreach (var slot in ent.Comp.Slots)
|
||||
{
|
||||
if (inventorySlots.SlotData.TryGetValue(slot.Name, out var slotData))
|
||||
slotData.SlotDef = slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SlotData
|
||||
{
|
||||
public SlotDefinition SlotDef;
|
||||
public readonly SlotDefinition SlotDef;
|
||||
public EntityUid? HeldEntity => Container?.ContainedEntity;
|
||||
public bool Blocked;
|
||||
public bool Highlighted;
|
||||
|
||||
@@ -17,7 +17,6 @@ using Content.Shared.Inventory.VirtualItem;
|
||||
using Content.Shared.Strip.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
@@ -30,13 +29,10 @@ namespace Content.Client.Inventory
|
||||
[UsedImplicitly]
|
||||
public sealed class StrippableBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
||||
|
||||
private readonly ExamineSystem _examine;
|
||||
private readonly InventorySystem _inv;
|
||||
private readonly SharedCuffableSystem _cuffable;
|
||||
private readonly StrippableSystem _strippable;
|
||||
|
||||
[ViewVariables]
|
||||
private const int ButtonSeparation = 4;
|
||||
@@ -55,8 +51,6 @@ namespace Content.Client.Inventory
|
||||
_examine = EntMan.System<ExamineSystem>();
|
||||
_inv = EntMan.System<InventorySystem>();
|
||||
_cuffable = EntMan.System<SharedCuffableSystem>();
|
||||
_strippable = EntMan.System<StrippableSystem>();
|
||||
|
||||
_virtualHiddenEntity = EntMan.SpawnEntity(HiddenPocketEntityId, MapCoordinates.Nullspace);
|
||||
}
|
||||
|
||||
@@ -104,7 +98,7 @@ namespace Content.Client.Inventory
|
||||
}
|
||||
}
|
||||
|
||||
if (EntMan.TryGetComponent<HandsComponent>(Owner, out var handsComp) && handsComp.CanBeStripped)
|
||||
if (EntMan.TryGetComponent<HandsComponent>(Owner, out var handsComp))
|
||||
{
|
||||
// good ol hands shit code. there is a GuiHands comparer that does the same thing... but these are hands
|
||||
// and not gui hands... which are different...
|
||||
@@ -191,15 +185,9 @@ namespace Content.Client.Inventory
|
||||
return;
|
||||
|
||||
if (ev.Function == ContentKeyFunctions.ExamineEntity)
|
||||
{
|
||||
_examine.DoExamine(slot.Entity.Value);
|
||||
ev.Handle();
|
||||
}
|
||||
else if (ev.Function == EngineKeyFunctions.UseSecondary)
|
||||
{
|
||||
_ui.GetUIController<VerbMenuUIController>().OpenVerbMenu(slot.Entity.Value);
|
||||
ev.Handle();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddInventoryButton(EntityUid invUid, string slotId, InventoryComponent inv)
|
||||
@@ -210,8 +198,7 @@ namespace Content.Client.Inventory
|
||||
var entity = container.ContainedEntity;
|
||||
|
||||
// If this is a full pocket, obscure the real entity
|
||||
// this does not work for modified clients because they are still sent the real entity
|
||||
if (entity != null && _strippable.IsStripHidden(slotDef, _player.LocalEntity))
|
||||
if (entity != null && slotDef.StripHidden)
|
||||
entity = _virtualHiddenEntity;
|
||||
|
||||
var button = new SlotButton(new SlotData(slotDef, container));
|
||||
|
||||
@@ -5,7 +5,6 @@ using Content.Client.Clickable;
|
||||
using Content.Client.DebugMon;
|
||||
using Content.Client.Eui;
|
||||
using Content.Client.Fullscreen;
|
||||
using Content.Client.GameTicking.Managers;
|
||||
using Content.Client.GhostKick;
|
||||
using Content.Client.Guidebook;
|
||||
using Content.Client.Launcher;
|
||||
@@ -19,11 +18,8 @@ using Content.Client.Viewport;
|
||||
using Content.Client.Voting;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Client.Lobby;
|
||||
using Content.Client.Players.RateLimiting;
|
||||
using Content.Shared.Administration.Managers;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Players.PlayTimeTracking;
|
||||
using Content.Shared.Players.RateLimiting;
|
||||
|
||||
namespace Content.Client.IoC
|
||||
{
|
||||
@@ -35,7 +31,6 @@ namespace Content.Client.IoC
|
||||
|
||||
collection.Register<IParallaxManager, ParallaxManager>();
|
||||
collection.Register<IChatManager, ChatManager>();
|
||||
collection.Register<ISharedChatManager, ChatManager>();
|
||||
collection.Register<IClientPreferencesManager, ClientPreferencesManager>();
|
||||
collection.Register<IStylesheetManager, StylesheetManager>();
|
||||
collection.Register<IScreenshotHook, ScreenshotHook>();
|
||||
@@ -52,13 +47,10 @@ namespace Content.Client.IoC
|
||||
collection.Register<ExtendedDisconnectInformationManager>();
|
||||
collection.Register<JobRequirementsManager>();
|
||||
collection.Register<DocumentParsingManager>();
|
||||
collection.Register<ContentReplayPlaybackManager>();
|
||||
collection.Register<ContentReplayPlaybackManager, ContentReplayPlaybackManager>();
|
||||
collection.Register<ISharedPlaytimeManager, JobRequirementsManager>();
|
||||
collection.Register<MappingManager>();
|
||||
collection.Register<DebugMonitorManager>();
|
||||
collection.Register<PlayerRateLimitManager>();
|
||||
collection.Register<SharedPlayerRateLimitManager, PlayerRateLimitManager>();
|
||||
collection.Register<TitleWindowManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,22 +21,6 @@ public sealed class HandheldLightSystem : SharedHandheldLightSystem
|
||||
SubscribeLocalEvent<HandheldLightComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// TODO: Not properly predicted yet. Don't call this function if you want a the actual return value!
|
||||
/// </remarks>
|
||||
public override bool TurnOff(Entity<HandheldLightComponent> ent, bool makeNoise = true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// TODO: Not properly predicted yet. Don't call this function if you want a the actual return value!
|
||||
/// </remarks>
|
||||
public override bool TurnOn(EntityUid user, Entity<HandheldLightComponent> uid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnAppearanceChange(EntityUid uid, HandheldLightComponent? component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace Content.Client.Lobby
|
||||
return;
|
||||
}
|
||||
|
||||
Lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-not-started");
|
||||
Lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-not-started");
|
||||
string text;
|
||||
|
||||
if (_gameTicker.Paused)
|
||||
@@ -136,10 +136,6 @@ namespace Content.Client.Lobby
|
||||
{
|
||||
text = Loc.GetString(seconds < -5 ? "lobby-state-right-now-question" : "lobby-state-right-now-confirmation");
|
||||
}
|
||||
else if (difference.TotalHours >= 1)
|
||||
{
|
||||
text = $"{Math.Floor(difference.TotalHours)}:{difference.Minutes:D2}:{difference.Seconds:D2}";
|
||||
}
|
||||
else
|
||||
{
|
||||
text = $"{difference.Minutes}:{difference.Seconds:D2}";
|
||||
|
||||
@@ -279,7 +279,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
||||
|
||||
_profileEditor.OnOpenGuidebook += _guide.OpenHelp;
|
||||
|
||||
_characterSetup = new CharacterSetupGui(_profileEditor);
|
||||
_characterSetup = new CharacterSetupGui(EntityManager, _prototypeManager, _resourceCache, _preferencesManager, _profileEditor);
|
||||
|
||||
_characterSetup.CloseButton.OnPressed += _ =>
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:style="clr-namespace:Content.Client.Stylesheets"
|
||||
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
VerticalExpand="True">
|
||||
<Control>
|
||||
<PanelContainer Name="BackgroundPanel" />
|
||||
@@ -11,15 +10,10 @@
|
||||
<Label Text="{Loc 'character-setup-gui-character-setup-label'}"
|
||||
Margin="8 0 0 0" VAlign="Center"
|
||||
StyleClasses="LabelHeadingBigger" />
|
||||
|
||||
<Button Name="StatsButton" HorizontalExpand="True"
|
||||
Text="{Loc 'character-setup-gui-character-setup-stats-button'}"
|
||||
StyleClasses="ButtonBig"
|
||||
HorizontalAlignment="Right" />
|
||||
<cc:CommandButton Name="AdminRemarksButton"
|
||||
Command="adminremarks"
|
||||
Text="{Loc 'character-setup-gui-character-setup-adminremarks-button'}"
|
||||
StyleClasses="ButtonBig" />
|
||||
<Button Name="RulesButton"
|
||||
Text="{Loc 'character-setup-gui-character-setup-rules-button'}"
|
||||
StyleClasses="ButtonBig"/>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Client.Info;
|
||||
using Content.Client.Info.PlaytimeStats;
|
||||
using Content.Client.Resources;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Preferences;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
@@ -9,7 +8,6 @@ using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Lobby.UI
|
||||
@@ -20,23 +18,28 @@ namespace Content.Client.Lobby.UI
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CharacterSetupGui : Control
|
||||
{
|
||||
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _protomanager = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
private readonly IClientPreferencesManager _preferencesManager;
|
||||
private readonly IEntityManager _entManager;
|
||||
private readonly IPrototypeManager _protomanager;
|
||||
|
||||
private readonly Button _createNewCharacterButton;
|
||||
|
||||
public event Action<int>? SelectCharacter;
|
||||
public event Action<int>? DeleteCharacter;
|
||||
|
||||
public CharacterSetupGui(HumanoidProfileEditor profileEditor)
|
||||
public CharacterSetupGui(
|
||||
IEntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
IResourceCache resourceCache,
|
||||
IClientPreferencesManager preferencesManager,
|
||||
HumanoidProfileEditor profileEditor)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
_preferencesManager = preferencesManager;
|
||||
_entManager = entManager;
|
||||
_protomanager = protoManager;
|
||||
|
||||
var panelTex = _resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
|
||||
var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
|
||||
var back = new StyleBoxTexture
|
||||
{
|
||||
Texture = panelTex,
|
||||
@@ -53,7 +56,7 @@ namespace Content.Client.Lobby.UI
|
||||
|
||||
_createNewCharacterButton.OnPressed += args =>
|
||||
{
|
||||
_preferencesManager.CreateCharacter(HumanoidCharacterProfile.Random());
|
||||
preferencesManager.CreateCharacter(HumanoidCharacterProfile.Random());
|
||||
ReloadCharacterPickers();
|
||||
args.Event.Handle();
|
||||
};
|
||||
@@ -62,8 +65,6 @@ namespace Content.Client.Lobby.UI
|
||||
RulesButton.OnPressed += _ => new RulesAndInfoWindow().Open();
|
||||
|
||||
StatsButton.OnPressed += _ => new PlaytimeStatsWindow().OpenCentered();
|
||||
|
||||
_cfg.OnValueChanged(CCVars.SeeOwnNotes, p => AdminRemarksButton.Visible = p, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -36,18 +36,17 @@ public sealed partial class LoadoutContainer : BoxContainer
|
||||
|
||||
if (_protoManager.TryIndex(proto, out var loadProto))
|
||||
{
|
||||
var ent = loadProto.DummyEntity ?? _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto);
|
||||
var ent = _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto);
|
||||
|
||||
if (ent == null)
|
||||
return;
|
||||
if (ent != null)
|
||||
{
|
||||
_entity = _entManager.SpawnEntity(ent, MapCoordinates.Nullspace);
|
||||
Sprite.SetEntity(_entity);
|
||||
|
||||
_entity = _entManager.SpawnEntity(ent, MapCoordinates.Nullspace);
|
||||
Sprite.SetEntity(_entity);
|
||||
|
||||
var spriteTooltip = new Tooltip();
|
||||
spriteTooltip.SetMessage(FormattedMessage.FromUnformatted(_entManager.GetComponent<MetaDataComponent>(_entity.Value).EntityDescription));
|
||||
|
||||
TooltipSupplier = _ => spriteTooltip;
|
||||
var spriteTooltip = new Tooltip();
|
||||
spriteTooltip.SetMessage(FormattedMessage.FromUnformatted(_entManager.GetComponent<MetaDataComponent>(_entity.Value).EntityDescription));
|
||||
TooltipSupplier = _ => spriteTooltip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using Content.Client.Message;
|
||||
using Content.Client.UserInterface.Systems.EscapeMenu;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.State;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
|
||||
149
Content.Client/Movement/Systems/WaddleAnimationSystem.cs
Normal file
149
Content.Client/Movement/Systems/WaddleAnimationSystem.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.Buckle;
|
||||
using Content.Client.Gravity;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Animations;
|
||||
|
||||
namespace Content.Client.Movement.Systems;
|
||||
|
||||
public sealed class WaddleAnimationSystem : SharedWaddleAnimationSystem
|
||||
{
|
||||
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
|
||||
[Dependency] private readonly GravitySystem _gravity = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||
[Dependency] private readonly BuckleSystem _buckle = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeAllEvent<StartedWaddlingEvent>(OnStartWaddling);
|
||||
SubscribeLocalEvent<WaddleAnimationComponent, AnimationCompletedEvent>(OnAnimationCompleted);
|
||||
SubscribeAllEvent<StoppedWaddlingEvent>(OnStopWaddling);
|
||||
}
|
||||
|
||||
private void OnStartWaddling(StartedWaddlingEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (TryComp<WaddleAnimationComponent>(GetEntity(msg.Entity), out var comp))
|
||||
StartWaddling((GetEntity(msg.Entity), comp));
|
||||
}
|
||||
|
||||
private void OnStopWaddling(StoppedWaddlingEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (TryComp<WaddleAnimationComponent>(GetEntity(msg.Entity), out var comp))
|
||||
StopWaddling((GetEntity(msg.Entity), comp));
|
||||
}
|
||||
|
||||
private void StartWaddling(Entity<WaddleAnimationComponent> entity)
|
||||
{
|
||||
if (_animation.HasRunningAnimation(entity.Owner, entity.Comp.KeyName))
|
||||
return;
|
||||
|
||||
if (!TryComp<InputMoverComponent>(entity.Owner, out var mover))
|
||||
return;
|
||||
|
||||
if (_gravity.IsWeightless(entity.Owner))
|
||||
return;
|
||||
|
||||
if (!_actionBlocker.CanMove(entity.Owner, mover))
|
||||
return;
|
||||
|
||||
// Do nothing if buckled in
|
||||
if (_buckle.IsBuckled(entity.Owner))
|
||||
return;
|
||||
|
||||
// Do nothing if crit or dead (for obvious reasons)
|
||||
if (_mobState.IsIncapacitated(entity.Owner))
|
||||
return;
|
||||
|
||||
PlayWaddleAnimationUsing(
|
||||
(entity.Owner, entity.Comp),
|
||||
CalculateAnimationLength(entity.Comp, mover),
|
||||
CalculateTumbleIntensity(entity.Comp)
|
||||
);
|
||||
}
|
||||
|
||||
private static float CalculateTumbleIntensity(WaddleAnimationComponent component)
|
||||
{
|
||||
return component.LastStep ? 360 - component.TumbleIntensity : component.TumbleIntensity;
|
||||
}
|
||||
|
||||
private static float CalculateAnimationLength(WaddleAnimationComponent component, InputMoverComponent mover)
|
||||
{
|
||||
return mover.Sprinting ? component.AnimationLength * component.RunAnimationLengthMultiplier : component.AnimationLength;
|
||||
}
|
||||
|
||||
private void OnAnimationCompleted(Entity<WaddleAnimationComponent> entity, ref AnimationCompletedEvent args)
|
||||
{
|
||||
if (args.Key != entity.Comp.KeyName)
|
||||
return;
|
||||
|
||||
if (!TryComp<InputMoverComponent>(entity.Owner, out var mover))
|
||||
return;
|
||||
|
||||
PlayWaddleAnimationUsing(
|
||||
(entity.Owner, entity.Comp),
|
||||
CalculateAnimationLength(entity.Comp, mover),
|
||||
CalculateTumbleIntensity(entity.Comp)
|
||||
);
|
||||
}
|
||||
|
||||
private void StopWaddling(Entity<WaddleAnimationComponent> entity)
|
||||
{
|
||||
if (!_animation.HasRunningAnimation(entity.Owner, entity.Comp.KeyName))
|
||||
return;
|
||||
|
||||
_animation.Stop(entity.Owner, entity.Comp.KeyName);
|
||||
|
||||
if (!TryComp<SpriteComponent>(entity.Owner, out var sprite))
|
||||
return;
|
||||
|
||||
sprite.Offset = new Vector2();
|
||||
sprite.Rotation = Angle.FromDegrees(0);
|
||||
}
|
||||
|
||||
private void PlayWaddleAnimationUsing(Entity<WaddleAnimationComponent> entity, float len, float tumbleIntensity)
|
||||
{
|
||||
entity.Comp.LastStep = !entity.Comp.LastStep;
|
||||
|
||||
var anim = new Animation()
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(len),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackComponentProperty()
|
||||
{
|
||||
ComponentType = typeof(SpriteComponent),
|
||||
Property = nameof(SpriteComponent.Rotation),
|
||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), 0),
|
||||
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(tumbleIntensity), len/2),
|
||||
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), len/2),
|
||||
}
|
||||
},
|
||||
new AnimationTrackComponentProperty()
|
||||
{
|
||||
ComponentType = typeof(SpriteComponent),
|
||||
Property = nameof(SpriteComponent.Offset),
|
||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(new Vector2(), 0),
|
||||
new AnimationTrackProperty.KeyFrame(entity.Comp.HopIntensity, len/2),
|
||||
new AnimationTrackProperty.KeyFrame(new Vector2(), len/2),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_animation.Play(entity.Owner, anim, entity.Comp.KeyName);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
|
||||
[ViewVariables]
|
||||
protected bool IsActive;
|
||||
protected virtual SlotFlags TargetSlots => ~SlotFlags.POCKET;
|
||||
|
||||
@@ -103,7 +102,7 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
|
||||
args.Components.Add(component);
|
||||
}
|
||||
|
||||
protected void RefreshOverlay(EntityUid uid)
|
||||
private void RefreshOverlay(EntityUid uid)
|
||||
{
|
||||
if (uid != _player.LocalSession?.AttachedEntity)
|
||||
return;
|
||||
|
||||
@@ -21,16 +21,9 @@ public sealed class ShowHealthBarsSystem : EquipmentHudSystem<ShowHealthBarsComp
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ShowHealthBarsComponent, AfterAutoHandleStateEvent>(OnHandleState);
|
||||
|
||||
_overlay = new(EntityManager, _prototype);
|
||||
}
|
||||
|
||||
private void OnHandleState(Entity<ShowHealthBarsComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
RefreshOverlay(ent);
|
||||
}
|
||||
|
||||
protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthBarsComponent> component)
|
||||
{
|
||||
base.UpdateInternal(component);
|
||||
|
||||
@@ -17,7 +17,6 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
|
||||
|
||||
[ViewVariables]
|
||||
public HashSet<string> DamageContainers = new();
|
||||
|
||||
public override void Initialize()
|
||||
@@ -25,7 +24,6 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DamageableComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
|
||||
SubscribeLocalEvent<ShowHealthIconsComponent, AfterAutoHandleStateEvent>(OnHandleState);
|
||||
}
|
||||
|
||||
protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthIconsComponent> component)
|
||||
@@ -45,11 +43,6 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
|
||||
DamageContainers.Clear();
|
||||
}
|
||||
|
||||
private void OnHandleState(Entity<ShowHealthIconsComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
RefreshOverlay(ent);
|
||||
}
|
||||
|
||||
private void OnGetStatusIconsEvent(Entity<DamageableComponent> entity, ref GetStatusIconsEvent args)
|
||||
{
|
||||
if (!IsActive)
|
||||
|
||||
@@ -22,6 +22,6 @@ public sealed class ShowThirstIconsSystem : EquipmentHudSystem<ShowThirstIconsCo
|
||||
return;
|
||||
|
||||
if (_thirst.TryGetStatusIconPrototype(component, out var iconPrototype))
|
||||
ev.StatusIcons.Add(iconPrototype);
|
||||
ev.StatusIcons.Add(iconPrototype!);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed partial class StencilOverlay
|
||||
var matty = Matrix3x2.Multiply(matrix, invMatrix);
|
||||
worldHandle.SetTransform(matty);
|
||||
|
||||
foreach (var tile in _map.GetTilesIntersecting(grid.Owner, grid, worldAABB))
|
||||
foreach (var tile in grid.Comp.GetTilesIntersecting(worldAABB))
|
||||
{
|
||||
// Ignored tiles for stencil
|
||||
if (_weather.CanWeatherAffect(grid.Owner, grid, tile))
|
||||
|
||||
@@ -26,7 +26,6 @@ public sealed partial class StencilOverlay : Overlay
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
private readonly ParallaxSystem _parallax;
|
||||
private readonly SharedTransformSystem _transform;
|
||||
private readonly SharedMapSystem _map;
|
||||
private readonly SpriteSystem _sprite;
|
||||
private readonly WeatherSystem _weather;
|
||||
|
||||
@@ -36,12 +35,11 @@ public sealed partial class StencilOverlay : Overlay
|
||||
|
||||
private readonly ShaderInstance _shader;
|
||||
|
||||
public StencilOverlay(ParallaxSystem parallax, SharedTransformSystem transform, SharedMapSystem map, SpriteSystem sprite, WeatherSystem weather)
|
||||
public StencilOverlay(ParallaxSystem parallax, SharedTransformSystem transform, SpriteSystem sprite, WeatherSystem weather)
|
||||
{
|
||||
ZIndex = ParallaxSystem.ParallaxZIndex + 1;
|
||||
_parallax = parallax;
|
||||
_transform = transform;
|
||||
_map = map;
|
||||
_sprite = sprite;
|
||||
_weather = weather;
|
||||
IoCManager.InjectDependencies(this);
|
||||
@@ -78,16 +76,16 @@ public sealed partial class StencilOverlay : Overlay
|
||||
|
||||
|
||||
//CP14 Overlays
|
||||
if (_entManager.TryGetComponent<CP14CloudShadowsComponent>(mapUid, out var shadows))
|
||||
if (_entManager.TryGetComponent<CP14WorldEdgeComponent>(mapUid, out var worldEdge))
|
||||
{
|
||||
DrawCloudShadows(args, shadows, invMatrix);
|
||||
DrawWorldEdge(args, worldEdge, invMatrix);
|
||||
}
|
||||
//CP14 Overlays end
|
||||
|
||||
//CP14 Overlays
|
||||
if (_entManager.TryGetComponent<CP14WorldEdgeComponent>(mapUid, out var worldEdge))
|
||||
if (_entManager.TryGetComponent<CP14CloudShadowsComponent>(mapUid, out var shadows))
|
||||
{
|
||||
DrawWorldEdge(args, worldEdge, invMatrix);
|
||||
DrawCloudShadows(args, shadows, invMatrix);
|
||||
}
|
||||
//CP14 Overlays end
|
||||
|
||||
|
||||
@@ -10,14 +10,13 @@ public sealed class StencilOverlaySystem : EntitySystem
|
||||
[Dependency] private readonly IOverlayManager _overlay = default!;
|
||||
[Dependency] private readonly ParallaxSystem _parallax = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
[Dependency] private readonly WeatherSystem _weather = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_overlay.AddOverlay(new StencilOverlay(_parallax, _transform, _map, _sprite, _weather));
|
||||
_overlay.AddOverlay(new StencilOverlay(_parallax, _transform, _sprite, _weather));
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
|
||||
@@ -319,8 +319,6 @@ namespace Content.Client.Paper.UI
|
||||
|
||||
private void RunOnSaved()
|
||||
{
|
||||
// Prevent further saving while text processing still in
|
||||
SaveButton.Disabled = true;
|
||||
OnSaved?.Invoke(Rope.Collapse(Input.TextRope));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Pulling.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Physics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -17,8 +14,6 @@ public sealed class MoverController : SharedMoverController
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -140,15 +135,4 @@ public sealed class MoverController : SharedMoverController
|
||||
{
|
||||
return _timing is { IsFirstTimePredicted: true, InSimulation: true };
|
||||
}
|
||||
|
||||
public override void SetSprinting(Entity<InputMoverComponent> entity, ushort subTick, bool walking)
|
||||
{
|
||||
// Logger.Info($"[{_gameTiming.CurTick}/{subTick}] Sprint: {enabled}");
|
||||
base.SetSprinting(entity, subTick, walking);
|
||||
|
||||
if (walking && _cfg.GetCVar(CCVars.ToggleWalk))
|
||||
_alerts.ShowAlert(entity, WalkingAlert, showCooldown: false, autoRemove: false);
|
||||
else
|
||||
_alerts.ClearAlert(entity, WalkingAlert);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,303 +0,0 @@
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Pinpointer;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Client.Pinpointer;
|
||||
|
||||
public sealed partial class NavMapSystem
|
||||
{
|
||||
private (AtmosDirection, Vector2i, AtmosDirection)[] _regionPropagationTable =
|
||||
{
|
||||
(AtmosDirection.East, new Vector2i(1, 0), AtmosDirection.West),
|
||||
(AtmosDirection.West, new Vector2i(-1, 0), AtmosDirection.East),
|
||||
(AtmosDirection.North, new Vector2i(0, 1), AtmosDirection.South),
|
||||
(AtmosDirection.South, new Vector2i(0, -1), AtmosDirection.North),
|
||||
};
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
// To prevent compute spikes, only one region is flood filled per frame
|
||||
var query = AllEntityQuery<NavMapComponent>();
|
||||
|
||||
while (query.MoveNext(out var ent, out var entNavMapRegions))
|
||||
FloodFillNextEnqueuedRegion(ent, entNavMapRegions);
|
||||
}
|
||||
|
||||
private void FloodFillNextEnqueuedRegion(EntityUid uid, NavMapComponent component)
|
||||
{
|
||||
if (!component.QueuedRegionsToFlood.Any())
|
||||
return;
|
||||
|
||||
var regionOwner = component.QueuedRegionsToFlood.Dequeue();
|
||||
|
||||
// If the region is no longer valid, flood the next one in the queue
|
||||
if (!component.RegionProperties.TryGetValue(regionOwner, out var regionProperties) ||
|
||||
!regionProperties.Seeds.Any())
|
||||
{
|
||||
FloodFillNextEnqueuedRegion(uid, component);
|
||||
return;
|
||||
}
|
||||
|
||||
// Flood fill the region, using the region seeds as starting points
|
||||
var (floodedTiles, floodedChunks) = FloodFillRegion(uid, component, regionProperties);
|
||||
|
||||
// Combine the flooded tiles into larger rectangles
|
||||
var gridCoords = GetMergedRegionTiles(floodedTiles);
|
||||
|
||||
// Create and assign the new region overlay
|
||||
var regionOverlay = new NavMapRegionOverlay(regionProperties.UiKey, gridCoords)
|
||||
{
|
||||
Color = regionProperties.Color
|
||||
};
|
||||
|
||||
component.RegionOverlays[regionOwner] = regionOverlay;
|
||||
|
||||
// To reduce unnecessary future flood fills, we will track which chunks have been flooded by a region owner
|
||||
|
||||
// First remove an old assignments
|
||||
if (component.RegionOwnerToChunkTable.TryGetValue(regionOwner, out var oldChunks))
|
||||
{
|
||||
foreach (var chunk in oldChunks)
|
||||
{
|
||||
if (component.ChunkToRegionOwnerTable.TryGetValue(chunk, out var oldOwners))
|
||||
{
|
||||
oldOwners.Remove(regionOwner);
|
||||
component.ChunkToRegionOwnerTable[chunk] = oldOwners;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now update with the new assignments
|
||||
component.RegionOwnerToChunkTable[regionOwner] = floodedChunks;
|
||||
|
||||
foreach (var chunk in floodedChunks)
|
||||
{
|
||||
if (!component.ChunkToRegionOwnerTable.TryGetValue(chunk, out var owners))
|
||||
owners = new();
|
||||
|
||||
owners.Add(regionOwner);
|
||||
component.ChunkToRegionOwnerTable[chunk] = owners;
|
||||
}
|
||||
}
|
||||
|
||||
private (HashSet<Vector2i>, HashSet<Vector2i>) FloodFillRegion(EntityUid uid, NavMapComponent component, NavMapRegionProperties regionProperties)
|
||||
{
|
||||
if (!regionProperties.Seeds.Any())
|
||||
return (new(), new());
|
||||
|
||||
var visitedChunks = new HashSet<Vector2i>();
|
||||
var visitedTiles = new HashSet<Vector2i>();
|
||||
var tilesToVisit = new Stack<Vector2i>();
|
||||
|
||||
foreach (var regionSeed in regionProperties.Seeds)
|
||||
{
|
||||
tilesToVisit.Push(regionSeed);
|
||||
|
||||
while (tilesToVisit.Count > 0)
|
||||
{
|
||||
// If the max region area is hit, exit
|
||||
if (visitedTiles.Count > regionProperties.MaxArea)
|
||||
return (new(), new());
|
||||
|
||||
// Pop the top tile from the stack
|
||||
var current = tilesToVisit.Pop();
|
||||
|
||||
// If the current tile position has already been visited,
|
||||
// or is too far away from the seed, continue
|
||||
if ((regionSeed - current).Length > regionProperties.MaxRadius)
|
||||
continue;
|
||||
|
||||
if (visitedTiles.Contains(current))
|
||||
continue;
|
||||
|
||||
// Determine the tile's chunk index
|
||||
var chunkOrigin = SharedMapSystem.GetChunkIndices(current, ChunkSize);
|
||||
var relative = SharedMapSystem.GetChunkRelative(current, ChunkSize);
|
||||
var idx = GetTileIndex(relative);
|
||||
|
||||
// Extract the tile data
|
||||
if (!component.Chunks.TryGetValue(chunkOrigin, out var chunk))
|
||||
continue;
|
||||
|
||||
var flag = chunk.TileData[idx];
|
||||
|
||||
// If the current tile is entirely occupied, continue
|
||||
if ((FloorMask & flag) == 0)
|
||||
continue;
|
||||
|
||||
if ((WallMask & flag) == WallMask)
|
||||
continue;
|
||||
|
||||
if ((AirlockMask & flag) == AirlockMask)
|
||||
continue;
|
||||
|
||||
// Otherwise the tile can be added to this region
|
||||
visitedTiles.Add(current);
|
||||
visitedChunks.Add(chunkOrigin);
|
||||
|
||||
// Determine if we can propagate the region into its cardinally adjacent neighbors
|
||||
// To propagate to a neighbor, movement into the neighbors closest edge must not be
|
||||
// blocked, and vice versa
|
||||
|
||||
foreach (var (direction, tileOffset, reverseDirection) in _regionPropagationTable)
|
||||
{
|
||||
if (!RegionCanPropagateInDirection(chunk, current, direction))
|
||||
continue;
|
||||
|
||||
var neighbor = current + tileOffset;
|
||||
var neighborOrigin = SharedMapSystem.GetChunkIndices(neighbor, ChunkSize);
|
||||
|
||||
if (!component.Chunks.TryGetValue(neighborOrigin, out var neighborChunk))
|
||||
continue;
|
||||
|
||||
visitedChunks.Add(neighborOrigin);
|
||||
|
||||
if (!RegionCanPropagateInDirection(neighborChunk, neighbor, reverseDirection))
|
||||
continue;
|
||||
|
||||
tilesToVisit.Push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (visitedTiles, visitedChunks);
|
||||
}
|
||||
|
||||
private bool RegionCanPropagateInDirection(NavMapChunk chunk, Vector2i tile, AtmosDirection direction)
|
||||
{
|
||||
var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize);
|
||||
var idx = GetTileIndex(relative);
|
||||
var flag = chunk.TileData[idx];
|
||||
|
||||
if ((FloorMask & flag) == 0)
|
||||
return false;
|
||||
|
||||
var directionMask = 1 << (int)direction;
|
||||
var wallMask = (int)direction << (int)NavMapChunkType.Wall;
|
||||
var airlockMask = (int)direction << (int)NavMapChunkType.Airlock;
|
||||
|
||||
if ((wallMask & flag) > 0)
|
||||
return false;
|
||||
|
||||
if ((airlockMask & flag) > 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<(Vector2i, Vector2i)> GetMergedRegionTiles(HashSet<Vector2i> tiles)
|
||||
{
|
||||
if (!tiles.Any())
|
||||
return new();
|
||||
|
||||
var x = tiles.Select(t => t.X);
|
||||
var minX = x.Min();
|
||||
var maxX = x.Max();
|
||||
|
||||
var y = tiles.Select(t => t.Y);
|
||||
var minY = y.Min();
|
||||
var maxY = y.Max();
|
||||
|
||||
var matrix = new int[maxX - minX + 1, maxY - minY + 1];
|
||||
|
||||
foreach (var tile in tiles)
|
||||
{
|
||||
var a = tile.X - minX;
|
||||
var b = tile.Y - minY;
|
||||
|
||||
matrix[a, b] = 1;
|
||||
}
|
||||
|
||||
return GetMergedRegionTiles(matrix, new Vector2i(minX, minY));
|
||||
}
|
||||
|
||||
private List<(Vector2i, Vector2i)> GetMergedRegionTiles(int[,] matrix, Vector2i offset)
|
||||
{
|
||||
var output = new List<(Vector2i, Vector2i)>();
|
||||
|
||||
var rows = matrix.GetLength(0);
|
||||
var cols = matrix.GetLength(1);
|
||||
|
||||
var dp = new int[rows, cols];
|
||||
var coords = (new Vector2i(), new Vector2i());
|
||||
var maxArea = 0;
|
||||
|
||||
var count = 0;
|
||||
|
||||
while (!IsArrayEmpty(matrix))
|
||||
{
|
||||
count++;
|
||||
|
||||
if (count > rows * cols)
|
||||
break;
|
||||
|
||||
// Clear old values
|
||||
dp = new int[rows, cols];
|
||||
coords = (new Vector2i(), new Vector2i());
|
||||
maxArea = 0;
|
||||
|
||||
// Initialize the first row of dp
|
||||
for (int j = 0; j < cols; j++)
|
||||
{
|
||||
dp[0, j] = matrix[0, j];
|
||||
}
|
||||
|
||||
// Calculate dp values for remaining rows
|
||||
for (int i = 1; i < rows; i++)
|
||||
{
|
||||
for (int j = 0; j < cols; j++)
|
||||
dp[i, j] = matrix[i, j] == 1 ? dp[i - 1, j] + 1 : 0;
|
||||
}
|
||||
|
||||
// Find the largest rectangular area seeded for each position in the matrix
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
for (int j = 0; j < cols; j++)
|
||||
{
|
||||
int minWidth = dp[i, j];
|
||||
|
||||
for (int k = j; k >= 0; k--)
|
||||
{
|
||||
if (dp[i, k] <= 0)
|
||||
break;
|
||||
|
||||
minWidth = Math.Min(minWidth, dp[i, k]);
|
||||
var currArea = Math.Max(maxArea, minWidth * (j - k + 1));
|
||||
|
||||
if (currArea > maxArea)
|
||||
{
|
||||
maxArea = currArea;
|
||||
coords = (new Vector2i(i - minWidth + 1, k), new Vector2i(i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the recorded rectangle vertices
|
||||
output.Add((coords.Item1 + offset, coords.Item2 + offset));
|
||||
|
||||
// Removed the tiles covered by the rectangle from matrix
|
||||
for (int i = coords.Item1.X; i <= coords.Item2.X; i++)
|
||||
{
|
||||
for (int j = coords.Item1.Y; j <= coords.Item2.Y; j++)
|
||||
matrix[i, j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private bool IsArrayEmpty(int[,] matrix)
|
||||
{
|
||||
for (int i = 0; i < matrix.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 0; j < matrix.GetLength(1); j++)
|
||||
{
|
||||
if (matrix[i, j] == 1)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Pinpointer;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
@@ -17,7 +16,6 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
||||
{
|
||||
Dictionary<Vector2i, int[]> modifiedChunks;
|
||||
Dictionary<NetEntity, NavMapBeacon> beacons;
|
||||
Dictionary<NetEntity, NavMapRegionProperties> regions;
|
||||
|
||||
switch (args.Current)
|
||||
{
|
||||
@@ -25,8 +23,6 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
||||
{
|
||||
modifiedChunks = delta.ModifiedChunks;
|
||||
beacons = delta.Beacons;
|
||||
regions = delta.Regions;
|
||||
|
||||
foreach (var index in component.Chunks.Keys)
|
||||
{
|
||||
if (!delta.AllChunks!.Contains(index))
|
||||
@@ -39,8 +35,6 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
||||
{
|
||||
modifiedChunks = state.Chunks;
|
||||
beacons = state.Beacons;
|
||||
regions = state.Regions;
|
||||
|
||||
foreach (var index in component.Chunks.Keys)
|
||||
{
|
||||
if (!state.Chunks.ContainsKey(index))
|
||||
@@ -53,54 +47,13 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
||||
return;
|
||||
}
|
||||
|
||||
// Update region data and queue new regions for flooding
|
||||
var prevRegionOwners = component.RegionProperties.Keys.ToList();
|
||||
var validRegionOwners = new List<NetEntity>();
|
||||
|
||||
component.RegionProperties.Clear();
|
||||
|
||||
foreach (var (regionOwner, regionData) in regions)
|
||||
{
|
||||
if (!regionData.Seeds.Any())
|
||||
continue;
|
||||
|
||||
component.RegionProperties[regionOwner] = regionData;
|
||||
validRegionOwners.Add(regionOwner);
|
||||
|
||||
if (component.RegionOverlays.ContainsKey(regionOwner))
|
||||
continue;
|
||||
|
||||
if (component.QueuedRegionsToFlood.Contains(regionOwner))
|
||||
continue;
|
||||
|
||||
component.QueuedRegionsToFlood.Enqueue(regionOwner);
|
||||
}
|
||||
|
||||
// Remove stale region owners
|
||||
var regionOwnersToRemove = prevRegionOwners.Except(validRegionOwners);
|
||||
|
||||
foreach (var regionOwnerRemoved in regionOwnersToRemove)
|
||||
RemoveNavMapRegion(uid, component, regionOwnerRemoved);
|
||||
|
||||
// Modify chunks
|
||||
foreach (var (origin, chunk) in modifiedChunks)
|
||||
{
|
||||
var newChunk = new NavMapChunk(origin);
|
||||
Array.Copy(chunk, newChunk.TileData, chunk.Length);
|
||||
component.Chunks[origin] = newChunk;
|
||||
|
||||
// If the affected chunk intersects one or more regions, re-flood them
|
||||
if (!component.ChunkToRegionOwnerTable.TryGetValue(origin, out var affectedOwners))
|
||||
continue;
|
||||
|
||||
foreach (var affectedOwner in affectedOwners)
|
||||
{
|
||||
if (!component.QueuedRegionsToFlood.Contains(affectedOwner))
|
||||
component.QueuedRegionsToFlood.Enqueue(affectedOwner);
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh beacons
|
||||
component.Beacons.Clear();
|
||||
foreach (var (nuid, beacon) in beacons)
|
||||
{
|
||||
|
||||
@@ -48,7 +48,6 @@ public partial class NavMapControl : MapGridControl
|
||||
public List<(Vector2, Vector2)> TileLines = new();
|
||||
public List<(Vector2, Vector2)> TileRects = new();
|
||||
public List<(Vector2[], Color)> TilePolygons = new();
|
||||
public List<NavMapRegionOverlay> RegionOverlays = new();
|
||||
|
||||
// Default colors
|
||||
public Color WallColor = new(102, 217, 102);
|
||||
@@ -229,7 +228,7 @@ public partial class NavMapControl : MapGridControl
|
||||
{
|
||||
if (!blip.Selectable)
|
||||
continue;
|
||||
|
||||
|
||||
var currentDistance = (_transformSystem.ToMapCoordinates(blip.Coordinates).Position - worldPosition).Length();
|
||||
|
||||
if (closestDistance < currentDistance || currentDistance * MinimapScale > MaxSelectableDistance)
|
||||
@@ -320,22 +319,6 @@ public partial class NavMapControl : MapGridControl
|
||||
}
|
||||
}
|
||||
|
||||
// Draw region overlays
|
||||
if (_grid != null)
|
||||
{
|
||||
foreach (var regionOverlay in RegionOverlays)
|
||||
{
|
||||
foreach (var gridCoords in regionOverlay.GridCoords)
|
||||
{
|
||||
var positionTopLeft = ScalePosition(new Vector2(gridCoords.Item1.X, -gridCoords.Item1.Y) - new Vector2(offset.X, -offset.Y));
|
||||
var positionBottomRight = ScalePosition(new Vector2(gridCoords.Item2.X + _grid.TileSize, -gridCoords.Item2.Y - _grid.TileSize) - new Vector2(offset.X, -offset.Y));
|
||||
|
||||
var box = new UIBox2(positionTopLeft, positionBottomRight);
|
||||
handle.DrawRect(box, regionOverlay.Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw map lines
|
||||
if (TileLines.Any())
|
||||
{
|
||||
|
||||
@@ -51,8 +51,6 @@ public sealed class JobRequirementsManager : ISharedPlaytimeManager
|
||||
{
|
||||
// Reset on disconnect, just in case.
|
||||
_roles.Clear();
|
||||
_jobWhitelists.Clear();
|
||||
_roleBans.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +58,9 @@ public sealed class JobRequirementsManager : ISharedPlaytimeManager
|
||||
{
|
||||
_sawmill.Debug($"Received roleban info containing {message.Bans.Count} entries.");
|
||||
|
||||
if (_roleBans.Equals(message.Bans))
|
||||
return;
|
||||
|
||||
_roleBans.Clear();
|
||||
_roleBans.AddRange(message.Bans);
|
||||
Updated?.Invoke();
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
using Content.Shared.Players.RateLimiting;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.Players.RateLimiting;
|
||||
|
||||
public sealed class PlayerRateLimitManager : SharedPlayerRateLimitManager
|
||||
{
|
||||
public override RateLimitStatus CountAction(ICommonSession player, string key)
|
||||
{
|
||||
// TODO Rate-Limit
|
||||
// Add support for rate limit prediction
|
||||
// I.e., dont mis-predict just because somebody is clicking too quickly.
|
||||
return RateLimitStatus.Allowed;
|
||||
}
|
||||
|
||||
public override void Register(string key, RateLimitRegistration registration)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
using Content.Client.Effects;
|
||||
using Content.Client.Smoking;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Polymorph.Components;
|
||||
using Content.Shared.Polymorph.Systems;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.Polymorph.Systems;
|
||||
|
||||
@@ -13,20 +10,14 @@ public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
|
||||
private EntityQuery<AppearanceComponent> _appearanceQuery;
|
||||
private EntityQuery<SpriteComponent> _spriteQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_appearanceQuery = GetEntityQuery<AppearanceComponent>();
|
||||
_spriteQuery = GetEntityQuery<SpriteComponent>();
|
||||
|
||||
SubscribeLocalEvent<ChameleonDisguiseComponent, AfterAutoHandleStateEvent>(OnHandleState);
|
||||
|
||||
SubscribeLocalEvent<ChameleonDisguisedComponent, ComponentStartup>(OnStartup);
|
||||
SubscribeLocalEvent<ChameleonDisguisedComponent, ComponentShutdown>(OnShutdown);
|
||||
SubscribeLocalEvent<ChameleonDisguisedComponent, GetFlashEffectTargetEvent>(OnGetFlashEffectTargetEvent);
|
||||
}
|
||||
|
||||
private void OnHandleState(Entity<ChameleonDisguiseComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
@@ -34,30 +25,9 @@ public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem
|
||||
CopyComp<SpriteComponent>(ent);
|
||||
CopyComp<GenericVisualizerComponent>(ent);
|
||||
CopyComp<SolutionContainerVisualsComponent>(ent);
|
||||
CopyComp<BurnStateVisualsComponent>(ent);
|
||||
|
||||
// reload appearance to hopefully prevent any invisible layers
|
||||
if (_appearanceQuery.TryComp(ent, out var appearance))
|
||||
_appearance.QueueUpdate(ent, appearance);
|
||||
}
|
||||
|
||||
private void OnStartup(Entity<ChameleonDisguisedComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
if (!_spriteQuery.TryComp(ent, out var sprite))
|
||||
return;
|
||||
|
||||
ent.Comp.WasVisible = sprite.Visible;
|
||||
sprite.Visible = false;
|
||||
}
|
||||
|
||||
private void OnShutdown(Entity<ChameleonDisguisedComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (_spriteQuery.TryComp(ent, out var sprite))
|
||||
sprite.Visible = ent.Comp.WasVisible;
|
||||
}
|
||||
|
||||
private void OnGetFlashEffectTargetEvent(Entity<ChameleonDisguisedComponent> ent, ref GetFlashEffectTargetEvent args)
|
||||
{
|
||||
args.Target = ent.Comp.Disguise;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using Content.Client.Power.APC.UI;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Client.Power.APC.UI;
|
||||
using Content.Shared.APC;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.Power.APC
|
||||
{
|
||||
@@ -23,14 +22,6 @@ namespace Content.Client.Power.APC
|
||||
_menu = this.CreateWindow<ApcMenu>();
|
||||
_menu.SetEntity(Owner);
|
||||
_menu.OnBreaker += BreakerPressed;
|
||||
|
||||
var hasAccess = false;
|
||||
if (PlayerManager.LocalEntity != null)
|
||||
{
|
||||
var accessReader = EntMan.System<AccessReaderSystem>();
|
||||
hasAccess = accessReader.IsAllowed((EntityUid)PlayerManager.LocalEntity, Owner);
|
||||
}
|
||||
_menu?.SetAccessEnabled(hasAccess);
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -36,9 +36,19 @@ namespace Content.Client.Power.APC.UI
|
||||
{
|
||||
var castState = (ApcBoundInterfaceState) state;
|
||||
|
||||
if (!BreakerButton.Disabled)
|
||||
if (BreakerButton != null)
|
||||
{
|
||||
BreakerButton.Pressed = castState.MainBreaker;
|
||||
if(castState.HasAccess == false)
|
||||
{
|
||||
BreakerButton.Disabled = true;
|
||||
BreakerButton.ToolTip = Loc.GetString("apc-component-insufficient-access");
|
||||
}
|
||||
else
|
||||
{
|
||||
BreakerButton.Disabled = false;
|
||||
BreakerButton.ToolTip = null;
|
||||
BreakerButton.Pressed = castState.MainBreaker;
|
||||
}
|
||||
}
|
||||
|
||||
if (PowerLabel != null)
|
||||
@@ -76,20 +86,6 @@ namespace Content.Client.Power.APC.UI
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAccessEnabled(bool hasAccess)
|
||||
{
|
||||
if(hasAccess)
|
||||
{
|
||||
BreakerButton.Disabled = false;
|
||||
BreakerButton.ToolTip = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
BreakerButton.Disabled = true;
|
||||
BreakerButton.ToolTip = Loc.GetString("apc-component-insufficient-access");
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateChargeBarColor(float charge)
|
||||
{
|
||||
if (ChargeBar == null)
|
||||
|
||||
@@ -116,7 +116,7 @@ public partial class BaseShuttleControl : MapGridControl
|
||||
}
|
||||
}
|
||||
|
||||
protected void DrawGrid(DrawingHandleScreen handle, Matrix3x2 gridToView, Entity<MapGridComponent> grid, Color color, float alpha = 0.01f)
|
||||
protected void DrawGrid(DrawingHandleScreen handle, Matrix3x2 matrix, Entity<MapGridComponent> grid, Color color, float alpha = 0.01f)
|
||||
{
|
||||
var rator = Maps.GetAllTilesEnumerator(grid.Owner, grid.Comp);
|
||||
var minimapScale = MinimapScale;
|
||||
@@ -264,7 +264,7 @@ public partial class BaseShuttleControl : MapGridControl
|
||||
Extensions.EnsureLength(ref _allVertices, totalData);
|
||||
|
||||
_drawJob.MidPoint = midpoint;
|
||||
_drawJob.Matrix = gridToView;
|
||||
_drawJob.Matrix = matrix;
|
||||
_drawJob.MinimapScale = minimapScale;
|
||||
_drawJob.Vertices = gridData.Vertices;
|
||||
_drawJob.ScaledVertices = _allVertices;
|
||||
@@ -286,7 +286,7 @@ public partial class BaseShuttleControl : MapGridControl
|
||||
|
||||
private record struct GridDrawJob : IParallelRobustJob
|
||||
{
|
||||
public int BatchSize => 64;
|
||||
public int BatchSize => 16;
|
||||
|
||||
public float MinimapScale;
|
||||
public Vector2 MidPoint;
|
||||
@@ -297,7 +297,12 @@ public partial class BaseShuttleControl : MapGridControl
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
ScaledVertices[index] = Vector2.Transform(Vertices[index], Matrix);
|
||||
var vert = Vertices[index];
|
||||
var adjustedVert = Vector2.Transform(vert, Matrix);
|
||||
adjustedVert = adjustedVert with { Y = -adjustedVert.Y };
|
||||
|
||||
var scaledVert = ScalePosition(adjustedVert, MinimapScale, MidPoint);
|
||||
ScaledVertices[index] = scaledVert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ public sealed partial class NavScreen : BoxContainer
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
private SharedTransformSystem _xformSystem;
|
||||
|
||||
private EntityUid? _consoleEntity; // Entity of controlling console
|
||||
private EntityUid? _shuttleEntity;
|
||||
|
||||
public NavScreen()
|
||||
@@ -36,12 +35,6 @@ public sealed partial class NavScreen : BoxContainer
|
||||
_shuttleEntity = shuttle;
|
||||
}
|
||||
|
||||
public void SetConsole(EntityUid? console)
|
||||
{
|
||||
_consoleEntity = console;
|
||||
NavRadar.SetConsole(console);
|
||||
}
|
||||
|
||||
private void OnIFFTogglePressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
NavRadar.ShowIFF ^= true;
|
||||
|
||||
@@ -138,7 +138,6 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
||||
{
|
||||
var coordinates = _entManager.GetCoordinates(cState.NavState.Coordinates);
|
||||
NavContainer.SetShuttle(coordinates?.EntityId);
|
||||
NavContainer.SetConsole(owner);
|
||||
MapContainer.SetShuttle(coordinates?.EntityId);
|
||||
MapContainer.SetConsole(owner);
|
||||
|
||||
|
||||
@@ -107,19 +107,16 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
DrawCircles(handle);
|
||||
var gridNent = EntManager.GetNetEntity(GridEntity);
|
||||
var mapPos = _xformSystem.ToMapCoordinates(_coordinates.Value);
|
||||
var ourGridToWorld = _xformSystem.GetWorldMatrix(GridEntity.Value);
|
||||
var selectedDockToOurGrid = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, Angle.Zero);
|
||||
var selectedDockToWorld = Matrix3x2.Multiply(selectedDockToOurGrid, ourGridToWorld);
|
||||
var ourGridMatrix = _xformSystem.GetWorldMatrix(GridEntity.Value);
|
||||
var dockMatrix = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, Angle.Zero);
|
||||
var worldFromDock = Matrix3x2.Multiply(dockMatrix, ourGridMatrix);
|
||||
|
||||
Box2 viewBoundsWorld = Matrix3Helpers.TransformBox(selectedDockToWorld, new Box2(-WorldRangeVector, WorldRangeVector));
|
||||
|
||||
Matrix3x2.Invert(selectedDockToWorld, out var worldToSelectedDock);
|
||||
var selectedDockToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector);
|
||||
Matrix3x2.Invert(worldFromDock, out var offsetMatrix);
|
||||
|
||||
// Draw nearby grids
|
||||
var controlBounds = PixelSizeBox;
|
||||
_grids.Clear();
|
||||
_mapManager.FindGridsIntersecting(gridXform.MapID, viewBoundsWorld, ref _grids);
|
||||
_mapManager.FindGridsIntersecting(gridXform.MapID, new Box2(mapPos.Position - WorldRangeVector, mapPos.Position + WorldRangeVector), ref _grids);
|
||||
|
||||
// offset the dotted-line position to the bounds.
|
||||
Vector2? viewedDockPos = _viewedState != null ? MidPointVector : null;
|
||||
@@ -139,11 +136,11 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
if (grid.Owner != GridEntity && !_shuttles.CanDraw(grid.Owner, iffComp: iffComp))
|
||||
continue;
|
||||
|
||||
var curGridToWorld = _xformSystem.GetWorldMatrix(grid.Owner);
|
||||
var curGridToView = curGridToWorld * worldToSelectedDock * selectedDockToView;
|
||||
var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner);
|
||||
var matty = Matrix3x2.Multiply(gridMatrix, offsetMatrix);
|
||||
var color = _shuttles.GetIFFColor(grid.Owner, grid.Owner == GridEntity, component: iffComp);
|
||||
|
||||
DrawGrid(handle, curGridToView, grid, color);
|
||||
DrawGrid(handle, matty, grid, color);
|
||||
|
||||
// Draw any docks on that grid
|
||||
if (!DockState.Docks.TryGetValue(EntManager.GetNetEntity(grid), out var gridDocks))
|
||||
@@ -154,24 +151,23 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
if (ViewedDock == dock.Entity)
|
||||
continue;
|
||||
|
||||
var otherDockRotation = Matrix3Helpers.CreateRotation(dock.Angle);
|
||||
var position = Vector2.Transform(dock.Coordinates.Position, matty);
|
||||
|
||||
// This box is the AABB of all the vertices we draw below.
|
||||
var dockRenderBoundsLocal = new Box2(-0.5f, -0.7f, 0.5f, 0.5f);
|
||||
var currentDockToCurGrid = Matrix3Helpers.CreateTransform(dock.Coordinates.Position, dock.Angle);
|
||||
var currentDockToWorld = Matrix3x2.Multiply(currentDockToCurGrid, curGridToWorld);
|
||||
var dockRenderBoundsWorld = Matrix3Helpers.TransformBox(currentDockToWorld, dockRenderBoundsLocal);
|
||||
if (!viewBoundsWorld.Intersects(dockRenderBoundsWorld))
|
||||
var otherDockRotation = Matrix3Helpers.CreateRotation(dock.Angle);
|
||||
var scaledPos = ScalePosition(position with {Y = -position.Y});
|
||||
|
||||
if (!controlBounds.Contains(scaledPos.Floored()))
|
||||
continue;
|
||||
|
||||
// Draw the dock's collision
|
||||
var collisionBL = Vector2.Transform(dock.Coordinates.Position +
|
||||
Vector2.Transform(new Vector2(-0.2f, -0.7f), otherDockRotation), curGridToView);
|
||||
Vector2.Transform(new Vector2(-0.2f, -0.7f), otherDockRotation), matty);
|
||||
var collisionBR = Vector2.Transform(dock.Coordinates.Position +
|
||||
Vector2.Transform(new Vector2(0.2f, -0.7f), otherDockRotation), curGridToView);
|
||||
Vector2.Transform(new Vector2(0.2f, -0.7f), otherDockRotation), matty);
|
||||
var collisionTR = Vector2.Transform(dock.Coordinates.Position +
|
||||
Vector2.Transform(new Vector2(0.2f, -0.5f), otherDockRotation), curGridToView);
|
||||
Vector2.Transform(new Vector2(0.2f, -0.5f), otherDockRotation), matty);
|
||||
var collisionTL = Vector2.Transform(dock.Coordinates.Position +
|
||||
Vector2.Transform(new Vector2(-0.2f, -0.5f), otherDockRotation), curGridToView);
|
||||
Vector2.Transform(new Vector2(-0.2f, -0.5f), otherDockRotation), matty);
|
||||
|
||||
var verts = new[]
|
||||
{
|
||||
@@ -185,6 +181,13 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
collisionBL,
|
||||
};
|
||||
|
||||
for (var i = 0; i < verts.Length; i++)
|
||||
{
|
||||
var vert = verts[i];
|
||||
vert.Y = -vert.Y;
|
||||
verts[i] = ScalePosition(vert);
|
||||
}
|
||||
|
||||
var collisionCenter = verts[0] + verts[1] + verts[3] + verts[5];
|
||||
|
||||
var otherDockConnection = Color.ToSrgb(Color.Pink);
|
||||
@@ -192,10 +195,10 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.LineList, verts, otherDockConnection);
|
||||
|
||||
// Draw the dock itself
|
||||
var dockBL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, -0.5f), curGridToView);
|
||||
var dockBR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, -0.5f), curGridToView);
|
||||
var dockTR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, 0.5f), curGridToView);
|
||||
var dockTL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, 0.5f), curGridToView);
|
||||
var dockBL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, -0.5f), matty);
|
||||
var dockBR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, -0.5f), matty);
|
||||
var dockTR = Vector2.Transform(dock.Coordinates.Position + new Vector2(0.5f, 0.5f), matty);
|
||||
var dockTL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, 0.5f), matty);
|
||||
|
||||
verts = new[]
|
||||
{
|
||||
@@ -209,6 +212,13 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
dockBL
|
||||
};
|
||||
|
||||
for (var i = 0; i < verts.Length; i++)
|
||||
{
|
||||
var vert = verts[i];
|
||||
vert.Y = -vert.Y;
|
||||
verts[i] = ScalePosition(vert);
|
||||
}
|
||||
|
||||
Color otherDockColor;
|
||||
|
||||
if (HighlightedDock == dock.Entity)
|
||||
@@ -243,11 +253,9 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
collisionCenter /= 4;
|
||||
var range = viewedDockPos.Value - collisionCenter;
|
||||
|
||||
var maxRange = SharedDockingSystem.DockingHiglightRange * MinimapScale;
|
||||
var maxRangeSq = maxRange * maxRange;
|
||||
if (range.LengthSquared() < maxRangeSq)
|
||||
if (range.Length() < SharedDockingSystem.DockingHiglightRange * MinimapScale)
|
||||
{
|
||||
if (dock.GridDockedWith == null)
|
||||
if (_viewedState?.GridDockedWith == null)
|
||||
{
|
||||
var coordsOne = EntManager.GetCoordinates(_viewedState!.Coordinates);
|
||||
var coordsTwo = EntManager.GetCoordinates(dock.Coordinates);
|
||||
@@ -257,11 +265,10 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
var rotA = _xformSystem.GetWorldRotation(coordsOne.EntityId) + _viewedState!.Angle;
|
||||
var rotB = _xformSystem.GetWorldRotation(coordsTwo.EntityId) + dock.Angle;
|
||||
|
||||
var distanceSq = (mapOne.Position - mapTwo.Position).LengthSquared();
|
||||
var distance = (mapOne.Position - mapTwo.Position).Length();
|
||||
|
||||
var inAlignment = _dockSystem.InAlignment(mapOne, rotA, mapTwo, rotB);
|
||||
var maxDockDistSq = SharedDockingSystem.DockRange * SharedDockingSystem.DockRange;
|
||||
var canDock = distanceSq < maxDockDistSq && inAlignment;
|
||||
var canDock = distance < SharedDockingSystem.DockRange && inAlignment;
|
||||
|
||||
if (dockButton != null)
|
||||
dockButton.Disabled = !canDock || !canDockChange;
|
||||
@@ -290,8 +297,7 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
||||
{
|
||||
// Because it's being layed out top-down we have to arrange for first frame.
|
||||
container.Arrange(PixelRect);
|
||||
var dockPositionInView = Vector2.Transform(dock.Coordinates.Position, curGridToView);
|
||||
var containerPos = dockPositionInView / UIScale - container.DesiredSize / 2 - new Vector2(0f, 0.75f) * MinimapScale;
|
||||
var containerPos = scaledPos / UIScale - container.DesiredSize / 2 - new Vector2(0f, 0.75f) * MinimapScale;
|
||||
SetPosition(container, containerPos);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,6 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
/// </summary>
|
||||
private EntityCoordinates? _coordinates;
|
||||
|
||||
/// <summary>
|
||||
/// Entity of controlling console
|
||||
/// </summary>
|
||||
private EntityUid? _consoleEntity;
|
||||
|
||||
private Angle? _rotation;
|
||||
|
||||
private Dictionary<NetEntity, List<DockingPortState>> _docks = new();
|
||||
@@ -62,11 +57,6 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
_rotation = angle;
|
||||
}
|
||||
|
||||
public void SetConsole(EntityUid? consoleEntity)
|
||||
{
|
||||
_consoleEntity = consoleEntity;
|
||||
}
|
||||
|
||||
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.KeyBindUp(args);
|
||||
@@ -149,35 +139,40 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
}
|
||||
|
||||
var mapPos = _transform.ToMapCoordinates(_coordinates.Value);
|
||||
var posMatrix = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, _rotation.Value);
|
||||
var offset = _coordinates.Value.Position;
|
||||
var posMatrix = Matrix3Helpers.CreateTransform(offset, _rotation.Value);
|
||||
var ourEntRot = RotateWithEntity ? _transform.GetWorldRotation(xform) : _rotation.Value;
|
||||
var ourEntMatrix = Matrix3Helpers.CreateTransform(_transform.GetWorldPosition(xform), ourEntRot);
|
||||
var shuttleToWorld = Matrix3x2.Multiply(posMatrix, ourEntMatrix);
|
||||
Matrix3x2.Invert(shuttleToWorld, out var worldToShuttle);
|
||||
var shuttleToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector);
|
||||
var ourWorldMatrix = Matrix3x2.Multiply(posMatrix, ourEntMatrix);
|
||||
Matrix3x2.Invert(ourWorldMatrix, out var ourWorldMatrixInvert);
|
||||
|
||||
// Draw our grid in detail
|
||||
var ourGridId = xform.GridUid;
|
||||
if (EntManager.TryGetComponent<MapGridComponent>(ourGridId, out var ourGrid) &&
|
||||
fixturesQuery.HasComponent(ourGridId.Value))
|
||||
{
|
||||
var ourGridToWorld = _transform.GetWorldMatrix(ourGridId.Value);
|
||||
var ourGridToShuttle = Matrix3x2.Multiply(ourGridToWorld, worldToShuttle);
|
||||
var ourGridToView = ourGridToShuttle * shuttleToView;
|
||||
var ourGridMatrix = _transform.GetWorldMatrix(ourGridId.Value);
|
||||
var matrix = Matrix3x2.Multiply(ourGridMatrix, ourWorldMatrixInvert);
|
||||
var color = _shuttles.GetIFFColor(ourGridId.Value, self: true);
|
||||
|
||||
DrawGrid(handle, ourGridToView, (ourGridId.Value, ourGrid), color);
|
||||
DrawDocks(handle, ourGridId.Value, ourGridToView);
|
||||
DrawGrid(handle, matrix, (ourGridId.Value, ourGrid), color);
|
||||
DrawDocks(handle, ourGridId.Value, matrix);
|
||||
}
|
||||
|
||||
var invertedPosition = _coordinates.Value.Position - offset;
|
||||
invertedPosition.Y = -invertedPosition.Y;
|
||||
// Don't need to transform the InvWorldMatrix again as it's already offset to its position.
|
||||
|
||||
// Draw radar position on the station
|
||||
var radarPos = invertedPosition;
|
||||
const float radarVertRadius = 2f;
|
||||
|
||||
var radarPosVerts = new Vector2[]
|
||||
{
|
||||
ScalePosition(new Vector2(0f, -radarVertRadius)),
|
||||
ScalePosition(new Vector2(radarVertRadius / 2f, 0f)),
|
||||
ScalePosition(new Vector2(0f, radarVertRadius)),
|
||||
ScalePosition(new Vector2(radarVertRadius / -2f, 0f)),
|
||||
ScalePosition(radarPos + new Vector2(0f, -radarVertRadius)),
|
||||
ScalePosition(radarPos + new Vector2(radarVertRadius / 2f, 0f)),
|
||||
ScalePosition(radarPos + new Vector2(0f, radarVertRadius)),
|
||||
ScalePosition(radarPos + new Vector2(radarVertRadius / -2f, 0f)),
|
||||
};
|
||||
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, radarPosVerts, Color.Lime);
|
||||
@@ -202,8 +197,8 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
if (!_shuttles.CanDraw(gUid, gridBody, iff))
|
||||
continue;
|
||||
|
||||
var curGridToWorld = _transform.GetWorldMatrix(gUid);
|
||||
var curGridToView = curGridToWorld * worldToShuttle * shuttleToView;
|
||||
var gridMatrix = _transform.GetWorldMatrix(gUid);
|
||||
var matty = Matrix3x2.Multiply(gridMatrix, ourWorldMatrixInvert);
|
||||
|
||||
var labelColor = _shuttles.GetIFFColor(grid, self: false, iff);
|
||||
var coordColor = new Color(labelColor.R * 0.8f, labelColor.G * 0.8f, labelColor.B * 0.8f, 0.5f);
|
||||
@@ -218,7 +213,8 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
{
|
||||
var gridBounds = grid.Comp.LocalAABB;
|
||||
|
||||
var gridCentre = Vector2.Transform(gridBody.LocalCenter, curGridToView);
|
||||
var gridCentre = Vector2.Transform(gridBody.LocalCenter, matty);
|
||||
gridCentre.Y = -gridCentre.Y;
|
||||
|
||||
var distance = gridCentre.Length();
|
||||
var labelText = Loc.GetString("shuttle-console-iff-label", ("name", labelName),
|
||||
@@ -234,8 +230,9 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
// y-offset the control to always render below the grid (vertically)
|
||||
var yOffset = Math.Max(gridBounds.Height, gridBounds.Width) * MinimapScale / 1.8f;
|
||||
|
||||
// The actual position in the UI.
|
||||
var gridScaledPosition = gridCentre - new Vector2(0, -yOffset);
|
||||
// The actual position in the UI. We centre the label by offsetting the matrix position
|
||||
// by half the label's width, plus the y-offset
|
||||
var gridScaledPosition = ScalePosition(gridCentre) - new Vector2(0, -yOffset);
|
||||
|
||||
// Normalize the grid position if it exceeds the viewport bounds
|
||||
// normalizing it instead of clamping it preserves the direction of the vector and prevents corner-hugging
|
||||
@@ -267,32 +264,18 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
}
|
||||
|
||||
// Detailed view
|
||||
var gridAABB = curGridToWorld.TransformBox(grid.Comp.LocalAABB);
|
||||
var gridAABB = gridMatrix.TransformBox(grid.Comp.LocalAABB);
|
||||
|
||||
// Skip drawing if it's out of range.
|
||||
if (!gridAABB.Intersects(viewAABB))
|
||||
continue;
|
||||
|
||||
DrawGrid(handle, curGridToView, grid, labelColor);
|
||||
DrawDocks(handle, gUid, curGridToView);
|
||||
DrawGrid(handle, matty, grid, labelColor);
|
||||
DrawDocks(handle, gUid, matty);
|
||||
}
|
||||
|
||||
// If we've set the controlling console, and it's on a different grid
|
||||
// to the shuttle itself, then draw an additional marker to help the
|
||||
// player determine where they are relative to the shuttle.
|
||||
if (_consoleEntity != null && xformQuery.TryGetComponent(_consoleEntity, out var consoleXform))
|
||||
{
|
||||
if (consoleXform.ParentUid != _coordinates.Value.EntityId)
|
||||
{
|
||||
var consolePositionWorld = _transform.GetWorldPosition((EntityUid)_consoleEntity);
|
||||
var p = Vector2.Transform(consolePositionWorld, worldToShuttle * shuttleToView);
|
||||
handle.DrawCircle(p, 5, Color.ToSrgb(Color.Cyan), true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3x2 gridToView)
|
||||
private void DrawDocks(DrawingHandleScreen handle, EntityUid uid, Matrix3x2 matrix)
|
||||
{
|
||||
if (!ShowDocks)
|
||||
return;
|
||||
@@ -300,32 +283,33 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
||||
const float DockScale = 0.6f;
|
||||
var nent = EntManager.GetNetEntity(uid);
|
||||
|
||||
const float sqrt2 = 1.41421356f;
|
||||
const float dockRadius = DockScale * sqrt2;
|
||||
// Worst-case bounds used to cull a dock:
|
||||
Box2 viewBounds = new Box2(-dockRadius, -dockRadius, Size.X + dockRadius, Size.Y + dockRadius);
|
||||
if (_docks.TryGetValue(nent, out var docks))
|
||||
{
|
||||
foreach (var state in docks)
|
||||
{
|
||||
var position = state.Coordinates.Position;
|
||||
var uiPosition = Vector2.Transform(position, matrix);
|
||||
|
||||
var positionInView = Vector2.Transform(position, gridToView);
|
||||
if (!viewBounds.Contains(positionInView))
|
||||
{
|
||||
if (uiPosition.Length() > (WorldRange * 2f) - DockScale)
|
||||
continue;
|
||||
}
|
||||
|
||||
var color = Color.ToSrgb(Color.Magenta);
|
||||
|
||||
var verts = new[]
|
||||
{
|
||||
Vector2.Transform(position + new Vector2(-DockScale, -DockScale), gridToView),
|
||||
Vector2.Transform(position + new Vector2(DockScale, -DockScale), gridToView),
|
||||
Vector2.Transform(position + new Vector2(DockScale, DockScale), gridToView),
|
||||
Vector2.Transform(position + new Vector2(-DockScale, DockScale), gridToView),
|
||||
Vector2.Transform(position + new Vector2(-DockScale, -DockScale), matrix),
|
||||
Vector2.Transform(position + new Vector2(DockScale, -DockScale), matrix),
|
||||
Vector2.Transform(position + new Vector2(DockScale, DockScale), matrix),
|
||||
Vector2.Transform(position + new Vector2(-DockScale, DockScale), matrix),
|
||||
};
|
||||
|
||||
for (var i = 0; i < verts.Length; i++)
|
||||
{
|
||||
var vert = verts[i];
|
||||
vert.Y = -vert.Y;
|
||||
verts[i] = ScalePosition(vert);
|
||||
}
|
||||
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, verts, color.WithAlpha(0.8f));
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.LineStrip, verts, color);
|
||||
}
|
||||
|
||||
@@ -131,8 +131,7 @@ public sealed partial class BorgMenu : FancyWindow
|
||||
_modules.Clear();
|
||||
foreach (var module in chassis.ModuleContainer.ContainedEntities)
|
||||
{
|
||||
var moduleComponent = _entity.GetComponent<BorgModuleComponent>(module);
|
||||
var control = new BorgModuleControl(module, _entity, !moduleComponent.DefaultModule);
|
||||
var control = new BorgModuleControl(module, _entity);
|
||||
control.RemoveButtonPressed += () =>
|
||||
{
|
||||
RemoveModuleButtonPressed?.Invoke(module);
|
||||
|
||||
@@ -9,7 +9,7 @@ public sealed partial class BorgModuleControl : PanelContainer
|
||||
{
|
||||
public Action? RemoveButtonPressed;
|
||||
|
||||
public BorgModuleControl(EntityUid entity, IEntityManager entityManager, bool canRemove)
|
||||
public BorgModuleControl(EntityUid entity, IEntityManager entityManager)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
@@ -20,7 +20,6 @@ public sealed partial class BorgModuleControl : PanelContainer
|
||||
{
|
||||
RemoveButtonPressed?.Invoke();
|
||||
};
|
||||
RemoveButton.Visible = canRemove;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
Title="{Loc 'borg-select-type-menu-title'}"
|
||||
SetSize="550 300">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal" VerticalExpand="True">
|
||||
<!-- Left pane: selection of borg type -->
|
||||
<BoxContainer Orientation="Vertical" MinWidth="200" Margin="2 0">
|
||||
<Label Text="{Loc 'borg-select-type-menu-available'}" StyleClasses="LabelHeading" />
|
||||
<ScrollContainer HScrollEnabled="False" VerticalExpand="True">
|
||||
<BoxContainer Name="SelectionsContainer" Orientation="Vertical" />
|
||||
</ScrollContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<customControls:VSeparator />
|
||||
|
||||
<!-- Right pane: information about selected borg module, confirm button. -->
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="2 0">
|
||||
<Label Text="{Loc 'borg-select-type-menu-information'}" StyleClasses="LabelHeading" />
|
||||
<Control VerticalExpand="True">
|
||||
<controls:Placeholder Name="InfoPlaceholder" PlaceholderText="{Loc 'borg-select-type-menu-select-type'}" />
|
||||
<BoxContainer Name="InfoContents" Orientation="Vertical" Visible="False">
|
||||
<BoxContainer Orientation="Horizontal" Margin="0 0 0 4">
|
||||
<EntityPrototypeView Name="ChassisView" Scale="2,2" />
|
||||
<Label Name="NameLabel" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
|
||||
<RichTextLabel Name="DescriptionLabel" VerticalExpand="True" VerticalAlignment="Top" />
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
<controls:ConfirmButton Name="ConfirmTypeButton" Text="{Loc 'borg-select-type-menu-confirm'}"
|
||||
Disabled="True" HorizontalAlignment="Right"
|
||||
MinWidth="200" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<controls:StripeBack Margin="0 0 0 4">
|
||||
<Label Text="{Loc 'borg-select-type-menu-bottom-text'}" HorizontalAlignment="Center" StyleClasses="LabelSubText" Margin="4 4 0 4"/>
|
||||
</controls:StripeBack>
|
||||
</BoxContainer>
|
||||
|
||||
</controls:FancyWindow>
|
||||
@@ -1,81 +0,0 @@
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Client.UserInterface.Systems.Guidebook;
|
||||
using Content.Shared.Guidebook;
|
||||
using Content.Shared.Silicons.Borgs;
|
||||
using Content.Shared.Silicons.Borgs.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Silicons.Borgs;
|
||||
|
||||
/// <summary>
|
||||
/// Menu used by borgs to select their type.
|
||||
/// </summary>
|
||||
/// <seealso cref="BorgSelectTypeUserInterface"/>
|
||||
/// <seealso cref="BorgSwitchableTypeComponent"/>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class BorgSelectTypeMenu : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
private BorgTypePrototype? _selectedBorgType;
|
||||
|
||||
public event Action<ProtoId<BorgTypePrototype>>? ConfirmedBorgType;
|
||||
|
||||
[ValidatePrototypeId<GuideEntryPrototype>]
|
||||
private static readonly List<ProtoId<GuideEntryPrototype>> GuidebookEntries = new() { "Cyborgs", "Robotics" };
|
||||
|
||||
public BorgSelectTypeMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
var group = new ButtonGroup();
|
||||
foreach (var borgType in _prototypeManager.EnumeratePrototypes<BorgTypePrototype>().OrderBy(PrototypeName))
|
||||
{
|
||||
var button = new Button
|
||||
{
|
||||
Text = PrototypeName(borgType),
|
||||
Group = group,
|
||||
};
|
||||
button.OnPressed += _ =>
|
||||
{
|
||||
_selectedBorgType = borgType;
|
||||
UpdateInformation(borgType);
|
||||
};
|
||||
SelectionsContainer.AddChild(button);
|
||||
}
|
||||
|
||||
ConfirmTypeButton.OnPressed += ConfirmButtonPressed;
|
||||
HelpGuidebookIds = GuidebookEntries;
|
||||
}
|
||||
|
||||
private void UpdateInformation(BorgTypePrototype prototype)
|
||||
{
|
||||
_selectedBorgType = prototype;
|
||||
|
||||
InfoContents.Visible = true;
|
||||
InfoPlaceholder.Visible = false;
|
||||
ConfirmTypeButton.Disabled = false;
|
||||
|
||||
NameLabel.Text = PrototypeName(prototype);
|
||||
DescriptionLabel.Text = Loc.GetString($"borg-type-{prototype.ID}-desc");
|
||||
ChassisView.SetPrototype(prototype.DummyPrototype);
|
||||
}
|
||||
|
||||
private void ConfirmButtonPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
if (_selectedBorgType == null)
|
||||
return;
|
||||
|
||||
ConfirmedBorgType?.Invoke(_selectedBorgType);
|
||||
}
|
||||
|
||||
private static string PrototypeName(BorgTypePrototype prototype)
|
||||
{
|
||||
return Loc.GetString($"borg-type-{prototype.ID}-name");
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
using Content.Shared.Silicons.Borgs.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.Silicons.Borgs;
|
||||
|
||||
/// <summary>
|
||||
/// User interface used by borgs to select their type.
|
||||
/// </summary>
|
||||
/// <seealso cref="BorgSelectTypeMenu"/>
|
||||
/// <seealso cref="BorgSwitchableTypeComponent"/>
|
||||
/// <seealso cref="BorgSwitchableTypeUiKey"/>
|
||||
[UsedImplicitly]
|
||||
public sealed class BorgSelectTypeUserInterface : BoundUserInterface
|
||||
{
|
||||
[ViewVariables]
|
||||
private BorgSelectTypeMenu? _menu;
|
||||
|
||||
public BorgSelectTypeUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<BorgSelectTypeMenu>();
|
||||
_menu.ConfirmedBorgType += prototype => SendMessage(new BorgSelectTypeMessage(prototype));
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Silicons.Borgs;
|
||||
using Content.Shared.Silicons.Borgs.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client.Silicons.Borgs;
|
||||
|
||||
/// <summary>
|
||||
/// Client side logic for borg type switching. Sets up primarily client-side visual information.
|
||||
/// </summary>
|
||||
/// <seealso cref="SharedBorgSwitchableTypeSystem"/>
|
||||
/// <seealso cref="BorgSwitchableTypeComponent"/>
|
||||
public sealed class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem
|
||||
{
|
||||
[Dependency] private readonly BorgSystem _borgSystem = default!;
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BorgSwitchableTypeComponent, AfterAutoHandleStateEvent>(AfterStateHandler);
|
||||
SubscribeLocalEvent<BorgSwitchableTypeComponent, ComponentStartup>(OnComponentStartup);
|
||||
}
|
||||
|
||||
private void OnComponentStartup(Entity<BorgSwitchableTypeComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
UpdateEntityAppearance(ent);
|
||||
}
|
||||
|
||||
private void AfterStateHandler(Entity<BorgSwitchableTypeComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
UpdateEntityAppearance(ent);
|
||||
}
|
||||
|
||||
protected override void UpdateEntityAppearance(
|
||||
Entity<BorgSwitchableTypeComponent> entity,
|
||||
BorgTypePrototype prototype)
|
||||
{
|
||||
if (TryComp(entity, out SpriteComponent? sprite))
|
||||
{
|
||||
sprite.LayerSetState(BorgVisualLayers.Body, prototype.SpriteBodyState);
|
||||
sprite.LayerSetState(BorgVisualLayers.LightStatus, prototype.SpriteToggleLightState);
|
||||
}
|
||||
|
||||
if (TryComp(entity, out BorgChassisComponent? chassis))
|
||||
{
|
||||
_borgSystem.SetMindStates(
|
||||
(entity.Owner, chassis),
|
||||
prototype.SpriteHasMindState,
|
||||
prototype.SpriteNoMindState);
|
||||
|
||||
if (TryComp(entity, out AppearanceComponent? appearance))
|
||||
{
|
||||
// Queue update so state changes apply.
|
||||
_appearance.QueueUpdate(entity, appearance);
|
||||
}
|
||||
}
|
||||
|
||||
if (prototype.SpriteBodyMovementState is { } movementState)
|
||||
{
|
||||
var spriteMovement = EnsureComp<SpriteMovementComponent>(entity);
|
||||
spriteMovement.NoMovementLayers.Clear();
|
||||
spriteMovement.NoMovementLayers["movement"] = new PrototypeLayerData
|
||||
{
|
||||
State = prototype.SpriteBodyState,
|
||||
};
|
||||
spriteMovement.MovementLayers.Clear();
|
||||
spriteMovement.MovementLayers["movement"] = new PrototypeLayerData
|
||||
{
|
||||
State = movementState,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
RemComp<SpriteMovementComponent>(entity);
|
||||
}
|
||||
|
||||
base.UpdateEntityAppearance(entity, prototype);
|
||||
}
|
||||
}
|
||||
@@ -92,18 +92,4 @@ public sealed class BorgSystem : SharedBorgSystem
|
||||
sprite.LayerSetState(MMIVisualLayers.Base, state);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the sprite states used for the borg "is there a mind or not" indication.
|
||||
/// </summary>
|
||||
/// <param name="borg">The entity and component to modify.</param>
|
||||
/// <param name="hasMindState">The state to use if the borg has a mind.</param>
|
||||
/// <param name="noMindState">The state to use if the borg has no mind.</param>
|
||||
/// <seealso cref="BorgChassisComponent.HasMindState"/>
|
||||
/// <seealso cref="BorgChassisComponent.NoMindState"/>
|
||||
public void SetMindStates(Entity<BorgChassisComponent> borg, string hasMindState, string noMindState)
|
||||
{
|
||||
borg.Comp.HasMindState = hasMindState;
|
||||
borg.Comp.NoMindState = noMindState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Silicons.Laws.Ui;
|
||||
@@ -19,13 +18,8 @@ public sealed partial class LawDisplay : Control
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
|
||||
private static readonly TimeSpan PressCooldown = TimeSpan.FromSeconds(3);
|
||||
|
||||
private readonly Dictionary<Button, TimeSpan> _nextAllowedPress = new();
|
||||
|
||||
public LawDisplay(EntityUid uid, SiliconLaw law, HashSet<string>? radioChannels)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
@@ -53,12 +47,9 @@ public sealed partial class LawDisplay : Control
|
||||
MinWidth = 75,
|
||||
};
|
||||
|
||||
_nextAllowedPress[localButton] = TimeSpan.Zero;
|
||||
|
||||
localButton.OnPressed += _ =>
|
||||
{
|
||||
_chatManager.SendMessage($"{lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Local);
|
||||
_nextAllowedPress[localButton] = _timing.CurTime + PressCooldown;
|
||||
};
|
||||
|
||||
LawAnnouncementButtons.AddChild(localButton);
|
||||
@@ -80,8 +71,6 @@ public sealed partial class LawDisplay : Control
|
||||
MinWidth = 75,
|
||||
};
|
||||
|
||||
_nextAllowedPress[radioChannelButton] = TimeSpan.Zero;
|
||||
|
||||
radioChannelButton.OnPressed += _ =>
|
||||
{
|
||||
switch (radioChannel)
|
||||
@@ -91,21 +80,9 @@ public sealed partial class LawDisplay : Control
|
||||
default:
|
||||
_chatManager.SendMessage($"{SharedChatSystem.RadioChannelPrefix}{radioChannelProto.KeyCode} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); break;
|
||||
}
|
||||
_nextAllowedPress[radioChannelButton] = _timing.CurTime + PressCooldown;
|
||||
};
|
||||
|
||||
LawAnnouncementButtons.AddChild(radioChannelButton);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
var curTime = _timing.CurTime;
|
||||
foreach (var (button, nextPress) in _nextAllowedPress)
|
||||
{
|
||||
button.Disabled = curTime < nextPress;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Content.Shared.Doors.Components;
|
||||
using Content.Shared.Electrocution;
|
||||
using Content.Shared.Silicons.StationAi;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -7,69 +6,25 @@ namespace Content.Client.Silicons.StationAi;
|
||||
|
||||
public sealed partial class StationAiSystem
|
||||
{
|
||||
private readonly ResPath _aiActionsRsi = new ResPath("/Textures/Interface/Actions/actions_ai.rsi");
|
||||
|
||||
private void InitializeAirlock()
|
||||
{
|
||||
SubscribeLocalEvent<DoorBoltComponent, GetStationAiRadialEvent>(OnDoorBoltGetRadial);
|
||||
SubscribeLocalEvent<AirlockComponent, GetStationAiRadialEvent>(OnEmergencyAccessGetRadial);
|
||||
SubscribeLocalEvent<ElectrifiedComponent, GetStationAiRadialEvent>(OnDoorElectrifiedGetRadial);
|
||||
}
|
||||
|
||||
private void OnDoorBoltGetRadial(Entity<DoorBoltComponent> ent, ref GetStationAiRadialEvent args)
|
||||
{
|
||||
args.Actions.Add(
|
||||
new StationAiRadial
|
||||
args.Actions.Add(new StationAiRadial()
|
||||
{
|
||||
Sprite = ent.Comp.BoltsDown ?
|
||||
new SpriteSpecifier.Rsi(
|
||||
new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "open") :
|
||||
new SpriteSpecifier.Rsi(
|
||||
new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "closed"),
|
||||
Tooltip = ent.Comp.BoltsDown ? Loc.GetString("bolt-open") : Loc.GetString("bolt-close"),
|
||||
Event = new StationAiBoltEvent()
|
||||
{
|
||||
Sprite = ent.Comp.BoltsDown
|
||||
? new SpriteSpecifier.Rsi(_aiActionsRsi, "unbolt_door")
|
||||
: new SpriteSpecifier.Rsi(_aiActionsRsi, "bolt_door"),
|
||||
Tooltip = ent.Comp.BoltsDown
|
||||
? Loc.GetString("bolt-open")
|
||||
: Loc.GetString("bolt-close"),
|
||||
Event = new StationAiBoltEvent
|
||||
{
|
||||
Bolted = !ent.Comp.BoltsDown,
|
||||
}
|
||||
Bolted = !ent.Comp.BoltsDown,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void OnEmergencyAccessGetRadial(Entity<AirlockComponent> ent, ref GetStationAiRadialEvent args)
|
||||
{
|
||||
args.Actions.Add(
|
||||
new StationAiRadial
|
||||
{
|
||||
Sprite = ent.Comp.EmergencyAccess
|
||||
? new SpriteSpecifier.Rsi(_aiActionsRsi, "emergency_off")
|
||||
: new SpriteSpecifier.Rsi(_aiActionsRsi, "emergency_on"),
|
||||
Tooltip = ent.Comp.EmergencyAccess
|
||||
? Loc.GetString("emergency-access-off")
|
||||
: Loc.GetString("emergency-access-on"),
|
||||
Event = new StationAiEmergencyAccessEvent
|
||||
{
|
||||
EmergencyAccess = !ent.Comp.EmergencyAccess,
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void OnDoorElectrifiedGetRadial(Entity<ElectrifiedComponent> ent, ref GetStationAiRadialEvent args)
|
||||
{
|
||||
args.Actions.Add(
|
||||
new StationAiRadial
|
||||
{
|
||||
Sprite = ent.Comp.Enabled
|
||||
? new SpriteSpecifier.Rsi(_aiActionsRsi, "door_overcharge_off")
|
||||
: new SpriteSpecifier.Rsi(_aiActionsRsi, "door_overcharge_on"),
|
||||
Tooltip = ent.Comp.Enabled
|
||||
? Loc.GetString("electrify-door-off")
|
||||
: Loc.GetString("electrify-door-on"),
|
||||
Event = new StationAiElectrifiedEvent
|
||||
{
|
||||
Electrified = !ent.Comp.Enabled,
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Shared.Singularity.EntitySystems;
|
||||
using Content.Shared.Singularity.Components;
|
||||
|
||||
namespace Content.Client.Singularity.Systems;
|
||||
namespace Content.Client.Singularity.EntitySystems;
|
||||
|
||||
/// <summary>
|
||||
/// The client-side version of <see cref="SharedEventHorizonSystem"/>.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user