Compare commits

..

3 Commits

Author SHA1 Message Date
Ed
c4d2478d89 cut out old zlevel system 2024-10-07 13:55:47 +03:00
Ed
52d8e8b00f brute zlevel reloading 2024-10-07 00:07:47 +03:00
Ed
5475758e65 start random zlevel 2024-10-06 22:49:30 +03:00
3066 changed files with 195592 additions and 206637 deletions

2
.github/CODEOWNERS vendored
View File

@@ -19,7 +19,7 @@
/Resources/engineCommandPerms.yml @moonheart08 @Chief-Engineer
/Resources/clientCommandPerms.yml @moonheart08 @Chief-Engineer
/Resources/Prototypes/Maps/** @Emisse
/Resources/Prototypes/Maps/ @Emisse
/Resources/Prototypes/Body/ @DrSmugleaf # suffering
/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf

2
.github/labeler.yml vendored
View File

@@ -16,7 +16,7 @@
- changed-files:
- any-glob-to-any-file: '**/*.swsl'
"Changes: No C#":
"No C#":
- changed-files:
# Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label.
- all-globs-to-all-files: "!**/*.cs"

View File

@@ -16,6 +16,6 @@ jobs:
- name: Check for Merge Conflicts
uses: eps1lon/actions-label-merge-conflict@v3.0.0
with:
dirtyLabel: "S: Merge Conflict"
dirtyLabel: "Merge Conflict"
repoToken: "${{ secrets.GITHUB_TOKEN }}"
commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request."

View File

@@ -10,7 +10,7 @@ jobs:
steps:
- uses: actions-ecosystem/action-add-labels@v1
with:
labels: "S: Needs Review"
labels: "Status: Needs Review"
- uses: actions-ecosystem/action-remove-labels@v1
with:
labels: "S: Awaiting Changes"
labels: "Status: Awaiting Changes"

View File

@@ -1,23 +0,0 @@
name: "Labels: Approved"
on:
pull_request_review:
types: [submitted]
jobs:
add_label:
# Change the repository name after you've made sure the team name is correct for your fork!
if: ${{ (github.repository == 'space-wizards/space-station-14') && (github.event.review.state == 'APPROVED') }}
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: tspascoal/get-user-teams-membership@v3
id: checkUserMember
with:
username: ${{ github.actor }}
team: "content-maintainers,junior-maintainers"
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
- if: ${{ steps.checkUserMember.outputs.isTeamMember == 'true' }}
uses: actions-ecosystem/action-add-labels@v1
with:
labels: "S: Approved"

View File

@@ -1,20 +0,0 @@
name: "Labels: Size"
on: pull_request_target
jobs:
size-label:
runs-on: ubuntu-latest
steps:
- name: size-label
uses: "pascalgn/size-label-action@v0.5.5"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
with:
# Custom size configuration
sizes: >
{
"0": "XS",
"10": "S",
"30": "M",
"100": "L",
"1000": "XL"
}

View File

@@ -1,16 +0,0 @@
name: "Labels: Branch stable"
on:
pull_request_target:
types:
- opened
branches:
- 'stable'
jobs:
add_label:
runs-on: ubuntu-latest
steps:
- uses: actions-ecosystem/action-add-labels@v1
with:
labels: "Branch: Stable"

View File

@@ -1,16 +0,0 @@
name: "Labels: Branch staging"
on:
pull_request_target:
types:
- opened
branches:
- 'staging'
jobs:
add_label:
runs-on: ubuntu-latest
steps:
- uses: actions-ecosystem/action-add-labels@v1
with:
labels: "Branch: Staging"

View File

@@ -3,8 +3,6 @@
on:
issues:
types: [opened]
pull_request_target:
types: [opened]
jobs:
add_label:
@@ -13,4 +11,4 @@ jobs:
- uses: actions-ecosystem/action-add-labels@v1
if: join(github.event.issue.labels) == ''
with:
labels: "S: Untriaged"
labels: "Status: Untriaged"

View File

@@ -5,8 +5,8 @@ concurrency:
on:
workflow_dispatch:
# schedule:
# - cron: '0 10 * * *'
schedule:
- cron: '0 10 * * *'
jobs:
build:

View File

@@ -22,11 +22,11 @@ namespace Content.Client.Administration.UI.BanPanel;
[GenerateTypedNameReferences]
public sealed partial class BanPanel : DefaultWindow
{
public event Action<string?, (IPAddress, int)?, bool, ImmutableTypedHwid?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted;
public event Action<string?, (IPAddress, int)?, bool, byte[]?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted;
public event Action<string>? PlayerChanged;
private string? PlayerUsername { get; set; }
private (IPAddress, int)? IpAddress { get; set; }
private ImmutableTypedHwid? Hwid { get; set; }
private byte[]? Hwid { get; set; }
private double TimeEntered { get; set; }
private uint Multiplier { get; set; }
private bool HasBanFlag { get; set; }
@@ -371,8 +371,9 @@ public sealed partial class BanPanel : DefaultWindow
private void OnHwidChanged()
{
var hwidString = HwidLine.Text;
ImmutableTypedHwid? hwid = null;
if (HwidCheckbox.Pressed && !(string.IsNullOrEmpty(hwidString) && LastConnCheckbox.Pressed) && !ImmutableTypedHwid.TryParse(hwidString, out hwid))
var length = 3 * (hwidString.Length / 4) - hwidString.TakeLast(2).Count(c => c == '=');
Hwid = new byte[length];
if (HwidCheckbox.Pressed && !(string.IsNullOrEmpty(hwidString) && LastConnCheckbox.Pressed) && !Convert.TryFromBase64String(hwidString, Hwid, out _))
{
ErrorLevel |= ErrorLevelEnum.Hwid;
HwidLine.ModulateSelfOverride = Color.Red;
@@ -389,7 +390,7 @@ public sealed partial class BanPanel : DefaultWindow
Hwid = null;
return;
}
Hwid = hwid;
Hwid = Convert.FromHexString(hwidString);
}
private void OnTypeChanged()

View File

@@ -8,7 +8,6 @@
<Label Name="ExpiryLabel" Text="{Loc admin-note-editor-expiry-label}" Visible="False" />
<HistoryLineEdit Name="ExpiryLineEdit" PlaceHolder="{Loc admin-note-editor-expiry-placeholder}"
Visible="False" HorizontalExpand="True" />
<OptionButton Name="ExpiryLengthDropdown" Visible="False" />
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<OptionButton Name="TypeOption" HorizontalAlignment="Center" />

View File

@@ -17,17 +17,6 @@ public sealed partial class NoteEdit : FancyWindow
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IClientConsoleHost _console = default!;
private enum Multipliers
{
Minutes,
Hours,
Days,
Weeks,
Months,
Years,
Centuries
}
public event Action<int, NoteType, string, NoteSeverity?, bool, DateTime?>? SubmitPressed;
public NoteEdit(SharedAdminNote? note, string playerName, bool canCreate, bool canEdit)
@@ -42,20 +31,6 @@ public sealed partial class NoteEdit : FancyWindow
ResetSubmitButton();
// It's weird to use minutes as the IDs, but it works and makes sense kind of :)
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-minutes"), (int) Multipliers.Minutes);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-hours"), (int) Multipliers.Hours);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-days"), (int) Multipliers.Days);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-weeks"), (int) Multipliers.Weeks);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-months"), (int) Multipliers.Months);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-years"), (int) Multipliers.Years);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-centuries"), (int) Multipliers.Centuries);
ExpiryLengthDropdown.OnItemSelected += OnLengthChanged;
ExpiryLengthDropdown.SelectId((int) Multipliers.Weeks);
ExpiryLineEdit.OnTextChanged += OnTextChanged;
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-note"), (int) NoteType.Note);
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-message"), (int) NoteType.Message);
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-watchlist"), (int) NoteType.Watchlist);
@@ -197,9 +172,8 @@ public sealed partial class NoteEdit : FancyWindow
{
ExpiryLabel.Visible = !PermanentCheckBox.Pressed;
ExpiryLineEdit.Visible = !PermanentCheckBox.Pressed;
ExpiryLengthDropdown.Visible = !PermanentCheckBox.Pressed;
ExpiryLineEdit.Text = !PermanentCheckBox.Pressed ? 1.ToString() : string.Empty;
ExpiryLineEdit.Text = !PermanentCheckBox.Pressed ? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") : string.Empty;
}
private void OnSecretPressed(BaseButton.ButtonEventArgs _)
@@ -213,16 +187,6 @@ public sealed partial class NoteEdit : FancyWindow
SeverityOption.SelectId(args.Id);
}
private void OnLengthChanged(OptionButton.ItemSelectedEventArgs args)
{
ExpiryLengthDropdown.SelectId(args.Id);
}
private void OnTextChanged(HistoryLineEdit.LineEditEventArgs args)
{
ParseExpiryTime();
}
private void OnSubmitButtonPressed(BaseButton.ButtonEventArgs args)
{
if (!ParseExpiryTime())
@@ -299,24 +263,13 @@ public sealed partial class NoteEdit : FancyWindow
return true;
}
if (string.IsNullOrWhiteSpace(ExpiryLineEdit.Text) || !uint.TryParse(ExpiryLineEdit.Text, out var inputInt))
if (string.IsNullOrWhiteSpace(ExpiryLineEdit.Text) || !DateTime.TryParse(ExpiryLineEdit.Text, out var result) || DateTime.UtcNow > result)
{
ExpiryLineEdit.ModulateSelfOverride = Color.Red;
return false;
}
var mult = ExpiryLengthDropdown.SelectedId switch
{
(int) Multipliers.Minutes => TimeSpan.FromMinutes(1).TotalMinutes,
(int) Multipliers.Hours => TimeSpan.FromHours(1).TotalMinutes,
(int) Multipliers.Days => TimeSpan.FromDays(1).TotalMinutes,
(int) Multipliers.Weeks => TimeSpan.FromDays(7).TotalMinutes,
(int) Multipliers.Months => TimeSpan.FromDays(30).TotalMinutes,
(int) Multipliers.Years => TimeSpan.FromDays(365).TotalMinutes,
(int) Multipliers.Centuries => TimeSpan.FromDays(36525).TotalMinutes,
_ => throw new ArgumentOutOfRangeException(nameof(ExpiryLengthDropdown.SelectedId), "Multiplier out of range :(")
};
ExpiryTime = DateTime.UtcNow.AddMinutes(inputInt * mult);
ExpiryTime = result.ToUniversalTime();
ExpiryLineEdit.ModulateSelfOverride = null;
return true;
}

View File

@@ -2,7 +2,6 @@ using System.Linq;
using Content.Shared.Alert;
using JetBrains.Annotations;
using Robust.Client.Player;
using Robust.Shared.GameStates;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
@@ -25,7 +24,8 @@ public sealed class ClientAlertsSystem : AlertsSystem
SubscribeLocalEvent<AlertsComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<AlertsComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
SubscribeLocalEvent<AlertsComponent, ComponentHandleState>(OnHandleState);
SubscribeLocalEvent<AlertsComponent, AfterAutoHandleStateEvent>(ClientAlertsHandleState);
}
protected override void LoadPrototypes()
{
@@ -47,16 +47,6 @@ public sealed class ClientAlertsSystem : AlertsSystem
}
}
private void OnHandleState(Entity<AlertsComponent> alerts, ref ComponentHandleState args)
{
if (args.Current is not AlertComponentState cast)
return;
alerts.Comp.Alerts = cast.Alerts;
UpdateHud(alerts);
}
protected override void AfterShowAlert(Entity<AlertsComponent> alerts)
{
UpdateHud(alerts);
@@ -67,6 +57,11 @@ public sealed class ClientAlertsSystem : AlertsSystem
UpdateHud(alerts);
}
private void ClientAlertsHandleState(Entity<AlertsComponent> alerts, ref AfterAutoHandleStateEvent args)
{
UpdateHud(alerts);
}
private void UpdateHud(Entity<AlertsComponent> entity)
{
if (_playerManager.LocalEntity == entity.Owner)

View File

@@ -23,7 +23,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
{
private readonly IEntityManager _entManager;
private readonly SpriteSystem _spriteSystem;
private readonly SharedNavMapSystem _navMapSystem;
private EntityUid? _owner;
private NetEntity? _trackedEntity;
@@ -43,32 +42,19 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
private const float SilencingDuration = 2.5f;
// Colors
private Color _wallColor = new Color(64, 64, 64);
private Color _tileColor = new Color(28, 28, 28);
private Color _monitorBlipColor = Color.Cyan;
private Color _untrackedEntColor = Color.DimGray;
private Color _regionBaseColor = new Color(154, 154, 154);
private Color _inactiveColor = StyleNano.DisabledFore;
private Color _statusTextColor = StyleNano.GoodGreenFore;
private Color _goodColor = Color.LimeGreen;
private Color _warningColor = new Color(255, 182, 72);
private Color _dangerColor = new Color(255, 67, 67);
public AtmosAlertsComputerWindow(AtmosAlertsComputerBoundUserInterface userInterface, EntityUid? owner)
{
RobustXamlLoader.Load(this);
_entManager = IoCManager.Resolve<IEntityManager>();
_spriteSystem = _entManager.System<SpriteSystem>();
_navMapSystem = _entManager.System<SharedNavMapSystem>();
// Pass the owner to nav map
_owner = owner;
NavMap.Owner = _owner;
// Set nav map colors
NavMap.WallColor = _wallColor;
NavMap.TileColor = _tileColor;
NavMap.WallColor = new Color(64, 64, 64);
NavMap.TileColor = Color.DimGray * NavMap.WallColor;
// Set nav map grid uid
var stationName = Loc.GetString("atmos-alerts-window-unknown-location");
@@ -193,9 +179,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
// Add tracked entities to the nav map
foreach (var device in console.AtmosDevices)
{
if (!device.NetEntity.Valid)
continue;
if (!NavMap.Visible)
continue;
@@ -226,7 +209,7 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
if (consoleCoords != null && consoleUid != null)
{
var texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")));
var blip = new NavMapBlip(consoleCoords.Value, texture, _monitorBlipColor, true, false);
var blip = new NavMapBlip(consoleCoords.Value, texture, Color.Cyan, true, false);
NavMap.TrackedEntities[consoleUid.Value] = blip;
}
@@ -275,7 +258,7 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
VerticalAlignment = VAlignment.Center,
};
label.SetMarkup(Loc.GetString("atmos-alerts-window-no-active-alerts", ("color", _statusTextColor.ToHexNoAlpha())));
label.SetMarkup(Loc.GetString("atmos-alerts-window-no-active-alerts", ("color", StyleNano.GoodGreenFore.ToHexNoAlpha())));
AlertsTable.AddChild(label);
}
@@ -287,34 +270,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
else
MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-alerts-window-tab-alerts", ("value", activeAlarmCount)));
// Update sensor regions
NavMap.RegionOverlays.Clear();
var prioritizedRegionOverlays = new Dictionary<NavMapRegionOverlay, int>();
if (_owner != null &&
_entManager.TryGetComponent<TransformComponent>(_owner, out var xform) &&
_entManager.TryGetComponent<NavMapComponent>(xform.GridUid, out var navMap))
{
var regionOverlays = _navMapSystem.GetNavMapRegionOverlays(_owner.Value, navMap, AtmosAlertsComputerUiKey.Key);
foreach (var (regionOwner, regionOverlay) in regionOverlays)
{
var alarmState = GetAlarmState(regionOwner);
if (!TryGetSensorRegionColor(regionOwner, alarmState, out var regionColor))
continue;
regionOverlay.Color = regionColor;
var priority = (_trackedEntity == regionOwner) ? 999 : (int)alarmState;
prioritizedRegionOverlays.Add(regionOverlay, priority);
}
// Sort overlays according to their priority
var sortedOverlays = prioritizedRegionOverlays.OrderBy(x => x.Value).Select(x => x.Key).ToList();
NavMap.RegionOverlays = sortedOverlays;
}
// Auto-scroll re-enable
if (_autoScrollAwaitsUpdate)
{
@@ -335,7 +290,7 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
var coords = _entManager.GetCoordinates(metaData.NetCoordinates);
if (_trackedEntity != null && _trackedEntity != metaData.NetEntity)
color *= _untrackedEntColor;
color *= Color.DimGray;
var selectable = true;
var blip = new NavMapBlip(coords, _spriteSystem.Frame0(texture), color, _trackedEntity == metaData.NetEntity, selectable);
@@ -343,24 +298,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
NavMap.TrackedEntities[metaData.NetEntity] = blip;
}
private bool TryGetSensorRegionColor(NetEntity regionOwner, AtmosAlarmType alarmState, out Color color)
{
color = Color.White;
var blip = GetBlipTexture(alarmState);
if (blip == null)
return false;
// Color the region based on alarm state and entity tracking
color = blip.Value.Item2 * _regionBaseColor;
if (_trackedEntity != null && _trackedEntity != regionOwner)
color *= _untrackedEntColor;
return true;
}
private void UpdateUIEntry(AtmosAlertsComputerEntry entry, int index, Control table, AtmosAlertsComputerComponent console, AtmosAlertsFocusDeviceData? focusData = null)
{
// Make new UI entry if required
@@ -597,13 +534,13 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
switch (alarmState)
{
case AtmosAlarmType.Invalid:
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), _inactiveColor); break;
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), StyleNano.DisabledFore); break;
case AtmosAlarmType.Normal:
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), _goodColor); break;
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), Color.LimeGreen); break;
case AtmosAlarmType.Warning:
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), _warningColor); break;
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), new Color(255, 182, 72)); break;
case AtmosAlarmType.Danger:
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_square.png")), _dangerColor); break;
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_square.png")), new Color(255, 67, 67)); break;
}
return output;

