Compare commits
1 Commits
fishing
...
revert-995
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c24bb1535 |
2
.github/workflows/benchmarks.yml
vendored
2
.github/workflows/benchmarks.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
name: Run Benchmarks
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
- uses: actions/checkout@v3.6.0
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Get Engine version
|
||||
|
||||
4
.github/workflows/build-docfx.yml
vendored
4
.github/workflows/build-docfx.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
docfx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
- uses: actions/checkout@v3.6.0
|
||||
- name: Setup submodule
|
||||
run: |
|
||||
git submodule update --init --recursive
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
cd RobustToolbox/
|
||||
git submodule update --init --recursive
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
uses: actions/setup-dotnet@v3.2.0
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
|
||||
4
.github/workflows/build-map-renderer.yml
vendored
4
.github/workflows/build-map-renderer.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Master
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v3.6.0
|
||||
|
||||
- name: Setup Submodule
|
||||
run: |
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
git submodule update --init --recursive
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
uses: actions/setup-dotnet@v3.2.0
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
|
||||
4
.github/workflows/build-test-debug.yml
vendored
4
.github/workflows/build-test-debug.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Master
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v3.6.0
|
||||
|
||||
- name: Setup Submodule
|
||||
run: |
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
git submodule update --init --recursive
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
uses: actions/setup-dotnet@v3.2.0
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
|
||||
2
.github/workflows/check-crlf.yml
vendored
2
.github/workflows/check-crlf.yml
vendored
@@ -10,6 +10,6 @@ jobs:
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
- uses: actions/checkout@v3.6.0
|
||||
- name: Check for CRLF
|
||||
run: Tools/check_crlf.py
|
||||
|
||||
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
@@ -16,11 +16,11 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -y python3-paramiko python3-lxml
|
||||
|
||||
- uses: actions/checkout@v4.2.2
|
||||
- uses: actions/checkout@v3.6.0
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
uses: actions/setup-dotnet@v3.2.0
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
|
||||
4
.github/workflows/rsi-diff.yml
vendored
4
.github/workflows/rsi-diff.yml
vendored
@@ -11,14 +11,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v3.6.0
|
||||
|
||||
- name: Get changed files
|
||||
id: files
|
||||
uses: Ana06/get-changed-files@v2.3.0
|
||||
with:
|
||||
format: 'space-delimited'
|
||||
filter: |
|
||||
filter: |
|
||||
**.rsi
|
||||
**.png
|
||||
|
||||
|
||||
4
.github/workflows/test-packaging.yml
vendored
4
.github/workflows/test-packaging.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Master
|
||||
uses: actions/checkout@v4.2.2
|
||||
uses: actions/checkout@v3.6.0
|
||||
|
||||
- name: Setup Submodule
|
||||
run: |
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
git submodule update --init --recursive
|
||||
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
uses: actions/setup-dotnet@v3.2.0
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
|
||||
|
||||
20
.github/workflows/update-credits.yml
vendored
20
.github/workflows/update-credits.yml
vendored
@@ -4,19 +4,19 @@ on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: 0 0 * * 0
|
||||
|
||||
|
||||
jobs:
|
||||
get_credits:
|
||||
runs-on: ubuntu-latest
|
||||
# Hey there fork dev! If you like to include your own contributors in this then you can probably just change this to your own repo
|
||||
# Do this in dump_github_contributors.ps1 too into your own repo
|
||||
if: github.repository == 'space-wizards/space-station-14'
|
||||
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
- uses: actions/checkout@v3.6.0
|
||||
with:
|
||||
ref: master
|
||||
|
||||
|
||||
- name: Get this week's Contributors
|
||||
shell: pwsh
|
||||
env:
|
||||
@@ -25,25 +25,25 @@ jobs:
|
||||
|
||||
# TODO
|
||||
#- name: Get this week's Patreons
|
||||
# run: Tools/script2dumppatreons > Resources/Credits/Patrons.yml
|
||||
|
||||
# run: Tools/script2dumppatreons > Resources/Credits/Patrons.yml
|
||||
|
||||
# MAKE SURE YOU ENABLED "Allow GitHub Actions to create and approve pull requests" IN YOUR ACTIONS, OTHERWISE IT WILL MOST LIKELY FAIL
|
||||
|
||||
|
||||
# For this you can use a pat token of an account with direct push access to the repo if you have protected branches.
|
||||
# For this you can use a pat token of an account with direct push access to the repo if you have protected branches.
|
||||
# Uncomment this and comment the other line if you do this.
|
||||
# https://github.com/stefanzweifel/git-auto-commit-action#push-to-protected-branches
|
||||
|
||||
|
||||
#- name: Commit new credit files
|
||||
# uses: stefanzweifel/git-auto-commit-action@v4
|
||||
# with:
|
||||
# commit_message: Update Credits
|
||||
# commit_author: PJBot <pieterjan.briers+bot@gmail.com>
|
||||
|
||||
|
||||
# This will make a PR
|
||||
- name: Set current date as env variable
|
||||
run: echo "NOW=$(date +'%Y-%m-%dT%H-%M-%S')" >> $GITHUB_ENV
|
||||
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
|
||||
2
.github/workflows/validate-rgas.yml
vendored
2
.github/workflows/validate-rgas.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
if: github.actor != 'PJBot' && github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
- uses: actions/checkout@v3.6.0
|
||||
- name: Setup Submodule
|
||||
run: git submodule update --init
|
||||
- name: Pull engine updates
|
||||
|
||||
2
.github/workflows/validate-rsis.yml
vendored
2
.github/workflows/validate-rsis.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Validate RSIs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
- uses: actions/checkout@v3.6.0
|
||||
- name: Setup Submodule
|
||||
run: git submodule update --init
|
||||
- name: Pull engine updates
|
||||
|
||||
2
.github/workflows/validate_mapfiles.yml
vendored
2
.github/workflows/validate_mapfiles.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
if: github.actor != 'PJBot' && github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
- uses: actions/checkout@v3.6.0
|
||||
- name: Setup Submodule
|
||||
run: git submodule update --init
|
||||
- name: Pull engine updates
|
||||
|
||||
4
.github/workflows/yaml-linter.yml
vendored
4
.github/workflows/yaml-linter.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
if: github.actor != 'PJBot' && github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4.2.2
|
||||
- uses: actions/checkout@v3.6.0
|
||||
- name: Setup submodule
|
||||
run: |
|
||||
git submodule update --init --recursive
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
cd RobustToolbox/
|
||||
git submodule update --init --recursive
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v4.1.0
|
||||
uses: actions/setup-dotnet@v3.2.0
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client.Administration.Systems;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Mind;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.ResourceManagement;
|
||||
@@ -17,54 +14,32 @@ namespace Content.Client.Administration;
|
||||
|
||||
internal sealed class AdminNameOverlay : Overlay
|
||||
{
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
|
||||
private readonly AdminSystem _system;
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly IEyeManager _eyeManager;
|
||||
private readonly EntityLookupSystem _entityLookup;
|
||||
private readonly IUserInterfaceManager _userInterfaceManager;
|
||||
private readonly Font _font;
|
||||
private readonly Font _fontBold;
|
||||
private bool _overlayClassic;
|
||||
private bool _overlaySymbols;
|
||||
private bool _overlayPlaytime;
|
||||
private bool _overlayStartingJob;
|
||||
private float _ghostFadeDistance;
|
||||
private float _ghostHideDistance;
|
||||
private int _overlayStackMax;
|
||||
private float _overlayMergeDistance;
|
||||
|
||||
//TODO make this adjustable via GUI
|
||||
private readonly ProtoId<RoleTypePrototype>[] _filter =
|
||||
["SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"];
|
||||
private readonly string _antagLabelClassic = Loc.GetString("admin-overlay-antag-classic");
|
||||
private readonly Color _antagColorClassic = Color.OrangeRed;
|
||||
|
||||
public AdminNameOverlay(
|
||||
AdminSystem system,
|
||||
IEntityManager entityManager,
|
||||
IEyeManager eyeManager,
|
||||
IResourceCache resourceCache,
|
||||
EntityLookupSystem entityLookup,
|
||||
IUserInterfaceManager userInterfaceManager,
|
||||
IConfigurationManager config)
|
||||
public AdminNameOverlay(AdminSystem system, IEntityManager entityManager, IEyeManager eyeManager, IResourceCache resourceCache, EntityLookupSystem entityLookup, IUserInterfaceManager userInterfaceManager)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_system = system;
|
||||
_entityManager = entityManager;
|
||||
_eyeManager = eyeManager;
|
||||
_entityLookup = entityLookup;
|
||||
_userInterfaceManager = userInterfaceManager;
|
||||
ZIndex = 200;
|
||||
// Setting these to a specific ttf would break the antag symbols
|
||||
_font = resourceCache.NotoStack();
|
||||
_fontBold = resourceCache.NotoStack(variation: "Bold");
|
||||
|
||||
config.OnValueChanged(CCVars.AdminOverlayClassic, (show) => { _overlayClassic = show; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlaySymbols, (show) => { _overlaySymbols = show; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayPlaytime, (show) => { _overlayPlaytime = show; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayStartingJob, (show) => { _overlayStartingJob = show; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayGhostHideDistance, (f) => { _ghostHideDistance = f; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayGhostFadeDistance, (f) => { _ghostFadeDistance = f; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayStackMax, (i) => { _overlayStackMax = i; }, true);
|
||||
config.OnValueChanged(CCVars.AdminOverlayMergeDistance, (f) => { _overlayMergeDistance = f; }, true);
|
||||
_font = new VectorFont(resourceCache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
|
||||
}
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||
@@ -72,147 +47,75 @@ internal sealed class AdminNameOverlay : Overlay
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
var viewport = args.WorldAABB;
|
||||
var colorDisconnected = Color.White;
|
||||
var uiScale = _userInterfaceManager.RootControl.UIScale;
|
||||
var lineoffset = new Vector2(0f, 14f) * uiScale;
|
||||
var drawnOverlays = new List<(Vector2,Vector2)>() ; // A saved list of the overlays already drawn
|
||||
|
||||
// Get all player positions before drawing overlays, so they can be sorted before iteration
|
||||
var sortable = new List<(PlayerInfo, Box2, EntityUid, Vector2)>();
|
||||
foreach (var info in _system.PlayerList)
|
||||
//TODO make this adjustable via GUI
|
||||
var classic = _config.GetCVar(CCVars.AdminOverlayClassic);
|
||||
var playTime = _config.GetCVar(CCVars.AdminOverlayPlaytime);
|
||||
var startingJob = _config.GetCVar(CCVars.AdminOverlayStartingJob);
|
||||
|
||||
foreach (var playerInfo in _system.PlayerList)
|
||||
{
|
||||
var entity = _entityManager.GetEntity(info.NetEntity);
|
||||
var entity = _entityManager.GetEntity(playerInfo.NetEntity);
|
||||
|
||||
// If entity does not exist or is on a different map, skip
|
||||
if (entity == null
|
||||
|| !_entityManager.EntityExists(entity)
|
||||
|| _entityManager.GetComponent<TransformComponent>(entity.Value).MapID != args.MapId)
|
||||
// Otherwise the entity can not exist yet
|
||||
if (entity == null || !_entityManager.EntityExists(entity))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if not on the same map, continue
|
||||
if (_entityManager.GetComponent<TransformComponent>(entity.Value).MapID != args.MapId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var aabb = _entityLookup.GetWorldAABB(entity.Value);
|
||||
// if not on screen, skip
|
||||
|
||||
// if not on screen, continue
|
||||
if (!aabb.Intersects(in viewport))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get on-screen coordinates of player
|
||||
var screenCoordinates = _eyeManager.WorldToScreen(aabb.Center).Rounded();
|
||||
var uiScale = _userInterfaceManager.RootControl.UIScale;
|
||||
var lineoffset = new Vector2(0f, 14f) * uiScale;
|
||||
var screenCoordinates = _eyeManager.WorldToScreen(aabb.Center +
|
||||
new Angle(-_eyeManager.CurrentEye.Rotation).RotateVec(
|
||||
aabb.TopRight - aabb.Center)) + new Vector2(1f, 7f);
|
||||
|
||||
sortable.Add((info, aabb, entity.Value, screenCoordinates));
|
||||
}
|
||||
|
||||
// Draw overlays for visible players, starting from the top of the screen
|
||||
foreach (var info in sortable.OrderBy(s => s.Item4.Y).ToList())
|
||||
{
|
||||
var playerInfo = info.Item1;
|
||||
var aabb = info.Item2;
|
||||
var entity = info.Item3;
|
||||
var screenCoordinatesCenter = info.Item4;
|
||||
//the center position is kept separately, for simpler position comparison later
|
||||
var centerOffset = new Vector2(28f, -18f) * uiScale;
|
||||
var screenCoordinates = screenCoordinatesCenter + centerOffset;
|
||||
var alpha = 1f;
|
||||
|
||||
//TODO make a smarter system where the starting offset can be modified by the predicted position and size of already-drawn overlays/stacks?
|
||||
var currentOffset = Vector2.Zero;
|
||||
|
||||
// Ghosts near the cursor are made transparent/invisible
|
||||
// TODO would be "cheaper" if playerinfo already contained a ghost bool, this gets called every frame for every onscreen player!
|
||||
if (_entityManager.HasComponent<GhostComponent>(entity))
|
||||
{
|
||||
// We want the map positions here, so we don't have to worry about resolution and such shenanigans
|
||||
var mobPosition = aabb.Center;
|
||||
var mousePosition = _eyeManager
|
||||
.ScreenToMap(_userInterfaceManager.MousePositionScaled.Position * uiScale)
|
||||
.Position;
|
||||
var dist = Vector2.Distance(mobPosition, mousePosition);
|
||||
if (dist < _ghostHideDistance)
|
||||
continue;
|
||||
|
||||
alpha = Math.Clamp((dist - _ghostHideDistance) / (_ghostFadeDistance - _ghostHideDistance), 0f, 1f);
|
||||
colorDisconnected.A = alpha;
|
||||
}
|
||||
|
||||
// If the new overlay text block is within merge distance of any previous ones
|
||||
// merge them into a stack so they don't hide each other
|
||||
var stack = drawnOverlays.FindAll(x =>
|
||||
Vector2.Distance(_eyeManager.ScreenToMap(x.Item1).Position, aabb.Center) <= _overlayMergeDistance);
|
||||
if (stack.Count > 0)
|
||||
{
|
||||
screenCoordinates = stack.First().Item1 + centerOffset;
|
||||
// Replacing this overlay's coordinates for the later save with the stack root's coordinates
|
||||
// so that other overlays don't try to stack to these coordinates
|
||||
screenCoordinatesCenter = stack.First().Item1;
|
||||
|
||||
var i = 1;
|
||||
foreach (var s in stack)
|
||||
{
|
||||
// additional entries after maximum stack size is reached will be drawn over the last entry
|
||||
if (i <= _overlayStackMax - 1)
|
||||
currentOffset = lineoffset + s.Item2 ;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Character name
|
||||
var color = Color.Aquamarine;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.CharacterName, uiScale, playerInfo.Connected ? color : colorDisconnected);
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.CharacterName, uiScale, playerInfo.Connected ? Color.Aquamarine : Color.White);
|
||||
currentOffset += lineoffset;
|
||||
|
||||
// Username
|
||||
color = Color.Yellow;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.Username, uiScale, playerInfo.Connected ? color : colorDisconnected);
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.Username, uiScale, playerInfo.Connected ? Color.Yellow : Color.White);
|
||||
currentOffset += lineoffset;
|
||||
|
||||
// Playtime
|
||||
if (!string.IsNullOrEmpty(playerInfo.PlaytimeString) && _overlayPlaytime)
|
||||
if (!string.IsNullOrEmpty(playerInfo.PlaytimeString) && playTime)
|
||||
{
|
||||
color = Color.Orange;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.PlaytimeString, uiScale, playerInfo.Connected ? color : colorDisconnected);
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, playerInfo.PlaytimeString, uiScale, playerInfo.Connected ? Color.Orange : Color.White);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
|
||||
// Job
|
||||
if (!string.IsNullOrEmpty(playerInfo.StartingJob) && _overlayStartingJob)
|
||||
if (!string.IsNullOrEmpty(playerInfo.StartingJob) && startingJob)
|
||||
{
|
||||
color = Color.GreenYellow;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, Loc.GetString(playerInfo.StartingJob), uiScale, playerInfo.Connected ? color : colorDisconnected);
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, Loc.GetString(playerInfo.StartingJob), uiScale, playerInfo.Connected ? Color.GreenYellow : Color.White);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
|
||||
// Classic Antag Label
|
||||
if (_overlayClassic && playerInfo.Antag)
|
||||
if (classic && playerInfo.Antag)
|
||||
{
|
||||
var symbol = _overlaySymbols ? Loc.GetString("player-tab-antag-prefix") : string.Empty;
|
||||
var label = _overlaySymbols
|
||||
? Loc.GetString("player-tab-character-name-antag-symbol",
|
||||
("symbol", symbol),
|
||||
("name", _antagLabelClassic))
|
||||
: _antagLabelClassic;
|
||||
color = Color.OrangeRed;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, color);
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, _antagLabelClassic, uiScale, Color.OrangeRed);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
// Role Type
|
||||
else if (!_overlayClassic && _filter.Contains(playerInfo.RoleProto))
|
||||
else if (!classic && _filter.Contains(playerInfo.RoleProto))
|
||||
{
|
||||
var symbol = _overlaySymbols && playerInfo.Antag ? playerInfo.RoleProto.Symbol : string.Empty;
|
||||
var role = Loc.GetString(playerInfo.RoleProto.Name).ToUpper();
|
||||
var label = _overlaySymbols
|
||||
? Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", role))
|
||||
: role;
|
||||
color = playerInfo.RoleProto.Color;
|
||||
color.A = alpha;
|
||||
args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, color);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
var label = Loc.GetString(playerInfo.RoleProto.Name).ToUpper();
|
||||
var color = playerInfo.RoleProto.Color;
|
||||
|
||||
//Save the coordinates and size of the text block, for stack merge check
|
||||
drawnOverlays.Add((screenCoordinatesCenter, currentOffset));
|
||||
args.ScreenHandle.DrawString(_font, screenCoordinates + currentOffset, label, uiScale, color);
|
||||
currentOffset += lineoffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace Content.Client.Administration.Systems
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
|
||||
private AdminNameOverlay _adminNameOverlay = default!;
|
||||
|
||||
@@ -23,14 +22,7 @@ namespace Content.Client.Administration.Systems
|
||||
|
||||
private void InitializeOverlay()
|
||||
{
|
||||
_adminNameOverlay = new AdminNameOverlay(
|
||||
this,
|
||||
EntityManager,
|
||||
_eyeManager,
|
||||
_resourceCache,
|
||||
_entityLookup,
|
||||
_userInterfaceManager,
|
||||
_configurationManager);
|
||||
_adminNameOverlay = new AdminNameOverlay(this, EntityManager, _eyeManager, _resourceCache, _entityLookup, _userInterfaceManager);
|
||||
_adminManager.AdminStatusUpdated += OnAdminStatusUpdated;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls">
|
||||
<PanelContainer StyleClasses="BackgroundDark">
|
||||
<SplitContainer Orientation="Vertical" ResizeMode="NotResizable">
|
||||
<SplitContainer Orientation="Vertical">
|
||||
<SplitContainer Orientation="Horizontal" VerticalExpand="True">
|
||||
<cc:PlayerListControl Access="Public" Name="ChannelSelector" HorizontalExpand="True" SizeFlagsStretchRatio="2" />
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="2">
|
||||
<BoxContainer Access="Public" Name="BwoinkArea" VerticalExpand="True" />
|
||||
</BoxContainer>
|
||||
</SplitContainer>
|
||||
<BoxContainer Orientation="Horizontal" SetHeight="30" >
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<CheckBox Name="AdminOnly" Access="Public" Text="{Loc 'admin-ahelp-admin-only'}" ToolTip="{Loc 'admin-ahelp-admin-only-tooltip'}" />
|
||||
<Control HorizontalExpand="True" MinWidth="5" />
|
||||
<CheckBox Name="PlaySound" Access="Public" Text="{Loc 'admin-bwoink-play-sound'}" Pressed="True" />
|
||||
|
||||
@@ -2,13 +2,11 @@ using System.Linq;
|
||||
using Content.Client.Administration.Systems;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Configuration;
|
||||
using static Content.Client.Administration.UI.Tabs.PlayerTab.PlayerTabHeader;
|
||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
||||
|
||||
@@ -18,7 +16,6 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab;
|
||||
public sealed partial class PlayerTab : Control
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerMan = default!;
|
||||
|
||||
private const string ArrowUp = "↑";
|
||||
@@ -44,10 +41,6 @@ public sealed partial class PlayerTab : Control
|
||||
_adminSystem.OverlayEnabled += OverlayEnabled;
|
||||
_adminSystem.OverlayDisabled += OverlayDisabled;
|
||||
|
||||
_config.OnValueChanged(CCVars.AdminPlayerlistSeparateSymbols, PlayerListSettingsChanged);
|
||||
_config.OnValueChanged(CCVars.AdminPlayerlistHighlightedCharacterColor, PlayerListSettingsChanged);
|
||||
_config.OnValueChanged(CCVars.AdminPlayerlistRoleTypeColor, PlayerListSettingsChanged);
|
||||
|
||||
OverlayButton.OnPressed += OverlayButtonPressed;
|
||||
ShowDisconnectedButton.OnPressed += ShowDisconnectedPressed;
|
||||
|
||||
@@ -113,11 +106,6 @@ public sealed partial class PlayerTab : Control
|
||||
|
||||
#region ListContainer
|
||||
|
||||
private void PlayerListSettingsChanged(bool _)
|
||||
{
|
||||
RefreshPlayerList(_adminSystem.PlayerList);
|
||||
}
|
||||
|
||||
private void RefreshPlayerList(IReadOnlyList<PlayerInfo> players)
|
||||
{
|
||||
_players = players;
|
||||
@@ -208,7 +196,8 @@ public sealed partial class PlayerTab : Control
|
||||
Header.Username => Compare(x.Username, y.Username),
|
||||
Header.Character => Compare(x.CharacterName, y.CharacterName),
|
||||
Header.Job => Compare(x.StartingJob, y.StartingJob),
|
||||
Header.RoleType => y.SortWeight - x.SortWeight,
|
||||
Header.Antagonist => x.Antag.CompareTo(y.Antag),
|
||||
Header.RoleType => Compare(x.RoleProto.Name , y.RoleProto.Name),
|
||||
Header.Playtime => TimeSpan.Compare(x.OverallPlaytime ?? default, y.OverallPlaytime ?? default),
|
||||
_ => 1
|
||||
};
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
HorizontalExpand="True"
|
||||
ClipText="True"/>
|
||||
<customControls:VSeparator/>
|
||||
<Label Name="AntagonistLabel"
|
||||
SizeFlagsStretchRatio="1"
|
||||
HorizontalExpand="True"
|
||||
ClipText="True"/>
|
||||
<customControls:VSeparator/>
|
||||
<Label Name="RoleTypeLabel"
|
||||
SizeFlagsStretchRatio="2"
|
||||
HorizontalExpand="True"
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Client.Administration.UI.Tabs.PlayerTab;
|
||||
|
||||
@@ -16,25 +14,17 @@ public sealed partial class PlayerTabEntry : PanelContainer
|
||||
public PlayerTabEntry(PlayerInfo player, StyleBoxFlat styleBoxFlat)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
var config = IoCManager.Resolve<IConfigurationManager>();
|
||||
|
||||
UsernameLabel.Text = player.Username;
|
||||
if (!player.Connected)
|
||||
UsernameLabel.StyleClasses.Add("Disabled");
|
||||
JobLabel.Text = player.StartingJob;
|
||||
var separateAntagSymbols = config.GetCVar(CCVars.AdminPlayerlistSeparateSymbols);
|
||||
var genericAntagSymbol = player.Antag ? Loc.GetString("player-tab-antag-prefix") : string.Empty;
|
||||
var roleSymbol = player.Antag ? player.RoleProto.Symbol : string.Empty;
|
||||
var symbol = separateAntagSymbols ? roleSymbol : genericAntagSymbol;
|
||||
CharacterLabel.Text = Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", player.CharacterName));
|
||||
|
||||
if (player.Antag && config.GetCVar(CCVars.AdminPlayerlistHighlightedCharacterColor))
|
||||
CharacterLabel.FontColorOverride = player.RoleProto.Color;
|
||||
CharacterLabel.Text = player.CharacterName;
|
||||
if (player.IdentityName != player.CharacterName)
|
||||
CharacterLabel.Text += $" [{player.IdentityName}]";
|
||||
AntagonistLabel.Text = Loc.GetString(player.Antag ? "player-tab-is-antag-yes" : "player-tab-is-antag-no");
|
||||
RoleTypeLabel.Text = Loc.GetString(player.RoleProto.Name);
|
||||
if (config.GetCVar(CCVars.AdminPlayerlistRoleTypeColor))
|
||||
RoleTypeLabel.FontColorOverride = player.RoleProto.Color;
|
||||
RoleTypeLabel.FontColorOverride = player.RoleProto.Color;
|
||||
BackgroundColorPanel.PanelOverride = styleBoxFlat;
|
||||
OverallPlaytimeLabel.Text = player.PlaytimeString;
|
||||
PlayerEntity = player.NetEntity;
|
||||
|
||||
@@ -25,6 +25,13 @@
|
||||
Text="{Loc player-tab-job}"
|
||||
MouseFilter="Pass"/>
|
||||
<cc:VSeparator/>
|
||||
<Label Name="AntagonistLabel"
|
||||
SizeFlagsStretchRatio="1"
|
||||
HorizontalExpand="True"
|
||||
ClipText="True"
|
||||
Text="{Loc player-tab-antagonist}"
|
||||
MouseFilter="Pass"/>
|
||||
<cc:VSeparator/>
|
||||
<Label Name="RoleTypeLabel"
|
||||
SizeFlagsStretchRatio="2"
|
||||
HorizontalExpand="True"
|
||||
|
||||
@@ -18,6 +18,7 @@ public sealed partial class PlayerTabHeader : Control
|
||||
UsernameLabel.OnKeyBindDown += UsernameClicked;
|
||||
CharacterLabel.OnKeyBindDown += CharacterClicked;
|
||||
JobLabel.OnKeyBindDown += JobClicked;
|
||||
AntagonistLabel.OnKeyBindDown += AntagonistClicked;
|
||||
RoleTypeLabel.OnKeyBindDown += RoleTypeClicked;
|
||||
PlaytimeLabel.OnKeyBindDown += PlaytimeClicked;
|
||||
}
|
||||
@@ -29,6 +30,7 @@ public sealed partial class PlayerTabHeader : Control
|
||||
Header.Username => UsernameLabel,
|
||||
Header.Character => CharacterLabel,
|
||||
Header.Job => JobLabel,
|
||||
Header.Antagonist => AntagonistLabel,
|
||||
Header.RoleType => RoleTypeLabel,
|
||||
Header.Playtime => PlaytimeLabel,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(header), header, null)
|
||||
@@ -40,6 +42,7 @@ public sealed partial class PlayerTabHeader : Control
|
||||
UsernameLabel.Text = Loc.GetString("player-tab-username");
|
||||
CharacterLabel.Text = Loc.GetString("player-tab-character");
|
||||
JobLabel.Text = Loc.GetString("player-tab-job");
|
||||
AntagonistLabel.Text = Loc.GetString("player-tab-antagonist");
|
||||
RoleTypeLabel.Text = Loc.GetString("player-tab-roletype");
|
||||
PlaytimeLabel.Text = Loc.GetString("player-tab-playtime");
|
||||
}
|
||||
@@ -70,6 +73,11 @@ public sealed partial class PlayerTabHeader : Control
|
||||
HeaderClicked(args, Header.Job);
|
||||
}
|
||||
|
||||
private void AntagonistClicked(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
HeaderClicked(args, Header.Antagonist);
|
||||
}
|
||||
|
||||
private void RoleTypeClicked(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
HeaderClicked(args, Header.RoleType);
|
||||
@@ -89,6 +97,7 @@ public sealed partial class PlayerTabHeader : Control
|
||||
UsernameLabel.OnKeyBindDown -= UsernameClicked;
|
||||
CharacterLabel.OnKeyBindDown -= CharacterClicked;
|
||||
JobLabel.OnKeyBindDown -= JobClicked;
|
||||
AntagonistLabel.OnKeyBindDown -= AntagonistClicked;
|
||||
RoleTypeLabel.OnKeyBindDown -= RoleTypeClicked;
|
||||
PlaytimeLabel.OnKeyBindDown -= PlaytimeClicked;
|
||||
}
|
||||
@@ -99,6 +108,7 @@ public sealed partial class PlayerTabHeader : Control
|
||||
Username,
|
||||
Character,
|
||||
Job,
|
||||
Antagonist,
|
||||
RoleType,
|
||||
Playtime
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public sealed class ClientAlertsSystem : AlertsSystem
|
||||
if (args.Current is not AlertComponentState cast)
|
||||
return;
|
||||
|
||||
alerts.Comp.Alerts = new(cast.Alerts);
|
||||
alerts.Comp.Alerts = cast.Alerts;
|
||||
|
||||
UpdateHud(alerts);
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
using Content.Shared.CartridgeLoader.Cartridges;
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
public sealed class NanoTaskCartridgeSystem : SharedNanoTaskCartridgeSystem;
|
||||
@@ -1,32 +0,0 @@
|
||||
<Control xmlns="https://spacestation14.io" xmlns:system="clr-namespace:System;assembly=System.Runtime">
|
||||
<BoxContainer Name="MainContainer"
|
||||
Orientation="Horizontal"
|
||||
SetWidth="250">
|
||||
<Button Name="MainButton"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True"
|
||||
StyleClasses="ButtonSquare"
|
||||
Margin="-1 0 0 0">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
Margin="-5 0 0 0">
|
||||
<Label Name="TaskLabel"
|
||||
StyleClasses="LabelSubText" />
|
||||
<Label Name="TaskForLabel"
|
||||
StyleClasses="LabelSubText"
|
||||
Margin="0 -5 0 0" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</Button>
|
||||
<Button Name="DoneButton"
|
||||
VerticalExpand="True"
|
||||
Text="{Loc 'nano-task-ui-done'}">
|
||||
<Button.StyleClasses>
|
||||
<system:String>ButtonSmall</system:String>
|
||||
<system:String>OpenLeft</system:String>
|
||||
</Button.StyleClasses>
|
||||
</Button>
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
@@ -1,33 +0,0 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Maths;
|
||||
using Content.Shared.CartridgeLoader.Cartridges;
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single control for a single NanoTask item
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class NanoTaskItemControl : Control
|
||||
{
|
||||
public Action<int>? OnMainPressed;
|
||||
public Action<int>? OnDonePressed;
|
||||
|
||||
public NanoTaskItemControl(NanoTaskItemAndId item)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
TaskLabel.Text = item.Data.Description;
|
||||
TaskLabel.FontColorOverride = Color.White;
|
||||
TaskForLabel.Text = item.Data.TaskIsFor;
|
||||
|
||||
MainButton.OnPressed += _ => OnMainPressed?.Invoke(item.Id);
|
||||
DoneButton.OnPressed += _ => OnDonePressed?.Invoke(item.Id);
|
||||
|
||||
MainButton.Disabled = item.Data.IsTaskDone;
|
||||
DoneButton.Text = item.Data.IsTaskDone ? Loc.GetString("nano-task-ui-revert-done") : Loc.GetString("nano-task-ui-done");
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
Title="{Loc nano-task-ui-item-title}"
|
||||
MinSize="300 300">
|
||||
<PanelContainer StyleClasses="AngleRect">
|
||||
<BoxContainer Orientation="Vertical" Margin="4">
|
||||
<!-- Task Description Input -->
|
||||
<BoxContainer Orientation="Vertical" Margin="0 4">
|
||||
<Label Text="{Loc nano-task-ui-description-label}"
|
||||
StyleClasses="LabelHeading" />
|
||||
<PanelContainer StyleClasses="ButtonSquare">
|
||||
<LineEdit Name="DescriptionInput"
|
||||
PlaceHolder="{Loc nano-task-ui-description-placeholder}" />
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<!-- Task Requester Input -->
|
||||
<BoxContainer Orientation="Vertical" Margin="0 4">
|
||||
<Label Text="{Loc nano-task-ui-requester-label}"
|
||||
StyleClasses="LabelHeading" />
|
||||
<PanelContainer StyleClasses="ButtonSquare">
|
||||
<LineEdit Name="RequesterInput"
|
||||
PlaceHolder="{Loc nano-task-ui-requester-placeholder}" />
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<!-- Severity Buttons -->
|
||||
<BoxContainer Orientation="Horizontal"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0 8 0 0">
|
||||
<Button Name="LowButton"
|
||||
Text="{Loc nano-task-ui-priority-low}"
|
||||
StyleClasses="OpenRight"
|
||||
MinSize="60 0" />
|
||||
<Button Name="MediumButton"
|
||||
Text="{Loc nano-task-ui-priority-medium}"
|
||||
StyleClasses="ButtonSquare"
|
||||
MinSize="60 0" />
|
||||
<Button Name="HighButton"
|
||||
Text="{Loc nano-task-ui-priority-high}"
|
||||
StyleClasses="OpenLeft"
|
||||
MinSize="60 0" />
|
||||
</BoxContainer>
|
||||
|
||||
<!-- Verb Buttons -->
|
||||
<BoxContainer Orientation="Horizontal"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0 8 0 0">
|
||||
<Button Name="CancelButton"
|
||||
Text="{Loc nano-task-ui-cancel}"
|
||||
StyleClasses="OpenRight"
|
||||
MinSize="60 0" />
|
||||
<Button Name="DeleteButton"
|
||||
Text="{Loc nano-task-ui-delete}"
|
||||
StyleClasses="ButtonSquare"
|
||||
MinSize="60 0" />
|
||||
<Button Name="PrintButton"
|
||||
Text="{Loc nano-task-ui-print}"
|
||||
StyleClasses="ButtonSquare"
|
||||
MinSize="60 0" />
|
||||
<Button Name="SaveButton"
|
||||
Text="{Loc nano-task-ui-save}"
|
||||
StyleClasses="OpenLeft"
|
||||
MinSize="60 0" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</DefaultWindow>
|
||||
@@ -1,109 +0,0 @@
|
||||
using System.Linq;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Content.Shared.CartridgeLoader.Cartridges;
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
/// <summary>
|
||||
/// Popup displayed to edit a NanoTask item
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class NanoTaskItemPopup : DefaultWindow
|
||||
{
|
||||
private readonly ButtonGroup _priorityGroup = new();
|
||||
private int? _editingTaskId = null;
|
||||
|
||||
public Action<int, NanoTaskItem>? TaskSaved;
|
||||
public Action<int>? TaskDeleted;
|
||||
public Action<NanoTaskItem>? TaskCreated;
|
||||
public Action<NanoTaskItem>? TaskPrinted;
|
||||
|
||||
private NanoTaskItem MakeItem()
|
||||
{
|
||||
return new(
|
||||
description: DescriptionInput.Text,
|
||||
taskIsFor: RequesterInput.Text,
|
||||
isTaskDone: false,
|
||||
priority: _priorityGroup.Pressed switch {
|
||||
var item when item == LowButton => NanoTaskPriority.Low,
|
||||
var item when item == MediumButton => NanoTaskPriority.Medium,
|
||||
var item when item == HighButton => NanoTaskPriority.High,
|
||||
_ => NanoTaskPriority.Medium,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public NanoTaskItemPopup()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
LowButton.Group = _priorityGroup;
|
||||
MediumButton.Group = _priorityGroup;
|
||||
HighButton.Group = _priorityGroup;
|
||||
|
||||
CancelButton.OnPressed += _ => Close();
|
||||
DeleteButton.OnPressed += _ =>
|
||||
{
|
||||
if (_editingTaskId is int id)
|
||||
{
|
||||
TaskDeleted?.Invoke(id);
|
||||
}
|
||||
};
|
||||
PrintButton.OnPressed += _ =>
|
||||
{
|
||||
TaskPrinted?.Invoke(MakeItem());
|
||||
};
|
||||
SaveButton.OnPressed += _ =>
|
||||
{
|
||||
if (_editingTaskId is int id)
|
||||
{
|
||||
TaskSaved?.Invoke(id, MakeItem());
|
||||
}
|
||||
else
|
||||
{
|
||||
TaskCreated?.Invoke(MakeItem());
|
||||
}
|
||||
};
|
||||
|
||||
DescriptionInput.OnTextChanged += args =>
|
||||
{
|
||||
if (args.Text.Length > NanoTaskItem.MaximumStringLength)
|
||||
DescriptionInput.Text = args.Text[..NanoTaskItem.MaximumStringLength];
|
||||
};
|
||||
RequesterInput.OnTextChanged += args =>
|
||||
{
|
||||
if (args.Text.Length > NanoTaskItem.MaximumStringLength)
|
||||
RequesterInput.Text = args.Text[..NanoTaskItem.MaximumStringLength];
|
||||
};
|
||||
}
|
||||
|
||||
public void SetEditingTaskId(int? id)
|
||||
{
|
||||
_editingTaskId = id;
|
||||
DeleteButton.Visible = id is not null;
|
||||
}
|
||||
|
||||
public void ResetInputs(NanoTaskItem? item)
|
||||
{
|
||||
if (item is NanoTaskItem task)
|
||||
{
|
||||
var button = task.Priority switch {
|
||||
NanoTaskPriority.High => HighButton,
|
||||
NanoTaskPriority.Medium => MediumButton,
|
||||
NanoTaskPriority.Low => LowButton,
|
||||
};
|
||||
button.Pressed = true;
|
||||
DescriptionInput.Text = task.Description;
|
||||
RequesterInput.Text = task.TaskIsFor;
|
||||
}
|
||||
else
|
||||
{
|
||||
MediumButton.Pressed = true;
|
||||
DescriptionInput.Text = "";
|
||||
RequesterInput.Text = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface.Fragments;
|
||||
using Content.Shared.CartridgeLoader;
|
||||
using Content.Shared.CartridgeLoader.Cartridges;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
/// <summary>
|
||||
/// UI fragment responsible for displaying NanoTask controls in a PDA and coordinating with the NanoTaskCartridgeSystem for state
|
||||
/// </summary>
|
||||
public sealed partial class NanoTaskUi : UIFragment
|
||||
{
|
||||
private NanoTaskUiFragment? _fragment;
|
||||
private NanoTaskItemPopup? _popup;
|
||||
|
||||
public override Control GetUIFragmentRoot()
|
||||
{
|
||||
return _fragment!;
|
||||
}
|
||||
|
||||
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
|
||||
{
|
||||
_fragment = new NanoTaskUiFragment();
|
||||
_popup = new NanoTaskItemPopup();
|
||||
_fragment.NewTask += () =>
|
||||
{
|
||||
_popup.ResetInputs(null);
|
||||
_popup.SetEditingTaskId(null);
|
||||
_popup.OpenCentered();
|
||||
};
|
||||
_fragment.OpenTask += id =>
|
||||
{
|
||||
if (_fragment.Tasks.Find(task => task.Id == id) is not NanoTaskItemAndId task)
|
||||
return;
|
||||
|
||||
_popup.ResetInputs(task.Data);
|
||||
_popup.SetEditingTaskId(task.Id);
|
||||
_popup.OpenCentered();
|
||||
};
|
||||
_fragment.ToggleTaskCompletion += id =>
|
||||
{
|
||||
if (_fragment.Tasks.Find(task => task.Id == id) is not NanoTaskItemAndId task)
|
||||
return;
|
||||
|
||||
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskUpdateTask(new(id, new(
|
||||
description: task.Data.Description,
|
||||
taskIsFor: task.Data.TaskIsFor,
|
||||
isTaskDone: !task.Data.IsTaskDone,
|
||||
priority: task.Data.Priority
|
||||
))))));
|
||||
};
|
||||
_popup.TaskSaved += (id, data) =>
|
||||
{
|
||||
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskUpdateTask(new(id, data)))));
|
||||
_popup.Close();
|
||||
};
|
||||
_popup.TaskDeleted += id =>
|
||||
{
|
||||
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskDeleteTask(id))));
|
||||
_popup.Close();
|
||||
};
|
||||
_popup.TaskCreated += data =>
|
||||
{
|
||||
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskAddTask(data))));
|
||||
_popup.Close();
|
||||
};
|
||||
_popup.TaskPrinted += data =>
|
||||
{
|
||||
userInterface.SendMessage(new CartridgeUiMessage(new NanoTaskUiMessageEvent(new NanoTaskPrintTask(data))));
|
||||
};
|
||||
}
|
||||
|
||||
public override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
if (state is not NanoTaskUiState nanoTaskState)
|
||||
return;
|
||||
|
||||
_fragment?.UpdateState(nanoTaskState.Tasks);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<cartridges:NanoTaskUiFragment xmlns:cartridges="clr-namespace:Content.Client.CartridgeLoader.Cartridges"
|
||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns="https://spacestation14.io" Margin="1 0 2 0">
|
||||
|
||||
<PanelContainer StyleClasses="BackgroundDark"></PanelContainer>
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<ScrollContainer HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical" Margin="8" SeparationOverride="8">
|
||||
<!-- Heading for High Priority Items -->
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<PanelContainer SetWidth="7" Margin="0 0 8 0">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#e93d58"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
</PanelContainer>
|
||||
<Label Name="HighPriority" StyleClasses="LabelHeading"/>
|
||||
</BoxContainer>
|
||||
<!-- Location for High Priority Items -->
|
||||
<GridContainer Name="HighContainer"
|
||||
HorizontalExpand="True"
|
||||
Access="Public"
|
||||
Columns="2" />
|
||||
|
||||
<!-- Heading for Medium Priority Items -->
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<PanelContainer SetWidth="7" Margin="0 0 8 0">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#ef973c"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
</PanelContainer>
|
||||
<Label Name="MediumPriority" StyleClasses="LabelHeading"/>
|
||||
</BoxContainer>
|
||||
<!-- Location for Medium Priority Items -->
|
||||
<GridContainer Name="MediumContainer"
|
||||
HorizontalExpand="True"
|
||||
Access="Public"
|
||||
Columns="2" />
|
||||
|
||||
<!-- Location for Low Priority Items -->
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<PanelContainer SetWidth="7" Margin="0 0 8 0">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#3dd425"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
</PanelContainer>
|
||||
<Label Name="LowPriority" StyleClasses="LabelHeading"/>
|
||||
</BoxContainer>
|
||||
<!-- Location for Low Priority Items -->
|
||||
<GridContainer Name="LowContainer"
|
||||
HorizontalExpand="True"
|
||||
Access="Public"
|
||||
Columns="2" />
|
||||
|
||||
<Button Name="NewTaskButton" Text="{Loc 'nano-task-ui-new-task'}" HorizontalAlignment="Right"/>
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
</BoxContainer>
|
||||
</cartridges:NanoTaskUiFragment>
|
||||
@@ -1,52 +0,0 @@
|
||||
using System.Linq;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Content.Shared.CartridgeLoader.Cartridges;
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
/// <summary>
|
||||
/// Class displaying the main UI of NanoTask
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class NanoTaskUiFragment : BoxContainer
|
||||
{
|
||||
public Action<int>? OpenTask;
|
||||
public Action<int>? ToggleTaskCompletion;
|
||||
public Action? NewTask;
|
||||
public List<NanoTaskItemAndId> Tasks = new();
|
||||
|
||||
public NanoTaskUiFragment()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
Orientation = LayoutOrientation.Vertical;
|
||||
HorizontalExpand = true;
|
||||
VerticalExpand = true;
|
||||
NewTaskButton.OnPressed += _ => NewTask?.Invoke();
|
||||
}
|
||||
public void UpdateState(List<NanoTaskItemAndId> tasks)
|
||||
{
|
||||
Tasks = tasks;
|
||||
HighContainer.RemoveAllChildren();
|
||||
MediumContainer.RemoveAllChildren();
|
||||
LowContainer.RemoveAllChildren();
|
||||
|
||||
HighPriority.Text = Loc.GetString("nano-task-ui-heading-high-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.High)));
|
||||
MediumPriority.Text = Loc.GetString("nano-task-ui-heading-medium-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.Medium)));
|
||||
LowPriority.Text = Loc.GetString("nano-task-ui-heading-low-priority-tasks", ("amount", tasks.Count(task => task.Data.Priority == NanoTaskPriority.Low)));
|
||||
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
var container = task.Data.Priority switch {
|
||||
NanoTaskPriority.High => HighContainer,
|
||||
NanoTaskPriority.Medium => MediumContainer,
|
||||
NanoTaskPriority.Low => LowContainer,
|
||||
};
|
||||
var control = new NanoTaskItemControl(task);
|
||||
container.AddChild(control);
|
||||
control.OnMainPressed += id => OpenTask?.Invoke(id);
|
||||
control.OnDonePressed += id => ToggleTaskCompletion?.Invoke(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,13 +131,13 @@ public sealed partial class ChangelogTab : Control
|
||||
Margin = new Thickness(6, 0, 0, 0),
|
||||
};
|
||||
authorLabel.SetMessage(
|
||||
FormattedMessage.FromMarkupOrThrow(Loc.GetString("changelog-author-changed", ("author", FormattedMessage.EscapeText(author)))));
|
||||
FormattedMessage.FromMarkupOrThrow(Loc.GetString("changelog-author-changed", ("author", author))));
|
||||
ChangelogBody.AddChild(authorLabel);
|
||||
|
||||
foreach (var change in groupedEntry.SelectMany(c => c.Changes))
|
||||
{
|
||||
var text = new RichTextLabel();
|
||||
text.SetMessage(FormattedMessage.FromUnformatted(change.Message));
|
||||
text.SetMessage(FormattedMessage.FromMarkupOrThrow(change.Message));
|
||||
ChangelogBody.AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
|
||||
@@ -169,7 +169,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||
|
||||
var state = $"equipped-{correctedSlot}";
|
||||
|
||||
if (!string.IsNullOrEmpty(clothing.EquippedPrefix))
|
||||
if (clothing.EquippedPrefix != null)
|
||||
state = $"{clothing.EquippedPrefix}-equipped-{correctedSlot}";
|
||||
|
||||
if (clothing.EquippedState != null)
|
||||
|
||||
@@ -3,7 +3,6 @@ using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CriminalRecords;
|
||||
using Content.Shared.Dataset;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Security;
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Client.AutoGenerated;
|
||||
@@ -33,7 +32,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
||||
|
||||
public readonly EntityUid Console;
|
||||
|
||||
[ValidatePrototypeId<LocalizedDatasetPrototype>]
|
||||
[ValidatePrototypeId<DatasetPrototype>]
|
||||
private const string ReasonPlaceholders = "CriminalRecordsWantedReasonPlaceholders";
|
||||
|
||||
public Action<uint?>? OnKeySelected;
|
||||
@@ -334,8 +333,8 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
||||
|
||||
var field = "reason";
|
||||
var title = Loc.GetString("criminal-records-status-" + status.ToString().ToLower());
|
||||
var placeholders = _proto.Index<LocalizedDatasetPrototype>(ReasonPlaceholders);
|
||||
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders))); // just funny it doesn't actually get used
|
||||
var placeholders = _proto.Index<DatasetPrototype>(ReasonPlaceholders);
|
||||
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders.Values))); // just funny it doesn't actually get used
|
||||
var prompt = Loc.GetString("criminal-records-console-reason");
|
||||
var entry = new QuickDialogEntry(field, QuickDialogEntryType.LongText, prompt, placeholder);
|
||||
var entries = new List<QuickDialogEntry>() { entry };
|
||||
|
||||
@@ -4,7 +4,6 @@ using Content.Shared.Verbs;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -41,17 +40,7 @@ public sealed class ExamineButton : ContainerButton
|
||||
Disabled = true;
|
||||
}
|
||||
|
||||
TooltipSupplier = sender =>
|
||||
{
|
||||
var label = new RichTextLabel();
|
||||
label.SetMessage(FormattedMessage.FromMarkupOrThrow(verb.Message ?? verb.Text));
|
||||
|
||||
var tooltip = new Tooltip();
|
||||
tooltip.GetChild(0).Children.Clear();
|
||||
tooltip.GetChild(0).Children.Add(label);
|
||||
|
||||
return tooltip;
|
||||
};
|
||||
ToolTip = verb.Message ?? verb.Text;
|
||||
|
||||
Icon = new TextureRect
|
||||
{
|
||||
|
||||
@@ -298,26 +298,8 @@ namespace Content.Client.Examine
|
||||
{
|
||||
Name = "ExamineButtonsHBox",
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
HorizontalAlignment = Control.HAlignment.Stretch,
|
||||
VerticalAlignment = Control.VAlignment.Bottom,
|
||||
};
|
||||
|
||||
var hoverExamineBox = new BoxContainer
|
||||
{
|
||||
Name = "HoverExamineHBox",
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
HorizontalAlignment = Control.HAlignment.Left,
|
||||
VerticalAlignment = Control.VAlignment.Center,
|
||||
HorizontalExpand = true
|
||||
};
|
||||
|
||||
var clickExamineBox = new BoxContainer
|
||||
{
|
||||
Name = "ClickExamineHBox",
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
HorizontalAlignment = Control.HAlignment.Right,
|
||||
VerticalAlignment = Control.VAlignment.Center,
|
||||
HorizontalExpand = true
|
||||
VerticalAlignment = Control.VAlignment.Bottom,
|
||||
};
|
||||
|
||||
// Examine button time
|
||||
@@ -334,15 +316,8 @@ namespace Content.Client.Examine
|
||||
|
||||
var button = new ExamineButton(examine);
|
||||
|
||||
if (examine.HoverVerb)
|
||||
{
|
||||
hoverExamineBox.AddChild(button);
|
||||
}
|
||||
else
|
||||
{
|
||||
button.OnPressed += VerbButtonPressed;
|
||||
clickExamineBox.AddChild(button);
|
||||
}
|
||||
button.OnPressed += VerbButtonPressed;
|
||||
buttonsHBox.AddChild(button);
|
||||
}
|
||||
|
||||
var vbox = _examineTooltipOpen?.GetChild(0).GetChild(0);
|
||||
@@ -359,8 +334,6 @@ namespace Content.Client.Examine
|
||||
{
|
||||
vbox.Children.Remove(hbox.First());
|
||||
}
|
||||
buttonsHBox.AddChild(hoverExamineBox);
|
||||
buttonsHBox.AddChild(clickExamineBox);
|
||||
vbox.AddChild(buttonsHBox);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,25 +29,24 @@
|
||||
VerticalAlignment="Center"
|
||||
Access="Public"
|
||||
Visible="False" />
|
||||
<!-- CP14 random reactions begin -->
|
||||
<BoxContainer Name="RandomVariations"
|
||||
Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
<controls:SplitBar MinHeight="10">
|
||||
</controls:SplitBar>
|
||||
<Label Name="RandomVariationsLabel"
|
||||
Text="{Loc 'cp14-guidebook-random-variations-title'}"
|
||||
Visible="False"
|
||||
HorizontalAlignment="Center"
|
||||
FontColorOverride="#1e6651" />
|
||||
<controls:SplitBar MinHeight="10">
|
||||
</controls:SplitBar>
|
||||
</BoxContainer>
|
||||
<!-- CP14 random reactions end -->
|
||||
</BoxContainer>
|
||||
<!-- CP14 random reactions begin -->
|
||||
<BoxContainer Name="RandomVariations"
|
||||
Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
<controls:SplitBar MinHeight="10">
|
||||
</controls:SplitBar>
|
||||
<Label Name="RandomVariationsLabel"
|
||||
Text="{Loc 'cp14-guidebook-random-variations-title'}"
|
||||
Visible="False"
|
||||
HorizontalAlignment="Center"
|
||||
FontColorOverride="#1e6651" />
|
||||
<controls:SplitBar MinHeight="10">
|
||||
</controls:SplitBar>
|
||||
</BoxContainer>
|
||||
<!-- CP14 random reactions end -->
|
||||
|
||||
</BoxContainer>
|
||||
<PanelContainer StyleClasses="LowDivider" Margin="0 5 0 5" />
|
||||
</BoxContainer>
|
||||
|
||||
@@ -2,7 +2,6 @@ using Content.Shared.CCVar;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Preferences;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Configuration;
|
||||
@@ -49,7 +48,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
}
|
||||
|
||||
private static bool IsHidden(HumanoidAppearanceComponent humanoid, HumanoidVisualLayers layer)
|
||||
=> humanoid.HiddenLayers.ContainsKey(layer) || humanoid.PermanentlyHidden.Contains(layer);
|
||||
=> humanoid.HiddenLayers.Contains(layer) || humanoid.PermanentlyHidden.Contains(layer);
|
||||
|
||||
private void UpdateLayers(HumanoidAppearanceComponent component, SpriteComponent sprite)
|
||||
{
|
||||
@@ -58,7 +57,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
|
||||
// add default species layers
|
||||
var speciesProto = _prototypeManager.Index(component.Species);
|
||||
var baseSprites = _prototypeManager.Index(speciesProto.SpriteSet);
|
||||
var baseSprites = _prototypeManager.Index<HumanoidSpeciesBaseSpritesPrototype>(speciesProto.SpriteSet);
|
||||
foreach (var (key, id) in baseSprites.Sprites)
|
||||
{
|
||||
oldLayers.Remove(key);
|
||||
@@ -215,7 +214,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
|
||||
humanoid.MarkingSet = markings;
|
||||
humanoid.PermanentlyHidden = new HashSet<HumanoidVisualLayers>();
|
||||
humanoid.HiddenLayers = new Dictionary<HumanoidVisualLayers, SlotFlags>();
|
||||
humanoid.HiddenLayers = new HashSet<HumanoidVisualLayers>();
|
||||
humanoid.CustomBaseLayers = customBaseLayers;
|
||||
humanoid.Sex = profile.Sex;
|
||||
humanoid.Gender = profile.Gender;
|
||||
@@ -403,21 +402,23 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetLayerVisibility(
|
||||
Entity<HumanoidAppearanceComponent> ent,
|
||||
protected override void SetLayerVisibility(
|
||||
EntityUid uid,
|
||||
HumanoidAppearanceComponent humanoid,
|
||||
HumanoidVisualLayers layer,
|
||||
bool visible,
|
||||
SlotFlags? slot,
|
||||
bool permanent,
|
||||
ref bool dirty)
|
||||
{
|
||||
base.SetLayerVisibility(ent, layer, visible, slot, ref dirty);
|
||||
base.SetLayerVisibility(uid, humanoid, layer, visible, permanent, ref dirty);
|
||||
|
||||
var sprite = Comp<SpriteComponent>(ent);
|
||||
var sprite = Comp<SpriteComponent>(uid);
|
||||
if (!sprite.LayerMapTryGet(layer, out var index))
|
||||
{
|
||||
if (!visible)
|
||||
return;
|
||||
index = sprite.LayerMapReserveBlank(layer);
|
||||
else
|
||||
index = sprite.LayerMapReserveBlank(layer);
|
||||
}
|
||||
|
||||
var spriteLayer = sprite[index];
|
||||
@@ -427,14 +428,13 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
spriteLayer.Visible = visible;
|
||||
|
||||
// I fucking hate this. I'll get around to refactoring sprite layers eventually I swear
|
||||
// Just a week away...
|
||||
|
||||
foreach (var markingList in ent.Comp.MarkingSet.Markings.Values)
|
||||
foreach (var markingList in humanoid.MarkingSet.Markings.Values)
|
||||
{
|
||||
foreach (var marking in markingList)
|
||||
{
|
||||
if (_markingManager.TryGetMarking(marking, out var markingPrototype) && markingPrototype.BodyPart == layer)
|
||||
ApplyMarking(markingPrototype, marking.MarkingColors, marking.Visible, ent, sprite);
|
||||
ApplyMarking(markingPrototype, marking.MarkingColors, marking.Visible, humanoid, sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,9 +84,6 @@ namespace Content.Client.Input
|
||||
human.AddFunction(ContentKeyFunctions.Arcade1);
|
||||
human.AddFunction(ContentKeyFunctions.Arcade2);
|
||||
human.AddFunction(ContentKeyFunctions.Arcade3);
|
||||
//CP14 Keys
|
||||
human.AddFunction(ContentKeyFunctions.CP14OpenSkillMenu);
|
||||
//CP14 Keys end
|
||||
|
||||
// actions should be common (for ghosts, mobs, etc)
|
||||
common.AddFunction(ContentKeyFunctions.OpenActionsMenu);
|
||||
@@ -126,6 +123,10 @@ namespace Content.Client.Input
|
||||
common.AddFunction(ContentKeyFunctions.OpenDecalSpawnWindow);
|
||||
common.AddFunction(ContentKeyFunctions.OpenAdminMenu);
|
||||
common.AddFunction(ContentKeyFunctions.OpenGuidebook);
|
||||
|
||||
//CP14 Keys
|
||||
human.AddFunction(ContentKeyFunctions.CP14OpenKnowledgeMenu);
|
||||
//CP14 Keys end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,13 +68,21 @@ public sealed partial class LatheMenu : DefaultWindow
|
||||
{
|
||||
ServerListButton.Visible = false;
|
||||
}
|
||||
|
||||
AmountLineEdit.SetText(latheComponent.DefaultProductionAmount.ToString());
|
||||
}
|
||||
|
||||
MaterialsList.SetOwner(Entity);
|
||||
}
|
||||
|
||||
protected override void Opened()
|
||||
{
|
||||
base.Opened();
|
||||
|
||||
if (_entityManager.TryGetComponent<LatheComponent>(Entity, out var latheComp))
|
||||
{
|
||||
AmountLineEdit.SetText(latheComp.DefaultProductionAmount.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the list of all the recipes
|
||||
/// </summary>
|
||||
|
||||
@@ -4,20 +4,7 @@
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<ScrollContainer VerticalExpand="True" HScrollEnabled="False">
|
||||
<BoxContainer Orientation="Vertical" Margin="8">
|
||||
<Label Text="{Loc 'ui-options-admin-player-panel'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="PlayerlistSeparateSymbolsCheckBox" Text="{Loc 'ui-options-admin-playerlist-separate-symbols'}" />
|
||||
<CheckBox Name="PlayerlistCharacterColorCheckBox" Text="{Loc 'ui-options-admin-playerlist-character-color'}" />
|
||||
<CheckBox Name="PlayerlistRoleTypeColorCheckBox" Text="{Loc 'ui-options-admin-playerlist-roletype-color'}" />
|
||||
<Label Text="{Loc 'ui-options-admin-overlay-title'}"
|
||||
StyleClasses="LabelKeyText"/>
|
||||
<CheckBox Name="EnableClassicOverlayCheckBox" Text="{Loc 'ui-options-enable-classic-overlay'}" />
|
||||
<CheckBox Name="EnableOverlaySymbolsCheckBox" Text="{Loc 'ui-options-enable-overlay-symbols'}" />
|
||||
<CheckBox Name="EnableOverlayPlaytimeCheckBox" Text="{Loc 'ui-options-enable-overlay-playtime'}" />
|
||||
<CheckBox Name="EnableOverlayStartingJobCheckBox" Text="{Loc 'ui-options-enable-overlay-starting-job'}" />
|
||||
<ui:OptionSlider Name="OverlayMergeDistanceSlider" Title="{Loc 'ui-options-overlay-merge-distance'}"/>
|
||||
<ui:OptionSlider Name="OverlayGhostFadeSlider" Title="{Loc 'ui-options-overlay-ghost-fade-distance'}"/>
|
||||
<ui:OptionSlider Name="OverlayGhostHideSlider" Title="{Loc 'ui-options-overlay-ghost-hide-distance'}"/>
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<ui:OptionsTabControlRow Name="Control" Access="Public" />
|
||||
|
||||
@@ -8,45 +8,13 @@ namespace Content.Client.Options.UI.Tabs;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AdminOptionsTab : Control
|
||||
{
|
||||
private const float OverlayMergeMin = 0.05f;
|
||||
private const float OverlayMergeMax = 0.95f;
|
||||
private const int OverlayGhostFadeMin = 0;
|
||||
private const int OverlayGhostFadeMax = 10;
|
||||
private const int OverlayGhostHideMin = 0;
|
||||
private const int OverlayGhostHideMax = 5;
|
||||
|
||||
public AdminOptionsTab()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
Control.AddOptionCheckBox(CCVars.AdminPlayerlistSeparateSymbols, PlayerlistSeparateSymbolsCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminPlayerlistHighlightedCharacterColor, PlayerlistCharacterColorCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminPlayerlistRoleTypeColor, PlayerlistRoleTypeColorCheckBox);
|
||||
|
||||
Control.AddOptionCheckBox(CCVars.AdminOverlayClassic, EnableClassicOverlayCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminOverlaySymbols, EnableOverlaySymbolsCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminOverlayPlaytime, EnableOverlayPlaytimeCheckBox);
|
||||
Control.AddOptionCheckBox(CCVars.AdminOverlayStartingJob, EnableOverlayStartingJobCheckBox);
|
||||
|
||||
Control.Initialize();
|
||||
|
||||
Control.AddOptionPercentSlider(
|
||||
CCVars.AdminOverlayMergeDistance,
|
||||
OverlayMergeDistanceSlider,
|
||||
OverlayMergeMin,
|
||||
OverlayMergeMax);
|
||||
|
||||
Control.AddOptionSlider(
|
||||
CCVars.AdminOverlayGhostFadeDistance,
|
||||
OverlayGhostFadeSlider,
|
||||
OverlayGhostFadeMin,
|
||||
OverlayGhostFadeMax);
|
||||
|
||||
Control.AddOptionSlider(
|
||||
CCVars.AdminOverlayGhostHideDistance,
|
||||
OverlayGhostHideSlider,
|
||||
OverlayGhostHideMin,
|
||||
OverlayGhostHideMax);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@ namespace Content.Client.Options.UI.Tabs
|
||||
|
||||
//CP14
|
||||
AddHeader("ui-options-header-cp14");
|
||||
AddButton(ContentKeyFunctions.CP14OpenSkillMenu);
|
||||
AddButton(ContentKeyFunctions.CP14OpenKnowledgeMenu);
|
||||
//CP14 end
|
||||
|
||||
foreach (var control in _keyControls.Values)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.Parallax;
|
||||
using Content.Client.Weather;
|
||||
using Content.Shared._CP14.CloudShadow;
|
||||
using Content.Shared._CP14.DayCycle.Components;
|
||||
using Content.Shared.Salvage;
|
||||
using Content.Shared.Weather;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -62,7 +62,7 @@ public sealed partial class StencilOverlay : Overlay
|
||||
{
|
||||
foreach (var (proto, weather) in comp.Weather)
|
||||
{
|
||||
if (!_protoManager.TryIndex(proto, out var weatherProto))
|
||||
if (!_protoManager.TryIndex<WeatherPrototype>(proto, out var weatherProto))
|
||||
continue;
|
||||
|
||||
var alpha = _weather.GetPercent(weather, mapUid);
|
||||
|
||||
@@ -11,21 +11,13 @@ public sealed class PaperVisualizerSystem : VisualizerSystem<PaperVisualsCompone
|
||||
if (args.Sprite == null)
|
||||
return;
|
||||
|
||||
if (AppearanceSystem.TryGetData<PaperStatus>(uid, PaperVisuals.Status, out var writingStatus, args.Component))
|
||||
if (AppearanceSystem.TryGetData<PaperStatus>(uid, PaperVisuals.Status , out var writingStatus, args.Component))
|
||||
args.Sprite.LayerSetVisible(PaperVisualLayers.Writing, writingStatus == PaperStatus.Written);
|
||||
|
||||
if (AppearanceSystem.TryGetData<string>(uid, PaperVisuals.Stamp, out var stampState, args.Component))
|
||||
{
|
||||
if (stampState != string.Empty)
|
||||
{
|
||||
args.Sprite.LayerSetState(PaperVisualLayers.Stamp, stampState);
|
||||
args.Sprite.LayerSetVisible(PaperVisualLayers.Stamp, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Sprite.LayerSetVisible(PaperVisualLayers.Stamp, false);
|
||||
}
|
||||
|
||||
args.Sprite.LayerSetState(PaperVisualLayers.Stamp, stampState);
|
||||
args.Sprite.LayerSetVisible(PaperVisualLayers.Stamp, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Content.Client.Parallax.Data;
|
||||
/// <summary>
|
||||
/// Prototype data for a parallax.
|
||||
/// </summary>
|
||||
[Prototype]
|
||||
[Prototype("parallax")]
|
||||
public sealed partial class ParallaxPrototype : IPrototype
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.Parallax.Data;
|
||||
using System.Numerics;
|
||||
using Content.Client.Parallax.Managers;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.ViewVariables;
|
||||
@@ -19,50 +17,27 @@ public sealed class ParallaxControl : Control
|
||||
[Dependency] private readonly IParallaxManager _parallaxManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private string _parallaxPrototype = "FastSpace";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] public Vector2 Offset { get; set; }
|
||||
[ViewVariables(VVAccess.ReadWrite)] public float SpeedX { get; set; } = 0.0f;
|
||||
[ViewVariables(VVAccess.ReadWrite)] public float SpeedY { get; set; } = 0.0f;
|
||||
[ViewVariables(VVAccess.ReadWrite)] public float ScaleX { get; set; } = 1.0f;
|
||||
[ViewVariables(VVAccess.ReadWrite)] public float ScaleY { get; set; } = 1.0f;
|
||||
[ViewVariables(VVAccess.ReadWrite)] public string ParallaxPrototype
|
||||
{
|
||||
get => _parallaxPrototype;
|
||||
set
|
||||
{
|
||||
_parallaxPrototype = value;
|
||||
_parallaxManager.LoadParallaxByName(value);
|
||||
}
|
||||
}
|
||||
|
||||
public ParallaxControl()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
Offset = new Vector2(_random.Next(0, 1000), _random.Next(0, 1000));
|
||||
|
||||
RectClipContent = true;
|
||||
_parallaxManager.LoadParallaxByName(_parallaxPrototype);
|
||||
_parallaxManager.LoadParallaxByName("FastSpace");
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
var currentTime = (float) _timing.RealTime.TotalSeconds;
|
||||
var offset = Offset + new Vector2(currentTime * SpeedX, currentTime * SpeedY);
|
||||
|
||||
foreach (var layer in _parallaxManager.GetParallaxLayers(_parallaxPrototype))
|
||||
foreach (var layer in _parallaxManager.GetParallaxLayers("FastSpace"))
|
||||
{
|
||||
var tex = layer.Texture;
|
||||
var texSize = new Vector2i(
|
||||
(int)(tex.Size.X * Size.X * layer.Config.Scale.X / 1920 * ScaleX),
|
||||
(int)(tex.Size.Y * Size.X * layer.Config.Scale.Y / 1920 * ScaleY)
|
||||
);
|
||||
var texSize = (tex.Size.X * (int) Size.X, tex.Size.Y * (int) Size.X) * layer.Config.Scale.Floored() / 1920;
|
||||
var ourSize = PixelSize;
|
||||
|
||||
//Protection from division by zero.
|
||||
texSize.X = Math.Max(texSize.X, 1);
|
||||
texSize.Y = Math.Max(texSize.Y, 1);
|
||||
var currentTime = (float) _timing.RealTime.TotalSeconds;
|
||||
var offset = Offset + new Vector2(currentTime * 100f, currentTime * 0f);
|
||||
|
||||
if (layer.Config.Tiled)
|
||||
{
|
||||
|
||||
@@ -237,12 +237,6 @@ namespace Content.Client.Popups
|
||||
PopupEntity(message, uid, recipient.Value, type);
|
||||
}
|
||||
|
||||
public override void PopupPredicted(string? message, EntityUid uid, EntityUid? recipient, Filter filter, bool recordReplay, PopupType type = PopupType.Small)
|
||||
{
|
||||
if (recipient != null && _timing.IsFirstTimePredicted)
|
||||
PopupEntity(message, uid, recipient.Value, type);
|
||||
}
|
||||
|
||||
public override void PopupPredicted(string? recipientMessage, string? othersMessage, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small)
|
||||
{
|
||||
if (recipient != null && _timing.IsFirstTimePredicted)
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
using Content.Client.UserInterface.Systems.Sandbox;
|
||||
using Content.Shared.DrawDepth;
|
||||
using Content.Shared.SubFloor;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client.SubFloor;
|
||||
|
||||
public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
|
||||
{
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
||||
|
||||
private bool _showAll;
|
||||
|
||||
@@ -21,13 +18,8 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
|
||||
{
|
||||
if (_showAll == value) return;
|
||||
_showAll = value;
|
||||
_ui.GetUIController<SandboxUIController>().SetToggleSubfloors(value);
|
||||
|
||||
var ev = new ShowSubfloorRequestEvent()
|
||||
{
|
||||
Value = value,
|
||||
};
|
||||
RaiseNetworkEvent(ev);
|
||||
UpdateAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,20 +28,6 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SubFloorHideComponent, AppearanceChangeEvent>(OnAppearanceChanged);
|
||||
SubscribeNetworkEvent<ShowSubfloorRequestEvent>(OnRequestReceived);
|
||||
SubscribeLocalEvent<LocalPlayerDetachedEvent>(OnPlayerDetached);
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(LocalPlayerDetachedEvent ev)
|
||||
{
|
||||
// Vismask resets so need to reset this.
|
||||
ShowAll = false;
|
||||
}
|
||||
|
||||
private void OnRequestReceived(ShowSubfloorRequestEvent ev)
|
||||
{
|
||||
// When client receives request Queue an update on all vis.
|
||||
UpdateAll();
|
||||
}
|
||||
|
||||
private void OnAppearanceChanged(EntityUid uid, SubFloorHideComponent component, ref AppearanceChangeEvent args)
|
||||
|
||||
@@ -14,7 +14,6 @@ public sealed partial class GhostGui : UIWidget
|
||||
public event Action? RequestWarpsPressed;
|
||||
public event Action? ReturnToBodyPressed;
|
||||
public event Action? GhostRolesPressed;
|
||||
private int _prevNumberRoles;
|
||||
|
||||
public GhostGui()
|
||||
{
|
||||
@@ -27,7 +26,6 @@ public sealed partial class GhostGui : UIWidget
|
||||
GhostWarpButton.OnPressed += _ => RequestWarpsPressed?.Invoke();
|
||||
ReturnToBodyButton.OnPressed += _ => ReturnToBodyPressed?.Invoke();
|
||||
GhostRolesButton.OnPressed += _ => GhostRolesPressed?.Invoke();
|
||||
GhostRolesButton.OnPressed += _ => GhostRolesButton.StyleClasses.Remove(StyleBase.ButtonCaution);
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
@@ -43,13 +41,14 @@ public sealed partial class GhostGui : UIWidget
|
||||
if (roles != null)
|
||||
{
|
||||
GhostRolesButton.Text = Loc.GetString("ghost-gui-ghost-roles-button", ("count", roles));
|
||||
|
||||
if (roles > _prevNumberRoles)
|
||||
if (roles > 0)
|
||||
{
|
||||
GhostRolesButton.StyleClasses.Add(StyleBase.ButtonCaution);
|
||||
}
|
||||
|
||||
_prevNumberRoles = (int)roles;
|
||||
else
|
||||
{
|
||||
GhostRolesButton.StyleClasses.Remove(StyleBase.ButtonCaution);
|
||||
}
|
||||
}
|
||||
|
||||
TargetWindow.Populate();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Client._CP14.UserInterface.Systems.Skill;
|
||||
using Content.Client.UserInterface.Systems.Actions;
|
||||
using Content.Client.UserInterface.Systems.Admin;
|
||||
using Content.Client.UserInterface.Systems.Bwoink;
|
||||
@@ -25,7 +24,7 @@ public sealed class GameTopMenuBarUIController : UIController
|
||||
[Dependency] private readonly SandboxUIController _sandbox = default!;
|
||||
[Dependency] private readonly GuidebookUIController _guidebook = default!;
|
||||
[Dependency] private readonly EmotesUIController _emotes = default!;
|
||||
[Dependency] private readonly CP14SkillUIController _skill = default!; //CP14
|
||||
[Dependency] private readonly CP14KnowledgeUIController _knowledge = default!; //CP14
|
||||
|
||||
private GameTopMenuBar? GameTopMenuBar => UIManager.GetActiveUIWidgetOrNull<GameTopMenuBar>();
|
||||
|
||||
@@ -49,7 +48,7 @@ public sealed class GameTopMenuBarUIController : UIController
|
||||
_action.UnloadButton();
|
||||
_sandbox.UnloadButton();
|
||||
_emotes.UnloadButton();
|
||||
_skill.UnloadButton(); //CP14
|
||||
_knowledge.UnloadButton(); //CP14
|
||||
}
|
||||
|
||||
public void LoadButtons()
|
||||
@@ -63,6 +62,6 @@ public sealed class GameTopMenuBarUIController : UIController
|
||||
_action.LoadButton();
|
||||
_sandbox.LoadButton();
|
||||
_emotes.LoadButton();
|
||||
_skill.LoadButton(); //CP14
|
||||
_knowledge.LoadButton(); //CP14
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@
|
||||
/>
|
||||
<!-- CP14 UI part -->
|
||||
<ui:MenuButton
|
||||
Name="CP14SkillButton"
|
||||
Name="CP14KnowledgeButton"
|
||||
Access="Internal"
|
||||
Icon="{xe:Tex '/Textures/Interface/students-cap.svg.192dpi.png'}"
|
||||
ToolTip="{Loc 'cp14-game-hud-open-skill-menu-button-tooltip'}"
|
||||
BoundKey = "{x:Static is:ContentKeyFunctions.CP14OpenSkillMenu}"
|
||||
ToolTip="{Loc 'cp14-game-hud-open-knowledge-menu-button-tooltip'}"
|
||||
BoundKey = "{x:Static is:ContentKeyFunctions.CP14OpenKnowledgeMenu}"
|
||||
MinSize="42 64"
|
||||
HorizontalExpand="True"
|
||||
AppendStyleClass="{x:Static style:StyleBase.ButtonSquare}"
|
||||
|
||||
@@ -39,6 +39,7 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
|
||||
[UISystemDependency] private readonly DebugPhysicsSystem _debugPhysics = default!;
|
||||
[UISystemDependency] private readonly MarkerSystem _marker = default!;
|
||||
[UISystemDependency] private readonly SandboxSystem _sandbox = default!;
|
||||
[UISystemDependency] private readonly SubFloorHideSystem _subfloorHide = default!;
|
||||
|
||||
private SandboxWindow? _window;
|
||||
|
||||
@@ -116,11 +117,10 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
|
||||
|
||||
_window.OnOpen += () => { SandboxButton!.Pressed = true; };
|
||||
_window.OnClose += () => { SandboxButton!.Pressed = false; };
|
||||
|
||||
// TODO: These need moving to opened so at least if they're not synced properly on open they work.
|
||||
_window.ToggleLightButton.Pressed = !_light.Enabled;
|
||||
_window.ToggleFovButton.Pressed = !_eye.CurrentEye.DrawFov;
|
||||
_window.ToggleShadowsButton.Pressed = !_light.DrawShadows;
|
||||
_window.ToggleSubfloorButton.Pressed = _subfloorHide.ShowAll;
|
||||
_window.ShowMarkersButton.Pressed = _marker.MarkersVisible;
|
||||
_window.ShowBbButton.Pressed = (_debugPhysics.Flags & PhysicsDebugFlags.Shapes) != 0x0;
|
||||
|
||||
@@ -219,16 +219,4 @@ public sealed class SandboxUIController : UIController, IOnStateChanged<Gameplay
|
||||
_window.Close();
|
||||
}
|
||||
}
|
||||
|
||||
#region Buttons
|
||||
|
||||
public void SetToggleSubfloors(bool value)
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
_window.ToggleSubfloorButton.Pressed = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Content.Client.SubFloor;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
@@ -8,18 +7,8 @@ namespace Content.Client.UserInterface.Systems.Sandbox.Windows;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class SandboxWindow : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = null!;
|
||||
|
||||
public SandboxWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
protected override void Opened()
|
||||
{
|
||||
base.Opened();
|
||||
// Make sure state is up to date.
|
||||
ToggleSubfloorButton.Pressed = _entManager.System<SubFloorHideSystem>().ShowAll;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,9 +42,6 @@ public sealed class StorageWindow : BaseWindow
|
||||
private ValueList<EntityUid> _contained = new();
|
||||
private ValueList<EntityUid> _toRemove = new();
|
||||
|
||||
// Manually store this because you can't have a 0x0 GridContainer but we still need to add child controls for 1x1 containers.
|
||||
private Vector2i _pieceGridSize;
|
||||
|
||||
private TextureButton? _backButton;
|
||||
|
||||
private bool _isDirty;
|
||||
@@ -411,14 +408,11 @@ public sealed class StorageWindow : BaseWindow
|
||||
_contained.Clear();
|
||||
_contained.AddRange(storageComp.Container.ContainedEntities.Reverse());
|
||||
|
||||
var width = boundingGrid.Width + 1;
|
||||
var height = boundingGrid.Height + 1;
|
||||
|
||||
// Build the grid representation
|
||||
if (_pieceGrid.Rows != _pieceGridSize.Y || _pieceGrid.Columns != _pieceGridSize.X)
|
||||
if (_pieceGrid.Rows - 1 != boundingGrid.Height || _pieceGrid.Columns - 1 != boundingGrid.Width)
|
||||
{
|
||||
_pieceGrid.Rows = height;
|
||||
_pieceGrid.Columns = width;
|
||||
_pieceGrid.Rows = boundingGrid.Height + 1;
|
||||
_pieceGrid.Columns = boundingGrid.Width + 1;
|
||||
_controlGrid.Clear();
|
||||
|
||||
for (var y = boundingGrid.Bottom; y <= boundingGrid.Top; y++)
|
||||
@@ -436,7 +430,6 @@ public sealed class StorageWindow : BaseWindow
|
||||
}
|
||||
}
|
||||
|
||||
_pieceGridSize = new(width, height);
|
||||
_toRemove.Clear();
|
||||
|
||||
// Remove entities no longer relevant / Update existing ones
|
||||
|
||||
@@ -3,12 +3,10 @@ using Content.Client.ContextMenu.UI;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Verbs.UI
|
||||
{
|
||||
@@ -29,17 +27,7 @@ namespace Content.Client.Verbs.UI
|
||||
|
||||
public VerbMenuElement(Verb verb) : base(verb.Text)
|
||||
{
|
||||
TooltipSupplier = sender =>
|
||||
{
|
||||
var label = new RichTextLabel();
|
||||
label.SetMessage(FormattedMessage.FromMarkupOrThrow(verb.Message ?? verb.Text));
|
||||
|
||||
var tooltip = new Tooltip();
|
||||
tooltip.GetChild(0).Children.Clear();
|
||||
tooltip.GetChild(0).Children.Add(label);
|
||||
|
||||
return tooltip;
|
||||
};
|
||||
ToolTip = verb.Message;
|
||||
Disabled = verb.Disabled;
|
||||
Verb = verb;
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ namespace Content.Client.Verbs
|
||||
{
|
||||
// maybe send an informative pop-up message.
|
||||
if (!string.IsNullOrWhiteSpace(verb.Message))
|
||||
_popupSystem.PopupEntity(FormattedMessage.RemoveMarkupOrThrow(verb.Message), user);
|
||||
_popupSystem.PopupEntity(verb.Message, user);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Content.Shared._CP14.Farming;
|
||||
using Content.Shared._CP14.Farming.Components;
|
||||
using Content.Shared.Rounding;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
@@ -33,7 +32,7 @@ public sealed class ClientCP14FarmingSystem : CP14SharedFarmingSystem
|
||||
if (!TryComp<SpriteComponent>(visuals, out var sprite))
|
||||
return;
|
||||
|
||||
if (!PlantQuery.TryComp(visuals, out var plant))
|
||||
if (!TryComp<CP14PlantComponent>(visuals, out var plant))
|
||||
return;
|
||||
|
||||
var growthState = ContentHelpers.RoundToNearestLevels(plant.GrowthLevel, 1, visuals.Comp.GrowthSteps);
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.Resources;
|
||||
using Content.Shared._CP14.Fishing.Components;
|
||||
using Content.Shared._CP14.Fishing.Prototypes;
|
||||
using Content.Shared._CP14.Fishing.Systems;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Fishing;
|
||||
|
||||
public sealed class CP14FishingOverlay : Overlay
|
||||
{
|
||||
[Dependency] private readonly IComponentFactory _factory = default!;
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
|
||||
private readonly SpriteSystem _sprite;
|
||||
private readonly TransformSystem _transform;
|
||||
private readonly CP14SharedFishingProcessSystem _sharedFishingProcess;
|
||||
|
||||
private Texture _backgroundTexture = default!;
|
||||
private Texture _handleTopTexture = default!;
|
||||
private Texture _handleMiddleTexture = default!;
|
||||
private Texture _handleBottomTexture = default!;
|
||||
|
||||
private Texture _lootTexture = default!;
|
||||
|
||||
private Vector2 _backgroundOffset;
|
||||
private Vector2 _backgroundHandleOffset;
|
||||
private Vector2 _backgroundHandleSize;
|
||||
|
||||
private Vector2 _progressOffset;
|
||||
private Vector2 _progressSize;
|
||||
|
||||
private EntityUid _process = EntityUid.Invalid;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
public CP14FishingOverlay()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
_transform = _entity.System<TransformSystem>();
|
||||
_sharedFishingProcess = _entity.System<CP14SharedFishingProcessSystem>();
|
||||
}
|
||||
|
||||
protected override void Draw(in OverlayDrawArgs args)
|
||||
{
|
||||
if (_player.LocalEntity is not { } localEntity)
|
||||
return;
|
||||
|
||||
if (!_sharedFishingProcess.TryGetByUser(localEntity, out var fishingProcess))
|
||||
return;
|
||||
|
||||
// Refresh the texture cache, with a new fishing process
|
||||
if (_process != fishingProcess.Value.Owner)
|
||||
{
|
||||
_process = fishingProcess.Value.Owner;
|
||||
|
||||
UpdateCachedStyleSheet(_sharedFishingProcess.GetStyle(fishingProcess.Value));
|
||||
|
||||
var prototype = _prototype.Index(fishingProcess.Value.Comp.LootProtoId);
|
||||
var iconPath = CP14FishingIconComponent.DefaultTexturePath;
|
||||
|
||||
if (prototype.Components.TryGetComponent(_factory.GetComponentName(typeof(CP14FishingIconComponent)), out var iconComponent))
|
||||
{
|
||||
var comp = (CP14FishingIconComponent) iconComponent;
|
||||
iconPath = comp.TexturePath;
|
||||
}
|
||||
|
||||
_lootTexture = _resourceCache.GetTexture(iconPath);
|
||||
}
|
||||
|
||||
// Getting the position of the player we will be working from
|
||||
var worldPosition = _transform.GetWorldPosition(localEntity);
|
||||
|
||||
// Calculate the shift of the player relative to the bottom of the coordinates
|
||||
var playerOffset = fishingProcess.Value.Comp.PlayerPositionNormalized * _backgroundHandleSize;
|
||||
var playerHalfSize = fishingProcess.Value.Comp.PlayerHalfSizeNormalized * _backgroundHandleSize;
|
||||
|
||||
var lootOffset = fishingProcess.Value.Comp.LootPositionNormalized * _backgroundHandleSize + Vector2.UnitX * _backgroundHandleSize.X / 2;
|
||||
|
||||
DrawBackground(args.WorldHandle, worldPosition - _backgroundOffset);
|
||||
DrawProgress(args.WorldHandle, worldPosition - _backgroundOffset + _progressOffset, _progressSize, fishingProcess.Value.Comp.Progress);
|
||||
DrawHandle(args.WorldHandle, worldPosition - _backgroundOffset + _backgroundHandleOffset + playerOffset, playerHalfSize);
|
||||
DrawLoot(args.WorldHandle, worldPosition - _backgroundOffset + _backgroundHandleOffset + lootOffset);
|
||||
}
|
||||
|
||||
private void DrawBackground(DrawingHandleWorld handle, Vector2 position)
|
||||
{
|
||||
handle.DrawTexture(_backgroundTexture, position);
|
||||
}
|
||||
|
||||
private void DrawProgress(DrawingHandleWorld handle, Vector2 position, Vector2 size, float progress)
|
||||
{
|
||||
var vectorA = position;
|
||||
var vectorB = position + new Vector2(size.X, size.Y * progress);
|
||||
var box = new Box2(vectorA, vectorB);
|
||||
|
||||
handle.DrawRect(box, Color.Aqua);
|
||||
}
|
||||
|
||||
private void DrawHandle(DrawingHandleWorld handle, Vector2 position, Vector2 halfSize)
|
||||
{
|
||||
var cursor = position - halfSize;
|
||||
|
||||
// Bottom
|
||||
handle.DrawTexture(_handleBottomTexture, cursor);
|
||||
cursor += new Vector2(0, _handleBottomTexture.Height / 32f);
|
||||
|
||||
// Middle
|
||||
while (cursor.Y < position.Y + halfSize.Y - _handleTopTexture.Height / 32f)
|
||||
{
|
||||
handle.DrawTexture(_handleMiddleTexture, cursor);
|
||||
cursor += new Vector2(0, _handleMiddleTexture.Height / 32f);
|
||||
}
|
||||
|
||||
// Front
|
||||
handle.DrawTexture(_handleTopTexture, cursor);
|
||||
}
|
||||
|
||||
private void DrawLoot(DrawingHandleWorld handle, Vector2 position)
|
||||
{
|
||||
handle.DrawTexture(_lootTexture, position - _lootTexture.Size / 64f);
|
||||
}
|
||||
|
||||
private void UpdateCachedStyleSheet(CP14FishingProcessStyleSheetPrototype styleSheet)
|
||||
{
|
||||
_backgroundTexture = _resourceCache.GetTexture(styleSheet.Background.Texture);
|
||||
_handleTopTexture = _resourceCache.GetTexture(styleSheet.Handle.TopTexture);
|
||||
_handleMiddleTexture = _resourceCache.GetTexture(styleSheet.Handle.MiddleTexture);
|
||||
_handleBottomTexture = _resourceCache.GetTexture(styleSheet.Handle.BottomTexture);
|
||||
|
||||
_backgroundOffset = styleSheet.Background.Offset + Vector2.UnitX * _backgroundTexture.Width / 32f;
|
||||
|
||||
_backgroundHandleOffset = styleSheet.Background.HandleOffset;
|
||||
_backgroundHandleSize = styleSheet.Background.HandleSize;
|
||||
|
||||
_progressOffset = styleSheet.Background.ProgressOffset;
|
||||
_progressSize = styleSheet.Background.ProgressSize;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using Content.Client.Overlays;
|
||||
using Robust.Client.Graphics;
|
||||
|
||||
namespace Content.Client._CP14.Fishing;
|
||||
|
||||
public sealed class CP14FishingOverlaySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IOverlayManager _overlay = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_overlay.AddOverlay(new CP14FishingOverlay());
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
_overlay.RemoveOverlay<StencilOverlay>();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
using Content.Shared._CP14.Fishing.Systems;
|
||||
|
||||
namespace Content.Client._CP14.Fishing;
|
||||
|
||||
public sealed class CP14FishingProcessSystem : CP14SharedFishingProcessSystem;
|
||||
@@ -1,35 +0,0 @@
|
||||
using Content.Client.Hands.Systems;
|
||||
using Content.Shared._CP14.Fishing.Components;
|
||||
using Content.Shared._CP14.Fishing.Systems;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client._CP14.Fishing;
|
||||
|
||||
public sealed class CP14FishingRodSystem : CP14SharedFishingRodSystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly InputSystem _input = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
var handUid = _hands.GetActiveHandEntity();
|
||||
|
||||
if (!TryComp<CP14FishingRodComponent>(handUid, out var fishingRodComponent))
|
||||
return;
|
||||
|
||||
var reelKey = _input.CmdStates.GetState(EngineKeyFunctions.UseSecondary) == BoundKeyState.Down;
|
||||
|
||||
if (fishingRodComponent.Reeling == reelKey)
|
||||
return;
|
||||
|
||||
RaisePredictiveEvent(new RequestFishingRodReelMessage(reelKey));
|
||||
}
|
||||
}
|
||||
43
Content.Client/_CP14/Knowledge/ClientCP14KnowledgeSystem.cs
Normal file
43
Content.Client/_CP14/Knowledge/ClientCP14KnowledgeSystem.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Content.Shared._CP14.Knowledge;
|
||||
using Content.Shared._CP14.Knowledge.Events;
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Knowledge;
|
||||
|
||||
public sealed class ClientCP14KnowledgeSystem : SharedCP14KnowledgeSystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _players = default!;
|
||||
|
||||
public event Action<KnowledgeData>? OnKnowledgeUpdate;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<CP14KnowledgeInfoEvent>(OnCharacterKnowledgeEvent);
|
||||
}
|
||||
|
||||
public void RequestKnowledgeInfo()
|
||||
{
|
||||
var entity = _players.LocalEntity;
|
||||
if (entity is null)
|
||||
return;
|
||||
|
||||
RaiseNetworkEvent(new CP14RequestKnowledgeInfoEvent(GetNetEntity(entity.Value)));
|
||||
}
|
||||
|
||||
private void OnCharacterKnowledgeEvent(CP14KnowledgeInfoEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
var entity = GetEntity(msg.NetEntity);
|
||||
var data = new KnowledgeData(entity, msg.AllKnowledge);
|
||||
|
||||
OnKnowledgeUpdate?.Invoke(data);
|
||||
}
|
||||
|
||||
public readonly record struct KnowledgeData(
|
||||
EntityUid Entity,
|
||||
HashSet<ProtoId<CP14KnowledgePrototype>> AllKnowledge
|
||||
);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
using Content.Shared._CP14.NightVision;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Client._CP14.NightVision;
|
||||
|
||||
public sealed class CP14ClientNightVisionSystem : CP14SharedNightVisionSystem
|
||||
{
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14NightVisionComponent, CP14ToggleNightVisionEvent>(OnToggleNightVision);
|
||||
SubscribeLocalEvent<CP14NightVisionComponent, PlayerDetachedEvent>(OnPlayerDetached);
|
||||
}
|
||||
|
||||
protected override void OnRemove(Entity<CP14NightVisionComponent> ent, ref ComponentRemove args)
|
||||
{
|
||||
base.OnRemove(ent, ref args);
|
||||
|
||||
NightVisionOff(ent);
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(Entity<CP14NightVisionComponent> ent, ref PlayerDetachedEvent args)
|
||||
{
|
||||
NightVisionOff(ent);
|
||||
}
|
||||
|
||||
private void OnToggleNightVision(Entity<CP14NightVisionComponent> ent, ref CP14ToggleNightVisionEvent args)
|
||||
{
|
||||
NightVisionToggle(ent);
|
||||
}
|
||||
|
||||
private void NightVisionOn(Entity<CP14NightVisionComponent> ent)
|
||||
{
|
||||
if (_playerManager.LocalSession?.AttachedEntity != ent)
|
||||
return;
|
||||
|
||||
var nightVisionLight = Spawn(ent.Comp.LightPrototype, Transform(ent).Coordinates);
|
||||
_transform.SetParent(nightVisionLight, ent);
|
||||
_transform.SetWorldRotation(nightVisionLight, _transform.GetWorldRotation(ent));
|
||||
ent.Comp.LocalLightEntity = nightVisionLight;
|
||||
}
|
||||
|
||||
private void NightVisionOff(Entity<CP14NightVisionComponent> ent)
|
||||
{
|
||||
QueueDel(ent.Comp.LocalLightEntity);
|
||||
ent.Comp.LocalLightEntity = null;
|
||||
}
|
||||
|
||||
private void NightVisionToggle(Entity<CP14NightVisionComponent> ent)
|
||||
{
|
||||
if (ent.Comp.LocalLightEntity == null)
|
||||
{
|
||||
NightVisionOn(ent);
|
||||
}
|
||||
else
|
||||
{
|
||||
NightVisionOff(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared._CP14.CloudShadow;
|
||||
using Content.Shared._CP14.DayCycle.Components;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Skill;
|
||||
|
||||
public sealed partial class CP14ClientSkillSystem : CP14SharedSkillSystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public event Action<EntityUid>? OnSkillUpdate;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14SkillStorageComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
|
||||
}
|
||||
|
||||
private void OnAfterAutoHandleState(Entity<CP14SkillStorageComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
if (ent != _playerManager.LocalEntity)
|
||||
return;
|
||||
|
||||
OnSkillUpdate?.Invoke(ent.Owner);
|
||||
}
|
||||
|
||||
public void RequestSkillData()
|
||||
{
|
||||
var localPlayer = _playerManager.LocalEntity;
|
||||
|
||||
if (!HasComp<CP14SkillStorageComponent>(localPlayer))
|
||||
return;
|
||||
|
||||
OnSkillUpdate?.Invoke(localPlayer.Value);
|
||||
}
|
||||
|
||||
public void RequestLearnSkill(EntityUid? target, CP14SkillPrototype? skill)
|
||||
{
|
||||
if (skill == null || target == null)
|
||||
return;
|
||||
|
||||
var netEv = new CP14TryLearnSkillMessage(GetNetEntity(target.Value), skill.ID);
|
||||
RaiseNetworkEvent(netEv);
|
||||
|
||||
if (_proto.TryIndex(skill.Tree, out var indexedTree))
|
||||
{
|
||||
_audio.PlayGlobal(indexedTree.LearnSound, target.Value, AudioParams.Default.WithVolume(6f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<Control xmlns="https://spacestation14.io" HorizontalExpand="True">
|
||||
<BoxContainer Name="MainContainer"
|
||||
Orientation="Horizontal"
|
||||
HorizontalExpand="True">
|
||||
<Button Name="MainButton"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True"
|
||||
StyleClasses="OpenRight"
|
||||
Margin="0 0 -1 0">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
Margin="-5 0 0 0">
|
||||
<Label Name="SkillTreeLabel" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</Button>
|
||||
<PanelContainer Name="ColorPanel"
|
||||
VerticalExpand="True"
|
||||
SetWidth="7"
|
||||
Margin="0 1 0 0" />
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
@@ -1,22 +0,0 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._CP14.Skill.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14SkillTreeButtonControl : Control
|
||||
{
|
||||
public event Action? OnPressed;
|
||||
|
||||
public CP14SkillTreeButtonControl(Color color, string label)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = color };
|
||||
SkillTreeLabel.Text = label;
|
||||
|
||||
MainButton.OnPressed += args => OnPressed?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<ui:CP14SkillTreeGraphControl
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client._CP14.Skill.Ui"
|
||||
xmlns:ui="clr-namespace:Content.Client._CP14.Skill.Ui"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True"
|
||||
MouseFilter="Stop"/>
|
||||
@@ -1,227 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared._CP14.Skill.Restrictions;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Skill.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14SkillTreeGraphControl : BoxContainer
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
private readonly CP14SharedSkillSystem _skillSystem;
|
||||
|
||||
private Entity<CP14SkillStorageComponent>? _player;
|
||||
|
||||
private IEnumerable<CP14SkillPrototype> _allSkills;
|
||||
|
||||
private CP14SkillPrototype? _hoveredNode;
|
||||
private CP14SkillPrototype? _selectedNode;
|
||||
public CP14SkillTreePrototype? Tree;
|
||||
|
||||
private bool dragging = false;
|
||||
private Vector2 _previousMousePosition = Vector2.Zero;
|
||||
private Vector2 _globalOffset = new (60,60);
|
||||
|
||||
private const float GridSize = 25f;
|
||||
|
||||
public event Action<CP14SkillPrototype?>? OnNodeSelected;
|
||||
public event Action<Vector2>? OnOffsetChanged;
|
||||
|
||||
public CP14SkillTreeGraphControl()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
_skillSystem = _entManager.System<CP14SharedSkillSystem>();
|
||||
|
||||
_allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>();
|
||||
_proto.PrototypesReloaded += _ => _allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>().OrderBy(skill => _skillSystem.GetSkillName(skill)).ToList();
|
||||
OnOffsetChanged?.Invoke(_globalOffset);
|
||||
}
|
||||
|
||||
public void UpdateState(Entity<CP14SkillStorageComponent>? player)
|
||||
{
|
||||
_player = player;
|
||||
OnOffsetChanged?.Invoke(_globalOffset);
|
||||
}
|
||||
|
||||
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.KeyBindDown(args);
|
||||
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (args.Function == EngineKeyFunctions.UIClick)
|
||||
{
|
||||
dragging = true;
|
||||
|
||||
if (_hoveredNode == null)
|
||||
return;
|
||||
|
||||
OnNodeSelected?.Invoke(_hoveredNode);
|
||||
UserInterfaceManager.ClickSound();
|
||||
_selectedNode = _hoveredNode;
|
||||
}
|
||||
|
||||
if (args.Function == EngineKeyFunctions.UIRightClick)
|
||||
{
|
||||
_globalOffset = new Vector2(60, 60); // Reset offset on right click
|
||||
OnOffsetChanged?.Invoke(_globalOffset);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.KeyBindUp(args);
|
||||
|
||||
if (args.Handled || args.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
protected override void ExitedTree()
|
||||
{
|
||||
base.ExitedTree();
|
||||
|
||||
OnNodeSelected?.Invoke(null);
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
_hoveredNode = null;
|
||||
if (_player == null || Tree == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var cursor = (UserInterfaceManager.MousePositionScaled.Position * UIScale) - GlobalPixelPosition;
|
||||
|
||||
if (dragging)
|
||||
{
|
||||
var delta = cursor - _previousMousePosition;
|
||||
_globalOffset += delta;
|
||||
OnOffsetChanged?.Invoke(_globalOffset);
|
||||
}
|
||||
|
||||
_previousMousePosition = cursor;
|
||||
|
||||
var playerSkills = _player.Value.Comp.LearnedSkills;
|
||||
|
||||
//Draw connection lines
|
||||
foreach (var skill in _allSkills)
|
||||
{
|
||||
if (skill.Tree != Tree)
|
||||
continue;
|
||||
|
||||
var fromPos = skill.SkillUiPosition * GridSize * UIScale + _globalOffset;
|
||||
|
||||
foreach (var req in skill.Restrictions)
|
||||
{
|
||||
switch (req)
|
||||
{
|
||||
case NeedPrerequisite prerequisite:
|
||||
if (!_proto.TryIndex(prerequisite.Prerequisite, out var prerequisiteSkill))
|
||||
continue;
|
||||
|
||||
if (prerequisiteSkill.Tree != Tree)
|
||||
continue;
|
||||
|
||||
var learned = playerSkills.Contains(skill.ID);
|
||||
|
||||
var toPos = prerequisiteSkill.SkillUiPosition * GridSize * UIScale + _globalOffset;
|
||||
var color = learned ? Color.White : Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f));
|
||||
handle.DrawLine(fromPos, toPos, color);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Draw skill icons over lines
|
||||
foreach (var skill in _allSkills)
|
||||
{
|
||||
if (skill.Tree != Tree)
|
||||
continue;
|
||||
|
||||
//TODO: Not optimized, recalculates every frame. Needs to be calculated on state update and cached.
|
||||
var canBeLearned = _skillSystem.CanLearnSkill(_player.Value, skill, _player.Value.Comp);
|
||||
var pos = skill.SkillUiPosition * GridSize * UIScale + _globalOffset;
|
||||
|
||||
// Base skill icon
|
||||
var baseTexture = skill.Icon.Frame0();
|
||||
var baseSize = new Vector2(baseTexture.Width, baseTexture.Height) * 2;
|
||||
var baseQuad = new UIBox2(pos - baseSize / 2, pos + baseSize / 2);
|
||||
|
||||
var hovered = (cursor - pos).LengthSquared() <= (baseSize.X / 2) * (baseSize.X / 2);
|
||||
|
||||
// Frame
|
||||
var frameTexture = Tree.FrameIcon.Frame0();
|
||||
var frameSize = new Vector2(frameTexture.Width, frameTexture.Height) * 2;
|
||||
var frameQuad = new UIBox2(pos - frameSize / 2, pos + frameSize / 2);
|
||||
handle.DrawTextureRect(frameTexture, frameQuad, canBeLearned ? Color.White : Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f)));
|
||||
|
||||
// Selected Skill
|
||||
if (_selectedNode == skill)
|
||||
{
|
||||
var selectedTexture = Tree.SelectedIcon.Frame0();
|
||||
var selectedSize = new Vector2(selectedTexture.Width, selectedTexture.Height) * 2;
|
||||
var selectedQuad = new UIBox2(pos - selectedSize / 2, pos + selectedSize / 2);
|
||||
handle.DrawTextureRect(selectedTexture, selectedQuad, Color.White);
|
||||
}
|
||||
|
||||
// Hovered Skill
|
||||
if (hovered)
|
||||
{
|
||||
_hoveredNode = skill;
|
||||
var hoveredTexture = Tree.HoveredIcon.Frame0();
|
||||
var hoveredSize = new Vector2(hoveredTexture.Width, hoveredTexture.Height) * 2;
|
||||
var hoveredQuad = new UIBox2(pos - hoveredSize / 2, pos + hoveredSize / 2);
|
||||
handle.DrawTextureRect(hoveredTexture, hoveredQuad, Color.White);
|
||||
}
|
||||
|
||||
var learned = playerSkills.Contains(skill.ID);
|
||||
var allowedToLearn = _skillSystem.AllowedToLearn(_player.Value, skill, _player.Value.Comp);
|
||||
|
||||
// Learned Skill
|
||||
if (learned)
|
||||
{
|
||||
var learnedTexture = Tree.LearnedIcon.Frame0();
|
||||
var learnedSize = new Vector2(learnedTexture.Width, learnedTexture.Height) * 2;
|
||||
var learnedQuad = new UIBox2(pos - learnedSize / 2, pos + learnedSize / 2);
|
||||
handle.DrawTextureRect(learnedTexture, learnedQuad, Color.White);
|
||||
}
|
||||
else if (canBeLearned)
|
||||
{
|
||||
var availableTexture = Tree.AvailableIcon.Frame0();
|
||||
var availableSize = new Vector2(availableTexture.Width, availableTexture.Height) * 2;
|
||||
var availableQuad = new UIBox2(pos - availableSize / 2, pos + availableSize / 2);
|
||||
handle.DrawTextureRect(availableTexture, availableQuad, Color.White);
|
||||
}
|
||||
|
||||
var iconColor = allowedToLearn switch
|
||||
{
|
||||
true when !learned => Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f)),
|
||||
false when !learned => Color.FromSrgb(new Color(0f, 0f, 0f)),
|
||||
_ => Color.White
|
||||
};
|
||||
|
||||
handle.DrawTextureRect(baseTexture, baseQuad, iconColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
using Content.Client._CP14.Knowledge;
|
||||
using Content.Client._CP14.UserInterface.Systems.Knowledge.Windows;
|
||||
using Content.Client.Gameplay;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Input;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Character;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class CP14KnowledgeUIController : UIController, IOnStateEntered<GameplayState>, IOnStateExited<GameplayState>,
|
||||
IOnSystemChanged<ClientCP14KnowledgeSystem>
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[UISystemDependency] private readonly ClientCP14KnowledgeSystem _knowledge = default!;
|
||||
|
||||
private CP14KnowledgeWindow? _window;
|
||||
|
||||
private MenuButton? KnowledgeButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.CP14KnowledgeButton;
|
||||
|
||||
public void OnStateEntered(GameplayState state)
|
||||
{
|
||||
DebugTools.Assert(_window == null);
|
||||
|
||||
_window = UIManager.CreateWindow<CP14KnowledgeWindow>();
|
||||
LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.CenterTop);
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.CP14OpenKnowledgeMenu,
|
||||
InputCmdHandler.FromDelegate(_ => ToggleWindow()))
|
||||
.Register<CP14KnowledgeUIController>();
|
||||
}
|
||||
|
||||
public void OnStateExited(GameplayState state)
|
||||
{
|
||||
if (_window != null)
|
||||
{
|
||||
_window.Dispose();
|
||||
_window = null;
|
||||
}
|
||||
|
||||
CommandBinds.Unregister<CP14KnowledgeUIController>();
|
||||
}
|
||||
|
||||
public void OnSystemLoaded(ClientCP14KnowledgeSystem system)
|
||||
{
|
||||
system.OnKnowledgeUpdate += KnowledgeUpdated;
|
||||
_player.LocalPlayerDetached += CharacterDetached;
|
||||
}
|
||||
|
||||
public void OnSystemUnloaded(ClientCP14KnowledgeSystem system)
|
||||
{
|
||||
system.OnKnowledgeUpdate -= KnowledgeUpdated;
|
||||
_player.LocalPlayerDetached -= CharacterDetached;
|
||||
}
|
||||
|
||||
public void UnloadButton()
|
||||
{
|
||||
if (KnowledgeButton is null)
|
||||
return;
|
||||
|
||||
KnowledgeButton.OnPressed -= KnowledgeButtonPressed;
|
||||
}
|
||||
|
||||
public void LoadButton()
|
||||
{
|
||||
if (KnowledgeButton is null)
|
||||
return;
|
||||
|
||||
KnowledgeButton.OnPressed += KnowledgeButtonPressed;
|
||||
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
_window.OnClose += DeactivateButton;
|
||||
_window.OnOpen += ActivateButton;
|
||||
}
|
||||
|
||||
private void DeactivateButton()
|
||||
{
|
||||
KnowledgeButton!.Pressed = false;
|
||||
}
|
||||
|
||||
private void ActivateButton()
|
||||
{
|
||||
KnowledgeButton!.Pressed = true;
|
||||
}
|
||||
|
||||
private void KnowledgeUpdated(ClientCP14KnowledgeSystem.KnowledgeData data)
|
||||
{
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
_window.KnowledgeContent.RemoveAllChildren();
|
||||
|
||||
var (entity, allKnowledge) = data;
|
||||
|
||||
foreach (var knowledge in allKnowledge)
|
||||
{
|
||||
if (!_proto.TryIndex(knowledge, out var indexedKnowledge))
|
||||
continue;
|
||||
|
||||
var knowledgeButton = new Button()
|
||||
{
|
||||
Access = AccessLevel.Public,
|
||||
Text = Loc.GetString(indexedKnowledge.Name),
|
||||
ToolTip = Loc.GetString(indexedKnowledge.Desc),
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
};
|
||||
|
||||
_window.KnowledgeContent.AddChild(knowledgeButton);
|
||||
}
|
||||
}
|
||||
|
||||
private void CharacterDetached(EntityUid uid)
|
||||
{
|
||||
CloseWindow();
|
||||
}
|
||||
|
||||
private void KnowledgeButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
ToggleWindow();
|
||||
}
|
||||
|
||||
private void CloseWindow()
|
||||
{
|
||||
_window?.Close();
|
||||
}
|
||||
|
||||
private void ToggleWindow()
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
if (KnowledgeButton != null)
|
||||
{
|
||||
KnowledgeButton.SetClickPressed(!_window.IsOpen);
|
||||
}
|
||||
|
||||
if (_window.IsOpen)
|
||||
{
|
||||
CloseWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
_knowledge.RequestKnowledgeInfo();
|
||||
_window.Open();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<windows:CP14KnowledgeWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:cc="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:windows="clr-namespace:Content.Client._CP14.UserInterface.Systems.Knowledge.Windows"
|
||||
Title="{Loc 'cp14-knowledge-info-title'}"
|
||||
MinWidth="400"
|
||||
MinHeight="200">
|
||||
<ScrollContainer>
|
||||
<BoxContainer Name="KnowledgeContent" Margin="5" Access="Public" Orientation="Vertical">
|
||||
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
</windows:CP14KnowledgeWindow>
|
||||
@@ -2,12 +2,12 @@ using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._CP14.UserInterface.Systems.Skill.Window;
|
||||
namespace Content.Client._CP14.UserInterface.Systems.Knowledge.Windows;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14SkillWindow : DefaultWindow
|
||||
public sealed partial class CP14KnowledgeWindow : DefaultWindow
|
||||
{
|
||||
public CP14SkillWindow()
|
||||
public CP14KnowledgeWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using Content.Client._CP14.Skill;
|
||||
using Content.Client._CP14.Skill.Ui;
|
||||
using Content.Client._CP14.UserInterface.Systems.Skill.Window;
|
||||
using Content.Client.Gameplay;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.Input;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client._CP14.UserInterface.Systems.Skill;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class CP14SkillUIController : UIController, IOnStateEntered<GameplayState>, IOnStateExited<GameplayState>,
|
||||
IOnSystemChanged<CP14ClientSkillSystem>
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[UISystemDependency] private readonly CP14ClientSkillSystem _skill = default!;
|
||||
|
||||
private CP14SkillWindow? _window;
|
||||
private CP14SkillPrototype? _selectedSkill;
|
||||
|
||||
private MenuButton? SkillButton => UIManager.GetActiveUIWidgetOrNull<Client.UserInterface.Systems.MenuBar.Widgets.GameTopMenuBar>()?.CP14SkillButton;
|
||||
|
||||
public void OnStateEntered(GameplayState state)
|
||||
{
|
||||
DebugTools.Assert(_window == null);
|
||||
|
||||
_window = UIManager.CreateWindow<CP14SkillWindow>();
|
||||
LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.CenterTop);
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.CP14OpenSkillMenu,
|
||||
InputCmdHandler.FromDelegate(_ => ToggleWindow()))
|
||||
.Register<CP14SkillUIController>();
|
||||
|
||||
_window.LearnButton.OnPressed += _ => _skill.RequestLearnSkill(_player.LocalEntity, _selectedSkill);
|
||||
_window.GraphControl.OnNodeSelected += SelectNode;
|
||||
_window.GraphControl.OnOffsetChanged += offset =>
|
||||
{
|
||||
_window.ParallaxBackground.Offset = -offset * 0.25f + new Vector2(1000,1000); //hardcoding is bad
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public void OnStateExited(GameplayState state)
|
||||
{
|
||||
if (_window != null)
|
||||
{
|
||||
_window.GraphControl.OnNodeSelected -= SelectNode;
|
||||
|
||||
_window.Dispose();
|
||||
_window = null;
|
||||
}
|
||||
|
||||
CommandBinds.Unregister<CP14SkillUIController>();
|
||||
}
|
||||
|
||||
public void OnSystemLoaded(CP14ClientSkillSystem system)
|
||||
{
|
||||
system.OnSkillUpdate += UpdateState;
|
||||
_player.LocalPlayerDetached += CharacterDetached;
|
||||
}
|
||||
|
||||
public void OnSystemUnloaded(CP14ClientSkillSystem system)
|
||||
{
|
||||
system.OnSkillUpdate -= UpdateState;
|
||||
_player.LocalPlayerDetached -= CharacterDetached;
|
||||
}
|
||||
|
||||
public void UnloadButton()
|
||||
{
|
||||
if (SkillButton is null)
|
||||
return;
|
||||
|
||||
SkillButton.OnPressed -= SkillButtonPressed;
|
||||
}
|
||||
|
||||
public void LoadButton()
|
||||
{
|
||||
if (SkillButton is null)
|
||||
return;
|
||||
|
||||
SkillButton.OnPressed += SkillButtonPressed;
|
||||
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
_window.OnClose += DeactivateButton;
|
||||
_window.OnOpen += ActivateButton;
|
||||
}
|
||||
|
||||
private void DeactivateButton()
|
||||
{
|
||||
SkillButton!.Pressed = false;
|
||||
}
|
||||
|
||||
private void ActivateButton()
|
||||
{
|
||||
SkillButton!.Pressed = true;
|
||||
}
|
||||
|
||||
private void SelectNode(CP14SkillPrototype? skill)
|
||||
{
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
if (_player.LocalEntity == null)
|
||||
return;
|
||||
|
||||
_selectedSkill = skill;
|
||||
|
||||
if (skill == null)
|
||||
{
|
||||
_window.SkillName.Text = string.Empty;
|
||||
_window.SkillDescription.Text = string.Empty;
|
||||
_window.SkillView.Texture = null;
|
||||
_window.LearnButton.Disabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_window.SkillName.Text = _skill.GetSkillName(skill);
|
||||
_window.SkillDescription.SetMessage(GetSkillDescription(skill));
|
||||
_window.SkillView.Texture = skill.Icon.Frame0();
|
||||
_window.LearnButton.Disabled = !_skill.CanLearnSkill(_player.LocalEntity.Value, skill);
|
||||
_window.SkillCost.Text = skill.LearnCost.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private FormattedMessage GetSkillDescription(CP14SkillPrototype skill)
|
||||
{
|
||||
var msg = new FormattedMessage();
|
||||
|
||||
if (_player.LocalEntity == null)
|
||||
return msg;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
//Description
|
||||
sb.Append(_skill.GetSkillDescription(skill) + "\n \n");
|
||||
|
||||
//Restrictions
|
||||
foreach (var req in skill.Restrictions)
|
||||
{
|
||||
var color = req.Check(_entManager, _player.LocalEntity.Value) ? "green" : "red";
|
||||
|
||||
sb.Append($"- [color={color}]{req.GetDescription(_entManager, _proto)}[/color]\n");
|
||||
}
|
||||
|
||||
msg.TryAddMarkup(sb.ToString(), out _);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
private void UpdateState(EntityUid player)
|
||||
{
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
if (!EntityManager.TryGetComponent<CP14SkillStorageComponent>(player, out var storage))
|
||||
return;
|
||||
|
||||
_window.GraphControl.UpdateState((player, storage));
|
||||
|
||||
// Reselect for update state
|
||||
SelectNode(_selectedSkill);
|
||||
|
||||
//If tree not selected, select the first one
|
||||
if (_window.GraphControl.Tree == null && storage.Progress.Count > 0)
|
||||
{
|
||||
var firstTree = storage.Progress.First().Key;
|
||||
|
||||
if (_proto.TryIndex(firstTree, out var indexedTree))
|
||||
{
|
||||
SelectTree(indexedTree, storage); // Set the first tree from the player's progress
|
||||
}
|
||||
}
|
||||
|
||||
// Update the experience points for the selected tree
|
||||
var playerProgress = storage.Progress;
|
||||
if (_window.GraphControl.Tree is not null && playerProgress.TryGetValue(_window.GraphControl.Tree, out var skillpoint))
|
||||
{
|
||||
_window.ExpPointLabel.Text = skillpoint.ToString();
|
||||
}
|
||||
|
||||
_window.LevelLabel.Text = $"{storage.SkillsSumExperience}/{storage.ExperienceMaxCap}";
|
||||
|
||||
_window.TreeTabsContainer.RemoveAllChildren();
|
||||
foreach (var (tree, progress) in storage.Progress)
|
||||
{
|
||||
if (!_proto.TryIndex(tree, out var indexedTree))
|
||||
continue;
|
||||
|
||||
var treeButton2 = new CP14SkillTreeButtonControl(indexedTree.Color, Loc.GetString(indexedTree.Name));
|
||||
treeButton2.ToolTip = Loc.GetString(indexedTree.Desc ?? string.Empty);
|
||||
treeButton2.OnPressed += () =>
|
||||
{
|
||||
SelectTree(indexedTree, storage);
|
||||
};
|
||||
|
||||
_window.TreeTabsContainer.AddChild(treeButton2);
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectTree(CP14SkillTreePrototype tree, CP14SkillStorageComponent storage)
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
_window.GraphControl.Tree = tree;
|
||||
_window.ParallaxBackground.ParallaxPrototype = tree.Parallax;
|
||||
_window.TreeName.Text = Loc.GetString(tree.Name);
|
||||
|
||||
var playerProgress = storage.Progress;
|
||||
_window.ExpPointLabel.Text = playerProgress.TryGetValue(tree, out var skillpoint) ? skillpoint.ToString() : "0";
|
||||
}
|
||||
|
||||
private void CharacterDetached(EntityUid uid)
|
||||
{
|
||||
CloseWindow();
|
||||
}
|
||||
|
||||
private void SkillButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
ToggleWindow();
|
||||
}
|
||||
|
||||
private void CloseWindow()
|
||||
{
|
||||
_window?.Close();
|
||||
}
|
||||
|
||||
private void ToggleWindow()
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
if (SkillButton != null)
|
||||
{
|
||||
SkillButton.SetClickPressed(!_window.IsOpen);
|
||||
}
|
||||
|
||||
if (_window.IsOpen)
|
||||
{
|
||||
CloseWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
_skill.RequestSkillData();
|
||||
_window.Open();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
<window:CP14SkillWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:window="clr-namespace:Content.Client._CP14.UserInterface.Systems.Skill.Window"
|
||||
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
xmlns:parallax="clr-namespace:Content.Client.Parallax"
|
||||
xmlns:ui1="clr-namespace:Content.Client._CP14.Skill.Ui"
|
||||
Title="{Loc 'cp14-skill-info-title'}"
|
||||
MinSize="700 350"
|
||||
SetSize="980 550">
|
||||
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
|
||||
|
||||
<!-- Selected Skill -->
|
||||
<BoxContainer Margin="10 10 10 10" MaxWidth="240" SetWidth="240" Orientation="Vertical"
|
||||
HorizontalExpand="False" VerticalExpand="True">
|
||||
<!-- Skill View -->
|
||||
<PanelContainer Name="BackPanel" HorizontalAlignment="Center">
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxTexture Modulate="#1B1B1E" PatchMarginBottom="10" PatchMarginLeft="10"
|
||||
PatchMarginRight="10" PatchMarginTop="10" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" >
|
||||
<TextureRect Stretch="Scale" Name="SkillView" SetSize="64 64" HorizontalAlignment="Center" VerticalAlignment="Center" MinSize="64 64"
|
||||
HorizontalExpand="True" VerticalExpand="True" Access="Public"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<customControls:HSeparator StyleClasses="HighDivider" Margin="0 15 0 10" />
|
||||
<!-- Skill Data -->
|
||||
<BoxContainer Name="NodeViewContainer" Orientation="Vertical" VerticalExpand="True">
|
||||
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="False" VerticalExpand="True">
|
||||
<BoxContainer Name="InfoContainer" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<Label Name="SkillName" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
|
||||
HorizontalExpand="True" HorizontalAlignment="Center" />
|
||||
</BoxContainer>
|
||||
<!-- Skill Cost -->
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<RichTextLabel HorizontalExpand="True" Access="Public" Text="{Loc 'cp14-skill-menu-learncost'}" Margin="0 10 0 10" />
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Left" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Skills/skillpoint.png"/>
|
||||
<RichTextLabel Name="SkillCost" Access="Public" Text="0"/>
|
||||
</BoxContainer>
|
||||
<!-- Skill Description -->
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<RichTextLabel Name="SkillDescription" HorizontalExpand="True" Access="Public"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<Control MinHeight="5"/>
|
||||
<!-- Skill Buttons -->
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Button Name="LearnButton" Text="{Loc 'cp14-skill-menu-learn-button'}" StyleClasses="OpenRight" HorizontalExpand="True" MinHeight="35" Access="Public"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<customControls:VSeparator StyleClasses="LowDivider" />
|
||||
|
||||
<!-- Skills Tree -->
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<Label Name="TreeName" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
|
||||
HorizontalExpand="True" HorizontalAlignment="Center" />
|
||||
</BoxContainer>
|
||||
<PanelContainer Margin="10 10 10 10" HorizontalExpand="True" VerticalExpand="True" RectClipContent="True">
|
||||
<parallax:ParallaxControl Name="ParallaxBackground" ScaleX="4" ScaleY="4" Access="Public" SpeedX="10" SpeedY="5"/>
|
||||
<BoxContainer Margin="10 10 10 10" Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
|
||||
<ui1:CP14SkillTreeGraphControl Name="GraphControl" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Access="Public"/>
|
||||
</BoxContainer>
|
||||
<!-- Tree Tabs -->
|
||||
<BoxContainer Margin="10 10 10 10" VerticalAlignment="Top" HorizontalAlignment="Right" Orientation="Vertical" VerticalExpand="True">
|
||||
<BoxContainer Name="TreeTabsContainer" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Access="Public"/>
|
||||
</BoxContainer>
|
||||
<!-- Experience Data -->
|
||||
<BoxContainer Margin="10 10 10 10" VerticalAlignment="Bottom" HorizontalAlignment="Center" Orientation="Horizontal" VerticalExpand="True">
|
||||
<RichTextLabel VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Loc 'cp14-skill-menu-skillpoints'}" StyleClasses="LabelKeyText"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Skills/skillpoint.png"/>
|
||||
<RichTextLabel Margin="0 0 20 0" Name="ExpPointLabel" VerticalAlignment="Center" HorizontalAlignment="Left" Text="0" StyleClasses="LabelKeyText" Access="Public"/>
|
||||
|
||||
<RichTextLabel VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Loc 'cp14-skill-menu-level'}" StyleClasses="LabelKeyText"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Skills/skillpoint.png"/>
|
||||
<RichTextLabel Margin="0 0 0 0" Name="LevelLabel" VerticalAlignment="Center" HorizontalAlignment="Left" Text="0" StyleClasses="LabelKeyText" Access="Public"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</window:CP14SkillWindow>
|
||||
@@ -1,94 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.DeviceLinking.Systems;
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Content.Shared.Prototypes;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.DeviceLinking;
|
||||
|
||||
public sealed class DeviceLinkingTest
|
||||
{
|
||||
private const string PortTesterProtoId = "DeviceLinkingSinkPortTester";
|
||||
|
||||
[TestPrototypes]
|
||||
private const string Prototypes = $@"
|
||||
- type: entity
|
||||
id: {PortTesterProtoId}
|
||||
components:
|
||||
- type: DeviceLinkSource
|
||||
ports:
|
||||
- Output
|
||||
";
|
||||
|
||||
/// <summary>
|
||||
/// Spawns every entity that has a <see cref="DeviceLinkSinkComponent"/>
|
||||
/// and sends a signal to every port to make sure nothing causes an error.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task AllDeviceLinkSinksWorkTest()
|
||||
{
|
||||
await using var pair = await PoolManager.GetServerClient();
|
||||
var server = pair.Server;
|
||||
var compFact = server.ResolveDependency<IComponentFactory>();
|
||||
var mapMan = server.ResolveDependency<IMapManager>();
|
||||
var mapSys = server.System<SharedMapSystem>();
|
||||
var deviceLinkSys = server.System<DeviceLinkSystem>();
|
||||
|
||||
var prototypes = server.ProtoMan.EnumeratePrototypes<EntityPrototype>();
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
foreach (var proto in prototypes)
|
||||
{
|
||||
if (proto.Abstract || pair.IsTestPrototype(proto))
|
||||
continue;
|
||||
|
||||
if (!proto.TryGetComponent<DeviceLinkSinkComponent>(out var protoSinkComp, compFact))
|
||||
continue;
|
||||
|
||||
foreach (var port in protoSinkComp.Ports)
|
||||
{
|
||||
// Create a map for each entity/port combo so they can't interfere
|
||||
mapSys.CreateMap(out var mapId);
|
||||
var grid = mapMan.CreateGridEntity(mapId);
|
||||
mapSys.SetTile(grid.Owner, grid.Comp, Vector2i.Zero, new Tile(1));
|
||||
var coord = new EntityCoordinates(grid.Owner, 0, 0);
|
||||
|
||||
// Spawn the sink entity
|
||||
var sinkEnt = server.EntMan.SpawnEntity(proto.ID, coord);
|
||||
// Get the actual sink component, since the one we got from the prototype doesn't have its owner set up
|
||||
Assert.That(server.EntMan.TryGetComponent<DeviceLinkSinkComponent>(sinkEnt, out var sinkComp),
|
||||
$"{proto.ID} does not have a DeviceLinkSinkComponent!");
|
||||
|
||||
// Spawn the tester
|
||||
var sourceEnt = server.EntMan.SpawnEntity(PortTesterProtoId, coord);
|
||||
Assert.That(server.EntMan.TryGetComponent<DeviceLinkSourceComponent>(sourceEnt, out var sourceComp),
|
||||
$"Tester prototype does not have a DeviceLinkSourceComponent!");
|
||||
|
||||
// Create a link from the tester's output to the target port on the sink
|
||||
deviceLinkSys.SaveLinks(null,
|
||||
sourceEnt,
|
||||
sinkEnt,
|
||||
[("Output", port.Id)],
|
||||
sourceComp,
|
||||
sinkComp);
|
||||
|
||||
// Send a signal to the port
|
||||
Assert.DoesNotThrow(() => { deviceLinkSys.InvokePort(sourceEnt, "Output", null, sourceComp); },
|
||||
$"Exception thrown while triggering port {port.Id} of sink device {proto.ID}");
|
||||
|
||||
mapSys.DeleteMap(mapId);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using Content.Shared.Projectiles;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Embedding;
|
||||
|
||||
public sealed class EmbedTest : InteractionTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Embeddable entity that will be thrown at the target.
|
||||
/// </summary>
|
||||
private const string EmbeddableProtoId = "SurvivalKnife";
|
||||
|
||||
/// <summary>
|
||||
/// Target entity that the thrown item will embed into.
|
||||
/// </summary>
|
||||
private const string TargetProtoId = "AirlockGlass";
|
||||
|
||||
/// <summary>
|
||||
/// Embeds an entity with a <see cref="EmbeddableProjectileComponent"/> into a target,
|
||||
/// then disconnects the client. Intended to reveal any clientside issues that might
|
||||
/// occur due to reparenting during cleanup.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestDisconnectWhileEmbedded()
|
||||
{
|
||||
// Spawn the target we're going to throw at
|
||||
await SpawnTarget(TargetProtoId);
|
||||
|
||||
// Give the player the embeddable to throw
|
||||
var projectile = await PlaceInHands(EmbeddableProtoId);
|
||||
Assert.That(TryComp<EmbeddableProjectileComponent>(projectile, out var embedComp),
|
||||
$"{EmbeddableProtoId} does not have EmbeddableProjectileComponent");
|
||||
// Make sure the projectile isn't already embedded into anything
|
||||
Assert.That(embedComp.EmbeddedIntoUid, Is.Null,
|
||||
$"Projectile already embedded into {SEntMan.ToPrettyString(embedComp.EmbeddedIntoUid)}");
|
||||
|
||||
// Have the player throw the embeddable at the target
|
||||
await ThrowItem();
|
||||
|
||||
// Wait a moment for the item to hit and embed
|
||||
await RunSeconds(0.5f);
|
||||
|
||||
// Make sure the projectile is embedded into the target
|
||||
Assert.That(embedComp.EmbeddedIntoUid, Is.EqualTo(ToServer(Target)),
|
||||
"Projectile not embedded into target");
|
||||
|
||||
// Disconnect the client
|
||||
var cNetMgr = Client.ResolveDependency<IClientNetManager>();
|
||||
await Client.WaitPost(Client.EntMan.FlushEntities);
|
||||
await Pair.RunTicksSync(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Embeds an entity with a <see cref="EmbeddableProjectileComponent"/> into a target,
|
||||
/// then deletes the target and makes sure the embeddable is not deleted.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestEmbedDetach()
|
||||
{
|
||||
// Spawn the target we're going to throw at
|
||||
await SpawnTarget(TargetProtoId);
|
||||
|
||||
// Give the player the embeddable to throw
|
||||
var projectile = await PlaceInHands(EmbeddableProtoId);
|
||||
Assert.That(TryComp<EmbeddableProjectileComponent>(projectile, out var embedComp),
|
||||
$"{EmbeddableProtoId} does not have EmbeddableProjectileComponent");
|
||||
// Make sure the projectile isn't already embedded into anything
|
||||
Assert.That(embedComp.EmbeddedIntoUid, Is.Null,
|
||||
$"Projectile already embedded into {SEntMan.ToPrettyString(embedComp.EmbeddedIntoUid)}");
|
||||
|
||||
// Have the player throw the embeddable at the target
|
||||
await ThrowItem();
|
||||
|
||||
// Wait a moment for the item to hit and embed
|
||||
await RunSeconds(0.5f);
|
||||
|
||||
// Make sure the projectile is embedded into the target
|
||||
Assert.That(embedComp.EmbeddedIntoUid, Is.EqualTo(ToServer(Target)),
|
||||
"Projectile not embedded into target");
|
||||
|
||||
// Delete the target
|
||||
await Delete(Target.Value);
|
||||
|
||||
await RunTicks(1);
|
||||
|
||||
// Make sure the embeddable wasn't deleted with the target
|
||||
AssertExists(projectile);
|
||||
await AssertEntityLookup(EmbeddableProtoId);
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,6 @@ namespace Content.IntegrationTests.Tests
|
||||
.Where(p => !pair.IsTestPrototype(p))
|
||||
.Where(p => !p.Components.ContainsKey("MapGrid")) // This will smash stuff otherwise.
|
||||
.Where(p => !p.Components.ContainsKey("RoomFill")) // This comp can delete all entities, and spawn others
|
||||
.Where(p => !p.Components.ContainsKey("CP14BiomeSpawner")) // CP14 this component delete all entities on this tile
|
||||
.Select(p => p.ID)
|
||||
.ToList();
|
||||
|
||||
@@ -104,7 +103,6 @@ namespace Content.IntegrationTests.Tests
|
||||
.Where(p => !pair.IsTestPrototype(p))
|
||||
.Where(p => !p.Components.ContainsKey("MapGrid")) // This will smash stuff otherwise.
|
||||
.Where(p => !p.Components.ContainsKey("RoomFill")) // This comp can delete all entities, and spawn others
|
||||
.Where(p => !p.Components.ContainsKey("CP14BiomeSpawner")) // CP14 this component delete all entities on this tile
|
||||
.Select(p => p.ID)
|
||||
.ToList();
|
||||
foreach (var protoId in protoIds)
|
||||
@@ -346,7 +344,6 @@ namespace Content.IntegrationTests.Tests
|
||||
"DebugExceptionStartup",
|
||||
"GridFill",
|
||||
"RoomFill",
|
||||
"CP14BiomeSpawner", // CP14 this component delete all entities on this tile
|
||||
"Map", // We aren't testing a map entity in this test
|
||||
"MapGrid",
|
||||
"Broadphase",
|
||||
|
||||
@@ -155,7 +155,7 @@ public sealed class NukeOpsTest
|
||||
// The game rule exists, and all the stations/shuttles/maps are properly initialized
|
||||
var rule = entMan.AllComponents<NukeopsRuleComponent>().Single();
|
||||
var ruleComp = rule.Component;
|
||||
var gridsRule = entMan.GetComponent<RuleGridsComponent>(rule.Uid);
|
||||
var gridsRule = entMan.AllComponents<RuleGridsComponent>().Single().Component;
|
||||
foreach (var grid in gridsRule.MapGrids)
|
||||
{
|
||||
Assert.That(entMan.EntityExists(grid));
|
||||
|
||||
@@ -19,19 +19,16 @@ public sealed class LocalizedDatasetPrototypeTest
|
||||
|
||||
var protos = protoMan.EnumeratePrototypes<LocalizedDatasetPrototype>().OrderBy(p => p.ID);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
// Check each prototype
|
||||
foreach (var proto in protos)
|
||||
{
|
||||
// Check each prototype
|
||||
foreach (var proto in protos)
|
||||
// Check each value in the prototype
|
||||
foreach (var locId in proto.Values)
|
||||
{
|
||||
// Check each value in the prototype
|
||||
foreach (var locId in proto.Values)
|
||||
{
|
||||
// Make sure the localization manager has a string for the LocId
|
||||
Assert.That(localizationMan.HasString(locId), $"LocalizedDataset {proto.ID} with prefix \"{proto.Values.Prefix}\" specifies {proto.Values.Count} entries, but no localized string was found matching {locId}!");
|
||||
}
|
||||
// Make sure the localization manager has a string for the LocId
|
||||
Assert.That(localizationMan.HasString(locId), $"LocalizedDataset {proto.ID} with prefix \"{proto.Values.Prefix}\" specifies {proto.Values.Count} entries, but no localized string was found matching {locId}!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ using Robust.Shared.EntitySerialization.Systems;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using Robust.Shared.Map.Events;
|
||||
|
||||
namespace Content.IntegrationTests.Tests
|
||||
{
|
||||
@@ -70,6 +69,7 @@ namespace Content.IntegrationTests.Tests
|
||||
"Dev",
|
||||
"MeteorArena",
|
||||
"Comoss",
|
||||
"Factoria",
|
||||
//CrystallEdge Map replacement end
|
||||
};
|
||||
|
||||
@@ -213,12 +213,9 @@ namespace Content.IntegrationTests.Tests
|
||||
}
|
||||
|
||||
var deps = server.ResolveDependency<IEntitySystemManager>().DependencyCollection;
|
||||
var ev = new BeforeEntityReadEvent();
|
||||
server.EntMan.EventBus.RaiseEvent(EventSource.Local, ev);
|
||||
|
||||
foreach (var map in v7Maps)
|
||||
{
|
||||
Assert.That(IsPreInit(map, loader, deps, ev.RenamedPrototypes, ev.DeletedPrototypes));
|
||||
Assert.That(IsPreInit(map, loader, deps));
|
||||
}
|
||||
|
||||
// Check that the test actually does manage to catch post-init maps and isn't just blindly passing everything.
|
||||
@@ -231,12 +228,12 @@ namespace Content.IntegrationTests.Tests
|
||||
// First check that a pre-init version passes
|
||||
var path = new ResPath($"{nameof(NoSavedPostMapInitTest)}.yml");
|
||||
Assert.That(loader.TrySaveMap(id, path));
|
||||
Assert.That(IsPreInit(path, loader, deps, ev.RenamedPrototypes, ev.DeletedPrototypes));
|
||||
Assert.That(IsPreInit(path, loader, deps));
|
||||
|
||||
// and the post-init version fails.
|
||||
await server.WaitPost(() => mapSys.InitializeMap(id));
|
||||
Assert.That(loader.TrySaveMap(id, path));
|
||||
Assert.That(IsPreInit(path, loader, deps, ev.RenamedPrototypes, ev.DeletedPrototypes), Is.False);
|
||||
Assert.That(IsPreInit(path, loader, deps), Is.False);
|
||||
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
@@ -269,11 +266,7 @@ namespace Content.IntegrationTests.Tests
|
||||
});
|
||||
}
|
||||
|
||||
private bool IsPreInit(ResPath map,
|
||||
MapLoaderSystem loader,
|
||||
IDependencyCollection deps,
|
||||
Dictionary<string, string> renamedPrototypes,
|
||||
HashSet<string> deletedPrototypes)
|
||||
private bool IsPreInit(ResPath map, MapLoaderSystem loader, IDependencyCollection deps)
|
||||
{
|
||||
if (!loader.TryReadFile(map, out var data))
|
||||
{
|
||||
@@ -281,12 +274,7 @@ namespace Content.IntegrationTests.Tests
|
||||
return false;
|
||||
}
|
||||
|
||||
var reader = new EntityDeserializer(deps,
|
||||
data,
|
||||
DeserializationOptions.Default,
|
||||
renamedPrototypes,
|
||||
deletedPrototypes);
|
||||
|
||||
var reader = new EntityDeserializer(deps, data, DeserializationOptions.Default);
|
||||
if (!reader.TryProcessData())
|
||||
{
|
||||
Assert.Fail($"Failed to process {map}");
|
||||
|
||||
@@ -35,6 +35,7 @@ public sealed class PrototypeSaveTest
|
||||
await using var pair = await PoolManager.GetServerClient();
|
||||
var server = pair.Server;
|
||||
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var entityMan = server.ResolveDependency<IEntityManager>();
|
||||
var prototypeMan = server.ResolveDependency<IPrototypeManager>();
|
||||
var seriMan = server.ResolveDependency<ISerializationManager>();
|
||||
|
||||
@@ -102,12 +102,6 @@ public sealed class StoreTests
|
||||
+ $"flag as 'true'. This marks the fact that cost modifier of discount is not applied properly!"
|
||||
);
|
||||
|
||||
// The storeComponent returns discounted items with conditions randomly, so we remove these to sanitize the data.
|
||||
foreach (var discountedItem in discountedListingItems)
|
||||
{
|
||||
discountedItem.Conditions = null;
|
||||
}
|
||||
|
||||
// Refund action requests re-generation of listing items so we will be re-acquiring items from component a lot of times.
|
||||
var itemIds = discountedListingItems.Select(x => x.ID);
|
||||
foreach (var itemId in itemIds)
|
||||
@@ -146,9 +140,6 @@ public sealed class StoreTests
|
||||
// get refreshed item after refund re-generated items
|
||||
discountedListingItem = storeComponent.FullListingsCatalog.First(x => x.ID == itemId);
|
||||
|
||||
// The storeComponent can give a discounted item a condition at random, so we remove it to sanitize the data.
|
||||
discountedListingItem.Conditions = null;
|
||||
|
||||
var afterRefundBalance = storeComponent.Balance[UplinkSystem.TelecrystalCurrencyPrototype];
|
||||
Assert.That(afterRefundBalance.Value, Is.EqualTo(originalBalance.Value), "Expected refund to return all discounted cost value.");
|
||||
Assert.That(
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
using System.Linq;
|
||||
using Content.IntegrationTests.Tests.Interaction;
|
||||
using Content.Server.VendingMachines;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.VendingMachines;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Vending;
|
||||
|
||||
public sealed class VendingInteractionTest : InteractionTest
|
||||
{
|
||||
private const string VendingMachineProtoId = "InteractionTestVendingMachine";
|
||||
|
||||
private const string VendedItemProtoId = "InteractionTestItem";
|
||||
|
||||
private const string RestockBoxProtoId = "InteractionTestRestockBox";
|
||||
|
||||
private const string RestockBoxOtherProtoId = "InteractionTestRestockBoxOther";
|
||||
|
||||
[TestPrototypes]
|
||||
private const string TestPrototypes = $@"
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
id: {VendedItemProtoId}
|
||||
name: {VendedItemProtoId}
|
||||
|
||||
- type: vendingMachineInventory
|
||||
id: InteractionTestVendingInventory
|
||||
startingInventory:
|
||||
{VendedItemProtoId}: 5
|
||||
|
||||
- type: vendingMachineInventory
|
||||
id: InteractionTestVendingInventoryOther
|
||||
startingInventory:
|
||||
{VendedItemProtoId}: 5
|
||||
|
||||
- type: entity
|
||||
parent: BaseVendingMachineRestock
|
||||
id: {RestockBoxProtoId}
|
||||
components:
|
||||
- type: VendingMachineRestock
|
||||
canRestock:
|
||||
- InteractionTestVendingInventory
|
||||
|
||||
- type: entity
|
||||
parent: BaseVendingMachineRestock
|
||||
id: {RestockBoxOtherProtoId}
|
||||
components:
|
||||
- type: VendingMachineRestock
|
||||
canRestock:
|
||||
- InteractionTestVendingInventoryOther
|
||||
|
||||
- type: entity
|
||||
id: {VendingMachineProtoId}
|
||||
parent: VendingMachine
|
||||
components:
|
||||
- type: VendingMachine
|
||||
pack: InteractionTestVendingInventory
|
||||
ejectDelay: 0 # no delay to speed up tests
|
||||
- type: Sprite
|
||||
sprite: error.rsi
|
||||
";
|
||||
|
||||
[Test]
|
||||
public async Task InteractUITest()
|
||||
{
|
||||
await SpawnTarget(VendingMachineProtoId);
|
||||
|
||||
// Should start with no BUI open
|
||||
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "BUI was open unexpectedly.");
|
||||
|
||||
// Unpowered vending machine does not open BUI
|
||||
await Activate();
|
||||
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "BUI opened without power.");
|
||||
|
||||
// Power the vending machine
|
||||
var apc = await SpawnEntity("APCBasic", SEntMan.GetCoordinates(TargetCoords));
|
||||
await RunTicks(1);
|
||||
|
||||
// Interacting with powered vending machine opens BUI
|
||||
await Activate();
|
||||
Assert.That(IsUiOpen(VendingMachineUiKey.Key), "BUI failed to open.");
|
||||
|
||||
// Interacting with it again closes the BUI
|
||||
await Activate();
|
||||
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "BUI failed to close on interaction.");
|
||||
|
||||
// Reopen BUI for the next check
|
||||
await Activate();
|
||||
Assert.That(IsUiOpen(VendingMachineUiKey.Key), "BUI failed to reopen.");
|
||||
|
||||
// Remove power
|
||||
await Delete(apc);
|
||||
await RunTicks(1);
|
||||
|
||||
// The BUI should close when power is lost
|
||||
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "BUI failed to close on power loss.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DispenseItemTest()
|
||||
{
|
||||
await SpawnTarget(VendingMachineProtoId);
|
||||
var vendorEnt = SEntMan.GetEntity(Target.Value);
|
||||
|
||||
var vendingSystem = SEntMan.System<VendingMachineSystem>();
|
||||
var items = vendingSystem.GetAllInventory(vendorEnt);
|
||||
|
||||
// Verify initial item count
|
||||
Assert.That(items, Is.Not.Empty, $"{VendingMachineProtoId} spawned with no items.");
|
||||
Assert.That(items.First().Amount, Is.EqualTo(5), $"{VendingMachineProtoId} spawned with unexpected item count.");
|
||||
|
||||
// Power the vending machine
|
||||
await SpawnEntity("APCBasic", SEntMan.GetCoordinates(TargetCoords));
|
||||
await RunTicks(1);
|
||||
|
||||
// Open the BUI
|
||||
await Activate();
|
||||
Assert.That(IsUiOpen(VendingMachineUiKey.Key), "BUI failed to open.");
|
||||
|
||||
// Request an item be dispensed
|
||||
var ev = new VendingMachineEjectMessage(InventoryType.Regular, VendedItemProtoId);
|
||||
await SendBui(VendingMachineUiKey.Key, ev);
|
||||
|
||||
// Make sure the stock decreased
|
||||
Assert.That(items.First().Amount, Is.EqualTo(4), "Stocked item count did not decrease.");
|
||||
// Make sure the dispensed item was spawned in to the world
|
||||
await AssertEntityLookup(
|
||||
("APCBasic", 1),
|
||||
(VendedItemProtoId, 1)
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RestockTest()
|
||||
{
|
||||
var vendingSystem = SEntMan.System<VendingMachineSystem>();
|
||||
|
||||
await SpawnTarget(VendingMachineProtoId);
|
||||
var vendorEnt = SEntMan.GetEntity(Target.Value);
|
||||
|
||||
var items = vendingSystem.GetAllInventory(vendorEnt);
|
||||
|
||||
Assert.That(items, Is.Not.Empty, $"{VendingMachineProtoId} spawned with no items.");
|
||||
Assert.That(items.First().Amount, Is.EqualTo(5), $"{VendingMachineProtoId} spawned with unexpected item count.");
|
||||
|
||||
// Try to restock with the maintenance panel closed (nothing happens)
|
||||
await InteractUsing(RestockBoxProtoId);
|
||||
|
||||
Assert.That(items.First().Amount, Is.EqualTo(5), "Restocked without opening maintenance panel.");
|
||||
|
||||
// Open the maintenance panel
|
||||
await InteractUsing(Screw);
|
||||
|
||||
// Try to restock using the wrong restock box (nothing happens)
|
||||
await InteractUsing(RestockBoxOtherProtoId);
|
||||
|
||||
Assert.That(items.First().Amount, Is.EqualTo(5), "Restocked with wrong restock box.");
|
||||
|
||||
// Restock the machine
|
||||
await InteractUsing(RestockBoxProtoId);
|
||||
|
||||
Assert.That(items.First().Amount, Is.EqualTo(10), "Restocking resulted in unexpected item count.");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RepairTest()
|
||||
{
|
||||
await SpawnTarget(VendingMachineProtoId);
|
||||
|
||||
// Power the vending machine
|
||||
await SpawnEntity("APCBasic", SEntMan.GetCoordinates(TargetCoords));
|
||||
await RunTicks(1);
|
||||
|
||||
// Break it
|
||||
await BreakVendor();
|
||||
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "BUI did not close when vending machine broke.");
|
||||
|
||||
// Make sure we can't open the BUI while it's broken
|
||||
await Activate();
|
||||
Assert.That(IsUiOpen(VendingMachineUiKey.Key), Is.False, "Opened BUI of broken vending machine.");
|
||||
|
||||
// Repair the vending machine
|
||||
await InteractUsing(Weld);
|
||||
|
||||
// Make sure the BUI can open now that the machine has been repaired
|
||||
await Activate();
|
||||
Assert.That(IsUiOpen(VendingMachineUiKey.Key), "Failed to open BUI after repair.");
|
||||
}
|
||||
|
||||
private async Task BreakVendor()
|
||||
{
|
||||
var damageableSys = SEntMan.System<DamageableSystem>();
|
||||
Assert.That(TryComp<DamageableComponent>(out var damageableComp), $"{VendingMachineProtoId} does not have DamageableComponent.");
|
||||
Assert.That(damageableComp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero), $"{VendingMachineProtoId} started with unexpected damage.");
|
||||
|
||||
// Damage the vending machine to the point that it breaks
|
||||
var damageType = ProtoMan.Index<DamageTypePrototype>("Blunt");
|
||||
var damage = new DamageSpecifier(damageType, FixedPoint2.New(100));
|
||||
await Server.WaitPost(() => damageableSys.TryChangeDamage(SEntMan.GetEntity(Target), damage, ignoreResistances: true));
|
||||
await RunTicks(5);
|
||||
Assert.That(damageableComp.Damage.GetTotal(), Is.GreaterThan(FixedPoint2.Zero), $"{VendingMachineProtoId} did not take damage.");
|
||||
}
|
||||
}
|
||||
@@ -241,7 +241,7 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
||||
var addedTags = newAccessList.Except(oldTags).Select(tag => "+" + tag).ToList();
|
||||
var removedTags = oldTags.Except(newAccessList).Select(tag => "-" + tag).ToList();
|
||||
|
||||
_adminLogger.Add(LogType.Action, LogImpact.High,
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Medium,
|
||||
$"{ToPrettyString(player):player} has modified {ToPrettyString(accessReaderEnt.Value):entity} with the following allowed access level holders: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]");
|
||||
|
||||
accessReaderEnt.Value.Comp.AccessLists = ConvertAccessListToHashSet(newAccessList);
|
||||
|
||||
@@ -168,7 +168,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
||||
|
||||
/*TODO: ECS SharedIdCardConsoleComponent and then log on card ejection, together with the save.
|
||||
This current implementation is pretty shit as it logs 27 entries (27 lines) if someone decides to give themselves AA*/
|
||||
_adminLogger.Add(LogType.Action, LogImpact.High,
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Medium,
|
||||
$"{ToPrettyString(player):player} has modified {ToPrettyString(targetId):entity} with the following accesses: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]");
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ public sealed class IdCardSystem : SharedIdCardSystem
|
||||
access.Tags.Add(random.ID);
|
||||
Dirty(uid, access);
|
||||
|
||||
_adminLogger.Add(LogType.Action, LogImpact.High,
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Medium,
|
||||
$"{ToPrettyString(args.Microwave)} added {random.ID} access to {ToPrettyString(uid):entity}");
|
||||
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ public sealed class ChangeCvarCommand : IConsoleCommand
|
||||
var oldValue = _configurationManager.GetCVar<object>(cvar);
|
||||
_configurationManager.SetCVar(cvar, parsed);
|
||||
_adminLogManager.Add(LogType.AdminCommands,
|
||||
LogImpact.Extreme,
|
||||
LogImpact.High,
|
||||
$"{shell.Player!.Name} ({shell.Player!.UserId}) changed CVAR {cvar} from {oldValue.ToString()} to {parsed.ToString()}"
|
||||
);
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Notes;
|
||||
using Content.Server.Administration.Notes;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.ViewNotes)]
|
||||
public sealed class OpenAdminNotesCommand : LocalizedCommands
|
||||
public sealed class OpenAdminNotesCommand : IConsoleCommand
|
||||
{
|
||||
public const string CommandName = "adminnotes";
|
||||
|
||||
public override string Command => CommandName;
|
||||
public string Command => CommandName;
|
||||
public string Description => "Opens the admin notes panel.";
|
||||
public string Help => $"Usage: {Command} <notedPlayerUserId OR notedPlayerUsername>";
|
||||
|
||||
public override async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
public async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (shell.Player is not { } player)
|
||||
{
|
||||
@@ -33,27 +33,17 @@ public sealed class OpenAdminNotesCommand : LocalizedCommands
|
||||
|
||||
if (dbGuid == null)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-adminnotes-wrong-target", ("user", args[0])));
|
||||
shell.WriteError($"Unable to find {args[0]} netuserid");
|
||||
return;
|
||||
}
|
||||
|
||||
notedPlayer = dbGuid.UserId;
|
||||
break;
|
||||
default:
|
||||
shell.WriteError(Loc.GetString("cmd-adminnotes-args-error"));
|
||||
shell.WriteError($"Invalid arguments.\n{Help}");
|
||||
return;
|
||||
}
|
||||
|
||||
await IoCManager.Resolve<IAdminNotesManager>().OpenEui(player, notedPlayer);
|
||||
}
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
return CompletionResult.Empty;
|
||||
|
||||
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
||||
var options = playerMgr.Sessions.Select(c => c.Name).OrderBy(c => c).ToArray();
|
||||
return CompletionResult.FromHintOptions(options, Loc.GetString("cmd-adminnotes-hint"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Content.Server.Administration.Commands
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player.Status != SessionStatus.InGame || player.AttachedEntity is not { Valid: true } playerEntity)
|
||||
if (player.Status != SessionStatus.InGame || player.AttachedEntity is not {Valid: true} playerEntity)
|
||||
{
|
||||
shell.WriteLine("You are not in-game!");
|
||||
return;
|
||||
@@ -57,16 +57,14 @@ namespace Content.Server.Administration.Commands
|
||||
var currentMap = _entManager.GetComponent<TransformComponent>(playerEntity).MapID;
|
||||
var currentGrid = _entManager.GetComponent<TransformComponent>(playerEntity).GridUid;
|
||||
|
||||
var xformSystem = _entManager.System<SharedTransformSystem>();
|
||||
|
||||
var found = GetWarpPointByName(location)
|
||||
.OrderBy(p => p.Item1, Comparer<EntityCoordinates>.Create((a, b) =>
|
||||
{
|
||||
// Sort so that warp points on the same grid/map are first.
|
||||
// So if you have two maps loaded with the same warp points,
|
||||
// it will prefer the warp points on the map you're currently on.
|
||||
var aGrid = xformSystem.GetGrid(a);
|
||||
var bGrid = xformSystem.GetGrid(b);
|
||||
var aGrid = a.GetGridUid(_entManager);
|
||||
var bGrid = b.GetGridUid(_entManager);
|
||||
|
||||
if (aGrid == bGrid)
|
||||
{
|
||||
@@ -83,8 +81,8 @@ namespace Content.Server.Administration.Commands
|
||||
return 1;
|
||||
}
|
||||
|
||||
var mapA = xformSystem.GetMapId(a);
|
||||
var mapB = xformSystem.GetMapId(b);
|
||||
var mapA = a.GetMapId(_entManager);
|
||||
var mapB = a.GetMapId(_entManager);
|
||||
|
||||
if (mapA == mapB)
|
||||
{
|
||||
@@ -119,8 +117,10 @@ namespace Content.Server.Administration.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
xformSystem.SetCoordinates(playerEntity, coords);
|
||||
xformSystem.AttachToGridOrMap(playerEntity);
|
||||
var xform = _entManager.GetComponent<TransformComponent>(playerEntity);
|
||||
var xformSystem = _entManager.System<SharedTransformSystem>();
|
||||
xform.Coordinates = coords;
|
||||
xformSystem.AttachToGridOrMap(playerEntity, xform);
|
||||
if (_entManager.TryGetComponent(playerEntity, out PhysicsComponent? physics))
|
||||
{
|
||||
_entManager.System<SharedPhysicsSystem>().SetLinearVelocity(playerEntity, Vector2.Zero, body: physics);
|
||||
|
||||
@@ -2,19 +2,14 @@
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Administration.Systems;
|
||||
using Content.Server.Database;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Players.PlayTimeTracking;
|
||||
using Prometheus;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -30,9 +25,6 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
||||
[Dependency] private readonly IDynamicTypeFactory _typeFactory = default!;
|
||||
[Dependency] private readonly IReflectionManager _reflection = default!;
|
||||
[Dependency] private readonly IDependencyCollection _dependencies = default!;
|
||||
[Dependency] private readonly ISharedPlayerManager _player = default!;
|
||||
[Dependency] private readonly ISharedPlaytimeManager _playtime = default!;
|
||||
[Dependency] private readonly ISharedChatManager _chat = default!;
|
||||
|
||||
public const string SawmillId = "admin.logs";
|
||||
|
||||
@@ -74,7 +66,6 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
||||
private int _queueMax;
|
||||
private int _preRoundQueueMax;
|
||||
private int _dropThreshold;
|
||||
private int _highImpactLogPlaytime;
|
||||
|
||||
// Per update
|
||||
private TimeSpan _nextUpdateTime;
|
||||
@@ -109,8 +100,6 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
||||
value => _preRoundQueueMax = value, true);
|
||||
_configuration.OnValueChanged(CCVars.AdminLogsDropThreshold,
|
||||
value => _dropThreshold = value, true);
|
||||
_configuration.OnValueChanged(CCVars.AdminLogsHighLogPlaytime,
|
||||
value => _highImpactLogPlaytime = value, true);
|
||||
|
||||
if (_metricsEnabled)
|
||||
{
|
||||
@@ -311,10 +300,6 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
||||
Players = new List<AdminLogPlayer>(players.Count)
|
||||
};
|
||||
|
||||
var adminLog = false;
|
||||
var adminSys = _entityManager.SystemOrNull<AdminSystem>();
|
||||
var logMessage = message;
|
||||
|
||||
foreach (var id in players)
|
||||
{
|
||||
var player = new AdminLogPlayer
|
||||
@@ -324,39 +309,8 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
||||
};
|
||||
|
||||
log.Players.Add(player);
|
||||
|
||||
if (adminSys != null)
|
||||
{
|
||||
var cachedInfo = adminSys.GetCachedPlayerInfo(new NetUserId(id));
|
||||
if (cachedInfo != null && cachedInfo.Antag)
|
||||
{
|
||||
logMessage += " [ANTAG: " + cachedInfo.CharacterName + "]";
|
||||
}
|
||||
}
|
||||
|
||||
if (adminLog)
|
||||
continue;
|
||||
|
||||
if (impact == LogImpact.Extreme) // Always chat-notify Extreme logs
|
||||
adminLog = true;
|
||||
|
||||
if (impact == LogImpact.High) // Only chat-notify High logs if the player is below a threshold playtime
|
||||
{
|
||||
if (_highImpactLogPlaytime >= 0 && _player.TryGetSessionById(new NetUserId(id), out var session))
|
||||
{
|
||||
var playtimes = _playtime.GetPlayTimes(session);
|
||||
if (playtimes.TryGetValue(PlayTimeTrackingShared.TrackerOverall, out var overallTime) &&
|
||||
overallTime <= TimeSpan.FromHours(_highImpactLogPlaytime))
|
||||
{
|
||||
adminLog = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (adminLog)
|
||||
_chat.SendAdminAlert(logMessage);
|
||||
|
||||
if (preRound)
|
||||
{
|
||||
_preRoundLogQueue.Enqueue(log);
|
||||
|
||||
@@ -221,7 +221,6 @@ public sealed class AdminSystem : EntitySystem
|
||||
var name = data.UserName;
|
||||
var entityName = string.Empty;
|
||||
var identityName = string.Empty;
|
||||
var sortWeight = 0;
|
||||
|
||||
// Visible (identity) name can be different from real name
|
||||
if (session?.AttachedEntity != null)
|
||||
@@ -235,10 +234,8 @@ public sealed class AdminSystem : EntitySystem
|
||||
// Starting role, antagonist status and role type
|
||||
RoleTypePrototype roleType = new();
|
||||
var startingRole = string.Empty;
|
||||
if (_minds.TryGetMind(session, out var mindId, out var mindComp) && mindComp is not null)
|
||||
if (_minds.TryGetMind(session, out var mindId, out var mindComp))
|
||||
{
|
||||
sortWeight = _role.GetRoleCompByTime(mindComp)?.Comp.SortWeight ?? 0;
|
||||
|
||||
if (_proto.TryIndex(mindComp.RoleType, out var role))
|
||||
roleType = role;
|
||||
else
|
||||
@@ -262,19 +259,8 @@ public sealed class AdminSystem : EntitySystem
|
||||
overallPlaytime = playTime;
|
||||
}
|
||||
|
||||
return new PlayerInfo(
|
||||
name,
|
||||
entityName,
|
||||
identityName,
|
||||
startingRole,
|
||||
antag,
|
||||
roleType,
|
||||
sortWeight,
|
||||
GetNetEntity(session?.AttachedEntity),
|
||||
data.UserId,
|
||||
connected,
|
||||
_roundActivePlayers.Contains(data.UserId),
|
||||
overallPlaytime);
|
||||
return new PlayerInfo(name, entityName, identityName, startingRole, antag, roleType, GetNetEntity(session?.AttachedEntity), data.UserId,
|
||||
connected, _roundActivePlayers.Contains(data.UserId), overallPlaytime);
|
||||
}
|
||||
|
||||
private void OnPanicBunkerChanged(bool enabled)
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using Content.Server._CP14.GameTicking.Rules.Components;
|
||||
using Content.Server.Administration.Commands;
|
||||
using Content.Server.Antag;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Zombies;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Verbs;
|
||||
@@ -20,7 +18,6 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
[Dependency] private readonly AntagSelectionSystem _antag = default!;
|
||||
[Dependency] private readonly ZombieSystem _zombie = default!;
|
||||
[Dependency] private readonly GameTicker _gameTicker = default!;
|
||||
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
private const string DefaultTraitorRule = "Traitor";
|
||||
@@ -40,8 +37,6 @@ public sealed partial class AdminVerbSystem
|
||||
[ValidatePrototypeId<StartingGearPrototype>]
|
||||
private const string PirateGearId = "PirateGear";
|
||||
|
||||
private readonly EntProtoId _paradoxCloneRuleId = "ParadoxCloneSpawn";
|
||||
|
||||
//CP14
|
||||
[ValidatePrototypeId<EntityPrototype>]
|
||||
private const string CP14VampireRule = "CP14Vampire";
|
||||
@@ -184,30 +179,6 @@ public sealed partial class AdminVerbSystem
|
||||
Message = string.Join(": ", thiefName, Loc.GetString("admin-verb-make-thief")),
|
||||
};
|
||||
args.Verbs.Add(thief);
|
||||
|
||||
var paradoxCloneName = Loc.GetString("admin-verb-text-make-paradox-clone");
|
||||
Verb paradox = new()
|
||||
{
|
||||
Text = paradoxCloneName,
|
||||
Category = VerbCategory.Antag,
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/job_icons.rsi"), "ParadoxClone"),
|
||||
Act = () =>
|
||||
{
|
||||
var ruleEnt = _gameTicker.AddGameRule(_paradoxCloneRuleId);
|
||||
|
||||
if (!TryComp<ParadoxCloneRuleComponent>(ruleEnt, out var paradoxCloneRuleComp))
|
||||
return;
|
||||
|
||||
paradoxCloneRuleComp.OriginalBody = args.Target; // override the target player
|
||||
|
||||
_gameTicker.StartGameRule(ruleEnt);
|
||||
},
|
||||
Impact = LogImpact.High,
|
||||
Message = string.Join(": ", paradoxCloneName, Loc.GetString("admin-verb-make-paradox-clone")),
|
||||
};
|
||||
|
||||
if (HasComp<HumanoidAppearanceComponent>(args.Target)) // only humanoids can be cloned
|
||||
args.Verbs.Add(paradox);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ public sealed partial class AdminVerbSystem
|
||||
Filter.PvsExcept(args.Target), true, PopupType.MediumCaution);
|
||||
var board = Spawn("ChessBoard", xform.Coordinates);
|
||||
var session = _tabletopSystem.EnsureSession(Comp<TabletopGameComponent>(board));
|
||||
_transformSystem.SetMapCoordinates(args.Target, session.Position);
|
||||
xform.Coordinates = _transformSystem.ToCoordinates(session.Position);
|
||||
_transformSystem.SetWorldRotationNoLerp((args.Target, xform), Angle.Zero);
|
||||
},
|
||||
Impact = LogImpact.Extreme,
|
||||
@@ -421,7 +421,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
var xform = Transform(args.Target);
|
||||
var fixtures = Comp<FixturesComponent>(args.Target);
|
||||
_transformSystem.Unanchor(args.Target); // Just in case.
|
||||
xform.Anchored = false; // Just in case.
|
||||
_physics.SetBodyType(args.Target, BodyType.Dynamic, manager: fixtures, body: physics);
|
||||
_physics.SetBodyStatus(args.Target, physics, BodyStatus.InAir);
|
||||
_physics.WakeBody(args.Target, manager: fixtures, body: physics);
|
||||
@@ -456,7 +456,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
var xform = Transform(args.Target);
|
||||
var fixtures = Comp<FixturesComponent>(args.Target);
|
||||
_transformSystem.Unanchor(args.Target); // Just in case.
|
||||
xform.Anchored = false; // Just in case.
|
||||
|
||||
_physics.SetBodyType(args.Target, BodyType.Dynamic, body: physics);
|
||||
_physics.SetBodyStatus(args.Target, physics, BodyStatus.InAir);
|
||||
|
||||
@@ -637,7 +637,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
if (_adminManager.HasAdminFlag(player, AdminFlags.Mapping))
|
||||
{
|
||||
if (_map.IsPaused(map.MapId))
|
||||
if (_mapManager.IsMapPaused(map.MapId))
|
||||
{
|
||||
Verb unpauseMap = new()
|
||||
{
|
||||
@@ -646,7 +646,7 @@ public sealed partial class AdminVerbSystem
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/play.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_map.SetPaused(map.MapId, false);
|
||||
_mapManager.SetMapPaused(map.MapId, false);
|
||||
},
|
||||
Impact = LogImpact.Extreme,
|
||||
Message = Loc.GetString("admin-trick-unpause-map-description"),
|
||||
@@ -663,7 +663,7 @@ public sealed partial class AdminVerbSystem
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/pause.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_map.SetPaused(map.MapId, true);
|
||||
_mapManager.SetMapPaused(map.MapId, true);
|
||||
},
|
||||
Impact = LogImpact.Extreme,
|
||||
Message = Loc.GetString("admin-trick-pause-map-description"),
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Content.Server.Administration.Systems
|
||||
[Dependency] private readonly IConsoleHost _console = default!;
|
||||
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly AdminSystem _adminSystem = default!;
|
||||
[Dependency] private readonly DisposalTubeSystem _disposalTubes = default!;
|
||||
@@ -153,10 +153,12 @@ namespace Content.Server.Administration.Systems
|
||||
|
||||
var profile = _ticker.GetPlayerProfile(targetActor.PlayerSession);
|
||||
var mobUid = _spawning.SpawnPlayerMob(coords.Value, null, profile, stationUid);
|
||||
var targetMind = _mindSystem.GetMind(args.Target);
|
||||
|
||||
if (_mindSystem.TryGetMind(args.Target, out var mindId, out var mindComp))
|
||||
_mindSystem.TransferTo(mindId, mobUid, true, mind: mindComp);
|
||||
|
||||
if (targetMind != null)
|
||||
{
|
||||
_mindSystem.TransferTo(targetMind.Value, mobUid, true);
|
||||
}
|
||||
},
|
||||
ConfirmationPopup = true,
|
||||
Impact = LogImpact.High,
|
||||
|
||||
@@ -14,7 +14,6 @@ internal sealed class ServerAlertsSystem : AlertsSystem
|
||||
|
||||
private void OnGetState(Entity<AlertsComponent> alerts, ref ComponentGetState args)
|
||||
{
|
||||
// TODO: Use sourcegen when clone-state bug fixed.
|
||||
args.State = new AlertComponentState(new(alerts.Comp.Alerts));
|
||||
args.State = new AlertComponentState(alerts.Comp.Alerts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ public sealed class AmeControllerSystem : EntitySystem
|
||||
return;
|
||||
|
||||
var humanReadableState = value ? "Inject" : "Not inject";
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{EntityManager.ToPrettyString(user.Value):player} has set the AME to {humanReadableState}");
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{EntityManager.ToPrettyString(user.Value):player} has set the AME to {humanReadableState}");
|
||||
}
|
||||
|
||||
public void ToggleInjecting(EntityUid uid, EntityUid? user = null, AmeControllerComponent? controller = null)
|
||||
@@ -267,15 +267,27 @@ public sealed class AmeControllerSystem : EntitySystem
|
||||
return;
|
||||
|
||||
var humanReadableState = controller.Injecting ? "Inject" : "Not inject";
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{EntityManager.ToPrettyString(user.Value):player} has set the AME to inject {controller.InjectionAmount} while set to {humanReadableState}");
|
||||
|
||||
/* This needs to be information which an admin is very likely to want to be informed about in order to be an admin alert or have a sound notification.
|
||||
At the time of editing, players regularly "overclock" the AME and those cases require no admin attention.
|
||||
|
||||
// Admin alert
|
||||
var safeLimit = int.MaxValue;
|
||||
if (TryGetAMENodeGroup(uid, out var group))
|
||||
safeLimit = group.CoreCount * 4;
|
||||
|
||||
var logImpact = (oldValue <= safeLimit && value > safeLimit) ? LogImpact.Extreme : LogImpact.Medium;
|
||||
|
||||
_adminLogger.Add(LogType.Action, logImpact, $"{EntityManager.ToPrettyString(user.Value):player} has set the AME to inject {controller.InjectionAmount} while set to {humanReadableState}");
|
||||
if (oldValue <= safeLimit && value > safeLimit)
|
||||
{
|
||||
if (_gameTiming.CurTime > controller.EffectCooldown)
|
||||
{
|
||||
_chatManager.SendAdminAlert(user.Value, $"increased AME over safe limit to {controller.InjectionAmount}");
|
||||
_audioSystem.PlayGlobal("/Audio/Misc/adminlarm.ogg",
|
||||
Filter.Empty().AddPlayers(_adminManager.ActiveAdmins), false, AudioParams.Default.WithVolume(-8f));
|
||||
controller.EffectCooldown = _gameTiming.CurTime + controller.CooldownDuration;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void AdjustInjectionAmount(EntityUid uid, int delta, EntityUid? user = null, AmeControllerComponent? controller = null)
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Content.Server.Announcements;
|
||||
/// <summary>
|
||||
/// Used for any announcements on the start of a round.
|
||||
/// </summary>
|
||||
[Prototype]
|
||||
[Prototype("roundAnnouncement")]
|
||||
public sealed partial class RoundAnnouncementPrototype : IPrototype
|
||||
{
|
||||
[IdDataField]
|
||||
|
||||
@@ -116,7 +116,7 @@ public sealed class InnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
|
||||
|
||||
_popup.PopupEntity(message, ent, ent, PopupType.MediumCaution);
|
||||
|
||||
_adminLog.Add(LogType.Anomaly,LogImpact.Medium,$"{ToPrettyString(ent)} became anomaly host.");
|
||||
_adminLog.Add(LogType.Anomaly,LogImpact.Extreme,$"{ToPrettyString(ent)} became anomaly host.");
|
||||
}
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Content.Server.Antag.Components;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Content.Server.GameTicking.Rules;
|
||||
|
||||
namespace Content.Server.Antag;
|
||||
@@ -15,20 +14,9 @@ public sealed class AntagRandomSpawnSystem : GameRuleSystem<AntagRandomSpawnComp
|
||||
SubscribeLocalEvent<AntagRandomSpawnComponent, AntagSelectLocationEvent>(OnSelectLocation);
|
||||
}
|
||||
|
||||
protected override void Added(EntityUid uid, AntagRandomSpawnComponent comp, GameRuleComponent gameRule, GameRuleAddedEvent args)
|
||||
{
|
||||
base.Added(uid, comp, gameRule, args);
|
||||
|
||||
// we have to select this here because AntagSelectLocationEvent is raised twice because MakeAntag is called twice
|
||||
// once when a ghost role spawner is created and once when someone takes the ghost role
|
||||
|
||||
if (TryFindRandomTile(out _, out _, out _, out var coords))
|
||||
comp.Coords = coords;
|
||||
}
|
||||
|
||||
private void OnSelectLocation(Entity<AntagRandomSpawnComponent> ent, ref AntagSelectLocationEvent args)
|
||||
{
|
||||
if (ent.Comp.Coords != null)
|
||||
args.Coordinates.Add(_transform.ToMapCoordinates(ent.Comp.Coords.Value));
|
||||
if (TryFindRandomTile(out _, out _, out _, out var coords))
|
||||
args.Coordinates.Add(_transform.ToMapCoordinates(coords));
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user