Compare commits
1 Commits
workbench-
...
SpellStora
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
544a260f4b |
37
.github/CODEOWNERS
vendored
37
.github/CODEOWNERS
vendored
@@ -2,30 +2,49 @@
|
|||||||
|
|
||||||
# Sorting by path instead of by who added it one day :(
|
# Sorting by path instead of by who added it one day :(
|
||||||
# this isn't how codeowners rules work pls read the first comment instead of trying to force a sorting order
|
# this isn't how codeowners rules work pls read the first comment instead of trying to force a sorting order
|
||||||
|
/Resources/ConfigPresets/WizardsDen/ @Chief-Engineer
|
||||||
|
|
||||||
/Resources/ConfigPresets/WizardsDen/ @nikthechampiongr @crazybrain23
|
# Moony's Gargantuan List Of Things She Cares About, or MGLOTSCA for short.
|
||||||
/Content.*/Administration/ @DrSmugleaf @nikthechampiongr @crazybrain23
|
# You need to add your name to these entries, not make a new one, if you care about them.
|
||||||
/Resources/ServerInfo/ @nikthechampiongr @crazybrain23
|
/Content.*/Toolshed/ @moonheart08
|
||||||
/Resources/ServerInfo/Guidebook/ServerRules/ @nikthechampiongr @crazybrain23
|
**/Toolshed/** @moonheart08
|
||||||
|
*Command.cs @moonheart08
|
||||||
|
/Content.*/Administration/ @moonheart08 @DrSmugleaf @Chief-Engineer
|
||||||
|
/Content.*/Station/ @moonheart08
|
||||||
|
/Content.*/Maps/ @moonheart08
|
||||||
|
/Content.*/GameTicking/ @moonheart08 @EmoGarbage404
|
||||||
|
/Resources/ServerInfo/ @moonheart08 @Chief-Engineer
|
||||||
|
/Resources/ServerInfo/Guidebook/ @moonheart08 @EmoGarbage404
|
||||||
|
/Resources/ServerInfo/Guidebook/ServerRules/ @Chief-Engineer
|
||||||
|
/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/Body/ @DrSmugleaf # suffering
|
||||||
/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf
|
/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf
|
||||||
/Resources/Prototypes/Entities/Mobs/Species/ @DrSmugleaf
|
/Resources/Prototypes/Entities/Mobs/Species/ @DrSmugleaf
|
||||||
/Resources/Prototypes/Guidebook/rules.yml @nikthechampiongr @crazybrain23
|
/Resources/Prototypes/Guidebook/rules.yml @Chief-Engineer
|
||||||
/Content.*/Body/ @DrSmugleaf
|
/Content.*/Body/ @DrSmugleaf
|
||||||
/Content.YAMLLinter @DrSmugleaf
|
/Content.YAMLLinter @DrSmugleaf
|
||||||
/Content.Shared/Damage/ @DrSmugleaf
|
/Content.Shared/Damage/ @DrSmugleaf
|
||||||
|
|
||||||
/Content.*/Anomaly/ @TheShuEd
|
/Content.*/Anomaly/ @EmoGarbage404 @TheShuEd
|
||||||
/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml @TheShuEd
|
/Content.*/Lathe/ @EmoGarbage404
|
||||||
|
/Content.*/Materials/ @EmoGarbage404
|
||||||
|
/Content.*/Mech/ @EmoGarbage404
|
||||||
|
/Content.*/Research/ @EmoGarbage404
|
||||||
|
/Content.*/Stack/ @EmoGarbage404
|
||||||
|
/Content.*/Xenoarchaeology/ @EmoGarbage404
|
||||||
|
/Content.*/Zombies/ @EmoGarbage404
|
||||||
|
/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml @EmoGarbage404 @TheShuEd
|
||||||
|
/Resources/Prototypes/Research/ @EmoGarbage404
|
||||||
|
|
||||||
/Content.*/Forensics/ @ficcialfaint
|
/Content.*/Forensics/ @ficcialfaint
|
||||||
|
|
||||||
# SKREEEE
|
# SKREEEE
|
||||||
/Content.*.Database/ @PJB3005 @DrSmugleaf
|
/Content.*.Database/ @PJB3005 @DrSmugleaf
|
||||||
/Content.Shared.Database/Log*.cs @PJB3005 @DrSmugleaf @nikthechampiongr @crazybrain23
|
/Content.Shared.Database/Log*.cs @PJB3005 @DrSmugleaf @Chief-Engineer
|
||||||
/Pow3r/ @PJB3005
|
/Pow3r/ @PJB3005
|
||||||
/Content.Server/Power/Pow3r/ @PJB3005
|
/Content.Server/Power/Pow3r/ @PJB3005
|
||||||
|
|
||||||
@@ -33,7 +52,7 @@
|
|||||||
/Content.*/Atmos/ @Partmedia
|
/Content.*/Atmos/ @Partmedia
|
||||||
/Content.*/Botany/ @Partmedia
|
/Content.*/Botany/ @Partmedia
|
||||||
|
|
||||||
# Jezi
|
#Jezi
|
||||||
/Content.*/Medical @Jezithyr
|
/Content.*/Medical @Jezithyr
|
||||||
/Content.*/Body @Jezithyr
|
/Content.*/Body @Jezithyr
|
||||||
|
|
||||||
|
|||||||
4
.github/labeler.yml
vendored
4
.github/labeler.yml
vendored
@@ -16,10 +16,6 @@
|
|||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: '**/*.swsl'
|
- any-glob-to-any-file: '**/*.swsl'
|
||||||
|
|
||||||
"Changes: Audio":
|
|
||||||
- changed-files:
|
|
||||||
- any-glob-to-any-file: '**/*.ogg'
|
|
||||||
|
|
||||||
"Changes: No C#":
|
"Changes: No C#":
|
||||||
- changed-files:
|
- 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.
|
# Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label.
|
||||||
|
|||||||
4
.github/workflows/build-map-renderer.yml
vendored
4
.github/workflows/build-map-renderer.yml
vendored
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, staging, stable ]
|
branches: [ master, staging, trying ]
|
||||||
merge_group:
|
merge_group:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [ opened, reopened, synchronize, ready_for_review ]
|
types: [ opened, reopened, synchronize, ready_for_review ]
|
||||||
branches: [ master, staging, stable ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
4
.github/workflows/build-test-debug.yml
vendored
4
.github/workflows/build-test-debug.yml
vendored
@@ -2,11 +2,11 @@ name: Build & Test Debug
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, staging, stable ]
|
branches: [ master, staging, trying ]
|
||||||
merge_group:
|
merge_group:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [ opened, reopened, synchronize, ready_for_review ]
|
types: [ opened, reopened, synchronize, ready_for_review ]
|
||||||
branches: [ master, staging, stable ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
2
.github/workflows/labeler-review.yml
vendored
2
.github/workflows/labeler-review.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
team: "content-maintainers,junior-maintainers"
|
team: "content-maintainers,junior-maintainers"
|
||||||
GITHUB_TOKEN: ${{ secrets.LABELER_PAT }}
|
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
|
||||||
- if: ${{ steps.checkUserMember.outputs.isTeamMember == 'true' }}
|
- if: ${{ steps.checkUserMember.outputs.isTeamMember == 'true' }}
|
||||||
uses: actions-ecosystem/action-add-labels@v1
|
uses: actions-ecosystem/action-add-labels@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
6
.github/workflows/labeler-size.yml
vendored
6
.github/workflows/labeler-size.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
{
|
{
|
||||||
"0": "XS",
|
"0": "XS",
|
||||||
"10": "S",
|
"10": "S",
|
||||||
"100": "M",
|
"30": "M",
|
||||||
"1000": "L",
|
"100": "L",
|
||||||
"5000": "XL"
|
"1000": "XL"
|
||||||
}
|
}
|
||||||
|
|||||||
4
.github/workflows/test-packaging.yml
vendored
4
.github/workflows/test-packaging.yml
vendored
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, staging, stable ]
|
branches: [ master, staging, trying ]
|
||||||
paths:
|
paths:
|
||||||
- '**.cs'
|
- '**.cs'
|
||||||
- '**.csproj'
|
- '**.csproj'
|
||||||
@@ -16,7 +16,7 @@ on:
|
|||||||
merge_group:
|
merge_group:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [ opened, reopened, synchronize, ready_for_review ]
|
types: [ opened, reopened, synchronize, ready_for_review ]
|
||||||
branches: [ master, staging, stable ]
|
branches: [ master ]
|
||||||
paths:
|
paths:
|
||||||
- '**.cs'
|
- '**.cs'
|
||||||
- '**.csproj'
|
- '**.csproj'
|
||||||
|
|||||||
2
.github/workflows/validate-rgas.yml
vendored
2
.github/workflows/validate-rgas.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
name: RGA schema validator
|
name: RGA schema validator
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, staging, stable ]
|
branches: [ master, staging, trying ]
|
||||||
merge_group:
|
merge_group:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [ opened, reopened, synchronize, ready_for_review ]
|
types: [ opened, reopened, synchronize, ready_for_review ]
|
||||||
|
|||||||
2
.github/workflows/validate-rsis.yml
vendored
2
.github/workflows/validate-rsis.yml
vendored
@@ -2,7 +2,7 @@ name: RSI Validator
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, staging, stable ]
|
branches: [ staging, trying ]
|
||||||
merge_group:
|
merge_group:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
|
|||||||
2
.github/workflows/validate_mapfiles.yml
vendored
2
.github/workflows/validate_mapfiles.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
name: Map file schema validator
|
name: Map file schema validator
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, staging, stable ]
|
branches: [ master, staging, trying ]
|
||||||
merge_group:
|
merge_group:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [ opened, reopened, synchronize, ready_for_review ]
|
types: [ opened, reopened, synchronize, ready_for_review ]
|
||||||
|
|||||||
2
.github/workflows/yaml-linter.yml
vendored
2
.github/workflows/yaml-linter.yml
vendored
@@ -2,7 +2,7 @@ name: YAML Linter
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master, staging, stable ]
|
branches: [ master, staging, trying ]
|
||||||
merge_group:
|
merge_group:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [ opened, reopened, synchronize, ready_for_review ]
|
types: [ opened, reopened, synchronize, ready_for_review ]
|
||||||
|
|||||||
@@ -258,13 +258,13 @@ namespace Content.Client.Actions
|
|||||||
|
|
||||||
public void LinkAllActions(ActionsComponent? actions = null)
|
public void LinkAllActions(ActionsComponent? actions = null)
|
||||||
{
|
{
|
||||||
if (_playerManager.LocalEntity is not { } user ||
|
if (_playerManager.LocalEntity is not { } user ||
|
||||||
!Resolve(user, ref actions, false))
|
!Resolve(user, ref actions, false))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkActions?.Invoke(actions);
|
LinkActions?.Invoke(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
|
|||||||
@@ -159,7 +159,6 @@ public sealed partial class NoteEdit : FancyWindow
|
|||||||
SecretCheckBox.Pressed = false;
|
SecretCheckBox.Pressed = false;
|
||||||
SeverityOption.Disabled = false;
|
SeverityOption.Disabled = false;
|
||||||
PermanentCheckBox.Pressed = true;
|
PermanentCheckBox.Pressed = true;
|
||||||
SubmitButton.Disabled = true;
|
|
||||||
UpdatePermanentCheckboxFields();
|
UpdatePermanentCheckboxFields();
|
||||||
break;
|
break;
|
||||||
case (int) NoteType.Message: // Message: these are shown to the player when they log on
|
case (int) NoteType.Message: // Message: these are shown to the player when they log on
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Components;
|
namespace Content.Client.Atmos.Components;
|
||||||
|
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed partial class PipeColorVisualsComponent : Component;
|
public sealed partial class PipeColorVisualsComponent : Component
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<BoxContainer xmlns="https://spacestation14.io"
|
<BoxContainer xmlns="https://spacestation14.io"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
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:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
Orientation="Vertical" HorizontalExpand ="True" Margin="0 0 0 3">
|
Orientation="Vertical" HorizontalExpand ="True" Margin="0 0 0 3">
|
||||||
@@ -61,7 +62,7 @@
|
|||||||
</PanelContainer>
|
</PanelContainer>
|
||||||
</BoxContainer>
|
</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>
|
<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 -->
|
<!-- Silencing progress bar -->
|
||||||
|
|||||||
@@ -31,6 +31,19 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
|
|||||||
[AtmosAlarmType.Danger] = "atmos-alerts-window-danger-state",
|
[AtmosAlarmType.Danger] = "atmos-alerts-window-danger-state",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private Dictionary<Gas, string> _gasShorthands = new Dictionary<Gas, string>()
|
||||||
|
{
|
||||||
|
[Gas.Ammonia] = "NH₃",
|
||||||
|
[Gas.CarbonDioxide] = "CO₂",
|
||||||
|
[Gas.Frezon] = "F",
|
||||||
|
[Gas.Nitrogen] = "N₂",
|
||||||
|
[Gas.NitrousOxide] = "N₂O",
|
||||||
|
[Gas.Oxygen] = "O₂",
|
||||||
|
[Gas.Plasma] = "P",
|
||||||
|
[Gas.Tritium] = "T",
|
||||||
|
[Gas.WaterVapor] = "H₂O",
|
||||||
|
};
|
||||||
|
|
||||||
public AtmosAlarmEntryContainer(NetEntity uid, EntityCoordinates? coordinates)
|
public AtmosAlarmEntryContainer(NetEntity uid, EntityCoordinates? coordinates)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
@@ -123,9 +136,8 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
|
|||||||
GasGridContainer.RemoveAllChildren();
|
GasGridContainer.RemoveAllChildren();
|
||||||
|
|
||||||
var gasData = focusData.Value.GasData.Where(g => g.Key != Gas.Oxygen);
|
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
|
// No other gases
|
||||||
var gasLabel = new Label()
|
var gasLabel = new Label()
|
||||||
@@ -146,14 +158,17 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Add an entry for each gas
|
// 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;
|
||||||
var gasAbbreviation = Atmospherics.GasAbbreviations.GetValueOrDefault(gas, Loc.GetString("gas-unknown-abbreviation"));
|
gasPercent = percent * 100f;
|
||||||
|
|
||||||
|
if (!_gasShorthands.TryGetValue(gas, out var gasShorthand))
|
||||||
|
gasShorthand = "X";
|
||||||
|
|
||||||
var gasLabel = new Label()
|
var gasLabel = new Label()
|
||||||
{
|
{
|
||||||
Text = Loc.GetString("atmos-alerts-window-other-gases-value", ("shorthand", gasAbbreviation), ("value", gasPercent)),
|
Text = Loc.GetString("atmos-alerts-window-other-gases-value", ("shorthand", gasShorthand), ("value", gasPercent)),
|
||||||
FontOverride = normalFont,
|
FontOverride = normalFont,
|
||||||
FontColorOverride = GetAlarmStateColor(alert),
|
FontColorOverride = GetAlarmStateColor(alert),
|
||||||
HorizontalAlignment = HAlignment.Center,
|
HorizontalAlignment = HAlignment.Center,
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ public sealed class AtmosAlertsComputerBoundUserInterface : BoundUserInterface
|
|||||||
_menu = new AtmosAlertsComputerWindow(this, Owner);
|
_menu = new AtmosAlertsComputerWindow(this, Owner);
|
||||||
_menu.OpenCentered();
|
_menu.OpenCentered();
|
||||||
_menu.OnClose += Close;
|
_menu.OnClose += Close;
|
||||||
|
|
||||||
|
EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState(BoundUserInterfaceState state)
|
protected override void UpdateState(BoundUserInterfaceState state)
|
||||||
@@ -22,6 +24,9 @@ public sealed class AtmosAlertsComputerBoundUserInterface : BoundUserInterface
|
|||||||
|
|
||||||
var castState = (AtmosAlertsComputerBoundInterfaceState) state;
|
var castState = (AtmosAlertsComputerBoundInterfaceState) state;
|
||||||
|
|
||||||
|
if (castState == null)
|
||||||
|
return;
|
||||||
|
|
||||||
EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
|
EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
|
||||||
_menu?.UpdateUI(xform?.Coordinates, castState.AirAlarms, castState.FireAlarms, castState.FocusData);
|
_menu?.UpdateUI(xform?.Coordinates, castState.AirAlarms, castState.FireAlarms, castState.FocusData);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:ui="clr-namespace:Content.Client.Pinpointer.UI"
|
xmlns:ui="clr-namespace:Content.Client.Pinpointer.UI"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
|
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||||
Title="{Loc 'atmos-alerts-window-title'}"
|
Title="{Loc 'atmos-alerts-window-title'}"
|
||||||
Resizable="False"
|
Resizable="False"
|
||||||
SetSize="1120 750"
|
SetSize="1120 750"
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
using Content.Shared.Atmos.Components;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Consoles;
|
|
||||||
|
|
||||||
public sealed class AtmosMonitoringConsoleBoundUserInterface : BoundUserInterface
|
|
||||||
{
|
|
||||||
[ViewVariables]
|
|
||||||
private AtmosMonitoringConsoleWindow? _menu;
|
|
||||||
|
|
||||||
public AtmosMonitoringConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { }
|
|
||||||
|
|
||||||
protected override void Open()
|
|
||||||
{
|
|
||||||
base.Open();
|
|
||||||
|
|
||||||
_menu = new AtmosMonitoringConsoleWindow(this, Owner);
|
|
||||||
_menu.OpenCentered();
|
|
||||||
_menu.OnClose += Close;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateState(BoundUserInterfaceState state)
|
|
||||||
{
|
|
||||||
base.UpdateState(state);
|
|
||||||
|
|
||||||
if (state is not AtmosMonitoringConsoleBoundInterfaceState castState)
|
|
||||||
return;
|
|
||||||
|
|
||||||
EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
|
|
||||||
_menu?.UpdateUI(xform?.Coordinates, castState.AtmosNetworks);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
base.Dispose(disposing);
|
|
||||||
if (!disposing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_menu?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,295 +0,0 @@
|
|||||||
using Content.Client.Pinpointer.UI;
|
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Pinpointer;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Shared.Collections;
|
|
||||||
using Robust.Shared.Map.Components;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Numerics;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Consoles;
|
|
||||||
|
|
||||||
public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
|
||||||
|
|
||||||
public bool ShowPipeNetwork = true;
|
|
||||||
public int? FocusNetId = null;
|
|
||||||
|
|
||||||
private const int ChunkSize = 4;
|
|
||||||
|
|
||||||
private readonly Color _basePipeNetColor = Color.LightGray;
|
|
||||||
private readonly Color _unfocusedPipeNetColor = Color.DimGray;
|
|
||||||
|
|
||||||
private List<AtmosMonitoringConsoleLine> _atmosPipeNetwork = new();
|
|
||||||
private Dictionary<Color, Color> _sRGBLookUp = new Dictionary<Color, Color>();
|
|
||||||
|
|
||||||
// Look up tables for merging continuous lines. Indexed by line color
|
|
||||||
private Dictionary<Color, Dictionary<Vector2i, Vector2i>> _horizLines = new();
|
|
||||||
private Dictionary<Color, Dictionary<Vector2i, Vector2i>> _horizLinesReversed = new();
|
|
||||||
private Dictionary<Color, Dictionary<Vector2i, Vector2i>> _vertLines = new();
|
|
||||||
private Dictionary<Color, Dictionary<Vector2i, Vector2i>> _vertLinesReversed = new();
|
|
||||||
|
|
||||||
public AtmosMonitoringConsoleNavMapControl() : base()
|
|
||||||
{
|
|
||||||
PostWallDrawingAction += DrawAllPipeNetworks;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateNavMap()
|
|
||||||
{
|
|
||||||
base.UpdateNavMap();
|
|
||||||
|
|
||||||
if (!_entManager.TryGetComponent<AtmosMonitoringConsoleComponent>(Owner, out var console))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!_entManager.TryGetComponent<MapGridComponent>(MapUid, out var grid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_atmosPipeNetwork = GetDecodedAtmosPipeChunks(console.AtmosPipeChunks, grid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawAllPipeNetworks(DrawingHandleScreen handle)
|
|
||||||
{
|
|
||||||
if (!ShowPipeNetwork)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Draw networks
|
|
||||||
if (_atmosPipeNetwork != null && _atmosPipeNetwork.Any())
|
|
||||||
DrawPipeNetwork(handle, _atmosPipeNetwork);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawPipeNetwork(DrawingHandleScreen handle, List<AtmosMonitoringConsoleLine> atmosPipeNetwork)
|
|
||||||
{
|
|
||||||
var offset = GetOffset();
|
|
||||||
offset = offset with { Y = -offset.Y };
|
|
||||||
|
|
||||||
if (WorldRange / WorldMaxRange > 0.5f)
|
|
||||||
{
|
|
||||||
var pipeNetworks = new Dictionary<Color, ValueList<Vector2>>();
|
|
||||||
|
|
||||||
foreach (var chunkedLine in atmosPipeNetwork)
|
|
||||||
{
|
|
||||||
var start = ScalePosition(chunkedLine.Origin - offset);
|
|
||||||
var end = ScalePosition(chunkedLine.Terminus - offset);
|
|
||||||
|
|
||||||
if (!pipeNetworks.TryGetValue(chunkedLine.Color, out var subNetwork))
|
|
||||||
subNetwork = new ValueList<Vector2>();
|
|
||||||
|
|
||||||
subNetwork.Add(start);
|
|
||||||
subNetwork.Add(end);
|
|
||||||
|
|
||||||
pipeNetworks[chunkedLine.Color] = subNetwork;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ((var color, var subNetwork) in pipeNetworks)
|
|
||||||
{
|
|
||||||
if (subNetwork.Count > 0)
|
|
||||||
handle.DrawPrimitives(DrawPrimitiveTopology.LineList, subNetwork.Span, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var pipeVertexUVs = new Dictionary<Color, ValueList<Vector2>>();
|
|
||||||
|
|
||||||
foreach (var chunkedLine in atmosPipeNetwork)
|
|
||||||
{
|
|
||||||
var leftTop = ScalePosition(new Vector2
|
|
||||||
(Math.Min(chunkedLine.Origin.X, chunkedLine.Terminus.X) - 0.1f,
|
|
||||||
Math.Min(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) - 0.1f)
|
|
||||||
- offset);
|
|
||||||
|
|
||||||
var rightTop = ScalePosition(new Vector2
|
|
||||||
(Math.Max(chunkedLine.Origin.X, chunkedLine.Terminus.X) + 0.1f,
|
|
||||||
Math.Min(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) - 0.1f)
|
|
||||||
- offset);
|
|
||||||
|
|
||||||
var leftBottom = ScalePosition(new Vector2
|
|
||||||
(Math.Min(chunkedLine.Origin.X, chunkedLine.Terminus.X) - 0.1f,
|
|
||||||
Math.Max(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) + 0.1f)
|
|
||||||
- offset);
|
|
||||||
|
|
||||||
var rightBottom = ScalePosition(new Vector2
|
|
||||||
(Math.Max(chunkedLine.Origin.X, chunkedLine.Terminus.X) + 0.1f,
|
|
||||||
Math.Max(chunkedLine.Origin.Y, chunkedLine.Terminus.Y) + 0.1f)
|
|
||||||
- offset);
|
|
||||||
|
|
||||||
if (!pipeVertexUVs.TryGetValue(chunkedLine.Color, out var pipeVertexUV))
|
|
||||||
pipeVertexUV = new ValueList<Vector2>();
|
|
||||||
|
|
||||||
pipeVertexUV.Add(leftBottom);
|
|
||||||
pipeVertexUV.Add(leftTop);
|
|
||||||
pipeVertexUV.Add(rightBottom);
|
|
||||||
pipeVertexUV.Add(leftTop);
|
|
||||||
pipeVertexUV.Add(rightBottom);
|
|
||||||
pipeVertexUV.Add(rightTop);
|
|
||||||
|
|
||||||
pipeVertexUVs[chunkedLine.Color] = pipeVertexUV;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ((var color, var pipeVertexUV) in pipeVertexUVs)
|
|
||||||
{
|
|
||||||
if (pipeVertexUV.Count > 0)
|
|
||||||
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleList, pipeVertexUV.Span, color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<AtmosMonitoringConsoleLine> GetDecodedAtmosPipeChunks(Dictionary<Vector2i, AtmosPipeChunk>? chunks, MapGridComponent? grid)
|
|
||||||
{
|
|
||||||
var decodedOutput = new List<AtmosMonitoringConsoleLine>();
|
|
||||||
|
|
||||||
if (chunks == null || grid == null)
|
|
||||||
return decodedOutput;
|
|
||||||
|
|
||||||
// Clear stale look up table values
|
|
||||||
_horizLines.Clear();
|
|
||||||
_horizLinesReversed.Clear();
|
|
||||||
_vertLines.Clear();
|
|
||||||
_vertLinesReversed.Clear();
|
|
||||||
|
|
||||||
// Generate masks
|
|
||||||
var northMask = (ulong)1 << 0;
|
|
||||||
var southMask = (ulong)1 << 1;
|
|
||||||
var westMask = (ulong)1 << 2;
|
|
||||||
var eastMask = (ulong)1 << 3;
|
|
||||||
|
|
||||||
foreach ((var chunkOrigin, var chunk) in chunks)
|
|
||||||
{
|
|
||||||
var list = new List<AtmosMonitoringConsoleLine>();
|
|
||||||
|
|
||||||
foreach (var ((netId, hexColor), atmosPipeData) in chunk.AtmosPipeData)
|
|
||||||
{
|
|
||||||
// Determine the correct coloration for the pipe
|
|
||||||
var color = Color.FromHex(hexColor) * _basePipeNetColor;
|
|
||||||
|
|
||||||
if (FocusNetId != null && FocusNetId != netId)
|
|
||||||
color *= _unfocusedPipeNetColor;
|
|
||||||
|
|
||||||
// Get the associated line look up tables
|
|
||||||
if (!_horizLines.TryGetValue(color, out var horizLines))
|
|
||||||
{
|
|
||||||
horizLines = new();
|
|
||||||
_horizLines[color] = horizLines;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_horizLinesReversed.TryGetValue(color, out var horizLinesReversed))
|
|
||||||
{
|
|
||||||
horizLinesReversed = new();
|
|
||||||
_horizLinesReversed[color] = horizLinesReversed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_vertLines.TryGetValue(color, out var vertLines))
|
|
||||||
{
|
|
||||||
vertLines = new();
|
|
||||||
_vertLines[color] = vertLines;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_vertLinesReversed.TryGetValue(color, out var vertLinesReversed))
|
|
||||||
{
|
|
||||||
vertLinesReversed = new();
|
|
||||||
_vertLinesReversed[color] = vertLinesReversed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop over the chunk
|
|
||||||
for (var tileIdx = 0; tileIdx < ChunkSize * ChunkSize; tileIdx++)
|
|
||||||
{
|
|
||||||
if (atmosPipeData == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var mask = (ulong)SharedNavMapSystem.AllDirMask << tileIdx * SharedNavMapSystem.Directions;
|
|
||||||
|
|
||||||
if ((atmosPipeData & mask) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var relativeTile = GetTileFromIndex(tileIdx);
|
|
||||||
var tile = (chunk.Origin * ChunkSize + relativeTile) * grid.TileSize;
|
|
||||||
tile = tile with { Y = -tile.Y };
|
|
||||||
|
|
||||||
// Calculate the draw point offsets
|
|
||||||
var vertLineOrigin = (atmosPipeData & northMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
|
|
||||||
new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 1f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);
|
|
||||||
|
|
||||||
var vertLineTerminus = (atmosPipeData & southMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
|
|
||||||
new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);
|
|
||||||
|
|
||||||
var horizLineOrigin = (atmosPipeData & eastMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
|
|
||||||
new Vector2(grid.TileSize * 1f, -grid.TileSize * 0.5f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);
|
|
||||||
|
|
||||||
var horizLineTerminus = (atmosPipeData & westMask << tileIdx * SharedNavMapSystem.Directions) > 0 ?
|
|
||||||
new Vector2(grid.TileSize * 0f, -grid.TileSize * 0.5f) : new Vector2(grid.TileSize * 0.5f, -grid.TileSize * 0.5f);
|
|
||||||
|
|
||||||
// Since we can have pipe lines that have a length of a half tile,
|
|
||||||
// double the vectors and convert to vector2i so we can merge them
|
|
||||||
AddOrUpdateNavMapLine(ConvertVector2ToVector2i(tile + horizLineOrigin, 2), ConvertVector2ToVector2i(tile + horizLineTerminus, 2), horizLines, horizLinesReversed);
|
|
||||||
AddOrUpdateNavMapLine(ConvertVector2ToVector2i(tile + vertLineOrigin, 2), ConvertVector2ToVector2i(tile + vertLineTerminus, 2), vertLines, vertLinesReversed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scale the vector2is back down and convert to vector2
|
|
||||||
foreach (var (color, horizLines) in _horizLines)
|
|
||||||
{
|
|
||||||
// Get the corresponding sRBG color
|
|
||||||
var sRGB = GetsRGBColor(color);
|
|
||||||
|
|
||||||
foreach (var (origin, terminal) in horizLines)
|
|
||||||
decodedOutput.Add(new AtmosMonitoringConsoleLine
|
|
||||||
(ConvertVector2iToVector2(origin, 0.5f), ConvertVector2iToVector2(terminal, 0.5f), sRGB));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (color, vertLines) in _vertLines)
|
|
||||||
{
|
|
||||||
// Get the corresponding sRBG color
|
|
||||||
var sRGB = GetsRGBColor(color);
|
|
||||||
|
|
||||||
foreach (var (origin, terminal) in vertLines)
|
|
||||||
decodedOutput.Add(new AtmosMonitoringConsoleLine
|
|
||||||
(ConvertVector2iToVector2(origin, 0.5f), ConvertVector2iToVector2(terminal, 0.5f), sRGB));
|
|
||||||
}
|
|
||||||
|
|
||||||
return decodedOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vector2 ConvertVector2iToVector2(Vector2i vector, float scale = 1f)
|
|
||||||
{
|
|
||||||
return new Vector2(vector.X * scale, vector.Y * scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vector2i ConvertVector2ToVector2i(Vector2 vector, float scale = 1f)
|
|
||||||
{
|
|
||||||
return new Vector2i((int)MathF.Round(vector.X * scale), (int)MathF.Round(vector.Y * scale));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vector2i GetTileFromIndex(int index)
|
|
||||||
{
|
|
||||||
var x = index / ChunkSize;
|
|
||||||
var y = index % ChunkSize;
|
|
||||||
return new Vector2i(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color GetsRGBColor(Color color)
|
|
||||||
{
|
|
||||||
if (!_sRGBLookUp.TryGetValue(color, out var sRGB))
|
|
||||||
{
|
|
||||||
sRGB = Color.ToSrgb(color);
|
|
||||||
_sRGBLookUp[color] = sRGB;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sRGB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct AtmosMonitoringConsoleLine
|
|
||||||
{
|
|
||||||
public readonly Vector2 Origin;
|
|
||||||
public readonly Vector2 Terminus;
|
|
||||||
public readonly Color Color;
|
|
||||||
|
|
||||||
public AtmosMonitoringConsoleLine(Vector2 origin, Vector2 terminus, Color color)
|
|
||||||
{
|
|
||||||
Origin = origin;
|
|
||||||
Terminus = terminus;
|
|
||||||
Color = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Atmos.Consoles;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Consoles;
|
|
||||||
|
|
||||||
public sealed class AtmosMonitoringConsoleSystem : SharedAtmosMonitoringConsoleSystem
|
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<AtmosMonitoringConsoleComponent, ComponentHandleState>(OnHandleState);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHandleState(EntityUid uid, AtmosMonitoringConsoleComponent component, ref ComponentHandleState args)
|
|
||||||
{
|
|
||||||
Dictionary<Vector2i, Dictionary<(int, string), ulong>> modifiedChunks;
|
|
||||||
Dictionary<NetEntity, AtmosDeviceNavMapData> atmosDevices;
|
|
||||||
|
|
||||||
switch (args.Current)
|
|
||||||
{
|
|
||||||
case AtmosMonitoringConsoleDeltaState delta:
|
|
||||||
{
|
|
||||||
modifiedChunks = delta.ModifiedChunks;
|
|
||||||
atmosDevices = delta.AtmosDevices;
|
|
||||||
|
|
||||||
foreach (var index in component.AtmosPipeChunks.Keys)
|
|
||||||
{
|
|
||||||
if (!delta.AllChunks!.Contains(index))
|
|
||||||
component.AtmosPipeChunks.Remove(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case AtmosMonitoringConsoleState state:
|
|
||||||
{
|
|
||||||
modifiedChunks = state.Chunks;
|
|
||||||
atmosDevices = state.AtmosDevices;
|
|
||||||
|
|
||||||
foreach (var index in component.AtmosPipeChunks.Keys)
|
|
||||||
{
|
|
||||||
if (!state.Chunks.ContainsKey(index))
|
|
||||||
component.AtmosPipeChunks.Remove(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (origin, chunk) in modifiedChunks)
|
|
||||||
{
|
|
||||||
var newChunk = new AtmosPipeChunk(origin);
|
|
||||||
newChunk.AtmosPipeData = new Dictionary<(int, string), ulong>(chunk);
|
|
||||||
|
|
||||||
component.AtmosPipeChunks[origin] = newChunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
component.AtmosDevices.Clear();
|
|
||||||
|
|
||||||
foreach (var (nuid, atmosDevice) in atmosDevices)
|
|
||||||
{
|
|
||||||
component.AtmosDevices[nuid] = atmosDevice;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
|
||||||
xmlns:ui="clr-namespace:Content.Client.Atmos.Consoles"
|
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
|
||||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
|
||||||
Title="{Loc 'atmos-monitoring-window-title'}"
|
|
||||||
Resizable="False"
|
|
||||||
SetSize="1120 750"
|
|
||||||
MinSize="1120 750">
|
|
||||||
<BoxContainer Orientation="Vertical">
|
|
||||||
<!-- Main display -->
|
|
||||||
<BoxContainer Orientation="Horizontal" VerticalExpand="True" HorizontalExpand="True">
|
|
||||||
<!-- Nav map -->
|
|
||||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
|
|
||||||
<ui:AtmosMonitoringConsoleNavMapControl Name="NavMap" Margin="5 5" VerticalExpand="True" HorizontalExpand="True">
|
|
||||||
|
|
||||||
<!-- System warning -->
|
|
||||||
<PanelContainer Name="SystemWarningPanel"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
HorizontalExpand="True"
|
|
||||||
Margin="0 48 0 0"
|
|
||||||
Visible="False">
|
|
||||||
<RichTextLabel Name="SystemWarningLabel" Margin="12 8 12 8"/>
|
|
||||||
</PanelContainer>
|
|
||||||
|
|
||||||
</ui:AtmosMonitoringConsoleNavMapControl>
|
|
||||||
|
|
||||||
<!-- Nav map legend -->
|
|
||||||
<BoxContainer Orientation="Horizontal" Margin="0 10 0 10">
|
|
||||||
<TextureRect Stretch="KeepAspectCentered"
|
|
||||||
TexturePath="/Textures/Interface/NavMap/beveled_square.png"
|
|
||||||
Modulate="#a9a9a9"
|
|
||||||
SetSize="16 16"
|
|
||||||
Margin="20 0 5 0"/>
|
|
||||||
<Label Text="{Loc 'atmos-monitoring-window-label-gas-opening'}"/>
|
|
||||||
<TextureRect Stretch="KeepAspectCentered"
|
|
||||||
TexturePath="/Textures/Interface/NavMap/beveled_circle.png"
|
|
||||||
SetSize="16 16"
|
|
||||||
Modulate="#a9a9a9"
|
|
||||||
Margin="20 0 5 0"/>
|
|
||||||
<Label Text="{Loc 'atmos-monitoring-window-label-gas-scrubber'}"/>
|
|
||||||
<TextureRect Stretch="KeepAspectCentered"
|
|
||||||
TexturePath="/Textures/Interface/NavMap/beveled_arrow_east.png"
|
|
||||||
SetSize="16 16"
|
|
||||||
Modulate="#a9a9a9"
|
|
||||||
Margin="20 0 5 0"/>
|
|
||||||
<Label Text="{Loc 'atmos-monitoring-window-label-gas-flow-regulator'}"/>
|
|
||||||
<TextureRect Stretch="KeepAspectCentered"
|
|
||||||
TexturePath="/Textures/Interface/NavMap/beveled_hexagon.png"
|
|
||||||
SetSize="16 16"
|
|
||||||
Modulate="#a9a9a9"
|
|
||||||
Margin="20 0 5 0"/>
|
|
||||||
<Label Text="{Loc 'atmos-monitoring-window-label-thermoregulator'}"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Atmosphere status -->
|
|
||||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" SetWidth="440" Margin="0 0 10 10">
|
|
||||||
|
|
||||||
<!-- Station name -->
|
|
||||||
<controls:StripeBack>
|
|
||||||
<PanelContainer>
|
|
||||||
<RichTextLabel Name="StationName" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0 5 0 3"/>
|
|
||||||
</PanelContainer>
|
|
||||||
</controls:StripeBack>
|
|
||||||
|
|
||||||
<!-- Alarm status (entries added by C# code) -->
|
|
||||||
<TabContainer Name="MasterTabContainer" VerticalExpand="True" HorizontalExpand="True" Margin="0 10 0 0">
|
|
||||||
<ScrollContainer HorizontalExpand="True" Margin="8, 8, 8, 8">
|
|
||||||
<BoxContainer Name="AtmosNetworksTable" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True" Margin="0 0 0 10"/>
|
|
||||||
</ScrollContainer>
|
|
||||||
</TabContainer>
|
|
||||||
|
|
||||||
<!-- Overlay toggles -->
|
|
||||||
<BoxContainer Orientation="Vertical" Margin="0 10 0 0">
|
|
||||||
<Label Text="{Loc 'atmos-monitoring-window-toggle-overlays'}" Margin="0 0 0 5"/>
|
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
|
||||||
<CheckBox Name="ShowPipeNetwork" Text="{Loc 'atmos-monitoring-window-show-pipe-network'}" Pressed="True" HorizontalExpand="True"/>
|
|
||||||
<CheckBox Name="ShowGasPipeSensors" Text="{Loc 'atmos-monitoring-window-show-gas-pipe-sensors'}" Pressed="False" HorizontalExpand="True"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Footer -->
|
|
||||||
<BoxContainer Orientation="Vertical">
|
|
||||||
<PanelContainer StyleClasses="LowDivider" />
|
|
||||||
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
|
|
||||||
<Label Text="{Loc 'atmos-monitoring-window-flavor-left'}" StyleClasses="WindowFooterText" />
|
|
||||||
<Label Text="{Loc 'atmos-monitoring-window-flavor-right'}" StyleClasses="WindowFooterText"
|
|
||||||
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
|
|
||||||
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered"
|
|
||||||
VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</controls:FancyWindow>
|
|
||||||
@@ -1,455 +0,0 @@
|
|||||||
using Content.Client.Pinpointer.UI;
|
|
||||||
using Content.Client.UserInterface.Controls;
|
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Prototypes;
|
|
||||||
using Robust.Client.AutoGenerated;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.UserInterface;
|
|
||||||
using Robust.Client.UserInterface.Controls;
|
|
||||||
using Robust.Client.UserInterface.XAML;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Consoles;
|
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
|
||||||
public sealed partial class AtmosMonitoringConsoleWindow : FancyWindow
|
|
||||||
{
|
|
||||||
private readonly IEntityManager _entManager;
|
|
||||||
private readonly IPrototypeManager _protoManager;
|
|
||||||
private readonly SpriteSystem _spriteSystem;
|
|
||||||
|
|
||||||
private EntityUid? _owner;
|
|
||||||
private NetEntity? _focusEntity;
|
|
||||||
private int? _focusNetId;
|
|
||||||
|
|
||||||
private bool _autoScrollActive = false;
|
|
||||||
|
|
||||||
private readonly Color _unfocusedDeviceColor = Color.DimGray;
|
|
||||||
private ProtoId<NavMapBlipPrototype> _navMapConsoleProtoId = "NavMapConsole";
|
|
||||||
private ProtoId<NavMapBlipPrototype> _gasPipeSensorProtoId = "GasPipeSensor";
|
|
||||||
|
|
||||||
public AtmosMonitoringConsoleWindow(AtmosMonitoringConsoleBoundUserInterface userInterface, EntityUid? owner)
|
|
||||||
{
|
|
||||||
RobustXamlLoader.Load(this);
|
|
||||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
|
||||||
_protoManager = IoCManager.Resolve<IPrototypeManager>();
|
|
||||||
_spriteSystem = _entManager.System<SpriteSystem>();
|
|
||||||
|
|
||||||
// Pass the owner to nav map
|
|
||||||
_owner = owner;
|
|
||||||
NavMap.Owner = _owner;
|
|
||||||
|
|
||||||
// Set nav map grid uid
|
|
||||||
var stationName = Loc.GetString("atmos-monitoring-window-unknown-location");
|
|
||||||
EntityCoordinates? consoleCoords = null;
|
|
||||||
|
|
||||||
if (_entManager.TryGetComponent<TransformComponent>(owner, out var xform))
|
|
||||||
{
|
|
||||||
consoleCoords = xform.Coordinates;
|
|
||||||
NavMap.MapUid = xform.GridUid;
|
|
||||||
|
|
||||||
// Assign station name
|
|
||||||
if (_entManager.TryGetComponent<MetaDataComponent>(xform.GridUid, out var stationMetaData))
|
|
||||||
stationName = stationMetaData.EntityName;
|
|
||||||
|
|
||||||
var msg = new FormattedMessage();
|
|
||||||
msg.TryAddMarkup(Loc.GetString("atmos-monitoring-window-station-name", ("stationName", stationName)), out _);
|
|
||||||
|
|
||||||
StationName.SetMessage(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
StationName.SetMessage(stationName);
|
|
||||||
NavMap.Visible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set trackable entity selected action
|
|
||||||
NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap;
|
|
||||||
|
|
||||||
// Update nav map
|
|
||||||
NavMap.ForceNavMapUpdate();
|
|
||||||
|
|
||||||
// Set tab container headers
|
|
||||||
MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-monitoring-window-tab-networks"));
|
|
||||||
|
|
||||||
// Set UI toggles
|
|
||||||
ShowPipeNetwork.OnToggled += _ => OnShowPipeNetworkToggled();
|
|
||||||
ShowGasPipeSensors.OnToggled += _ => OnShowGasPipeSensors();
|
|
||||||
|
|
||||||
// Set nav map colors
|
|
||||||
if (!_entManager.TryGetComponent<AtmosMonitoringConsoleComponent>(_owner, out var console))
|
|
||||||
return;
|
|
||||||
|
|
||||||
NavMap.TileColor = console.NavMapTileColor;
|
|
||||||
NavMap.WallColor = console.NavMapWallColor;
|
|
||||||
|
|
||||||
// Initalize
|
|
||||||
UpdateUI(consoleCoords, Array.Empty<AtmosMonitoringConsoleEntry>());
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Toggle handling
|
|
||||||
|
|
||||||
private void OnShowPipeNetworkToggled()
|
|
||||||
{
|
|
||||||
if (_owner == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!_entManager.TryGetComponent<AtmosMonitoringConsoleComponent>(_owner.Value, out var console))
|
|
||||||
return;
|
|
||||||
|
|
||||||
NavMap.ShowPipeNetwork = ShowPipeNetwork.Pressed;
|
|
||||||
|
|
||||||
foreach (var (netEnt, device) in console.AtmosDevices)
|
|
||||||
{
|
|
||||||
if (device.NavMapBlip == _gasPipeSensorProtoId)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ShowPipeNetwork.Pressed)
|
|
||||||
AddTrackedEntityToNavMap(device);
|
|
||||||
|
|
||||||
else
|
|
||||||
NavMap.TrackedEntities.Remove(netEnt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnShowGasPipeSensors()
|
|
||||||
{
|
|
||||||
if (_owner == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!_entManager.TryGetComponent<AtmosMonitoringConsoleComponent>(_owner.Value, out var console))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var (netEnt, device) in console.AtmosDevices)
|
|
||||||
{
|
|
||||||
if (device.NavMapBlip != _gasPipeSensorProtoId)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ShowGasPipeSensors.Pressed)
|
|
||||||
AddTrackedEntityToNavMap(device, true);
|
|
||||||
|
|
||||||
else
|
|
||||||
NavMap.TrackedEntities.Remove(netEnt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public void UpdateUI
|
|
||||||
(EntityCoordinates? consoleCoords,
|
|
||||||
AtmosMonitoringConsoleEntry[] atmosNetworks)
|
|
||||||
{
|
|
||||||
if (_owner == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!_entManager.TryGetComponent<AtmosMonitoringConsoleComponent>(_owner.Value, out var console))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Reset nav map values
|
|
||||||
NavMap.TrackedCoordinates.Clear();
|
|
||||||
NavMap.TrackedEntities.Clear();
|
|
||||||
|
|
||||||
if (_focusEntity != null && !console.AtmosDevices.Any(x => x.Key == _focusEntity))
|
|
||||||
ClearFocus();
|
|
||||||
|
|
||||||
// Add tracked entities to the nav map
|
|
||||||
UpdateNavMapBlips();
|
|
||||||
|
|
||||||
// Show the monitor location
|
|
||||||
var consoleNetEnt = _entManager.GetNetEntity(_owner);
|
|
||||||
|
|
||||||
if (consoleCoords != null && consoleNetEnt != null)
|
|
||||||
{
|
|
||||||
var proto = _protoManager.Index(_navMapConsoleProtoId);
|
|
||||||
|
|
||||||
if (proto.TexturePaths != null && proto.TexturePaths.Length != 0)
|
|
||||||
{
|
|
||||||
var texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(proto.TexturePaths[0]));
|
|
||||||
var blip = new NavMapBlip(consoleCoords.Value, texture, proto.Color, proto.Blinks, proto.Selectable);
|
|
||||||
NavMap.TrackedEntities[consoleNetEnt.Value] = blip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the nav map
|
|
||||||
NavMap.ForceNavMapUpdate();
|
|
||||||
|
|
||||||
// Clear excess children from the tables
|
|
||||||
while (AtmosNetworksTable.ChildCount > atmosNetworks.Length)
|
|
||||||
AtmosNetworksTable.RemoveChild(AtmosNetworksTable.GetChild(AtmosNetworksTable.ChildCount - 1));
|
|
||||||
|
|
||||||
// Update all entries in each table
|
|
||||||
for (int index = 0; index < atmosNetworks.Length; index++)
|
|
||||||
{
|
|
||||||
var entry = atmosNetworks.ElementAt(index);
|
|
||||||
UpdateUIEntry(entry, index, AtmosNetworksTable, console);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateNavMapBlips()
|
|
||||||
{
|
|
||||||
if (_owner == null || !_entManager.TryGetComponent<AtmosMonitoringConsoleComponent>(_owner.Value, out var console))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (NavMap.Visible)
|
|
||||||
{
|
|
||||||
foreach (var (netEnt, device) in console.AtmosDevices)
|
|
||||||
{
|
|
||||||
// Update the focus network ID, incase it has changed
|
|
||||||
if (_focusEntity == netEnt)
|
|
||||||
{
|
|
||||||
_focusNetId = device.NetId;
|
|
||||||
NavMap.FocusNetId = _focusNetId;
|
|
||||||
}
|
|
||||||
|
|
||||||
var isSensor = device.NavMapBlip == _gasPipeSensorProtoId;
|
|
||||||
|
|
||||||
// Skip network devices if the toggled is off
|
|
||||||
if (!ShowPipeNetwork.Pressed && !isSensor)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Skip gas pipe sensors if the toggle is off
|
|
||||||
if (!ShowGasPipeSensors.Pressed && isSensor)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
AddTrackedEntityToNavMap(device, isSensor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddTrackedEntityToNavMap(AtmosDeviceNavMapData metaData, bool isSensor = false)
|
|
||||||
{
|
|
||||||
var proto = _protoManager.Index(metaData.NavMapBlip);
|
|
||||||
|
|
||||||
if (proto.TexturePaths == null || proto.TexturePaths.Length == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var idx = Math.Clamp((int)metaData.Direction / 2, 0, proto.TexturePaths.Length - 1);
|
|
||||||
var texture = proto.TexturePaths.Length > 0 ? proto.TexturePaths[idx] : proto.TexturePaths[0];
|
|
||||||
var color = isSensor ? proto.Color : proto.Color * metaData.PipeColor;
|
|
||||||
|
|
||||||
if (_focusNetId != null && metaData.NetId != _focusNetId)
|
|
||||||
color *= _unfocusedDeviceColor;
|
|
||||||
|
|
||||||
var blinks = proto.Blinks || _focusEntity == metaData.NetEntity;
|
|
||||||
var coords = _entManager.GetCoordinates(metaData.NetCoordinates);
|
|
||||||
var blip = new NavMapBlip(coords, _spriteSystem.Frame0(new SpriteSpecifier.Texture(texture)), color, blinks, proto.Selectable, proto.Scale);
|
|
||||||
NavMap.TrackedEntities[metaData.NetEntity] = blip;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateUIEntry(AtmosMonitoringConsoleEntry data, int index, Control table, AtmosMonitoringConsoleComponent console)
|
|
||||||
{
|
|
||||||
// Make new UI entry if required
|
|
||||||
if (index >= table.ChildCount)
|
|
||||||
{
|
|
||||||
var newEntryContainer = new AtmosMonitoringEntryContainer(data);
|
|
||||||
|
|
||||||
// On click
|
|
||||||
newEntryContainer.FocusButton.OnButtonUp += args =>
|
|
||||||
{
|
|
||||||
if (_focusEntity == newEntryContainer.Data.NetEntity)
|
|
||||||
{
|
|
||||||
ClearFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetFocus(newEntryContainer.Data.NetEntity, newEntryContainer.Data.NetId);
|
|
||||||
|
|
||||||
var coords = _entManager.GetCoordinates(newEntryContainer.Data.Coordinates);
|
|
||||||
NavMap.CenterToCoordinates(coords);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update affected UI elements across all tables
|
|
||||||
UpdateConsoleTable(console, AtmosNetworksTable, _focusEntity);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add the entry to the current table
|
|
||||||
table.AddChild(newEntryContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update values and UI elements
|
|
||||||
var tableChild = table.GetChild(index);
|
|
||||||
|
|
||||||
if (tableChild is not AtmosMonitoringEntryContainer)
|
|
||||||
{
|
|
||||||
table.RemoveChild(tableChild);
|
|
||||||
UpdateUIEntry(data, index, table, console);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var entryContainer = (AtmosMonitoringEntryContainer)tableChild;
|
|
||||||
entryContainer.UpdateEntry(data, data.NetEntity == _focusEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateConsoleTable(AtmosMonitoringConsoleComponent console, Control table, NetEntity? currTrackedEntity)
|
|
||||||
{
|
|
||||||
foreach (var tableChild in table.Children)
|
|
||||||
{
|
|
||||||
if (tableChild is not AtmosAlarmEntryContainer)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var entryContainer = (AtmosAlarmEntryContainer)tableChild;
|
|
||||||
|
|
||||||
if (entryContainer.NetEntity != currTrackedEntity)
|
|
||||||
entryContainer.RemoveAsFocus();
|
|
||||||
|
|
||||||
else if (entryContainer.NetEntity == currTrackedEntity)
|
|
||||||
entryContainer.SetAsFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetTrackedEntityFromNavMap(NetEntity? focusEntity)
|
|
||||||
{
|
|
||||||
if (focusEntity == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!_entManager.TryGetComponent<AtmosMonitoringConsoleComponent>(_owner, out var console))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var (netEnt, device) in console.AtmosDevices)
|
|
||||||
{
|
|
||||||
if (netEnt != focusEntity)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (device.NavMapBlip != _gasPipeSensorProtoId)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Set new focus
|
|
||||||
SetFocus(focusEntity.Value, device.NetId);
|
|
||||||
|
|
||||||
// Get the scroll position of the selected entity on the selected button the UI
|
|
||||||
ActivateAutoScrollToFocus();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
|
||||||
{
|
|
||||||
AutoScrollToFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ActivateAutoScrollToFocus()
|
|
||||||
{
|
|
||||||
_autoScrollActive = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AutoScrollToFocus()
|
|
||||||
{
|
|
||||||
if (!_autoScrollActive)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var scroll = AtmosNetworksTable.Parent as ScrollContainer;
|
|
||||||
if (scroll == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!TryGetVerticalScrollbar(scroll, out var vScrollbar))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!TryGetNextScrollPosition(out float? nextScrollPosition))
|
|
||||||
return;
|
|
||||||
|
|
||||||
vScrollbar.ValueTarget = nextScrollPosition.Value;
|
|
||||||
|
|
||||||
if (MathHelper.CloseToPercent(vScrollbar.Value, vScrollbar.ValueTarget))
|
|
||||||
_autoScrollActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryGetVerticalScrollbar(ScrollContainer scroll, [NotNullWhen(true)] out VScrollBar? vScrollBar)
|
|
||||||
{
|
|
||||||
vScrollBar = null;
|
|
||||||
|
|
||||||
foreach (var control in scroll.Children)
|
|
||||||
{
|
|
||||||
if (control is not VScrollBar)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
vScrollBar = (VScrollBar)control;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryGetNextScrollPosition([NotNullWhen(true)] out float? nextScrollPosition)
|
|
||||||
{
|
|
||||||
nextScrollPosition = null;
|
|
||||||
|
|
||||||
var scroll = AtmosNetworksTable.Parent as ScrollContainer;
|
|
||||||
if (scroll == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var container = scroll.Children.ElementAt(0) as BoxContainer;
|
|
||||||
if (container == null || container.Children.Count() == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Exit if the heights of the children haven't been initialized yet
|
|
||||||
if (!container.Children.Any(x => x.Height > 0))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
nextScrollPosition = 0;
|
|
||||||
|
|
||||||
foreach (var control in container.Children)
|
|
||||||
{
|
|
||||||
if (control is not AtmosMonitoringEntryContainer)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var entry = (AtmosMonitoringEntryContainer)control;
|
|
||||||
|
|
||||||
if (entry.Data.NetEntity == _focusEntity)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
nextScrollPosition += control.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failed to find control
|
|
||||||
nextScrollPosition = null;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetFocus(NetEntity focusEntity, int focusNetId)
|
|
||||||
{
|
|
||||||
_focusEntity = focusEntity;
|
|
||||||
_focusNetId = focusNetId;
|
|
||||||
NavMap.FocusNetId = focusNetId;
|
|
||||||
|
|
||||||
OnFocusChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearFocus()
|
|
||||||
{
|
|
||||||
_focusEntity = null;
|
|
||||||
_focusNetId = null;
|
|
||||||
NavMap.FocusNetId = null;
|
|
||||||
|
|
||||||
OnFocusChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnFocusChanged()
|
|
||||||
{
|
|
||||||
UpdateNavMapBlips();
|
|
||||||
NavMap.ForceNavMapUpdate();
|
|
||||||
|
|
||||||
if (!_entManager.TryGetComponent<AtmosMonitoringConsoleComponent>(_owner, out var console))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (int index = 0; index < AtmosNetworksTable.ChildCount; index++)
|
|
||||||
{
|
|
||||||
var entry = (AtmosMonitoringEntryContainer)AtmosNetworksTable.GetChild(index);
|
|
||||||
|
|
||||||
if (entry == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
UpdateUIEntry(entry.Data, index, AtmosNetworksTable, console);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
<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">
|
|
||||||
|
|
||||||
<!-- Network selection button -->
|
|
||||||
<Button Name="FocusButton" HorizontalExpand="True" VerticalExpand="True" Margin="0 0 6 8" StyleClasses="OpenLeft" Access="Public">
|
|
||||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
|
|
||||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Horizontal" SetHeight="32">
|
|
||||||
<PanelContainer Name="NetworkColorStripe" HorizontalAlignment="Left" SetWidth="8" VerticalExpand="True" Margin="-8 -2 0 0">
|
|
||||||
<PanelContainer.PanelOverride>
|
|
||||||
<gfx:StyleBoxFlat BackgroundColor="#d7d7d7"/>
|
|
||||||
</PanelContainer.PanelOverride>
|
|
||||||
</PanelContainer>
|
|
||||||
<Label Name="NetworkNameLabel" Text="???" HorizontalExpand="True" HorizontalAlignment="Center"/>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Panel that appears on selecting the device -->
|
|
||||||
|
|
||||||
<PanelContainer HorizontalExpand="True" Margin="-8 0 -14 -4" Access="Public">
|
|
||||||
<PanelContainer.PanelOverride>
|
|
||||||
<gfx:StyleBoxFlat BackgroundColor="#25252a"/>
|
|
||||||
</PanelContainer.PanelOverride>
|
|
||||||
<BoxContainer Name="MainDataContainer" HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
|
|
||||||
<Control>
|
|
||||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
|
|
||||||
<BoxContainer HorizontalExpand="True" Orientation="Horizontal">
|
|
||||||
<Label Name="TemperatureHeaderLabel" Text="{Loc 'atmos-alerts-window-temperature-label'}" HorizontalAlignment="Center" HorizontalExpand="True" FontColorOverride="#a9a9a9" Margin="0 2 0 0" SetHeight="24"></Label>
|
|
||||||
<Label Name="PressureHeaderLabel" Text="{Loc 'atmos-alerts-window-pressure-label'}" HorizontalAlignment="Center" HorizontalExpand="True" FontColorOverride="#a9a9a9" Margin="0 2 0 0" SetHeight="24"></Label>
|
|
||||||
<Label Name="TotalMolHeaderLabel" Text="{Loc 'atmos-alerts-window-total-mol-label'}" HorizontalAlignment="Center" HorizontalExpand="True" FontColorOverride="#a9a9a9" Margin="0 2 0 0" SetHeight="24"></Label>
|
|
||||||
</BoxContainer>
|
|
||||||
<PanelContainer HorizontalExpand="True">
|
|
||||||
<PanelContainer.PanelOverride>
|
|
||||||
<gfx:StyleBoxFlat BackgroundColor="#202023"/>
|
|
||||||
</PanelContainer.PanelOverride>
|
|
||||||
<BoxContainer HorizontalExpand="True" Orientation="Horizontal">
|
|
||||||
<Label Name="TemperatureLabel" Text="???" HorizontalAlignment="Center" HorizontalExpand="True" FontColorOverride="#a9a9a9" Margin="0 2 0 0" SetHeight="24"></Label>
|
|
||||||
<Label Name="PressureLabel" Text="???" HorizontalAlignment="Center" HorizontalExpand="True" FontColorOverride="#a9a9a9" Margin="0 2 0 0" SetHeight="24"></Label>
|
|
||||||
<Label Name="TotalMolLabel" Text="???" HorizontalAlignment="Center" HorizontalExpand="True" FontColorOverride="#a9a9a9" Margin="0 2 0 0" SetHeight="24"></Label>
|
|
||||||
</BoxContainer>
|
|
||||||
</PanelContainer>
|
|
||||||
<BoxContainer HorizontalExpand="True" Orientation="Horizontal" Margin="8 0">
|
|
||||||
<TextureRect Name="ArrowTexture" VerticalAlignment="Center" SetSize="12 12" Stretch="KeepAspectCentered" Margin="3 0" TexturePath="/Textures/Interface/Nano/triangle_right.png"></TextureRect>
|
|
||||||
<Label Name="GasesHeaderLabel" Text="{Loc 'atmos-monitoring-window-label-gases'}" HorizontalAlignment="Left" HorizontalExpand="True" FontColorOverride="#a9a9a9" Margin="4 0 0 0" SetHeight="24"></Label>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
</BoxContainer>
|
|
||||||
</Control>
|
|
||||||
|
|
||||||
<!-- Atmosphere status -->
|
|
||||||
<Control Name="FocusContainer" ReservesSpace="False" Visible="False">
|
|
||||||
<!-- Main container for displaying atmospheric data -->
|
|
||||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
|
|
||||||
<PanelContainer HorizontalExpand="True">
|
|
||||||
<PanelContainer.PanelOverride>
|
|
||||||
<gfx:StyleBoxFlat BackgroundColor="#202023"/>
|
|
||||||
</PanelContainer.PanelOverride>
|
|
||||||
|
|
||||||
<!-- Gas entries added via C# code -->
|
|
||||||
<GridContainer Name="GasGridContainer" HorizontalExpand="True" Columns = "4"></GridContainer>
|
|
||||||
</PanelContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</Control>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- If the alarm is inactive, this is label is displayed instead -->
|
|
||||||
<Label Name="NoDataLabel" Text="{Loc 'atmos-alerts-window-no-data-available'}" HorizontalAlignment="Center" Margin="0 15" FontColorOverride="#a9a9a9" ReservesSpace="False" Visible="False"></Label>
|
|
||||||
|
|
||||||
</PanelContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</Button>
|
|
||||||
</BoxContainer>
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
using Content.Client.Stylesheets;
|
|
||||||
using Content.Shared.Atmos;
|
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.FixedPoint;
|
|
||||||
using Content.Shared.Temperature;
|
|
||||||
using Robust.Client.AutoGenerated;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.ResourceManagement;
|
|
||||||
using Robust.Client.UserInterface.Controls;
|
|
||||||
using Robust.Client.UserInterface.XAML;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Consoles;
|
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
|
||||||
public sealed partial class AtmosMonitoringEntryContainer : BoxContainer
|
|
||||||
{
|
|
||||||
public AtmosMonitoringConsoleEntry Data;
|
|
||||||
|
|
||||||
private readonly IEntityManager _entManager;
|
|
||||||
private readonly IResourceCache _cache;
|
|
||||||
|
|
||||||
public AtmosMonitoringEntryContainer(AtmosMonitoringConsoleEntry data)
|
|
||||||
{
|
|
||||||
RobustXamlLoader.Load(this);
|
|
||||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
|
||||||
_cache = IoCManager.Resolve<IResourceCache>();
|
|
||||||
|
|
||||||
Data = data;
|
|
||||||
|
|
||||||
// Modulate colored stripe
|
|
||||||
NetworkColorStripe.Modulate = data.Color;
|
|
||||||
|
|
||||||
// Load fonts
|
|
||||||
var headerFont = new VectorFont(_cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Bold.ttf"), 11);
|
|
||||||
var normalFont = new VectorFont(_cache.GetResource<FontResource>("/Fonts/NotoSansDisplay/NotoSansDisplay-Regular.ttf"), 11);
|
|
||||||
|
|
||||||
// Set fonts
|
|
||||||
TemperatureHeaderLabel.FontOverride = headerFont;
|
|
||||||
PressureHeaderLabel.FontOverride = headerFont;
|
|
||||||
TotalMolHeaderLabel.FontOverride = headerFont;
|
|
||||||
GasesHeaderLabel.FontOverride = headerFont;
|
|
||||||
|
|
||||||
TemperatureLabel.FontOverride = normalFont;
|
|
||||||
PressureLabel.FontOverride = normalFont;
|
|
||||||
TotalMolLabel.FontOverride = normalFont;
|
|
||||||
|
|
||||||
NoDataLabel.FontOverride = headerFont;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateEntry(AtmosMonitoringConsoleEntry updatedData, bool isFocus)
|
|
||||||
{
|
|
||||||
// Load fonts
|
|
||||||
var normalFont = new VectorFont(_cache.GetResource<FontResource>("/Fonts/NotoSansDisplay/NotoSansDisplay-Regular.ttf"), 11);
|
|
||||||
|
|
||||||
// Update name and values
|
|
||||||
if (!string.IsNullOrEmpty(updatedData.Address))
|
|
||||||
NetworkNameLabel.Text = Loc.GetString("atmos-alerts-window-alarm-label", ("name", updatedData.EntityName), ("address", updatedData.Address));
|
|
||||||
|
|
||||||
else
|
|
||||||
NetworkNameLabel.Text = Loc.GetString(updatedData.EntityName);
|
|
||||||
|
|
||||||
Data = updatedData;
|
|
||||||
|
|
||||||
// Modulate colored stripe
|
|
||||||
NetworkColorStripe.Modulate = Data.Color;
|
|
||||||
|
|
||||||
// Focus updates
|
|
||||||
if (isFocus)
|
|
||||||
SetAsFocus();
|
|
||||||
else
|
|
||||||
RemoveAsFocus();
|
|
||||||
|
|
||||||
// Check if powered
|
|
||||||
if (!updatedData.IsPowered)
|
|
||||||
{
|
|
||||||
MainDataContainer.Visible = false;
|
|
||||||
NoDataLabel.Visible = true;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set container visibility
|
|
||||||
MainDataContainer.Visible = true;
|
|
||||||
NoDataLabel.Visible = false;
|
|
||||||
|
|
||||||
// Update temperature
|
|
||||||
var isNotVacuum = updatedData.TotalMolData > 1e-6f;
|
|
||||||
var tempK = (FixedPoint2)updatedData.TemperatureData;
|
|
||||||
var tempC = (FixedPoint2)TemperatureHelpers.KelvinToCelsius(tempK.Float());
|
|
||||||
|
|
||||||
TemperatureLabel.Text = isNotVacuum ?
|
|
||||||
Loc.GetString("atmos-alerts-window-temperature-value", ("valueInC", tempC), ("valueInK", tempK)) :
|
|
||||||
Loc.GetString("atmos-alerts-window-invalid-value");
|
|
||||||
|
|
||||||
TemperatureLabel.FontColorOverride = isNotVacuum ? Color.DarkGray : StyleNano.DisabledFore;
|
|
||||||
|
|
||||||
// Update pressure
|
|
||||||
PressureLabel.Text = Loc.GetString("atmos-alerts-window-pressure-value", ("value", (FixedPoint2)updatedData.PressureData));
|
|
||||||
PressureLabel.FontColorOverride = isNotVacuum ? Color.DarkGray : StyleNano.DisabledFore;
|
|
||||||
|
|
||||||
// Update total mol
|
|
||||||
TotalMolLabel.Text = Loc.GetString("atmos-alerts-window-total-mol-value", ("value", (FixedPoint2)updatedData.TotalMolData));
|
|
||||||
TotalMolLabel.FontColorOverride = isNotVacuum ? Color.DarkGray : StyleNano.DisabledFore;
|
|
||||||
|
|
||||||
// Update other present gases
|
|
||||||
GasGridContainer.RemoveAllChildren();
|
|
||||||
|
|
||||||
if (updatedData.GasData.Count() == 0)
|
|
||||||
{
|
|
||||||
// No gases
|
|
||||||
var gasLabel = new Label()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("atmos-alerts-window-other-gases-value-nil"),
|
|
||||||
FontOverride = normalFont,
|
|
||||||
FontColorOverride = StyleNano.DisabledFore,
|
|
||||||
HorizontalAlignment = HAlignment.Center,
|
|
||||||
VerticalAlignment = VAlignment.Center,
|
|
||||||
HorizontalExpand = true,
|
|
||||||
Margin = new Thickness(0, 2, 0, 0),
|
|
||||||
SetHeight = 24f,
|
|
||||||
};
|
|
||||||
|
|
||||||
GasGridContainer.AddChild(gasLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Add an entry for each gas
|
|
||||||
foreach (var (gas, percent) in updatedData.GasData)
|
|
||||||
{
|
|
||||||
var gasPercent = (FixedPoint2)0f;
|
|
||||||
gasPercent = percent * 100f;
|
|
||||||
|
|
||||||
var gasAbbreviation = Atmospherics.GasAbbreviations.GetValueOrDefault(gas, Loc.GetString("gas-unknown-abbreviation"));
|
|
||||||
|
|
||||||
var gasLabel = new Label()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("atmos-alerts-window-other-gases-value", ("shorthand", gasAbbreviation), ("value", gasPercent)),
|
|
||||||
FontOverride = normalFont,
|
|
||||||
HorizontalAlignment = HAlignment.Center,
|
|
||||||
VerticalAlignment = VAlignment.Center,
|
|
||||||
HorizontalExpand = true,
|
|
||||||
Margin = new Thickness(0, 2, 0, 0),
|
|
||||||
SetHeight = 24f,
|
|
||||||
};
|
|
||||||
|
|
||||||
GasGridContainer.AddChild(gasLabel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetAsFocus()
|
|
||||||
{
|
|
||||||
FocusButton.AddStyleClass(StyleNano.StyleClassButtonColorGreen);
|
|
||||||
ArrowTexture.TexturePath = "/Textures/Interface/Nano/inverted_triangle.svg.png";
|
|
||||||
FocusContainer.Visible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveAsFocus()
|
|
||||||
{
|
|
||||||
FocusButton.RemoveStyleClass(StyleNano.StyleClassButtonColorGreen);
|
|
||||||
ArrowTexture.TexturePath = "/Textures/Interface/Nano/triangle_right.png";
|
|
||||||
FocusContainer.Visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,6 +4,8 @@ using Content.Shared.Atmos.Components;
|
|||||||
using Content.Shared.Atmos.Piping;
|
using Content.Shared.Atmos.Piping;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.ResourceManagement;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.EntitySystems;
|
namespace Content.Client.Atmos.EntitySystems;
|
||||||
|
|
||||||
@@ -17,7 +19,7 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<PipeAppearanceComponent, ComponentInit>(OnInit);
|
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)
|
private void OnInit(EntityUid uid, PipeAppearanceComponent component, ComponentInit args)
|
||||||
@@ -82,8 +84,7 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
|
|||||||
|
|
||||||
layer.Visible &= visible;
|
layer.Visible &= visible;
|
||||||
|
|
||||||
if (!visible)
|
if (!visible) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
layer.Color = color;
|
layer.Color = color;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
using Content.Client.Atmos.UI;
|
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
|
||||||
using Content.Shared.Atmos.Piping.Binary.Components;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.EntitySystems;
|
|
||||||
|
|
||||||
public sealed class GasPressurePumpSystem : SharedGasPressurePumpSystem
|
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
SubscribeLocalEvent<GasPressurePumpComponent, AfterAutoHandleStateEvent>(OnPumpUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPumpUpdate(Entity<GasPressurePumpComponent> ent, ref AfterAutoHandleStateEvent args)
|
|
||||||
{
|
|
||||||
if (UserInterfaceSystem.TryGetOpenUi<GasPressurePumpBoundUserInterface>(ent.Owner, GasPressurePumpUiKey.Key, out var bui))
|
|
||||||
{
|
|
||||||
bui.Update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using Content.Shared.Atmos.Monitor;
|
using Content.Shared.Atmos.Monitor;
|
||||||
using Content.Shared.Power;
|
using Content.Shared.Power;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
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;
|
namespace Content.Client.Atmos.Monitor;
|
||||||
|
|
||||||
@@ -22,7 +27,7 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
|
|||||||
{
|
{
|
||||||
foreach (var visLayer in component.HideOnDepowered)
|
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);
|
args.Sprite.LayerSetVisible(powerVisibilityLayer, powered);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +36,7 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
|
|||||||
{
|
{
|
||||||
foreach (var (setLayer, powerState) in component.SetOnDepowered)
|
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));
|
args.Sprite.LayerSetState(setStateLayer, new RSI.StateId(powerState));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Monitor;
|
using Content.Shared.Atmos.Monitor;
|
||||||
using Content.Shared.Atmos.Monitor.Components;
|
using Content.Shared.Atmos.Monitor.Components;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Monitor.UI;
|
namespace Content.Client.Atmos.Monitor.UI;
|
||||||
|
|
||||||
@@ -74,7 +78,6 @@ public sealed class AirAlarmBoundUserInterface : BoundUserInterface
|
|||||||
{
|
{
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
|
|
||||||
if (disposing)
|
if (disposing) _window?.Dispose();
|
||||||
_window?.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Content.Shared.Atmos.Monitor.Components;
|
|||||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||||
using Content.Shared.Temperature;
|
using Content.Shared.Temperature;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
|||||||
AirAlarmMode.Fill => "air-alarm-ui-mode-fill",
|
AirAlarmMode.Fill => "air-alarm-ui-mode-fill",
|
||||||
AirAlarmMode.Panic => "air-alarm-ui-mode-panic",
|
AirAlarmMode.Panic => "air-alarm-ui-mode-panic",
|
||||||
AirAlarmMode.None => "air-alarm-ui-mode-none",
|
AirAlarmMode.None => "air-alarm-ui-mode-none",
|
||||||
_ => "error",
|
_ => "error"
|
||||||
};
|
};
|
||||||
_modes.AddItem(Loc.GetString(text));
|
_modes.AddItem(Loc.GetString(text));
|
||||||
}
|
}
|
||||||
@@ -69,7 +70,7 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
|||||||
AirAlarmModeChanged!.Invoke((AirAlarmMode) args.Id);
|
AirAlarmModeChanged!.Invoke((AirAlarmMode) args.Id);
|
||||||
};
|
};
|
||||||
|
|
||||||
_autoMode.OnToggled += _ =>
|
_autoMode.OnToggled += args =>
|
||||||
{
|
{
|
||||||
AutoModeChanged!.Invoke(_autoMode.Pressed);
|
AutoModeChanged!.Invoke(_autoMode.Pressed);
|
||||||
};
|
};
|
||||||
@@ -175,18 +176,22 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
|||||||
|
|
||||||
public static Color ColorForThreshold(float amount, AtmosAlarmThreshold threshold)
|
public static Color ColorForThreshold(float amount, AtmosAlarmThreshold threshold)
|
||||||
{
|
{
|
||||||
threshold.CheckThreshold(amount, out var curAlarm);
|
threshold.CheckThreshold(amount, out AtmosAlarmType curAlarm);
|
||||||
return ColorForAlarm(curAlarm);
|
return ColorForAlarm(curAlarm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Color ColorForAlarm(AtmosAlarmType curAlarm)
|
public static Color ColorForAlarm(AtmosAlarmType curAlarm)
|
||||||
{
|
{
|
||||||
return curAlarm switch
|
if(curAlarm == AtmosAlarmType.Danger)
|
||||||
{
|
{
|
||||||
AtmosAlarmType.Danger => StyleNano.DangerousRedFore,
|
return StyleNano.DangerousRedFore;
|
||||||
AtmosAlarmType.Warning => StyleNano.ConcerningOrangeFore,
|
}
|
||||||
_ => StyleNano.GoodGreenFore,
|
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.Monitor.Components;
|
||||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
||||||
|
|
||||||
@@ -21,7 +25,7 @@ public sealed partial class PumpControl : BoxContainer
|
|||||||
private OptionButton _pressureCheck => CPressureCheck;
|
private OptionButton _pressureCheck => CPressureCheck;
|
||||||
private FloatSpinBox _externalBound => CExternalBound;
|
private FloatSpinBox _externalBound => CExternalBound;
|
||||||
private FloatSpinBox _internalBound => CInternalBound;
|
private FloatSpinBox _internalBound => CInternalBound;
|
||||||
private Button _copySettings => CCopySettings;
|
private Button _copySettings => CCopySettings;
|
||||||
|
|
||||||
public PumpControl(GasVentPumpData data, string address)
|
public PumpControl(GasVentPumpData data, string address)
|
||||||
{
|
{
|
||||||
@@ -82,7 +86,7 @@ public sealed partial class PumpControl : BoxContainer
|
|||||||
_data.PressureChecks = (VentPressureBound) args.Id;
|
_data.PressureChecks = (VentPressureBound) args.Id;
|
||||||
PumpDataChanged?.Invoke(_address, _data);
|
PumpDataChanged?.Invoke(_address, _data);
|
||||||
};
|
};
|
||||||
|
|
||||||
_copySettings.OnPressed += _ =>
|
_copySettings.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
PumpDataCopied?.Invoke(_data);
|
PumpDataCopied?.Invoke(_data);
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Atmos.Monitor;
|
||||||
using Content.Shared.Atmos.Monitor.Components;
|
using Content.Shared.Atmos.Monitor.Components;
|
||||||
using Content.Shared.Atmos.Piping.Unary.Components;
|
using Content.Shared.Atmos.Piping.Unary.Components;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
namespace Content.Client.Atmos.Monitor.UI.Widgets;
|
||||||
|
|
||||||
@@ -21,7 +27,7 @@ public sealed partial class ScrubberControl : BoxContainer
|
|||||||
private OptionButton _pumpDirection => CPumpDirection;
|
private OptionButton _pumpDirection => CPumpDirection;
|
||||||
private FloatSpinBox _volumeRate => CVolumeRate;
|
private FloatSpinBox _volumeRate => CVolumeRate;
|
||||||
private CheckBox _wideNet => CWideNet;
|
private CheckBox _wideNet => CWideNet;
|
||||||
private Button _copySettings => CCopySettings;
|
private Button _copySettings => CCopySettings;
|
||||||
|
|
||||||
private GridContainer _gases => CGasContainer;
|
private GridContainer _gases => CGasContainer;
|
||||||
private Dictionary<Gas, Button> _gasControls = new();
|
private Dictionary<Gas, Button> _gasControls = new();
|
||||||
@@ -71,7 +77,7 @@ public sealed partial class ScrubberControl : BoxContainer
|
|||||||
_data.PumpDirection = (ScrubberPumpDirection) args.Id;
|
_data.PumpDirection = (ScrubberPumpDirection) args.Id;
|
||||||
ScrubberDataChanged?.Invoke(_address, _data);
|
ScrubberDataChanged?.Invoke(_address, _data);
|
||||||
};
|
};
|
||||||
|
|
||||||
_copySettings.OnPressed += _ =>
|
_copySettings.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
ScrubberDataCopied?.Invoke(_data);
|
ScrubberDataCopied?.Invoke(_data);
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ public sealed partial class SensorInfo : BoxContainer
|
|||||||
var label = new RichTextLabel();
|
var label = new RichTextLabel();
|
||||||
|
|
||||||
var fractionGas = amount / data.TotalMoles;
|
var fractionGas = amount / data.TotalMoles;
|
||||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
|
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator", ("gas", $"{gas}"),
|
||||||
("gas", $"{gas}"),
|
|
||||||
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
||||||
("amount", $"{amount:0.####}"),
|
("amount", $"{amount:0.####}"),
|
||||||
("percentage", $"{(100 * fractionGas):0.##}")));
|
("percentage", $"{(100 * fractionGas):0.##}")));
|
||||||
@@ -54,9 +53,9 @@ public sealed partial class SensorInfo : BoxContainer
|
|||||||
var threshold = data.GasThresholds[gas];
|
var threshold = data.GasThresholds[gas];
|
||||||
var gasThresholdControl = new ThresholdControl(Loc.GetString($"air-alarm-ui-thresholds-gas-title", ("gas", $"{gas}")), threshold, AtmosMonitorThresholdType.Gas, gas, 100);
|
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.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);
|
_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);
|
_pressureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-pressure-title"), data.PressureThreshold, AtmosMonitorThresholdType.Pressure);
|
||||||
PressureThresholdContainer.AddChild(_pressureThreshold);
|
PressureThresholdContainer.AddChild(_pressureThreshold);
|
||||||
_temperatureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-temperature-title"),
|
_temperatureThreshold = new ThresholdControl(Loc.GetString("air-alarm-ui-thresholds-temperature-title"), data.TemperatureThreshold,
|
||||||
data.TemperatureThreshold,
|
|
||||||
AtmosMonitorThresholdType.Temperature);
|
AtmosMonitorThresholdType.Temperature);
|
||||||
TemperatureThresholdContainer.AddChild(_temperatureThreshold);
|
TemperatureThresholdContainer.AddChild(_temperatureThreshold);
|
||||||
|
|
||||||
@@ -105,8 +103,7 @@ public sealed partial class SensorInfo : BoxContainer
|
|||||||
}
|
}
|
||||||
|
|
||||||
var fractionGas = amount / data.TotalMoles;
|
var fractionGas = amount / data.TotalMoles;
|
||||||
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
|
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator", ("gas", $"{gas}"),
|
||||||
("gas", $"{gas}"),
|
|
||||||
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
|
||||||
("amount", $"{amount:0.####}"),
|
("amount", $"{amount:0.####}"),
|
||||||
("percentage", $"{(100 * fractionGas):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.Atmos.Monitor;
|
||||||
|
using Content.Shared.Temperature;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
using System;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Monitor;
|
using Content.Shared.Atmos.Monitor;
|
||||||
|
using Content.Shared.Atmos.Monitor.Components;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
|
||||||
// holy FUCK
|
// holy FUCK
|
||||||
// this technically works because some of this you can *not* do in XAML but 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;
|
_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}");
|
return Loc.GetString($"air-alarm-ui-thresholds-{boundType}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateThresholdData(AtmosAlarmThreshold threshold, float currentAmount)
|
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 upperDangerState = AtmosAlarmType.Normal;
|
||||||
var lowerDangerState = AtmosAlarmType.Normal;
|
var lowerDangerState = AtmosAlarmType.Normal;
|
||||||
var upperWarningState = AtmosAlarmType.Normal;
|
var upperWarningState = AtmosAlarmType.Normal;
|
||||||
var lowerWarningState = AtmosAlarmType.Normal;
|
var lowerWarningState = AtmosAlarmType.Normal;
|
||||||
|
|
||||||
switch (alarm)
|
if(alarm == AtmosAlarmType.Danger)
|
||||||
{
|
{
|
||||||
case AtmosAlarmType.Danger:
|
if(which == AtmosMonitorThresholdBound.Upper) upperDangerState = alarm;
|
||||||
{
|
else lowerDangerState = alarm;
|
||||||
if (bound == AtmosMonitorThresholdBound.Upper)
|
}
|
||||||
upperDangerState = alarm;
|
else if(alarm == AtmosAlarmType.Warning)
|
||||||
else
|
{
|
||||||
lowerDangerState = alarm;
|
if(which == AtmosMonitorThresholdBound.Upper) upperWarningState = alarm;
|
||||||
break;
|
else lowerWarningState = alarm;
|
||||||
}
|
|
||||||
case AtmosAlarmType.Warning:
|
|
||||||
{
|
|
||||||
if (bound == AtmosMonitorThresholdBound.Upper)
|
|
||||||
upperWarningState = alarm;
|
|
||||||
else
|
|
||||||
lowerWarningState = alarm;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_upperBoundControl.SetValue(threshold.UpperBound.Value);
|
_upperBoundControl.SetValue(threshold.UpperBound.Value);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Client.Atmos.EntitySystems;
|
using Content.Client.Atmos.EntitySystems;
|
||||||
@@ -102,9 +101,14 @@ public sealed class AtmosDebugOverlay : Overlay
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Red-Green-Blue interpolation
|
// Red-Green-Blue interpolation
|
||||||
res = interp < 0.5f
|
if (interp < 0.5f)
|
||||||
? Color.InterpolateBetween(Color.Red, Color.LimeGreen, interp * 2)
|
{
|
||||||
: Color.InterpolateBetween(Color.LimeGreen, Color.Blue, (interp - 0.5f) * 2);
|
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);
|
res = res.WithAlpha(0.75f);
|
||||||
@@ -177,10 +181,7 @@ public sealed class AtmosDebugOverlay : Overlay
|
|||||||
handle.DrawCircle(tileCentre, 0.05f, Color.Black);
|
handle.DrawCircle(tileCentre, 0.05f, Color.Black);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckAndShowBlockDir(
|
private void CheckAndShowBlockDir(AtmosDebugOverlayData data, DrawingHandleWorld handle, AtmosDirection dir,
|
||||||
AtmosDebugOverlayData data,
|
|
||||||
DrawingHandleWorld handle,
|
|
||||||
AtmosDirection dir,
|
|
||||||
Vector2 tileCentre)
|
Vector2 tileCentre)
|
||||||
{
|
{
|
||||||
if (!data.BlockDirection.HasFlag(dir))
|
if (!data.BlockDirection.HasFlag(dir))
|
||||||
@@ -242,7 +243,7 @@ public sealed class AtmosDebugOverlay : Overlay
|
|||||||
|
|
||||||
var moles = data.Moles == null
|
var moles = data.Moles == null
|
||||||
? "No Air"
|
? "No Air"
|
||||||
: data.Moles.Sum().ToString(CultureInfo.InvariantCulture);
|
: data.Moles.Sum().ToString();
|
||||||
|
|
||||||
handle.DrawString(_font, pos, $"Moles: {moles}");
|
handle.DrawString(_font, pos, $"Moles: {moles}");
|
||||||
pos += offset;
|
pos += offset;
|
||||||
@@ -262,12 +263,7 @@ public sealed class AtmosDebugOverlay : Overlay
|
|||||||
private void GetGrids(MapId mapId, Box2Rotated box)
|
private void GetGrids(MapId mapId, Box2Rotated box)
|
||||||
{
|
{
|
||||||
_grids.Clear();
|
_grids.Clear();
|
||||||
_mapManager.FindGridsIntersecting(
|
_mapManager.FindGridsIntersecting(mapId, box, ref _grids, (EntityUid uid, MapGridComponent grid,
|
||||||
mapId,
|
|
||||||
box,
|
|
||||||
ref _grids,
|
|
||||||
(EntityUid uid,
|
|
||||||
MapGridComponent grid,
|
|
||||||
ref List<(Entity<MapGridComponent>, DebugMessage)> state) =>
|
ref List<(Entity<MapGridComponent>, DebugMessage)> state) =>
|
||||||
{
|
{
|
||||||
if (_system.TileData.TryGetValue(uid, out var data))
|
if (_system.TileData.TryGetValue(uid, out var data))
|
||||||
|
|||||||
@@ -1,63 +1,65 @@
|
|||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Atmos.Piping.Binary.Components;
|
using Content.Shared.Atmos.Piping.Binary.Components;
|
||||||
using Content.Shared.IdentityManagement;
|
|
||||||
using Content.Shared.Localizations;
|
using Content.Shared.Localizations;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.UI;
|
namespace Content.Client.Atmos.UI
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a <see cref="GasPressurePumpWindow"/> and updates it when new server messages are received.
|
|
||||||
/// </summary>
|
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed class GasPressurePumpBoundUserInterface : BoundUserInterface
|
|
||||||
{
|
{
|
||||||
[ViewVariables]
|
/// <summary>
|
||||||
private const float MaxPressure = Atmospherics.MaxOutputPressure;
|
/// Initializes a <see cref="GasPressurePumpWindow"/> and updates it when new server messages are received.
|
||||||
|
/// </summary>
|
||||||
[ViewVariables]
|
[UsedImplicitly]
|
||||||
private GasPressurePumpWindow? _window;
|
public sealed class GasPressurePumpBoundUserInterface : BoundUserInterface
|
||||||
|
|
||||||
public GasPressurePumpBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
|
||||||
{
|
{
|
||||||
}
|
[ViewVariables]
|
||||||
|
private const float MaxPressure = Atmospherics.MaxOutputPressure;
|
||||||
|
|
||||||
protected override void Open()
|
[ViewVariables]
|
||||||
{
|
private GasPressurePumpWindow? _window;
|
||||||
base.Open();
|
|
||||||
|
|
||||||
_window = this.CreateWindow<GasPressurePumpWindow>();
|
public GasPressurePumpBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
_window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
|
protected override void Open()
|
||||||
_window.PumpOutputPressureChanged += OnPumpOutputPressurePressed;
|
{
|
||||||
Update();
|
base.Open();
|
||||||
}
|
|
||||||
|
|
||||||
public void Update()
|
_window = this.CreateWindow<GasPressurePumpWindow>();
|
||||||
{
|
|
||||||
if (_window == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_window.Title = Identity.Name(Owner, EntMan);
|
_window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
|
||||||
|
_window.PumpOutputPressureChanged += OnPumpOutputPressurePressed;
|
||||||
|
}
|
||||||
|
|
||||||
if (!EntMan.TryGetComponent(Owner, out GasPressurePumpComponent? pump))
|
private void OnToggleStatusButtonPressed()
|
||||||
return;
|
{
|
||||||
|
if (_window is null) return;
|
||||||
|
SendMessage(new GasPressurePumpToggleStatusMessage(_window.PumpStatus));
|
||||||
|
}
|
||||||
|
|
||||||
_window.SetPumpStatus(pump.Enabled);
|
private void OnPumpOutputPressurePressed(string value)
|
||||||
_window.MaxPressure = pump.MaxTargetPressure;
|
{
|
||||||
_window.SetOutputPressure(pump.TargetPressure);
|
var pressure = UserInputParser.TryFloat(value, out var parsed) ? parsed : 0f;
|
||||||
}
|
if (pressure > MaxPressure) pressure = MaxPressure;
|
||||||
|
|
||||||
private void OnToggleStatusButtonPressed()
|
SendMessage(new GasPressurePumpChangeOutputPressureMessage(pressure));
|
||||||
{
|
}
|
||||||
if (_window is null) return;
|
|
||||||
SendPredictedMessage(new GasPressurePumpToggleStatusMessage(_window.PumpStatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPumpOutputPressurePressed(float value)
|
/// <summary>
|
||||||
{
|
/// Update the UI state based on server-sent info
|
||||||
SendPredictedMessage(new GasPressurePumpChangeOutputPressureMessage(value));
|
/// </summary>
|
||||||
|
/// <param name="state"></param>
|
||||||
|
protected override void UpdateState(BoundUserInterfaceState state)
|
||||||
|
{
|
||||||
|
base.UpdateState(state);
|
||||||
|
if (_window == null || state is not GasPressurePumpBoundUserInterfaceState cast)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_window.Title = (cast.PumpLabel);
|
||||||
|
_window.SetPumpStatus(cast.Enabled);
|
||||||
|
_window.SetOutputPressure(cast.OutputPressure);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
MinSize="200 120" Title="Pressure Pump">
|
||||||
SetSize="340 110" MinSize="340 110" Title="Pressure Pump">
|
|
||||||
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
<Label Text="{Loc comp-gas-pump-ui-pump-status}" Margin="0 0 5 0"/>
|
<Label Text="{Loc comp-gas-pump-ui-pump-status}"/>
|
||||||
|
<Control MinSize="5 0" />
|
||||||
<Button Name="ToggleStatusButton"/>
|
<Button Name="ToggleStatusButton"/>
|
||||||
<Control HorizontalExpand="True"/>
|
|
||||||
<Button HorizontalAlignment="Right" Name="SetOutputPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-rate}" Disabled="True" Margin="0 0 5 0"/>
|
|
||||||
<Button Name="SetMaxPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-max}" />
|
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
<Label Text="{Loc comp-gas-pump-ui-pump-output-pressure}"/>
|
<Label Text="{Loc comp-gas-pump-ui-pump-output-pressure}"/>
|
||||||
<FloatSpinBox HorizontalExpand="True" Name="PumpPressureOutputInput" MinSize="70 0" />
|
<Control MinSize="5 0" />
|
||||||
|
<LineEdit Name="PumpPressureOutputInput" MinSize="70 0" />
|
||||||
|
<Control MinSize="5 0" />
|
||||||
|
<Button Name="SetMaxPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-max}" />
|
||||||
|
<Control MinSize="5 0" />
|
||||||
|
<Control HorizontalExpand="True" />
|
||||||
|
<Button Name="SetOutputPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-rate}" HorizontalAlignment="Right" Disabled="True"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</controls:FancyWindow>
|
</DefaultWindow>
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
using Content.Client.UserInterface.Controls;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using Content.Client.Atmos.EntitySystems;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Atmos.Prototypes;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.UI
|
namespace Content.Client.Atmos.UI
|
||||||
{
|
{
|
||||||
@@ -10,25 +16,12 @@ namespace Content.Client.Atmos.UI
|
|||||||
/// Client-side UI used to control a gas pressure pump.
|
/// Client-side UI used to control a gas pressure pump.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class GasPressurePumpWindow : FancyWindow
|
public sealed partial class GasPressurePumpWindow : DefaultWindow
|
||||||
{
|
{
|
||||||
public bool PumpStatus = true;
|
public bool PumpStatus = true;
|
||||||
|
|
||||||
public event Action? ToggleStatusButtonPressed;
|
public event Action? ToggleStatusButtonPressed;
|
||||||
public event Action<float>? PumpOutputPressureChanged;
|
public event Action<string>? PumpOutputPressureChanged;
|
||||||
|
|
||||||
public float MaxPressure
|
|
||||||
{
|
|
||||||
get => _maxPressure;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_maxPressure = value;
|
|
||||||
|
|
||||||
PumpPressureOutputInput.Value = MathF.Min(value, PumpPressureOutputInput.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float _maxPressure = Atmospherics.MaxOutputPressure;
|
|
||||||
|
|
||||||
public GasPressurePumpWindow()
|
public GasPressurePumpWindow()
|
||||||
{
|
{
|
||||||
@@ -37,25 +30,23 @@ namespace Content.Client.Atmos.UI
|
|||||||
ToggleStatusButton.OnPressed += _ => SetPumpStatus(!PumpStatus);
|
ToggleStatusButton.OnPressed += _ => SetPumpStatus(!PumpStatus);
|
||||||
ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();
|
ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();
|
||||||
|
|
||||||
PumpPressureOutputInput.OnValueChanged += _ => SetOutputPressureButton.Disabled = false;
|
PumpPressureOutputInput.OnTextChanged += _ => SetOutputPressureButton.Disabled = false;
|
||||||
|
|
||||||
SetOutputPressureButton.OnPressed += _ =>
|
SetOutputPressureButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
PumpPressureOutputInput.Value = Math.Clamp(PumpPressureOutputInput.Value, 0f, _maxPressure);
|
PumpOutputPressureChanged?.Invoke(PumpPressureOutputInput.Text ??= "");
|
||||||
PumpOutputPressureChanged?.Invoke(PumpPressureOutputInput.Value);
|
|
||||||
SetOutputPressureButton.Disabled = true;
|
SetOutputPressureButton.Disabled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
SetMaxPressureButton.OnPressed += _ =>
|
SetMaxPressureButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
PumpPressureOutputInput.Value = _maxPressure;
|
PumpPressureOutputInput.Text = Atmospherics.MaxOutputPressure.ToString(CultureInfo.CurrentCulture);
|
||||||
SetOutputPressureButton.Disabled = false;
|
SetOutputPressureButton.Disabled = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetOutputPressure(float pressure)
|
public void SetOutputPressure(float pressure)
|
||||||
{
|
{
|
||||||
PumpPressureOutputInput.Value = pressure;
|
PumpPressureOutputInput.Text = pressure.ToString(CultureInfo.CurrentCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPumpStatus(bool enabled)
|
public void SetPumpStatus(bool enabled)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System.Numerics;
|
|||||||
using Content.Client.Chat.Managers;
|
using Content.Client.Chat.Managers;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
using Content.Shared.Speech;
|
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
@@ -142,12 +141,7 @@ namespace Content.Client.Chat.UI
|
|||||||
Modulate = Color.White;
|
Modulate = Color.White;
|
||||||
}
|
}
|
||||||
|
|
||||||
var baseOffset = 0f;
|
var offset = (-_eyeManager.CurrentEye.Rotation).ToWorldVec() * -EntityVerticalOffset;
|
||||||
|
|
||||||
if (_entityManager.TryGetComponent<SpeechComponent>(_senderEntity, out var speech))
|
|
||||||
baseOffset = speech.SpeechBubbleOffset;
|
|
||||||
|
|
||||||
var offset = (-_eyeManager.CurrentEye.Rotation).ToWorldVec() * -(EntityVerticalOffset + baseOffset);
|
|
||||||
var worldPos = _transformSystem.GetWorldPosition(xform) + offset;
|
var worldPos = _transformSystem.GetWorldPosition(xform) + offset;
|
||||||
|
|
||||||
var lowerCenter = _eyeManager.WorldToScreen(worldPos) / UIScale;
|
var lowerCenter = _eyeManager.WorldToScreen(worldPos) / UIScale;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ using Robust.Shared.Utility;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||||
|
|
||||||
namespace Content.Client.Chemistry.UI
|
namespace Content.Client.Chemistry.UI
|
||||||
@@ -91,40 +90,10 @@ namespace Content.Client.Chemistry.UI
|
|||||||
|
|
||||||
private ReagentButton MakeReagentButton(string text, ChemMasterReagentAmount amount, ReagentId id, bool isBuffer, string styleClass)
|
private ReagentButton MakeReagentButton(string text, ChemMasterReagentAmount amount, ReagentId id, bool isBuffer, string styleClass)
|
||||||
{
|
{
|
||||||
var reagentTransferButton = new ReagentButton(text, amount, id, isBuffer, styleClass);
|
var button = new ReagentButton(text, amount, id, isBuffer, styleClass);
|
||||||
reagentTransferButton.OnPressed += args
|
button.OnPressed += args
|
||||||
=> OnReagentButtonPressed?.Invoke(args, reagentTransferButton);
|
=> OnReagentButtonPressed?.Invoke(args, button);
|
||||||
return reagentTransferButton;
|
return button;
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Conditionally generates a set of reagent buttons based on the supplied boolean argument.
|
|
||||||
/// This was moved outside of BuildReagentRow to facilitate conditional logic, stops indentation depth getting out of hand as well.
|
|
||||||
/// </summary>
|
|
||||||
private List<ReagentButton> CreateReagentTransferButtons(ReagentId reagent, bool isBuffer, bool addReagentButtons)
|
|
||||||
{
|
|
||||||
if (!addReagentButtons)
|
|
||||||
return new List<ReagentButton>(); // Return an empty list if reagentTransferButton creation is disabled.
|
|
||||||
|
|
||||||
var buttonConfigs = new (string text, ChemMasterReagentAmount amount, string styleClass)[]
|
|
||||||
{
|
|
||||||
("1", ChemMasterReagentAmount.U1, StyleBase.ButtonOpenBoth),
|
|
||||||
("5", ChemMasterReagentAmount.U5, StyleBase.ButtonOpenBoth),
|
|
||||||
("10", ChemMasterReagentAmount.U10, StyleBase.ButtonOpenBoth),
|
|
||||||
("25", ChemMasterReagentAmount.U25, StyleBase.ButtonOpenBoth),
|
|
||||||
("50", ChemMasterReagentAmount.U50, StyleBase.ButtonOpenBoth),
|
|
||||||
("100", ChemMasterReagentAmount.U100, StyleBase.ButtonOpenBoth),
|
|
||||||
(Loc.GetString("chem-master-window-buffer-all-amount"), ChemMasterReagentAmount.All, StyleBase.ButtonOpenLeft),
|
|
||||||
};
|
|
||||||
|
|
||||||
var buttons = new List<ReagentButton>();
|
|
||||||
|
|
||||||
foreach (var (text, amount, styleClass) in buttonConfigs)
|
|
||||||
{
|
|
||||||
var reagentTransferButton = MakeReagentButton(text, amount, reagent, isBuffer, styleClass);
|
|
||||||
buttons.Add(reagentTransferButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buttons;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -133,36 +102,25 @@ namespace Content.Client.Chemistry.UI
|
|||||||
/// <param name="state">State data sent by the server.</param>
|
/// <param name="state">State data sent by the server.</param>
|
||||||
public void UpdateState(BoundUserInterfaceState state)
|
public void UpdateState(BoundUserInterfaceState state)
|
||||||
{
|
{
|
||||||
var castState = (ChemMasterBoundUserInterfaceState)state;
|
var castState = (ChemMasterBoundUserInterfaceState) state;
|
||||||
|
|
||||||
if (castState.UpdateLabel)
|
if (castState.UpdateLabel)
|
||||||
LabelLine = GenerateLabel(castState);
|
LabelLine = GenerateLabel(castState);
|
||||||
|
|
||||||
// Ensure the Panel Info is updated, including UI elements for Buffer Volume, Output Container and so on
|
|
||||||
UpdatePanelInfo(castState);
|
UpdatePanelInfo(castState);
|
||||||
|
|
||||||
BufferCurrentVolume.Text = $" {castState.BufferCurrentVolume?.Int() ?? 0}u";
|
|
||||||
|
|
||||||
InputEjectButton.Disabled = castState.InputContainerInfo is null;
|
|
||||||
OutputEjectButton.Disabled = castState.OutputContainerInfo is null;
|
|
||||||
CreateBottleButton.Disabled = castState.OutputContainerInfo?.Reagents == null;
|
|
||||||
CreatePillButton.Disabled = castState.OutputContainerInfo?.Entities == null;
|
|
||||||
|
|
||||||
UpdateDosageFields(castState);
|
|
||||||
}
|
|
||||||
|
|
||||||
//assign default values for pill and bottle fields.
|
|
||||||
private void UpdateDosageFields(ChemMasterBoundUserInterfaceState castState)
|
|
||||||
{
|
|
||||||
var output = castState.OutputContainerInfo;
|
var output = castState.OutputContainerInfo;
|
||||||
|
|
||||||
|
BufferCurrentVolume.Text = $" {castState.BufferCurrentVolume?.Int() ?? 0}u";
|
||||||
|
|
||||||
|
InputEjectButton.Disabled = castState.InputContainerInfo is null;
|
||||||
|
OutputEjectButton.Disabled = output is null;
|
||||||
|
CreateBottleButton.Disabled = output?.Reagents == null;
|
||||||
|
CreatePillButton.Disabled = output?.Entities == null;
|
||||||
|
|
||||||
var remainingCapacity = output is null ? 0 : (output.MaxVolume - output.CurrentVolume).Int();
|
var remainingCapacity = output is null ? 0 : (output.MaxVolume - output.CurrentVolume).Int();
|
||||||
var holdsReagents = output?.Reagents != null;
|
var holdsReagents = output?.Reagents != null;
|
||||||
var pillNumberMax = holdsReagents ? 0 : remainingCapacity;
|
var pillNumberMax = holdsReagents ? 0 : remainingCapacity;
|
||||||
var bottleAmountMax = holdsReagents ? remainingCapacity : 0;
|
var bottleAmountMax = holdsReagents ? remainingCapacity : 0;
|
||||||
var bufferVolume = castState.BufferCurrentVolume?.Int() ?? 0;
|
|
||||||
|
|
||||||
PillDosage.Value = (int)Math.Min(bufferVolume, castState.PillDosageLimit);
|
|
||||||
|
|
||||||
PillTypeButtons[castState.SelectedPillType].Pressed = true;
|
PillTypeButtons[castState.SelectedPillType].Pressed = true;
|
||||||
PillNumber.IsValid = x => x >= 0 && x <= pillNumberMax;
|
PillNumber.IsValid = x => x >= 0 && x <= pillNumberMax;
|
||||||
PillDosage.IsValid = x => x > 0 && x <= castState.PillDosageLimit;
|
PillDosage.IsValid = x => x > 0 && x <= castState.PillDosageLimit;
|
||||||
@@ -172,19 +130,8 @@ namespace Content.Client.Chemistry.UI
|
|||||||
PillNumber.Value = pillNumberMax;
|
PillNumber.Value = pillNumberMax;
|
||||||
if (BottleDosage.Value > bottleAmountMax)
|
if (BottleDosage.Value > bottleAmountMax)
|
||||||
BottleDosage.Value = bottleAmountMax;
|
BottleDosage.Value = bottleAmountMax;
|
||||||
|
|
||||||
// Avoid division by zero
|
|
||||||
if (PillDosage.Value > 0)
|
|
||||||
{
|
|
||||||
PillNumber.Value = Math.Min(bufferVolume / PillDosage.Value, pillNumberMax);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PillNumber.Value = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BottleDosage.Value = Math.Min(bottleAmountMax, bufferVolume);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a product label based on reagents in the buffer.
|
/// Generate a product label based on reagents in the buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -231,23 +178,46 @@ namespace Content.Client.Chemistry.UI
|
|||||||
var bufferVol = new Label
|
var bufferVol = new Label
|
||||||
{
|
{
|
||||||
Text = $"{state.BufferCurrentVolume}u",
|
Text = $"{state.BufferCurrentVolume}u",
|
||||||
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor }
|
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
|
||||||
};
|
};
|
||||||
bufferHBox.AddChild(bufferVol);
|
bufferHBox.AddChild(bufferVol);
|
||||||
|
|
||||||
// initialises rowCount to allow for striped rows
|
|
||||||
|
|
||||||
var rowCount = 0;
|
|
||||||
foreach (var (reagent, quantity) in state.BufferReagents)
|
foreach (var (reagent, quantity) in state.BufferReagents)
|
||||||
{
|
{
|
||||||
var reagentId = reagent;
|
// Try to get the prototype for the given reagent. This gives us its name.
|
||||||
_prototypeManager.TryIndex(reagentId.Prototype, out ReagentPrototype? proto);
|
_prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto);
|
||||||
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
|
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
|
||||||
var reagentColor = proto?.SubstanceColor ?? default(Color);
|
|
||||||
BufferInfo.Children.Add(BuildReagentRow(reagentColor, rowCount++, name, reagentId, quantity, true, true));
|
if (proto != null)
|
||||||
|
{
|
||||||
|
BufferInfo.Children.Add(new BoxContainer
|
||||||
|
{
|
||||||
|
Orientation = LayoutOrientation.Horizontal,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new Label {Text = $"{name}: "},
|
||||||
|
new Label
|
||||||
|
{
|
||||||
|
Text = $"{quantity}u",
|
||||||
|
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Padding
|
||||||
|
new Control {HorizontalExpand = true},
|
||||||
|
|
||||||
|
MakeReagentButton("1", ChemMasterReagentAmount.U1, reagent, true, StyleBase.ButtonOpenRight),
|
||||||
|
MakeReagentButton("5", ChemMasterReagentAmount.U5, reagent, true, StyleBase.ButtonOpenBoth),
|
||||||
|
MakeReagentButton("10", ChemMasterReagentAmount.U10, reagent, true, StyleBase.ButtonOpenBoth),
|
||||||
|
MakeReagentButton("25", ChemMasterReagentAmount.U25, reagent, true, StyleBase.ButtonOpenBoth),
|
||||||
|
MakeReagentButton("50", ChemMasterReagentAmount.U50, reagent, true, StyleBase.ButtonOpenBoth),
|
||||||
|
MakeReagentButton("100", ChemMasterReagentAmount.U100, reagent, true, StyleBase.ButtonOpenBoth),
|
||||||
|
MakeReagentButton(Loc.GetString("chem-master-window-buffer-all-amount"), ChemMasterReagentAmount.All, reagent, true, StyleBase.ButtonOpenLeft),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildContainerUI(Control control, ContainerInfo? info, bool addReagentButtons)
|
private void BuildContainerUI(Control control, ContainerInfo? info, bool addReagentButtons)
|
||||||
{
|
{
|
||||||
control.Children.Clear();
|
control.Children.Clear();
|
||||||
@@ -258,111 +228,104 @@ namespace Content.Client.Chemistry.UI
|
|||||||
{
|
{
|
||||||
Text = Loc.GetString("chem-master-window-no-container-loaded-text")
|
Text = Loc.GetString("chem-master-window-no-container-loaded-text")
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// Name of the container and its fill status (Ex: 44/100u)
|
|
||||||
control.Children.Add(new BoxContainer
|
|
||||||
{
|
{
|
||||||
Orientation = LayoutOrientation.Horizontal,
|
// Name of the container and its fill status (Ex: 44/100u)
|
||||||
Children =
|
control.Children.Add(new BoxContainer
|
||||||
{
|
{
|
||||||
new Label { Text = $"{info.DisplayName}: " },
|
Orientation = LayoutOrientation.Horizontal,
|
||||||
new Label
|
Children =
|
||||||
{
|
{
|
||||||
Text = $"{info.CurrentVolume}/{info.MaxVolume}",
|
new Label {Text = $"{info.DisplayName}: "},
|
||||||
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor }
|
new Label
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Initialises rowCount to allow for striped rows
|
|
||||||
var rowCount = 0;
|
|
||||||
|
|
||||||
// Handle entities if they are not null
|
|
||||||
if (info.Entities != null)
|
|
||||||
{
|
|
||||||
foreach (var (id, quantity) in info.Entities.Select(x => (x.Id, x.Quantity)))
|
|
||||||
{
|
|
||||||
control.Children.Add(BuildReagentRow(default(Color), rowCount++, id, default(ReagentId), quantity, false, addReagentButtons));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle reagents if they are not null
|
|
||||||
if (info.Reagents != null)
|
|
||||||
{
|
|
||||||
foreach (var reagent in info.Reagents)
|
|
||||||
{
|
|
||||||
_prototypeManager.TryIndex(reagent.Reagent.Prototype, out ReagentPrototype? proto);
|
|
||||||
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
|
|
||||||
var reagentColor = proto?.SubstanceColor ?? default(Color);
|
|
||||||
|
|
||||||
control.Children.Add(BuildReagentRow(reagentColor, rowCount++, name, reagent.Reagent, reagent.Quantity, false, addReagentButtons));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Take reagent/entity data and present rows, labels, and buttons appropriately. todo sprites?
|
|
||||||
/// </summary>
|
|
||||||
private Control BuildReagentRow(Color reagentColor, int rowCount, string name, ReagentId reagent, FixedPoint2 quantity, bool isBuffer, bool addReagentButtons)
|
|
||||||
{
|
|
||||||
//Colors rows and sets fallback for reagentcolor to the same as background, this will hide colorPanel for entities hopefully
|
|
||||||
var rowColor1 = Color.FromHex("#1B1B1E");
|
|
||||||
var rowColor2 = Color.FromHex("#202025");
|
|
||||||
var currentRowColor = (rowCount % 2 == 1) ? rowColor1 : rowColor2;
|
|
||||||
if ((reagentColor == default(Color))|(!addReagentButtons))
|
|
||||||
{
|
|
||||||
reagentColor = currentRowColor;
|
|
||||||
}
|
|
||||||
//this calls the separated button builder, and stores the return to render after labels
|
|
||||||
var reagentButtonConstructors = CreateReagentTransferButtons(reagent, isBuffer, addReagentButtons);
|
|
||||||
|
|
||||||
// Create the row layout with the color panel
|
|
||||||
var rowContainer = new BoxContainer
|
|
||||||
{
|
|
||||||
Orientation = LayoutOrientation.Horizontal,
|
|
||||||
Children =
|
|
||||||
{
|
|
||||||
new Label { Text = $"{name}: " },
|
|
||||||
new Label
|
|
||||||
{
|
|
||||||
Text = $"{quantity}u",
|
|
||||||
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor }
|
|
||||||
},
|
|
||||||
|
|
||||||
// Padding
|
|
||||||
new Control { HorizontalExpand = true },
|
|
||||||
// Colored panels for reagents
|
|
||||||
new PanelContainer
|
|
||||||
{
|
|
||||||
Name = "colorPanel",
|
|
||||||
VerticalExpand = true,
|
|
||||||
MinWidth = 4,
|
|
||||||
PanelOverride = new StyleBoxFlat
|
|
||||||
{
|
{
|
||||||
BackgroundColor = reagentColor
|
Text = $"{info.CurrentVolume}/{info.MaxVolume}",
|
||||||
},
|
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
|
||||||
Margin = new Thickness(0, 1)
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
IEnumerable<(string Name, ReagentId Id, FixedPoint2 Quantity)> contents;
|
||||||
|
|
||||||
|
if (info.Entities != null)
|
||||||
|
{
|
||||||
|
contents = info.Entities.Select(x => (x.Id, default(ReagentId), x.Quantity));
|
||||||
|
}
|
||||||
|
else if (info.Reagents != null)
|
||||||
|
{
|
||||||
|
contents = info.Reagents.Select(x =>
|
||||||
|
{
|
||||||
|
_prototypeManager.TryIndex(x.Reagent.Prototype, out ReagentPrototype? proto);
|
||||||
|
var name = proto?.LocalizedName
|
||||||
|
?? Loc.GetString("chem-master-window-unknown-reagent-text");
|
||||||
|
|
||||||
|
return (name, Id: x.Reagent, x.Quantity);
|
||||||
|
})
|
||||||
|
.OrderBy(r => r.Item1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var (name, id, quantity) in contents)
|
||||||
|
{
|
||||||
|
var inner = new BoxContainer
|
||||||
|
{
|
||||||
|
Orientation = LayoutOrientation.Horizontal,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new Label { Text = $"{name}: " },
|
||||||
|
new Label
|
||||||
|
{
|
||||||
|
Text = $"{quantity}u",
|
||||||
|
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (addReagentButtons)
|
||||||
|
{
|
||||||
|
var cs = inner.Children;
|
||||||
|
|
||||||
|
// Padding
|
||||||
|
cs.Add(new Control { HorizontalExpand = true });
|
||||||
|
|
||||||
|
cs.Add(MakeReagentButton(
|
||||||
|
"1", ChemMasterReagentAmount.U1, id, false, StyleBase.ButtonOpenRight));
|
||||||
|
cs.Add(MakeReagentButton(
|
||||||
|
"5", ChemMasterReagentAmount.U5, id, false, StyleBase.ButtonOpenBoth));
|
||||||
|
cs.Add(MakeReagentButton(
|
||||||
|
"10", ChemMasterReagentAmount.U10, id, false, StyleBase.ButtonOpenBoth));
|
||||||
|
cs.Add(MakeReagentButton(
|
||||||
|
"25", ChemMasterReagentAmount.U25, id, false, StyleBase.ButtonOpenBoth));
|
||||||
|
cs.Add(MakeReagentButton(
|
||||||
|
"50", ChemMasterReagentAmount.U50, id, false, StyleBase.ButtonOpenBoth));
|
||||||
|
cs.Add(MakeReagentButton(
|
||||||
|
"100", ChemMasterReagentAmount.U100, id, false, StyleBase.ButtonOpenBoth));
|
||||||
|
cs.Add(MakeReagentButton(
|
||||||
|
Loc.GetString("chem-master-window-buffer-all-amount"),
|
||||||
|
ChemMasterReagentAmount.All, id, false, StyleBase.ButtonOpenLeft));
|
||||||
|
}
|
||||||
|
|
||||||
|
control.Children.Add(inner);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the reagent buttons after the color panel
|
|
||||||
foreach (var reagentTransferButton in reagentButtonConstructors)
|
|
||||||
{
|
|
||||||
rowContainer.AddChild(reagentTransferButton);
|
|
||||||
}
|
}
|
||||||
//Apply panencontainer to allow for striped rows
|
|
||||||
return new PanelContainer
|
|
||||||
{
|
|
||||||
PanelOverride = new StyleBoxFlat(currentRowColor),
|
|
||||||
Children = { rowContainer }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string LabelLine
|
public String LabelLine
|
||||||
{
|
{
|
||||||
get => LabelLineEdit.Text;
|
get
|
||||||
set => LabelLineEdit.Text = value;
|
{
|
||||||
|
return LabelLineEdit.Text;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
LabelLineEdit.Text = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
/// 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.
|
/// 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>
|
/// </summary>
|
||||||
public static readonly Dictionary<string, string> TemporarySlotMap = new() //CP14 Public
|
private static readonly Dictionary<string, string> TemporarySlotMap = new()
|
||||||
{
|
{
|
||||||
{"head", "HELMET"},
|
{"head", "HELMET"},
|
||||||
{"eyes", "EYES"},
|
{"eyes", "EYES"},
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using Robust.Client.GameObjects;
|
|||||||
|
|
||||||
namespace Content.Client.Clothing;
|
namespace Content.Client.Clothing;
|
||||||
|
|
||||||
public sealed class FlippableClothingVisualizerSystem : VisualizerSystem<FlippableClothingVisualsComponent>
|
public sealed class FlippableClothingVisualizerSystem : VisualizerSystem<FlippableClothingVisualsComponent>
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedItemSystem _itemSys = default!;
|
[Dependency] private readonly SharedItemSystem _itemSys = default!;
|
||||||
|
|
||||||
|
|||||||
@@ -1,62 +1,17 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
Title="{Loc 'comms-console-menu-title'}"
|
Title="{Loc 'comms-console-menu-title'}"
|
||||||
MinSize="400 300">
|
MinSize="400 225">
|
||||||
|
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="5">
|
||||||
|
<TextEdit Name="MessageInput" HorizontalExpand="True" VerticalExpand="True" Margin="0 0 0 5" MinHeight="100" />
|
||||||
|
<Button Name="AnnounceButton" Text="{Loc 'comms-console-menu-announcement-button'}" ToolTip="{Loc 'comms-console-menu-announcement-button-tooltip'}" StyleClasses="OpenLeft" Access="Public" />
|
||||||
|
<Button Name="BroadcastButton" Text="{Loc 'comms-console-menu-broadcast-button'}" ToolTip="{Loc 'comms-console-menu-broadcast-button-tooltip'}" StyleClasses="OpenLeft" Access="Public" />
|
||||||
|
|
||||||
<!-- Main Container -->
|
<OptionButton Name="AlertLevelButton" ToolTip="{Loc 'comms-console-menu-alert-level-button-tooltip'}" StyleClasses="OpenRight" Access="Public" />
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
HorizontalExpand="False"
|
|
||||||
VerticalExpand="True"
|
|
||||||
Margin="6 6 6 5">
|
|
||||||
|
|
||||||
<TextEdit Name="MessageInput"
|
<Control MinSize="10 10" />
|
||||||
VerticalExpand="True"
|
|
||||||
HorizontalExpand="True"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
MinHeight="100"/>
|
|
||||||
|
|
||||||
<!-- ButtonsPart -->
|
<RichTextLabel Name="CountdownLabel" VerticalExpand="True" />
|
||||||
<BoxContainer Orientation="Vertical"
|
<Button Name="EmergencyShuttleButton" Text="Placeholder Text" ToolTip="{Loc 'comms-console-menu-emergency-shuttle-button-tooltip'}" Access="Public" />
|
||||||
VerticalAlignment="Bottom"
|
|
||||||
SeparationOverride="4">
|
|
||||||
|
|
||||||
<!-- AnnouncePart -->
|
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
Margin="0 2">
|
|
||||||
|
|
||||||
<Button Name="AnnounceButton"
|
|
||||||
Access="Public"
|
|
||||||
Text="{Loc 'comms-console-menu-announcement-button'}"
|
|
||||||
ToolTip="{Loc 'comms-console-menu-announcement-button-tooltip'}"
|
|
||||||
StyleClasses="OpenLeft"
|
|
||||||
Margin="0 0 1 0"
|
|
||||||
Disabled="True"/>
|
|
||||||
|
|
||||||
<Button Name="BroadcastButton"
|
|
||||||
Access="Public"
|
|
||||||
Text="{Loc 'comms-console-menu-broadcast-button'}"
|
|
||||||
ToolTip="{Loc 'comms-console-menu-broadcast-button-tooltip'}"
|
|
||||||
StyleClasses="OpenBoth"/>
|
|
||||||
|
|
||||||
<OptionButton Name="AlertLevelButton"
|
|
||||||
Access="Public"
|
|
||||||
ToolTip="{Loc 'comms-console-menu-alert-level-button-tooltip'}"
|
|
||||||
StyleClasses="OpenRight"/>
|
|
||||||
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- EmergencyPart -->
|
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
SeparationOverride="6">
|
|
||||||
|
|
||||||
<RichTextLabel Name="CountdownLabel"/>
|
|
||||||
|
|
||||||
<Button Name="EmergencyShuttleButton"
|
|
||||||
Access="Public"
|
|
||||||
Text="Placeholder Text"
|
|
||||||
ToolTip="{Loc 'comms-console-menu-emergency-shuttle-button-tooltip'}"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</controls:FancyWindow>
|
</controls:FancyWindow>
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,6 @@ using Content.Client.IoC;
|
|||||||
using Content.Client.Launcher;
|
using Content.Client.Launcher;
|
||||||
using Content.Client.Lobby;
|
using Content.Client.Lobby;
|
||||||
using Content.Client.MainMenu;
|
using Content.Client.MainMenu;
|
||||||
using Content.Client.Overlays;
|
|
||||||
using Content.Client.Parallax.Managers;
|
using Content.Client.Parallax.Managers;
|
||||||
using Content.Client.Players.PlayTimeTracking;
|
using Content.Client.Players.PlayTimeTracking;
|
||||||
using Content.Client.Radiation.Overlays;
|
using Content.Client.Radiation.Overlays;
|
||||||
@@ -160,7 +159,6 @@ namespace Content.Client.Entry
|
|||||||
|
|
||||||
_parallaxManager.LoadDefaultParallax();
|
_parallaxManager.LoadDefaultParallax();
|
||||||
|
|
||||||
_overlayManager.AddOverlay(new CP14BasePostProcessOverlay()); // CP14-PostProcess
|
|
||||||
_overlayManager.AddOverlay(new SingularityOverlay());
|
_overlayManager.AddOverlay(new SingularityOverlay());
|
||||||
_overlayManager.AddOverlay(new RadiationPulseOverlay());
|
_overlayManager.AddOverlay(new RadiationPulseOverlay());
|
||||||
_chatManager.Initialize();
|
_chatManager.Initialize();
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ namespace Content.Client.Eui
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected void SendMessage(EuiMessageBase msg)
|
protected void SendMessage(EuiMessageBase msg)
|
||||||
{
|
{
|
||||||
var netMsg = new MsgEuiMessage();
|
var netMsg = _netManager.CreateNetMessage<MsgEuiMessage>();
|
||||||
netMsg.Id = Id;
|
netMsg.Id = Id;
|
||||||
netMsg.Message = msg;
|
netMsg.Message = msg;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
using Content.Shared.Explosion.EntitySystems;
|
|
||||||
|
|
||||||
namespace Content.Client.Explosion;
|
|
||||||
|
|
||||||
public sealed class ScatteringGrenadeSystem : SharedScatteringGrenadeSystem
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -112,12 +112,7 @@ namespace Content.Client.Ghost
|
|||||||
_actions.RemoveAction(uid, component.ToggleLightingActionEntity);
|
_actions.RemoveAction(uid, component.ToggleLightingActionEntity);
|
||||||
_actions.RemoveAction(uid, component.ToggleFoVActionEntity);
|
_actions.RemoveAction(uid, component.ToggleFoVActionEntity);
|
||||||
_actions.RemoveAction(uid, component.ToggleGhostsActionEntity);
|
_actions.RemoveAction(uid, component.ToggleGhostsActionEntity);
|
||||||
//_actions.RemoveAction(uid, component.ToggleGhostHearingActionEntity); //Dont need in CP14
|
_actions.RemoveAction(uid, component.ToggleGhostHearingActionEntity);
|
||||||
//CP14
|
|
||||||
_actions.RemoveAction(uid, component.CP14ZLevelUpActionEntity);
|
|
||||||
_actions.RemoveAction(uid, component.CP14ZLevelDownActionEntity);
|
|
||||||
_actions.RemoveAction(uid, component.CP14ToggleRoofActionEntity);
|
|
||||||
//CP14 end
|
|
||||||
|
|
||||||
if (uid != _playerManager.LocalEntity)
|
if (uid != _playerManager.LocalEntity)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
using Content.Shared.Holopad;
|
|
||||||
using Content.Shared.Silicons.StationAi;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.UserInterface;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
using System.Numerics;
|
|
||||||
|
|
||||||
namespace Content.Client.Holopad;
|
|
||||||
|
|
||||||
public sealed class HolopadBoundUserInterface : BoundUserInterface
|
|
||||||
{
|
|
||||||
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;
|
|
||||||
[Dependency] private readonly IClyde _displayManager = default!;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
private HolopadWindow? _window;
|
|
||||||
|
|
||||||
public HolopadBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
|
||||||
{
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Open()
|
|
||||||
{
|
|
||||||
base.Open();
|
|
||||||
|
|
||||||
_window = this.CreateWindow<HolopadWindow>();
|
|
||||||
_window.Title = Loc.GetString("holopad-window-title", ("title", EntMan.GetComponent<MetaDataComponent>(Owner).EntityName));
|
|
||||||
|
|
||||||
if (this.UiKey is not HolopadUiKey)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var uiKey = (HolopadUiKey)this.UiKey;
|
|
||||||
|
|
||||||
// AIs will see a different holopad interface to crew when interacting with them in the world
|
|
||||||
if (uiKey == HolopadUiKey.InteractionWindow && EntMan.HasComponent<StationAiHeldComponent>(_playerManager.LocalEntity))
|
|
||||||
uiKey = HolopadUiKey.InteractionWindowForAi;
|
|
||||||
|
|
||||||
_window.SetState(Owner, uiKey);
|
|
||||||
_window.UpdateState(new Dictionary<NetEntity, string>());
|
|
||||||
|
|
||||||
// Set message actions
|
|
||||||
_window.SendHolopadStartNewCallMessageAction += SendHolopadStartNewCallMessage;
|
|
||||||
_window.SendHolopadAnswerCallMessageAction += SendHolopadAnswerCallMessage;
|
|
||||||
_window.SendHolopadEndCallMessageAction += SendHolopadEndCallMessage;
|
|
||||||
_window.SendHolopadStartBroadcastMessageAction += SendHolopadStartBroadcastMessage;
|
|
||||||
_window.SendHolopadActivateProjectorMessageAction += SendHolopadActivateProjectorMessage;
|
|
||||||
_window.SendHolopadRequestStationAiMessageAction += SendHolopadRequestStationAiMessage;
|
|
||||||
|
|
||||||
// If this call is addressed to an AI, open the window in the bottom right hand corner of the screen
|
|
||||||
if (uiKey == HolopadUiKey.AiRequestWindow)
|
|
||||||
_window.OpenCenteredAt(new Vector2(1f, 1f));
|
|
||||||
|
|
||||||
// Otherwise offset to the left so the holopad can still be seen
|
|
||||||
else
|
|
||||||
_window.OpenCenteredAt(new Vector2(0.3333f, 0.50f));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateState(BoundUserInterfaceState state)
|
|
||||||
{
|
|
||||||
base.UpdateState(state);
|
|
||||||
|
|
||||||
var castState = (HolopadBoundInterfaceState)state;
|
|
||||||
EntMan.TryGetComponent<TransformComponent>(Owner, out var xform);
|
|
||||||
|
|
||||||
_window?.UpdateState(castState.Holopads);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendHolopadStartNewCallMessage(NetEntity receiver)
|
|
||||||
{
|
|
||||||
SendMessage(new HolopadStartNewCallMessage(receiver));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendHolopadAnswerCallMessage()
|
|
||||||
{
|
|
||||||
SendMessage(new HolopadAnswerCallMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendHolopadEndCallMessage()
|
|
||||||
{
|
|
||||||
SendMessage(new HolopadEndCallMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendHolopadStartBroadcastMessage()
|
|
||||||
{
|
|
||||||
SendMessage(new HolopadStartBroadcastMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendHolopadActivateProjectorMessage()
|
|
||||||
{
|
|
||||||
SendMessage(new HolopadActivateProjectorMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendHolopadRequestStationAiMessage()
|
|
||||||
{
|
|
||||||
SendMessage(new HolopadStationAiRequestMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
using Content.Shared.Chat.TypingIndicator;
|
|
||||||
using Content.Shared.Holopad;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.Player;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Content.Client.Holopad;
|
|
||||||
|
|
||||||
public sealed class HolopadSystem : SharedHolopadSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<HolopadHologramComponent, ComponentInit>(OnComponentInit);
|
|
||||||
SubscribeLocalEvent<HolopadHologramComponent, BeforePostShaderRenderEvent>(OnShaderRender);
|
|
||||||
SubscribeAllEvent<TypingChangedEvent>(OnTypingChanged);
|
|
||||||
|
|
||||||
SubscribeNetworkEvent<PlayerSpriteStateRequest>(OnPlayerSpriteStateRequest);
|
|
||||||
SubscribeNetworkEvent<PlayerSpriteStateMessage>(OnPlayerSpriteStateMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnComponentInit(EntityUid uid, HolopadHologramComponent component, ComponentInit ev)
|
|
||||||
{
|
|
||||||
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
|
||||||
return;
|
|
||||||
|
|
||||||
UpdateHologramSprite(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnShaderRender(EntityUid uid, HolopadHologramComponent component, BeforePostShaderRenderEvent ev)
|
|
||||||
{
|
|
||||||
if (ev.Sprite.PostShader == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ev.Sprite.PostShader.SetParameter("t", (float)_timing.CurTime.TotalSeconds * component.ScrollRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTypingChanged(TypingChangedEvent ev, EntitySessionEventArgs args)
|
|
||||||
{
|
|
||||||
var uid = args.SenderSession.AttachedEntity;
|
|
||||||
|
|
||||||
if (!Exists(uid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!HasComp<HolopadUserComponent>(uid))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var netEv = new HolopadUserTypingChangedEvent(GetNetEntity(uid.Value), ev.IsTyping);
|
|
||||||
RaiseNetworkEvent(netEv);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlayerSpriteStateRequest(PlayerSpriteStateRequest ev)
|
|
||||||
{
|
|
||||||
var targetPlayer = GetEntity(ev.TargetPlayer);
|
|
||||||
var player = _playerManager.LocalSession?.AttachedEntity;
|
|
||||||
|
|
||||||
// Ignore the request if received by a player who isn't the target
|
|
||||||
if (targetPlayer != player)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!TryComp<SpriteComponent>(player, out var playerSprite))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var spriteLayerData = new List<PrototypeLayerData>();
|
|
||||||
|
|
||||||
if (playerSprite.Visible)
|
|
||||||
{
|
|
||||||
// Record the RSI paths, state names and shader paramaters of all visible layers
|
|
||||||
for (int i = 0; i < playerSprite.AllLayers.Count(); i++)
|
|
||||||
{
|
|
||||||
if (!playerSprite.TryGetLayer(i, out var layer))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!layer.Visible ||
|
|
||||||
string.IsNullOrEmpty(layer.ActualRsi?.Path.ToString()) ||
|
|
||||||
string.IsNullOrEmpty(layer.State.Name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var layerDatum = new PrototypeLayerData();
|
|
||||||
layerDatum.RsiPath = layer.ActualRsi.Path.ToString();
|
|
||||||
layerDatum.State = layer.State.Name;
|
|
||||||
|
|
||||||
if (layer.CopyToShaderParameters != null)
|
|
||||||
{
|
|
||||||
var key = (string)layer.CopyToShaderParameters.LayerKey;
|
|
||||||
|
|
||||||
if (playerSprite.LayerMapTryGet(key, out var otherLayerIdx) &&
|
|
||||||
playerSprite.TryGetLayer(otherLayerIdx, out var otherLayer) &&
|
|
||||||
otherLayer.Visible)
|
|
||||||
{
|
|
||||||
layerDatum.MapKeys = new() { key };
|
|
||||||
|
|
||||||
layerDatum.CopyToShaderParameters = new PrototypeCopyToShaderParameters()
|
|
||||||
{
|
|
||||||
LayerKey = key,
|
|
||||||
ParameterTexture = layer.CopyToShaderParameters.ParameterTexture,
|
|
||||||
ParameterUV = layer.CopyToShaderParameters.ParameterUV
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spriteLayerData.Add(layerDatum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the recorded data to the server
|
|
||||||
var evResponse = new PlayerSpriteStateMessage(ev.TargetPlayer, spriteLayerData.ToArray());
|
|
||||||
RaiseNetworkEvent(evResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlayerSpriteStateMessage(PlayerSpriteStateMessage ev)
|
|
||||||
{
|
|
||||||
UpdateHologramSprite(GetEntity(ev.SpriteEntity), ev.SpriteLayerData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateHologramSprite(EntityUid uid, PrototypeLayerData[]? layerData = null)
|
|
||||||
{
|
|
||||||
if (!TryComp<SpriteComponent>(uid, out var hologramSprite))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!TryComp<HolopadHologramComponent>(uid, out var holopadhologram))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (int i = hologramSprite.AllLayers.Count() - 1; i >= 0; i--)
|
|
||||||
hologramSprite.RemoveLayer(i);
|
|
||||||
|
|
||||||
if (layerData == null || layerData.Length == 0)
|
|
||||||
{
|
|
||||||
layerData = new PrototypeLayerData[1];
|
|
||||||
layerData[0] = new PrototypeLayerData()
|
|
||||||
{
|
|
||||||
RsiPath = holopadhologram.RsiPath,
|
|
||||||
State = holopadhologram.RsiState
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < layerData.Length; i++)
|
|
||||||
{
|
|
||||||
var layer = layerData[i];
|
|
||||||
layer.Shader = "unshaded";
|
|
||||||
|
|
||||||
hologramSprite.AddLayer(layerData[i], i);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateHologramShader(uid, hologramSprite, holopadhologram);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateHologramShader(EntityUid uid, SpriteComponent sprite, HolopadHologramComponent holopadHologram)
|
|
||||||
{
|
|
||||||
// Find the texture height of the largest layer
|
|
||||||
float texHeight = sprite.AllLayers.Max(x => x.PixelSize.Y);
|
|
||||||
|
|
||||||
var instance = _prototypeManager.Index<ShaderPrototype>(holopadHologram.ShaderName).InstanceUnique();
|
|
||||||
instance.SetParameter("color1", new Vector3(holopadHologram.Color1.R, holopadHologram.Color1.G, holopadHologram.Color1.B));
|
|
||||||
instance.SetParameter("color2", new Vector3(holopadHologram.Color2.R, holopadHologram.Color2.G, holopadHologram.Color2.B));
|
|
||||||
instance.SetParameter("alpha", holopadHologram.Alpha);
|
|
||||||
instance.SetParameter("intensity", holopadHologram.Intensity);
|
|
||||||
instance.SetParameter("texHeight", texHeight);
|
|
||||||
instance.SetParameter("t", (float)_timing.CurTime.TotalSeconds * holopadHologram.ScrollRate);
|
|
||||||
|
|
||||||
sprite.PostShader = instance;
|
|
||||||
sprite.RaiseShaderEvent = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
|
||||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
|
||||||
Resizable="False"
|
|
||||||
MaxSize="400 800"
|
|
||||||
MinSize="400 150">
|
|
||||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
|
|
||||||
|
|
||||||
<BoxContainer Name="ControlsLockOutContainer" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True" ReservesSpace="False" Visible="False">
|
|
||||||
<!-- Header text -->
|
|
||||||
<controls:StripeBack>
|
|
||||||
<PanelContainer>
|
|
||||||
<RichTextLabel Name="EmergencyBroadcastText" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10 10 10 10" ReservesSpace="False"/>
|
|
||||||
</PanelContainer>
|
|
||||||
</controls:StripeBack>
|
|
||||||
|
|
||||||
<Label Text="{Loc 'holopad-window-controls-locked-out'}" HorizontalAlignment="Center" Margin="10 5 10 0" ReservesSpace="False"/>
|
|
||||||
<RichTextLabel Name="LockOutIdText" HorizontalAlignment="Center" Margin="10 5 10 0" ReservesSpace="False"/>
|
|
||||||
<Label Name="LockOutCountDownText" Text="{Loc 'holopad-window-controls-unlock-countdown'}" HorizontalAlignment="Center" Margin="10 15 10 10" ReservesSpace="False"/>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<BoxContainer Name="ControlsContainer" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True" ReservesSpace="False">
|
|
||||||
|
|
||||||
<!-- Active call controls (either this or the call placement controls will be active) -->
|
|
||||||
<BoxContainer Name="ActiveCallControlsContainer" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True" ReservesSpace="False">
|
|
||||||
|
|
||||||
<!-- Header text -->
|
|
||||||
<BoxContainer MinHeight="60" Orientation="Vertical" VerticalAlignment="Center">
|
|
||||||
<Label Name="CallStatusText" Margin="10 5 10 0" ReservesSpace="False"/>
|
|
||||||
<BoxContainer Name="CallerIdContainer" Orientation="Vertical" ReservesSpace="False">
|
|
||||||
<RichTextLabel Name="CallerIdText" HorizontalAlignment="Center" Margin="0 0 0 0"/>
|
|
||||||
<Label Text="{Loc 'holopad-window-relay-label'}" Margin="10 5 10 0" ReservesSpace="False"/>
|
|
||||||
<RichTextLabel Name="HolopadIdText" HorizontalAlignment="Center" Margin="0 0 0 10"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Controls (the answer call button is absent when the phone is not ringing) -->
|
|
||||||
<GridContainer Columns="2" ReservesSpace="False">
|
|
||||||
<Control HorizontalExpand="True" Margin="10 0 2 5">
|
|
||||||
<Button Name="AnswerCallButton" Text="{Loc 'holopad-window-answer-call'}" StyleClasses="OpenRight" Margin="0 0 0 5" Disabled="True"/>
|
|
||||||
</Control>
|
|
||||||
<Control HorizontalExpand="True" Margin="2 0 10 5">
|
|
||||||
<Button Name="EndCallButton" Text="{Loc 'holopad-window-end-call'}" StyleClasses="OpenLeft" Margin="0 0 0 5" Disabled="True"/>
|
|
||||||
</Control>
|
|
||||||
</GridContainer>
|
|
||||||
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Call placement controls (either this or the active call controls will be active) -->
|
|
||||||
<BoxContainer Name="CallPlacementControlsContainer" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True" ReservesSpace="False">
|
|
||||||
|
|
||||||
<controls:StripeBack>
|
|
||||||
<PanelContainer>
|
|
||||||
<BoxContainer Orientation="Vertical">
|
|
||||||
<RichTextLabel Name="SubtitleText" HorizontalAlignment="Center" Margin="0 5 0 0"/>
|
|
||||||
<RichTextLabel Name="OptionsText" HorizontalAlignment="Center" Margin="0 0 0 5"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</PanelContainer>
|
|
||||||
</controls:StripeBack>
|
|
||||||
|
|
||||||
<!-- Request the station AI or activate the holopad projector (only one of these should be active at a time) -->
|
|
||||||
<BoxContainer Name="RequestStationAiContainer" Orientation="Vertical" ReservesSpace="False" Visible="False">
|
|
||||||
<Button Name="RequestStationAiButton" Text="{Loc 'holopad-window-request-station-ai'}" Margin="10 5 10 5" Disabled="False"/>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<BoxContainer Name="ActivateProjectorContainer" Orientation="Vertical" ReservesSpace="False" Visible="False">
|
|
||||||
<Button Name="ActivateProjectorButton" Text="{Loc 'holopad-window-activate-projector'}" Margin="10 5 10 5" Disabled="False"/>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- List of contactable holopads (the list is created in C#) -->
|
|
||||||
<BoxContainer Name="HolopadContactListContainer" Orientation="Vertical" Margin="10 0 10 5" ReservesSpace="False" Visible="False">
|
|
||||||
<PanelContainer Name="HolopadContactListHeaderPanel">
|
|
||||||
<Label Text="{Loc 'holopad-window-select-contact-from-list'}" HorizontalAlignment="Center" Margin="0 3 0 3"/>
|
|
||||||
</PanelContainer>
|
|
||||||
|
|
||||||
<PanelContainer Name="HolopadContactListPanel">
|
|
||||||
<BoxContainer Orientation="Vertical">
|
|
||||||
|
|
||||||
<!-- Contact filter -->
|
|
||||||
<LineEdit Name="SearchLineEdit" HorizontalExpand="True" Margin="4, 4, 4, 0"
|
|
||||||
PlaceHolder="{Loc holopad-window-filter-line-placeholder}" />
|
|
||||||
|
|
||||||
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" Margin="8, 8, 8, 8" MinHeight="256">
|
|
||||||
|
|
||||||
<!-- If there is no data yet, this will be displayed -->
|
|
||||||
<BoxContainer Name="FetchingAvailableHolopadsContainer" HorizontalAlignment="Center" HorizontalExpand="True" VerticalExpand="True" ReservesSpace="False">
|
|
||||||
<Label Text="{Loc 'holopad-window-fetching-contacts-list'}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Container for the contacts -->
|
|
||||||
<BoxContainer Name="ContactsList" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="10 0 10 0"/>
|
|
||||||
</ScrollContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</PanelContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Button to start an emergency broadcast (the user requires a certain level of access to interact with it) -->
|
|
||||||
<BoxContainer Name="StartBroadcastContainer" Orientation="Vertical" ReservesSpace="False" Visible="False">
|
|
||||||
<Button Name="StartBroadcastButton" Text="{Loc 'holopad-window-emergency-broadcast'}" Margin="10 0 10 5" Disabled="False" ReservesSpace="False"/>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Footer -->
|
|
||||||
<BoxContainer Orientation="Vertical">
|
|
||||||
<PanelContainer StyleClasses="LowDivider" />
|
|
||||||
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
|
|
||||||
<Label Text="{Loc 'holopad-window-flavor-left'}" StyleClasses="WindowFooterText" />
|
|
||||||
<Label Text="{Loc 'holopad-window-flavor-right'}" StyleClasses="WindowFooterText"
|
|
||||||
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
|
|
||||||
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered"
|
|
||||||
VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
</controls:FancyWindow>
|
|
||||||
@@ -1,344 +0,0 @@
|
|||||||
using Content.Client.Popups;
|
|
||||||
using Content.Client.UserInterface.Controls;
|
|
||||||
using Content.Shared.Access.Systems;
|
|
||||||
using Content.Shared.Holopad;
|
|
||||||
using Content.Shared.Telephone;
|
|
||||||
using Robust.Client.AutoGenerated;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.Player;
|
|
||||||
using Robust.Client.UserInterface.Controls;
|
|
||||||
using Robust.Client.UserInterface.XAML;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Content.Client.Holopad;
|
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
|
||||||
public sealed partial class HolopadWindow : FancyWindow
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
|
|
||||||
private readonly SharedHolopadSystem _holopadSystem = default!;
|
|
||||||
private readonly SharedTelephoneSystem _telephoneSystem = default!;
|
|
||||||
private readonly AccessReaderSystem _accessReaderSystem = default!;
|
|
||||||
private readonly PopupSystem _popupSystem = default!;
|
|
||||||
|
|
||||||
private EntityUid? _owner = null;
|
|
||||||
private HolopadUiKey _currentUiKey;
|
|
||||||
private TelephoneState _currentState;
|
|
||||||
private TelephoneState _previousState;
|
|
||||||
private TimeSpan _buttonUnlockTime;
|
|
||||||
private float _updateTimer = 0.25f;
|
|
||||||
|
|
||||||
private const float UpdateTime = 0.25f;
|
|
||||||
private TimeSpan _buttonUnlockDelay = TimeSpan.FromSeconds(0.5f);
|
|
||||||
|
|
||||||
public event Action<NetEntity>? SendHolopadStartNewCallMessageAction;
|
|
||||||
public event Action? SendHolopadAnswerCallMessageAction;
|
|
||||||
public event Action? SendHolopadEndCallMessageAction;
|
|
||||||
public event Action? SendHolopadStartBroadcastMessageAction;
|
|
||||||
public event Action? SendHolopadActivateProjectorMessageAction;
|
|
||||||
public event Action? SendHolopadRequestStationAiMessageAction;
|
|
||||||
|
|
||||||
public HolopadWindow()
|
|
||||||
{
|
|
||||||
RobustXamlLoader.Load(this);
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
|
|
||||||
_holopadSystem = _entManager.System<SharedHolopadSystem>();
|
|
||||||
_telephoneSystem = _entManager.System<SharedTelephoneSystem>();
|
|
||||||
_accessReaderSystem = _entManager.System<AccessReaderSystem>();
|
|
||||||
_popupSystem = _entManager.System<PopupSystem>();
|
|
||||||
|
|
||||||
_buttonUnlockTime = _timing.CurTime + _buttonUnlockDelay;
|
|
||||||
|
|
||||||
// Assign button actions
|
|
||||||
AnswerCallButton.OnPressed += args => { OnHolopadAnswerCallMessage(); };
|
|
||||||
EndCallButton.OnPressed += args => { OnHolopadEndCallMessage(); };
|
|
||||||
StartBroadcastButton.OnPressed += args => { OnHolopadStartBroadcastMessage(); };
|
|
||||||
ActivateProjectorButton.OnPressed += args => { OnHolopadActivateProjectorMessage(); };
|
|
||||||
RequestStationAiButton.OnPressed += args => { OnHolopadRequestStationAiMessage(); };
|
|
||||||
|
|
||||||
// XML formatting
|
|
||||||
AnswerCallButton.AddStyleClass("ButtonAccept");
|
|
||||||
EndCallButton.AddStyleClass("Caution");
|
|
||||||
StartBroadcastButton.AddStyleClass("Caution");
|
|
||||||
|
|
||||||
HolopadContactListPanel.PanelOverride = new StyleBoxFlat
|
|
||||||
{
|
|
||||||
BackgroundColor = new Color(47, 47, 59) * Color.DarkGray,
|
|
||||||
BorderColor = new Color(82, 82, 82), //new Color(70, 73, 102),
|
|
||||||
BorderThickness = new Thickness(2),
|
|
||||||
};
|
|
||||||
|
|
||||||
HolopadContactListHeaderPanel.PanelOverride = new StyleBoxFlat
|
|
||||||
{
|
|
||||||
BackgroundColor = new Color(82, 82, 82),
|
|
||||||
};
|
|
||||||
|
|
||||||
EmergencyBroadcastText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-emergency-broadcast-in-progress")));
|
|
||||||
SubtitleText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-subtitle")));
|
|
||||||
OptionsText.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("holopad-window-options")));
|
|
||||||
}
|
|
||||||
|
|
||||||
#region: Button actions
|
|
||||||
|
|
||||||
private void OnSendHolopadStartNewCallMessage(NetEntity receiver)
|
|
||||||
{
|
|
||||||
SendHolopadStartNewCallMessageAction?.Invoke(receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHolopadAnswerCallMessage()
|
|
||||||
{
|
|
||||||
SendHolopadAnswerCallMessageAction?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHolopadEndCallMessage()
|
|
||||||
{
|
|
||||||
SendHolopadEndCallMessageAction?.Invoke();
|
|
||||||
|
|
||||||
if (_currentUiKey == HolopadUiKey.AiRequestWindow)
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHolopadStartBroadcastMessage()
|
|
||||||
{
|
|
||||||
if (_playerManager.LocalSession?.AttachedEntity == null || _owner == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var player = _playerManager.LocalSession.AttachedEntity;
|
|
||||||
|
|
||||||
if (!_accessReaderSystem.IsAllowed(player.Value, _owner.Value))
|
|
||||||
{
|
|
||||||
_popupSystem.PopupClient(Loc.GetString("holopad-window-access-denied"), _owner.Value, player.Value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SendHolopadStartBroadcastMessageAction?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHolopadActivateProjectorMessage()
|
|
||||||
{
|
|
||||||
SendHolopadActivateProjectorMessageAction?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHolopadRequestStationAiMessage()
|
|
||||||
{
|
|
||||||
SendHolopadRequestStationAiMessageAction?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public void SetState(EntityUid owner, HolopadUiKey uiKey)
|
|
||||||
{
|
|
||||||
_owner = owner;
|
|
||||||
_currentUiKey = uiKey;
|
|
||||||
|
|
||||||
// Determines what UI containers are available to the user.
|
|
||||||
// Components of these will be toggled on and off when
|
|
||||||
// UpdateAppearance() is called
|
|
||||||
|
|
||||||
switch (uiKey)
|
|
||||||
{
|
|
||||||
case HolopadUiKey.InteractionWindow:
|
|
||||||
RequestStationAiContainer.Visible = true;
|
|
||||||
HolopadContactListContainer.Visible = true;
|
|
||||||
StartBroadcastContainer.Visible = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HolopadUiKey.InteractionWindowForAi:
|
|
||||||
ActivateProjectorContainer.Visible = true;
|
|
||||||
StartBroadcastContainer.Visible = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HolopadUiKey.AiActionWindow:
|
|
||||||
HolopadContactListContainer.Visible = true;
|
|
||||||
StartBroadcastContainer.Visible = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HolopadUiKey.AiRequestWindow:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateState(Dictionary<NetEntity, string> holopads)
|
|
||||||
{
|
|
||||||
if (_owner == null || !_entManager.TryGetComponent<TelephoneComponent>(_owner.Value, out var telephone))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Caller ID text
|
|
||||||
var callerId = _telephoneSystem.GetFormattedCallerIdForEntity(telephone.LastCallerId.Item1, telephone.LastCallerId.Item2, Color.LightGray, "Default", 11);
|
|
||||||
var holoapdId = _telephoneSystem.GetFormattedDeviceIdForEntity(telephone.LastCallerId.Item3, Color.LightGray, "Default", 11);
|
|
||||||
|
|
||||||
CallerIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(callerId));
|
|
||||||
HolopadIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(holoapdId));
|
|
||||||
LockOutIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(callerId));
|
|
||||||
|
|
||||||
// Sort holopads alphabetically
|
|
||||||
var holopadArray = holopads.ToArray();
|
|
||||||
Array.Sort(holopadArray, AlphabeticalSort);
|
|
||||||
|
|
||||||
// Clear excess children from the contact list
|
|
||||||
while (ContactsList.ChildCount > holopadArray.Length)
|
|
||||||
ContactsList.RemoveChild(ContactsList.GetChild(ContactsList.ChildCount - 1));
|
|
||||||
|
|
||||||
// Make / update required children
|
|
||||||
for (int i = 0; i < holopadArray.Length; i++)
|
|
||||||
{
|
|
||||||
var (netEntity, label) = holopadArray[i];
|
|
||||||
|
|
||||||
if (i >= ContactsList.ChildCount)
|
|
||||||
{
|
|
||||||
var newContactButton = new HolopadContactButton();
|
|
||||||
newContactButton.OnPressed += args => { OnSendHolopadStartNewCallMessage(newContactButton.NetEntity); };
|
|
||||||
|
|
||||||
ContactsList.AddChild(newContactButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
var child = ContactsList.GetChild(i);
|
|
||||||
|
|
||||||
if (child is not HolopadContactButton)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var contactButton = (HolopadContactButton)child;
|
|
||||||
contactButton.UpdateValues(netEntity, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update buttons
|
|
||||||
UpdateAppearance();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateAppearance()
|
|
||||||
{
|
|
||||||
if (_owner == null || !_entManager.TryGetComponent<TelephoneComponent>(_owner.Value, out var telephone))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_owner == null || !_entManager.TryGetComponent<HolopadComponent>(_owner.Value, out var holopad))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var hasBroadcastAccess = !_holopadSystem.IsHolopadBroadcastOnCoolDown((_owner.Value, holopad));
|
|
||||||
var localPlayer = _playerManager.LocalSession?.AttachedEntity;
|
|
||||||
|
|
||||||
ControlsLockOutContainer.Visible = _holopadSystem.IsHolopadControlLocked((_owner.Value, holopad), localPlayer);
|
|
||||||
ControlsContainer.Visible = !ControlsLockOutContainer.Visible;
|
|
||||||
|
|
||||||
// Temporarily disable the interface buttons when the call state changes to prevent any misclicks
|
|
||||||
if (_currentState != telephone.CurrentState)
|
|
||||||
{
|
|
||||||
_previousState = _currentState;
|
|
||||||
_currentState = telephone.CurrentState;
|
|
||||||
_buttonUnlockTime = _timing.CurTime + _buttonUnlockDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lockButtons = _timing.CurTime < _buttonUnlockTime;
|
|
||||||
|
|
||||||
// Make / update required children
|
|
||||||
foreach (var child in ContactsList.Children)
|
|
||||||
{
|
|
||||||
if (child is not HolopadContactButton contactButton)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var passesFilter = string.IsNullOrEmpty(SearchLineEdit.Text) ||
|
|
||||||
contactButton.Text?.Contains(SearchLineEdit.Text, StringComparison.CurrentCultureIgnoreCase) == true;
|
|
||||||
|
|
||||||
contactButton.Visible = passesFilter;
|
|
||||||
contactButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update control text
|
|
||||||
var cooldown = _holopadSystem.GetHolopadBroadcastCoolDown((_owner.Value, holopad));
|
|
||||||
var cooldownString = $"{cooldown.Minutes:00}:{cooldown.Seconds:00}";
|
|
||||||
|
|
||||||
StartBroadcastButton.Text = _holopadSystem.IsHolopadBroadcastOnCoolDown((_owner.Value, holopad)) ?
|
|
||||||
Loc.GetString("holopad-window-emergency-broadcast-with-countdown", ("countdown", cooldownString)) :
|
|
||||||
Loc.GetString("holopad-window-emergency-broadcast");
|
|
||||||
|
|
||||||
var lockout = _holopadSystem.GetHolopadControlLockedPeriod((_owner.Value, holopad));
|
|
||||||
var lockoutString = $"{lockout.Minutes:00}:{lockout.Seconds:00}";
|
|
||||||
|
|
||||||
LockOutCountDownText.Text = Loc.GetString("holopad-window-controls-unlock-countdown", ("countdown", lockoutString));
|
|
||||||
|
|
||||||
switch (_currentState)
|
|
||||||
{
|
|
||||||
case TelephoneState.Idle:
|
|
||||||
CallStatusText.Text = Loc.GetString("holopad-window-no-calls-in-progress"); break;
|
|
||||||
|
|
||||||
case TelephoneState.Calling:
|
|
||||||
CallStatusText.Text = Loc.GetString("holopad-window-outgoing-call"); break;
|
|
||||||
|
|
||||||
case TelephoneState.Ringing:
|
|
||||||
CallStatusText.Text = (_currentUiKey == HolopadUiKey.AiRequestWindow) ?
|
|
||||||
Loc.GetString("holopad-window-ai-request") : Loc.GetString("holopad-window-incoming-call"); break;
|
|
||||||
|
|
||||||
case TelephoneState.InCall:
|
|
||||||
CallStatusText.Text = Loc.GetString("holopad-window-call-in-progress"); break;
|
|
||||||
|
|
||||||
case TelephoneState.EndingCall:
|
|
||||||
if (_previousState == TelephoneState.Calling || _previousState == TelephoneState.Idle)
|
|
||||||
CallStatusText.Text = Loc.GetString("holopad-window-call-rejected");
|
|
||||||
else
|
|
||||||
CallStatusText.Text = Loc.GetString("holopad-window-call-ending");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update control disability
|
|
||||||
AnswerCallButton.Disabled = (_currentState != TelephoneState.Ringing || lockButtons);
|
|
||||||
EndCallButton.Disabled = (_currentState == TelephoneState.Idle || _currentState == TelephoneState.EndingCall || lockButtons);
|
|
||||||
StartBroadcastButton.Disabled = (_currentState != TelephoneState.Idle || !hasBroadcastAccess || lockButtons);
|
|
||||||
RequestStationAiButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
|
|
||||||
ActivateProjectorButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
|
|
||||||
|
|
||||||
// Update control visibility
|
|
||||||
FetchingAvailableHolopadsContainer.Visible = (ContactsList.ChildCount == 0);
|
|
||||||
ActiveCallControlsContainer.Visible = (_currentState != TelephoneState.Idle || _currentUiKey == HolopadUiKey.AiRequestWindow);
|
|
||||||
CallPlacementControlsContainer.Visible = !ActiveCallControlsContainer.Visible;
|
|
||||||
CallerIdContainer.Visible = (_currentState == TelephoneState.Ringing);
|
|
||||||
AnswerCallButton.Visible = (_currentState == TelephoneState.Ringing);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
|
||||||
{
|
|
||||||
base.FrameUpdate(args);
|
|
||||||
|
|
||||||
_updateTimer += args.DeltaSeconds;
|
|
||||||
|
|
||||||
if (_updateTimer >= UpdateTime)
|
|
||||||
{
|
|
||||||
_updateTimer -= UpdateTime;
|
|
||||||
UpdateAppearance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class HolopadContactButton : Button
|
|
||||||
{
|
|
||||||
public NetEntity NetEntity;
|
|
||||||
|
|
||||||
public HolopadContactButton()
|
|
||||||
{
|
|
||||||
HorizontalExpand = true;
|
|
||||||
SetHeight = 32;
|
|
||||||
Margin = new Thickness(0f, 1f, 0f, 1f);
|
|
||||||
ReservesSpace = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateValues(NetEntity netEntity, string label)
|
|
||||||
{
|
|
||||||
NetEntity = netEntity;
|
|
||||||
Text = Loc.GetString("holopad-window-contact-label", ("label", label));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int AlphabeticalSort(KeyValuePair<NetEntity, string> x, KeyValuePair<NetEntity, string> y)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(x.Value))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(y.Value))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return x.Value.CompareTo(y.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -191,15 +191,9 @@ namespace Content.Client.Inventory
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (ev.Function == ContentKeyFunctions.ExamineEntity)
|
if (ev.Function == ContentKeyFunctions.ExamineEntity)
|
||||||
{
|
|
||||||
_examine.DoExamine(slot.Entity.Value);
|
_examine.DoExamine(slot.Entity.Value);
|
||||||
ev.Handle();
|
|
||||||
}
|
|
||||||
else if (ev.Function == EngineKeyFunctions.UseSecondary)
|
else if (ev.Function == EngineKeyFunctions.UseSecondary)
|
||||||
{
|
|
||||||
_ui.GetUIController<VerbMenuUIController>().OpenVerbMenu(slot.Entity.Value);
|
_ui.GetUIController<VerbMenuUIController>().OpenVerbMenu(slot.Entity.Value);
|
||||||
ev.Handle();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddInventoryButton(EntityUid invUid, string slotId, InventoryComponent inv)
|
private void AddInventoryButton(EntityUid invUid, string slotId, InventoryComponent inv)
|
||||||
|
|||||||
@@ -21,22 +21,6 @@ public sealed class HandheldLightSystem : SharedHandheldLightSystem
|
|||||||
SubscribeLocalEvent<HandheldLightComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
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)
|
private void OnAppearanceChange(EntityUid uid, HandheldLightComponent? component, ref AppearanceChangeEvent args)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref component))
|
if (!Resolve(uid, ref component))
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ namespace Content.Client.Lobby
|
|||||||
return;
|
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;
|
string text;
|
||||||
|
|
||||||
if (_gameTicker.Paused)
|
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");
|
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
|
else
|
||||||
{
|
{
|
||||||
text = $"{difference.Minutes}:{difference.Seconds:D2}";
|
text = $"{difference.Minutes}:{difference.Seconds:D2}";
|
||||||
|
|||||||
@@ -455,21 +455,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
|||||||
{
|
{
|
||||||
EntityUid dummyEnt;
|
EntityUid dummyEnt;
|
||||||
|
|
||||||
EntProtoId? previewEntity = null;
|
if (humanoid is not null)
|
||||||
if (humanoid != null && jobClothes)
|
|
||||||
{
|
|
||||||
job ??= GetPreferredJob(humanoid);
|
|
||||||
|
|
||||||
previewEntity = job.JobPreviewEntity ?? (EntProtoId?)job?.JobEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previewEntity != null)
|
|
||||||
{
|
|
||||||
// Special type like borg or AI, do not spawn a human just spawn the entity.
|
|
||||||
dummyEnt = EntityManager.SpawnEntity(previewEntity, MapCoordinates.Nullspace);
|
|
||||||
return dummyEnt;
|
|
||||||
}
|
|
||||||
else if (humanoid is not null)
|
|
||||||
{
|
{
|
||||||
var dummy = _prototypeManager.Index<SpeciesPrototype>(humanoid.Species).DollPrototype;
|
var dummy = _prototypeManager.Index<SpeciesPrototype>(humanoid.Species).DollPrototype;
|
||||||
dummyEnt = EntityManager.SpawnEntity(dummy, MapCoordinates.Nullspace);
|
dummyEnt = EntityManager.SpawnEntity(dummy, MapCoordinates.Nullspace);
|
||||||
@@ -483,8 +469,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
|
|||||||
|
|
||||||
if (humanoid != null && jobClothes)
|
if (humanoid != null && jobClothes)
|
||||||
{
|
{
|
||||||
DebugTools.Assert(job != null);
|
job ??= GetPreferredJob(humanoid);
|
||||||
|
|
||||||
GiveDummyJobClothes(dummyEnt, humanoid, job);
|
GiveDummyJobClothes(dummyEnt, humanoid, job);
|
||||||
|
|
||||||
if (_prototypeManager.HasIndex<RoleLoadoutPrototype>(LoadoutSystem.GetJobPrototype(job.ID)))
|
if (_prototypeManager.HasIndex<RoleLoadoutPrototype>(LoadoutSystem.GetJobPrototype(job.ID)))
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
SeparationOverride="0"
|
SeparationOverride="0"
|
||||||
Name="InternalHBox">
|
Name="InternalHBox">
|
||||||
<SpriteView Scale="2 2"
|
<SpriteView Scale="2 2"
|
||||||
Margin="0 4 4 4"
|
|
||||||
OverrideDirection="South"
|
OverrideDirection="South"
|
||||||
Name="View"/>
|
Name="View"/>
|
||||||
<Label Name="DescriptionLabel"
|
<Label Name="DescriptionLabel"
|
||||||
|
|||||||
@@ -140,7 +140,7 @@
|
|||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<!-- Right side -->
|
<!-- Right side -->
|
||||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" VerticalAlignment="Center">
|
<BoxContainer Orientation="Vertical" VerticalExpand="True" VerticalAlignment="Center">
|
||||||
<SpriteView Name="SpriteView" Scale="8 8" Margin="4" SizeFlagsStretchRatio="1" />
|
<SpriteView Name="SpriteView" Scale="8 8" SizeFlagsStretchRatio="1" />
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 5">
|
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 5">
|
||||||
<Button Name="SpriteRotateLeft" Text="◀" StyleClasses="OpenRight" />
|
<Button Name="SpriteRotateLeft" Text="◀" StyleClasses="OpenRight" />
|
||||||
<cc:VSeparator Margin="2 0 3 0" />
|
<cc:VSeparator Margin="2 0 3 0" />
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
using Content.Shared.Movement.Components;
|
|
||||||
using Content.Shared.Movement.Systems;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Client.Movement.Systems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Controls the switching of motion and standing still animation
|
|
||||||
/// </summary>
|
|
||||||
public sealed class ClientSpriteMovementSystem : SharedSpriteMovementSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
|
|
||||||
private EntityQuery<SpriteComponent> _spriteQuery;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
_spriteQuery = GetEntityQuery<SpriteComponent>();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<SpriteMovementComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAfterAutoHandleState(Entity<SpriteMovementComponent> ent, ref AfterAutoHandleStateEvent args)
|
|
||||||
{
|
|
||||||
if (!_spriteQuery.TryGetComponent(ent, out var sprite))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ent.Comp.IsMoving)
|
|
||||||
{
|
|
||||||
foreach (var (layer, state) in ent.Comp.MovementLayers)
|
|
||||||
{
|
|
||||||
sprite.LayerSetData(layer, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var (layer, state) in ent.Comp.NoMovementLayers)
|
|
||||||
{
|
|
||||||
sprite.LayerSetData(layer, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
51
Content.Client/Movement/Systems/SpriteMovementSystem.cs
Normal file
51
Content.Client/Movement/Systems/SpriteMovementSystem.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using Content.Shared.Movement.Components;
|
||||||
|
using Content.Shared.Movement.Events;
|
||||||
|
using Content.Shared.Movement.Systems;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Client.Movement.Systems;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles setting sprite states based on whether an entity has movement input.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SpriteMovementSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
|
||||||
|
private EntityQuery<SpriteComponent> _spriteQuery;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<SpriteMovementComponent, MoveInputEvent>(OnSpriteMoveInput);
|
||||||
|
_spriteQuery = GetEntityQuery<SpriteComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSpriteMoveInput(EntityUid uid, SpriteMovementComponent component, ref MoveInputEvent args)
|
||||||
|
{
|
||||||
|
if (!_timing.IsFirstTimePredicted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var oldMoving = (SharedMoverController.GetNormalizedMovement(args.OldMovement) & MoveButtons.AnyDirection) != MoveButtons.None;
|
||||||
|
var moving = (SharedMoverController.GetNormalizedMovement(args.Entity.Comp.HeldMoveButtons) & MoveButtons.AnyDirection) != MoveButtons.None;
|
||||||
|
|
||||||
|
if (oldMoving == moving || !_spriteQuery.TryGetComponent(uid, out var sprite))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (moving)
|
||||||
|
{
|
||||||
|
foreach (var (layer, state) in component.MovementLayers)
|
||||||
|
{
|
||||||
|
sprite.LayerSetData(layer, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var (layer, state) in component.NoMovementLayers)
|
||||||
|
{
|
||||||
|
sprite.LayerSetData(layer, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,7 @@ public sealed partial class StencilOverlay
|
|||||||
var matty = Matrix3x2.Multiply(matrix, invMatrix);
|
var matty = Matrix3x2.Multiply(matrix, invMatrix);
|
||||||
worldHandle.SetTransform(matty);
|
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
|
// Ignored tiles for stencil
|
||||||
if (_weather.CanWeatherAffect(grid.Owner, grid, tile))
|
if (_weather.CanWeatherAffect(grid.Owner, grid, tile))
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ public sealed partial class StencilOverlay : Overlay
|
|||||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||||
private readonly ParallaxSystem _parallax;
|
private readonly ParallaxSystem _parallax;
|
||||||
private readonly SharedTransformSystem _transform;
|
private readonly SharedTransformSystem _transform;
|
||||||
private readonly SharedMapSystem _map;
|
|
||||||
private readonly SpriteSystem _sprite;
|
private readonly SpriteSystem _sprite;
|
||||||
private readonly WeatherSystem _weather;
|
private readonly WeatherSystem _weather;
|
||||||
|
|
||||||
@@ -36,12 +35,11 @@ public sealed partial class StencilOverlay : Overlay
|
|||||||
|
|
||||||
private readonly ShaderInstance _shader;
|
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;
|
ZIndex = ParallaxSystem.ParallaxZIndex + 1;
|
||||||
_parallax = parallax;
|
_parallax = parallax;
|
||||||
_transform = transform;
|
_transform = transform;
|
||||||
_map = map;
|
|
||||||
_sprite = sprite;
|
_sprite = sprite;
|
||||||
_weather = weather;
|
_weather = weather;
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
|
|||||||
@@ -10,14 +10,13 @@ public sealed class StencilOverlaySystem : EntitySystem
|
|||||||
[Dependency] private readonly IOverlayManager _overlay = default!;
|
[Dependency] private readonly IOverlayManager _overlay = default!;
|
||||||
[Dependency] private readonly ParallaxSystem _parallax = default!;
|
[Dependency] private readonly ParallaxSystem _parallax = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
|
||||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||||
[Dependency] private readonly WeatherSystem _weather = default!;
|
[Dependency] private readonly WeatherSystem _weather = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
_overlay.AddOverlay(new StencilOverlay(_parallax, _transform, _map, _sprite, _weather));
|
_overlay.AddOverlay(new StencilOverlay(_parallax, _transform, _sprite, _weather));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using Robust.Client.UserInterface.Controls;
|
|||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Robust.Client.UserInterface.RichText;
|
using Robust.Client.UserInterface.RichText;
|
||||||
using Content.Client.UserInterface.RichText;
|
|
||||||
using Robust.Shared.Input;
|
using Robust.Shared.Input;
|
||||||
|
|
||||||
namespace Content.Client.Paper.UI
|
namespace Content.Client.Paper.UI
|
||||||
@@ -44,8 +43,7 @@ namespace Content.Client.Paper.UI
|
|||||||
typeof(BulletTag),
|
typeof(BulletTag),
|
||||||
typeof(ColorTag),
|
typeof(ColorTag),
|
||||||
typeof(HeadingTag),
|
typeof(HeadingTag),
|
||||||
typeof(ItalicTag),
|
typeof(ItalicTag)
|
||||||
typeof(MonoTag)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public event Action<string>? OnSaved;
|
public event Action<string>? OnSaved;
|
||||||
|
|||||||
@@ -385,6 +385,26 @@ public partial class NavMapControl : MapGridControl
|
|||||||
if (PostWallDrawingAction != null)
|
if (PostWallDrawingAction != null)
|
||||||
PostWallDrawingAction.Invoke(handle);
|
PostWallDrawingAction.Invoke(handle);
|
||||||
|
|
||||||
|
// Beacons
|
||||||
|
if (_beacons.Pressed)
|
||||||
|
{
|
||||||
|
var rectBuffer = new Vector2(5f, 3f);
|
||||||
|
|
||||||
|
// Calculate font size for current zoom level
|
||||||
|
var fontSize = (int) Math.Round(1 / WorldRange * DefaultDisplayedRange * UIScale * _targetFontsize, 0);
|
||||||
|
var font = new VectorFont(_cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Bold.ttf"), fontSize);
|
||||||
|
|
||||||
|
foreach (var beacon in _navMap.Beacons.Values)
|
||||||
|
{
|
||||||
|
var position = beacon.Position - offset;
|
||||||
|
position = ScalePosition(position with { Y = -position.Y });
|
||||||
|
|
||||||
|
var textDimensions = handle.GetDimensions(font, beacon.Text, 1f);
|
||||||
|
handle.DrawRect(new UIBox2(position - textDimensions / 2 - rectBuffer, position + textDimensions / 2 + rectBuffer), BackgroundColor);
|
||||||
|
handle.DrawString(font, position - textDimensions / 2, beacon.Text, beacon.Color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var curTime = Timing.RealTime;
|
var curTime = Timing.RealTime;
|
||||||
var blinkFrequency = 1f / 1f;
|
var blinkFrequency = 1f / 1f;
|
||||||
var lit = curTime.TotalSeconds % blinkFrequency > blinkFrequency / 2f;
|
var lit = curTime.TotalSeconds % blinkFrequency > blinkFrequency / 2f;
|
||||||
@@ -423,31 +443,11 @@ public partial class NavMapControl : MapGridControl
|
|||||||
position = ScalePosition(new Vector2(position.X, -position.Y));
|
position = ScalePosition(new Vector2(position.X, -position.Y));
|
||||||
|
|
||||||
var scalingCoefficient = MinmapScaleModifier * float.Sqrt(MinimapScale);
|
var scalingCoefficient = MinmapScaleModifier * float.Sqrt(MinimapScale);
|
||||||
var positionOffset = new Vector2(scalingCoefficient * blip.Scale * blip.Texture.Width, scalingCoefficient * blip.Scale * blip.Texture.Height);
|
var positionOffset = new Vector2(scalingCoefficient * blip.Texture.Width, scalingCoefficient * blip.Texture.Height);
|
||||||
|
|
||||||
handle.DrawTextureRect(blip.Texture, new UIBox2(position - positionOffset, position + positionOffset), blip.Color);
|
handle.DrawTextureRect(blip.Texture, new UIBox2(position - positionOffset, position + positionOffset), blip.Color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Beacons
|
|
||||||
if (_beacons.Pressed)
|
|
||||||
{
|
|
||||||
var rectBuffer = new Vector2(5f, 3f);
|
|
||||||
|
|
||||||
// Calculate font size for current zoom level
|
|
||||||
var fontSize = (int)Math.Round(1 / WorldRange * DefaultDisplayedRange * UIScale * _targetFontsize, 0);
|
|
||||||
var font = new VectorFont(_cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Bold.ttf"), fontSize);
|
|
||||||
|
|
||||||
foreach (var beacon in _navMap.Beacons.Values)
|
|
||||||
{
|
|
||||||
var position = beacon.Position - offset;
|
|
||||||
position = ScalePosition(position with { Y = -position.Y });
|
|
||||||
|
|
||||||
var textDimensions = handle.GetDimensions(font, beacon.Text, 1f);
|
|
||||||
handle.DrawRect(new UIBox2(position - textDimensions / 2 - rectBuffer, position + textDimensions / 2 + rectBuffer), BackgroundColor);
|
|
||||||
handle.DrawString(font, position - textDimensions / 2, beacon.Text, beacon.Color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
@@ -689,9 +689,6 @@ public partial class NavMapControl : MapGridControl
|
|||||||
Vector2i foundTermius;
|
Vector2i foundTermius;
|
||||||
Vector2i foundOrigin;
|
Vector2i foundOrigin;
|
||||||
|
|
||||||
if (origin == terminus)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Does our new line end at the beginning of an existing line?
|
// Does our new line end at the beginning of an existing line?
|
||||||
if (lookup.Remove(terminus, out foundTermius))
|
if (lookup.Remove(terminus, out foundTermius))
|
||||||
{
|
{
|
||||||
@@ -742,15 +739,13 @@ public struct NavMapBlip
|
|||||||
public Color Color;
|
public Color Color;
|
||||||
public bool Blinks;
|
public bool Blinks;
|
||||||
public bool Selectable;
|
public bool Selectable;
|
||||||
public float Scale;
|
|
||||||
|
|
||||||
public NavMapBlip(EntityCoordinates coordinates, Texture texture, Color color, bool blinks, bool selectable = true, float scale = 1f)
|
public NavMapBlip(EntityCoordinates coordinates, Texture texture, Color color, bool blinks, bool selectable = true)
|
||||||
{
|
{
|
||||||
Coordinates = coordinates;
|
Coordinates = coordinates;
|
||||||
Texture = texture;
|
Texture = texture;
|
||||||
Color = color;
|
Color = color;
|
||||||
Blinks = blinks;
|
Blinks = blinks;
|
||||||
Selectable = selectable;
|
Selectable = selectable;
|
||||||
Scale = scale;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using Robust.Shared.Utility;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Vector4 = Robust.Shared.Maths.Vector4;
|
|
||||||
|
|
||||||
namespace Content.Client.Power;
|
namespace Content.Client.Power;
|
||||||
|
|
||||||
@@ -105,26 +104,6 @@ public sealed partial class PowerMonitoringWindow
|
|||||||
// Update power value
|
// Update power value
|
||||||
// Don't use SI prefixes, just give the number in W, so that it is readily apparent which consumer is using a lot of power.
|
// Don't use SI prefixes, just give the number in W, so that it is readily apparent which consumer is using a lot of power.
|
||||||
button.PowerValue.Text = Loc.GetString("power-monitoring-window-button-value", ("value", Math.Round(entry.PowerValue).ToString("N0")));
|
button.PowerValue.Text = Loc.GetString("power-monitoring-window-button-value", ("value", Math.Round(entry.PowerValue).ToString("N0")));
|
||||||
|
|
||||||
// Update battery level if applicable
|
|
||||||
if (entry.BatteryLevel != null)
|
|
||||||
{
|
|
||||||
button.BatteryLevel.Value = entry.BatteryLevel.Value;
|
|
||||||
button.BatteryLevel.Visible = true;
|
|
||||||
|
|
||||||
button.BatteryPercentage.Text = entry.BatteryLevel.Value.ToString("P0");
|
|
||||||
button.BatteryPercentage.Visible = true;
|
|
||||||
|
|
||||||
// Set progress bar color based on percentage
|
|
||||||
var color = Color.FromHsv(new Vector4(entry.BatteryLevel.Value * 0.33f, 1, 1, 1));
|
|
||||||
|
|
||||||
button.BatteryLevel.ForegroundStyleBoxOverride = new StyleBoxFlat { BackgroundColor = color };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
button.BatteryLevel.Visible = false;
|
|
||||||
button.BatteryPercentage.Visible = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateEntrySourcesOrLoads(BoxContainer masterContainer, BoxContainer currentContainer, PowerMonitoringConsoleEntry[]? entries, SpriteSpecifier.Texture icon)
|
private void UpdateEntrySourcesOrLoads(BoxContainer masterContainer, BoxContainer currentContainer, PowerMonitoringConsoleEntry[]? entries, SpriteSpecifier.Texture icon)
|
||||||
@@ -464,11 +443,6 @@ public sealed class PowerMonitoringButton : Button
|
|||||||
public BoxContainer MainContainer;
|
public BoxContainer MainContainer;
|
||||||
public TextureRect TextureRect;
|
public TextureRect TextureRect;
|
||||||
public Label NameLocalized;
|
public Label NameLocalized;
|
||||||
|
|
||||||
public ProgressBar BatteryLevel;
|
|
||||||
public PanelContainer BackgroundPanel;
|
|
||||||
public Label BatteryPercentage;
|
|
||||||
|
|
||||||
public Label PowerValue;
|
public Label PowerValue;
|
||||||
|
|
||||||
public PowerMonitoringButton()
|
public PowerMonitoringButton()
|
||||||
@@ -504,49 +478,6 @@ public sealed class PowerMonitoringButton : Button
|
|||||||
|
|
||||||
MainContainer.AddChild(NameLocalized);
|
MainContainer.AddChild(NameLocalized);
|
||||||
|
|
||||||
BatteryLevel = new ProgressBar()
|
|
||||||
{
|
|
||||||
SetWidth = 47f,
|
|
||||||
SetHeight = 20f,
|
|
||||||
Margin = new Thickness(15, 0, 0, 0),
|
|
||||||
MaxValue = 1,
|
|
||||||
Visible = false,
|
|
||||||
BackgroundStyleBoxOverride = new StyleBoxFlat { BackgroundColor = Color.Black },
|
|
||||||
};
|
|
||||||
|
|
||||||
MainContainer.AddChild(BatteryLevel);
|
|
||||||
|
|
||||||
BackgroundPanel = new PanelContainer
|
|
||||||
{
|
|
||||||
// Draw a half-transparent box over the battery level to make the text more readable.
|
|
||||||
PanelOverride = new StyleBoxFlat
|
|
||||||
{
|
|
||||||
BackgroundColor = new Color(0, 0, 0, 0.9f)
|
|
||||||
},
|
|
||||||
HorizontalAlignment = HAlignment.Center,
|
|
||||||
VerticalAlignment = VAlignment.Center,
|
|
||||||
HorizontalExpand = true,
|
|
||||||
VerticalExpand = true,
|
|
||||||
// Box is undersized perfectly compared to the progress bar, so a little bit of the unaffected progress bar is visible.
|
|
||||||
SetSize = new Vector2(43f, 16f)
|
|
||||||
};
|
|
||||||
|
|
||||||
BatteryLevel.AddChild(BackgroundPanel);
|
|
||||||
|
|
||||||
BatteryPercentage = new Label()
|
|
||||||
{
|
|
||||||
VerticalAlignment = VAlignment.Center,
|
|
||||||
HorizontalAlignment = HAlignment.Center,
|
|
||||||
Align = Label.AlignMode.Center,
|
|
||||||
SetWidth = 45f,
|
|
||||||
MinWidth = 20f,
|
|
||||||
Margin = new Thickness(10, -4, 10, 0),
|
|
||||||
ClipText = true,
|
|
||||||
Visible = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
BackgroundPanel.AddChild(BatteryPercentage);
|
|
||||||
|
|
||||||
PowerValue = new Label()
|
PowerValue = new Label()
|
||||||
{
|
{
|
||||||
HorizontalAlignment = HAlignment.Right,
|
HorizontalAlignment = HAlignment.Right,
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ namespace Content.Client.Sandbox
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try copy tile.
|
// Try copy tile.
|
||||||
|
|
||||||
if (!_map.TryFindGridAt(_transform.ToMapCoordinates(coords), out var gridUid, out var grid) || !_mapSystem.TryGetTileRef(gridUid, grid, coords, out var tileRef))
|
if (!_map.TryFindGridAt(_transform.ToMapCoordinates(coords), out var gridUid, out var grid) || !_mapSystem.TryGetTileRef(gridUid, grid, coords, out var tileRef))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -157,5 +157,10 @@ namespace Content.Client.Sandbox
|
|||||||
{
|
{
|
||||||
_consoleHost.ExecuteCommand("physics shapes");
|
_consoleHost.ExecuteCommand("physics shapes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void MachineLinking()
|
||||||
|
{
|
||||||
|
_consoleHost.ExecuteCommand("signallink");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ public sealed partial class SensorMonitoringWindow : FancyWindow, IComputerWindo
|
|||||||
public SensorMonitoringWindow()
|
public SensorMonitoringWindow()
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateState(ConsoleUIState state)
|
public void UpdateState(ConsoleUIState state)
|
||||||
|
|||||||
@@ -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 rator = Maps.GetAllTilesEnumerator(grid.Owner, grid.Comp);
|
||||||
var minimapScale = MinimapScale;
|
var minimapScale = MinimapScale;
|
||||||
@@ -264,7 +264,7 @@ public partial class BaseShuttleControl : MapGridControl
|
|||||||
Extensions.EnsureLength(ref _allVertices, totalData);
|
Extensions.EnsureLength(ref _allVertices, totalData);
|
||||||
|
|
||||||
_drawJob.MidPoint = midpoint;
|
_drawJob.MidPoint = midpoint;
|
||||||
_drawJob.Matrix = gridToView;
|
_drawJob.Matrix = matrix;
|
||||||
_drawJob.MinimapScale = minimapScale;
|
_drawJob.MinimapScale = minimapScale;
|
||||||
_drawJob.Vertices = gridData.Vertices;
|
_drawJob.Vertices = gridData.Vertices;
|
||||||
_drawJob.ScaledVertices = _allVertices;
|
_drawJob.ScaledVertices = _allVertices;
|
||||||
@@ -286,7 +286,7 @@ public partial class BaseShuttleControl : MapGridControl
|
|||||||
|
|
||||||
private record struct GridDrawJob : IParallelRobustJob
|
private record struct GridDrawJob : IParallelRobustJob
|
||||||
{
|
{
|
||||||
public int BatchSize => 64;
|
public int BatchSize => 16;
|
||||||
|
|
||||||
public float MinimapScale;
|
public float MinimapScale;
|
||||||
public Vector2 MidPoint;
|
public Vector2 MidPoint;
|
||||||
@@ -297,7 +297,12 @@ public partial class BaseShuttleControl : MapGridControl
|
|||||||
|
|
||||||
public void Execute(int index)
|
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!;
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
private SharedTransformSystem _xformSystem;
|
private SharedTransformSystem _xformSystem;
|
||||||
|
|
||||||
private EntityUid? _consoleEntity; // Entity of controlling console
|
|
||||||
private EntityUid? _shuttleEntity;
|
private EntityUid? _shuttleEntity;
|
||||||
|
|
||||||
public NavScreen()
|
public NavScreen()
|
||||||
@@ -36,12 +35,6 @@ public sealed partial class NavScreen : BoxContainer
|
|||||||
_shuttleEntity = shuttle;
|
_shuttleEntity = shuttle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConsole(EntityUid? console)
|
|
||||||
{
|
|
||||||
_consoleEntity = console;
|
|
||||||
NavRadar.SetConsole(console);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnIFFTogglePressed(BaseButton.ButtonEventArgs args)
|
private void OnIFFTogglePressed(BaseButton.ButtonEventArgs args)
|
||||||
{
|
{
|
||||||
NavRadar.ShowIFF ^= true;
|
NavRadar.ShowIFF ^= true;
|
||||||
|
|||||||
@@ -138,7 +138,6 @@ public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
|||||||
{
|
{
|
||||||
var coordinates = _entManager.GetCoordinates(cState.NavState.Coordinates);
|
var coordinates = _entManager.GetCoordinates(cState.NavState.Coordinates);
|
||||||
NavContainer.SetShuttle(coordinates?.EntityId);
|
NavContainer.SetShuttle(coordinates?.EntityId);
|
||||||
NavContainer.SetConsole(owner);
|
|
||||||
MapContainer.SetShuttle(coordinates?.EntityId);
|
MapContainer.SetShuttle(coordinates?.EntityId);
|
||||||
MapContainer.SetConsole(owner);
|
MapContainer.SetConsole(owner);
|
||||||
|
|
||||||
|
|||||||
@@ -107,19 +107,16 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
|||||||
DrawCircles(handle);
|
DrawCircles(handle);
|
||||||
var gridNent = EntManager.GetNetEntity(GridEntity);
|
var gridNent = EntManager.GetNetEntity(GridEntity);
|
||||||
var mapPos = _xformSystem.ToMapCoordinates(_coordinates.Value);
|
var mapPos = _xformSystem.ToMapCoordinates(_coordinates.Value);
|
||||||
var ourGridToWorld = _xformSystem.GetWorldMatrix(GridEntity.Value);
|
var ourGridMatrix = _xformSystem.GetWorldMatrix(GridEntity.Value);
|
||||||
var selectedDockToOurGrid = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, Angle.Zero);
|
var dockMatrix = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, Angle.Zero);
|
||||||
var selectedDockToWorld = Matrix3x2.Multiply(selectedDockToOurGrid, ourGridToWorld);
|
var worldFromDock = Matrix3x2.Multiply(dockMatrix, ourGridMatrix);
|
||||||
|
|
||||||
Box2 viewBoundsWorld = Matrix3Helpers.TransformBox(selectedDockToWorld, new Box2(-WorldRangeVector, WorldRangeVector));
|
Matrix3x2.Invert(worldFromDock, out var offsetMatrix);
|
||||||
|
|
||||||
Matrix3x2.Invert(selectedDockToWorld, out var worldToSelectedDock);
|
|
||||||
var selectedDockToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector);
|
|
||||||
|
|
||||||
// Draw nearby grids
|
// Draw nearby grids
|
||||||
var controlBounds = PixelSizeBox;
|
var controlBounds = PixelSizeBox;
|
||||||
_grids.Clear();
|
_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.
|
// offset the dotted-line position to the bounds.
|
||||||
Vector2? viewedDockPos = _viewedState != null ? MidPointVector : null;
|
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))
|
if (grid.Owner != GridEntity && !_shuttles.CanDraw(grid.Owner, iffComp: iffComp))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var curGridToWorld = _xformSystem.GetWorldMatrix(grid.Owner);
|
var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner);
|
||||||
var curGridToView = curGridToWorld * worldToSelectedDock * selectedDockToView;
|
var matty = Matrix3x2.Multiply(gridMatrix, offsetMatrix);
|
||||||
var color = _shuttles.GetIFFColor(grid.Owner, grid.Owner == GridEntity, component: iffComp);
|
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
|
// Draw any docks on that grid
|
||||||
if (!DockState.Docks.TryGetValue(EntManager.GetNetEntity(grid), out var gridDocks))
|
if (!DockState.Docks.TryGetValue(EntManager.GetNetEntity(grid), out var gridDocks))
|
||||||
@@ -154,24 +151,23 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
|||||||
if (ViewedDock == dock.Entity)
|
if (ViewedDock == dock.Entity)
|
||||||
continue;
|
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 otherDockRotation = Matrix3Helpers.CreateRotation(dock.Angle);
|
||||||
var dockRenderBoundsLocal = new Box2(-0.5f, -0.7f, 0.5f, 0.5f);
|
var scaledPos = ScalePosition(position with {Y = -position.Y});
|
||||||
var currentDockToCurGrid = Matrix3Helpers.CreateTransform(dock.Coordinates.Position, dock.Angle);
|
|
||||||
var currentDockToWorld = Matrix3x2.Multiply(currentDockToCurGrid, curGridToWorld);
|
if (!controlBounds.Contains(scaledPos.Floored()))
|
||||||
var dockRenderBoundsWorld = Matrix3Helpers.TransformBox(currentDockToWorld, dockRenderBoundsLocal);
|
|
||||||
if (!viewBoundsWorld.Intersects(dockRenderBoundsWorld))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Draw the dock's collision
|
||||||
var collisionBL = Vector2.Transform(dock.Coordinates.Position +
|
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 +
|
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 +
|
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 +
|
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[]
|
var verts = new[]
|
||||||
{
|
{
|
||||||
@@ -185,6 +181,13 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
|||||||
collisionBL,
|
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 collisionCenter = verts[0] + verts[1] + verts[3] + verts[5];
|
||||||
|
|
||||||
var otherDockConnection = Color.ToSrgb(Color.Pink);
|
var otherDockConnection = Color.ToSrgb(Color.Pink);
|
||||||
@@ -192,10 +195,10 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
|||||||
handle.DrawPrimitives(DrawPrimitiveTopology.LineList, verts, otherDockConnection);
|
handle.DrawPrimitives(DrawPrimitiveTopology.LineList, verts, otherDockConnection);
|
||||||
|
|
||||||
// Draw the dock itself
|
// Draw the dock itself
|
||||||
var dockBL = 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), curGridToView);
|
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), curGridToView);
|
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), curGridToView);
|
var dockTL = Vector2.Transform(dock.Coordinates.Position + new Vector2(-0.5f, 0.5f), matty);
|
||||||
|
|
||||||
verts = new[]
|
verts = new[]
|
||||||
{
|
{
|
||||||
@@ -209,6 +212,13 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
|||||||
dockBL
|
dockBL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (var i = 0; i < verts.Length; i++)
|
||||||
|
{
|
||||||
|
var vert = verts[i];
|
||||||
|
vert.Y = -vert.Y;
|
||||||
|
verts[i] = ScalePosition(vert);
|
||||||
|
}
|
||||||
|
|
||||||
Color otherDockColor;
|
Color otherDockColor;
|
||||||
|
|
||||||
if (HighlightedDock == dock.Entity)
|
if (HighlightedDock == dock.Entity)
|
||||||
@@ -243,11 +253,9 @@ public sealed partial class ShuttleDockControl : BaseShuttleControl
|
|||||||
collisionCenter /= 4;
|
collisionCenter /= 4;
|
||||||
var range = viewedDockPos.Value - collisionCenter;
|
var range = viewedDockPos.Value - collisionCenter;
|
||||||
|
|
||||||
var maxRange = SharedDockingSystem.DockingHiglightRange * MinimapScale;
|
if (range.Length() < SharedDockingSystem.DockingHiglightRange * MinimapScale)
|
||||||
var maxRangeSq = maxRange * maxRange;
|
|
||||||
if (range.LengthSquared() < maxRangeSq)
|
|
||||||
{
|
{
|
||||||
if (dock.GridDockedWith == null)
|
if (_viewedState?.GridDockedWith == null)
|
||||||
{
|
{
|
||||||
var coordsOne = EntManager.GetCoordinates(_viewedState!.Coordinates);
|
var coordsOne = EntManager.GetCoordinates(_viewedState!.Coordinates);
|
||||||
var coordsTwo = EntManager.GetCoordinates(dock.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 rotA = _xformSystem.GetWorldRotation(coordsOne.EntityId) + _viewedState!.Angle;
|
||||||
var rotB = _xformSystem.GetWorldRotation(coordsTwo.EntityId) + dock.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 inAlignment = _dockSystem.InAlignment(mapOne, rotA, mapTwo, rotB);
|
||||||
var maxDockDistSq = SharedDockingSystem.DockRange * SharedDockingSystem.DockRange;
|
var canDock = distance < SharedDockingSystem.DockRange && inAlignment;
|
||||||
var canDock = distanceSq < maxDockDistSq && inAlignment;
|
|
||||||
|
|
||||||
if (dockButton != null)
|
if (dockButton != null)
|
||||||
dockButton.Disabled = !canDock || !canDockChange;
|
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.
|
// Because it's being layed out top-down we have to arrange for first frame.
|
||||||
container.Arrange(PixelRect);
|
container.Arrange(PixelRect);
|
||||||
var dockPositionInView = Vector2.Transform(dock.Coordinates.Position, curGridToView);
|
var containerPos = scaledPos / UIScale - container.DesiredSize / 2 - new Vector2(0f, 0.75f) * MinimapScale;
|
||||||
var containerPos = dockPositionInView / UIScale - container.DesiredSize / 2 - new Vector2(0f, 0.75f) * MinimapScale;
|
|
||||||
SetPosition(container, containerPos);
|
SetPosition(container, containerPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,6 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private EntityCoordinates? _coordinates;
|
private EntityCoordinates? _coordinates;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Entity of controlling console
|
|
||||||
/// </summary>
|
|
||||||
private EntityUid? _consoleEntity;
|
|
||||||
|
|
||||||
private Angle? _rotation;
|
private Angle? _rotation;
|
||||||
|
|
||||||
private Dictionary<NetEntity, List<DockingPortState>> _docks = new();
|
private Dictionary<NetEntity, List<DockingPortState>> _docks = new();
|
||||||
@@ -62,11 +57,6 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
|||||||
_rotation = angle;
|
_rotation = angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConsole(EntityUid? consoleEntity)
|
|
||||||
{
|
|
||||||
_consoleEntity = consoleEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
|
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
|
||||||
{
|
{
|
||||||
base.KeyBindUp(args);
|
base.KeyBindUp(args);
|
||||||
@@ -149,35 +139,40 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mapPos = _transform.ToMapCoordinates(_coordinates.Value);
|
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 ourEntRot = RotateWithEntity ? _transform.GetWorldRotation(xform) : _rotation.Value;
|
||||||
var ourEntMatrix = Matrix3Helpers.CreateTransform(_transform.GetWorldPosition(xform), ourEntRot);
|
var ourEntMatrix = Matrix3Helpers.CreateTransform(_transform.GetWorldPosition(xform), ourEntRot);
|
||||||
var shuttleToWorld = Matrix3x2.Multiply(posMatrix, ourEntMatrix);
|
var ourWorldMatrix = Matrix3x2.Multiply(posMatrix, ourEntMatrix);
|
||||||
Matrix3x2.Invert(shuttleToWorld, out var worldToShuttle);
|
Matrix3x2.Invert(ourWorldMatrix, out var ourWorldMatrixInvert);
|
||||||
var shuttleToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector);
|
|
||||||
|
|
||||||
// Draw our grid in detail
|
// Draw our grid in detail
|
||||||
var ourGridId = xform.GridUid;
|
var ourGridId = xform.GridUid;
|
||||||
if (EntManager.TryGetComponent<MapGridComponent>(ourGridId, out var ourGrid) &&
|
if (EntManager.TryGetComponent<MapGridComponent>(ourGridId, out var ourGrid) &&
|
||||||
fixturesQuery.HasComponent(ourGridId.Value))
|
fixturesQuery.HasComponent(ourGridId.Value))
|
||||||
{
|
{
|
||||||
var ourGridToWorld = _transform.GetWorldMatrix(ourGridId.Value);
|
var ourGridMatrix = _transform.GetWorldMatrix(ourGridId.Value);
|
||||||
var ourGridToShuttle = Matrix3x2.Multiply(ourGridToWorld, worldToShuttle);
|
var matrix = Matrix3x2.Multiply(ourGridMatrix, ourWorldMatrixInvert);
|
||||||
var ourGridToView = ourGridToShuttle * shuttleToView;
|
|
||||||
var color = _shuttles.GetIFFColor(ourGridId.Value, self: true);
|
var color = _shuttles.GetIFFColor(ourGridId.Value, self: true);
|
||||||
|
|
||||||
DrawGrid(handle, ourGridToView, (ourGridId.Value, ourGrid), color);
|
DrawGrid(handle, matrix, (ourGridId.Value, ourGrid), color);
|
||||||
DrawDocks(handle, ourGridId.Value, ourGridToView);
|
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
|
// Draw radar position on the station
|
||||||
|
var radarPos = invertedPosition;
|
||||||
const float radarVertRadius = 2f;
|
const float radarVertRadius = 2f;
|
||||||
|
|
||||||
var radarPosVerts = new Vector2[]
|
var radarPosVerts = new Vector2[]
|
||||||
{
|
{
|
||||||
ScalePosition(new Vector2(0f, -radarVertRadius)),
|
ScalePosition(radarPos + new Vector2(0f, -radarVertRadius)),
|
||||||
ScalePosition(new Vector2(radarVertRadius / 2f, 0f)),
|
ScalePosition(radarPos + new Vector2(radarVertRadius / 2f, 0f)),
|
||||||
ScalePosition(new Vector2(0f, radarVertRadius)),
|
ScalePosition(radarPos + new Vector2(0f, radarVertRadius)),
|
||||||
ScalePosition(new Vector2(radarVertRadius / -2f, 0f)),
|
ScalePosition(radarPos + new Vector2(radarVertRadius / -2f, 0f)),
|
||||||
};
|
};
|
||||||
|
|
||||||
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, radarPosVerts, Color.Lime);
|
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, radarPosVerts, Color.Lime);
|
||||||
@@ -202,8 +197,8 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
|||||||
if (!_shuttles.CanDraw(gUid, gridBody, iff))
|
if (!_shuttles.CanDraw(gUid, gridBody, iff))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var curGridToWorld = _transform.GetWorldMatrix(gUid);
|
var gridMatrix = _transform.GetWorldMatrix(gUid);
|
||||||
var curGridToView = curGridToWorld * worldToShuttle * shuttleToView;
|
var matty = Matrix3x2.Multiply(gridMatrix, ourWorldMatrixInvert);
|
||||||
|
|
||||||
var labelColor = _shuttles.GetIFFColor(grid, self: false, iff);
|
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);
|
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 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 distance = gridCentre.Length();
|
||||||
var labelText = Loc.GetString("shuttle-console-iff-label", ("name", labelName),
|
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)
|
// y-offset the control to always render below the grid (vertically)
|
||||||
var yOffset = Math.Max(gridBounds.Height, gridBounds.Width) * MinimapScale / 1.8f;
|
var yOffset = Math.Max(gridBounds.Height, gridBounds.Width) * MinimapScale / 1.8f;
|
||||||
|
|
||||||
// The actual position in the UI.
|
// The actual position in the UI. We centre the label by offsetting the matrix position
|
||||||
var gridScaledPosition = gridCentre - new Vector2(0, -yOffset);
|
// 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
|
// 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
|
// 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
|
// Detailed view
|
||||||
var gridAABB = curGridToWorld.TransformBox(grid.Comp.LocalAABB);
|
var gridAABB = gridMatrix.TransformBox(grid.Comp.LocalAABB);
|
||||||
|
|
||||||
// Skip drawing if it's out of range.
|
// Skip drawing if it's out of range.
|
||||||
if (!gridAABB.Intersects(viewAABB))
|
if (!gridAABB.Intersects(viewAABB))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
DrawGrid(handle, curGridToView, grid, labelColor);
|
DrawGrid(handle, matty, grid, labelColor);
|
||||||
DrawDocks(handle, gUid, curGridToView);
|
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)
|
if (!ShowDocks)
|
||||||
return;
|
return;
|
||||||
@@ -300,32 +283,33 @@ public sealed partial class ShuttleNavControl : BaseShuttleControl
|
|||||||
const float DockScale = 0.6f;
|
const float DockScale = 0.6f;
|
||||||
var nent = EntManager.GetNetEntity(uid);
|
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))
|
if (_docks.TryGetValue(nent, out var docks))
|
||||||
{
|
{
|
||||||
foreach (var state in docks)
|
foreach (var state in docks)
|
||||||
{
|
{
|
||||||
var position = state.Coordinates.Position;
|
var position = state.Coordinates.Position;
|
||||||
|
var uiPosition = Vector2.Transform(position, matrix);
|
||||||
|
|
||||||
var positionInView = Vector2.Transform(position, gridToView);
|
if (uiPosition.Length() > (WorldRange * 2f) - DockScale)
|
||||||
if (!viewBounds.Contains(positionInView))
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
var color = Color.ToSrgb(Color.Magenta);
|
var color = Color.ToSrgb(Color.Magenta);
|
||||||
|
|
||||||
var verts = new[]
|
var verts = new[]
|
||||||
{
|
{
|
||||||
Vector2.Transform(position + new Vector2(-DockScale, -DockScale), gridToView),
|
Vector2.Transform(position + new Vector2(-DockScale, -DockScale), matrix),
|
||||||
Vector2.Transform(position + new Vector2(DockScale, -DockScale), gridToView),
|
Vector2.Transform(position + new Vector2(DockScale, -DockScale), matrix),
|
||||||
Vector2.Transform(position + new Vector2(DockScale, DockScale), gridToView),
|
Vector2.Transform(position + new Vector2(DockScale, DockScale), matrix),
|
||||||
Vector2.Transform(position + new Vector2(-DockScale, DockScale), gridToView),
|
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.TriangleFan, verts, color.WithAlpha(0.8f));
|
||||||
handle.DrawPrimitives(DrawPrimitiveTopology.LineStrip, verts, color);
|
handle.DrawPrimitives(DrawPrimitiveTopology.LineStrip, verts, color);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using Robust.Client.UserInterface;
|
|||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Client.Silicons.Laws.Ui;
|
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 IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
[Dependency] private readonly EntityManager _entityManager = 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)
|
public LawDisplay(EntityUid uid, SiliconLaw law, HashSet<string>? radioChannels)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
@@ -53,12 +47,9 @@ public sealed partial class LawDisplay : Control
|
|||||||
MinWidth = 75,
|
MinWidth = 75,
|
||||||
};
|
};
|
||||||
|
|
||||||
_nextAllowedPress[localButton] = TimeSpan.Zero;
|
|
||||||
|
|
||||||
localButton.OnPressed += _ =>
|
localButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
_chatManager.SendMessage($"{lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Local);
|
_chatManager.SendMessage($"{lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Local);
|
||||||
_nextAllowedPress[localButton] = _timing.CurTime + PressCooldown;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LawAnnouncementButtons.AddChild(localButton);
|
LawAnnouncementButtons.AddChild(localButton);
|
||||||
@@ -80,8 +71,6 @@ public sealed partial class LawDisplay : Control
|
|||||||
MinWidth = 75,
|
MinWidth = 75,
|
||||||
};
|
};
|
||||||
|
|
||||||
_nextAllowedPress[radioChannelButton] = TimeSpan.Zero;
|
|
||||||
|
|
||||||
radioChannelButton.OnPressed += _ =>
|
radioChannelButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
switch (radioChannel)
|
switch (radioChannel)
|
||||||
@@ -91,21 +80,9 @@ public sealed partial class LawDisplay : Control
|
|||||||
default:
|
default:
|
||||||
_chatManager.SendMessage($"{SharedChatSystem.RadioChannelPrefix}{radioChannelProto.KeyCode} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); break;
|
_chatManager.SendMessage($"{SharedChatSystem.RadioChannelPrefix}{radioChannelProto.KeyCode} {lawIdentifierPlaintext}: {lawDescriptionPlaintext}", ChatSelectChannel.Radio); break;
|
||||||
}
|
}
|
||||||
_nextAllowedPress[radioChannelButton] = _timing.CurTime + PressCooldown;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LawAnnouncementButtons.AddChild(radioChannelButton);
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public sealed partial class StoreMenu : DefaultWindow
|
|||||||
foreach (var ((_, amount), proto) in currency)
|
foreach (var ((_, amount), proto) in currency)
|
||||||
{
|
{
|
||||||
balanceStr += Loc.GetString("store-ui-balance-display", ("amount", amount),
|
balanceStr += Loc.GetString("store-ui-balance-display", ("amount", amount),
|
||||||
("currency", Loc.GetString(proto.DisplayName, ("amount", 1)))) + "\n";
|
("currency", Loc.GetString(proto.DisplayName, ("amount", 1))));
|
||||||
}
|
}
|
||||||
|
|
||||||
BalanceInfo.SetMarkup(balanceStr.TrimEnd());
|
BalanceInfo.SetMarkup(balanceStr.TrimEnd());
|
||||||
@@ -63,10 +63,7 @@ public sealed partial class StoreMenu : DefaultWindow
|
|||||||
foreach (var type in currency)
|
foreach (var type in currency)
|
||||||
{
|
{
|
||||||
if (type.Value.CanWithdraw && type.Value.Cash != null && type.Key.Item2 > 0)
|
if (type.Value.CanWithdraw && type.Value.Cash != null && type.Key.Item2 > 0)
|
||||||
{
|
|
||||||
disabled = false;
|
disabled = false;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WithdrawButton.Disabled = disabled;
|
WithdrawButton.Disabled = disabled;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public sealed partial class StoreWithdrawWindow : DefaultWindow
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
private Dictionary<CurrencyPrototype, FixedPoint2> _validCurrencies = new();
|
private Dictionary<FixedPoint2, CurrencyPrototype> _validCurrencies = new();
|
||||||
private HashSet<CurrencyWithdrawButton> _buttons = new();
|
private HashSet<CurrencyWithdrawButton> _buttons = new();
|
||||||
public event Action<BaseButton.ButtonEventArgs, string, int>? OnWithdrawAttempt;
|
public event Action<BaseButton.ButtonEventArgs, string, int>? OnWithdrawAttempt;
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ public sealed partial class StoreWithdrawWindow : DefaultWindow
|
|||||||
if (!_prototypeManager.TryIndex(currency.Key, out var proto))
|
if (!_prototypeManager.TryIndex(currency.Key, out var proto))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_validCurrencies.Add(proto, currency.Value);
|
_validCurrencies.Add(currency.Value, proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
//this shouldn't ever happen but w/e
|
//this shouldn't ever happen but w/e
|
||||||
@@ -47,17 +47,14 @@ public sealed partial class StoreWithdrawWindow : DefaultWindow
|
|||||||
_buttons.Clear();
|
_buttons.Clear();
|
||||||
foreach (var currency in _validCurrencies)
|
foreach (var currency in _validCurrencies)
|
||||||
{
|
{
|
||||||
if (!currency.Key.CanWithdraw)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var button = new CurrencyWithdrawButton()
|
var button = new CurrencyWithdrawButton()
|
||||||
{
|
{
|
||||||
Id = currency.Key.ID,
|
Id = currency.Value.ID,
|
||||||
Amount = currency.Value,
|
Amount = currency.Key,
|
||||||
MinHeight = 20,
|
MinHeight = 20,
|
||||||
Text = Loc.GetString("store-withdraw-button-ui", ("currency",Loc.GetString(currency.Key.DisplayName, ("amount", currency.Value)))),
|
Text = Loc.GetString("store-withdraw-button-ui", ("currency",Loc.GetString(currency.Value.DisplayName, ("amount", currency.Key)))),
|
||||||
Disabled = false,
|
|
||||||
};
|
};
|
||||||
|
button.Disabled = false;
|
||||||
button.OnPressed += args =>
|
button.OnPressed += args =>
|
||||||
{
|
{
|
||||||
OnWithdrawAttempt?.Invoke(args, button.Id, WithdrawSlider.Value);
|
OnWithdrawAttempt?.Invoke(args, button.Id, WithdrawSlider.Value);
|
||||||
@@ -68,7 +65,7 @@ public sealed partial class StoreWithdrawWindow : DefaultWindow
|
|||||||
ButtonContainer.AddChild(button);
|
ButtonContainer.AddChild(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
var maxWithdrawAmount = _validCurrencies.Values.Max().Int();
|
var maxWithdrawAmount = _validCurrencies.Keys.Max().Int();
|
||||||
|
|
||||||
// setup withdraw slider
|
// setup withdraw slider
|
||||||
WithdrawSlider.MinValue = 1;
|
WithdrawSlider.MinValue = 1;
|
||||||
|
|||||||
@@ -110,7 +110,6 @@ namespace Content.Client.Stylesheets
|
|||||||
|
|
||||||
public static readonly Color ButtonColorGoodDefault = Color.FromHex("#3E6C45");
|
public static readonly Color ButtonColorGoodDefault = Color.FromHex("#3E6C45");
|
||||||
public static readonly Color ButtonColorGoodHovered = Color.FromHex("#31843E");
|
public static readonly Color ButtonColorGoodHovered = Color.FromHex("#31843E");
|
||||||
public static readonly Color ButtonColorGoodDisabled = Color.FromHex("#164420");
|
|
||||||
|
|
||||||
//NavMap
|
//NavMap
|
||||||
public static readonly Color PointRed = Color.FromHex("#B02E26");
|
public static readonly Color PointRed = Color.FromHex("#B02E26");
|
||||||
@@ -1500,20 +1499,6 @@ namespace Content.Client.Stylesheets
|
|||||||
|
|
||||||
Element<Button>().Class("ButtonColorGreen").Pseudo(ContainerButton.StylePseudoClassHover)
|
Element<Button>().Class("ButtonColorGreen").Pseudo(ContainerButton.StylePseudoClassHover)
|
||||||
.Prop(Control.StylePropertyModulateSelf, ButtonColorGoodHovered),
|
.Prop(Control.StylePropertyModulateSelf, ButtonColorGoodHovered),
|
||||||
|
|
||||||
// Accept button (merge with green button?) ---
|
|
||||||
Element<Button>().Class("ButtonAccept")
|
|
||||||
.Prop(Control.StylePropertyModulateSelf, ButtonColorGoodDefault),
|
|
||||||
|
|
||||||
Element<Button>().Class("ButtonAccept").Pseudo(ContainerButton.StylePseudoClassNormal)
|
|
||||||
.Prop(Control.StylePropertyModulateSelf, ButtonColorGoodDefault),
|
|
||||||
|
|
||||||
Element<Button>().Class("ButtonAccept").Pseudo(ContainerButton.StylePseudoClassHover)
|
|
||||||
.Prop(Control.StylePropertyModulateSelf, ButtonColorGoodHovered),
|
|
||||||
|
|
||||||
Element<Button>().Class("ButtonAccept").Pseudo(ContainerButton.StylePseudoClassDisabled)
|
|
||||||
.Prop(Control.StylePropertyModulateSelf, ButtonColorGoodDisabled),
|
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
// Small Button ---
|
// Small Button ---
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
using Content.Shared.Telephone;
|
|
||||||
|
|
||||||
namespace Content.Client.Telephone;
|
|
||||||
|
|
||||||
public sealed class TelephoneSystem : SharedTelephoneSystem
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -104,7 +104,7 @@ public sealed class TippyUIController : UIController
|
|||||||
? -WaddleRotation
|
? -WaddleRotation
|
||||||
: WaddleRotation;
|
: WaddleRotation;
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(_entity, out FootstepModifierComponent? step) && step.FootstepSoundCollection != null)
|
if (EntityManager.TryGetComponent(_entity, out FootstepModifierComponent? step))
|
||||||
{
|
{
|
||||||
var audioParams = step.FootstepSoundCollection.Params
|
var audioParams = step.FootstepSoundCollection.Params
|
||||||
.AddVolume(-7f)
|
.AddVolume(-7f)
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Robust.Client.ResourceManagement;
|
|
||||||
using Robust.Client.UserInterface.RichText;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Client.UserInterface.RichText;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the font to a monospaced variant
|
|
||||||
/// </summary>
|
|
||||||
public sealed class MonoTag : IMarkupTag
|
|
||||||
{
|
|
||||||
[ValidatePrototypeId<FontPrototype>] public const string MonoFont = "Monospace";
|
|
||||||
|
|
||||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
|
|
||||||
public string Name => "mono";
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void PushDrawContext(MarkupNode node, MarkupDrawingContext context)
|
|
||||||
{
|
|
||||||
var font = FontTag.CreateFont(context.Font, node, _resourceCache, _prototypeManager, MonoFont);
|
|
||||||
context.Font.Push(font);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void PopDrawContext(MarkupNode node, MarkupDrawingContext context)
|
|
||||||
{
|
|
||||||
context.Font.Pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<widgets:AlertsUI xmlns="https://spacestation14.io"
|
<widgets:AlertsUI xmlns="https://spacestation14.io"
|
||||||
xmlns:widgets="clr-namespace:Content.Client.UserInterface.Systems.Alerts.Widgets"
|
xmlns:widgets="clr-namespace:Content.Client.UserInterface.Systems.Alerts.Widgets"
|
||||||
MinSize="96 96">
|
MinSize="64 64">
|
||||||
<PanelContainer HorizontalAlignment="Right" VerticalAlignment="Top">
|
<PanelContainer HorizontalAlignment="Right" VerticalAlignment="Top">
|
||||||
<BoxContainer Name="AlertContainer" Access="Public" Orientation="Vertical" />
|
<BoxContainer Name="AlertContainer" Access="Public" Orientation="Vertical" />
|
||||||
</PanelContainer>
|
</PanelContainer>
|
||||||
|
|||||||
@@ -572,10 +572,6 @@ public sealed class UserAHelpUIHandler : IAHelpUIHandler
|
|||||||
_window.OnClose += () => { OnClose?.Invoke(); };
|
_window.OnClose += () => { OnClose?.Invoke(); };
|
||||||
_window.OnOpen += () => { OnOpen?.Invoke(); };
|
_window.OnOpen += () => { OnOpen?.Invoke(); };
|
||||||
_window.Contents.AddChild(_chatPanel);
|
_window.Contents.AddChild(_chatPanel);
|
||||||
|
|
||||||
var introText = Loc.GetString("bwoink-system-introductory-message");
|
|
||||||
var introMessage = new SharedBwoinkSystem.BwoinkTextMessage( _ownerId, SharedBwoinkSystem.SystemUserId, introText);
|
|
||||||
Receive(introMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ using static Robust.Client.UserInterface.Controls.LineEdit;
|
|||||||
namespace Content.Client.UserInterface.Systems.Chat.Widgets;
|
namespace Content.Client.UserInterface.Systems.Chat.Widgets;
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
[Virtual]
|
#pragma warning disable RA0003
|
||||||
public partial class ChatBox : UIWidget
|
public partial class ChatBox : UIWidget
|
||||||
|
#pragma warning restore RA0003
|
||||||
{
|
{
|
||||||
private readonly ChatUIController _controller;
|
private readonly ChatUIController _controller;
|
||||||
private readonly IEntityManager _entManager;
|
private readonly IEntityManager _entManager;
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|||||||
buttonHeading.AddStyleClass(ContainerButton.StyleClassButton);
|
buttonHeading.AddStyleClass(ContainerButton.StyleClassButton);
|
||||||
buttonHeading.Label.HorizontalAlignment = HAlignment.Center;
|
buttonHeading.Label.HorizontalAlignment = HAlignment.Center;
|
||||||
buttonHeading.Label.HorizontalExpand = true;
|
buttonHeading.Label.HorizontalExpand = true;
|
||||||
buttonHeading.Margin = new Thickness(8, 0, 8, 2);
|
|
||||||
|
|
||||||
var body = new CollapsibleBody
|
var body = new CollapsibleBody
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -83,27 +83,22 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
|
|||||||
if (args.Function == EngineKeyFunctions.UIClick)
|
if (args.Function == EngineKeyFunctions.UIClick)
|
||||||
{
|
{
|
||||||
_handsSystem.UIHandClick(_playerHandsComponent, hand.SlotName);
|
_handsSystem.UIHandClick(_playerHandsComponent, hand.SlotName);
|
||||||
args.Handle();
|
|
||||||
}
|
}
|
||||||
else if (args.Function == EngineKeyFunctions.UseSecondary)
|
else if (args.Function == EngineKeyFunctions.UseSecondary)
|
||||||
{
|
{
|
||||||
_handsSystem.UIHandOpenContextMenu(hand.SlotName);
|
_handsSystem.UIHandOpenContextMenu(hand.SlotName);
|
||||||
args.Handle();
|
|
||||||
}
|
}
|
||||||
else if (args.Function == ContentKeyFunctions.ActivateItemInWorld)
|
else if (args.Function == ContentKeyFunctions.ActivateItemInWorld)
|
||||||
{
|
{
|
||||||
_handsSystem.UIHandActivate(hand.SlotName);
|
_handsSystem.UIHandActivate(hand.SlotName);
|
||||||
args.Handle();
|
|
||||||
}
|
}
|
||||||
else if (args.Function == ContentKeyFunctions.AltActivateItemInWorld)
|
else if (args.Function == ContentKeyFunctions.AltActivateItemInWorld)
|
||||||
{
|
{
|
||||||
_handsSystem.UIHandAltActivateItem(hand.SlotName);
|
_handsSystem.UIHandAltActivateItem(hand.SlotName);
|
||||||
args.Handle();
|
|
||||||
}
|
}
|
||||||
else if (args.Function == ContentKeyFunctions.ExamineEntity)
|
else if (args.Function == ContentKeyFunctions.ExamineEntity)
|
||||||
{
|
{
|
||||||
_handsSystem.UIInventoryExamine(hand.SlotName);
|
_handsSystem.UIInventoryExamine(hand.SlotName);
|
||||||
args.Handle();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Numerics;
|
using Content.Client.Administration.Managers;
|
||||||
using Content.Client.Administration.Managers;
|
|
||||||
using Content.Client.Gameplay;
|
using Content.Client.Gameplay;
|
||||||
using Content.Client.Markers;
|
using Content.Client.Markers;
|
||||||
using Content.Client.Sandbox;
|
using Content.Client.Sandbox;
|
||||||
@@ -8,7 +7,9 @@ using Content.Client.UserInterface.Controls;
|
|||||||
using Content.Client.UserInterface.Systems.DecalPlacer;
|
using Content.Client.UserInterface.Systems.DecalPlacer;
|
||||||
using Content.Client.UserInterface.Systems.Sandbox.Windows;
|
using Content.Client.UserInterface.Systems.Sandbox.Windows;
|
||||||
using Content.Shared.Input;
|
using Content.Shared.Input;
|
||||||
|
using Content.Shared.Silicons.StationAi;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.Console;
|
||||||
using Robust.Client.Debugging;
|
using Robust.Client.Debugging;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Input;
|
using Robust.Client.Input;
|
||||||
@@ -108,13 +109,9 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
|
|||||||
|
|
||||||
private void EnsureWindow()
|
private void EnsureWindow()
|
||||||
{
|
{
|
||||||
if (_window is { Disposed: false })
|
if(_window is { Disposed: false })
|
||||||
return;
|
return;
|
||||||
_window = UIManager.CreateWindow<SandboxWindow>();
|
_window = UIManager.CreateWindow<SandboxWindow>();
|
||||||
// Pre-center the window without forcing it to the center every time.
|
|
||||||
_window.OpenCentered();
|
|
||||||
_window.Close();
|
|
||||||
|
|
||||||
_window.OnOpen += () => { SandboxButton!.Pressed = true; };
|
_window.OnOpen += () => { SandboxButton!.Pressed = true; };
|
||||||
_window.OnClose += () => { SandboxButton!.Pressed = false; };
|
_window.OnClose += () => { SandboxButton!.Pressed = false; };
|
||||||
_window.ToggleLightButton.Pressed = !_light.Enabled;
|
_window.ToggleLightButton.Pressed = !_light.Enabled;
|
||||||
@@ -152,6 +149,7 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
|
|||||||
_window.ToggleSubfloorButton.OnPressed += _ => _sandbox.ToggleSubFloor();
|
_window.ToggleSubfloorButton.OnPressed += _ => _sandbox.ToggleSubFloor();
|
||||||
_window.ShowMarkersButton.OnPressed += _ => _sandbox.ShowMarkers();
|
_window.ShowMarkersButton.OnPressed += _ => _sandbox.ShowMarkers();
|
||||||
_window.ShowBbButton.OnPressed += _ => _sandbox.ShowBb();
|
_window.ShowBbButton.OnPressed += _ => _sandbox.ShowBb();
|
||||||
|
_window.MachineLinkingButton.OnPressed += _ => _sandbox.MachineLinking();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckSandboxVisibility()
|
private void CheckSandboxVisibility()
|
||||||
@@ -166,7 +164,7 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
|
|||||||
{
|
{
|
||||||
if (_window != null)
|
if (_window != null)
|
||||||
{
|
{
|
||||||
_window.Close();
|
_window.Dispose();
|
||||||
_window = null;
|
_window = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +209,7 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
|
|||||||
if (_sandbox.SandboxAllowed && _window.IsOpen != true)
|
if (_sandbox.SandboxAllowed && _window.IsOpen != true)
|
||||||
{
|
{
|
||||||
UIManager.ClickSound();
|
UIManager.ClickSound();
|
||||||
_window.Open();
|
_window.OpenCentered();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,24 +4,20 @@
|
|||||||
Title="{Loc sandbox-window-title}"
|
Title="{Loc sandbox-window-title}"
|
||||||
Resizable="False">
|
Resizable="False">
|
||||||
<BoxContainer Orientation="Vertical" SeparationOverride="4">
|
<BoxContainer Orientation="Vertical" SeparationOverride="4">
|
||||||
<Label Text="{Loc sandbox-window-map-editing-label}"/>
|
<Button Name="AiOverlayButton" Access="Public" Text="{Loc sandbox-window-ai-overlay-button}" ToggleMode="True"/>
|
||||||
<Button Name="SpawnTilesButton" Access="Public" Text="{Loc sandbox-window-spawn-tiles-button}"/>
|
<Button Name="RespawnButton" Access="Public" Text="{Loc sandbox-window-respawn-button}"/>
|
||||||
<Button Name="SpawnEntitiesButton" Access="Public" Text="{Loc sandbox-window-spawn-entities-button}"/>
|
<Button Name="SpawnEntitiesButton" Access="Public" Text="{Loc sandbox-window-spawn-entities-button}"/>
|
||||||
|
<Button Name="SpawnTilesButton" Access="Public" Text="{Loc sandbox-window-spawn-tiles-button}"/>
|
||||||
<Button Name="SpawnDecalsButton" Access="Public" Text="{Loc sandbox-window-spawn-decals-button}"/>
|
<Button Name="SpawnDecalsButton" Access="Public" Text="{Loc sandbox-window-spawn-decals-button}"/>
|
||||||
|
<Button Name="GiveFullAccessButton" Access="Public" Text="{Loc sandbox-window-grant-full-access-button}"/>
|
||||||
<Label Text="{Loc sandbox-window-visibility-label}"/>
|
<Button Name="GiveAghostButton" Access="Public" Text="{Loc sandbox-window-ghost-button}"/>
|
||||||
<Button Name="ToggleLightButton" Access="Public" Text="{Loc sandbox-window-toggle-lights-button}" ToggleMode="True"/>
|
<Button Name="ToggleLightButton" Access="Public" Text="{Loc sandbox-window-toggle-lights-button}" ToggleMode="True"/>
|
||||||
<Button Name="ToggleFovButton" Access="Public" Text="{Loc sandbox-window-toggle-fov-button}" ToggleMode="True"/>
|
<Button Name="ToggleFovButton" Access="Public" Text="{Loc sandbox-window-toggle-fov-button}" ToggleMode="True"/>
|
||||||
<Button Name="ToggleShadowsButton" Access="Public" Text="{Loc sandbox-window-toggle-shadows-button}" ToggleMode="True"/>
|
<Button Name="ToggleShadowsButton" Access="Public" Text="{Loc sandbox-window-toggle-shadows-button}" ToggleMode="True"/>
|
||||||
<Button Name="ToggleSubfloorButton" Access="Public" Text="{Loc sandbox-window-toggle-subfloor-button}" ToggleMode="True"/>
|
<Button Name="ToggleSubfloorButton" Access="Public" Text="{Loc sandbox-window-toggle-subfloor-button}" ToggleMode="True"/>
|
||||||
<Button Name="AiOverlayButton" Access="Public" Text="{Loc sandbox-window-ai-overlay-button}" ToggleMode="True"/>
|
<Button Name="SuicideButton" Access="Public" Text="{Loc sandbox-window-toggle-suicide-button}" ToggleMode="True"/>
|
||||||
<Button Name="ShowMarkersButton" Access="Public" Text="{Loc sandbox-window-show-spawns-button}" ToggleMode="True"/>
|
<Button Name="ShowMarkersButton" Access="Public" Text="{Loc sandbox-window-show-spawns-button}" ToggleMode="True"/>
|
||||||
<Button Name="ShowBbButton" Access="Public" Text="{Loc sandbox-window-show-bb-button}" ToggleMode="True"/>
|
<Button Name="ShowBbButton" Access="Public" Text="{Loc sandbox-window-show-bb-button}" ToggleMode="True"/>
|
||||||
|
<Button Name="MachineLinkingButton" Access="Public" Text="{Loc sandbox-window-link-machines-button}" ToggleMode="True"/>
|
||||||
<Label Text="{Loc sandbox-window-your-character-label}"/>
|
|
||||||
<Button Name="GiveAghostButton" Access="Public" Text="{Loc sandbox-window-ghost-button}"/>
|
|
||||||
<Button Name="GiveFullAccessButton" Access="Public" Text="{Loc sandbox-window-grant-full-access-button}"/>
|
|
||||||
<Button Name="SuicideButton" Access="Public" Text="{Loc sandbox-window-toggle-suicide-button}"/>
|
|
||||||
<Button Name="RespawnButton" Access="Public" Text="{Loc sandbox-window-respawn-button}"/>
|
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</windows:SandboxWindow>
|
</windows:SandboxWindow>
|
||||||
|
|||||||
@@ -160,9 +160,8 @@ public sealed class ItemGridPiece : Control, IEntityControl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// typically you'd divide by two, but since the textures are half a tile, this is done implicitly
|
// typically you'd divide by two, but since the textures are half a tile, this is done implicitly
|
||||||
var iconPosition = new Vector2(
|
var iconPosition = new Vector2((boundingGrid.Width + 1) * size.X + itemComponent.StoredOffset.X * 2,
|
||||||
(boundingGrid.Width + 1) * size.X + Location.Rotation.RotateVec(itemComponent.StoredOffset).X * 2,
|
(boundingGrid.Height + 1) * size.Y + itemComponent.StoredOffset.Y * 2);
|
||||||
(boundingGrid.Height + 1) * size.Y + Location.Rotation.RotateVec(itemComponent.StoredOffset).Y * 2);
|
|
||||||
var iconRotation = Location.Rotation + Angle.FromDegrees(itemComponent.StoredRotation);
|
var iconRotation = Location.Rotation + Angle.FromDegrees(itemComponent.StoredRotation);
|
||||||
|
|
||||||
if (itemComponent.StoredSprite is { } storageSprite)
|
if (itemComponent.StoredSprite is { } storageSprite)
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ public sealed partial class GunSystem : SharedGunSystem
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
UpdatesOutsidePrediction = true;
|
UpdatesOutsidePrediction = true;
|
||||||
SubscribeLocalEvent<AmmoCounterComponent, ItemStatusCollectMessage>(OnAmmoCounterCollect);
|
SubscribeLocalEvent<AmmoCounterComponent, ItemStatusCollectMessage>(OnAmmoCounterCollect);
|
||||||
SubscribeLocalEvent<AmmoCounterComponent, UpdateClientAmmoEvent>(OnUpdateClientAmmo);
|
|
||||||
SubscribeAllEvent<MuzzleFlashEvent>(OnMuzzleFlash);
|
SubscribeAllEvent<MuzzleFlashEvent>(OnMuzzleFlash);
|
||||||
|
|
||||||
// Plays animated effects on the client.
|
// Plays animated effects on the client.
|
||||||
@@ -87,11 +86,6 @@ public sealed partial class GunSystem : SharedGunSystem
|
|||||||
InitializeSpentAmmo();
|
InitializeSpentAmmo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUpdateClientAmmo(EntityUid uid, AmmoCounterComponent ammoComp, ref UpdateClientAmmoEvent args)
|
|
||||||
{
|
|
||||||
UpdateAmmoCount(uid, ammoComp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMuzzleFlash(MuzzleFlashEvent args)
|
private void OnMuzzleFlash(MuzzleFlashEvent args)
|
||||||
{
|
{
|
||||||
var gunUid = GetEntity(args.Uid);
|
var gunUid = GetEntity(args.Uid);
|
||||||
|
|||||||
@@ -206,7 +206,8 @@ namespace Content.Client.Wires.UI
|
|||||||
(_statusContainer = new GridContainer
|
(_statusContainer = new GridContainer
|
||||||
{
|
{
|
||||||
Margin = new Thickness(8, 4),
|
Margin = new Thickness(8, 4),
|
||||||
Rows = 2
|
// TODO: automatically change columns count.
|
||||||
|
Columns = 3
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,8 +227,7 @@ namespace Content.Client.Wires.UI
|
|||||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")}
|
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")}
|
||||||
});
|
});
|
||||||
CloseButton.OnPressed += _ => Close();
|
CloseButton.OnPressed += _ => Close();
|
||||||
SetHeight = 200;
|
SetSize = new Vector2(320, 200);
|
||||||
MinWidth = 320;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -503,8 +503,6 @@ namespace Content.Client.Wires.UI
|
|||||||
|
|
||||||
public StatusLight(StatusLightData data, IResourceCache resourceCache)
|
public StatusLight(StatusLightData data, IResourceCache resourceCache)
|
||||||
{
|
{
|
||||||
HorizontalAlignment = HAlignment.Right;
|
|
||||||
|
|
||||||
var hsv = Color.ToHsv(data.Color);
|
var hsv = Color.ToHsv(data.Color);
|
||||||
hsv.Z /= 2;
|
hsv.Z /= 2;
|
||||||
var dimColor = Color.FromHsv(hsv);
|
var dimColor = Color.FromHsv(hsv);
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
using Content.Shared._CP14.Knowledge;
|
|
||||||
|
|
||||||
namespace Content.Client._CP14.Knowledge;
|
|
||||||
|
|
||||||
public sealed partial class ClientCP14KnowledgeSystem : SharedCP14KnowledgeSystem
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,218 +0,0 @@
|
|||||||
using Content.Client.Clothing;
|
|
||||||
using Content.Shared._CP14.ModularCraft;
|
|
||||||
using Content.Shared._CP14.ModularCraft.Components;
|
|
||||||
using Content.Shared.Clothing;
|
|
||||||
using Content.Shared.Hands;
|
|
||||||
using Content.Shared.Inventory;
|
|
||||||
using Content.Shared.Item;
|
|
||||||
using Content.Shared.Wieldable.Components;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.ResourceManagement;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations;
|
|
||||||
|
|
||||||
namespace Content.Client._CP14.ModularCraft;
|
|
||||||
|
|
||||||
public sealed class CP14ClientModularCraftSystem : CP14SharedModularCraftSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
|
||||||
[Dependency] private readonly IResourceCache _resCache = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<CP14ModularCraftStartPointComponent, AfterAutoHandleStateEvent>(OnAfterHandleState);
|
|
||||||
SubscribeLocalEvent<CP14ModularCraftStartPointComponent, GetInhandVisualsEvent>(OnGetInhandVisuals);
|
|
||||||
SubscribeLocalEvent<CP14ModularCraftStartPointComponent, GetEquipmentVisualsEvent>(OnGetEquipmentVisuals);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAfterHandleState(Entity<CP14ModularCraftStartPointComponent> start,
|
|
||||||
ref AfterAutoHandleStateEvent args)
|
|
||||||
{
|
|
||||||
if (!TryComp<SpriteComponent>(start, out var sprite))
|
|
||||||
return;
|
|
||||||
|
|
||||||
UpdateIcon(start, sprite);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateIcon(Entity<CP14ModularCraftStartPointComponent> start, SpriteComponent? sprite = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(start, ref sprite, false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
//Remove old layers
|
|
||||||
foreach (var key in start.Comp.RevealedLayers)
|
|
||||||
{
|
|
||||||
sprite.RemoveLayer(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
start.Comp.RevealedLayers.Clear();
|
|
||||||
|
|
||||||
//Add new layers
|
|
||||||
var counterPart = 0;
|
|
||||||
foreach (var part in start.Comp.InstalledParts)
|
|
||||||
{
|
|
||||||
var indexedPart = _proto.Index(part);
|
|
||||||
|
|
||||||
if (indexedPart.IconSprite is null)
|
|
||||||
{
|
|
||||||
//Try get default sprite
|
|
||||||
if (indexedPart.RsiPath is null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var state = $"icon";
|
|
||||||
|
|
||||||
var rsi = _resCache
|
|
||||||
.GetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / indexedPart.RsiPath)
|
|
||||||
.RSI;
|
|
||||||
|
|
||||||
if (!rsi.TryGetState(state, out _))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var defaultLayer = new PrototypeLayerData
|
|
||||||
{
|
|
||||||
RsiPath = indexedPart.RsiPath,
|
|
||||||
State = state,
|
|
||||||
};
|
|
||||||
|
|
||||||
var keyCode = $"cp14-modular-icon-layer-{counterPart}-default";
|
|
||||||
start.Comp.RevealedLayers.Add(keyCode);
|
|
||||||
var index = sprite.AddLayer(defaultLayer);
|
|
||||||
sprite.LayerMapSet(keyCode, index);
|
|
||||||
|
|
||||||
if (indexedPart.Color is not null)
|
|
||||||
sprite.LayerSetColor(keyCode, indexedPart.Color.Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var counter = 0;
|
|
||||||
foreach (var layer in indexedPart.IconSprite)
|
|
||||||
{
|
|
||||||
var keyCode = $"cp14-modular-icon-layer-{counterPart}-{counter}";
|
|
||||||
start.Comp.RevealedLayers.Add(keyCode);
|
|
||||||
var index = sprite.AddLayer(layer);
|
|
||||||
sprite.LayerMapSet(keyCode, index);
|
|
||||||
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
counterPart++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnGetInhandVisuals(Entity<CP14ModularCraftStartPointComponent> start, ref GetInhandVisualsEvent args)
|
|
||||||
{
|
|
||||||
var defaultKey = $"cp14-modular-inhand-layer-{args.Location.ToString().ToLowerInvariant()}";
|
|
||||||
|
|
||||||
if (!TryComp<ItemComponent>(start, out var item))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var wielded = item.HeldPrefix == "wielded"; //SHITCOOOOOOODE
|
|
||||||
|
|
||||||
var counterPart = 0;
|
|
||||||
foreach (var part in start.Comp.InstalledParts)
|
|
||||||
{
|
|
||||||
var indexedPart = _proto.Index(part);
|
|
||||||
|
|
||||||
var targetLayers =
|
|
||||||
wielded ? indexedPart.WieldedInhandVisuals : indexedPart.InhandVisuals;
|
|
||||||
|
|
||||||
if (targetLayers is not null && targetLayers.TryGetValue(args.Location, out var layers))
|
|
||||||
{
|
|
||||||
var i = 0;
|
|
||||||
foreach (var layer in layers)
|
|
||||||
{
|
|
||||||
var key = $"{defaultKey}-{counterPart}-{i}";
|
|
||||||
args.Layers.Add((key, layer));
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Try get default visuals
|
|
||||||
if (indexedPart.RsiPath is null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var rsi = _resCache
|
|
||||||
.GetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / indexedPart.RsiPath)
|
|
||||||
.RSI;
|
|
||||||
|
|
||||||
var state = $"inhand-{args.Location.ToString().ToLowerInvariant()}";
|
|
||||||
|
|
||||||
if (wielded)
|
|
||||||
state = $"wielded-{state}";
|
|
||||||
|
|
||||||
if (!rsi.TryGetState(state, out _))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var defaultLayer = new PrototypeLayerData
|
|
||||||
{
|
|
||||||
RsiPath = indexedPart.RsiPath,
|
|
||||||
State = state,
|
|
||||||
Color = indexedPart.Color,
|
|
||||||
};
|
|
||||||
|
|
||||||
var key = $"{defaultKey}-{counterPart}-default";
|
|
||||||
args.Layers.Add((key, defaultLayer));
|
|
||||||
}
|
|
||||||
|
|
||||||
counterPart++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnGetEquipmentVisuals(Entity<CP14ModularCraftStartPointComponent> start,
|
|
||||||
ref GetEquipmentVisualsEvent args)
|
|
||||||
{
|
|
||||||
if (!TryComp(args.Equipee, out InventoryComponent? inventory))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var defaultKey = $"cp14-modular-clothing-layer-{args.Slot}";
|
|
||||||
|
|
||||||
var counterPart = 0;
|
|
||||||
foreach (var part in start.Comp.InstalledParts)
|
|
||||||
{
|
|
||||||
var indexedPart = _proto.Index(part);
|
|
||||||
|
|
||||||
if (indexedPart.ClothingVisuals is not null && indexedPart.ClothingVisuals.TryGetValue(args.Slot, out var layers))
|
|
||||||
{
|
|
||||||
var i = 0;
|
|
||||||
foreach (var layer in layers)
|
|
||||||
{
|
|
||||||
var key = $"{defaultKey}-{counterPart}-{i}";
|
|
||||||
args.Layers.Add((key, layer));
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Try get default sprites
|
|
||||||
if (indexedPart.RsiPath is null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var rsi = _resCache
|
|
||||||
.GetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / indexedPart.RsiPath)
|
|
||||||
.RSI;
|
|
||||||
|
|
||||||
if (!ClientClothingSystem.TemporarySlotMap.TryGetValue(args.Slot, out var correctedSlot))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var state = $"equipped-{correctedSlot}";
|
|
||||||
|
|
||||||
if (!rsi.TryGetState(state, out _))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var defaultLayer = new PrototypeLayerData
|
|
||||||
{
|
|
||||||
RsiPath = indexedPart.RsiPath,
|
|
||||||
State = state,
|
|
||||||
Color = indexedPart.Color,
|
|
||||||
};
|
|
||||||
|
|
||||||
var key = $"{defaultKey}-{counterPart}-default";
|
|
||||||
args.Layers.Add((key, defaultLayer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,12 +16,11 @@
|
|||||||
<Label Text="{Loc 'cp14-ui-options-main-graphics-label'}"
|
<Label Text="{Loc 'cp14-ui-options-main-graphics-label'}"
|
||||||
StyleClasses="LabelKeyText"/>
|
StyleClasses="LabelKeyText"/>
|
||||||
|
|
||||||
<CheckBox Name="WaveShaderEnabled"
|
<!-- CP14 Wave shader settings -->
|
||||||
Text="{Loc 'cp14-ui-options-main-graphics-wave-shader'}"/>
|
<BoxContainer Orientation="Horizontal">
|
||||||
<!-- TODO: Wave shader tooltip -->
|
<Label Text="{Loc 'cp14-ui-options-main-graphics-wave-shader'}" Margin="0 0 4 0"/>
|
||||||
<CheckBox Name="PostProcessCheckBox"
|
<CheckBox Name="WaveShaderEnabled"/>
|
||||||
Text="{Loc 'cp14-ui-options-postprocess'}"
|
</BoxContainer>
|
||||||
ToolTip="{Loc 'cp14-ui-options-postprocess-tooltip'}"/>
|
|
||||||
|
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</ScrollContainer>
|
</ScrollContainer>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ public sealed partial class CP14OptionsMenuMainTab : Control
|
|||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
Control.AddOptionCheckBox(CP14ConfigVars.WaveShaderEnabled, WaveShaderEnabled);
|
Control.AddOptionCheckBox(CP14ConfigVars.WaveShaderEnabled, WaveShaderEnabled);
|
||||||
Control.AddOptionCheckBox(CP14ConfigVars.PostProcess, PostProcessCheckBox);
|
|
||||||
|
|
||||||
Control.Initialize();
|
Control.Initialize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
using Content.Shared._CP14.Configuration;
|
|
||||||
using System.Numerics;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.Player;
|
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
using Robust.Shared.Enums;
|
|
||||||
using Robust.Shared.Graphics;
|
|
||||||
using Robust.Shared.Physics;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Client.Overlays;
|
|
||||||
|
|
||||||
// This overlay serves as the foundational post processing overlay.
|
|
||||||
// Ideally, for performance reasons, post processing designed to be present at all times, such as additive light blending or tonemapping, should be done as part of a single shader pass.
|
|
||||||
public sealed class CP14BasePostProcessOverlay : Overlay
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
|
||||||
[Dependency] private readonly ILightManager _lightManager = default!;
|
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
|
|
||||||
public override bool RequestScreenTexture => true;
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
|
||||||
private readonly ShaderInstance _basePostProcessShader;
|
|
||||||
|
|
||||||
public CP14BasePostProcessOverlay()
|
|
||||||
{
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
_basePostProcessShader = _prototypeManager.Index<ShaderPrototype>("BasePostProcess").InstanceUnique();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
|
||||||
{
|
|
||||||
if (!_configManager.GetCVar(CP14ConfigVars.PostProcess))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!_entityManager.TryGetComponent(_playerManager.LocalSession?.AttachedEntity, out EyeComponent? eyeComp))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (args.Viewport.Eye != eyeComp.Eye)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!_lightManager.Enabled || !eyeComp.Eye.DrawLight || !eyeComp.Eye.DrawFov)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var playerEntity = _playerManager.LocalSession?.AttachedEntity;
|
|
||||||
|
|
||||||
if (playerEntity == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Draw(in OverlayDrawArgs args)
|
|
||||||
{
|
|
||||||
if (ScreenTexture == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (args.Viewport.Eye == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var playerEntity = _playerManager.LocalSession?.AttachedEntity;
|
|
||||||
|
|
||||||
var worldHandle = args.WorldHandle;
|
|
||||||
var viewport = args.WorldBounds;
|
|
||||||
|
|
||||||
_basePostProcessShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
|
|
||||||
_basePostProcessShader.SetParameter("LIGHT_TEXTURE", args.Viewport.LightRenderTarget.Texture);
|
|
||||||
|
|
||||||
_basePostProcessShader.SetParameter("Zoom", args.Viewport.Eye.Zoom.X);
|
|
||||||
|
|
||||||
worldHandle.UseShader(_basePostProcessShader);
|
|
||||||
worldHandle.DrawRect(viewport, Color.White);
|
|
||||||
worldHandle.UseShader(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
using Content.Shared._CP14.Roof;
|
|
||||||
using Content.Shared.Ghost;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.Player;
|
|
||||||
using Robust.Shared.Console;
|
|
||||||
using Robust.Shared.Map.Components;
|
|
||||||
|
|
||||||
namespace Content.Client._CP14.Roof;
|
|
||||||
|
|
||||||
public sealed class CP14RoofSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
||||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
|
||||||
|
|
||||||
private bool _roofVisible = true;
|
|
||||||
public bool DisabledByCommand = false;
|
|
||||||
|
|
||||||
private EntityQuery<GhostComponent> _ghostQuery;
|
|
||||||
private EntityQuery<TransformComponent> _xformQuery;
|
|
||||||
|
|
||||||
public bool RoofVisibility
|
|
||||||
{
|
|
||||||
get => _roofVisible && !DisabledByCommand;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_roofVisible = value;
|
|
||||||
UpdateRoofVisibilityAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
_ghostQuery = GetEntityQuery<GhostComponent>();
|
|
||||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<CP14RoofComponent, ComponentStartup>(RoofStartup);
|
|
||||||
SubscribeLocalEvent<GhostComponent, CP14ToggleRoofVisibilityAction>(OnToggleRoof);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
base.Update(frameTime);
|
|
||||||
|
|
||||||
var player = _playerManager.LocalEntity;
|
|
||||||
|
|
||||||
if (_ghostQuery.HasComp(player))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_xformQuery.TryComp(player, out var playerXform))
|
|
||||||
{
|
|
||||||
var grid = playerXform.GridUid;
|
|
||||||
if (grid == null || !TryComp<MapGridComponent>(grid, out var gridComp))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var roofQuery = GetEntityQuery<CP14RoofComponent>();
|
|
||||||
var anchored = _map.GetAnchoredEntities(grid.Value, gridComp, playerXform.Coordinates);
|
|
||||||
|
|
||||||
var underRoof = false;
|
|
||||||
foreach (var ent in anchored)
|
|
||||||
{
|
|
||||||
if (!roofQuery.HasComp(ent))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
underRoof = true;
|
|
||||||
}
|
|
||||||
if (underRoof && _roofVisible)
|
|
||||||
{
|
|
||||||
RoofVisibility = false;
|
|
||||||
}
|
|
||||||
if (!underRoof && !_roofVisible)
|
|
||||||
{
|
|
||||||
RoofVisibility = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnToggleRoof(Entity<GhostComponent> ent, ref CP14ToggleRoofVisibilityAction args)
|
|
||||||
{
|
|
||||||
if (args.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
DisabledByCommand = !DisabledByCommand;
|
|
||||||
UpdateRoofVisibilityAll();
|
|
||||||
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RoofStartup(Entity<CP14RoofComponent> ent, ref ComponentStartup args)
|
|
||||||
{
|
|
||||||
if (!TryComp<SpriteComponent>(ent, out var sprite))
|
|
||||||
return;
|
|
||||||
|
|
||||||
UpdateVisibility(ent, sprite);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateVisibility(Entity<CP14RoofComponent> ent, SpriteComponent sprite)
|
|
||||||
{
|
|
||||||
sprite.Visible = RoofVisibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateRoofVisibilityAll()
|
|
||||||
{
|
|
||||||
var query = EntityQueryEnumerator<CP14RoofComponent, SpriteComponent>();
|
|
||||||
while (query.MoveNext(out var uid, out var marker, out var sprite))
|
|
||||||
{
|
|
||||||
UpdateVisibility((uid, marker), sprite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class ShowRoof : LocalizedCommands
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
|
||||||
|
|
||||||
public override string Command => "cp14_toggleroof";
|
|
||||||
|
|
||||||
public override string Help => "Toggle roof visibility";
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
||||||
{
|
|
||||||
var roofSystem = _entitySystemManager.GetEntitySystem<CP14RoofSystem>();
|
|
||||||
roofSystem.DisabledByCommand = !roofSystem.DisabledByCommand;
|
|
||||||
roofSystem.UpdateRoofVisibilityAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,9 +12,6 @@ public sealed class CP14WorkbenchBoundUserInterface : BoundUserInterface
|
|||||||
{
|
{
|
||||||
private CP14WorkbenchWindow? _window;
|
private CP14WorkbenchWindow? _window;
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
private string _search = string.Empty;
|
|
||||||
|
|
||||||
public CP14WorkbenchBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
public CP14WorkbenchBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -26,12 +23,6 @@ public sealed class CP14WorkbenchBoundUserInterface : BoundUserInterface
|
|||||||
_window = this.CreateWindow<CP14WorkbenchWindow>();
|
_window = this.CreateWindow<CP14WorkbenchWindow>();
|
||||||
|
|
||||||
_window.OnCraft += entry => SendMessage(new CP14WorkbenchUiCraftMessage(entry.ProtoId));
|
_window.OnCraft += entry => SendMessage(new CP14WorkbenchUiCraftMessage(entry.ProtoId));
|
||||||
|
|
||||||
_window.OnTextUpdated += search =>
|
|
||||||
{
|
|
||||||
_search = search.Trim().ToLowerInvariant();
|
|
||||||
_window.UpdateFilter(_search);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState(BoundUserInterfaceState state)
|
protected override void UpdateState(BoundUserInterfaceState state)
|
||||||
@@ -41,7 +32,7 @@ public sealed class CP14WorkbenchBoundUserInterface : BoundUserInterface
|
|||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case CP14WorkbenchUiRecipesState recipesState:
|
case CP14WorkbenchUiRecipesState recipesState:
|
||||||
_window?.UpdateRecipes(recipesState, _search);
|
_window?.UpdateRecipes(recipesState);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
<Control xmlns="https://spacestation14.io">
|
<Control xmlns="https://spacestation14.io">
|
||||||
<GridContainer Columns="2">
|
<GridContainer Columns="2">
|
||||||
<EntityPrototypeView
|
<TextureRect Name="View"
|
||||||
Name="EntityView"
|
Margin="0,0,4,0"
|
||||||
Margin="0,0,4,0"
|
MinSize="48 48"
|
||||||
MinSize="48 48"
|
HorizontalAlignment="Left"
|
||||||
MaxSize="48 48"
|
Stretch="KeepAspectCentered"/>
|
||||||
Scale="2,2"
|
<Label Name="Name"/>
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalExpand="True" />
|
|
||||||
<TextureRect
|
|
||||||
Name="View"
|
|
||||||
Margin="0,0,4,0"
|
|
||||||
MinSize="48 48"
|
|
||||||
MaxSize="48 48"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Stretch="KeepAspectCentered" />
|
|
||||||
<Label Name="Name" />
|
|
||||||
</GridContainer>
|
</GridContainer>
|
||||||
</Control>
|
</Control>
|
||||||
|
|||||||
@@ -31,9 +31,7 @@ public sealed partial class CP14WorkbenchRecipeControl : Control
|
|||||||
{
|
{
|
||||||
var entityName = prototype.Name;
|
var entityName = prototype.Name;
|
||||||
Name.Text = count <= 1 ? entityName : $"{entityName} x{count}";
|
Name.Text = count <= 1 ? entityName : $"{entityName} x{count}";
|
||||||
|
View.Texture = _sprite.GetPrototypeIcon(prototype).Default;
|
||||||
View.Visible = false;
|
|
||||||
EntityView.SetPrototype(prototype);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CP14WorkbenchRecipeControl(StackPrototype prototype, int count) : this()
|
public CP14WorkbenchRecipeControl(StackPrototype prototype, int count) : this()
|
||||||
@@ -45,7 +43,6 @@ public sealed partial class CP14WorkbenchRecipeControl : Control
|
|||||||
if (icon is null)
|
if (icon is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EntityView.Visible = false;
|
|
||||||
View.Texture = _sprite.Frame0(icon);
|
View.Texture = _sprite.Frame0(icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user