View File

@@ -43,8 +43,6 @@ public sealed partial class ContentAudioSystem
private void CP14UpdateAmbientLoops()
{
return; //DISABLED UNTIL CLIENT ERROR SPAM FIXED
if (_timing.CurTime <= _nextUpdateTime)
return;

View File

@@ -65,7 +65,6 @@ public sealed class ClientClothingSystem : ClothingSystem
base.Initialize();
SubscribeLocalEvent<ClothingComponent, GetEquipmentVisualsEvent>(OnGetVisuals);
SubscribeLocalEvent<ClothingComponent, InventoryTemplateUpdated>(OnInventoryTemplateUpdated);
SubscribeLocalEvent<InventoryComponent, VisualsChangedEvent>(OnVisualsChanged);
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
@@ -78,7 +77,11 @@ public sealed class ClientClothingSystem : ClothingSystem
if (args.Sprite == null)
return;
UpdateAllSlots(uid, component);
var enumerator = _inventorySystem.GetSlotEnumerator((uid, component));
while (enumerator.NextItem(out var item, out var slot))
{
RenderEquipment(uid, item, slot.Name, component);
}
// No clothing equipped -> make sure the layer is hidden, though this should already be handled by on-unequip.
if (args.Sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var layer))
@@ -88,23 +91,6 @@ public sealed class ClientClothingSystem : ClothingSystem
}
}
private void OnInventoryTemplateUpdated(Entity<ClothingComponent> ent, ref InventoryTemplateUpdated args)
{
UpdateAllSlots(ent.Owner, clothing: ent.Comp);
}
private void UpdateAllSlots(
EntityUid uid,
InventoryComponent? inventoryComponent = null,
ClothingComponent? clothing = null)
{
var enumerator = _inventorySystem.GetSlotEnumerator((uid, inventoryComponent));
while (enumerator.NextItem(out var item, out var slot))
{
RenderEquipment(uid, item, slot.Name, inventoryComponent, clothingComponent: clothing);
}
}
private void OnGetVisuals(EntityUid uid, ClothingComponent item, GetEquipmentVisualsEvent args)
{
if (!TryComp(args.Equipee, out InventoryComponent? inventory))

View File

@@ -1,8 +1,6 @@
using Content.Shared.Damage.Prototypes;
using Content.Shared.Overlays;
using Robust.Client.Player;
using Robust.Shared.Console;
using Robust.Shared.Prototypes;
using System.Linq;
namespace Content.Client.Commands;
@@ -36,7 +34,7 @@ public sealed class ShowHealthBarsCommand : LocalizedCommands
{
var showHealthBarsComponent = new ShowHealthBarsComponent
{
DamageContainers = args.Select(arg => new ProtoId<DamageContainerPrototype>(arg)).ToList(),
DamageContainers = args.ToList(),
HealthStatusIcon = null,
NetSyncEnabled = false
};

View File

@@ -1,20 +1,15 @@
<DefaultWindow xmlns="https://spacestation14.io">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Vertical" MinWidth="243" Margin="0 0 5 0">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.4" Margin="0 0 5 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 0 0 5">
<LineEdit Name="SearchBar" PlaceHolder="Search" HorizontalExpand="True"/>
<OptionButton Name="OptionCategories" Access="Public" MinSize="130 0"/>
</BoxContainer>
<ItemList Name="Recipes" Access="Public" SelectMode="Single" VerticalExpand="True"/>
<ScrollContainer Name="RecipesGridScrollContainer" VerticalExpand="True" Access="Public" Visible="False">
<GridContainer Name="RecipesGrid" Columns="5" Access="Public"/>
</ScrollContainer>
</BoxContainer>
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<BoxContainer Orientation="Horizontal">
<Button Name="MenuGridViewButton" ToggleMode="True" Text="{Loc construction-menu-grid-view}"/>
<Button Name="FavoriteButton" Visible="false"/>
</BoxContainer>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.6">
<Button Name="FavoriteButton" Visible="false" HorizontalExpand="False"
HorizontalAlignment="Right" Margin="0 0 0 15"/>
<Control>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="0 0 0 5">
<BoxContainer Orientation="Horizontal" Align="Center">

View File

@@ -25,16 +25,11 @@ namespace Content.Client.Construction.UI
OptionButton OptionCategories { get; }
bool EraseButtonPressed { get; set; }
bool GridViewButtonPressed { get; set; }
bool BuildButtonPressed { get; set; }
ItemList Recipes { get; }
ItemList RecipeStepList { get; }
ScrollContainer RecipesGridScrollContainer { get; }
GridContainer RecipesGrid { get; }
event EventHandler<(string search, string catagory)> PopulateRecipes;
event EventHandler<ItemList.Item?> RecipeSelected;
event EventHandler RecipeFavorited;
@@ -77,16 +72,9 @@ namespace Content.Client.Construction.UI
set => EraseButton.Pressed = value;
}
public bool GridViewButtonPressed
{
get => MenuGridViewButton.Pressed;
set => MenuGridViewButton.Pressed = value;
}
public ConstructionMenu()
{
SetSize = new Vector2(560, 450);
MinSize = new Vector2(560, 320);
SetSize = MinSize = new Vector2(720, 320);
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
@@ -114,9 +102,6 @@ namespace Content.Client.Construction.UI
EraseButton.OnToggled += args => EraseButtonToggled?.Invoke(this, args.Pressed);
FavoriteButton.OnPressed += args => RecipeFavorited?.Invoke(this, EventArgs.Empty);
MenuGridViewButton.OnPressed += _ =>
PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[OptionCategories.SelectedId]));
}
public event EventHandler? ClearAllGhosts;

View File

@@ -1,8 +1,7 @@
using System.Linq;
using System.Numerics;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Systems.MenuBar.Widgets;
using Content.Shared.Construction.Prototypes;
using Content.Shared.Tag;
using Content.Shared.Whitelist;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
@@ -12,6 +11,7 @@ using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
using Robust.Shared.Enums;
using Robust.Shared.Graphics;
using Robust.Shared.Prototypes;
using static Robust.Client.UserInterface.Controls.BaseButton;
@@ -33,12 +33,10 @@ namespace Content.Client.Construction.UI
private readonly IConstructionMenuView _constructionView;
private readonly EntityWhitelistSystem _whitelistSystem;
private readonly SpriteSystem _spriteSystem;
private ConstructionSystem? _constructionSystem;
private ConstructionPrototype? _selected;
private List<ConstructionPrototype> _favoritedRecipes = [];
private Dictionary<string, TextureButton> _recipeButtons = new();
private string _selectedCategory = string.Empty;
private string _favoriteCatName = "construction-category-favorites";
private string _forAllCategoryName = "construction-category-all";
@@ -87,7 +85,6 @@ namespace Content.Client.Construction.UI
IoCManager.InjectDependencies(this);
_constructionView = new ConstructionMenu();
_whitelistSystem = _entManager.System<EntityWhitelistSystem>();
_spriteSystem = _entManager.System<SpriteSystem>();
// This is required so that if we load after the system is initialized, we can bind to it immediately
if (_systemManager.TryGetEntitySystem<ConstructionSystem>(out var constructionSystem))
@@ -153,24 +150,12 @@ namespace Content.Client.Construction.UI
PopulateInfo(_selected);
}
private void OnGridViewRecipeSelected(object? sender, ConstructionPrototype? recipe)
{
if (recipe is null)
{
_selected = null;
_constructionView.ClearRecipeInfo();
return;
}
_selected = recipe;
if (_placementManager.IsActive && !_placementManager.Eraser) UpdateGhostPlacement();
PopulateInfo(_selected);
}
private void OnViewPopulateRecipes(object? sender, (string search, string catagory) args)
{
var (search, category) = args;
var recipesList = _constructionView.Recipes;
recipesList.Clear();
var recipes = new List<ConstructionPrototype>();
var isEmptyCategory = string.IsNullOrEmpty(category) || category == _forAllCategoryName;
@@ -185,7 +170,7 @@ namespace Content.Client.Construction.UI
if (recipe.Hide)
continue;
if (!recipe.CrystallPunkAllowed) //CrystallEdge clearing recipes
if (!recipe.CrystallPunkAllowed) //CrystallPunk clearing recipes
continue;
if (_playerManager.LocalSession == null
@@ -219,73 +204,12 @@ namespace Content.Client.Construction.UI
recipes.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.InvariantCulture));
var recipesList = _constructionView.Recipes;
recipesList.Clear();
var recipesGrid = _constructionView.RecipesGrid;
recipesGrid.RemoveAllChildren();
_constructionView.RecipesGridScrollContainer.Visible = _constructionView.GridViewButtonPressed;
_constructionView.Recipes.Visible = !_constructionView.GridViewButtonPressed;
if (_constructionView.GridViewButtonPressed)
foreach (var recipe in recipes)
{
foreach (var recipe in recipes)
{
var itemButton = new TextureButton
{
TextureNormal = _spriteSystem.Frame0(recipe.Icon),
VerticalAlignment = Control.VAlignment.Center,
Name = recipe.Name,
ToolTip = recipe.Name,
Scale = new Vector2(1.35f),
ToggleMode = true,
};
var itemButtonPanelContainer = new PanelContainer
{
PanelOverride = new StyleBoxFlat { BackgroundColor = StyleNano.ButtonColorDefault },
Children = { itemButton },
};
itemButton.OnToggled += buttonToggledEventArgs =>
{
SelectGridButton(itemButton, buttonToggledEventArgs.Pressed);
if (buttonToggledEventArgs.Pressed &&
_selected != null &&
_recipeButtons.TryGetValue(_selected.Name, out var oldButton))
{
oldButton.Pressed = false;
SelectGridButton(oldButton, false);
}
OnGridViewRecipeSelected(this, buttonToggledEventArgs.Pressed ? recipe : null);
};
recipesGrid.AddChild(itemButtonPanelContainer);
_recipeButtons[recipe.Name] = itemButton;
var isCurrentButtonSelected = _selected == recipe;
itemButton.Pressed = isCurrentButtonSelected;
SelectGridButton(itemButton, isCurrentButtonSelected);
}
recipesList.Add(GetItem(recipe, recipesList));
}
else
{
foreach (var recipe in recipes)
{
recipesList.Add(GetItem(recipe, recipesList));
}
}
}
private void SelectGridButton(TextureButton button, bool select)
{
if (button.Parent is not PanelContainer buttonPanel)
return;
button.Modulate = select ? Color.Green : Color.White;
var buttonColor = select ? StyleNano.ButtonColorDefault : Color.Transparent;
buttonPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = buttonColor };
// There is apparently no way to set which
}
private void PopulateCategories(string? selectCategory = null)
@@ -336,10 +260,11 @@ namespace Content.Client.Construction.UI
private void PopulateInfo(ConstructionPrototype prototype)
{
var spriteSys = _systemManager.GetEntitySystem<SpriteSystem>();
_constructionView.ClearRecipeInfo();
_constructionView.SetRecipeInfo(
prototype.Name, prototype.Description, _spriteSystem.Frame0(prototype.Icon),
prototype.Name, prototype.Description, spriteSys.Frame0(prototype.Icon),
prototype.Type != ConstructionType.Item,
!_favoritedRecipes.Contains(prototype));
@@ -352,6 +277,7 @@ namespace Content.Client.Construction.UI
if (_constructionSystem?.GetGuide(prototype) is not { } guide)
return;
var spriteSys = _systemManager.GetEntitySystem<SpriteSystem>();
foreach (var entry in guide.Entries)
{
@@ -367,20 +293,20 @@ namespace Content.Client.Construction.UI
// The padding needs to be applied regardless of text length... (See PadLeft documentation)
text = text.PadLeft(text.Length + entry.Padding);
var icon = entry.Icon != null ? _spriteSystem.Frame0(entry.Icon) : Texture.Transparent;
var icon = entry.Icon != null ? spriteSys.Frame0(entry.Icon) : Texture.Transparent;
stepList.AddItem(text, icon, false);
}
}
private ItemList.Item GetItem(ConstructionPrototype recipe, ItemList itemList)
private static ItemList.Item GetItem(ConstructionPrototype recipe, ItemList itemList)
{
return new(itemList)
{
Metadata = recipe,
Text = recipe.Name,
Icon = _spriteSystem.Frame0(recipe.Icon),
Icon = recipe.Icon.Frame0(),
TooltipEnabled = true,
TooltipText = recipe.Description,
TooltipText = recipe.Description
};
}

View File

@@ -31,7 +31,7 @@ namespace Content.Client.Crayon.UI
private void PopulateCrayons()
{
var crayonDecals = _protoManager.EnumeratePrototypes<DecalPrototype>().Where(x => x.Tags.Contains("crayon"));
_menu?.Populate(crayonDecals.ToList());
_menu?.Populate(crayonDecals);
}
public override void OnProtoReload(PrototypesReloadedEventArgs args)
@@ -44,16 +44,6 @@ namespace Content.Client.Crayon.UI
PopulateCrayons();
}
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
{
base.ReceiveMessage(message);
if (_menu is null || message is not CrayonUsedMessage crayonMessage)
return;
_menu.AdvanceState(crayonMessage.DrawnDecal);
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);

View File

@@ -1,13 +1,14 @@
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc 'crayon-window-title'}"
MinSize="450 500"
SetSize="450 500">
MinSize="250 300"
SetSize="250 300">
<BoxContainer Orientation="Vertical">
<ColorSelectorSliders Name="ColorSelector" Visible="False" />
<LineEdit Name="Search" Margin="0 0 0 8" PlaceHolder="{Loc 'crayon-window-placeholder'}" />
<LineEdit Name="Search" />
<ScrollContainer VerticalExpand="True">
<BoxContainer Name="Grids" Orientation="Vertical">
</BoxContainer>
<GridContainer Name="Grid" Columns="6">
<!-- Crayon decals get added here by code -->
</GridContainer>
</ScrollContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -1,10 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using Content.Client.Stylesheets;
using Content.Shared.Crayon;
using Content.Shared.Decals;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
@@ -20,12 +18,7 @@ namespace Content.Client.Crayon.UI
[GenerateTypedNameReferences]
public sealed partial class CrayonWindow : DefaultWindow
{
[Dependency] private readonly IEntitySystemManager _entitySystem = default!;
private readonly SpriteSystem _spriteSystem = default!;
private Dictionary<string, List<(string Name, Texture Texture)>>? _decals;
private List<string>? _allDecals;
private string? _autoSelected;
private Dictionary<string, Texture>? _decals;
private string? _selected;
private Color _color;
@@ -35,10 +28,8 @@ namespace Content.Client.Crayon.UI
public CrayonWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_spriteSystem = _entitySystem.GetEntitySystem<SpriteSystem>();
Search.OnTextChanged += SearchChanged;
Search.OnTextChanged += _ => RefreshList();
ColorSelector.OnColorChanged += SelectColor;
}
@@ -53,94 +44,51 @@ namespace Content.Client.Crayon.UI
private void RefreshList()
{
// Clear
Grids.DisposeAllChildren();
if (_decals == null || _allDecals == null)
Grid.DisposeAllChildren();
if (_decals == null)
return;
var filter = Search.Text;
var comma = filter.IndexOf(',');
var first = (comma == -1 ? filter : filter[..comma]).Trim();
var names = _decals.Keys.ToList();
names.Sort((a, b) => a == "random" ? 1 : b == "random" ? -1 : a.CompareTo(b));
if (_autoSelected != null && first != _autoSelected && _allDecals.Contains(first))
foreach (var (decal, tex) in _decals)
{
_selected = first;
_autoSelected = _selected;
OnSelected?.Invoke(_selected);
}
foreach (var categoryName in names)
{
var locName = Loc.GetString("crayon-category-" + categoryName);
var category = _decals[categoryName].Where(d => locName.Contains(first) || d.Name.Contains(first)).ToList();
if (category.Count == 0)
if (!decal.Contains(filter))
continue;
var label = new Label
var button = new TextureButton()
{
Text = locName
TextureNormal = tex,
Name = decal,
ToolTip = decal,
Modulate = _color,
};
var grid = new GridContainer
button.OnPressed += ButtonOnPressed;
if (_selected == decal)
{
Columns = 6,
Margin = new Thickness(0, 0, 0, 16)
};
Grids.AddChild(label);
Grids.AddChild(grid);
foreach (var (name, texture) in category)
{
var button = new TextureButton()
var panelContainer = new PanelContainer()
{
TextureNormal = texture,
Name = name,
ToolTip = name,
Modulate = _color,
Scale = new System.Numerics.Vector2(2, 2)
};
button.OnPressed += ButtonOnPressed;
if (_selected == name)
{
var panelContainer = new PanelContainer()
PanelOverride = new StyleBoxFlat()
{
PanelOverride = new StyleBoxFlat()
{
BackgroundColor = StyleNano.ButtonColorDefault,
},
Children =
{
button,
},
};
grid.AddChild(panelContainer);
}
else
{
grid.AddChild(button);
}
BackgroundColor = StyleNano.ButtonColorDefault,
},
Children =
{
button,
},
};
Grid.AddChild(panelContainer);
}
else
{
Grid.AddChild(button);
}
}
}
private void SearchChanged(LineEdit.LineEditEventArgs obj)
{
_autoSelected = ""; // Placeholder to kick off the auto-select in refreshlist()
RefreshList();
}
private void ButtonOnPressed(ButtonEventArgs obj)
{
if (obj.Button.Name == null) return;
_selected = obj.Button.Name;
_autoSelected = null;
OnSelected?.Invoke(_selected);
RefreshList();
}
@@ -159,38 +107,12 @@ namespace Content.Client.Crayon.UI
RefreshList();
}
public void AdvanceState(string drawnDecal)
public void Populate(IEnumerable<DecalPrototype> prototypes)
{
var filter = Search.Text;
if (!filter.Contains(',') || !filter.Contains(drawnDecal))
return;
var first = filter[..filter.IndexOf(',')].Trim();
if (first.Equals(drawnDecal, StringComparison.InvariantCultureIgnoreCase))
{
Search.Text = filter[(filter.IndexOf(',') + 1)..].Trim();
_autoSelected = first;
}
RefreshList();
}
public void Populate(List<DecalPrototype> prototypes)
{
_decals = [];
_allDecals = [];
prototypes.Sort((a, b) => a.ID.CompareTo(b.ID));
_decals = new Dictionary<string, Texture>();
foreach (var decalPrototype in prototypes)
{
var category = "random";
if (decalPrototype.Tags.Count > 1 && decalPrototype.Tags[1].StartsWith("crayon-"))
category = decalPrototype.Tags[1].Replace("crayon-", "");
var list = _decals.GetOrNew(category);
list.Add((decalPrototype.ID, _spriteSystem.Frame0(decalPrototype.Sprite)));
_allDecals.Add(decalPrototype.ID);
_decals.Add(decalPrototype.ID, decalPrototype.Sprite.Frame0());
}
RefreshList();

View File

@@ -124,10 +124,6 @@ public sealed class ColorFlashEffectSystem : SharedColorFlashEffectSystem
continue;
}
var targetEv = new GetFlashEffectTargetEvent(ent);
RaiseLocalEvent(ent, ref targetEv);
ent = targetEv.Target;
EnsureComp<ColorFlashEffectComponent>(ent, out comp);
comp.NetSyncEnabled = false;
comp.Color = sprite.Color;
@@ -136,9 +132,3 @@ public sealed class ColorFlashEffectSystem : SharedColorFlashEffectSystem
}
}
}
/// <summary>
/// Raised on an entity to change the target for a color flash effect.
/// </summary>
[ByRefEvent]
public record struct GetFlashEffectTargetEvent(EntityUid Target);

View File

@@ -4,7 +4,6 @@ using Content.Client.Chat.Managers;
using Content.Client.DebugMon;
using Content.Client.Eui;
using Content.Client.Fullscreen;
using Content.Client.GameTicking.Managers;
using Content.Client.GhostKick;
using Content.Client.Guidebook;
using Content.Client.Input;
@@ -72,7 +71,6 @@ namespace Content.Client.Entry
[Dependency] private readonly IReplayLoadManager _replayLoad = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly DebugMonitorManager _debugMonitorManager = default!;
[Dependency] private readonly TitleWindowManager _titleWindowManager = default!;
public override void Init()
{
@@ -142,12 +140,6 @@ namespace Content.Client.Entry
_configManager.SetCVar("interface.resolutionAutoScaleMinimum", 0.5f);
}
public override void Shutdown()
{
base.Shutdown();
_titleWindowManager.Shutdown();
}
public override void PostInit()
{
base.PostInit();
@@ -165,10 +157,9 @@ namespace Content.Client.Entry
_clientPreferencesManager.Initialize();
_euiManager.Initialize();
_voteManager.Initialize();
_userInterfaceManager.SetDefaultTheme("SS14DefaultTheme");
_userInterfaceManager.SetDefaultTheme(_configManager.GetCVar(CCVars.UIDefaultInterfaceTheme));
_userInterfaceManager.SetActiveTheme(_configManager.GetCVar(CVars.InterfaceTheme));
_documentParsingManager.Initialize();
_titleWindowManager.Initialize();
_baseClient.RunLevelChanged += (_, args) =>
{

View File

@@ -1,62 +0,0 @@
using Content.Shared.CCVar;
using Robust.Client;
using Robust.Client.Graphics;
using Robust.Shared;
using Robust.Shared.Configuration;
namespace Content.Client.GameTicking.Managers;
public sealed class TitleWindowManager
{
[Dependency] private readonly IBaseClient _client = default!;
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IGameController _gameController = default!;
public void Initialize()
{
_cfg.OnValueChanged(CVars.GameHostName, OnHostnameChange, true);
_cfg.OnValueChanged(CCVars.GameHostnameInTitlebar, OnHostnameTitleChange, true);
_client.RunLevelChanged += OnRunLevelChangedChange;
}
public void Shutdown()
{
_cfg.UnsubValueChanged(CVars.GameHostName, OnHostnameChange);
_cfg.UnsubValueChanged(CCVars.GameHostnameInTitlebar, OnHostnameTitleChange);
}
private void OnHostnameChange(string hostname)
{
var defaultWindowTitle = _gameController.GameTitle();
// Since the game assumes the server name is MyServer and that GameHostnameInTitlebar CCVar is true by default
// Lets just... not show anything. This also is used to revert back to just the game title on disconnect.
if (_client.RunLevel == ClientRunLevel.Initialize)
{
_clyde.SetWindowTitle(defaultWindowTitle);
return;
}
if (_cfg.GetCVar(CCVars.GameHostnameInTitlebar))
// If you really dislike the dash I guess change it here
_clyde.SetWindowTitle(hostname + " - " + defaultWindowTitle);
else
_clyde.SetWindowTitle(defaultWindowTitle);
}
// Clients by default assume game.hostname_in_titlebar is true
// but we need to clear it as soon as we join and actually receive the servers preference on this.
// This will ensure we rerun OnHostnameChange and set the correct title bar name.
private void OnHostnameTitleChange(bool colonthree)
{
OnHostnameChange(_cfg.GetCVar(CVars.GameHostName));
}
// This is just used we can rerun the hostname change function when we disconnect to revert back to just the games title.
private void OnRunLevelChangedChange(object? sender, RunLevelChangedEventArgs runLevelChangedEventArgs)
{
OnHostnameChange(_cfg.GetCVar(CVars.GameHostName));
}
}

View File

@@ -168,8 +168,8 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
var parent = forcedRoot == null ? null : AddEntry(forcedRoot.Value, null, addedEntries);
foreach (var entry in GetSortedEntries(roots))
{
if (!entry.CrystallPunkAllowed) continue; //CrystallEdge guidebook filter
if (entry.LocFilter is not null && entry.LocFilter != ContentLocalizationManager.Culture) continue; //CrystallEdge guidebook filter
if (!entry.CrystallPunkAllowed) continue; //CrystallPunk guidebook filter
if (entry.LocFilter is not null && entry.LocFilter != ContentLocalizationManager.Culture) continue; //CrystallPunk guidebook filter
AddEntry(entry.Id, parent, addedEntries);
}

View File

@@ -32,7 +32,7 @@ public sealed class GuidebookSystem : EntitySystem
[Dependency] private readonly RgbLightControllerSystem _rgbLightControllerSystem = default!;
[Dependency] private readonly SharedPointLightSystem _pointLightSystem = default!;
[Dependency] private readonly TagSystem _tags = default!;
[Dependency] private readonly IPrototypeManager _proto = default!; //CrystallEdge guidebook filter
[Dependency] private readonly IPrototypeManager _proto = default!; //CrystallPunk guidebook filter
public event Action<List<ProtoId<GuideEntryPrototype>>,
List<ProtoId<GuideEntryPrototype>>?,
@@ -47,7 +47,7 @@ public sealed class GuidebookSystem : EntitySystem
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<GuideHelpComponent, MapInitEvent>(OnCrystallEdgeMapInit); //CrystallEdge guidebook filter
SubscribeLocalEvent<GuideHelpComponent, MapInitEvent>(OnCrystallPunkMapInit); //CrystallPunk guidebook filter
SubscribeLocalEvent<GuideHelpComponent, GetVerbsEvent<ExamineVerb>>(OnGetVerbs);
SubscribeLocalEvent<GuideHelpComponent, ActivateInWorldEvent>(OnInteract);
@@ -57,12 +57,12 @@ public sealed class GuidebookSystem : EntitySystem
OnGuidebookControlsTestGetAlternateVerbs);
}
//CrystallEdge guidebook filter
private void OnCrystallEdgeMapInit(Entity<GuideHelpComponent> ent, ref MapInitEvent args)
//CrystallPunk guidebook filter
private void OnCrystallPunkMapInit(Entity<GuideHelpComponent> ent, ref MapInitEvent args)
{
foreach (var guide in ent.Comp.Guides)
{
var guideProto = _proto.Index(guide);
var guideProto = _proto.Index<GuideEntryPrototype>(guide);
if (!guideProto.CrystallPunkAllowed) //REMOVE unnecessary guidebook
{
RemComp<GuideHelpComponent>(ent);
@@ -70,7 +70,7 @@ public sealed class GuidebookSystem : EntitySystem
}
}
}
//CrystallEdge guidebook filter end
//CrystallPunk guidebook filter end
/// <summary>
/// Gets a user entity to use for verbs and examinations. If the player has no attached entity, this will use a

View File

@@ -130,9 +130,9 @@ namespace Content.Client.Hands.Systems
OnPlayerHandsAdded?.Invoke(hands);
}
public override void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, HandsComponent? hands = null, bool log = true)
public override void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, HandsComponent? hands = null)
{
base.DoDrop(uid, hand, doDropInteraction, hands, log);
base.DoDrop(uid, hand, doDropInteraction, hands);
if (TryComp(hand.HeldEntity, out SpriteComponent? sprite))
sprite.RenderOrder = EntityManager.CurrentTick.Value;

View File

@@ -34,7 +34,6 @@ namespace Content.Client.Info
AddInfoButton("server-info-website-button", CCVars.InfoLinksWebsite);
AddInfoButton("server-info-wiki-button", CCVars.InfoLinksWiki);
AddInfoButton("server-info-forum-button", CCVars.InfoLinksForum);
AddInfoButton("server-info-telegram-button", CCVars.InfoLinksTelegram);
var guidebookController = UserInterfaceManager.GetUIController<GuidebookUIController>();
var guidebookButton = new Button() { Text = Loc.GetString("server-info-guidebook-button") };

View File

@@ -1,4 +1,3 @@
using Content.Shared.Localizations;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
@@ -17,10 +16,19 @@ public sealed partial class PlaytimeStatsEntry : ContainerButton
RoleLabel.Text = role;
Playtime = playtime; // store the TimeSpan value directly
PlaytimeLabel.Text = ContentLocalizationManager.FormatPlaytime(playtime); // convert to string for display
PlaytimeLabel.Text = ConvertTimeSpanToHoursMinutes(playtime); // convert to string for display
BackgroundColorPanel.PanelOverride = styleBox;
}
private static string ConvertTimeSpanToHoursMinutes(TimeSpan timeSpan)
{
var hours = (int)timeSpan.TotalHours;
var minutes = timeSpan.Minutes;
var formattedTimeLoc = Loc.GetString("ui-playtime-time-format", ("hours", hours), ("minutes", minutes));
return formattedTimeLoc;
}
public void UpdateShading(StyleBoxFlat styleBox)
{
BackgroundColorPanel.PanelOverride = styleBox;

View File

@@ -104,7 +104,8 @@ public sealed partial class PlaytimeStatsWindow : FancyWindow
{
var overallPlaytime = _jobRequirementsManager.FetchOverallPlaytime();
OverallPlaytimeLabel.Text = Loc.GetString("ui-playtime-overall", ("time", overallPlaytime));
var formattedPlaytime = ConvertTimeSpanToHoursMinutes(overallPlaytime);
OverallPlaytimeLabel.Text = Loc.GetString("ui-playtime-overall", ("time", formattedPlaytime));
var rolePlaytimes = _jobRequirementsManager.FetchPlaytimeByRoles();
@@ -133,4 +134,13 @@ public sealed partial class PlaytimeStatsWindow : FancyWindow
_sawmill.Error($"The provided playtime string '{playtimeString}' is not in the correct format.");
}
}
private static string ConvertTimeSpanToHoursMinutes(TimeSpan timeSpan)
{
var hours = (int) timeSpan.TotalHours;
var minutes = timeSpan.Minutes;
var formattedTimeLoc = Loc.GetString("ui-playtime-time-format", ("hours", hours), ("minutes", minutes));
return formattedTimeLoc;
}
}

View File

@@ -235,23 +235,9 @@ namespace Content.Client.Inventory
EntityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true));
}
protected override void UpdateInventoryTemplate(Entity<InventoryComponent> ent)
{
base.UpdateInventoryTemplate(ent);
if (TryComp(ent, out InventorySlotsComponent? inventorySlots))
{
foreach (var slot in ent.Comp.Slots)
{
if (inventorySlots.SlotData.TryGetValue(slot.Name, out var slotData))
slotData.SlotDef = slot;
}
}
}
public sealed class SlotData
{
public SlotDefinition SlotDef;
public readonly SlotDefinition SlotDef;
public EntityUid? HeldEntity => Container?.ContainedEntity;
public bool Blocked;
public bool Highlighted;

View File

@@ -17,7 +17,6 @@ using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Strip.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
@@ -30,13 +29,10 @@ namespace Content.Client.Inventory
[UsedImplicitly]
public sealed class StrippableBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IUserInterfaceManager _ui = default!;
private readonly ExamineSystem _examine;
private readonly InventorySystem _inv;
private readonly SharedCuffableSystem _cuffable;
private readonly StrippableSystem _strippable;
[ViewVariables]
private const int ButtonSeparation = 4;
@@ -55,8 +51,6 @@ namespace Content.Client.Inventory
_examine = EntMan.System<ExamineSystem>();
_inv = EntMan.System<InventorySystem>();
_cuffable = EntMan.System<SharedCuffableSystem>();
_strippable = EntMan.System<StrippableSystem>();
_virtualHiddenEntity = EntMan.SpawnEntity(HiddenPocketEntityId, MapCoordinates.Nullspace);
}
@@ -204,8 +198,7 @@ namespace Content.Client.Inventory
var entity = container.ContainedEntity;
// If this is a full pocket, obscure the real entity
// this does not work for modified clients because they are still sent the real entity
if (entity != null && _strippable.IsStripHidden(slotDef, _player.LocalEntity))
if (entity != null && slotDef.StripHidden)
entity = _virtualHiddenEntity;
var button = new SlotButton(new SlotData(slotDef, container));

View File

@@ -5,7 +5,6 @@ using Content.Client.Clickable;
using Content.Client.DebugMon;
using Content.Client.Eui;
using Content.Client.Fullscreen;
using Content.Client.GameTicking.Managers;
using Content.Client.GhostKick;
using Content.Client.Guidebook;
using Content.Client.Launcher;
@@ -58,7 +57,6 @@ namespace Content.Client.IoC
collection.Register<DebugMonitorManager>();
collection.Register<PlayerRateLimitManager>();
collection.Register<SharedPlayerRateLimitManager, PlayerRateLimitManager>();
collection.Register<TitleWindowManager>();
}
}
}

View File

@@ -279,7 +279,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
_profileEditor.OnOpenGuidebook += _guide.OpenHelp;
_characterSetup = new CharacterSetupGui(_profileEditor);
_characterSetup = new CharacterSetupGui(EntityManager, _prototypeManager, _resourceCache, _preferencesManager, _profileEditor);
_characterSetup.CloseButton.OnPressed += _ =>
{

View File

@@ -2,7 +2,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:style="clr-namespace:Content.Client.Stylesheets"
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
VerticalExpand="True">
<Control>
<PanelContainer Name="BackgroundPanel" />
@@ -11,15 +10,10 @@
<Label Text="{Loc 'character-setup-gui-character-setup-label'}"
Margin="8 0 0 0" VAlign="Center"
StyleClasses="LabelHeadingBigger" />
<Button Name="StatsButton" HorizontalExpand="True"
Text="{Loc 'character-setup-gui-character-setup-stats-button'}"
StyleClasses="ButtonBig"
HorizontalAlignment="Right" />
<cc:CommandButton Name="AdminRemarksButton"
Command="adminremarks"
Text="{Loc 'character-setup-gui-character-setup-adminremarks-button'}"
StyleClasses="ButtonBig" />
<Button Name="RulesButton"
Text="{Loc 'character-setup-gui-character-setup-rules-button'}"
StyleClasses="ButtonBig"/>

View File

@@ -1,7 +1,6 @@
using Content.Client.Info;
using Content.Client.Info.PlaytimeStats;
using Content.Client.Resources;
using Content.Shared.CCVar;
using Content.Shared.Preferences;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
@@ -9,7 +8,6 @@ using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
namespace Content.Client.Lobby.UI
@@ -20,23 +18,28 @@ namespace Content.Client.Lobby.UI
[GenerateTypedNameReferences]
public sealed partial class CharacterSetupGui : Control
{
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IPrototypeManager _protomanager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private readonly IClientPreferencesManager _preferencesManager;
private readonly IEntityManager _entManager;
private readonly IPrototypeManager _protomanager;
private readonly Button _createNewCharacterButton;
public event Action<int>? SelectCharacter;
public event Action<int>? DeleteCharacter;
public CharacterSetupGui(HumanoidProfileEditor profileEditor)
public CharacterSetupGui(
IEntityManager entManager,
IPrototypeManager protoManager,
IResourceCache resourceCache,
IClientPreferencesManager preferencesManager,
HumanoidProfileEditor profileEditor)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_preferencesManager = preferencesManager;
_entManager = entManager;
_protomanager = protoManager;
var panelTex = _resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
var back = new StyleBoxTexture
{
Texture = panelTex,
@@ -53,7 +56,7 @@ namespace Content.Client.Lobby.UI
_createNewCharacterButton.OnPressed += args =>
{
_preferencesManager.CreateCharacter(HumanoidCharacterProfile.Random());
preferencesManager.CreateCharacter(HumanoidCharacterProfile.Random());
ReloadCharacterPickers();
args.Event.Handle();
};
@@ -62,8 +65,6 @@ namespace Content.Client.Lobby.UI
RulesButton.OnPressed += _ => new RulesAndInfoWindow().Open();
StatsButton.OnPressed += _ => new PlaytimeStatsWindow().OpenCentered();
_cfg.OnValueChanged(CCVars.SeeOwnNotes, p => AdminRemarksButton.Visible = p, true);
}
/// <summary>

View File

@@ -36,18 +36,17 @@ public sealed partial class LoadoutContainer : BoxContainer
if (_protoManager.TryIndex(proto, out var loadProto))
{
var ent = loadProto.DummyEntity ?? _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto);
var ent = _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto);
if (ent == null)
return;
if (ent != null)
{
_entity = _entManager.SpawnEntity(ent, MapCoordinates.Nullspace);
Sprite.SetEntity(_entity);
_entity = _entManager.SpawnEntity(ent, MapCoordinates.Nullspace);
Sprite.SetEntity(_entity);
var spriteTooltip = new Tooltip();
spriteTooltip.SetMessage(FormattedMessage.FromUnformatted(_entManager.GetComponent<MetaDataComponent>(_entity.Value).EntityDescription));
TooltipSupplier = _ => spriteTooltip;
var spriteTooltip = new Tooltip();
spriteTooltip.SetMessage(FormattedMessage.FromUnformatted(_entManager.GetComponent<MetaDataComponent>(_entity.Value).EntityDescription));
TooltipSupplier = _ => spriteTooltip;
}
}
}

View File

@@ -2,6 +2,7 @@ using Content.Client.Message;
using Content.Client.UserInterface.Systems.EscapeMenu;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.State;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;

View File

@@ -0,0 +1,149 @@
using System.Numerics;
using Content.Client.Buckle;
using Content.Client.Gravity;
using Content.Shared.ActionBlocker;
using Content.Shared.Mobs.Systems;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Shared.Animations;
namespace Content.Client.Movement.Systems;
public sealed class WaddleAnimationSystem : SharedWaddleAnimationSystem
{
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
[Dependency] private readonly GravitySystem _gravity = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
[Dependency] private readonly BuckleSystem _buckle = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
public override void Initialize()
{
base.Initialize();
SubscribeAllEvent<StartedWaddlingEvent>(OnStartWaddling);
SubscribeLocalEvent<WaddleAnimationComponent, AnimationCompletedEvent>(OnAnimationCompleted);
SubscribeAllEvent<StoppedWaddlingEvent>(OnStopWaddling);
}
private void OnStartWaddling(StartedWaddlingEvent msg, EntitySessionEventArgs args)
{
if (TryComp<WaddleAnimationComponent>(GetEntity(msg.Entity), out var comp))
StartWaddling((GetEntity(msg.Entity), comp));
}
private void OnStopWaddling(StoppedWaddlingEvent msg, EntitySessionEventArgs args)
{
if (TryComp<WaddleAnimationComponent>(GetEntity(msg.Entity), out var comp))
StopWaddling((GetEntity(msg.Entity), comp));
}
private void StartWaddling(Entity<WaddleAnimationComponent> entity)
{
if (_animation.HasRunningAnimation(entity.Owner, entity.Comp.KeyName))
return;
if (!TryComp<InputMoverComponent>(entity.Owner, out var mover))
return;
if (_gravity.IsWeightless(entity.Owner))
return;
if (!_actionBlocker.CanMove(entity.Owner, mover))
return;
// Do nothing if buckled in
if (_buckle.IsBuckled(entity.Owner))
return;
// Do nothing if crit or dead (for obvious reasons)
if (_mobState.IsIncapacitated(entity.Owner))
return;
PlayWaddleAnimationUsing(
(entity.Owner, entity.Comp),
CalculateAnimationLength(entity.Comp, mover),
CalculateTumbleIntensity(entity.Comp)
);
}
private static float CalculateTumbleIntensity(WaddleAnimationComponent component)
{
return component.LastStep ? 360 - component.TumbleIntensity : component.TumbleIntensity;
}
private static float CalculateAnimationLength(WaddleAnimationComponent component, InputMoverComponent mover)
{
return mover.Sprinting ? component.AnimationLength * component.RunAnimationLengthMultiplier : component.AnimationLength;
}
private void OnAnimationCompleted(Entity<WaddleAnimationComponent> entity, ref AnimationCompletedEvent args)
{
if (args.Key != entity.Comp.KeyName)
return;
if (!TryComp<InputMoverComponent>(entity.Owner, out var mover))
return;
PlayWaddleAnimationUsing(
(entity.Owner, entity.Comp),
CalculateAnimationLength(entity.Comp, mover),
CalculateTumbleIntensity(entity.Comp)
);
}
private void StopWaddling(Entity<WaddleAnimationComponent> entity)
{
if (!_animation.HasRunningAnimation(entity.Owner, entity.Comp.KeyName))
return;
_animation.Stop(entity.Owner, entity.Comp.KeyName);
if (!TryComp<SpriteComponent>(entity.Owner, out var sprite))
return;
sprite.Offset = new Vector2();
sprite.Rotation = Angle.FromDegrees(0);
}
private void PlayWaddleAnimationUsing(Entity<WaddleAnimationComponent> entity, float len, float tumbleIntensity)
{
entity.Comp.LastStep = !entity.Comp.LastStep;
var anim = new Animation()
{
Length = TimeSpan.FromSeconds(len),
AnimationTracks =
{
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Rotation),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), 0),
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(tumbleIntensity), len/2),
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), len/2),
}
},
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Offset),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(new Vector2(), 0),
new AnimationTrackProperty.KeyFrame(entity.Comp.HopIntensity, len/2),
new AnimationTrackProperty.KeyFrame(new Vector2(), len/2),
}
}
}
};
_animation.Play(entity.Owner, anim, entity.Comp.KeyName);
}
}

View File

@@ -14,7 +14,6 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
{
[Dependency] private readonly IPlayerManager _player = default!;
[ViewVariables]
protected bool IsActive;
protected virtual SlotFlags TargetSlots => ~SlotFlags.POCKET;
@@ -103,7 +102,7 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
args.Components.Add(component);
}
protected void RefreshOverlay(EntityUid uid)
private void RefreshOverlay(EntityUid uid)
{
if (uid != _player.LocalSession?.AttachedEntity)
return;

View File

@@ -21,16 +21,9 @@ public sealed class ShowHealthBarsSystem : EquipmentHudSystem<ShowHealthBarsComp
{
base.Initialize();
SubscribeLocalEvent<ShowHealthBarsComponent, AfterAutoHandleStateEvent>(OnHandleState);
_overlay = new(EntityManager, _prototype);
}
private void OnHandleState(Entity<ShowHealthBarsComponent> ent, ref AfterAutoHandleStateEvent args)
{
RefreshOverlay(ent);
}
protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthBarsComponent> component)
{
base.UpdateInternal(component);

View File

@@ -17,7 +17,6 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
{
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
[ViewVariables]
public HashSet<string> DamageContainers = new();
public override void Initialize()
@@ -25,7 +24,6 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
base.Initialize();
SubscribeLocalEvent<DamageableComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
SubscribeLocalEvent<ShowHealthIconsComponent, AfterAutoHandleStateEvent>(OnHandleState);
}
protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthIconsComponent> component)
@@ -45,11 +43,6 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
DamageContainers.Clear();
}
private void OnHandleState(Entity<ShowHealthIconsComponent> ent, ref AfterAutoHandleStateEvent args)
{
RefreshOverlay(ent);
}
private void OnGetStatusIconsEvent(Entity<DamageableComponent> entity, ref GetStatusIconsEvent args)
{
if (!IsActive)

View File

@@ -22,6 +22,6 @@ public sealed class ShowThirstIconsSystem : EquipmentHudSystem<ShowThirstIconsCo
return;
if (_thirst.TryGetStatusIconPrototype(component, out var iconPrototype))
ev.StatusIcons.Add(iconPrototype);
ev.StatusIcons.Add(iconPrototype!);
}
}

View File

@@ -76,16 +76,16 @@ public sealed partial class StencilOverlay : Overlay
//CP14 Overlays
if (_entManager.TryGetComponent<CP14CloudShadowsComponent>(mapUid, out var shadows))
if (_entManager.TryGetComponent<CP14WorldEdgeComponent>(mapUid, out var worldEdge))
{
DrawCloudShadows(args, shadows, invMatrix);
DrawWorldEdge(args, worldEdge, invMatrix);
}
//CP14 Overlays end
//CP14 Overlays
if (_entManager.TryGetComponent<CP14WorldEdgeComponent>(mapUid, out var worldEdge))
if (_entManager.TryGetComponent<CP14CloudShadowsComponent>(mapUid, out var shadows))
{
DrawWorldEdge(args, worldEdge, invMatrix);
DrawCloudShadows(args, shadows, invMatrix);
}
//CP14 Overlays end

View File

@@ -1,12 +1,9 @@
using Content.Shared.Alert;
using Content.Shared.CCVar;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Systems;
using Robust.Client.GameObjects;
using Robust.Client.Physics;
using Robust.Client.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Physics.Components;
using Robust.Shared.Player;
using Robust.Shared.Timing;
@@ -17,8 +14,6 @@ public sealed class MoverController : SharedMoverController
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
public override void Initialize()
{
@@ -140,15 +135,4 @@ public sealed class MoverController : SharedMoverController
{
return _timing is { IsFirstTimePredicted: true, InSimulation: true };
}
public override void SetSprinting(Entity<InputMoverComponent> entity, ushort subTick, bool walking)
{
// Logger.Info($"[{_gameTiming.CurTick}/{subTick}] Sprint: {enabled}");
base.SetSprinting(entity, subTick, walking);
if (walking && _cfg.GetCVar(CCVars.ToggleWalk))
_alerts.ShowAlert(entity, WalkingAlert, showCooldown: false, autoRemove: false);
else
_alerts.ClearAlert(entity, WalkingAlert);
}
}

View File

@@ -1,303 +0,0 @@
using Content.Shared.Atmos;
using Content.Shared.Pinpointer;
using System.Linq;
namespace Content.Client.Pinpointer;
public sealed partial class NavMapSystem
{
private (AtmosDirection, Vector2i, AtmosDirection)[] _regionPropagationTable =
{
(AtmosDirection.East, new Vector2i(1, 0), AtmosDirection.West),
(AtmosDirection.West, new Vector2i(-1, 0), AtmosDirection.East),
(AtmosDirection.North, new Vector2i(0, 1), AtmosDirection.South),
(AtmosDirection.South, new Vector2i(0, -1), AtmosDirection.North),
};
public override void Update(float frameTime)
{
// To prevent compute spikes, only one region is flood filled per frame
var query = AllEntityQuery<NavMapComponent>();
while (query.MoveNext(out var ent, out var entNavMapRegions))
FloodFillNextEnqueuedRegion(ent, entNavMapRegions);
}
private void FloodFillNextEnqueuedRegion(EntityUid uid, NavMapComponent component)
{
if (!component.QueuedRegionsToFlood.Any())
return;
var regionOwner = component.QueuedRegionsToFlood.Dequeue();
// If the region is no longer valid, flood the next one in the queue
if (!component.RegionProperties.TryGetValue(regionOwner, out var regionProperties) ||
!regionProperties.Seeds.Any())
{
FloodFillNextEnqueuedRegion(uid, component);
return;
}
// Flood fill the region, using the region seeds as starting points
var (floodedTiles, floodedChunks) = FloodFillRegion(uid, component, regionProperties);
// Combine the flooded tiles into larger rectangles
var gridCoords = GetMergedRegionTiles(floodedTiles);
// Create and assign the new region overlay
var regionOverlay = new NavMapRegionOverlay(regionProperties.UiKey, gridCoords)
{
Color = regionProperties.Color
};
component.RegionOverlays[regionOwner] = regionOverlay;
// To reduce unnecessary future flood fills, we will track which chunks have been flooded by a region owner
// First remove an old assignments
if (component.RegionOwnerToChunkTable.TryGetValue(regionOwner, out var oldChunks))
{
foreach (var chunk in oldChunks)
{
if (component.ChunkToRegionOwnerTable.TryGetValue(chunk, out var oldOwners))
{
oldOwners.Remove(regionOwner);
component.ChunkToRegionOwnerTable[chunk] = oldOwners;
}
}
}
// Now update with the new assignments
component.RegionOwnerToChunkTable[regionOwner] = floodedChunks;
foreach (var chunk in floodedChunks)
{
if (!component.ChunkToRegionOwnerTable.TryGetValue(chunk, out var owners))
owners = new();
owners.Add(regionOwner);
component.ChunkToRegionOwnerTable[chunk] = owners;
}
}
private (HashSet<Vector2i>, HashSet<Vector2i>) FloodFillRegion(EntityUid uid, NavMapComponent component, NavMapRegionProperties regionProperties)
{
if (!regionProperties.Seeds.Any())
return (new(), new());
var visitedChunks = new HashSet<Vector2i>();
var visitedTiles = new HashSet<Vector2i>();
var tilesToVisit = new Stack<Vector2i>();
foreach (var regionSeed in regionProperties.Seeds)
{
tilesToVisit.Push(regionSeed);
while (tilesToVisit.Count > 0)
{
// If the max region area is hit, exit
if (visitedTiles.Count > regionProperties.MaxArea)
return (new(), new());
// Pop the top tile from the stack
var current = tilesToVisit.Pop();
// If the current tile position has already been visited,
// or is too far away from the seed, continue
if ((regionSeed - current).Length > regionProperties.MaxRadius)
continue;
if (visitedTiles.Contains(current))
continue;
// Determine the tile's chunk index
var chunkOrigin = SharedMapSystem.GetChunkIndices(current, ChunkSize);
var relative = SharedMapSystem.GetChunkRelative(current, ChunkSize);
var idx = GetTileIndex(relative);
// Extract the tile data
if (!component.Chunks.TryGetValue(chunkOrigin, out var chunk))
continue;
var flag = chunk.TileData[idx];
// If the current tile is entirely occupied, continue
if ((FloorMask & flag) == 0)
continue;
if ((WallMask & flag) == WallMask)
continue;
if ((AirlockMask & flag) == AirlockMask)
continue;
// Otherwise the tile can be added to this region
visitedTiles.Add(current);
visitedChunks.Add(chunkOrigin);
// Determine if we can propagate the region into its cardinally adjacent neighbors
// To propagate to a neighbor, movement into the neighbors closest edge must not be
// blocked, and vice versa
foreach (var (direction, tileOffset, reverseDirection) in _regionPropagationTable)
{
if (!RegionCanPropagateInDirection(chunk, current, direction))
continue;
var neighbor = current + tileOffset;
var neighborOrigin = SharedMapSystem.GetChunkIndices(neighbor, ChunkSize);
if (!component.Chunks.TryGetValue(neighborOrigin, out var neighborChunk))
continue;
visitedChunks.Add(neighborOrigin);
if (!RegionCanPropagateInDirection(neighborChunk, neighbor, reverseDirection))
continue;
tilesToVisit.Push(neighbor);
}
}
}
return (visitedTiles, visitedChunks);
}
private bool RegionCanPropagateInDirection(NavMapChunk chunk, Vector2i tile, AtmosDirection direction)
{
var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize);
var idx = GetTileIndex(relative);
var flag = chunk.TileData[idx];
if ((FloorMask & flag) == 0)
return false;
var directionMask = 1 << (int)direction;
var wallMask = (int)direction << (int)NavMapChunkType.Wall;
var airlockMask = (int)direction << (int)NavMapChunkType.Airlock;
if ((wallMask & flag) > 0)
return false;
if ((airlockMask & flag) > 0)
return false;
return true;
}
private List<(Vector2i, Vector2i)> GetMergedRegionTiles(HashSet<Vector2i> tiles)
{
if (!tiles.Any())
return new();
var x = tiles.Select(t => t.X);
var minX = x.Min();
var maxX = x.Max();
var y = tiles.Select(t => t.Y);
var minY = y.Min();
var maxY = y.Max();
var matrix = new int[maxX - minX + 1, maxY - minY + 1];
foreach (var tile in tiles)
{
var a = tile.X - minX;
var b = tile.Y - minY;
matrix[a, b] = 1;
}
return GetMergedRegionTiles(matrix, new Vector2i(minX, minY));
}
private List<(Vector2i, Vector2i)> GetMergedRegionTiles(int[,] matrix, Vector2i offset)
{
var output = new List<(Vector2i, Vector2i)>();
var rows = matrix.GetLength(0);
var cols = matrix.GetLength(1);
var dp = new int[rows, cols];
var coords = (new Vector2i(), new Vector2i());
var maxArea = 0;
var count = 0;
while (!IsArrayEmpty(matrix))
{
count++;
if (count > rows * cols)
break;
// Clear old values
dp = new int[rows, cols];
coords = (new Vector2i(), new Vector2i());
maxArea = 0;
// Initialize the first row of dp
for (int j = 0; j < cols; j++)
{
dp[0, j] = matrix[0, j];
}
// Calculate dp values for remaining rows
for (int i = 1; i < rows; i++)
{
for (int j = 0; j < cols; j++)
dp[i, j] = matrix[i, j] == 1 ? dp[i - 1, j] + 1 : 0;
}
// Find the largest rectangular area seeded for each position in the matrix
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
int minWidth = dp[i, j];
for (int k = j; k >= 0; k--)
{
if (dp[i, k] <= 0)
break;
minWidth = Math.Min(minWidth, dp[i, k]);
var currArea = Math.Max(maxArea, minWidth * (j - k + 1));
if (currArea > maxArea)
{
maxArea = currArea;
coords = (new Vector2i(i - minWidth + 1, k), new Vector2i(i, j));
}
}
}
}
// Save the recorded rectangle vertices
output.Add((coords.Item1 + offset, coords.Item2 + offset));
// Removed the tiles covered by the rectangle from matrix
for (int i = coords.Item1.X; i <= coords.Item2.X; i++)
{
for (int j = coords.Item1.Y; j <= coords.Item2.Y; j++)
matrix[i, j] = 0;
}
}
return output;
}
private bool IsArrayEmpty(int[,] matrix)
{
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
if (matrix[i, j] == 1)
return false;
}
}
return true;
}
}

View File

@@ -1,4 +1,3 @@
using System.Linq;
using Content.Shared.Pinpointer;
using Robust.Shared.GameStates;
@@ -17,7 +16,6 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
{
Dictionary<Vector2i, int[]> modifiedChunks;
Dictionary<NetEntity, NavMapBeacon> beacons;
Dictionary<NetEntity, NavMapRegionProperties> regions;
switch (args.Current)
{
@@ -25,8 +23,6 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
{
modifiedChunks = delta.ModifiedChunks;
beacons = delta.Beacons;
regions = delta.Regions;
foreach (var index in component.Chunks.Keys)
{
if (!delta.AllChunks!.Contains(index))
@@ -39,8 +35,6 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
{
modifiedChunks = state.Chunks;
beacons = state.Beacons;
regions = state.Regions;
foreach (var index in component.Chunks.Keys)
{
if (!state.Chunks.ContainsKey(index))
@@ -53,54 +47,13 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
return;
}
// Update region data and queue new regions for flooding
var prevRegionOwners = component.RegionProperties.Keys.ToList();
var validRegionOwners = new List<NetEntity>();
component.RegionProperties.Clear();
foreach (var (regionOwner, regionData) in regions)
{
if (!regionData.Seeds.Any())
continue;
component.RegionProperties[regionOwner] = regionData;
validRegionOwners.Add(regionOwner);
if (component.RegionOverlays.ContainsKey(regionOwner))
continue;
if (component.QueuedRegionsToFlood.Contains(regionOwner))
continue;
component.QueuedRegionsToFlood.Enqueue(regionOwner);
}
// Remove stale region owners
var regionOwnersToRemove = prevRegionOwners.Except(validRegionOwners);
foreach (var regionOwnerRemoved in regionOwnersToRemove)
RemoveNavMapRegion(uid, component, regionOwnerRemoved);
// Modify chunks
foreach (var (origin, chunk) in modifiedChunks)
{
var newChunk = new NavMapChunk(origin);
Array.Copy(chunk, newChunk.TileData, chunk.Length);
component.Chunks[origin] = newChunk;
// If the affected chunk intersects one or more regions, re-flood them
if (!component.ChunkToRegionOwnerTable.TryGetValue(origin, out var affectedOwners))
continue;
foreach (var affectedOwner in affectedOwners)
{
if (!component.QueuedRegionsToFlood.Contains(affectedOwner))
component.QueuedRegionsToFlood.Enqueue(affectedOwner);
}
}
// Refresh beacons
component.Beacons.Clear();
foreach (var (nuid, beacon) in beacons)
{

View File

@@ -48,7 +48,6 @@ public partial class NavMapControl : MapGridControl
public List<(Vector2, Vector2)> TileLines = new();
public List<(Vector2, Vector2)> TileRects = new();
public List<(Vector2[], Color)> TilePolygons = new();
public List<NavMapRegionOverlay> RegionOverlays = new();
// Default colors
public Color WallColor = new(102, 217, 102);
@@ -229,7 +228,7 @@ public partial class NavMapControl : MapGridControl
{
if (!blip.Selectable)
continue;
var currentDistance = (_transformSystem.ToMapCoordinates(blip.Coordinates).Position - worldPosition).Length();
if (closestDistance < currentDistance || currentDistance * MinimapScale > MaxSelectableDistance)
@@ -320,22 +319,6 @@ public partial class NavMapControl : MapGridControl
}
}
// Draw region overlays
if (_grid != null)
{
foreach (var regionOverlay in RegionOverlays)
{
foreach (var gridCoords in regionOverlay.GridCoords)
{
var positionTopLeft = ScalePosition(new Vector2(gridCoords.Item1.X, -gridCoords.Item1.Y) - new Vector2(offset.X, -offset.Y));
var positionBottomRight = ScalePosition(new Vector2(gridCoords.Item2.X + _grid.TileSize, -gridCoords.Item2.Y - _grid.TileSize) - new Vector2(offset.X, -offset.Y));
var box = new UIBox2(positionTopLeft, positionBottomRight);
handle.DrawRect(box, regionOverlay.Color);
}
}
}
// Draw map lines
if (TileLines.Any())
{

View File

@@ -51,8 +51,6 @@ public sealed class JobRequirementsManager : ISharedPlaytimeManager
{
// Reset on disconnect, just in case.
_roles.Clear();
_jobWhitelists.Clear();
_roleBans.Clear();
}
}
@@ -60,6 +58,9 @@ public sealed class JobRequirementsManager : ISharedPlaytimeManager
{
_sawmill.Debug($"Received roleban info containing {message.Bans.Count} entries.");
if (_roleBans.Equals(message.Bans))
return;
_roleBans.Clear();
_roleBans.AddRange(message.Bans);
Updated?.Invoke();

View File

@@ -1,10 +1,7 @@
using Content.Client.Effects;
using Content.Client.Smoking;
using Content.Shared.Chemistry.Components;
using Content.Shared.Polymorph.Components;
using Content.Shared.Polymorph.Systems;
using Robust.Client.GameObjects;
using Robust.Shared.Player;
namespace Content.Client.Polymorph.Systems;
@@ -13,20 +10,14 @@ public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
private EntityQuery<AppearanceComponent> _appearanceQuery;
private EntityQuery<SpriteComponent> _spriteQuery;
public override void Initialize()
{
base.Initialize();
_appearanceQuery = GetEntityQuery<AppearanceComponent>();
_spriteQuery = GetEntityQuery<SpriteComponent>();
SubscribeLocalEvent<ChameleonDisguiseComponent, AfterAutoHandleStateEvent>(OnHandleState);
SubscribeLocalEvent<ChameleonDisguisedComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<ChameleonDisguisedComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<ChameleonDisguisedComponent, GetFlashEffectTargetEvent>(OnGetFlashEffectTargetEvent);
}
private void OnHandleState(Entity<ChameleonDisguiseComponent> ent, ref AfterAutoHandleStateEvent args)
@@ -34,30 +25,9 @@ public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem
CopyComp<SpriteComponent>(ent);
CopyComp<GenericVisualizerComponent>(ent);
CopyComp<SolutionContainerVisualsComponent>(ent);
CopyComp<BurnStateVisualsComponent>(ent);
// reload appearance to hopefully prevent any invisible layers
if (_appearanceQuery.TryComp(ent, out var appearance))
_appearance.QueueUpdate(ent, appearance);
}
private void OnStartup(Entity<ChameleonDisguisedComponent> ent, ref ComponentStartup args)
{
if (!_spriteQuery.TryComp(ent, out var sprite))
return;
ent.Comp.WasVisible = sprite.Visible;
sprite.Visible = false;
}
private void OnShutdown(Entity<ChameleonDisguisedComponent> ent, ref ComponentShutdown args)
{
if (_spriteQuery.TryComp(ent, out var sprite))
sprite.Visible = ent.Comp.WasVisible;
}
private void OnGetFlashEffectTargetEvent(Entity<ChameleonDisguisedComponent> ent, ref GetFlashEffectTargetEvent args)
{
args.Target = ent.Comp.Disguise;
}
}

View File

@@ -1,9 +1,8 @@
using Content.Client.Power.APC.UI;
using Content.Shared.Access.Systems;
using Content.Client.Power.APC.UI;
using Content.Shared.APC;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.Player;
namespace Content.Client.Power.APC
{
@@ -23,14 +22,6 @@ namespace Content.Client.Power.APC
_menu = this.CreateWindow<ApcMenu>();
_menu.SetEntity(Owner);
_menu.OnBreaker += BreakerPressed;
var hasAccess = false;
if (PlayerManager.LocalEntity != null)
{
var accessReader = EntMan.System<AccessReaderSystem>();
hasAccess = accessReader.IsAllowed((EntityUid)PlayerManager.LocalEntity, Owner);
}
_menu?.SetAccessEnabled(hasAccess);
}
protected override void UpdateState(BoundUserInterfaceState state)

View File

@@ -1,4 +1,4 @@
using Robust.Client.AutoGenerated;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
using Robust.Client.GameObjects;
using Robust.Shared.IoC;
@@ -36,9 +36,19 @@ namespace Content.Client.Power.APC.UI
{
var castState = (ApcBoundInterfaceState) state;
if (!BreakerButton.Disabled)
if (BreakerButton != null)
{
BreakerButton.Pressed = castState.MainBreaker;
if(castState.HasAccess == false)
{
BreakerButton.Disabled = true;
BreakerButton.ToolTip = Loc.GetString("apc-component-insufficient-access");
}
else
{
BreakerButton.Disabled = false;
BreakerButton.ToolTip = null;
BreakerButton.Pressed = castState.MainBreaker;
}
}
if (PowerLabel != null)
@@ -76,20 +86,6 @@ namespace Content.Client.Power.APC.UI
}
}
public void SetAccessEnabled(bool hasAccess)
{
if(hasAccess)
{
BreakerButton.Disabled = false;
BreakerButton.ToolTip = null;
}
else
{
BreakerButton.Disabled = true;
BreakerButton.ToolTip = Loc.GetString("apc-component-insufficient-access");
}
}
private void UpdateChargeBarColor(float charge)
{
if (ChargeBar == null)

View File

@@ -131,8 +131,7 @@ public sealed partial class BorgMenu : FancyWindow
_modules.Clear();
foreach (var module in chassis.ModuleContainer.ContainedEntities)
{
var moduleComponent = _entity.GetComponent<BorgModuleComponent>(module);
var control = new BorgModuleControl(module, _entity, !moduleComponent.DefaultModule);
var control = new BorgModuleControl(module, _entity);
control.RemoveButtonPressed += () =>
{
RemoveModuleButtonPressed?.Invoke(module);

View File

@@ -9,7 +9,7 @@ public sealed partial class BorgModuleControl : PanelContainer
{
public Action? RemoveButtonPressed;
public BorgModuleControl(EntityUid entity, IEntityManager entityManager, bool canRemove)
public BorgModuleControl(EntityUid entity, IEntityManager entityManager)
{
RobustXamlLoader.Load(this);
@@ -20,7 +20,6 @@ public sealed partial class BorgModuleControl : PanelContainer
{
RemoveButtonPressed?.Invoke();
};
RemoveButton.Visible = canRemove;
}
}

View File

@@ -1,43 +0,0 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
Title="{Loc 'borg-select-type-menu-title'}"
SetSize="550 300">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal" VerticalExpand="True">
<!-- Left pane: selection of borg type -->
<BoxContainer Orientation="Vertical" MinWidth="200" Margin="2 0">
<Label Text="{Loc 'borg-select-type-menu-available'}" StyleClasses="LabelHeading" />
<ScrollContainer HScrollEnabled="False" VerticalExpand="True">
<BoxContainer Name="SelectionsContainer" Orientation="Vertical" />
</ScrollContainer>
</BoxContainer>
<customControls:VSeparator />
<!-- Right pane: information about selected borg module, confirm button. -->
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="2 0">
<Label Text="{Loc 'borg-select-type-menu-information'}" StyleClasses="LabelHeading" />
<Control VerticalExpand="True">
<controls:Placeholder Name="InfoPlaceholder" PlaceholderText="{Loc 'borg-select-type-menu-select-type'}" />
<BoxContainer Name="InfoContents" Orientation="Vertical" Visible="False">
<BoxContainer Orientation="Horizontal" Margin="0 0 0 4">
<EntityPrototypeView Name="ChassisView" Scale="2,2" />
<Label Name="NameLabel" HorizontalExpand="True" />
</BoxContainer>
<RichTextLabel Name="DescriptionLabel" VerticalExpand="True" VerticalAlignment="Top" />
</BoxContainer>
</Control>
<controls:ConfirmButton Name="ConfirmTypeButton" Text="{Loc 'borg-select-type-menu-confirm'}"
Disabled="True" HorizontalAlignment="Right"
MinWidth="200" />
</BoxContainer>
</BoxContainer>
<controls:StripeBack Margin="0 0 0 4">
<Label Text="{Loc 'borg-select-type-menu-bottom-text'}" HorizontalAlignment="Center" StyleClasses="LabelSubText" Margin="4 4 0 4"/>
</controls:StripeBack>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -1,81 +0,0 @@
using System.Linq;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Systems.Guidebook;
using Content.Shared.Guidebook;
using Content.Shared.Silicons.Borgs;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Silicons.Borgs;
/// <summary>
/// Menu used by borgs to select their type.
/// </summary>
/// <seealso cref="BorgSelectTypeUserInterface"/>
/// <seealso cref="BorgSwitchableTypeComponent"/>
[GenerateTypedNameReferences]
public sealed partial class BorgSelectTypeMenu : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private BorgTypePrototype? _selectedBorgType;
public event Action<ProtoId<BorgTypePrototype>>? ConfirmedBorgType;
[ValidatePrototypeId<GuideEntryPrototype>]
private static readonly List<ProtoId<GuideEntryPrototype>> GuidebookEntries = new() { "Cyborgs", "Robotics" };
public BorgSelectTypeMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var group = new ButtonGroup();
foreach (var borgType in _prototypeManager.EnumeratePrototypes<BorgTypePrototype>().OrderBy(PrototypeName))
{
var button = new Button
{
Text = PrototypeName(borgType),
Group = group,
};
button.OnPressed += _ =>
{
_selectedBorgType = borgType;
UpdateInformation(borgType);
};
SelectionsContainer.AddChild(button);
}
ConfirmTypeButton.OnPressed += ConfirmButtonPressed;
HelpGuidebookIds = GuidebookEntries;
}
private void UpdateInformation(BorgTypePrototype prototype)
{
_selectedBorgType = prototype;
InfoContents.Visible = true;
InfoPlaceholder.Visible = false;
ConfirmTypeButton.Disabled = false;
NameLabel.Text = PrototypeName(prototype);
DescriptionLabel.Text = Loc.GetString($"borg-type-{prototype.ID}-desc");
ChassisView.SetPrototype(prototype.DummyPrototype);
}
private void ConfirmButtonPressed(BaseButton.ButtonEventArgs obj)
{
if (_selectedBorgType == null)
return;
ConfirmedBorgType?.Invoke(_selectedBorgType);
}
private static string PrototypeName(BorgTypePrototype prototype)
{
return Loc.GetString($"borg-type-{prototype.ID}-name");
}
}

View File

@@ -1,30 +0,0 @@
using Content.Shared.Silicons.Borgs.Components;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Silicons.Borgs;
/// <summary>
/// User interface used by borgs to select their type.
/// </summary>
/// <seealso cref="BorgSelectTypeMenu"/>
/// <seealso cref="BorgSwitchableTypeComponent"/>
/// <seealso cref="BorgSwitchableTypeUiKey"/>
[UsedImplicitly]
public sealed class BorgSelectTypeUserInterface : BoundUserInterface
{
[ViewVariables]
private BorgSelectTypeMenu? _menu;
public BorgSelectTypeUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_menu = this.CreateWindow<BorgSelectTypeMenu>();
_menu.ConfirmedBorgType += prototype => SendMessage(new BorgSelectTypeMessage(prototype));
}
}

View File

@@ -1,81 +0,0 @@
using Content.Shared.Movement.Components;
using Content.Shared.Silicons.Borgs;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Silicons.Borgs;
/// <summary>
/// Client side logic for borg type switching. Sets up primarily client-side visual information.
/// </summary>
/// <seealso cref="SharedBorgSwitchableTypeSystem"/>
/// <seealso cref="BorgSwitchableTypeComponent"/>
public sealed class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem
{
[Dependency] private readonly BorgSystem _borgSystem = default!;
[Dependency] private readonly AppearanceSystem _appearance = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BorgSwitchableTypeComponent, AfterAutoHandleStateEvent>(AfterStateHandler);
SubscribeLocalEvent<BorgSwitchableTypeComponent, ComponentStartup>(OnComponentStartup);
}
private void OnComponentStartup(Entity<BorgSwitchableTypeComponent> ent, ref ComponentStartup args)
{
UpdateEntityAppearance(ent);
}
private void AfterStateHandler(Entity<BorgSwitchableTypeComponent> ent, ref AfterAutoHandleStateEvent args)
{
UpdateEntityAppearance(ent);
}
protected override void UpdateEntityAppearance(
Entity<BorgSwitchableTypeComponent> entity,
BorgTypePrototype prototype)
{
if (TryComp(entity, out SpriteComponent? sprite))
{
sprite.LayerSetState(BorgVisualLayers.Body, prototype.SpriteBodyState);
sprite.LayerSetState(BorgVisualLayers.LightStatus, prototype.SpriteToggleLightState);
}
if (TryComp(entity, out BorgChassisComponent? chassis))
{
_borgSystem.SetMindStates(
(entity.Owner, chassis),
prototype.SpriteHasMindState,
prototype.SpriteNoMindState);
if (TryComp(entity, out AppearanceComponent? appearance))
{
// Queue update so state changes apply.
_appearance.QueueUpdate(entity, appearance);
}
}
if (prototype.SpriteBodyMovementState is { } movementState)
{
var spriteMovement = EnsureComp<SpriteMovementComponent>(entity);
spriteMovement.NoMovementLayers.Clear();
spriteMovement.NoMovementLayers["movement"] = new PrototypeLayerData
{
State = prototype.SpriteBodyState,
};
spriteMovement.MovementLayers.Clear();
spriteMovement.MovementLayers["movement"] = new PrototypeLayerData
{
State = movementState,
};
}
else
{
RemComp<SpriteMovementComponent>(entity);
}
base.UpdateEntityAppearance(entity, prototype);
}
}

View File

@@ -92,18 +92,4 @@ public sealed class BorgSystem : SharedBorgSystem
sprite.LayerSetState(MMIVisualLayers.Base, state);
}
}
/// <summary>
/// Sets the sprite states used for the borg "is there a mind or not" indication.
/// </summary>
/// <param name="borg">The entity and component to modify.</param>
/// <param name="hasMindState">The state to use if the borg has a mind.</param>
/// <param name="noMindState">The state to use if the borg has no mind.</param>
/// <seealso cref="BorgChassisComponent.HasMindState"/>
/// <seealso cref="BorgChassisComponent.NoMindState"/>
public void SetMindStates(Entity<BorgChassisComponent> borg, string hasMindState, string noMindState)
{
borg.Comp.HasMindState = hasMindState;
borg.Comp.NoMindState = noMindState;
}
}

View File

@@ -1,7 +1,7 @@
using Content.Shared.Singularity.EntitySystems;
using Content.Shared.Singularity.Components;
namespace Content.Client.Singularity.Systems;
namespace Content.Client.Singularity.EntitySystems;
/// <summary>
/// The client-side version of <see cref="SharedEventHorizonSystem"/>.

View File

@@ -1,12 +0,0 @@
using Content.Shared.Singularity.EntitySystems;
using Content.Shared.Singularity.Components;
namespace Content.Client.Singularity.Systems;
/// <summary>
/// The client-side version of <see cref="SharedSingularityGeneratorSystem"/>.
/// Manages <see cref="SingularityGeneratorComponent"/>s.
/// Exists to make relevant signal handlers (ie: <see cref="SharedSingularityGeneratorSystem.OnEmagged"/>) work on the client.
/// </summary>
public sealed class SingularityGeneratorSystem : SharedSingularityGeneratorSystem
{}

View File

@@ -5,7 +5,7 @@ using Robust.Client.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Utility;
namespace Content.Client.Singularity.Systems;
namespace Content.Client.Singularity.EntitySystems;
/// <summary>
/// The client-side version of <see cref="SharedSingularitySystem"/>.

View File

@@ -100,7 +100,7 @@ namespace Content.Client.Stylesheets
public static readonly Color ButtonColorDefaultRed = Color.FromHex("#D43B3B");
public static readonly Color ButtonColorHovered = Color.FromHex("#7f6357");
public static readonly Color ButtonColorHoveredRed = Color.FromHex("#DF6B6B");
public static readonly Color ButtonColorPressed = Color.FromHex("#4a332b");
public static readonly Color ButtonColorPressed = Color.FromHex("#6c4a3e");
public static readonly Color ButtonColorDisabled = Color.FromHex("#3c3330");
public static readonly Color ButtonColorCautionDefault = Color.FromHex("#ab3232");

View File

@@ -1,9 +0,0 @@
<BoxContainer xmlns="https://spacestation14.io"
Orientation="Vertical"
Margin="8 0 8 0">
<BoxContainer Name="Buttons"
Orientation="Vertical"
SeparationOverride="5">
<!-- Buttons are added here by code -->
</BoxContainer>
</BoxContainer>

View File

@@ -1,15 +1,15 @@
<BoxContainer xmlns="https://spacestation14.io"
Orientation="Horizontal"
HorizontalAlignment="Stretch">
Orientation="Horizontal">
<Button Name="RequestButton"
Access="Public"
Text="{Loc 'ghost-roles-window-request-role-button'}"
StyleClasses="OpenRight"
HorizontalExpand="True"
SizeFlagsStretchRatio="3"/>
HorizontalAlignment="Left"
SetWidth="300"/>
<Button Name="FollowButton"
Access="Public"
Text="{Loc 'ghost-roles-window-follow-role-button'}"
StyleClasses="OpenLeft"
HorizontalExpand="True"/>
HorizontalAlignment="Right"
SetWidth="150"/>
</BoxContainer>

View File

@@ -1,8 +0,0 @@
<BoxContainer xmlns="https://spacestation14.io"
Orientation="Vertical">
<Label Name="Title"
StyleClasses="LabelKeyText"/>
<PanelContainer StyleClasses="HighDivider" />
<RichTextLabel Name="Description"
Margin="0 4"/>
</BoxContainer>

View File

@@ -1,18 +0,0 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
{
[GenerateTypedNameReferences]
public sealed partial class GhostRoleInfoBox : BoxContainer
{
public GhostRoleInfoBox(string name, string description)
{
RobustXamlLoader.Load(this);
Title.Text = name;
Description.SetMessage(description);
}
}
}

View File

@@ -0,0 +1,16 @@
<BoxContainer xmlns="https://spacestation14.io"
Orientation="Vertical"
HorizontalExpand="True"
Margin="0 0 8 8">
<Label Name="Title"
StyleClasses="LabelKeyText"/>
<PanelContainer StyleClasses="HighDivider" />
<RichTextLabel Name="Description"
Margin="0 4"/>
<BoxContainer Name="Buttons"
HorizontalAlignment="Left"
Orientation="Vertical"
SeparationOverride="5">
<!-- Buttons are added here by code -->
</BoxContainer>
</BoxContainer>

View File

@@ -10,17 +10,20 @@ using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
{
[GenerateTypedNameReferences]
public sealed partial class GhostRoleButtonsBox : BoxContainer
public sealed partial class GhostRolesEntry : BoxContainer
{
private SpriteSystem _spriteSystem;
public event Action<GhostRoleInfo>? OnRoleSelected;
public event Action<GhostRoleInfo>? OnRoleFollow;
public GhostRoleButtonsBox(bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
public GhostRolesEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
{
RobustXamlLoader.Load(this);
_spriteSystem = spriteSystem;
Title.Text = name;
Description.SetMessage(description);
foreach (var role in roles)
{
var button = new GhostRoleEntryButtons(role);

View File

@@ -5,6 +5,7 @@ using Content.Shared.Eui;
using Content.Shared.Ghost.Roles;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
{
@@ -76,13 +77,6 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
if (state is not GhostRolesEuiState ghostState)
return;
// We must save BodyVisible state, so all Collapsible boxes will not close
// on adding new ghost role.
// Save the current state of each Collapsible box being visible or not
_window.SaveCollapsibleBoxesStates();
// Clearing the container before adding new roles
_window.ClearEntries();
var entityManager = IoCManager.Resolve<IEntityManager>();
@@ -90,32 +84,28 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
var spriteSystem = sysManager.GetEntitySystem<SpriteSystem>();
var requirementsManager = IoCManager.Resolve<JobRequirementsManager>();
// TODO: role.Requirements value doesn't work at all as an equality key, this must be fixed
// Grouping roles
var groupedRoles = ghostState.GhostRoles.GroupBy(
role => (role.Name, role.Description, role.Requirements));
// Add a new entry for each role group
foreach (var group in groupedRoles)
{
var name = group.Key.Name;
var description = group.Key.Description;
var hasAccess = requirementsManager.CheckRoleRequirements(
group.Key.Requirements,
null,
out var reason);
bool hasAccess = true;
FormattedMessage? reason;
if (!requirementsManager.CheckRoleRequirements(group.Key.Requirements, null, out reason))
{
hasAccess = false;
}
// Adding a new role
_window.AddEntry(name, description, hasAccess, reason, group, spriteSystem);
}
// Restore the Collapsible box state if it is saved
_window.RestoreCollapsibleBoxesStates();
// Close the rules window if it is no longer needed
var closeRulesWindow = ghostState.GhostRoles.All(role => role.Identifier != _windowRulesId);
if (closeRulesWindow)
{
_windowRules?.Close();
}
}
}
}

View File

@@ -1,10 +1,7 @@
using System.Linq;
using Content.Shared.Ghost.Roles;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
@@ -15,86 +12,20 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
public event Action<GhostRoleInfo>? OnRoleRequestButtonClicked;
public event Action<GhostRoleInfo>? OnRoleFollow;
private Dictionary<(string name, string description), Collapsible> _collapsibleBoxes = new();
private HashSet<(string name, string description)> _uncollapsedStates = new();
public GhostRolesWindow()
{
RobustXamlLoader.Load(this);
}
public void ClearEntries()
{
NoRolesMessage.Visible = true;
EntryContainer.DisposeAllChildren();
_collapsibleBoxes.Clear();
}
public void SaveCollapsibleBoxesStates()
{
_uncollapsedStates.Clear();
foreach (var (key, collapsible) in _collapsibleBoxes)
{
if (collapsible.BodyVisible)
{
_uncollapsedStates.Add(key);
}
}
}
public void RestoreCollapsibleBoxesStates()
{
foreach (var (key, collapsible) in _collapsibleBoxes)
{
collapsible.BodyVisible = _uncollapsedStates.Contains(key);
}
}
public void AddEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
{
NoRolesMessage.Visible = false;
var ghostRoleInfos = roles.ToList();
var rolesCount = ghostRoleInfos.Count;
var info = new GhostRoleInfoBox(name, description);
var buttons = new GhostRoleButtonsBox(hasAccess, reason, ghostRoleInfos, spriteSystem);
buttons.OnRoleSelected += OnRoleRequestButtonClicked;
buttons.OnRoleFollow += OnRoleFollow;
EntryContainer.AddChild(info);
if (rolesCount > 1)
{
var buttonHeading = new CollapsibleHeading(Loc.GetString("ghost-roles-window-available-button", ("rolesCount", rolesCount)));
buttonHeading.AddStyleClass(ContainerButton.StyleClassButton);
buttonHeading.Label.HorizontalAlignment = HAlignment.Center;
buttonHeading.Label.HorizontalExpand = true;
var body = new CollapsibleBody
{
Margin = new Thickness(0, 5, 0, 0),
};
// TODO: Add Requirements to this key when it'll be fixed and work as an equality key in GhostRolesEui
var key = (name, description);
var collapsible = new Collapsible(buttonHeading, body)
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
Margin = new Thickness(0, 0, 0, 8),
};
body.AddChild(buttons);
EntryContainer.AddChild(collapsible);
_collapsibleBoxes.Add(key, collapsible);
}
else
{
EntryContainer.AddChild(buttons);
}
var entry = new GhostRolesEntry(name, description, hasAccess, reason, roles, spriteSystem);
entry.OnRoleSelected += OnRoleRequestButtonClicked;
entry.OnRoleFollow += OnRoleFollow;
EntryContainer.AddChild(entry);
}
}
}

View File

@@ -307,6 +307,12 @@ public sealed class StorageUIController : UIController, IOnSystemChanged<Storage
_entity.GetNetEntity(storageEnt),
new ItemStorageLocation(DraggingRotation, position)));
}
else
{
_entity.RaisePredictiveEvent(new StorageRemoveItemEvent(
_entity.GetNetEntity(draggingGhost.Entity),
_entity.GetNetEntity(storageEnt)));
}
_menuDragHelper.EndDrag();
_container?.BuildItemPieces();

View File

@@ -2,8 +2,7 @@
xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:co="clr-namespace:Content.Client.UserInterface.Controls"
MinHeight="210">
xmlns:co="clr-namespace:Content.Client.UserInterface.Controls">
<BoxContainer Name="MainContainer" Orientation="Vertical">
<LineEdit Name="SearchBar" PlaceHolder="{Loc 'vending-machine-component-search-filter'}" HorizontalExpand="True" Margin ="4 4"/>
<co:SearchListContainer Name="VendingContents" VerticalExpand="True" Margin="4 4"/>

View File

@@ -1,6 +1,5 @@
using System.Linq;
using System.Numerics;
using Content.Client.Gameplay;
using Content.Client.Stylesheets;
using Content.Shared.Administration;
using Content.Shared.CCVar;
@@ -9,7 +8,6 @@ using Content.Shared.Voting;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.State;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
@@ -30,7 +28,6 @@ namespace Content.Client.Voting.UI
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IEntityNetworkManager _entNetManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IStateManager _state = default!;
private VotingSystem _votingSystem;
@@ -65,7 +62,7 @@ namespace Content.Client.Voting.UI
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
CloseButton.OnPressed += _ => Close();
VoteNotTrustedLabel.Text = Loc.GetString("ui-vote-trusted-users-notice", ("timeReq", _cfg.GetCVar(CCVars.VotekickEligibleVoterDeathtime)));
VoteNotTrustedLabel.Text = Loc.GetString("ui-vote-trusted-users-notice", ("timeReq", _cfg.GetCVar(CCVars.VotekickEligibleVoterDeathtime) / 60));
foreach (StandardVoteType voteType in Enum.GetValues<StandardVoteType>())
{
@@ -73,7 +70,6 @@ namespace Content.Client.Voting.UI
VoteTypeButton.AddItem(Loc.GetString(option.Name), (int)voteType);
}
_state.OnStateChanged += OnStateChanged;
VoteTypeButton.OnItemSelected += VoteTypeSelected;
CreateButton.OnPressed += CreatePressed;
FollowButton.OnPressed += FollowSelected;
@@ -105,14 +101,6 @@ namespace Content.Client.Voting.UI
UpdateVoteTimeout();
}
private void OnStateChanged(StateChangedEventArgs obj)
{
if (obj.NewState is not GameplayState)
return;
Close();
}
private void CanCallVoteChanged(bool obj)
{
if (!obj)

View File

@@ -19,6 +19,11 @@ public sealed class VotingSystem : EntitySystem
private void OnVotePlayerListResponseEvent(VotePlayerListResponseEvent msg)
{
if (!_ghostSystem.IsGhost)
{
return;
}
VotePlayerListResponse?.Invoke(msg);
}

View File

@@ -20,7 +20,7 @@ public enum WeaponArcAnimation : byte
None,
Thrust,
Slash,
//CrystallEdge Melee upgrade
//CrystallPunk Melee upgrade
CPSlash,
CPThrust
}

View File

@@ -43,8 +43,8 @@ public sealed partial class MeleeWeaponSystem
return;
}
var length = 1f; //CrystallEdgeMelee upgrade
var offset = -1f; //CrystallEdge Melee upgrade
var length = 1f; //CrystallPunk Melee upgrade
var offset = -1f; //CrystallPunk Melee upgrade
var spriteRotation = Angle.Zero;
if (arcComponent.Animation != WeaponArcAnimation.None
@@ -59,8 +59,8 @@ public sealed partial class MeleeWeaponSystem
if (meleeWeaponComponent.SwingLeft)
angle *= -1;
length = meleeWeaponComponent.CPAnimationLength; //CrystallEdge Melee upgrade
offset = meleeWeaponComponent.CPAnimationOffset; //CrystallEdge Melee upgrade
length = meleeWeaponComponent.CPAnimationLength; //CrystallPunk Melee upgrade
offset = meleeWeaponComponent.CPAnimationOffset; //CrystallPunk Melee upgrade
}
sprite.Rotation = localPos.ToWorldAngle();
var distance = Math.Clamp(localPos.Length() / 2f, 0.2f, 1f);
@@ -92,7 +92,7 @@ public sealed partial class MeleeWeaponSystem
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
break;
//CrystallEdge MeleeUpgrade
//CrystallPunk MeleeUpgrade
case WeaponArcAnimation.CPSlash:
track = EnsureComp<TrackUserComponent>(animationUid);
track.User = user;
@@ -107,7 +107,7 @@ public sealed partial class MeleeWeaponSystem
if (arcComponent.Fadeout)
_animation.Play(animationUid, GetFadeAnimation(sprite, 0f, 0.15f), FadeAnimationKey);
break;
//CrystallEdge MeleeUpgrade end
//CrystallPunk MeleeUpgrade end
}
}
@@ -207,7 +207,7 @@ public sealed partial class MeleeWeaponSystem
/// </summary>
private Animation GetLungeAnimation(Vector2 direction)
{
const float length = 0.2f; // 0.1 original, CrystallEdge update
const float length = 0.2f; // 0.1 original, CrystallPunk update
return new Animation
{
@@ -221,9 +221,9 @@ public sealed partial class MeleeWeaponSystem
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), //CrystallEdge MeleeUpgrade
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, length*0.4f), //CrystallEdge MeleeUpgrade
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length*0.6f) //CrystallEdge MeleeUpgrade
new AnimationTrackProperty.KeyFrame(Vector2.Zero, 0f), //CrystallPunk MeleeUpgrade
new AnimationTrackProperty.KeyFrame(direction.Normalized() * 0.15f, length*0.4f), //CrystallPunk MeleeUpgrade
new AnimationTrackProperty.KeyFrame(Vector2.Zero, length*0.6f) //CrystallPunk MeleeUpgrade
}
}
}
@@ -253,7 +253,7 @@ public sealed partial class MeleeWeaponSystem
}
}
//CrystallEdge MeleeUpgrade start
//CrystallPunk MeleeUpgrade start
private Animation CPGetSlashAnimation(SpriteComponent sprite, Angle arc, Angle spriteRotation, float length, float offset = -1f)
{
var startRotation = sprite.Rotation + (arc * 0.5f);
@@ -324,6 +324,6 @@ public sealed partial class MeleeWeaponSystem
};
}
//CrystallEdge MeleeUpgrade end
//CrystallPunk MeleeUpgrade end
}

View File

@@ -28,7 +28,6 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
[Dependency] private readonly InputSystem _inputSystem = default!;
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
[Dependency] private readonly MapSystem _map = default!;
private EntityQuery<TransformComponent> _xformQuery;
@@ -110,11 +109,11 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
if (MapManager.TryFindGridAt(mousePos, out var gridUid, out _))
{
coordinates = TransformSystem.ToCoordinates(gridUid, mousePos);
coordinates = EntityCoordinates.FromMap(gridUid, mousePos, TransformSystem, EntityManager);
}
else
{
coordinates = TransformSystem.ToCoordinates(_map.GetMap(mousePos.MapId), mousePos);
coordinates = EntityCoordinates.FromMap(MapManager.GetMapEntityId(mousePos.MapId), mousePos, TransformSystem, EntityManager);
}
// Heavy attack.

View File

@@ -157,7 +157,7 @@ public sealed partial class GunSystem : SharedGunSystem
var useKey = gun.UseKey ? EngineKeyFunctions.Use : EngineKeyFunctions.UseSecondary;
if (_inputSystem.CmdStates.GetState(useKey) != BoundKeyState.Down && !gun.BurstActivated)
if (_inputSystem.CmdStates.GetState(useKey) != BoundKeyState.Down)
{
if (gun.ShotCounter != 0)
EntityManager.RaisePredictiveEvent(new RequestStopShootEvent { Gun = GetNetEntity(gunUid) });

View File

@@ -1,31 +0,0 @@
namespace Content.Client._CP14.Localization;
/// <summary>
/// Controls the visual of the sprite, depending on the localization. Useful for drawn lettering
/// </summary>
[RegisterComponent]
public sealed partial class CP14LocalizationVisualsComponent : Component
{
/// <summary>
/// map(map,(lang, state))
/// in yml:
///
/// - type: Sprite
/// layers:
/// - state: stateName0
/// map: ["map1"]
/// - state: stateName0
/// map: ["map2"]
/// - type: CP14LocalizationVisuals
/// mapStates:
/// map1:
/// ru-RU: stateName1
/// en-US: stateName2
/// map2:
/// ru-RU: stateName3
/// en-US: stateName4
///
/// </summary>
[DataField]
public Dictionary<string, Dictionary<string, string>> MapStates;
}

View File

@@ -1,29 +0,0 @@
using Content.Shared.Localizations;
using Robust.Client.GameObjects;
namespace Content.Client._CP14.Localization;
public sealed class CP14LocalizationVisualsSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14LocalizationVisualsComponent, ComponentInit>(OnCompInit);
}
private void OnCompInit(Entity<CP14LocalizationVisualsComponent> visuals, ref ComponentInit args)
{
if (!TryComp<SpriteComponent>(visuals, out var sprite))
return;
foreach (var (map, pDictionary) in visuals.Comp.MapStates)
{
if (!pDictionary.TryGetValue(ContentLocalizationManager.Culture, out var state))
return;
if (sprite.LayerMapTryGet(map, out _))
sprite.LayerSetState(map, state);
}
}
}

View File

@@ -1,7 +0,0 @@
using Content.Shared._CP14.MagicSpell;
namespace Content.Client._CP14.MagicSpell;
public sealed partial class CP14ClientMagicSystem : CP14SharedMagicSystem
{
}

View File

@@ -1,17 +0,0 @@
using Robust.Shared;
using Robust.Shared.Configuration;
namespace Content.Client._CP14.Shitcode;
/// <summary>
/// Эта система - сборник разного мелкого барахла, который слишком мелкий чтобы иметь свои собственные системы. В идеале в будущем разнести по отдельным файлам.
/// </summary>
public sealed class CP14EdSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
public override void Initialize()
{
_cfg.SetCVar(CVars.EntitiesCategoryFilter, "ForkFiltered");
}
}

View File

@@ -1,7 +0,0 @@
using Content.Shared._CP14.Temperature;
namespace Content.Client._CP14.Temperature;
public sealed partial class CP14ClientFireSpreadSystem : CP14SharedFireSpreadSystem
{
}

View File

@@ -1,22 +0,0 @@
<Control xmlns="https://spacestation14.io">
<GridContainer Columns="6">
<TextureRect Name="GoldView"
MinSize="10 10"
Stretch="KeepAspectCentered"/>
<Label Name="GoldText"
Margin="0,0,5,0"/>
<TextureRect Name="SilverView"
MinSize="10 10"
Stretch="KeepAspectCentered"/>
<Label Name="SilverText"
Margin="0,0,5,0"/>
<TextureRect Name="CopperView"
MinSize="10 10"
Stretch="KeepAspectCentered"/>
<Label Name="CopperText"
Margin="0,0,5,0"/>
</GridContainer>
</Control>

View File

@@ -1,46 +0,0 @@
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client._CP14.TravelingStoreShip;
[GenerateTypedNameReferences]
public sealed partial class CP14PriceControl : Control
{
[Dependency] private readonly IEntityManager _entity = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
private readonly SpriteSystem _sprite;
public CP14PriceControl(int price)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sprite = _entity.System<SpriteSystem>();
var rsiPath = new ResPath("_CP14/Interface/Misc/coins.rsi");
var total = price;
var gp = total / 100;
total %= 100;
var sp = total / 10;
total %= 10;
var cp = total;
CopperView.Texture = _sprite.Frame0(new SpriteSpecifier.Rsi(rsiPath, "c"));
CopperText.Text = cp.ToString();
SilverView.Texture = _sprite.Frame0(new SpriteSpecifier.Rsi(rsiPath, "s"));
SilverText.Text = sp.ToString();
GoldView.Texture = _sprite.Frame0(new SpriteSpecifier.Rsi(rsiPath, "g"));
GoldText.Text = gp.ToString();
}
}

View File

@@ -1,34 +0,0 @@
using Content.Shared._CP14.Cargo;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client._CP14.TravelingStoreShip;
public sealed class CP14StoreBoundUserInterface : BoundUserInterface
{
private CP14StoreWindow? _window;
public CP14StoreBoundUserInterface(EntityUid owner, [NotNull] Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = this.CreateWindow<CP14StoreWindow>();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
switch (state)
{
case CP14StoreUiState storeState:
_window?.UpdateUI(storeState);
break;
}
}
}

View File

@@ -1,15 +0,0 @@
<Control xmlns="https://spacestation14.io">
<Button Name="ProductButton" Access="Public">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal">
<TextureRect Name="View"
MinSize="48 48"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Stretch="KeepAspectCentered"/>
<RichTextLabel Name="ProductName" VerticalAlignment="Center" Access="Public"/>
<BoxContainer Name="PriceHolder" VerticalAlignment="Center" HorizontalExpand="True" HorizontalAlignment="Right"/>
</BoxContainer>
</BoxContainer>
</Button>
</Control>

View File

@@ -1,44 +0,0 @@
using Content.Shared._CP14.Cargo;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
namespace Content.Client._CP14.TravelingStoreShip;
[GenerateTypedNameReferences]
public sealed partial class CP14StoreProductControl : Control
{
[Dependency] private readonly IEntityManager _entity = default!;
private readonly SpriteSystem _sprite;
public CP14StoreProductControl(CP14StoreUiProductEntry entry)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sprite = _entity.System<SpriteSystem>();
UpdateName(entry.Name);
UpdateView(entry.Icon);
UpdatePrice(entry.Price);
}
private void UpdatePrice(int price)
{
PriceHolder.RemoveAllChildren();
PriceHolder.AddChild(new CP14PriceControl(price));
}
private void UpdateName(string name)
{
ProductName.Text = $"[bold]{name}[/bold]";
}
private void UpdateView(SpriteSpecifier spriteSpecifier)
{
View.Texture = _sprite.Frame0(spriteSpecifier);
}
}

View File

@@ -1,31 +0,0 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'cp14-store-ui-title'}"
MinSize="800 600"
SetSize="800 600">
<BoxContainer Orientation="Horizontal">
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Horizontal">
<!-- Product list (left side UI) -->
<TabContainer SizeFlagsStretchRatio="0.5" Name="Tabs" HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
<BoxContainer Name="BuyProductsContainer" Orientation="Vertical" HorizontalExpand="True"/>
</ScrollContainer>
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
<BoxContainer Name="SellProductsContainer" Orientation="Vertical" HorizontalExpand="True"/>
</ScrollContainer>
</TabContainer>
<!-- Station trading data (right side UI) -->
<BoxContainer SizeFlagsStretchRatio="0.5" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="0 0 10 0">
<controls:StripeBack>
<PanelContainer>
<Label Text="{Loc 'cp14-store-ui-order'}" Align="Center" Margin="0 5 0 3"/>
</PanelContainer>
</controls:StripeBack>
<Label Name="TravelTimeLabel" Text="00:00" HorizontalAlignment="Center" HorizontalExpand="True" Margin="0 15 0 0"/>
<controls:HLine Color="#404040" Thickness="2" Margin="0 5"/>
<RichTextLabel Name="SelectedName" HorizontalExpand="True" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="5"/>
<RichTextLabel Name="SelectedDesc" HorizontalExpand="True" VerticalExpand="True" VerticalAlignment="Top" Margin="5"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -1,79 +0,0 @@
using Content.Shared._CP14.Cargo;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client._CP14.TravelingStoreShip;
[GenerateTypedNameReferences]
public sealed partial class CP14StoreWindow : DefaultWindow
{
[Dependency] private readonly IGameTiming _timing = default!;
private TimeSpan? _nextTravelTime;
private bool _onStation;
public CP14StoreWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
Tabs.SetTabTitle(0, Loc.GetString("cp14-store-ui-tab-buy"));
Tabs.SetTabTitle(1, Loc.GetString("cp14-store-ui-tab-sell"));
}
public void UpdateUI(CP14StoreUiState state)
{
UpdateProducts(state);
_nextTravelTime = state.NextTravelTime;
_onStation = state.OnStation;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
//Updating time
if (_nextTravelTime is not null)
{
var time = _nextTravelTime.Value - _timing.CurTime;
TravelTimeLabel.Text =
$"{Loc.GetString(_onStation ? "cp14-store-ui-next-travel-out" : "cp14-store-ui-next-travel-in")} {Math.Max(time.Minutes, 0):00}:{Math.Max(time.Seconds, 0):00}";
}
}
private void UpdateProducts(CP14StoreUiState state)
{
BuyProductsContainer.RemoveAllChildren();
SellProductsContainer.RemoveAllChildren();
foreach (var product in state.ProductsBuy)
{
var control = new CP14StoreProductControl(product);
control.ProductButton.OnPressed += _ =>
{
SelectProduct(product);
};
BuyProductsContainer.AddChild(control);
}
foreach (var product in state.ProductsSell)
{
var control = new CP14StoreProductControl(product);
control.ProductButton.OnPressed += _ =>
{
SelectProduct(product);
};
SellProductsContainer.AddChild(control);
}
}
private void SelectProduct(CP14StoreUiProductEntry? entry)
{
SelectedName.Text = entry is null ? string.Empty : $"[bold]{entry.Value.Name}[/bold]";
SelectedDesc.Text = entry is null ? string.Empty : entry.Value.Desc;
}
}

View File

@@ -107,41 +107,13 @@ public sealed partial class TestPair
/// <summary>
/// Retrieve all entity prototypes that have some component.
/// </summary>
public List<(EntityPrototype, T)> GetPrototypesWithComponent<T>(
public List<EntityPrototype> GetPrototypesWithComponent<T>(
HashSet<string>? ignored = null,
bool ignoreAbstract = true,
bool ignoreTestPrototypes = true)
where T : IComponent
{
var id = Server.ResolveDependency<IComponentFactory>().GetComponentName(typeof(T));
var list = new List<(EntityPrototype, T)>();
foreach (var proto in Server.ProtoMan.EnumeratePrototypes<EntityPrototype>())
{
if (ignored != null && ignored.Contains(proto.ID))
continue;
if (ignoreAbstract && proto.Abstract)
continue;
if (ignoreTestPrototypes && IsTestPrototype(proto))
continue;
if (proto.Components.TryGetComponent(id, out var cmp))
list.Add((proto, (T)cmp));
}
return list;
}
/// <summary>
/// Retrieve all entity prototypes that have some component.
/// </summary>
public List<EntityPrototype> GetPrototypesWithComponent(Type type,
HashSet<string>? ignored = null,
bool ignoreAbstract = true,
bool ignoreTestPrototypes = true)
{
var id = Server.ResolveDependency<IComponentFactory>().GetComponentName(type);
var list = new List<EntityPrototype>();
foreach (var proto in Server.ProtoMan.EnumeratePrototypes<EntityPrototype>())
{
@@ -155,7 +127,7 @@ public sealed partial class TestPair
continue;
if (proto.Components.ContainsKey(id))
list.Add((proto));
list.Add(proto);
}
return list;

View File

@@ -12,7 +12,6 @@ namespace Content.IntegrationTests.Tests.Access
[TestOf(typeof(AccessReaderComponent))]
public sealed class AccessReaderTest
{
/*
[Test]
public async Task TestProtoTags()
{
@@ -124,6 +123,6 @@ namespace Content.IntegrationTests.Tests.Access
});
await pair.CleanReturnAsync();
}
*/
}
}

View File

@@ -6,7 +6,7 @@ namespace Content.IntegrationTests.Tests.Atmos
[TestFixture]
[TestOf(typeof(AtmosAlarmThreshold))]
public sealed class AlarmThresholdTest
{/*
{
[TestPrototypes]
private const string Prototypes = @"
- type: alarmThreshold
@@ -135,6 +135,6 @@ namespace Content.IntegrationTests.Tests.Atmos
}
});
await pair.CleanReturnAsync();
}*/
}
}
}

View File

@@ -8,7 +8,7 @@ namespace Content.IntegrationTests.Tests.Atmos
[TestFixture]
[TestOf(typeof(Atmospherics))]
public sealed class ConstantsTest
{/*
{
[Test]
public async Task TotalGasesTest()
{
@@ -27,6 +27,6 @@ namespace Content.IntegrationTests.Tests.Atmos
});
});
await pair.CleanReturnAsync();
}*/
}
}
}

View File

@@ -8,7 +8,7 @@ namespace Content.IntegrationTests.Tests.Atmos
[TestFixture]
[TestOf(typeof(GasMixture))]
public sealed class GasMixtureTest
{/*
{
[Test]
public async Task TestMerge()
{
@@ -105,6 +105,6 @@ namespace Content.IntegrationTests.Tests.Atmos
});
await pair.CleanReturnAsync();
}*/
}
}
}

View File

@@ -8,7 +8,7 @@ namespace Content.IntegrationTests.Tests.Atmos;
[TestFixture]
public sealed class GridJoinTest
{/*
{
private const string CanisterProtoId = "AirCanister";
[Test]
@@ -49,5 +49,5 @@ public sealed class GridJoinTest
});
await pair.CleanReturnAsync();
}*/
}
}

Some files were not shown because too many files have changed in this diff Show More