Upstream Merge (June / July) attempt 2 electric boogaloo (#4607)
* Fix the sensor monitoring console forcing a GC every 3 seconds (#38146) * Optimize sensor monitoring window graph drawing * Add shared static Vector2 pool for all GraphView instances * Address requested changes * remove lock * Update submodule to 264.0.0 (#38629) * Toy/Plushie Inhands and Wearables (#38514) * Fixed dependency injection and some other issues in a few places. * More issue fixes * patchfor broken NetworkConfiguratorLinkMenu (#38632) fix * Fix solutions flickering when transferring contents (#34838) * Use Solution clones when applying SolutionComponent states * Revert "Use Solution clones when applying SolutionComponent states" This reverts commit 013fd111cf92b22562e00f98a7aaa49bc4b4ed62. * Make Solution implement ICloneable and rename Clone method. * Copy CanReact value when cloning a Solution * Convert to IRobustCloneable * Fix typos in guidebook: Buisness → Business (#38636) * Fix typo in `MinorAntagonists.xml` Buisness → Business * Fix typo in `YourFirstCharacter.xml` Buisness → Business * Various Headphones Fixes and Tweaks (#38479) * sprites, wearables * neck * icon-on sprite * Cleanup prototype instantiation in `DamageTest` (#38639) Cleanup prototype instantiation in DamageTest * Cleanup prototype instantiation in `ExplosionSystem` (#38642) Cleanup prototype instantiation in ExplosionSystem * AddBodyPartCommand localization. (#38612) commit * fix ItemSlotsSystem debug assert (#38655) * Allow the Command & Super door remotes to use the access of their user. (Re-creation of PR due to changes to game balance) (#35536) * Added directional beacons (#38284) * Added directional beacons Signed-off-by: Nox38 <nebulousnox38@gmail.com> * Fixed names Signed-off-by: Nox38 <nebulousnox38@gmail.com> --------- Signed-off-by: Nox38 <nebulousnox38@gmail.com> * Power stat and nuke codes commands get some LEC love. (#38585) * commit * requested changes. * Dsay Dirty and Follow commands converted to LEC and localized. (#38666) * commit * whoopwhoopwhoop * Retro laser sprite fix (#38676) * Fixed everything except the icon Signed-off-by: Nox38 <nebulousnox38@gmail.com> * fixed icon Signed-off-by: Nox38 <nebulousnox38@gmail.com> --------- Signed-off-by: Nox38 <nebulousnox38@gmail.com> * fix water coolers (#38681) * Monochromacy typo fix (#38686) * fixes the typo * Fixed cloning looking for the trait, not the component, RE https://github.com/space-wizards/space-station-14/pull/38686#issuecomment-3025093504 * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Validate `CloningSettingsPrototype`s (#38688) * Validate CloningSettingsPrototypes * Update Content.IntegrationTests/Tests/Cloning/CloningSettingsPrototypeTest.cs Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Check EventComponents too --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Add test of objective-related console commands (#36400) * Add test of objective add/list/remove commands * Not sure why we're validating test prototypes, but sure * We don't need a map * Improvements and fixups for New Status Effect API (#38660) * Predict healing and bloodstream (#38690) * initial commit * reapply 38126 * fix rootable * someone missed an important minus sign here * try this * fix * fix * reenable crit hits * cleanup * fix status time dirtying * fix * camelCase * Healing and bloodstream prediction fixes. * Resolving Wizard casting recall on nuke disk making it impossible to disarm (#38661) * Resolving Wizard Recall on Nuke disk making it impossible to disarm - Adding a DisarmBomb case to nuke status update loop - Changing a few methods and parameters to properly follow formatting standards - Updating some names to follow camelCase * Updating missed tag * Reverting DataField change Should prevent this preventative bugfix being a breaking change. * Switch HSV to the default colorspace for character customization (#38434) * Made HSV default for character editor * Adds/fixes comments to HSV defaulting * Added dropbox fix, potentially cursed * Revert "Added dropbox fix, potentially cursed" This reverts commit a709883366fbee813e839742125e70844672af29. --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * Fix: Don't deploy foldables when clicking on items inside containers (#38709) * Fix * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Pressure Relief Valve (#36708) * initial system (this math is probably WRONG) * General code cleanup and OnExamined support (holy moly this code sucks) * UICode and related events foundation TODO: - Actually write the XAML UI and the underlying system - Un-shitcode the entire thing - Actually test everything... * Working UI code TODO: Make predicted, as this certainly isn't predicted. Even though I said it was. It isn't. * Remove one TODO for unshitcoding the examine code * Add reminder yea * Make predicted (defenitely isn't) (also defenitely isn't a copypaste from pressure pump code) * It's predicted! TODO: - Give it snazzy predicted visuals! - Have a different field for pressure entry, lest it gets bulldozed every UI update. * Improve gas pressure relief valve UI TODO: Reminder to reduce amount of dirties using deltafields * Implement DirtyField prediction * Entity<T> cleanup A lot of Entity<T> conversions and lukewarm cleanup. Also got caught copy pasting code in 4K UHD but it's not like you couldn't tell. * More cleanup and comments * Remove TODO comment on bulldozing window title * """refactoring""" - Move appearance out of shared and finally fix it. Pointless to predict appearance in this instance. - More Entity<T> conversions because I like them. - Move UI creation handling over entirely to the ActivatableUI system. - Fix a hardcoded locale string (why????). * Add visuals * Revert debugging variable replacememt yea * Revert skissue * Remove unused using directives and remove TODO * Localize, cleanup, document * Fix adminlogging discrepancy * Add ability to construct, add guidebook entry * Clear up comment * Add guidebook tooltip to valve * Convert GasPressureReliefValveBoundUserInterface declaration into primary constructor * Adds more input handling and adds autofill on open * Un-deepfry input validator shitcode Genuinely what was I smoking * improve visuals logic * Refactor again - Update math to the correct implementation - Moved code that could be re-used in the future into a helper method under AtmosphereSystem.Gases.cs * I'm sorry but I hate warnings * Remove unused using directive in AtmosphereSystem.Gases.cs * Review and cleanup * Lukewarm UI glossup * Maintainer for the upstream project btw * Remove redundant state sets and messy logic * Unduplicate valve updater code * Redo UI (im sorry Slarti) * run tests * Test refactored UI messaging * Second round of UI improvements - God please find a way to improve this system. Feels bad. * Update loop implementation * Further predict UI * Clear up SetToCurrentThreshold * cleanup * Update to master + pipe layers and bug fixes want to run tests * fixes * Deploy rename pipebomb * Documentation and requested changes * Rename the method that wiggled away * Undo rounding changes * Fix comment * Rename and cleanup * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Fix TextLinkTag (#32203) * Adjust uplink buy button to be under item icon (#38596) * Adjusted uplink buy button to be under item icon * Put the discount subtext under the icon * Indent fixes, added margin --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * Scurrets - Audio Improvements (#38482) * Scurret audio tuning * Add new sfx * Update sneezing sfx * YAML support * Rename a folder * make telesci wreck easier (#37569) rel * Validate `ShaderPrototype` IDs (#38728) * Convert all shader prototype string literals to protoids in overlays * Convert more shader prototype literal strings to protoids * Convert ValidatePrototypeId to ProtoId * Later * [BUGFIX] Fixed revenant malfunction ability not working properly only MediBots and Stasis bed (#38664) * fixed * clean up * orks fix smart * review fix 1 * more requested changes * less cursed * more descriptive description * better wording * Tiny Tiny Cleanup of the EyeClosingSystem. (#38734) Update EyeClosingSystem.cs * Fix human skin tone distribution (#38701) * fix: Use PredictedQueueDel for gib spell (#38729) * fix: don't default to uncharged sprite state for cells (#38730) * Fix Hristov description - remove inaccurate technical specs (#38746) - Removes inaccurate 'armor piercing 14.5mm shells' reference - Replaces it with a more funny description, matching the style of the other snipers and guns - Keeps ammunition type '.60 anti-materiel ammo' specification - Fixes issue #38590 Co-authored-by: Arthur Fiorese de Andrade <aandrade@cmcxs.gov.br> * feat: allow mopping evaporating puddles (#38743) * Validate remaining `ProtoId` strings (#38747) Validate remaining ProtoId strings * Validate `ProtoId`s in tests (#38745) * Convert string literals to protoids in Content.Tests * Convert string literals to protoids or consts in Content.IntegrationTests * Fix linter failures Tricksy static using misled me * Cleanup warning in StomachSystem (#38748) you did not see this * Vox scars (#38592) * Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl * Revert "Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl" This reverts commit c73da55ba3b39ddf93b493aecd85604c54dd8a15. * locale key fix * Changed top surgery scar names to be more generalized * Adjusted face scars * Formatting fixes --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * UnlockNode command to LEC. (#38751) * commit * Update UnlockNodeCommand.cs * commit * move command locale to its own file. * Update Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Typofixes for figurine dialogue (#38737) * Typofixes for figurine dialogue * Forgot two * Janitor Tool: Wire Brush (#38667) * Wow! It's -brush- * spacing. * Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * fixed changes --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Minor escape menu UX improvements (#38650) * fix: spellbooks can have infinite charges (#38376) * fix: spellbooks can have infinite charges * refactor: indicate infinite spellbook charges with null Not sure if I like this much better...
This commit is contained in:
parent
88a11aea06
commit
29e55b9464
|
|
@ -77,6 +77,8 @@ csharp_style_expression_bodied_methods = false:suggestion
|
||||||
#csharp_style_expression_bodied_operators = false:silent
|
#csharp_style_expression_bodied_operators = false:silent
|
||||||
csharp_style_expression_bodied_properties = true:suggestion
|
csharp_style_expression_bodied_properties = true:suggestion
|
||||||
|
|
||||||
|
csharp_style_namespace_declarations = file_scoped:suggestion
|
||||||
|
|
||||||
# Pattern matching preferences
|
# Pattern matching preferences
|
||||||
#csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
#csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||||
#csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
#csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
|
|
||||||
- name: Build Project
|
- name: Build Project
|
||||||
run: dotnet build --no-restore /p:WarningsAsErrors=nullable
|
run: dotnet build --no-restore
|
||||||
|
|
||||||
- name: Build DocFX
|
- name: Build DocFX
|
||||||
uses: nikeee/docfx-action@v1.0.0
|
uses: nikeee/docfx-action@v1.0.0
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
|
|
||||||
- name: Build Project
|
- name: Build Project
|
||||||
run: dotnet build Content.MapRenderer --configuration Release --no-restore /p:WarningsAsErrors=nullable /m
|
run: dotnet build Content.MapRenderer --configuration Release --no-restore /m
|
||||||
|
|
||||||
- name: Run Map Renderer
|
- name: Run Map Renderer
|
||||||
run: dotnet run --project Content.MapRenderer Dev
|
run: dotnet run --project Content.MapRenderer Dev
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
|
|
||||||
- name: Build Project
|
- name: Build Project
|
||||||
run: dotnet build --configuration DebugOpt --no-restore /p:WarningsAsErrors=nullable /m
|
run: dotnet build --configuration DebugOpt --no-restore /m
|
||||||
|
|
||||||
- name: Run Content.Tests
|
- name: Run Content.Tests
|
||||||
run: dotnet test --no-build --configuration DebugOpt Content.Tests/Content.Tests.csproj -- NUnit.ConsoleOut=0
|
run: dotnet test --no-build --configuration DebugOpt Content.Tests/Content.Tests.csproj -- NUnit.ConsoleOut=0
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using Robust.Shared;
|
||||||
using Robust.Shared.Analyzers;
|
using Robust.Shared.Analyzers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Benchmarks;
|
namespace Content.Benchmarks;
|
||||||
|
|
||||||
|
|
@ -18,9 +19,11 @@ namespace Content.Benchmarks;
|
||||||
[Virtual, MemoryDiagnoser]
|
[Virtual, MemoryDiagnoser]
|
||||||
public class SpawnEquipDeleteBenchmark
|
public class SpawnEquipDeleteBenchmark
|
||||||
{
|
{
|
||||||
|
private static readonly EntProtoId Mob = "MobHuman";
|
||||||
|
private static readonly ProtoId<StartingGearPrototype> CaptainStartingGear = "CaptainGear";
|
||||||
|
|
||||||
private TestPair _pair = default!;
|
private TestPair _pair = default!;
|
||||||
private StationSpawningSystem _spawnSys = default!;
|
private StationSpawningSystem _spawnSys = default!;
|
||||||
private const string Mob = "MobHuman";
|
|
||||||
private StartingGearPrototype _gear = default!;
|
private StartingGearPrototype _gear = default!;
|
||||||
private EntityUid _entity;
|
private EntityUid _entity;
|
||||||
private EntityCoordinates _coords;
|
private EntityCoordinates _coords;
|
||||||
|
|
@ -39,7 +42,7 @@ public class SpawnEquipDeleteBenchmark
|
||||||
var mapData = await _pair.CreateTestMap();
|
var mapData = await _pair.CreateTestMap();
|
||||||
_coords = mapData.GridCoords;
|
_coords = mapData.GridCoords;
|
||||||
_spawnSys = server.System<StationSpawningSystem>();
|
_spawnSys = server.System<StationSpawningSystem>();
|
||||||
_gear = server.ProtoMan.Index<StartingGearPrototype>("CaptainGear");
|
_gear = server.ProtoMan.Index(CaptainStartingGear);
|
||||||
}
|
}
|
||||||
|
|
||||||
[GlobalCleanup]
|
[GlobalCleanup]
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ namespace Content.Client.Access.UI;
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<AccessGroupPrototype> GeneralAccessGroup = "General";
|
||||||
|
|
||||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||||
|
|
||||||
private bool _isMonotone;
|
private bool _isMonotone;
|
||||||
|
|
@ -63,7 +65,7 @@ public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
||||||
|
|
||||||
// Ensure that the 'general' access group is added to handle
|
// Ensure that the 'general' access group is added to handle
|
||||||
// misc. access levels that aren't associated with any group
|
// misc. access levels that aren't associated with any group
|
||||||
if (_protoManager.TryIndex<AccessGroupPrototype>("General", out var generalAccessProto))
|
if (_protoManager.TryIndex(GeneralAccessGroup, out var generalAccessProto))
|
||||||
_groupedAccessLevels.TryAdd(generalAccessProto, new());
|
_groupedAccessLevels.TryAdd(generalAccessProto, new());
|
||||||
|
|
||||||
// Assign known access levels with their associated groups
|
// Assign known access levels with their associated groups
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ namespace Content.Client.Actions
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var request = new RequestPerformActionEvent(GetNetEntity(action));
|
var request = new RequestPerformActionEvent(GetNetEntity(action));
|
||||||
EntityManager.RaisePredictiveEvent(request);
|
RaisePredictiveEvent(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Collections.Frozen;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Client.Administration.Systems;
|
using Content.Client.Administration.Systems;
|
||||||
|
|
@ -24,6 +25,7 @@ internal sealed class AdminNameOverlay : Overlay
|
||||||
private readonly EntityLookupSystem _entityLookup;
|
private readonly EntityLookupSystem _entityLookup;
|
||||||
private readonly IUserInterfaceManager _userInterfaceManager;
|
private readonly IUserInterfaceManager _userInterfaceManager;
|
||||||
private readonly SharedRoleSystem _roles;
|
private readonly SharedRoleSystem _roles;
|
||||||
|
private readonly IPrototypeManager _prototypeManager;
|
||||||
private readonly Font _font;
|
private readonly Font _font;
|
||||||
private readonly Font _fontBold;
|
private readonly Font _fontBold;
|
||||||
private AdminOverlayAntagFormat _overlayFormat;
|
private AdminOverlayAntagFormat _overlayFormat;
|
||||||
|
|
@ -36,8 +38,9 @@ internal sealed class AdminNameOverlay : Overlay
|
||||||
private float _overlayMergeDistance;
|
private float _overlayMergeDistance;
|
||||||
|
|
||||||
//TODO make this adjustable via GUI?
|
//TODO make this adjustable via GUI?
|
||||||
private readonly ProtoId<RoleTypePrototype>[] _filter =
|
private static readonly FrozenSet<ProtoId<RoleTypePrototype>> Filter =
|
||||||
["SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"];
|
new ProtoId<RoleTypePrototype>[] {"SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"}
|
||||||
|
.ToFrozenSet();
|
||||||
|
|
||||||
private readonly string _antagLabelClassic = Loc.GetString("admin-overlay-antag-classic");
|
private readonly string _antagLabelClassic = Loc.GetString("admin-overlay-antag-classic");
|
||||||
|
|
||||||
|
|
@ -49,7 +52,8 @@ internal sealed class AdminNameOverlay : Overlay
|
||||||
EntityLookupSystem entityLookup,
|
EntityLookupSystem entityLookup,
|
||||||
IUserInterfaceManager userInterfaceManager,
|
IUserInterfaceManager userInterfaceManager,
|
||||||
IConfigurationManager config,
|
IConfigurationManager config,
|
||||||
SharedRoleSystem roles)
|
SharedRoleSystem roles,
|
||||||
|
IPrototypeManager prototypeManager)
|
||||||
{
|
{
|
||||||
_system = system;
|
_system = system;
|
||||||
_entityManager = entityManager;
|
_entityManager = entityManager;
|
||||||
|
|
@ -57,6 +61,7 @@ internal sealed class AdminNameOverlay : Overlay
|
||||||
_entityLookup = entityLookup;
|
_entityLookup = entityLookup;
|
||||||
_userInterfaceManager = userInterfaceManager;
|
_userInterfaceManager = userInterfaceManager;
|
||||||
_roles = roles;
|
_roles = roles;
|
||||||
|
_prototypeManager = prototypeManager;
|
||||||
ZIndex = 200;
|
ZIndex = 200;
|
||||||
// Setting these to a specific ttf would break the antag symbols
|
// Setting these to a specific ttf would break the antag symbols
|
||||||
_font = resourceCache.NotoStack();
|
_font = resourceCache.NotoStack();
|
||||||
|
|
@ -125,6 +130,14 @@ internal sealed class AdminNameOverlay : Overlay
|
||||||
foreach (var info in sortable.OrderBy(s => s.Item4.Y).ToList())
|
foreach (var info in sortable.OrderBy(s => s.Item4.Y).ToList())
|
||||||
{
|
{
|
||||||
var playerInfo = info.Item1;
|
var playerInfo = info.Item1;
|
||||||
|
var rolePrototype = playerInfo.RoleProto == null
|
||||||
|
? null
|
||||||
|
: _prototypeManager.Index(playerInfo.RoleProto.Value);
|
||||||
|
|
||||||
|
var roleName = Loc.GetString(rolePrototype?.Name ?? RoleTypePrototype.FallbackName);
|
||||||
|
var roleColor = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
|
||||||
|
var roleSymbol = rolePrototype?.Symbol ?? RoleTypePrototype.FallbackSymbol;
|
||||||
|
|
||||||
var aabb = info.Item2;
|
var aabb = info.Item2;
|
||||||
var entity = info.Item3;
|
var entity = info.Item3;
|
||||||
var screenCoordinatesCenter = info.Item4;
|
var screenCoordinatesCenter = info.Item4;
|
||||||
|
|
@ -209,7 +222,7 @@ internal sealed class AdminNameOverlay : Overlay
|
||||||
switch (_overlaySymbolStyle)
|
switch (_overlaySymbolStyle)
|
||||||
{
|
{
|
||||||
case AdminOverlayAntagSymbolStyle.Specific:
|
case AdminOverlayAntagSymbolStyle.Specific:
|
||||||
symbol = playerInfo.RoleProto.Symbol;
|
symbol = roleSymbol;
|
||||||
break;
|
break;
|
||||||
case AdminOverlayAntagSymbolStyle.Basic:
|
case AdminOverlayAntagSymbolStyle.Basic:
|
||||||
symbol = Loc.GetString("player-tab-antag-prefix");
|
symbol = Loc.GetString("player-tab-antag-prefix");
|
||||||
|
|
@ -225,17 +238,17 @@ internal sealed class AdminNameOverlay : Overlay
|
||||||
switch (_overlayFormat)
|
switch (_overlayFormat)
|
||||||
{
|
{
|
||||||
case AdminOverlayAntagFormat.Roletype:
|
case AdminOverlayAntagFormat.Roletype:
|
||||||
color = playerInfo.RoleProto.Color;
|
color = roleColor;
|
||||||
symbol = _filter.Contains(playerInfo.RoleProto) ? symbol : string.Empty;
|
symbol = IsFiltered(playerInfo.RoleProto) ? symbol : string.Empty;
|
||||||
text = _filter.Contains(playerInfo.RoleProto)
|
text = IsFiltered(playerInfo.RoleProto)
|
||||||
? Loc.GetString(playerInfo.RoleProto.Name).ToUpper()
|
? roleName.ToUpper()
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
break;
|
break;
|
||||||
case AdminOverlayAntagFormat.Subtype:
|
case AdminOverlayAntagFormat.Subtype:
|
||||||
color = playerInfo.RoleProto.Color;
|
color = roleColor;
|
||||||
symbol = _filter.Contains(playerInfo.RoleProto) ? symbol : string.Empty;
|
symbol = IsFiltered(playerInfo.RoleProto) ? symbol : string.Empty;
|
||||||
text = _filter.Contains(playerInfo.RoleProto)
|
text = IsFiltered(playerInfo.RoleProto)
|
||||||
? _roles.GetRoleSubtypeLabel(playerInfo.RoleProto.Name, playerInfo.Subtype).ToUpper()
|
? _roles.GetRoleSubtypeLabel(roleName, playerInfo.Subtype).ToUpper()
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -258,4 +271,12 @@ internal sealed class AdminNameOverlay : Overlay
|
||||||
drawnOverlays.Add((screenCoordinatesCenter, currentOffset));
|
drawnOverlays.Add((screenCoordinatesCenter, currentOffset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsFiltered(ProtoId<RoleTypePrototype>? roleProtoId)
|
||||||
|
{
|
||||||
|
if (roleProtoId == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Filter.Contains(roleProtoId.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using Robust.Client.Graphics;
|
||||||
using Robust.Client.ResourceManagement;
|
using Robust.Client.ResourceManagement;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.Administration.Systems
|
namespace Content.Client.Administration.Systems
|
||||||
{
|
{
|
||||||
|
|
@ -17,6 +18,7 @@ namespace Content.Client.Administration.Systems
|
||||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||||
[Dependency] private readonly SharedRoleSystem _roles = default!;
|
[Dependency] private readonly SharedRoleSystem _roles = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
|
|
||||||
private AdminNameOverlay _adminNameOverlay = default!;
|
private AdminNameOverlay _adminNameOverlay = default!;
|
||||||
|
|
||||||
|
|
@ -33,7 +35,8 @@ namespace Content.Client.Administration.Systems
|
||||||
_entityLookup,
|
_entityLookup,
|
||||||
_userInterfaceManager,
|
_userInterfaceManager,
|
||||||
_configurationManager,
|
_configurationManager,
|
||||||
_roles);
|
_roles,
|
||||||
|
_proto);
|
||||||
_adminManager.AdminStatusUpdated += OnAdminStatusUpdated;
|
_adminManager.AdminStatusUpdated += OnAdminStatusUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<Control
|
||||||
|
xmlns="https://spacestation14.io"
|
||||||
|
xmlns:viewport="clr-namespace:Content.Client.Viewport"
|
||||||
|
MouseFilter="Stop">
|
||||||
|
<PanelContainer StyleClasses="BackgroundDark" Name="AdminCameraWindowRoot" Access="Public">
|
||||||
|
<BoxContainer Orientation="Vertical" Access="Public">
|
||||||
|
<!-- Camera -->
|
||||||
|
<Control VerticalExpand="True" Name="CameraViewBox">
|
||||||
|
<viewport:ScalingViewport Name="CameraView"
|
||||||
|
MinSize="100 100"
|
||||||
|
MouseFilter="Ignore" />
|
||||||
|
</Control>
|
||||||
|
<!-- Controller buttons -->
|
||||||
|
<BoxContainer Orientation="Horizontal" Margin="5 5 5 5">
|
||||||
|
<Button StyleClasses="OpenRight" Name="FollowButton" HorizontalExpand="True" Access="Public" Text="{Loc 'admin-camera-window-follow'}" />
|
||||||
|
<Button StyleClasses="OpenLeft" Name="PopControl" HorizontalExpand="True" Access="Public" Text="{Loc 'admin-camera-window-pop-out'}" />
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
</PanelContainer>
|
||||||
|
</Control>
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
using System.Numerics;
|
||||||
|
using Content.Client.Eye;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.Timing;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Client.Administration.UI.AdminCamera;
|
||||||
|
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class AdminCameraControl : Control
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
|
[Dependency] private readonly IClientGameTiming _timing = default!;
|
||||||
|
|
||||||
|
public event Action? OnFollow;
|
||||||
|
public event Action? OnPopoutControl;
|
||||||
|
|
||||||
|
private readonly EyeLerpingSystem _eyeLerpingSystem;
|
||||||
|
private readonly FixedEye _defaultEye = new();
|
||||||
|
private AdminCameraEuiState? _nextState;
|
||||||
|
|
||||||
|
private const float MinimumZoom = 0.1f;
|
||||||
|
private const float MaximumZoom = 2.0f;
|
||||||
|
|
||||||
|
public EntityUid? CurrentCamera;
|
||||||
|
public float Zoom = 1.0f;
|
||||||
|
|
||||||
|
public bool IsPoppedOut;
|
||||||
|
|
||||||
|
public AdminCameraControl()
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
|
_eyeLerpingSystem = _entManager.System<EyeLerpingSystem>();
|
||||||
|
|
||||||
|
CameraView.Eye = _defaultEye;
|
||||||
|
|
||||||
|
FollowButton.OnPressed += _ => OnFollow?.Invoke();
|
||||||
|
PopControl.OnPressed += _ => OnPopoutControl?.Invoke();
|
||||||
|
CameraView.OnResized += OnResized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private new void OnResized()
|
||||||
|
{
|
||||||
|
var width = Math.Max(CameraView.PixelWidth, (int)Math.Floor(CameraView.MinWidth));
|
||||||
|
var height = Math.Max(CameraView.PixelHeight, (int)Math.Floor(CameraView.MinHeight));
|
||||||
|
|
||||||
|
CameraView.ViewportSize = new Vector2i(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void MouseWheel(GUIMouseWheelEventArgs args)
|
||||||
|
{
|
||||||
|
base.MouseWheel(args);
|
||||||
|
|
||||||
|
if (CameraView.Eye == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Zoom = Math.Clamp(Zoom - args.Delta.Y * 0.15f * Zoom, MinimumZoom, MaximumZoom);
|
||||||
|
CameraView.Eye.Zoom = new Vector2(Zoom, Zoom);
|
||||||
|
args.Handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetState(AdminCameraEuiState state)
|
||||||
|
{
|
||||||
|
_nextState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I know that this is awful, but I copied this from the solution editor anyways.
|
||||||
|
// This is needed because EUIs update before the gamestate is applied, which means it will fail to get the uid from the net entity.
|
||||||
|
// The suggestion from the comment in the solution editor saying to use a BUI is not ideal either:
|
||||||
|
// - We would need to bind the UI to an entity, but with how BUIs currently work we cannot open it in the same tick as we spawn that entity on the server.
|
||||||
|
// - We want the UI opened by the user session, not by their currently attached entity. Otherwise it would close in cases where admins move from one entity to another, for example when ghosting.
|
||||||
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
|
{
|
||||||
|
if (_nextState == null || _timing.LastRealTick < _nextState.Tick) // make sure the last gamestate has been applied
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_entManager.TryGetEntity(_nextState.Camera, out var cameraUid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (CurrentCamera == null)
|
||||||
|
{
|
||||||
|
_eyeLerpingSystem.AddEye(cameraUid.Value);
|
||||||
|
CurrentCamera = cameraUid;
|
||||||
|
}
|
||||||
|
else if (CurrentCamera != cameraUid)
|
||||||
|
{
|
||||||
|
_eyeLerpingSystem.RemoveEye(CurrentCamera.Value);
|
||||||
|
_eyeLerpingSystem.AddEye(cameraUid.Value);
|
||||||
|
CurrentCamera = cameraUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_entManager.TryGetComponent<EyeComponent>(CurrentCamera, out var eye))
|
||||||
|
CameraView.Eye = eye.Eye ?? _defaultEye;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
using System.Numerics;
|
||||||
|
using Content.Client.Eui;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.Eui;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
|
||||||
|
namespace Content.Client.Administration.UI.AdminCamera;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Admin Eui for opening a viewport window to observe entities.
|
||||||
|
/// Use the "Open Camera" admin verb or the "camera" command to open.
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed partial class AdminCameraEui : BaseEui
|
||||||
|
{
|
||||||
|
private readonly AdminCameraWindow _window;
|
||||||
|
private readonly AdminCameraControl _control;
|
||||||
|
|
||||||
|
// If not null the camera is in "popped out" mode and is in an external window.
|
||||||
|
private OSWindow? _OSWindow;
|
||||||
|
|
||||||
|
// The last location the window was located at in game.
|
||||||
|
// Is used for getting knowing where to "pop in" external windows.
|
||||||
|
private Vector2 _lastLocation;
|
||||||
|
|
||||||
|
public AdminCameraEui()
|
||||||
|
{
|
||||||
|
_window = new AdminCameraWindow();
|
||||||
|
_control = new AdminCameraControl();
|
||||||
|
|
||||||
|
_window.Contents.AddChild(_control);
|
||||||
|
|
||||||
|
_control.OnFollow += () => SendMessage(new AdminCameraFollowMessage());
|
||||||
|
_window.OnClose += () =>
|
||||||
|
{
|
||||||
|
if (!_control.IsPoppedOut)
|
||||||
|
SendMessage(new CloseEuiMessage());
|
||||||
|
};
|
||||||
|
|
||||||
|
_control.OnPopoutControl += () =>
|
||||||
|
{
|
||||||
|
if (_control.IsPoppedOut)
|
||||||
|
PopIn();
|
||||||
|
else
|
||||||
|
PopOut();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop the window out into an external OS window
|
||||||
|
private void PopOut()
|
||||||
|
{
|
||||||
|
_lastLocation = _window.Position;
|
||||||
|
|
||||||
|
// TODO: When there is a way to have a minimum window size, enforce something!
|
||||||
|
_OSWindow = new OSWindow
|
||||||
|
{
|
||||||
|
SetSize = _window.Size,
|
||||||
|
Title = _window.Title ?? Loc.GetString("admin-camera-window-title-placeholder"),
|
||||||
|
};
|
||||||
|
|
||||||
|
_OSWindow.Show();
|
||||||
|
|
||||||
|
if (_OSWindow.Root == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_control.Orphan();
|
||||||
|
_OSWindow.Root.AddChild(_control);
|
||||||
|
|
||||||
|
_OSWindow.Closed += () =>
|
||||||
|
{
|
||||||
|
if (_control.IsPoppedOut)
|
||||||
|
SendMessage(new CloseEuiMessage());
|
||||||
|
};
|
||||||
|
|
||||||
|
_control.IsPoppedOut = true;
|
||||||
|
_control.PopControl.Text = Loc.GetString("admin-camera-window-pop-in");
|
||||||
|
|
||||||
|
_window.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop the window back into the in game window.
|
||||||
|
private void PopIn()
|
||||||
|
{
|
||||||
|
_control.Orphan();
|
||||||
|
_window.Contents.AddChild(_control);
|
||||||
|
|
||||||
|
_window.Open(_lastLocation);
|
||||||
|
|
||||||
|
_control.IsPoppedOut = false;
|
||||||
|
_control.PopControl.Text = Loc.GetString("admin-camera-window-pop-out");
|
||||||
|
|
||||||
|
_OSWindow?.Close();
|
||||||
|
_OSWindow = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Opened()
|
||||||
|
{
|
||||||
|
base.Opened();
|
||||||
|
_window.OpenCentered();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Closed()
|
||||||
|
{
|
||||||
|
base.Closed();
|
||||||
|
_window.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void HandleState(EuiStateBase baseState)
|
||||||
|
{
|
||||||
|
if (baseState is not AdminCameraEuiState state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_window.SetState(state);
|
||||||
|
_control.SetState(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
|
Title="{Loc admin-camera-window-title-placeholder}"
|
||||||
|
SetSize="425 550"
|
||||||
|
MinSize="200 225"
|
||||||
|
Name="Window">
|
||||||
|
</DefaultWindow>
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
|
||||||
|
namespace Content.Client.Administration.UI.AdminCamera;
|
||||||
|
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class AdminCameraWindow : DefaultWindow
|
||||||
|
{
|
||||||
|
public AdminCameraWindow()
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
|
ContentsContainer.Margin = new Thickness(5, 0, 5, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetState(AdminCameraEuiState state)
|
||||||
|
{
|
||||||
|
Title = Loc.GetString("admin-camera-window-title", ("name", state.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<DefaultWindow
|
<DefaultWindow
|
||||||
xmlns="https://spacestation14.io"
|
xmlns="https://spacestation14.io"
|
||||||
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||||
Title="{Loc ban-panel-title}" MinSize="350 500">
|
Title="{Loc ban-panel-title}" MinSize="410 500">
|
||||||
<BoxContainer Orientation="Vertical">
|
<BoxContainer Orientation="Vertical">
|
||||||
<TabContainer Name="Tabs" VerticalExpand="True">
|
<TabContainer Name="Tabs" VerticalExpand="True">
|
||||||
<!-- Basic info -->
|
<!-- Basic info -->
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Numerics;
|
||||||
using Content.Client.Administration.UI.CustomControls;
|
using Content.Client.Administration.UI.CustomControls;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
|
@ -31,14 +33,21 @@ public sealed partial class BanPanel : DefaultWindow
|
||||||
private uint Multiplier { get; set; }
|
private uint Multiplier { get; set; }
|
||||||
private bool HasBanFlag { get; set; }
|
private bool HasBanFlag { get; set; }
|
||||||
private TimeSpan? ButtonResetOn { get; set; }
|
private TimeSpan? ButtonResetOn { get; set; }
|
||||||
|
|
||||||
// This is less efficient than just holding a reference to the root control and enumerating children, but you
|
// This is less efficient than just holding a reference to the root control and enumerating children, but you
|
||||||
// have to know how the controls are nested, which makes the code more complicated.
|
// have to know how the controls are nested, which makes the code more complicated.
|
||||||
private readonly List<CheckBox> _roleCheckboxes = new();
|
// Role group name -> the role buttons themselves.
|
||||||
|
private readonly Dictionary<string, List<Button>> _roleCheckboxes = new();
|
||||||
private readonly ISawmill _banpanelSawmill;
|
private readonly ISawmill _banpanelSawmill;
|
||||||
|
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly ILogManager _logManager = default!;
|
[Dependency] private readonly ILogManager _logManager = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||||
|
|
||||||
|
private const string ExpandedArrow = "▼";
|
||||||
|
private const string ContractedArrow = "▶";
|
||||||
|
|
||||||
private enum TabNumbers
|
private enum TabNumbers
|
||||||
{
|
{
|
||||||
|
|
@ -144,47 +153,90 @@ public sealed partial class BanPanel : DefaultWindow
|
||||||
|
|
||||||
ReasonTextEdit.Placeholder = new Rope.Leaf(Loc.GetString("ban-panel-reason"));
|
ReasonTextEdit.Placeholder = new Rope.Leaf(Loc.GetString("ban-panel-reason"));
|
||||||
|
|
||||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
var departmentJobs = _protoMan.EnumeratePrototypes<DepartmentPrototype>()
|
||||||
foreach (var proto in prototypeManager.EnumeratePrototypes<DepartmentPrototype>())
|
.OrderBy(x => x.Weight);
|
||||||
|
foreach (var proto in departmentJobs)
|
||||||
{
|
{
|
||||||
CreateRoleGroup(proto.ID, proto.Roles.Select(p => p.Id), proto.Color);
|
var roles = proto.Roles.Select(x => _protoMan.Index(x))
|
||||||
|
.OrderBy(x => x.ID);
|
||||||
|
CreateRoleGroup(proto.ID, proto.Color, roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateRoleGroup("Antagonist", prototypeManager.EnumeratePrototypes<AntagPrototype>().Select(p => p.ID), Color.Red);
|
var antagRoles = _protoMan.EnumeratePrototypes<AntagPrototype>()
|
||||||
|
.OrderBy(x => x.ID);
|
||||||
|
CreateRoleGroup("Antagonist", Color.Red, antagRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateRoleGroup(string roleName, IEnumerable<string> roleList, Color color)
|
/// <summary>
|
||||||
|
/// Creates a "Role group" which stores information and logic for one "group" of roll bans.
|
||||||
|
/// For example, all antags are one group, logi is a group, medical is a group, etc...
|
||||||
|
/// </summary>
|
||||||
|
private void CreateRoleGroup<T>(string groupName, Color color, IEnumerable<T> roles) where T : class, IPrototype
|
||||||
{
|
{
|
||||||
var outerContainer = new BoxContainer
|
var outerContainer = new BoxContainer
|
||||||
{
|
{
|
||||||
Name = $"{roleName}GroupOuterBox",
|
Name = $"{groupName}GroupOuterBox",
|
||||||
HorizontalExpand = true,
|
HorizontalExpand = true,
|
||||||
VerticalExpand = true,
|
VerticalExpand = true,
|
||||||
Orientation = BoxContainer.LayoutOrientation.Vertical,
|
Orientation = BoxContainer.LayoutOrientation.Vertical,
|
||||||
Margin = new Thickness(4)
|
Margin = new Thickness(4),
|
||||||
};
|
};
|
||||||
var departmentCheckbox = new CheckBox
|
|
||||||
|
// Stores stuff like ban all and expand buttons.
|
||||||
|
var roleGroupHeader = new BoxContainer
|
||||||
{
|
{
|
||||||
Name = $"{roleName}GroupCheckbox",
|
Orientation = BoxContainer.LayoutOrientation.Horizontal,
|
||||||
Text = roleName,
|
|
||||||
Modulate = color,
|
|
||||||
HorizontalAlignment = HAlignment.Left
|
|
||||||
};
|
};
|
||||||
outerContainer.AddChild(departmentCheckbox);
|
|
||||||
var innerContainer = new BoxContainer
|
// Stores the role checkboxes themselves.
|
||||||
|
var innerContainer = new GridContainer
|
||||||
{
|
{
|
||||||
Name = $"{roleName}GroupInnerBox",
|
Name = $"{groupName}GroupInnerBox",
|
||||||
HorizontalExpand = true,
|
HorizontalExpand = true,
|
||||||
Orientation = BoxContainer.LayoutOrientation.Horizontal
|
Columns = 2,
|
||||||
|
Visible = false,
|
||||||
|
Margin = new Thickness(15, 5, 0, 5),
|
||||||
};
|
};
|
||||||
departmentCheckbox.OnToggled += args =>
|
|
||||||
|
var roleGroupCheckbox = CreateRoleGroupHeader(groupName, roleGroupHeader, color, innerContainer);
|
||||||
|
|
||||||
|
outerContainer.AddChild(roleGroupHeader);
|
||||||
|
|
||||||
|
// Add the roles themselves
|
||||||
|
foreach (var role in roles)
|
||||||
{
|
{
|
||||||
foreach (var child in innerContainer.Children)
|
AddRoleCheckbox(groupName, role.ID, innerContainer, roleGroupCheckbox);
|
||||||
{
|
|
||||||
if (child is CheckBox c)
|
|
||||||
{
|
|
||||||
c.Pressed = args.Pressed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outerContainer.AddChild(innerContainer);
|
||||||
|
|
||||||
|
RolesContainer.AddChild(new PanelContainer
|
||||||
|
{
|
||||||
|
PanelOverride = new StyleBoxFlat
|
||||||
|
{
|
||||||
|
BackgroundColor = color
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RolesContainer.AddChild(outerContainer);
|
||||||
|
RolesContainer.AddChild(new HSeparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Button CreateRoleGroupHeader(string groupName, BoxContainer header, Color color, GridContainer innerContainer)
|
||||||
|
{
|
||||||
|
var roleGroupCheckbox = new Button
|
||||||
|
{
|
||||||
|
Name = $"{groupName}GroupCheckbox",
|
||||||
|
Text = "Ban all",
|
||||||
|
Margin = new Thickness(0, 0, 5, 0),
|
||||||
|
ToggleMode = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// When this is toggled, toggle all buttons in this group so they match.
|
||||||
|
roleGroupCheckbox.OnToggled += args =>
|
||||||
|
{
|
||||||
|
foreach (var role in _roleCheckboxes[groupName])
|
||||||
|
{
|
||||||
|
role.Pressed = args.Pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.Pressed)
|
if (args.Pressed)
|
||||||
|
|
@ -199,17 +251,14 @@ public sealed partial class BanPanel : DefaultWindow
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var childContainer in RolesContainer.Children)
|
foreach (var roleButtons in _roleCheckboxes.Values)
|
||||||
{
|
{
|
||||||
if (childContainer is Container)
|
foreach (var button in roleButtons)
|
||||||
{
|
{
|
||||||
foreach (var child in childContainer.Children)
|
if (button.Pressed)
|
||||||
{
|
|
||||||
if (child is CheckBox { Pressed: true })
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!Enum.TryParse(_cfg.GetCVar(CCVars.RoleBanDefaultSeverity), true, out NoteSeverity newSeverity))
|
if (!Enum.TryParse(_cfg.GetCVar(CCVars.RoleBanDefaultSeverity), true, out NoteSeverity newSeverity))
|
||||||
{
|
{
|
||||||
|
|
@ -220,38 +269,72 @@ public sealed partial class BanPanel : DefaultWindow
|
||||||
SeverityOption.SelectId((int) newSeverity);
|
SeverityOption.SelectId((int) newSeverity);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
outerContainer.AddChild(innerContainer);
|
|
||||||
foreach (var role in roleList)
|
var hideButton = new Button
|
||||||
{
|
{
|
||||||
AddRoleCheckbox(role, innerContainer, departmentCheckbox);
|
Text = Loc.GetString("role-bans-expand-roles") + " " + ContractedArrow,
|
||||||
}
|
ToggleMode = true,
|
||||||
RolesContainer.AddChild(new PanelContainer
|
};
|
||||||
|
hideButton.OnPressed += args =>
|
||||||
{
|
{
|
||||||
PanelOverride = new StyleBoxFlat
|
innerContainer.Visible = args.Button.Pressed;
|
||||||
|
((Button)args.Button).Text = args.Button.Pressed
|
||||||
|
? Loc.GetString("role-bans-contract-roles") + " " + ExpandedArrow
|
||||||
|
: Loc.GetString("role-bans-expand-roles") + " " + ContractedArrow;
|
||||||
|
};
|
||||||
|
header.AddChild(new Label
|
||||||
{
|
{
|
||||||
BackgroundColor = color
|
Text = groupName,
|
||||||
}
|
Modulate = color,
|
||||||
|
Margin = new Thickness(0, 0, 5, 0),
|
||||||
});
|
});
|
||||||
RolesContainer.AddChild(outerContainer);
|
header.AddChild(roleGroupCheckbox);
|
||||||
RolesContainer.AddChild(new HSeparator());
|
header.AddChild(hideButton);
|
||||||
|
return roleGroupCheckbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddRoleCheckbox(string role, Control container, CheckBox header)
|
/// <summary>
|
||||||
|
/// Adds a checkbutton specifically for one "role" in a "group"
|
||||||
|
/// E.g. it would add the Chief Medical Officer "role" into the "Medical" group.
|
||||||
|
/// </summary>
|
||||||
|
private void AddRoleCheckbox(string group, string role, GridContainer roleGroupInnerContainer, Button roleGroupCheckbox)
|
||||||
{
|
{
|
||||||
var roleCheckbox = new CheckBox
|
var roleCheckboxContainer = new BoxContainer();
|
||||||
|
var roleCheckButton = new Button
|
||||||
{
|
{
|
||||||
Name = $"{role}RoleCheckbox",
|
Name = $"{role}RoleCheckbox",
|
||||||
Text = role
|
Text = role,
|
||||||
|
ToggleMode = true,
|
||||||
};
|
};
|
||||||
roleCheckbox.OnToggled += args =>
|
roleCheckButton.OnToggled += args =>
|
||||||
{
|
{
|
||||||
if (args is { Pressed: true, Button.Parent: { } } && args.Button.Parent.Children.Where(e => e is CheckBox).All(e => ((CheckBox) e).Pressed))
|
// Checks the role group checkbox if all the children are pressed
|
||||||
header.Pressed = args.Pressed;
|
if (args.Pressed && _roleCheckboxes[group].All(e => e.Pressed))
|
||||||
|
roleGroupCheckbox.Pressed = args.Pressed;
|
||||||
else
|
else
|
||||||
header.Pressed = false;
|
roleGroupCheckbox.Pressed = false;
|
||||||
};
|
};
|
||||||
container.AddChild(roleCheckbox);
|
|
||||||
_roleCheckboxes.Add(roleCheckbox);
|
// This is adding the icon before the role name
|
||||||
|
// Yeah, this is sus, but having to split the functions up and stuff is worse imo.
|
||||||
|
if (_protoMan.TryIndex<JobPrototype>(role, out var jobPrototype) && _protoMan.TryIndex(jobPrototype.Icon, out var iconProto))
|
||||||
|
{
|
||||||
|
var jobIconTexture = new TextureRect
|
||||||
|
{
|
||||||
|
Texture = _entMan.System<SpriteSystem>().Frame0(iconProto.Icon),
|
||||||
|
TextureScale = new Vector2(2.5f, 2.5f),
|
||||||
|
Stretch = TextureRect.StretchMode.KeepCentered,
|
||||||
|
Margin = new Thickness(5, 0, 0, 0),
|
||||||
|
};
|
||||||
|
roleCheckboxContainer.AddChild(jobIconTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
roleCheckboxContainer.AddChild(roleCheckButton);
|
||||||
|
|
||||||
|
roleGroupInnerContainer.AddChild(roleCheckboxContainer);
|
||||||
|
|
||||||
|
_roleCheckboxes.TryAdd(group, []);
|
||||||
|
_roleCheckboxes[group].Add(roleCheckButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateBanFlag(bool newFlag)
|
public void UpdateBanFlag(bool newFlag)
|
||||||
|
|
@ -469,7 +552,13 @@ public sealed partial class BanPanel : DefaultWindow
|
||||||
if (_roleCheckboxes.Count == 0)
|
if (_roleCheckboxes.Count == 0)
|
||||||
throw new DebugAssertException("RoleCheckboxes was empty");
|
throw new DebugAssertException("RoleCheckboxes was empty");
|
||||||
|
|
||||||
rolesList.AddRange(_roleCheckboxes.Where(c => c is { Pressed: true, Text: { } }).Select(c => c.Text!));
|
foreach (var button in _roleCheckboxes.Values.SelectMany(departmentButtons => departmentButtons))
|
||||||
|
{
|
||||||
|
if (button is { Pressed: true, Text: not null })
|
||||||
|
{
|
||||||
|
rolesList.Add(button.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rolesList.Count == 0)
|
if (rolesList.Count == 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,21 @@
|
||||||
<OptionButton Name="SolutionOption" HorizontalExpand="True"/>
|
<OptionButton Name="SolutionOption" HorizontalExpand="True"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|
||||||
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 4">
|
||||||
|
<Button Name="VVButton"
|
||||||
|
Text="{Loc 'admin-solutions-window-vv-button'}"
|
||||||
|
ToolTip="{Loc 'admin-solutions-window-vv-button-tooltip'}"
|
||||||
|
Disabled="True"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
StyleClasses="OpenRight"/>
|
||||||
|
<Button Name="SolutionButton"
|
||||||
|
Text="{Loc 'admin-solutions-window-solution-button'}"
|
||||||
|
ToolTip="{Loc 'admin-solutions-window-solution-button-tooltip'}"
|
||||||
|
Disabled="True"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
StyleClasses="OpenLeft"/>
|
||||||
|
</BoxContainer>
|
||||||
|
|
||||||
<!-- The total volume / capacity of the solution -->
|
<!-- The total volume / capacity of the solution -->
|
||||||
<BoxContainer Name="VolumeBox" Orientation="Vertical" HorizontalExpand="True" Margin="0 4"/>
|
<BoxContainer Name="VolumeBox" Orientation="Vertical" HorizontalExpand="True" Margin="0 4"/>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Content.Client.Administration.Managers;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
|
@ -20,6 +21,7 @@ namespace Content.Client.Administration.UI.ManageSolutions
|
||||||
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
|
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IClientGameTiming _timing = default!;
|
[Dependency] private readonly IClientGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly IClientAdminManager _admin = default!;
|
||||||
|
|
||||||
private NetEntity _target = NetEntity.Invalid;
|
private NetEntity _target = NetEntity.Invalid;
|
||||||
private string? _selectedSolution;
|
private string? _selectedSolution;
|
||||||
|
|
@ -34,6 +36,11 @@ namespace Content.Client.Administration.UI.ManageSolutions
|
||||||
|
|
||||||
SolutionOption.OnItemSelected += SolutionSelected;
|
SolutionOption.OnItemSelected += SolutionSelected;
|
||||||
AddButton.OnPressed += OpenAddReagentWindow;
|
AddButton.OnPressed += OpenAddReagentWindow;
|
||||||
|
VVButton.OnPressed += OpenVVWindow;
|
||||||
|
SolutionButton.OnPressed += OpenSolutionWindow;
|
||||||
|
|
||||||
|
VVButton.Disabled = !_admin.CanViewVar();
|
||||||
|
SolutionButton.Disabled = !_admin.CanViewVar();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Close()
|
public override void Close()
|
||||||
|
|
@ -271,6 +278,32 @@ namespace Content.Client.Administration.UI.ManageSolutions
|
||||||
_addReagentWindow.OpenCentered();
|
_addReagentWindow.OpenCentered();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Open the corresponding solution entity in a ViewVariables window.
|
||||||
|
/// </summary>
|
||||||
|
private void OpenVVWindow(BaseButton.ButtonEventArgs obj)
|
||||||
|
{
|
||||||
|
if (_solutions == null
|
||||||
|
|| _selectedSolution == null
|
||||||
|
|| !_solutions.TryGetValue(_selectedSolution, out var uid)
|
||||||
|
|| !_entityManager.TryGetNetEntity(uid, out var netEntity))
|
||||||
|
return;
|
||||||
|
_consoleHost.ExecuteCommand($"vv {netEntity}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Open the corresponding Solution instance in a ViewVariables window.
|
||||||
|
/// </summary>
|
||||||
|
private void OpenSolutionWindow(BaseButton.ButtonEventArgs obj)
|
||||||
|
{
|
||||||
|
if (_solutions == null
|
||||||
|
|| _selectedSolution == null
|
||||||
|
|| !_solutions.TryGetValue(_selectedSolution, out var uid)
|
||||||
|
|| !_entityManager.TryGetNetEntity(uid, out var netEntity))
|
||||||
|
return;
|
||||||
|
_consoleHost.ExecuteCommand($"vv /entity/{netEntity}/Solution/Solution");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When a new solution is selected, set _selectedSolution and update the reagent list.
|
/// When a new solution is selected, set _selectedSolution and update the reagent list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
<Button Name="FreezeAndMuteToggleButton" Text="{Loc player-panel-freeze-and-mute}" Disabled="True"/>
|
<Button Name="FreezeAndMuteToggleButton" Text="{Loc player-panel-freeze-and-mute}" Disabled="True"/>
|
||||||
<Button Name="BanButton" Text="{Loc player-panel-ban}" Disabled="True"/>
|
<Button Name="BanButton" Text="{Loc player-panel-ban}" Disabled="True"/>
|
||||||
<controls:ConfirmButton Name="RejuvenateButton" Text="{Loc player-panel-rejuvenate}" Disabled="True"/>
|
<controls:ConfirmButton Name="RejuvenateButton" Text="{Loc player-panel-rejuvenate}" Disabled="True"/>
|
||||||
|
<Button Name="CameraButton" Text="{Loc player-panel-camera}" Disabled="True"/>
|
||||||
</GridContainer>
|
</GridContainer>
|
||||||
<Button Name="JobWhitelistsButton" Text="{Loc player-panel-job-whitelists}" SetWidth="136" SetHeight="27" Disabled="True"/> <!-- DeltaV: Job whitelists -->
|
<Button Name="JobWhitelistsButton" Text="{Loc player-panel-job-whitelists}" SetWidth="136" SetHeight="27" Disabled="True"/> <!-- DeltaV: Job whitelists -->
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ public sealed partial class PlayerPanel : FancyWindow
|
||||||
public event Action<NetUserId?>? OnOpenBans;
|
public event Action<NetUserId?>? OnOpenBans;
|
||||||
public event Action<NetUserId?>? OnAhelp;
|
public event Action<NetUserId?>? OnAhelp;
|
||||||
public event Action<string?>? OnKick;
|
public event Action<string?>? OnKick;
|
||||||
|
public event Action<string?>? OnCamera;
|
||||||
public event Action<NetUserId?>? OnOpenBanPanel;
|
public event Action<NetUserId?>? OnOpenBanPanel;
|
||||||
public event Action<NetUserId?, bool>? OnWhitelistToggle;
|
public event Action<NetUserId?, bool>? OnWhitelistToggle;
|
||||||
public event Action? OnFollow;
|
public event Action? OnFollow;
|
||||||
|
|
@ -40,6 +41,7 @@ public sealed partial class PlayerPanel : FancyWindow
|
||||||
UsernameCopyButton.OnPressed += _ => OnUsernameCopy?.Invoke(TargetUsername ?? "");
|
UsernameCopyButton.OnPressed += _ => OnUsernameCopy?.Invoke(TargetUsername ?? "");
|
||||||
BanButton.OnPressed += _ => OnOpenBanPanel?.Invoke(TargetPlayer);
|
BanButton.OnPressed += _ => OnOpenBanPanel?.Invoke(TargetPlayer);
|
||||||
KickButton.OnPressed += _ => OnKick?.Invoke(TargetUsername);
|
KickButton.OnPressed += _ => OnKick?.Invoke(TargetUsername);
|
||||||
|
CameraButton.OnPressed += _ => OnCamera?.Invoke(TargetUsername);
|
||||||
NotesButton.OnPressed += _ => OnOpenNotes?.Invoke(TargetPlayer);
|
NotesButton.OnPressed += _ => OnOpenNotes?.Invoke(TargetPlayer);
|
||||||
ShowBansButton.OnPressed += _ => OnOpenBans?.Invoke(TargetPlayer);
|
ShowBansButton.OnPressed += _ => OnOpenBans?.Invoke(TargetPlayer);
|
||||||
AhelpButton.OnPressed += _ => OnAhelp?.Invoke(TargetPlayer);
|
AhelpButton.OnPressed += _ => OnAhelp?.Invoke(TargetPlayer);
|
||||||
|
|
@ -125,6 +127,7 @@ public sealed partial class PlayerPanel : FancyWindow
|
||||||
{
|
{
|
||||||
BanButton.Disabled = !_adminManager.CanCommand("banpanel");
|
BanButton.Disabled = !_adminManager.CanCommand("banpanel");
|
||||||
KickButton.Disabled = !_adminManager.CanCommand("kick");
|
KickButton.Disabled = !_adminManager.CanCommand("kick");
|
||||||
|
CameraButton.Disabled = !_adminManager.CanCommand("camera");
|
||||||
NotesButton.Disabled = !_adminManager.CanCommand("adminnotes");
|
NotesButton.Disabled = !_adminManager.CanCommand("adminnotes");
|
||||||
ShowBansButton.Disabled = !_adminManager.CanCommand("banlist");
|
ShowBansButton.Disabled = !_adminManager.CanCommand("banlist");
|
||||||
WhitelistToggle.Disabled =
|
WhitelistToggle.Disabled =
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ public sealed class PlayerPanelEui : BaseEui
|
||||||
PlayerPanel.OnOpenNotes += id => _console.ExecuteCommand($"adminnotes \"{id}\"");
|
PlayerPanel.OnOpenNotes += id => _console.ExecuteCommand($"adminnotes \"{id}\"");
|
||||||
// Kick command does not support GUIDs
|
// Kick command does not support GUIDs
|
||||||
PlayerPanel.OnKick += username => _console.ExecuteCommand($"kick \"{username}\"");
|
PlayerPanel.OnKick += username => _console.ExecuteCommand($"kick \"{username}\"");
|
||||||
|
PlayerPanel.OnCamera += username => _console.ExecuteCommand($"camera \"{username}\"");
|
||||||
PlayerPanel.OnOpenBanPanel += id => _console.ExecuteCommand($"banpanel \"{id}\"");
|
PlayerPanel.OnOpenBanPanel += id => _console.ExecuteCommand($"banpanel \"{id}\"");
|
||||||
PlayerPanel.OnOpenBans += id => _console.ExecuteCommand($"banlist \"{id}\"");
|
PlayerPanel.OnOpenBans += id => _console.ExecuteCommand($"banlist \"{id}\"");
|
||||||
PlayerPanel.OnAhelp += id => _console.ExecuteCommand($"openahelp \"{id}\"");
|
PlayerPanel.OnAhelp += id => _console.ExecuteCommand($"openahelp \"{id}\"");
|
||||||
|
|
@ -37,7 +38,7 @@ public sealed class PlayerPanelEui : BaseEui
|
||||||
PlayerPanel.OnFreeze += () => SendMessage(new PlayerPanelFreezeMessage());
|
PlayerPanel.OnFreeze += () => SendMessage(new PlayerPanelFreezeMessage());
|
||||||
PlayerPanel.OnLogs += () => SendMessage(new PlayerPanelLogsMessage());
|
PlayerPanel.OnLogs += () => SendMessage(new PlayerPanelLogsMessage());
|
||||||
PlayerPanel.OnRejuvenate += () => SendMessage(new PlayerPanelRejuvenationMessage());
|
PlayerPanel.OnRejuvenate += () => SendMessage(new PlayerPanelRejuvenationMessage());
|
||||||
PlayerPanel.OnDelete+= () => SendMessage(new PlayerPanelDeleteMessage());
|
PlayerPanel.OnDelete += () => SendMessage(new PlayerPanelDeleteMessage());
|
||||||
PlayerPanel.OnOpenJobWhitelists += id => _console.ExecuteCommand($"jobwhitelists \"{id}\""); // DeltaV
|
PlayerPanel.OnOpenJobWhitelists += id => _console.ExecuteCommand($"jobwhitelists \"{id}\""); // DeltaV
|
||||||
PlayerPanel.OnFollow += () => SendMessage(new PlayerPanelFollowMessage());
|
PlayerPanel.OnFollow += () => SendMessage(new PlayerPanelFollowMessage());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -132,8 +132,8 @@ public sealed partial class ObjectsTab : Control
|
||||||
entry.OnTeleport += TeleportTo;
|
entry.OnTeleport += TeleportTo;
|
||||||
entry.OnDelete += Delete;
|
entry.OnDelete += Delete;
|
||||||
button.ToolTip = $"{info.Name}, {info.Entity}";
|
button.ToolTip = $"{info.Name}, {info.Entity}";
|
||||||
|
|
||||||
button.AddChild(entry);
|
button.AddChild(entry);
|
||||||
|
button.StyleClasses.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool DataFilterCondition(string filter, ListData listData)
|
private bool DataFilterCondition(string filter, ListData listData)
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,7 @@ public sealed partial class PlayerTab : Control
|
||||||
_playerTabSymbolSetting);
|
_playerTabSymbolSetting);
|
||||||
button.AddChild(entry);
|
button.AddChild(entry);
|
||||||
button.ToolTip = $"{player.Username}, {player.CharacterName}, {player.IdentityName}, {player.StartingJob}";
|
button.ToolTip = $"{player.Username}, {player.CharacterName}, {player.IdentityName}, {player.StartingJob}";
|
||||||
|
button.StyleClasses.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.Mind;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.Administration.UI.Tabs.PlayerTab;
|
namespace Content.Client.Administration.UI.Tabs.PlayerTab;
|
||||||
|
|
||||||
|
|
@ -11,6 +13,7 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab;
|
||||||
public sealed partial class PlayerTabEntry : PanelContainer
|
public sealed partial class PlayerTabEntry : PanelContainer
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||||
|
|
||||||
public PlayerTabEntry(
|
public PlayerTabEntry(
|
||||||
PlayerInfo player,
|
PlayerInfo player,
|
||||||
|
|
@ -23,6 +26,8 @@ public sealed partial class PlayerTabEntry : PanelContainer
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
var roles = _entMan.System<SharedRoleSystem>();
|
var roles = _entMan.System<SharedRoleSystem>();
|
||||||
|
|
||||||
|
var rolePrototype = player.RoleProto == null ? null : _prototype.Index(player.RoleProto.Value);
|
||||||
|
|
||||||
UsernameLabel.Text = player.Username;
|
UsernameLabel.Text = player.Username;
|
||||||
if (!player.Connected)
|
if (!player.Connected)
|
||||||
UsernameLabel.StyleClasses.Add("Disabled");
|
UsernameLabel.StyleClasses.Add("Disabled");
|
||||||
|
|
@ -57,19 +62,19 @@ public sealed partial class PlayerTabEntry : PanelContainer
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case AdminPlayerTabSymbolOption.Specific:
|
case AdminPlayerTabSymbolOption.Specific:
|
||||||
symbol = player.Antag ? player.RoleProto.Symbol : string.Empty;
|
symbol = player.Antag ? rolePrototype?.Symbol ?? RoleTypePrototype.FallbackSymbol : string.Empty;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterLabel.Text = Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", player.CharacterName));
|
CharacterLabel.Text = Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", player.CharacterName));
|
||||||
|
|
||||||
if (player.Antag && colorAntags)
|
if (player.Antag && colorAntags)
|
||||||
CharacterLabel.FontColorOverride = player.RoleProto.Color;
|
CharacterLabel.FontColorOverride = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
|
||||||
if (player.IdentityName != player.CharacterName)
|
if (player.IdentityName != player.CharacterName)
|
||||||
CharacterLabel.Text += $" [{player.IdentityName}]";
|
CharacterLabel.Text += $" [{player.IdentityName}]";
|
||||||
|
|
||||||
var roletype = RoleTypeLabel.Text = Loc.GetString(player.RoleProto.Name);
|
var roletype = RoleTypeLabel.Text = Loc.GetString(rolePrototype?.Name ?? RoleTypePrototype.FallbackName);
|
||||||
var subtype = roles.GetRoleSubtypeLabel(player.RoleProto.Name, player.Subtype);
|
var subtype = roles.GetRoleSubtypeLabel(rolePrototype?.Name ?? RoleTypePrototype.FallbackName, player.Subtype);
|
||||||
switch (roleSetting)
|
switch (roleSetting)
|
||||||
{
|
{
|
||||||
case AdminPlayerTabRoleTypeOption.RoleTypeSubtype:
|
case AdminPlayerTabRoleTypeOption.RoleTypeSubtype:
|
||||||
|
|
@ -92,7 +97,7 @@ public sealed partial class PlayerTabEntry : PanelContainer
|
||||||
}
|
}
|
||||||
|
|
||||||
if (colorRoles)
|
if (colorRoles)
|
||||||
RoleTypeLabel.FontColorOverride = player.RoleProto.Color;
|
RoleTypeLabel.FontColorOverride = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
|
||||||
BackgroundColorPanel.PanelOverride = styleBoxFlat;
|
BackgroundColorPanel.PanelOverride = styleBoxFlat;
|
||||||
OverallPlaytimeLabel.Text = player.PlaytimeString;
|
OverallPlaytimeLabel.Text = player.PlaytimeString;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,11 +62,11 @@ public sealed class AnomalySystem : SharedAnomalySystem
|
||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<AnomalySupercriticalComponent, SpriteComponent>();
|
var query = EntityQueryEnumerator<AnomalyComponent, AnomalySupercriticalComponent, SpriteComponent>();
|
||||||
|
|
||||||
while (query.MoveNext(out var uid, out var super, out var sprite))
|
while (query.MoveNext(out var uid, out var anomaly, out var super, out var sprite))
|
||||||
{
|
{
|
||||||
var completion = 1f - (float)((super.EndTime - _timing.CurTime) / super.SupercriticalDuration);
|
var completion = 1f - (float) ((super.EndTime - _timing.CurTime) / anomaly.SupercriticalDuration);
|
||||||
var scale = completion * (super.MaxScaleAmount - 1f) + 1f;
|
var scale = completion * (super.MaxScaleAmount - 1f) + 1f;
|
||||||
_sprite.SetScale((uid, sprite), new Vector2(scale, scale));
|
_sprite.SetScale((uid, sprite), new Vector2(scale, scale));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -162,10 +162,10 @@ public sealed partial class AtmosMonitoringConsoleNavMapControl : NavMapControl
|
||||||
{
|
{
|
||||||
var list = new List<AtmosMonitoringConsoleLine>();
|
var list = new List<AtmosMonitoringConsoleLine>();
|
||||||
|
|
||||||
foreach (var ((netId, layer, hexColor), atmosPipeData) in chunk.AtmosPipeData)
|
foreach (var ((netId, layer, pipeColor), atmosPipeData) in chunk.AtmosPipeData)
|
||||||
{
|
{
|
||||||
// Determine the correct coloration for the pipe
|
// Determine the correct coloration for the pipe
|
||||||
var color = Color.FromHex(hexColor) * _basePipeNetColor;
|
var color = pipeColor * _basePipeNetColor;
|
||||||
|
|
||||||
if (FocusNetId != null && FocusNetId != netId)
|
if (FocusNetId != null && FocusNetId != netId)
|
||||||
color *= _unfocusedPipeNetColor;
|
color *= _unfocusedPipeNetColor;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,46 @@
|
||||||
using Content.Client.Atmos.Components;
|
using Content.Client.Atmos.Components;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
using Content.Client.UserInterface.Systems.Storage.Controls;
|
||||||
using Content.Shared.Atmos.Piping;
|
using Content.Shared.Atmos.Piping;
|
||||||
|
using Content.Shared.Hands;
|
||||||
|
using Content.Shared.Atmos.Components;
|
||||||
|
using Content.Shared.Item;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.EntitySystems;
|
namespace Content.Client.Atmos.EntitySystems;
|
||||||
|
|
||||||
public sealed class PipeColorVisualizerSystem : VisualizerSystem<PipeColorVisualsComponent>
|
public sealed class PipeColorVisualizerSystem : VisualizerSystem<PipeColorVisualsComponent>
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedItemSystem _itemSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<PipeColorVisualsComponent, GetInhandVisualsEvent>(OnGetVisuals);
|
||||||
|
SubscribeLocalEvent<PipeColorVisualsComponent, BeforeRenderInGridEvent>(OnDrawInGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method is used to display the color changes of the pipe on the screen..
|
||||||
|
/// </summary>
|
||||||
|
private void OnGetVisuals(Entity<PipeColorVisualsComponent> item, ref GetInhandVisualsEvent args)
|
||||||
|
{
|
||||||
|
foreach (var (_, layerData) in args.Layers)
|
||||||
|
{
|
||||||
|
if (TryComp(item.Owner, out AtmosPipeColorComponent? pipeColor))
|
||||||
|
layerData.Color = pipeColor.Color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method is used to change the pipe's color in a container grid.
|
||||||
|
/// </summary>
|
||||||
|
private void OnDrawInGrid(Entity<PipeColorVisualsComponent> item, ref BeforeRenderInGridEvent args)
|
||||||
|
{
|
||||||
|
if (TryComp(item.Owner, out AtmosPipeColorComponent? pipeColor))
|
||||||
|
args.Color = pipeColor.Color;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnAppearanceChange(EntityUid uid, PipeColorVisualsComponent component, ref AppearanceChangeEvent args)
|
protected override void OnAppearanceChange(EntityUid uid, PipeColorVisualsComponent component, ref AppearanceChangeEvent args)
|
||||||
{
|
{
|
||||||
if (TryComp<SpriteComponent>(uid, out var sprite)
|
if (TryComp<SpriteComponent>(uid, out var sprite)
|
||||||
|
|
@ -15,6 +50,8 @@ public sealed class PipeColorVisualizerSystem : VisualizerSystem<PipeColorVisual
|
||||||
var layer = sprite[PipeVisualLayers.Pipe];
|
var layer = sprite[PipeVisualLayers.Pipe];
|
||||||
layer.Color = color.WithAlpha(layer.Color.A);
|
layer.Color = color.WithAlpha(layer.Color.A);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_itemSystem.VisualsChanged(uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2007/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2007/xaml"
|
||||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||||
MinSize="500 500" Resizable="True" Title="Air Alarm">
|
MinSize="500 500" Resizable="True" Title="{Loc air-alarm-ui-title}">
|
||||||
<BoxContainer Orientation="Vertical" Margin="5 5 5 5">
|
<BoxContainer Orientation="Vertical" Margin="5 5 5 5">
|
||||||
<!-- Status (pressure, temperature, alarm state, device total, address, etc) -->
|
<!-- Status (pressure, temperature, alarm state, device total, address, etc) -->
|
||||||
<BoxContainer Orientation="Horizontal" Margin="0 0 0 2">
|
<BoxContainer Orientation="Horizontal" Margin="0 0 0 2">
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ namespace Content.Client.Atmos.Overlays
|
||||||
{
|
{
|
||||||
public sealed class GasTileOverlay : Overlay
|
public sealed class GasTileOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||||
|
|
||||||
private readonly IEntityManager _entManager;
|
private readonly IEntityManager _entManager;
|
||||||
private readonly IMapManager _mapManager;
|
private readonly IMapManager _mapManager;
|
||||||
private readonly SharedMapSystem _mapSystem;
|
private readonly SharedMapSystem _mapSystem;
|
||||||
|
|
@ -54,7 +56,7 @@ namespace Content.Client.Atmos.Overlays
|
||||||
_mapManager = IoCManager.Resolve<IMapManager>();
|
_mapManager = IoCManager.Resolve<IMapManager>();
|
||||||
_mapSystem = entManager.System<SharedMapSystem>();
|
_mapSystem = entManager.System<SharedMapSystem>();
|
||||||
_xformSys = xformSys;
|
_xformSys = xformSys;
|
||||||
_shader = protoMan.Index<ShaderPrototype>("unshaded").Instance();
|
_shader = protoMan.Index(UnshadedShader).Instance();
|
||||||
ZIndex = GasOverlayZIndex;
|
ZIndex = GasOverlayZIndex;
|
||||||
|
|
||||||
_gasCount = system.VisibleGasId.Length;
|
_gasCount = system.VisibleGasId.Length;
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
|
||||||
_targetTime = _gameTiming.CurTime + TimeSpan.FromSeconds(_cooldown);
|
_targetTime = _gameTiming.CurTime + TimeSpan.FromSeconds(_cooldown);
|
||||||
|
|
||||||
var player = _playerManager.LocalEntity;
|
var player = _playerManager.LocalEntity;
|
||||||
if (!EntityManager.TryGetComponent(player, out TransformComponent? xform))
|
if (!TryComp(player, out TransformComponent? xform))
|
||||||
{
|
{
|
||||||
ClearSounds();
|
ClearSounds();
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
using Content.Shared.Bed;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Client.Bed;
|
|
||||||
|
|
||||||
public sealed class StasisBedSystem : VisualizerSystem<StasisBedVisualsComponent>
|
|
||||||
{
|
|
||||||
protected override void OnAppearanceChange(EntityUid uid, StasisBedVisualsComponent component, ref AppearanceChangeEvent args)
|
|
||||||
{
|
|
||||||
if (args.Sprite != null
|
|
||||||
&& AppearanceSystem.TryGetData<bool>(uid, StasisBedVisuals.IsOn, out var isOn, args.Component))
|
|
||||||
{
|
|
||||||
SpriteSystem.LayerSetVisible((uid, args.Sprite), StasisBedVisualLayers.IsOn, isOn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum StasisBedVisualLayers : byte
|
|
||||||
{
|
|
||||||
IsOn,
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
using Content.Shared.Body.Systems;
|
||||||
|
|
||||||
|
namespace Content.Client.Body.Systems;
|
||||||
|
|
||||||
|
public sealed class BloodstreamSystem : SharedBloodstreamSystem;
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
using Content.Shared.Body.Systems;
|
||||||
|
|
||||||
|
namespace Content.Client.Body.Systems;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public sealed class MetabolizerSystem : SharedMetabolizerSystem;
|
||||||
|
|
@ -18,14 +18,10 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
|
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
|
||||||
|
|
||||||
[ValidatePrototypeId<MixingCategoryPrototype>]
|
private static readonly ProtoId<MixingCategoryPrototype> DefaultMixingCategory = "DummyMix";
|
||||||
private const string DefaultMixingCategory = "DummyMix";
|
private static readonly ProtoId<MixingCategoryPrototype> DefaultGrindCategory = "DummyGrind";
|
||||||
[ValidatePrototypeId<MixingCategoryPrototype>]
|
private static readonly ProtoId<MixingCategoryPrototype> DefaultJuiceCategory = "DummyJuice";
|
||||||
private const string DefaultGrindCategory = "DummyGrind";
|
private static readonly ProtoId<MixingCategoryPrototype> DefaultCondenseCategory = "DummyCondense";
|
||||||
[ValidatePrototypeId<MixingCategoryPrototype>]
|
|
||||||
private const string DefaultJuiceCategory = "DummyJuice";
|
|
||||||
[ValidatePrototypeId<MixingCategoryPrototype>]
|
|
||||||
private const string DefaultCondenseCategory = "DummyCondense";
|
|
||||||
|
|
||||||
private readonly Dictionary<string, List<ReagentSourceData>> _reagentSources = new();
|
private readonly Dictionary<string, List<ReagentSourceData>> _reagentSources = new();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<ClothingComponent, GetEquipmentVisualsEvent>(OnGetVisuals);
|
SubscribeLocalEvent<ClothingComponent, GetEquipmentVisualsEvent>(OnGetVisuals);
|
||||||
SubscribeLocalEvent<ClothingComponent, InventoryTemplateUpdated>(OnInventoryTemplateUpdated);
|
SubscribeLocalEvent<InventoryComponent, InventoryTemplateUpdated>(OnInventoryTemplateUpdated);
|
||||||
|
|
||||||
SubscribeLocalEvent<InventoryComponent, VisualsChangedEvent>(OnVisualsChanged);
|
SubscribeLocalEvent<InventoryComponent, VisualsChangedEvent>(OnVisualsChanged);
|
||||||
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
|
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
|
||||||
|
|
@ -83,20 +83,19 @@ public sealed class ClientClothingSystem : ClothingSystem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInventoryTemplateUpdated(Entity<ClothingComponent> ent, ref InventoryTemplateUpdated args)
|
private void OnInventoryTemplateUpdated(Entity<InventoryComponent> ent, ref InventoryTemplateUpdated args)
|
||||||
{
|
{
|
||||||
UpdateAllSlots(ent.Owner, clothing: ent.Comp);
|
UpdateAllSlots(ent.Owner, ent.Comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateAllSlots(
|
private void UpdateAllSlots(
|
||||||
EntityUid uid,
|
EntityUid uid,
|
||||||
InventoryComponent? inventoryComponent = null,
|
InventoryComponent? inventoryComponent = null)
|
||||||
ClothingComponent? clothing = null)
|
|
||||||
{
|
{
|
||||||
var enumerator = _inventorySystem.GetSlotEnumerator((uid, inventoryComponent));
|
var enumerator = _inventorySystem.GetSlotEnumerator((uid, inventoryComponent));
|
||||||
while (enumerator.NextItem(out var item, out var slot))
|
while (enumerator.NextItem(out var item, out var slot))
|
||||||
{
|
{
|
||||||
RenderEquipment(uid, item, slot.Name, inventoryComponent, clothingComponent: clothing);
|
RenderEquipment(uid, item, slot.Name, inventoryComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ namespace Content.Client.CombatMode
|
||||||
{
|
{
|
||||||
public sealed class ColoredScreenBorderOverlay : Overlay
|
public sealed class ColoredScreenBorderOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> Shader = "ColoredScreenBorder";
|
||||||
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||||
|
|
@ -16,7 +18,7 @@ namespace Content.Client.CombatMode
|
||||||
public ColoredScreenBorderOverlay()
|
public ColoredScreenBorderOverlay()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
_shader = _prototypeManager.Index<ShaderPrototype>("ColoredScreenBorder").Instance();
|
_shader = _prototypeManager.Index(Shader).Instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Draw(in OverlayDrawArgs args)
|
protected override void Draw(in OverlayDrawArgs args)
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,42 @@
|
||||||
using Content.Client.Markers;
|
using Content.Client.Markers;
|
||||||
using Content.Client.Popups;
|
using Content.Client.Popups;
|
||||||
using Content.Client.SubFloor;
|
using Content.Client.SubFloor;
|
||||||
using Content.Shared.SubFloor;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
|
||||||
|
|
||||||
namespace Content.Client.Commands;
|
namespace Content.Client.Commands;
|
||||||
|
|
||||||
internal sealed class ShowMarkersCommand : LocalizedCommands
|
internal sealed class ShowMarkersCommand : LocalizedEntityCommands
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
[Dependency] private readonly MarkerSystem _markerSystem = default!;
|
||||||
|
|
||||||
public override string Command => "showmarkers";
|
public override string Command => "showmarkers";
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
_entitySystemManager.GetEntitySystem<MarkerSystem>().MarkersVisible ^= true;
|
_markerSystem.MarkersVisible ^= true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class ShowSubFloor : LocalizedCommands
|
internal sealed class ShowSubFloor : LocalizedEntityCommands
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
[Dependency] private readonly SubFloorHideSystem _subfloorSystem = default!;
|
||||||
|
|
||||||
public override string Command => "showsubfloor";
|
public override string Command => "showsubfloor";
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
_entitySystemManager.GetEntitySystem<SubFloorHideSystem>().ShowAll ^= true;
|
_subfloorSystem.ShowAll ^= true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class NotifyCommand : LocalizedCommands
|
internal sealed class NotifyCommand : LocalizedEntityCommands
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
|
||||||
public override string Command => "notify";
|
public override string Command => "notify";
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
var message = args[0];
|
_popupSystem.PopupCursor(args[0]);
|
||||||
|
|
||||||
_entitySystemManager.GetEntitySystem<PopupSystem>().PopupCursor(message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,32 +5,27 @@ using Robust.Shared.Containers;
|
||||||
|
|
||||||
namespace Content.Client.Commands;
|
namespace Content.Client.Commands;
|
||||||
|
|
||||||
public sealed class HideMechanismsCommand : LocalizedCommands
|
public sealed class HideMechanismsCommand : LocalizedEntityCommands
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
|
[Dependency] private readonly SpriteSystem _spriteSystem = default!;
|
||||||
|
|
||||||
public override string Command => "hidemechanisms";
|
public override string Command => "hidemechanisms";
|
||||||
|
|
||||||
public override string Description => LocalizationManager.GetString($"cmd-{Command}-desc", ("showMechanismsCommand", ShowMechanismsCommand.CommandName));
|
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
var containerSys = _entityManager.System<SharedContainerSystem>();
|
var query = EntityManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
|
||||||
var spriteSys = _entityManager.System<SpriteSystem>();
|
|
||||||
var query = _entityManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
|
|
||||||
|
|
||||||
while (query.MoveNext(out var uid, out _, out var sprite))
|
while (query.MoveNext(out var uid, out _, out var sprite))
|
||||||
{
|
{
|
||||||
spriteSys.SetContainerOccluded((uid, sprite), false);
|
_spriteSystem.SetContainerOccluded((uid, sprite), false);
|
||||||
|
|
||||||
var tempParent = uid;
|
var tempParent = uid;
|
||||||
while (containerSys.TryGetContainingContainer((tempParent, null, null), out var container))
|
while (_containerSystem.TryGetContainingContainer((tempParent, null, null), out var container))
|
||||||
{
|
{
|
||||||
if (!container.ShowContents)
|
if (!container.ShowContents)
|
||||||
{
|
{
|
||||||
spriteSys.SetContainerOccluded((uid, sprite), true);
|
_spriteSystem.SetContainerOccluded((uid, sprite), true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,29 @@
|
||||||
using Content.Client.Actions;
|
using Content.Client.Actions;
|
||||||
using Content.Client.Mapping;
|
|
||||||
using Content.Client.Markers;
|
using Content.Client.Markers;
|
||||||
using JetBrains.Annotations;
|
using Content.Client.SubFloor;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.State;
|
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
|
||||||
namespace Content.Client.Commands;
|
namespace Content.Client.Commands;
|
||||||
|
|
||||||
[UsedImplicitly]
|
internal sealed class MappingClientSideSetupCommand : LocalizedEntityCommands
|
||||||
internal sealed class MappingClientSideSetupCommand : LocalizedCommands
|
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
|
||||||
[Dependency] private readonly ILightManager _lightManager = default!;
|
[Dependency] private readonly ILightManager _lightManager = default!;
|
||||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
[Dependency] private readonly ActionsSystem _actionSystem = default!;
|
||||||
|
[Dependency] private readonly MarkerSystem _markerSystem = default!;
|
||||||
|
[Dependency] private readonly SubFloorHideSystem _subfloorSystem = default!;
|
||||||
|
|
||||||
public override string Command => "mappingclientsidesetup";
|
public override string Command => "mappingclientsidesetup";
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
if (!_lightManager.LockConsoleAccess)
|
if (_lightManager.LockConsoleAccess)
|
||||||
{
|
return;
|
||||||
_entitySystemManager.GetEntitySystem<MarkerSystem>().MarkersVisible = true;
|
|
||||||
|
_markerSystem.MarkersVisible = true;
|
||||||
_lightManager.Enabled = false;
|
_lightManager.Enabled = false;
|
||||||
shell.ExecuteCommand("showsubfloor");
|
_subfloorSystem.ShowAll = true;
|
||||||
_entitySystemManager.GetEntitySystem<ActionsSystem>().LoadActionAssignments("/mapping_actions.yml", false);
|
_actionSystem.LoadActionAssignments("/mapping_actions.yml", false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,46 @@
|
||||||
using Content.Shared.Damage.Prototypes;
|
using Content.Shared.Damage.Prototypes;
|
||||||
using Content.Shared.Overlays;
|
using Content.Shared.Overlays;
|
||||||
using Robust.Client.Player;
|
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Content.Client.Commands;
|
namespace Content.Client.Commands;
|
||||||
|
|
||||||
public sealed class ShowHealthBarsCommand : LocalizedCommands
|
public sealed class ShowHealthBarsCommand : LocalizedEntityCommands
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
|
||||||
|
|
||||||
public override string Command => "showhealthbars";
|
public override string Command => "showhealthbars";
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
var player = _playerManager.LocalSession;
|
var player = shell.Player;
|
||||||
if (player == null)
|
if (player == null)
|
||||||
{
|
{
|
||||||
shell.WriteError(LocalizationManager.GetString($"cmd-{Command}-error-not-player"));
|
shell.WriteError(Loc.GetString("shell-only-players-can-run-this-command"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var playerEntity = player?.AttachedEntity;
|
if (player.AttachedEntity is not { } playerEntity)
|
||||||
if (!playerEntity.HasValue)
|
|
||||||
{
|
{
|
||||||
shell.WriteError(LocalizationManager.GetString($"cmd-{Command}-error-no-entity"));
|
shell.WriteError(Loc.GetString("shell-must-be-attached-to-entity"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_entityManager.HasComponent<ShowHealthBarsComponent>(playerEntity))
|
if (!EntityManager.HasComponent<ShowHealthBarsComponent>(playerEntity))
|
||||||
{
|
{
|
||||||
var showHealthBarsComponent = new ShowHealthBarsComponent
|
var showHealthBarsComponent = new ShowHealthBarsComponent
|
||||||
{
|
{
|
||||||
DamageContainers = args.Select(arg => new ProtoId<DamageContainerPrototype>(arg)).ToList(),
|
DamageContainers = args.Select(arg => new ProtoId<DamageContainerPrototype>(arg)).ToList(),
|
||||||
HealthStatusIcon = null,
|
HealthStatusIcon = null,
|
||||||
NetSyncEnabled = false
|
NetSyncEnabled = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
_entityManager.AddComponent(playerEntity.Value, showHealthBarsComponent, true);
|
EntityManager.AddComponent(playerEntity, showHealthBarsComponent, true);
|
||||||
|
|
||||||
shell.WriteLine(LocalizationManager.GetString($"cmd-{Command}-notify-enabled", ("args", string.Join(", ", args))));
|
shell.WriteLine(Loc.GetString("cmd-showhealthbars-notify-enabled", ("args", string.Join(", ", args))));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_entityManager.RemoveComponentDeferred<ShowHealthBarsComponent>(playerEntity.Value);
|
|
||||||
shell.WriteLine(LocalizationManager.GetString($"cmd-{Command}-notify-disabled"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
EntityManager.RemoveComponentDeferred<ShowHealthBarsComponent>(playerEntity);
|
||||||
|
shell.WriteLine(Loc.GetString("cmd-showhealthbars-notify-disabled"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,19 @@ using Robust.Shared.Console;
|
||||||
|
|
||||||
namespace Content.Client.Commands;
|
namespace Content.Client.Commands;
|
||||||
|
|
||||||
public sealed class ShowMechanismsCommand : LocalizedCommands
|
public sealed class ShowMechanismsCommand : LocalizedEntityCommands
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
[Dependency] private readonly SpriteSystem _spriteSystem = default!;
|
||||||
|
|
||||||
public const string CommandName = "showmechanisms";
|
public override string Command => "showmechanisms";
|
||||||
|
|
||||||
public override string Command => CommandName;
|
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
var spriteSys = _entManager.System<SpriteSystem>();
|
var query = EntityManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
|
||||||
var query = _entManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
|
|
||||||
|
|
||||||
while (query.MoveNext(out var uid, out _, out var sprite))
|
while (query.MoveNext(out var uid, out _, out var sprite))
|
||||||
{
|
{
|
||||||
spriteSys.SetContainerOccluded((uid, sprite), false);
|
_spriteSystem.SetContainerOccluded((uid, sprite), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -286,14 +286,14 @@ namespace Content.Client.Construction
|
||||||
if (!CheckConstructionConditions(prototype, loc, dir, user, showPopup: true))
|
if (!CheckConstructionConditions(prototype, loc, dir, user, showPopup: true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ghost = EntityManager.SpawnEntity("constructionghost", loc);
|
ghost = Spawn("constructionghost", loc);
|
||||||
var comp = EntityManager.GetComponent<ConstructionGhostComponent>(ghost.Value);
|
var comp = Comp<ConstructionGhostComponent>(ghost.Value);
|
||||||
comp.Prototype = prototype;
|
comp.Prototype = prototype;
|
||||||
comp.GhostId = ghost.GetHashCode();
|
comp.GhostId = ghost.GetHashCode();
|
||||||
EntityManager.GetComponent<TransformComponent>(ghost.Value).LocalRotation = dir.ToAngle();
|
Comp<TransformComponent>(ghost.Value).LocalRotation = dir.ToAngle();
|
||||||
_ghosts.Add(comp.GhostId, ghost.Value);
|
_ghosts.Add(comp.GhostId, ghost.Value);
|
||||||
|
|
||||||
var sprite = EntityManager.GetComponent<SpriteComponent>(ghost.Value);
|
var sprite = Comp<SpriteComponent>(ghost.Value);
|
||||||
_sprite.SetColor((ghost.Value, sprite), new Color(48, 255, 48, 128));
|
_sprite.SetColor((ghost.Value, sprite), new Color(48, 255, 48, 128));
|
||||||
|
|
||||||
if (targetProto.TryGetComponent(out IconComponent? icon, EntityManager.ComponentFactory))
|
if (targetProto.TryGetComponent(out IconComponent? icon, EntityManager.ComponentFactory))
|
||||||
|
|
@ -306,7 +306,7 @@ namespace Content.Client.Construction
|
||||||
else if (targetProto.Components.TryGetValue("Sprite", out _))
|
else if (targetProto.Components.TryGetValue("Sprite", out _))
|
||||||
{
|
{
|
||||||
var dummy = EntityManager.SpawnEntity(targetProtoId, MapCoordinates.Nullspace);
|
var dummy = EntityManager.SpawnEntity(targetProtoId, MapCoordinates.Nullspace);
|
||||||
var targetSprite = EntityManager.EnsureComponent<SpriteComponent>(dummy);
|
var targetSprite = EnsureComp<SpriteComponent>(dummy);
|
||||||
EntityManager.System<AppearanceSystem>().OnChangeData(dummy, targetSprite);
|
EntityManager.System<AppearanceSystem>().OnChangeData(dummy, targetSprite);
|
||||||
|
|
||||||
for (var i = 0; i < targetSprite.AllLayers.Count(); i++)
|
for (var i = 0; i < targetSprite.AllLayers.Count(); i++)
|
||||||
|
|
@ -325,7 +325,7 @@ namespace Content.Client.Construction
|
||||||
_sprite.LayerSetVisible((ghost.Value, sprite), i, true);
|
_sprite.LayerSetVisible((ghost.Value, sprite), i, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityManager.DeleteEntity(dummy);
|
Del(dummy);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -367,7 +367,7 @@ namespace Content.Client.Construction
|
||||||
{
|
{
|
||||||
foreach (var ghost in _ghosts)
|
foreach (var ghost in _ghosts)
|
||||||
{
|
{
|
||||||
if (EntityManager.GetComponent<TransformComponent>(ghost.Value).Coordinates.Equals(loc))
|
if (Comp<TransformComponent>(ghost.Value).Coordinates.Equals(loc))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -384,7 +384,7 @@ namespace Content.Client.Construction
|
||||||
throw new ArgumentException($"Can't start construction for a ghost with no prototype. Ghost id: {ghostId}");
|
throw new ArgumentException($"Can't start construction for a ghost with no prototype. Ghost id: {ghostId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var transform = EntityManager.GetComponent<TransformComponent>(ghostId);
|
var transform = Comp<TransformComponent>(ghostId);
|
||||||
var msg = new TryStartStructureConstructionMessage(GetNetCoordinates(transform.Coordinates), ghostComp.Prototype.ID, transform.LocalRotation, ghostId.GetHashCode());
|
var msg = new TryStartStructureConstructionMessage(GetNetCoordinates(transform.Coordinates), ghostComp.Prototype.ID, transform.LocalRotation, ghostId.GetHashCode());
|
||||||
RaiseNetworkEvent(msg);
|
RaiseNetworkEvent(msg);
|
||||||
}
|
}
|
||||||
|
|
@ -405,7 +405,7 @@ namespace Content.Client.Construction
|
||||||
if (!_ghosts.TryGetValue(ghostId, out var ghost))
|
if (!_ghosts.TryGetValue(ghostId, out var ghost))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EntityManager.QueueDeleteEntity(ghost);
|
QueueDel(ghost);
|
||||||
_ghosts.Remove(ghostId);
|
_ghosts.Remove(ghostId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,7 +416,7 @@ namespace Content.Client.Construction
|
||||||
{
|
{
|
||||||
foreach (var ghost in _ghosts.Values)
|
foreach (var ghost in _ghosts.Values)
|
||||||
{
|
{
|
||||||
EntityManager.QueueDeleteEntity(ghost);
|
QueueDel(ghost);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ghosts.Clear();
|
_ghosts.Clear();
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow
|
||||||
|
|
||||||
private EntityUid _owner;
|
private EntityUid _owner;
|
||||||
|
|
||||||
[ValidatePrototypeId<EntityPrototype>]
|
public static readonly EntProtoId NoBoardEffectId = "FlatpackerNoBoardEffect";
|
||||||
public const string NoBoardEffectId = "FlatpackerNoBoardEffect";
|
|
||||||
|
|
||||||
private EntityUid? _currentBoard = EntityUid.Invalid;
|
private EntityUid? _currentBoard = EntityUid.Invalid;
|
||||||
private EntityUid? _machinePreview;
|
private EntityUid? _machinePreview;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
<OutputPath>..\bin\Content.Client\</OutputPath>
|
<OutputPath>..\bin\Content.Client\</OutputPath>
|
||||||
<OutputType Condition="'$(FullRelease)' != 'True'">Exe</OutputType>
|
<OutputType Condition="'$(FullRelease)' != 'True'">Exe</OutputType>
|
||||||
<WarningsAsErrors>nullable</WarningsAsErrors>
|
<WarningsAsErrors>RA0032;nullable</WarningsAsErrors>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Configurations>Debug;Release;Tools;DebugOpt</Configurations>
|
<Configurations>Debug;Release;Tools;DebugOpt</Configurations>
|
||||||
<Platforms>AnyCPU</Platforms>
|
<Platforms>AnyCPU</Platforms>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Robust.Client.Graphics;
|
using System.Numerics;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
@ -7,6 +8,8 @@ namespace Content.Client.Cooldown
|
||||||
{
|
{
|
||||||
public sealed class CooldownGraphic : Control
|
public sealed class CooldownGraphic : Control
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> Shader = "CooldownAnimation";
|
||||||
|
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||||
|
|
||||||
|
|
@ -15,7 +18,7 @@ namespace Content.Client.Cooldown
|
||||||
public CooldownGraphic()
|
public CooldownGraphic()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
_shader = _protoMan.Index<ShaderPrototype>("CooldownAnimation").InstanceUnique();
|
_shader = _protoMan.Index(Shader).InstanceUnique();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -34,7 +37,7 @@ namespace Content.Client.Cooldown
|
||||||
if (Progress >= 0f)
|
if (Progress >= 0f)
|
||||||
{
|
{
|
||||||
var hue = (5f / 18f) * lerp;
|
var hue = (5f / 18f) * lerp;
|
||||||
color = Color.FromHsv((hue, 0.75f, 0.75f, 0.50f));
|
color = Color.FromHsv(new Vector4(hue, 0.75f, 0.75f, 0.50f));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
||||||
|
|
||||||
public readonly EntityUid Console;
|
public readonly EntityUid Console;
|
||||||
|
|
||||||
[ValidatePrototypeId<LocalizedDatasetPrototype>]
|
private static readonly ProtoId<LocalizedDatasetPrototype> ReasonPlaceholders = "CriminalRecordsWantedReasonPlaceholders";
|
||||||
private const string ReasonPlaceholders = "CriminalRecordsWantedReasonPlaceholders";
|
|
||||||
|
|
||||||
public Action<uint?>? OnKeySelected;
|
public Action<uint?>? OnKeySelected;
|
||||||
public Action<StationRecordFilterType, string>? OnFiltersChanged;
|
public Action<StationRecordFilterType, string>? OnFiltersChanged;
|
||||||
|
|
@ -296,7 +295,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
|
||||||
|
|
||||||
var field = "reason";
|
var field = "reason";
|
||||||
var title = Loc.GetString("criminal-records-status-" + status.ToString().ToLower());
|
var title = Loc.GetString("criminal-records-status-" + status.ToString().ToLower());
|
||||||
var placeholders = _proto.Index<LocalizedDatasetPrototype>(ReasonPlaceholders);
|
var placeholders = _proto.Index(ReasonPlaceholders);
|
||||||
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders))); // just funny it doesn't actually get used
|
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders))); // just funny it doesn't actually get used
|
||||||
var prompt = Loc.GetString("criminal-records-console-reason");
|
var prompt = Loc.GetString("criminal-records-console-reason");
|
||||||
var entry = new QuickDialogEntry(field, QuickDialogEntryType.LongText, prompt, placeholder);
|
var entry = new QuickDialogEntry(field, QuickDialogEntryType.LongText, prompt, placeholder);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,126 @@
|
||||||
using Content.Shared.Damage.Systems;
|
using Content.Client.Stunnable;
|
||||||
|
using Content.Shared.Damage.Components;
|
||||||
|
using Content.Shared.Damage.Systems;
|
||||||
|
using Content.Shared.Mobs;
|
||||||
|
using Content.Shared.Mobs.Systems;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
namespace Content.Client.Damage.Systems;
|
namespace Content.Client.Damage.Systems;
|
||||||
|
|
||||||
public sealed partial class StaminaSystem : SharedStaminaSystem
|
public sealed partial class StaminaSystem : SharedStaminaSystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
|
||||||
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
|
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||||
|
[Dependency] private readonly StunSystem _stun = default!; // Clientside Stun System
|
||||||
|
|
||||||
|
private const string StaminaAnimationKey = "stamina";
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<StaminaComponent, AnimationCompletedEvent>(OnAnimationCompleted);
|
||||||
|
SubscribeLocalEvent<ActiveStaminaComponent, ComponentShutdown>(OnActiveStaminaShutdown);
|
||||||
|
SubscribeLocalEvent<StaminaComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStamHandleState(Entity<StaminaComponent> entity, ref AfterAutoHandleStateEvent args)
|
||||||
|
{
|
||||||
|
base.OnStamHandleState(entity, ref args);
|
||||||
|
|
||||||
|
TryStartAnimation(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnActiveStaminaShutdown(Entity<ActiveStaminaComponent> entity, ref ComponentShutdown args)
|
||||||
|
{
|
||||||
|
// If we don't have active stamina, we shouldn't have stamina damage. If the update loop can trust it we can trust it.
|
||||||
|
if (!TryComp<StaminaComponent>(entity, out var stamina))
|
||||||
|
return;
|
||||||
|
|
||||||
|
StopAnimation((entity, stamina));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnShutdown(Entity<StaminaComponent> entity, ref ComponentShutdown args)
|
||||||
|
{
|
||||||
|
base.OnShutdown(entity, ref args);
|
||||||
|
|
||||||
|
StopAnimation(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMobStateChanged(Entity<StaminaComponent> ent, ref MobStateChangedEvent args)
|
||||||
|
{
|
||||||
|
if (args.NewMobState == MobState.Dead)
|
||||||
|
StopAnimation(ent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryStartAnimation(Entity<StaminaComponent> entity)
|
||||||
|
{
|
||||||
|
if (!TryComp<SpriteComponent>(entity, out var sprite))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the animation is running, the system should update it accordingly
|
||||||
|
// If we're below the threshold to animate, don't try to animate
|
||||||
|
// If we're in stamcrit don't override it
|
||||||
|
if (entity.Comp.AnimationThreshold > entity.Comp.StaminaDamage || _animation.HasRunningAnimation(entity, StaminaAnimationKey))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Don't animate if we're dead
|
||||||
|
if (_mobState.IsDead(entity))
|
||||||
|
return;
|
||||||
|
|
||||||
|
entity.Comp.StartOffset = sprite.Offset;
|
||||||
|
|
||||||
|
PlayAnimation((entity, entity.Comp, sprite));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopAnimation(Entity<StaminaComponent, SpriteComponent?> entity)
|
||||||
|
{
|
||||||
|
if(!Resolve(entity, ref entity.Comp2))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_animation.Stop(entity.Owner, StaminaAnimationKey);
|
||||||
|
entity.Comp1.StartOffset = entity.Comp2.Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAnimationCompleted(Entity<StaminaComponent> entity, ref AnimationCompletedEvent args)
|
||||||
|
{
|
||||||
|
if (args.Key != StaminaAnimationKey || !args.Finished || !TryComp<SpriteComponent>(entity, out var sprite))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// stop looping if we're below the threshold
|
||||||
|
if (entity.Comp.AnimationThreshold > entity.Comp.StaminaDamage)
|
||||||
|
{
|
||||||
|
_animation.Stop(entity.Owner, StaminaAnimationKey);
|
||||||
|
_sprite.SetOffset((entity, sprite), entity.Comp.StartOffset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HasComp<AnimationPlayerComponent>(entity))
|
||||||
|
return;
|
||||||
|
|
||||||
|
PlayAnimation((entity, entity.Comp, sprite));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayAnimation(Entity<StaminaComponent, SpriteComponent> entity)
|
||||||
|
{
|
||||||
|
var step = Math.Clamp((entity.Comp1.StaminaDamage - entity.Comp1.AnimationThreshold) /
|
||||||
|
(entity.Comp1.CritThreshold - entity.Comp1.AnimationThreshold),
|
||||||
|
0f,
|
||||||
|
1f); // The things I do for project 0 warnings
|
||||||
|
var frequency = entity.Comp1.FrequencyMin + step * entity.Comp1.FrequencyMod;
|
||||||
|
var jitter = entity.Comp1.JitterAmplitudeMin + step * entity.Comp1.JitterAmplitudeMod;
|
||||||
|
var breathing = entity.Comp1.BreathingAmplitudeMin + step * entity.Comp1.BreathingAmplitudeMod;
|
||||||
|
|
||||||
|
_animation.Play(entity.Owner,
|
||||||
|
_stun.GetFatigueAnimation(entity.Comp2,
|
||||||
|
frequency,
|
||||||
|
entity.Comp1.Jitters,
|
||||||
|
jitter * entity.Comp1.JitterMin,
|
||||||
|
jitter * entity.Comp1.JitterMax,
|
||||||
|
breathing,
|
||||||
|
entity.Comp1.StartOffset,
|
||||||
|
ref entity.Comp1.LastJitter),
|
||||||
|
StaminaAnimationKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
using Content.Shared.Devour;
|
|
||||||
|
|
||||||
namespace Content.Client.Devour;
|
|
||||||
public sealed class DevourSystem : SharedDevourSystem
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Content.Shared.Disposal;
|
using System.Numerics;
|
||||||
|
using Content.Shared.Disposal;
|
||||||
using Content.Shared.Disposal.Unit;
|
using Content.Shared.Disposal.Unit;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ namespace Content.Client.DoAfter;
|
||||||
|
|
||||||
public sealed class DoAfterOverlay : Overlay
|
public sealed class DoAfterOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||||
|
|
||||||
private readonly IEntityManager _entManager;
|
private readonly IEntityManager _entManager;
|
||||||
private readonly IGameTiming _timing;
|
private readonly IGameTiming _timing;
|
||||||
private readonly IPlayerManager _player;
|
private readonly IPlayerManager _player;
|
||||||
|
|
@ -50,7 +52,7 @@ public sealed class DoAfterOverlay : Overlay
|
||||||
var sprite = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/progress_bar.rsi"), "icon");
|
var sprite = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/progress_bar.rsi"), "icon");
|
||||||
_barTexture = _entManager.EntitySysManager.GetEntitySystem<SpriteSystem>().Frame0(sprite);
|
_barTexture = _entManager.EntitySysManager.GetEntitySystem<SpriteSystem>().Frame0(sprite);
|
||||||
|
|
||||||
_unshadedShader = protoManager.Index<ShaderPrototype>("unshaded").Instance();
|
_unshadedShader = protoManager.Index(UnshadedShader).Instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Draw(in OverlayDrawArgs args)
|
protected override void Draw(in OverlayDrawArgs args)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using Content.Shared.Drowsiness;
|
using Content.Shared.Drowsiness;
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffectNew;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
|
|
@ -10,11 +10,14 @@ namespace Content.Client.Drowsiness;
|
||||||
|
|
||||||
public sealed class DrowsinessOverlay : Overlay
|
public sealed class DrowsinessOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> Shader = "Drowsiness";
|
||||||
|
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
private readonly StatusEffectsSystem _statusEffects = default!;
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||||
public override bool RequestScreenTexture => true;
|
public override bool RequestScreenTexture => true;
|
||||||
|
|
@ -29,7 +32,10 @@ public sealed class DrowsinessOverlay : Overlay
|
||||||
public DrowsinessOverlay()
|
public DrowsinessOverlay()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
_drowsinessShader = _prototypeManager.Index<ShaderPrototype>("Drowsiness").InstanceUnique();
|
|
||||||
|
_statusEffects = _sysMan.GetEntitySystem<StatusEffectsSystem>();
|
||||||
|
|
||||||
|
_drowsinessShader = _prototypeManager.Index(Shader).InstanceUnique();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
|
|
@ -39,17 +45,11 @@ public sealed class DrowsinessOverlay : Overlay
|
||||||
if (playerEntity == null)
|
if (playerEntity == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_entityManager.HasComponent<DrowsinessComponent>(playerEntity)
|
if (!_statusEffects.TryGetEffectsEndTimeWithComp<DrowsinessStatusEffectComponent>(playerEntity, out var endTime))
|
||||||
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
|
endTime ??= TimeSpan.MaxValue;
|
||||||
if (!statusSys.TryGetTime(playerEntity.Value, SharedDrowsinessSystem.DrowsinessKey, out var time, status))
|
var timeLeft = (float)(endTime - _timing.CurTime).Value.TotalSeconds;
|
||||||
return;
|
|
||||||
|
|
||||||
var curTime = _timing.CurTime;
|
|
||||||
var timeLeft = (float)(time.Value.Item2 - curTime).TotalSeconds;
|
|
||||||
|
|
||||||
CurrentPower += 8f * (0.5f * timeLeft - CurrentPower) * args.DeltaSeconds / (timeLeft + 1);
|
CurrentPower += 8f * (0.5f * timeLeft - CurrentPower) * args.DeltaSeconds / (timeLeft + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Content.Shared.Drowsiness;
|
using Content.Shared.Drowsiness;
|
||||||
|
using Content.Shared.StatusEffectNew;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
|
@ -9,6 +10,7 @@ public sealed class DrowsinessSystem : SharedDrowsinessSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPlayerManager _player = default!;
|
[Dependency] private readonly IPlayerManager _player = default!;
|
||||||
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
||||||
|
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
||||||
|
|
||||||
private DrowsinessOverlay _overlay = default!;
|
private DrowsinessOverlay _overlay = default!;
|
||||||
|
|
||||||
|
|
@ -16,35 +18,44 @@ public sealed class DrowsinessSystem : SharedDrowsinessSystem
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<DrowsinessComponent, ComponentInit>(OnDrowsinessInit);
|
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectAppliedEvent>(OnDrowsinessApply);
|
||||||
SubscribeLocalEvent<DrowsinessComponent, ComponentShutdown>(OnDrowsinessShutdown);
|
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectRemovedEvent>(OnDrowsinessShutdown);
|
||||||
|
|
||||||
SubscribeLocalEvent<DrowsinessComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
|
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerAttachedEvent>>(OnStatusEffectPlayerAttached);
|
||||||
SubscribeLocalEvent<DrowsinessComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
|
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerDetachedEvent>>(OnStatusEffectPlayerDetached);
|
||||||
|
|
||||||
_overlay = new();
|
_overlay = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayerAttached(EntityUid uid, DrowsinessComponent component, LocalPlayerAttachedEvent args)
|
private void OnDrowsinessApply(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
|
||||||
{
|
{
|
||||||
|
if (_player.LocalEntity == args.Target)
|
||||||
_overlayMan.AddOverlay(_overlay);
|
_overlayMan.AddOverlay(_overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayerDetached(EntityUid uid, DrowsinessComponent component, LocalPlayerDetachedEvent args)
|
private void OnDrowsinessShutdown(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
|
||||||
|
{
|
||||||
|
if (_player.LocalEntity != args.Target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_statusEffects.HasEffectComp<DrowsinessStatusEffectComponent>(_player.LocalEntity.Value))
|
||||||
{
|
{
|
||||||
_overlay.CurrentPower = 0;
|
_overlay.CurrentPower = 0;
|
||||||
_overlayMan.RemoveOverlay(_overlay);
|
_overlayMan.RemoveOverlay(_overlay);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnDrowsinessInit(EntityUid uid, DrowsinessComponent component, ComponentInit args)
|
private void OnStatusEffectPlayerAttached(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
|
||||||
{
|
{
|
||||||
if (_player.LocalEntity == uid)
|
|
||||||
_overlayMan.AddOverlay(_overlay);
|
_overlayMan.AddOverlay(_overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDrowsinessShutdown(EntityUid uid, DrowsinessComponent component, ComponentShutdown args)
|
private void OnStatusEffectPlayerDetached(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)
|
||||||
{
|
{
|
||||||
if (_player.LocalEntity == uid)
|
if (_player.LocalEntity is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_statusEffects.HasEffectComp<DrowsinessStatusEffectComponent>(_player.LocalEntity.Value))
|
||||||
{
|
{
|
||||||
_overlay.CurrentPower = 0;
|
_overlay.CurrentPower = 0;
|
||||||
_overlayMan.RemoveOverlay(_overlay);
|
_overlayMan.RemoveOverlay(_overlay);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Content.Shared.Drugs;
|
using Content.Shared.Drugs;
|
||||||
|
using Content.Shared.StatusEffectNew;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
|
@ -17,49 +18,47 @@ public sealed class DrugOverlaySystem : EntitySystem
|
||||||
|
|
||||||
private RainbowOverlay _overlay = default!;
|
private RainbowOverlay _overlay = default!;
|
||||||
|
|
||||||
public static string RainbowKey = "SeeingRainbows";
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<SeeingRainbowsComponent, ComponentInit>(OnInit);
|
SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectAppliedEvent>(OnApplied);
|
||||||
SubscribeLocalEvent<SeeingRainbowsComponent, ComponentShutdown>(OnShutdown);
|
SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectRemovedEvent>(OnRemoved);
|
||||||
|
|
||||||
SubscribeLocalEvent<SeeingRainbowsComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
|
SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerAttachedEvent>>(OnPlayerAttached);
|
||||||
SubscribeLocalEvent<SeeingRainbowsComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
|
SubscribeLocalEvent<SeeingRainbowsStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerDetachedEvent>>(OnPlayerDetached);
|
||||||
|
|
||||||
_overlay = new();
|
_overlay = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayerAttached(EntityUid uid, SeeingRainbowsComponent component, LocalPlayerAttachedEvent args)
|
private void OnRemoved(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
|
||||||
{
|
{
|
||||||
_overlayMan.AddOverlay(_overlay);
|
if (_player.LocalEntity != args.Target)
|
||||||
}
|
return;
|
||||||
|
|
||||||
private void OnPlayerDetached(EntityUid uid, SeeingRainbowsComponent component, LocalPlayerDetachedEvent args)
|
|
||||||
{
|
|
||||||
_overlay.Intoxication = 0;
|
_overlay.Intoxication = 0;
|
||||||
_overlay.TimeTicker = 0;
|
_overlay.TimeTicker = 0;
|
||||||
_overlayMan.RemoveOverlay(_overlay);
|
_overlayMan.RemoveOverlay(_overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInit(EntityUid uid, SeeingRainbowsComponent component, ComponentInit args)
|
private void OnApplied(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
|
||||||
{
|
|
||||||
if (_player.LocalEntity == uid)
|
|
||||||
{
|
{
|
||||||
|
if (_player.LocalEntity != args.Target)
|
||||||
|
return;
|
||||||
|
|
||||||
_overlay.Phase = _random.NextFloat(MathF.Tau); // random starting phase for movement effect
|
_overlay.Phase = _random.NextFloat(MathF.Tau); // random starting phase for movement effect
|
||||||
_overlayMan.AddOverlay(_overlay);
|
_overlayMan.AddOverlay(_overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnPlayerAttached(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
|
||||||
|
{
|
||||||
|
_overlayMan.AddOverlay(_overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnShutdown(EntityUid uid, SeeingRainbowsComponent component, ComponentShutdown args)
|
private void OnPlayerDetached(Entity<SeeingRainbowsStatusEffectComponent> ent, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)
|
||||||
{
|
|
||||||
if (_player.LocalEntity == uid)
|
|
||||||
{
|
{
|
||||||
_overlay.Intoxication = 0;
|
_overlay.Intoxication = 0;
|
||||||
_overlay.TimeTicker = 0;
|
_overlay.TimeTicker = 0;
|
||||||
_overlayMan.RemoveOverlay(_overlay);
|
_overlayMan.RemoveOverlay(_overlay);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Drugs;
|
using Content.Shared.Drugs;
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffectNew;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
|
|
@ -12,11 +12,15 @@ namespace Content.Client.Drugs;
|
||||||
|
|
||||||
public sealed class RainbowOverlay : Overlay
|
public sealed class RainbowOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> Shader = "Rainbow";
|
||||||
|
|
||||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
private readonly StatusEffectsSystem _statusEffects = default!;
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||||
public override bool RequestScreenTexture => true;
|
public override bool RequestScreenTexture => true;
|
||||||
|
|
@ -37,7 +41,9 @@ public sealed class RainbowOverlay : Overlay
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
_rainbowShader = _prototypeManager.Index<ShaderPrototype>("Rainbow").InstanceUnique();
|
_statusEffects = _sysMan.GetEntitySystem<StatusEffectsSystem>();
|
||||||
|
|
||||||
|
_rainbowShader = _prototypeManager.Index(Shader).InstanceUnique();
|
||||||
_config.OnValueChanged(CCVars.ReducedMotion, OnReducedMotionChanged, invokeImmediately: true);
|
_config.OnValueChanged(CCVars.ReducedMotion, OnReducedMotionChanged, invokeImmediately: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,18 +60,13 @@ public sealed class RainbowOverlay : Overlay
|
||||||
if (playerEntity == null)
|
if (playerEntity == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_entityManager.HasComponent<SeeingRainbowsComponent>(playerEntity)
|
if (!_statusEffects.TryGetEffectsEndTimeWithComp<SeeingRainbowsStatusEffectComponent>(playerEntity, out var endTime))
|
||||||
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
|
endTime ??= TimeSpan.MaxValue;
|
||||||
if (!statusSys.TryGetTime(playerEntity.Value, DrugOverlaySystem.RainbowKey, out var time, status))
|
var timeLeft = (float)(endTime - _timing.CurTime).Value.TotalSeconds;
|
||||||
return;
|
|
||||||
|
|
||||||
var timeLeft = (float)(time.Value.Item2 - time.Value.Item1).TotalSeconds;
|
|
||||||
|
|
||||||
TimeTicker += args.DeltaSeconds;
|
TimeTicker += args.DeltaSeconds;
|
||||||
|
|
||||||
if (timeLeft - TimeTicker > timeLeft / 16f)
|
if (timeLeft - TimeTicker > timeLeft / 16f)
|
||||||
{
|
{
|
||||||
Intoxication += (timeLeft - Intoxication) * args.DeltaSeconds / 16f;
|
Intoxication += (timeLeft - Intoxication) * args.DeltaSeconds / 16f;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ namespace Content.Client.Drunk;
|
||||||
|
|
||||||
public sealed class DrunkOverlay : Overlay
|
public sealed class DrunkOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> Shader = "Drunk";
|
||||||
|
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
|
@ -30,7 +32,7 @@ public sealed class DrunkOverlay : Overlay
|
||||||
public DrunkOverlay()
|
public DrunkOverlay()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
_drunkShader = _prototypeManager.Index<ShaderPrototype>("Drunk").InstanceUnique();
|
_drunkShader = _prototypeManager.Index(Shader).InstanceUnique();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ namespace Content.Client.Examine
|
||||||
{
|
{
|
||||||
var entity = args.EntityUid;
|
var entity = args.EntityUid;
|
||||||
|
|
||||||
if (!args.EntityUid.IsValid() || !EntityManager.EntityExists(entity))
|
if (!args.EntityUid.IsValid() || !Exists(entity))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -225,7 +225,7 @@ namespace Content.Client.Examine
|
||||||
|
|
||||||
vBox.AddChild(hBox);
|
vBox.AddChild(hBox);
|
||||||
|
|
||||||
if (EntityManager.HasComponent<SpriteComponent>(target))
|
if (HasComp<SpriteComponent>(target))
|
||||||
{
|
{
|
||||||
var spriteView = new SpriteView
|
var spriteView = new SpriteView
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ namespace Content.Client.Explosion;
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class ExplosionOverlay : Overlay
|
public sealed class ExplosionOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||||
|
|
||||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
|
|
@ -26,7 +28,7 @@ public sealed class ExplosionOverlay : Overlay
|
||||||
public ExplosionOverlay(SharedAppearanceSystem appearanceSystem)
|
public ExplosionOverlay(SharedAppearanceSystem appearanceSystem)
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
_shader = _proto.Index<ShaderPrototype>("unshaded").Instance();
|
_shader = _proto.Index(UnshadedShader).Instance();
|
||||||
_transformSystem = _entMan.System<SharedTransformSystem>();
|
_transformSystem = _entMan.System<SharedTransformSystem>();
|
||||||
_appearance = appearanceSystem;
|
_appearance = appearanceSystem;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ public sealed partial class TriggerSystem
|
||||||
|
|
||||||
private void OnProximityInit(EntityUid uid, TriggerOnProximityComponent component, ComponentInit args)
|
private void OnProximityInit(EntityUid uid, TriggerOnProximityComponent component, ComponentInit args)
|
||||||
{
|
{
|
||||||
EntityManager.EnsureComponent<AnimationPlayerComponent>(uid);
|
EnsureComp<AnimationPlayerComponent>(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnProxAppChange(EntityUid uid, TriggerOnProximityComponent component, ref AppearanceChangeEvent args)
|
private void OnProxAppChange(EntityUid uid, TriggerOnProximityComponent component, ref AppearanceChangeEvent args)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@ namespace Content.Client.Eye.Blinding
|
||||||
{
|
{
|
||||||
public sealed class BlindOverlay : Overlay
|
public sealed class BlindOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> GreyscaleShader = "GreyscaleFullscreen";
|
||||||
|
private static readonly ProtoId<ShaderPrototype> CircleShader = "CircleMask";
|
||||||
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
@ -27,8 +30,8 @@ namespace Content.Client.Eye.Blinding
|
||||||
public BlindOverlay()
|
public BlindOverlay()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
_greyscaleShader = _prototypeManager.Index<ShaderPrototype>("GreyscaleFullscreen").InstanceUnique();
|
_greyscaleShader = _prototypeManager.Index(GreyscaleShader).InstanceUnique();
|
||||||
_circleMaskShader = _prototypeManager.Index<ShaderPrototype>("CircleMask").InstanceUnique();
|
_circleMaskShader = _prototypeManager.Index(CircleShader).InstanceUnique();
|
||||||
}
|
}
|
||||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ namespace Content.Client.Eye.Blinding
|
||||||
{
|
{
|
||||||
public sealed class BlurryVisionOverlay : Overlay
|
public sealed class BlurryVisionOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> CataractsShader = "Cataracts";
|
||||||
|
private static readonly ProtoId<ShaderPrototype> CircleShader = "CircleMask";
|
||||||
|
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
@ -33,8 +36,8 @@ namespace Content.Client.Eye.Blinding
|
||||||
public BlurryVisionOverlay()
|
public BlurryVisionOverlay()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
_cataractsShader = _prototypeManager.Index<ShaderPrototype>("Cataracts").InstanceUnique();
|
_cataractsShader = _prototypeManager.Index(CataractsShader).InstanceUnique();
|
||||||
_circleMaskShader = _prototypeManager.Index<ShaderPrototype>("CircleMask").InstanceUnique();
|
_circleMaskShader = _prototypeManager.Index(CircleShader).InstanceUnique();
|
||||||
|
|
||||||
_circleMaskShader.SetParameter("CircleMinDist", 0.0f);
|
_circleMaskShader.SetParameter("CircleMinDist", 0.0f);
|
||||||
_circleMaskShader.SetParameter("CirclePow", NoMotion_Pow);
|
_circleMaskShader.SetParameter("CirclePow", NoMotion_Pow);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Flash;
|
using Content.Shared.Flash;
|
||||||
using Content.Shared.Flash.Components;
|
using Content.Shared.Flash.Components;
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffect;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
@ -11,23 +13,31 @@ namespace Content.Client.Flash
|
||||||
{
|
{
|
||||||
public sealed class FlashOverlay : Overlay
|
public sealed class FlashOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> FlashedEffectShader = "FlashedEffect";
|
||||||
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
||||||
|
|
||||||
private readonly StatusEffectsSystem _statusSys;
|
private readonly StatusEffectsSystem _statusSys;
|
||||||
|
private readonly SharedFlashSystem _flash;
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||||
private readonly ShaderInstance _shader;
|
private readonly ShaderInstance _shader;
|
||||||
public float PercentComplete = 0.0f;
|
private bool _reducedMotion;
|
||||||
|
public float PercentComplete;
|
||||||
public Texture? ScreenshotTexture;
|
public Texture? ScreenshotTexture;
|
||||||
|
|
||||||
public FlashOverlay()
|
public FlashOverlay()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
_shader = _prototypeManager.Index<ShaderPrototype>("FlashedEffect").InstanceUnique();
|
_shader = _prototypeManager.Index(FlashedEffectShader).InstanceUnique();
|
||||||
|
_flash = _entityManager.System<SharedFlashSystem>();
|
||||||
_statusSys = _entityManager.System<StatusEffectsSystem>();
|
_statusSys = _entityManager.System<StatusEffectsSystem>();
|
||||||
|
|
||||||
|
_configManager.OnValueChanged(CCVars.ReducedMotion, (b) => { _reducedMotion = b; }, invokeImmediately: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
|
|
@ -41,12 +51,12 @@ namespace Content.Client.Flash
|
||||||
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
|
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_statusSys.TryGetTime(playerEntity.Value, SharedFlashSystem.FlashedKey, out var time, status))
|
if (!_statusSys.TryGetTime(playerEntity.Value, _flash.FlashedKey, out var time, status))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var curTime = _timing.CurTime;
|
var curTime = _timing.CurTime;
|
||||||
var lastsFor = (float) (time.Value.Item2 - time.Value.Item1).TotalSeconds;
|
var lastsFor = (float)(time.Value.Item2 - time.Value.Item1).TotalSeconds;
|
||||||
var timeDone = (float) (curTime - time.Value.Item1).TotalSeconds;
|
var timeDone = (float)(curTime - time.Value.Item1).TotalSeconds;
|
||||||
|
|
||||||
PercentComplete = timeDone / lastsFor;
|
PercentComplete = timeDone / lastsFor;
|
||||||
}
|
}
|
||||||
|
|
@ -72,11 +82,23 @@ namespace Content.Client.Flash
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var worldHandle = args.WorldHandle;
|
var worldHandle = args.WorldHandle;
|
||||||
|
if (_reducedMotion)
|
||||||
|
{
|
||||||
|
// TODO: This is a very simple placeholder.
|
||||||
|
// Replace it with a proper shader once we come up with something good.
|
||||||
|
// Turns out making an effect that is supposed to be a bright, sudden, and disorienting flash
|
||||||
|
// not do any of that while also being equivalent in terms of game balance is hard.
|
||||||
|
var alpha = 1 - MathF.Pow(PercentComplete, 8f); // similar falloff curve to the flash shader
|
||||||
|
worldHandle.DrawRect(args.WorldBounds, new Color(0f, 0f, 0f, alpha));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
_shader.SetParameter("percentComplete", PercentComplete);
|
_shader.SetParameter("percentComplete", PercentComplete);
|
||||||
worldHandle.UseShader(_shader);
|
worldHandle.UseShader(_shader);
|
||||||
worldHandle.DrawTextureRectRegion(ScreenshotTexture, args.WorldBounds);
|
worldHandle.DrawTextureRectRegion(ScreenshotTexture, args.WorldBounds);
|
||||||
worldHandle.UseShader(null);
|
worldHandle.UseShader(null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void DisposeBehavior()
|
protected override void DisposeBehavior()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using Content.Shared.Flash;
|
using Content.Shared.Flash;
|
||||||
using Content.Shared.Flash.Components;
|
using Content.Shared.Flash.Components;
|
||||||
using Content.Shared.StatusEffect;
|
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@ namespace Content.Client.Guidebook.Controls;
|
||||||
[UsedImplicitly, GenerateTypedNameReferences]
|
[UsedImplicitly, GenerateTypedNameReferences]
|
||||||
public sealed partial class GuideReagentReaction : BoxContainer, ISearchableControl
|
public sealed partial class GuideReagentReaction : BoxContainer, ISearchableControl
|
||||||
{
|
{
|
||||||
[ValidatePrototypeId<MixingCategoryPrototype>]
|
private static readonly ProtoId<MixingCategoryPrototype> DefaultMixingCategory = "DummyMix";
|
||||||
private const string DefaultMixingCategory = "DummyMix";
|
|
||||||
|
|
||||||
private readonly IPrototypeManager _protoMan;
|
private readonly IPrototypeManager _protoMan;
|
||||||
|
|
||||||
|
|
@ -55,7 +54,7 @@ public sealed partial class GuideReagentReaction : BoxContainer, ISearchableCont
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mixingCategories.Add(protoMan.Index<MixingCategoryPrototype>(DefaultMixingCategory));
|
mixingCategories.Add(protoMan.Index(DefaultMixingCategory));
|
||||||
}
|
}
|
||||||
SetMixingCategory(mixingCategories, prototype, sysMan);
|
SetMixingCategory(mixingCategories, prototype, sysMan);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using Robust.Shared.Utility;
|
||||||
namespace Content.Client.Guidebook.Richtext;
|
namespace Content.Client.Guidebook.Richtext;
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class KeyBindTag : IMarkupTag
|
public sealed class KeyBindTag : IMarkupTagHandler
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ namespace Content.Client.Guidebook.RichText;
|
||||||
/// In order to be accessed by this tag, the desired field/property must
|
/// In order to be accessed by this tag, the desired field/property must
|
||||||
/// be tagged with <see cref="Shared.Guidebook.GuidebookDataAttribute"/>.
|
/// be tagged with <see cref="Shared.Guidebook.GuidebookDataAttribute"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ProtodataTag : IMarkupTag
|
public sealed class ProtodataTag : IMarkupTagHandler
|
||||||
{
|
{
|
||||||
[Dependency] private readonly ILogManager _logMan = default!;
|
[Dependency] private readonly ILogManager _logMan = default!;
|
||||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,14 @@ using Content.Client.UserInterface.ControlExtensions;
|
||||||
namespace Content.Client.Guidebook.RichText;
|
namespace Content.Client.Guidebook.RichText;
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class TextLinkTag : IMarkupTag
|
public sealed class TextLinkTag : IMarkupTagHandler
|
||||||
{
|
{
|
||||||
public static Color LinkColor => Color.CornflowerBlue;
|
public static Color LinkColor => Color.CornflowerBlue;
|
||||||
|
|
||||||
public string Name => "textlink";
|
public string Name => "textlink";
|
||||||
|
|
||||||
public Control? Control;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool TryGetControl(MarkupNode node, [NotNullWhen(true)] out Control? control)
|
public bool TryCreateControl(MarkupNode node, [NotNullWhen(true)] out Control? control)
|
||||||
{
|
{
|
||||||
if (!node.Value.TryGetString(out var text)
|
if (!node.Value.TryGetString(out var text)
|
||||||
|| !node.Attributes.TryGetValue("link", out var linkParameter)
|
|| !node.Attributes.TryGetValue("link", out var linkParameter)
|
||||||
|
|
@ -38,22 +36,21 @@ public sealed class TextLinkTag : IMarkupTag
|
||||||
|
|
||||||
label.OnMouseEntered += _ => label.FontColorOverride = Color.LightSkyBlue;
|
label.OnMouseEntered += _ => label.FontColorOverride = Color.LightSkyBlue;
|
||||||
label.OnMouseExited += _ => label.FontColorOverride = Color.CornflowerBlue;
|
label.OnMouseExited += _ => label.FontColorOverride = Color.CornflowerBlue;
|
||||||
label.OnKeyBindDown += args => OnKeybindDown(args, link);
|
label.OnKeyBindDown += args => OnKeybindDown(args, link, label);
|
||||||
|
|
||||||
control = label;
|
control = label;
|
||||||
Control = label;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnKeybindDown(GUIBoundKeyEventArgs args, string link)
|
private void OnKeybindDown(GUIBoundKeyEventArgs args, string link, Control? control)
|
||||||
{
|
{
|
||||||
if (args.Function != EngineKeyFunctions.UIClick)
|
if (args.Function != EngineKeyFunctions.UIClick)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Control == null)
|
if (control == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Control.TryGetParentHandler<ILinkClickHandler>(out var handler))
|
if (control.TryGetParentHandler<ILinkClickHandler>(out var handler))
|
||||||
handler.HandleClick(link);
|
handler.HandleClick(link);
|
||||||
else
|
else
|
||||||
Logger.Warning("Warning! No valid ILinkClickHandler found.");
|
Logger.Warning("Warning! No valid ILinkClickHandler found.");
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ using Robust.Client.UserInterface;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Client.Hands.Systems
|
namespace Content.Client.Hands.Systems
|
||||||
|
|
@ -29,16 +28,13 @@ namespace Content.Client.Hands.Systems
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
||||||
|
|
||||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
|
||||||
[Dependency] private readonly StrippableSystem _stripSys = default!;
|
[Dependency] private readonly StrippableSystem _stripSys = default!;
|
||||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||||
[Dependency] private readonly ExamineSystem _examine = default!;
|
[Dependency] private readonly ExamineSystem _examine = default!;
|
||||||
[Dependency] private readonly DisplacementMapSystem _displacement = default!;
|
[Dependency] private readonly DisplacementMapSystem _displacement = default!;
|
||||||
|
|
||||||
public event Action<string, HandLocation>? OnPlayerAddHand;
|
|
||||||
public event Action<string>? OnPlayerRemoveHand;
|
|
||||||
public event Action<string?>? OnPlayerSetActiveHand;
|
public event Action<string?>? OnPlayerSetActiveHand;
|
||||||
public event Action<HandsComponent>? OnPlayerHandsAdded;
|
public event Action<Entity<HandsComponent>>? OnPlayerHandsAdded;
|
||||||
public event Action? OnPlayerHandsRemoved;
|
public event Action? OnPlayerHandsRemoved;
|
||||||
public event Action<string, EntityUid>? OnPlayerItemAdded;
|
public event Action<string, EntityUid>? OnPlayerItemAdded;
|
||||||
public event Action<string, EntityUid>? OnPlayerItemRemoved;
|
public event Action<string, EntityUid>? OnPlayerItemRemoved;
|
||||||
|
|
@ -62,67 +58,28 @@ namespace Content.Client.Hands.Systems
|
||||||
}
|
}
|
||||||
|
|
||||||
#region StateHandling
|
#region StateHandling
|
||||||
private void HandleComponentState(EntityUid uid, HandsComponent component, ref ComponentHandleState args)
|
private void HandleComponentState(Entity<HandsComponent> ent, ref ComponentHandleState args)
|
||||||
{
|
{
|
||||||
if (args.Current is not HandsComponentState state)
|
if (args.Current is not HandsComponentState state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var handsModified = component.Hands.Count != state.Hands.Count;
|
var newHands = state.Hands.Keys.Except(ent.Comp.Hands.Keys); // hands that were added between states
|
||||||
// we need to check that, even if we have the same amount, that the individual hands didn't change.
|
var oldHands = ent.Comp.Hands.Keys.Except(state.Hands.Keys); // hands that were removed between states
|
||||||
if (!handsModified)
|
|
||||||
|
foreach (var handId in oldHands)
|
||||||
{
|
{
|
||||||
foreach (var hand in component.Hands.Values)
|
RemoveHand(ent.AsNullable(), handId);
|
||||||
{
|
|
||||||
if (state.Hands.Contains(hand))
|
|
||||||
continue;
|
|
||||||
handsModified = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var manager = EnsureComp<ContainerManagerComponent>(uid);
|
foreach (var handId in state.SortedHands.Intersect(newHands))
|
||||||
|
|
||||||
if (handsModified)
|
|
||||||
{
|
{
|
||||||
List<Hand> addedHands = new();
|
AddHand(ent.AsNullable(), handId, state.Hands[handId]);
|
||||||
foreach (var hand in state.Hands)
|
|
||||||
{
|
|
||||||
if (component.Hands.ContainsKey(hand.Name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var container = _containerSystem.EnsureContainer<ContainerSlot>(uid, hand.Name, manager);
|
|
||||||
var newHand = new Hand(hand.Name, hand.Location, container);
|
|
||||||
component.Hands.Add(hand.Name, newHand);
|
|
||||||
addedHands.Add(newHand);
|
|
||||||
}
|
}
|
||||||
|
ent.Comp.SortedHands = new (state.SortedHands);
|
||||||
|
|
||||||
foreach (var name in component.Hands.Keys)
|
SetActiveHand(ent.AsNullable(), state.ActiveHandId);
|
||||||
{
|
|
||||||
if (!state.HandNames.Contains(name))
|
|
||||||
{
|
|
||||||
RemoveHand(uid, name, component);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
component.SortedHands.Clear();
|
_stripSys.UpdateUi(ent);
|
||||||
component.SortedHands.AddRange(state.HandNames);
|
|
||||||
var sorted = addedHands.OrderBy(hand => component.SortedHands.IndexOf(hand.Name));
|
|
||||||
|
|
||||||
foreach (var hand in sorted)
|
|
||||||
{
|
|
||||||
AddHand(uid, hand, component);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_stripSys.UpdateUi(uid);
|
|
||||||
|
|
||||||
if (component.ActiveHand == null && state.ActiveHand == null)
|
|
||||||
return; //edge case
|
|
||||||
|
|
||||||
if (component.ActiveHand != null && state.ActiveHand != component.ActiveHand.Name)
|
|
||||||
{
|
|
||||||
SetActiveHand(uid, component.Hands[state.ActiveHand!], component);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
@ -133,72 +90,77 @@ namespace Content.Client.Hands.Systems
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnPlayerHandsAdded?.Invoke(hands);
|
OnPlayerHandsAdded?.Invoke(hands.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, HandsComponent? hands = null, bool log = true)
|
public override void DoDrop(Entity<HandsComponent?> ent,
|
||||||
|
string handId,
|
||||||
|
bool doDropInteraction = true,
|
||||||
|
bool log = true)
|
||||||
{
|
{
|
||||||
base.DoDrop(uid, hand, doDropInteraction, hands, log);
|
base.DoDrop(ent, handId, doDropInteraction, log);
|
||||||
|
|
||||||
if (TryComp(hand.HeldEntity, out SpriteComponent? sprite))
|
if (TryGetHeldItem(ent, handId, out var held) && TryComp(held, out SpriteComponent? sprite))
|
||||||
sprite.RenderOrder = EntityManager.CurrentTick.Value;
|
sprite.RenderOrder = EntityManager.CurrentTick.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityUid? GetActiveHandEntity()
|
public EntityUid? GetActiveHandEntity()
|
||||||
{
|
{
|
||||||
return TryGetPlayerHands(out var hands) ? hands.ActiveHandEntity : null;
|
return TryGetPlayerHands(out var hands) ? GetActiveItem(hands.Value.AsNullable()) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the hands component of the local player
|
/// Get the hands component of the local player
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryGetPlayerHands([NotNullWhen(true)] out HandsComponent? hands)
|
public bool TryGetPlayerHands([NotNullWhen(true)] out Entity<HandsComponent>? hands)
|
||||||
{
|
{
|
||||||
var player = _playerManager.LocalEntity;
|
var player = _playerManager.LocalEntity;
|
||||||
hands = null;
|
hands = null;
|
||||||
return player != null && TryComp(player.Value, out hands);
|
if (player == null || !TryComp<HandsComponent>(player.Value, out var handsComp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
hands = (player.Value, handsComp);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when a user clicked on their hands GUI
|
/// Called when a user clicked on their hands GUI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void UIHandClick(HandsComponent hands, string handName)
|
public void UIHandClick(Entity<HandsComponent> ent, string handName)
|
||||||
{
|
{
|
||||||
if (!hands.Hands.TryGetValue(handName, out var pressedHand))
|
var hands = ent.Comp;
|
||||||
|
if (hands.ActiveHandId == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (hands.ActiveHand == null)
|
var pressedEntity = GetHeldItem(ent.AsNullable(), handName);
|
||||||
return;
|
var activeEntity = GetActiveItem(ent.AsNullable());
|
||||||
|
|
||||||
var pressedEntity = pressedHand.HeldEntity;
|
if (handName == hands.ActiveHandId && activeEntity != null)
|
||||||
var activeEntity = hands.ActiveHand.HeldEntity;
|
|
||||||
|
|
||||||
if (pressedHand == hands.ActiveHand && activeEntity != null)
|
|
||||||
{
|
{
|
||||||
// use item in hand
|
// use item in hand
|
||||||
// it will always be attack_self() in my heart.
|
// it will always be attack_self() in my heart.
|
||||||
EntityManager.RaisePredictiveEvent(new RequestUseInHandEvent());
|
RaisePredictiveEvent(new RequestUseInHandEvent());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressedHand != hands.ActiveHand && pressedEntity == null)
|
if (handName != hands.ActiveHandId && pressedEntity == null)
|
||||||
{
|
{
|
||||||
// change active hand
|
// change active hand
|
||||||
EntityManager.RaisePredictiveEvent(new RequestSetHandEvent(handName));
|
RaisePredictiveEvent(new RequestSetHandEvent(handName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressedHand != hands.ActiveHand && pressedEntity != null && activeEntity != null)
|
if (handName != hands.ActiveHandId && pressedEntity != null && activeEntity != null)
|
||||||
{
|
{
|
||||||
// use active item on held item
|
// use active item on held item
|
||||||
EntityManager.RaisePredictiveEvent(new RequestHandInteractUsingEvent(pressedHand.Name));
|
RaisePredictiveEvent(new RequestHandInteractUsingEvent(handName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressedHand != hands.ActiveHand && pressedEntity != null && activeEntity == null)
|
if (handName != hands.ActiveHandId && pressedEntity != null && activeEntity == null)
|
||||||
{
|
{
|
||||||
// move the item to the active hand
|
// move the item to the active hand
|
||||||
EntityManager.RaisePredictiveEvent(new RequestMoveHandItemEvent(pressedHand.Name));
|
RaisePredictiveEvent(new RequestMoveHandItemEvent(handName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -208,19 +170,18 @@ namespace Content.Client.Hands.Systems
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void UIHandActivate(string handName)
|
public void UIHandActivate(string handName)
|
||||||
{
|
{
|
||||||
EntityManager.RaisePredictiveEvent(new RequestActivateInHandEvent(handName));
|
RaisePredictiveEvent(new RequestActivateInHandEvent(handName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UIInventoryExamine(string handName)
|
public void UIInventoryExamine(string handName)
|
||||||
{
|
{
|
||||||
if (!TryGetPlayerHands(out var hands) ||
|
if (!TryGetPlayerHands(out var hands) ||
|
||||||
!hands.Hands.TryGetValue(handName, out var hand) ||
|
!TryGetHeldItem(hands.Value.AsNullable(), handName, out var heldEntity))
|
||||||
hand.HeldEntity is not { Valid: true } entity)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_examine.DoExamine(entity);
|
_examine.DoExamine(heldEntity.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -230,13 +191,12 @@ namespace Content.Client.Hands.Systems
|
||||||
public void UIHandOpenContextMenu(string handName)
|
public void UIHandOpenContextMenu(string handName)
|
||||||
{
|
{
|
||||||
if (!TryGetPlayerHands(out var hands) ||
|
if (!TryGetPlayerHands(out var hands) ||
|
||||||
!hands.Hands.TryGetValue(handName, out var hand) ||
|
!TryGetHeldItem(hands.Value.AsNullable(), handName, out var heldEntity))
|
||||||
hand.HeldEntity is not { Valid: true } entity)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ui.GetUIController<VerbMenuUIController>().OpenVerbMenu(entity);
|
_ui.GetUIController<VerbMenuUIController>().OpenVerbMenu(heldEntity.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UIHandAltActivateItem(string handName)
|
public void UIHandAltActivateItem(string handName)
|
||||||
|
|
@ -279,60 +239,67 @@ namespace Content.Client.Hands.Systems
|
||||||
{
|
{
|
||||||
base.HandleEntityInserted(uid, hands, args);
|
base.HandleEntityInserted(uid, hands, args);
|
||||||
|
|
||||||
if (!hands.Hands.TryGetValue(args.Container.ID, out var hand))
|
if (!hands.Hands.ContainsKey(args.Container.ID))
|
||||||
return;
|
return;
|
||||||
UpdateHandVisuals(uid, args.Entity, hand);
|
|
||||||
|
UpdateHandVisuals(uid, args.Entity, args.Container.ID);
|
||||||
_stripSys.UpdateUi(uid);
|
_stripSys.UpdateUi(uid);
|
||||||
|
|
||||||
if (uid != _playerManager.LocalEntity)
|
if (uid != _playerManager.LocalEntity)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OnPlayerItemAdded?.Invoke(hand.Name, args.Entity);
|
OnPlayerItemAdded?.Invoke(args.Container.ID, args.Entity);
|
||||||
|
|
||||||
if (HasComp<VirtualItemComponent>(args.Entity))
|
if (HasComp<VirtualItemComponent>(args.Entity))
|
||||||
OnPlayerHandBlocked?.Invoke(hand.Name);
|
OnPlayerHandBlocked?.Invoke(args.Container.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void HandleEntityRemoved(EntityUid uid, HandsComponent hands, EntRemovedFromContainerMessage args)
|
protected override void HandleEntityRemoved(EntityUid uid, HandsComponent hands, EntRemovedFromContainerMessage args)
|
||||||
{
|
{
|
||||||
base.HandleEntityRemoved(uid, hands, args);
|
base.HandleEntityRemoved(uid, hands, args);
|
||||||
|
|
||||||
if (!hands.Hands.TryGetValue(args.Container.ID, out var hand))
|
if (!hands.Hands.ContainsKey(args.Container.ID))
|
||||||
return;
|
return;
|
||||||
UpdateHandVisuals(uid, args.Entity, hand);
|
|
||||||
|
UpdateHandVisuals(uid, args.Entity, args.Container.ID);
|
||||||
_stripSys.UpdateUi(uid);
|
_stripSys.UpdateUi(uid);
|
||||||
|
|
||||||
if (uid != _playerManager.LocalEntity)
|
if (uid != _playerManager.LocalEntity)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
OnPlayerItemRemoved?.Invoke(hand.Name, args.Entity);
|
OnPlayerItemRemoved?.Invoke(args.Container.ID, args.Entity);
|
||||||
|
|
||||||
if (HasComp<VirtualItemComponent>(args.Entity))
|
if (HasComp<VirtualItemComponent>(args.Entity))
|
||||||
OnPlayerHandUnblocked?.Invoke(hand.Name);
|
OnPlayerHandUnblocked?.Invoke(args.Container.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update the players sprite with new in-hand visuals.
|
/// Update the players sprite with new in-hand visuals.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateHandVisuals(EntityUid uid, EntityUid held, Hand hand, HandsComponent? handComp = null, SpriteComponent? sprite = null)
|
private void UpdateHandVisuals(Entity<HandsComponent?, SpriteComponent?> ent, EntityUid held, string handId)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref handComp, ref sprite, false))
|
if (!Resolve(ent, ref ent.Comp1, ref ent.Comp2, false))
|
||||||
|
return;
|
||||||
|
var handComp = ent.Comp1;
|
||||||
|
var sprite = ent.Comp2;
|
||||||
|
|
||||||
|
if (!TryGetHand((ent, handComp), handId, out var hand))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// visual update might involve changes to the entity's effective sprite -> need to update hands GUI.
|
// visual update might involve changes to the entity's effective sprite -> need to update hands GUI.
|
||||||
if (uid == _playerManager.LocalEntity)
|
if (ent == _playerManager.LocalEntity)
|
||||||
OnPlayerItemAdded?.Invoke(hand.Name, held);
|
OnPlayerItemAdded?.Invoke(handId, held);
|
||||||
|
|
||||||
if (!handComp.ShowInHands)
|
if (!handComp.ShowInHands)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Remove old layers. We could also just set them to invisible, but as items may add arbitrary layers, this
|
// Remove old layers. We could also just set them to invisible, but as items may add arbitrary layers, this
|
||||||
// may eventually bloat the player with lots of layers.
|
// may eventually bloat the player with lots of layers.
|
||||||
if (handComp.RevealedLayers.TryGetValue(hand.Location, out var revealedLayers))
|
if (handComp.RevealedLayers.TryGetValue(hand.Value.Location, out var revealedLayers))
|
||||||
{
|
{
|
||||||
foreach (var key in revealedLayers)
|
foreach (var key in revealedLayers)
|
||||||
{
|
{
|
||||||
_sprite.RemoveLayer((uid, sprite), key);
|
_sprite.RemoveLayer((ent, sprite), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
revealedLayers.Clear();
|
revealedLayers.Clear();
|
||||||
|
|
@ -340,22 +307,22 @@ namespace Content.Client.Hands.Systems
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
revealedLayers = new();
|
revealedLayers = new();
|
||||||
handComp.RevealedLayers[hand.Location] = revealedLayers;
|
handComp.RevealedLayers[hand.Value.Location] = revealedLayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hand.HeldEntity == null)
|
if (HandIsEmpty((ent, handComp), handId))
|
||||||
{
|
{
|
||||||
// the held item was removed.
|
// the held item was removed.
|
||||||
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);
|
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(ent, revealedLayers), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ev = new GetInhandVisualsEvent(uid, hand.Location);
|
var ev = new GetInhandVisualsEvent(ent, hand.Value.Location);
|
||||||
RaiseLocalEvent(held, ev);
|
RaiseLocalEvent(held, ev);
|
||||||
|
|
||||||
if (ev.Layers.Count == 0)
|
if (ev.Layers.Count == 0)
|
||||||
{
|
{
|
||||||
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);
|
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(ent, revealedLayers), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -368,7 +335,7 @@ namespace Content.Client.Hands.Systems
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var index = _sprite.LayerMapReserve((uid, sprite), key);
|
var index = _sprite.LayerMapReserve((ent, sprite), key);
|
||||||
|
|
||||||
// In case no RSI is given, use the item's base RSI as a default. This cuts down on a lot of unnecessary yaml entries.
|
// In case no RSI is given, use the item's base RSI as a default. This cuts down on a lot of unnecessary yaml entries.
|
||||||
if (layerData.RsiPath == null
|
if (layerData.RsiPath == null
|
||||||
|
|
@ -376,35 +343,34 @@ namespace Content.Client.Hands.Systems
|
||||||
&& sprite[index].Rsi == null)
|
&& sprite[index].Rsi == null)
|
||||||
{
|
{
|
||||||
if (TryComp<ItemComponent>(held, out var itemComponent) && itemComponent.RsiPath != null)
|
if (TryComp<ItemComponent>(held, out var itemComponent) && itemComponent.RsiPath != null)
|
||||||
_sprite.LayerSetRsi((uid, sprite), index, new ResPath(itemComponent.RsiPath));
|
_sprite.LayerSetRsi((ent, sprite), index, new ResPath(itemComponent.RsiPath));
|
||||||
else if (TryComp(held, out SpriteComponent? clothingSprite))
|
else if (TryComp(held, out SpriteComponent? clothingSprite))
|
||||||
_sprite.LayerSetRsi((uid, sprite), index, clothingSprite.BaseRSI);
|
_sprite.LayerSetRsi((ent, sprite), index, clothingSprite.BaseRSI);
|
||||||
}
|
}
|
||||||
|
|
||||||
_sprite.LayerSetData((uid, sprite), index, layerData);
|
_sprite.LayerSetData((ent, sprite), index, layerData);
|
||||||
|
|
||||||
// Add displacement maps
|
// Add displacement maps
|
||||||
var displacement = hand.Location switch
|
var displacement = hand.Value.Location switch
|
||||||
{
|
{
|
||||||
HandLocation.Left => handComp.LeftHandDisplacement,
|
HandLocation.Left => handComp.LeftHandDisplacement,
|
||||||
HandLocation.Right => handComp.RightHandDisplacement,
|
HandLocation.Right => handComp.RightHandDisplacement,
|
||||||
_ => handComp.HandDisplacement
|
_ => handComp.HandDisplacement
|
||||||
};
|
};
|
||||||
|
|
||||||
if (displacement is not null && _displacement.TryAddDisplacement(displacement, (uid, sprite), index, key, out var displacementKey))
|
if (displacement is not null && _displacement.TryAddDisplacement(displacement, (ent, sprite), index, key, out var displacementKey))
|
||||||
revealedLayers.Add(displacementKey);
|
revealedLayers.Add(displacementKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);
|
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(ent, revealedLayers), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnVisualsChanged(EntityUid uid, HandsComponent component, VisualsChangedEvent args)
|
private void OnVisualsChanged(EntityUid uid, HandsComponent component, VisualsChangedEvent args)
|
||||||
{
|
{
|
||||||
// update hands visuals if this item is in a hand (rather then inventory or other container).
|
// update hands visuals if this item is in a hand (rather then inventory or other container).
|
||||||
if (component.Hands.TryGetValue(args.ContainerId, out var hand))
|
if (!component.Hands.ContainsKey(args.ContainerId))
|
||||||
{
|
return;
|
||||||
UpdateHandVisuals(uid, GetEntity(args.Item), hand, component);
|
UpdateHandVisuals((uid, component), GetEntity(args.Item), args.ContainerId);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
@ -412,7 +378,7 @@ namespace Content.Client.Hands.Systems
|
||||||
|
|
||||||
private void HandlePlayerAttached(EntityUid uid, HandsComponent component, LocalPlayerAttachedEvent args)
|
private void HandlePlayerAttached(EntityUid uid, HandsComponent component, LocalPlayerAttachedEvent args)
|
||||||
{
|
{
|
||||||
OnPlayerHandsAdded?.Invoke(component);
|
OnPlayerHandsAdded?.Invoke((uid, component));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandlePlayerDetached(EntityUid uid, HandsComponent component, LocalPlayerDetachedEvent args)
|
private void HandlePlayerDetached(EntityUid uid, HandsComponent component, LocalPlayerDetachedEvent args)
|
||||||
|
|
@ -423,7 +389,7 @@ namespace Content.Client.Hands.Systems
|
||||||
private void OnHandsStartup(EntityUid uid, HandsComponent component, ComponentStartup args)
|
private void OnHandsStartup(EntityUid uid, HandsComponent component, ComponentStartup args)
|
||||||
{
|
{
|
||||||
if (_playerManager.LocalEntity == uid)
|
if (_playerManager.LocalEntity == uid)
|
||||||
OnPlayerHandsAdded?.Invoke(component);
|
OnPlayerHandsAdded?.Invoke((uid, component));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHandsShutdown(EntityUid uid, HandsComponent component, ComponentShutdown args)
|
private void OnHandsShutdown(EntityUid uid, HandsComponent component, ComponentShutdown args)
|
||||||
|
|
@ -433,36 +399,6 @@ namespace Content.Client.Hands.Systems
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void AddHand(EntityUid uid, Hand newHand, HandsComponent? handsComp = null)
|
|
||||||
{
|
|
||||||
AddHand(uid, newHand.Name, newHand.Location, handsComp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void AddHand(EntityUid uid, string handName, HandLocation handLocation, HandsComponent? handsComp = null)
|
|
||||||
{
|
|
||||||
base.AddHand(uid, handName, handLocation, handsComp);
|
|
||||||
|
|
||||||
if (uid == _playerManager.LocalEntity)
|
|
||||||
OnPlayerAddHand?.Invoke(handName, handLocation);
|
|
||||||
|
|
||||||
if (handsComp == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (handsComp.ActiveHand == null)
|
|
||||||
SetActiveHand(uid, handsComp.Hands[handName], handsComp);
|
|
||||||
}
|
|
||||||
public override void RemoveHand(EntityUid uid, string handName, HandsComponent? handsComp = null)
|
|
||||||
{
|
|
||||||
if (uid == _playerManager.LocalEntity && handsComp != null &&
|
|
||||||
handsComp.Hands.ContainsKey(handName) && uid ==
|
|
||||||
_playerManager.LocalEntity)
|
|
||||||
{
|
|
||||||
OnPlayerRemoveHand?.Invoke(handName);
|
|
||||||
}
|
|
||||||
|
|
||||||
base.RemoveHand(uid, handName, handsComp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHandActivated(Entity<HandsComponent>? ent)
|
private void OnHandActivated(Entity<HandsComponent>? ent)
|
||||||
{
|
{
|
||||||
if (ent is not { } hand)
|
if (ent is not { } hand)
|
||||||
|
|
@ -471,13 +407,7 @@ namespace Content.Client.Hands.Systems
|
||||||
if (_playerManager.LocalEntity != hand.Owner)
|
if (_playerManager.LocalEntity != hand.Owner)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (hand.Comp.ActiveHand == null)
|
OnPlayerSetActiveHand?.Invoke(hand.Comp.ActiveHandId);
|
||||||
{
|
|
||||||
OnPlayerSetActiveHand?.Invoke(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnPlayerSetActiveHand?.Invoke(hand.Comp.ActiveHand.Name);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using Robust.Client.Graphics;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
||||||
|
|
||||||
namespace Content.Client.Holopad;
|
namespace Content.Client.Holopad;
|
||||||
|
|
@ -107,7 +108,7 @@ public sealed class HolopadSystem : SharedHolopadSystem
|
||||||
// Remove shading from all layers (except displacement maps)
|
// Remove shading from all layers (except displacement maps)
|
||||||
for (var i = 0; i < hologramSprite.AllLayers.Count(); i++)
|
for (var i = 0; i < hologramSprite.AllLayers.Count(); i++)
|
||||||
{
|
{
|
||||||
if (_sprite.TryGetLayer((hologram, hologramSprite), i, out var layer, false) && layer.ShaderPrototype != "DisplacedStencilDraw")
|
if (_sprite.TryGetLayer((hologram, hologramSprite), i, out var layer, false) && layer.ShaderPrototype != "DisplacedDraw")
|
||||||
hologramSprite.LayerSetShader(i, "unshaded");
|
hologramSprite.LayerSetShader(i, "unshaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ public sealed class EyeColorPicker : Control
|
||||||
AddChild(vBox);
|
AddChild(vBox);
|
||||||
|
|
||||||
vBox.AddChild(_colorSelectors = new ColorSelectorSliders());
|
vBox.AddChild(_colorSelectors = new ColorSelectorSliders());
|
||||||
|
_colorSelectors.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
|
||||||
|
|
||||||
_colorSelectors.OnColorChanged += ColorValueChanged;
|
_colorSelectors.OnColorChanged += ColorValueChanged;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||||
|
|
||||||
private void OnCvarChanged(bool value)
|
private void OnCvarChanged(bool value)
|
||||||
{
|
{
|
||||||
var humanoidQuery = EntityManager.AllEntityQueryEnumerator<HumanoidAppearanceComponent, SpriteComponent>();
|
var humanoidQuery = AllEntityQuery<HumanoidAppearanceComponent, SpriteComponent>();
|
||||||
while (humanoidQuery.MoveNext(out var uid, out var humanoidComp, out var spriteComp))
|
while (humanoidQuery.MoveNext(out var uid, out var humanoidComp, out var spriteComp))
|
||||||
{
|
{
|
||||||
UpdateSprite((uid, humanoidComp, spriteComp));
|
UpdateSprite((uid, humanoidComp, spriteComp));
|
||||||
|
|
|
||||||
|
|
@ -416,6 +416,7 @@ public sealed partial class MarkingPicker : Control
|
||||||
CMarkingColors.AddChild(colorContainer);
|
CMarkingColors.AddChild(colorContainer);
|
||||||
|
|
||||||
ColorSelectorSliders colorSelector = new ColorSelectorSliders();
|
ColorSelectorSliders colorSelector = new ColorSelectorSliders();
|
||||||
|
colorSelector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
|
||||||
colorSliders.Add(colorSelector);
|
colorSliders.Add(colorSelector);
|
||||||
|
|
||||||
colorContainer.AddChild(new Label { Text = $"{stateNames[i]} color:" });
|
colorContainer.AddChild(new Label { Text = $"{stateNames[i]} color:" });
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,7 @@ public sealed partial class SingleMarkingPicker : BoxContainer
|
||||||
HorizontalExpand = true
|
HorizontalExpand = true
|
||||||
};
|
};
|
||||||
selector.Color = marking.MarkingColors[i];
|
selector.Color = marking.MarkingColors[i];
|
||||||
|
selector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
|
||||||
|
|
||||||
var colorIndex = i;
|
var colorIndex = i;
|
||||||
selector.OnColorChanged += color =>
|
selector.OnColorChanged += color =>
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,8 @@ public static class MidiParser
|
||||||
// 0x03 is TrackName,
|
// 0x03 is TrackName,
|
||||||
// 0x04 is InstrumentName
|
// 0x04 is InstrumentName
|
||||||
|
|
||||||
|
// This string can potentially contain control characters, including 0x00 which can cause problems if it ends up in database entries via admin logs
|
||||||
|
// we sanitize TrackName and InstrumentName after they have been send to the server
|
||||||
var text = Encoding.ASCII.GetString(metaData, 0, (int)metaLength);
|
var text = Encoding.ASCII.GetString(metaData, 0, (int)metaLength);
|
||||||
switch (metaType)
|
switch (metaType)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,14 @@ namespace Content.Client.Interactable.Components
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed partial class InteractionOutlineComponent : Component
|
public sealed partial class InteractionOutlineComponent : Component
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> ShaderInRange = "SelectionOutlineInrange";
|
||||||
|
private static readonly ProtoId<ShaderPrototype> ShaderOutOfRange = "SelectionOutline";
|
||||||
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
|
|
||||||
private const float DefaultWidth = 1;
|
private const float DefaultWidth = 1;
|
||||||
|
|
||||||
[ValidatePrototypeId<ShaderPrototype>]
|
|
||||||
private const string ShaderInRange = "SelectionOutlineInrange";
|
|
||||||
|
|
||||||
[ValidatePrototypeId<ShaderPrototype>]
|
|
||||||
private const string ShaderOutOfRange = "SelectionOutline";
|
|
||||||
|
|
||||||
private bool _inRange;
|
private bool _inRange;
|
||||||
private ShaderInstance? _shader;
|
private ShaderInstance? _shader;
|
||||||
private int _lastRenderScale;
|
private int _lastRenderScale;
|
||||||
|
|
@ -65,7 +62,7 @@ namespace Content.Client.Interactable.Components
|
||||||
{
|
{
|
||||||
var shaderName = inRange ? ShaderInRange : ShaderOutOfRange;
|
var shaderName = inRange ? ShaderInRange : ShaderOutOfRange;
|
||||||
|
|
||||||
var instance = _prototypeManager.Index<ShaderPrototype>(shaderName).InstanceUnique();
|
var instance = _prototypeManager.Index(shaderName).InstanceUnique();
|
||||||
instance.SetParameter("outline_width", DefaultWidth * renderScale);
|
instance.SetParameter("outline_width", DefaultWidth * renderScale);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,10 @@ namespace Content.Client.Interaction;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class DragDropSystem : SharedDragDropSystem
|
public sealed class DragDropSystem : SharedDragDropSystem
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> ShaderDropTargetInRange = "SelectionOutlineInrange";
|
||||||
|
|
||||||
|
private static readonly ProtoId<ShaderPrototype> ShaderDropTargetOutOfRange = "SelectionOutline";
|
||||||
|
|
||||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||||
|
|
@ -54,12 +58,6 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||||
// mousedown event so it can be treated like a regular click
|
// mousedown event so it can be treated like a regular click
|
||||||
private const float MaxMouseDownTimeForReplayingClick = 0.85f;
|
private const float MaxMouseDownTimeForReplayingClick = 0.85f;
|
||||||
|
|
||||||
[ValidatePrototypeId<ShaderPrototype>]
|
|
||||||
private const string ShaderDropTargetInRange = "SelectionOutlineInrange";
|
|
||||||
|
|
||||||
[ValidatePrototypeId<ShaderPrototype>]
|
|
||||||
private const string ShaderDropTargetOutOfRange = "SelectionOutline";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current entity being dragged around.
|
/// Current entity being dragged around.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -113,8 +111,8 @@ public sealed class DragDropSystem : SharedDragDropSystem
|
||||||
|
|
||||||
Subs.CVar(_cfgMan, CCVars.DragDropDeadZone, SetDeadZone, true);
|
Subs.CVar(_cfgMan, CCVars.DragDropDeadZone, SetDeadZone, true);
|
||||||
|
|
||||||
_dropTargetInRangeShader = _prototypeManager.Index<ShaderPrototype>(ShaderDropTargetInRange).Instance();
|
_dropTargetInRangeShader = _prototypeManager.Index(ShaderDropTargetInRange).Instance();
|
||||||
_dropTargetOutOfRangeShader = _prototypeManager.Index<ShaderPrototype>(ShaderDropTargetOutOfRange).Instance();
|
_dropTargetOutOfRangeShader = _prototypeManager.Index(ShaderDropTargetOutOfRange).Instance();
|
||||||
// needs to fire on mouseup and mousedown so we can detect a drag / drop
|
// needs to fire on mouseup and mousedown so we can detect a drag / drop
|
||||||
CommandBinds.Builder
|
CommandBinds.Builder
|
||||||
.BindBefore(EngineKeyFunctions.Use, new PointerInputCmdHandler(OnUse, false, true), new[] { typeof(SharedInteractionSystem) })
|
.BindBefore(EngineKeyFunctions.Use, new PointerInputCmdHandler(OnUse, false, true), new[] { typeof(SharedInteractionSystem) })
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Linq;
|
||||||
using Content.Client.Clothing;
|
using Content.Client.Clothing;
|
||||||
using Content.Client.Examine;
|
using Content.Client.Examine;
|
||||||
using Content.Client.Verbs.UI;
|
using Content.Client.Verbs.UI;
|
||||||
|
|
@ -12,6 +13,7 @@ using Robust.Client.UserInterface;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Input.Binding;
|
using Robust.Shared.Input.Binding;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Client.Inventory
|
namespace Content.Client.Inventory
|
||||||
{
|
{
|
||||||
|
|
@ -20,7 +22,7 @@ namespace Content.Client.Inventory
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly ClientClothingSystem _clothingVisualsSystem = default!;
|
[Dependency] private readonly ClientClothingSystem _clothingVisualsSystem = default!;
|
||||||
[Dependency] private readonly ExamineSystem _examine = default!;
|
[Dependency] private readonly ExamineSystem _examine = default!;
|
||||||
|
|
||||||
|
|
@ -92,6 +94,14 @@ namespace Content.Client.Inventory
|
||||||
|
|
||||||
private void OnShutdown(EntityUid uid, InventoryComponent component, ComponentShutdown args)
|
private void OnShutdown(EntityUid uid, InventoryComponent component, ComponentShutdown args)
|
||||||
{
|
{
|
||||||
|
if (TryComp(uid, out InventorySlotsComponent? inventorySlots))
|
||||||
|
{
|
||||||
|
foreach (var slot in component.Slots)
|
||||||
|
{
|
||||||
|
TryRemoveSlotData((uid, inventorySlots), (SlotData)slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (uid == _playerManager.LocalEntity)
|
if (uid == _playerManager.LocalEntity)
|
||||||
OnUnlinkInventory?.Invoke();
|
OnUnlinkInventory?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
@ -103,23 +113,6 @@ namespace Content.Client.Inventory
|
||||||
|
|
||||||
private void OnPlayerAttached(EntityUid uid, InventorySlotsComponent component, LocalPlayerAttachedEvent args)
|
private void OnPlayerAttached(EntityUid uid, InventorySlotsComponent component, LocalPlayerAttachedEvent args)
|
||||||
{
|
{
|
||||||
if (TryGetSlots(uid, out var definitions))
|
|
||||||
{
|
|
||||||
foreach (var definition in definitions)
|
|
||||||
{
|
|
||||||
if (!TryGetSlotContainer(uid, definition.Name, out var container, out _))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!component.SlotData.TryGetValue(definition.Name, out var data))
|
|
||||||
{
|
|
||||||
data = new SlotData(definition);
|
|
||||||
component.SlotData[definition.Name] = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Container = container;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OnLinkInventorySlots?.Invoke(uid, component);
|
OnLinkInventorySlots?.Invoke(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,20 +122,6 @@ namespace Content.Client.Inventory
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnInit(EntityUid uid, InventoryComponent component, ComponentInit args)
|
|
||||||
{
|
|
||||||
base.OnInit(uid, component, args);
|
|
||||||
_clothingVisualsSystem.InitClothing(uid, component);
|
|
||||||
|
|
||||||
if (!TryComp(uid, out InventorySlotsComponent? inventorySlots))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var slot in component.Slots)
|
|
||||||
{
|
|
||||||
TryAddSlotDef(uid, inventorySlots, slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReloadInventory(InventorySlotsComponent? component = null)
|
public void ReloadInventory(InventorySlotsComponent? component = null)
|
||||||
{
|
{
|
||||||
var player = _playerManager.LocalEntity;
|
var player = _playerManager.LocalEntity;
|
||||||
|
|
@ -166,7 +145,10 @@ namespace Content.Client.Inventory
|
||||||
public void UpdateSlot(EntityUid owner, InventorySlotsComponent component, string slotName,
|
public void UpdateSlot(EntityUid owner, InventorySlotsComponent component, string slotName,
|
||||||
bool? blocked = null, bool? highlight = null)
|
bool? blocked = null, bool? highlight = null)
|
||||||
{
|
{
|
||||||
var oldData = component.SlotData[slotName];
|
// The slot might have been removed when changing templates, which can cause items to be dropped.
|
||||||
|
if (!component.SlotData.TryGetValue(slotName, out var oldData))
|
||||||
|
return;
|
||||||
|
|
||||||
var newHighlight = oldData.Highlighted;
|
var newHighlight = oldData.Highlighted;
|
||||||
var newBlocked = oldData.Blocked;
|
var newBlocked = oldData.Blocked;
|
||||||
|
|
||||||
|
|
@ -182,25 +164,39 @@ namespace Content.Client.Inventory
|
||||||
EntitySlotUpdate?.Invoke(newData);
|
EntitySlotUpdate?.Invoke(newData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAddSlotDef(EntityUid owner, InventorySlotsComponent component, SlotDefinition newSlotDef)
|
public bool TryAddSlotData(Entity<InventorySlotsComponent> ent, SlotData newSlotData)
|
||||||
{
|
{
|
||||||
SlotData newSlotData = newSlotDef; //convert to slotData
|
if (!ent.Comp.SlotData.TryAdd(newSlotData.SlotName, newSlotData))
|
||||||
if (!component.SlotData.TryAdd(newSlotDef.Name, newSlotData))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (owner == _playerManager.LocalEntity)
|
if (TryGetSlotContainer(ent.Owner, newSlotData.SlotName, out var newContainer, out _))
|
||||||
|
ent.Comp.SlotData[newSlotData.SlotName].Container = newContainer;
|
||||||
|
|
||||||
|
if (ent.Owner == _playerManager.LocalEntity)
|
||||||
OnSlotAdded?.Invoke(newSlotData);
|
OnSlotAdded?.Invoke(newSlotData);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryRemoveSlotData(Entity<InventorySlotsComponent> ent, SlotData removedSlotData)
|
||||||
|
{
|
||||||
|
if (!ent.Comp.SlotData.Remove(removedSlotData.SlotName))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ent.Owner == _playerManager.LocalEntity)
|
||||||
|
OnSlotRemoved?.Invoke(removedSlotData);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UIInventoryActivate(string slot)
|
public void UIInventoryActivate(string slot)
|
||||||
{
|
{
|
||||||
EntityManager.RaisePredictiveEvent(new UseSlotNetworkMessage(slot));
|
RaisePredictiveEvent(new UseSlotNetworkMessage(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UIInventoryStorageActivate(string slot)
|
public void UIInventoryStorageActivate(string slot)
|
||||||
{
|
{
|
||||||
EntityManager.RaisePredictiveEvent(new OpenSlotStorageNetworkMessage(slot));
|
RaisePredictiveEvent(new OpenSlotStorageNetworkMessage(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UIInventoryExamine(string slot, EntityUid uid)
|
public void UIInventoryExamine(string slot, EntityUid uid)
|
||||||
|
|
@ -224,7 +220,7 @@ namespace Content.Client.Inventory
|
||||||
if (!TryGetSlotEntity(uid, slot, out var item))
|
if (!TryGetSlotEntity(uid, slot, out var item))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EntityManager.RaisePredictiveEvent(
|
RaisePredictiveEvent(
|
||||||
new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: false));
|
new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,41 +229,59 @@ namespace Content.Client.Inventory
|
||||||
if (!TryGetSlotEntity(uid, slot, out var item))
|
if (!TryGetSlotEntity(uid, slot, out var item))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EntityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true));
|
RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateInventoryTemplate(Entity<InventoryComponent> ent)
|
protected override void UpdateInventoryTemplate(Entity<InventoryComponent> ent)
|
||||||
{
|
{
|
||||||
base.UpdateInventoryTemplate(ent);
|
base.UpdateInventoryTemplate(ent);
|
||||||
|
|
||||||
if (TryComp(ent, out InventorySlotsComponent? inventorySlots))
|
if (!TryComp<InventorySlotsComponent>(ent, out var inventorySlots))
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<SlotData> slotDataToRemove = new(); // don't modify dict while iterating
|
||||||
|
|
||||||
|
foreach (var slotData in inventorySlots.SlotData.Values)
|
||||||
{
|
{
|
||||||
|
if (!ent.Comp.Slots.Any(s => s.Name == slotData.SlotName))
|
||||||
|
slotDataToRemove.Add(slotData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove slots that are no longer in the new template
|
||||||
|
foreach (var slotData in slotDataToRemove)
|
||||||
|
{
|
||||||
|
TryRemoveSlotData((ent.Owner, inventorySlots), slotData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update existing slots or add them if they don't exist yet
|
||||||
foreach (var slot in ent.Comp.Slots)
|
foreach (var slot in ent.Comp.Slots)
|
||||||
{
|
{
|
||||||
if (inventorySlots.SlotData.TryGetValue(slot.Name, out var slotData))
|
if (inventorySlots.SlotData.TryGetValue(slot.Name, out var slotData))
|
||||||
slotData.SlotDef = slot;
|
slotData.SlotDef = slot;
|
||||||
|
else
|
||||||
|
TryAddSlotData((ent.Owner, inventorySlots), (SlotData)slot);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
_clothingVisualsSystem.InitClothing(ent, ent.Comp);
|
||||||
|
if (ent.Owner == _playerManager.LocalEntity)
|
||||||
|
ReloadInventory(inventorySlots);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class SlotData
|
public sealed class SlotData
|
||||||
{
|
{
|
||||||
[ViewVariables] // Shitmed Change - Mostly for debugging.
|
[ViewVariables] public SlotDefinition SlotDef;
|
||||||
public SlotDefinition SlotDef;
|
[ViewVariables] public EntityUid? HeldEntity => Container?.ContainedEntity;
|
||||||
public EntityUid? HeldEntity => Container?.ContainedEntity;
|
[ViewVariables] public bool Blocked;
|
||||||
public bool Blocked;
|
[ViewVariables] public bool Highlighted;
|
||||||
public bool Highlighted;
|
[ViewVariables] public ContainerSlot? Container;
|
||||||
|
[ViewVariables] public bool HasSlotGroup => SlotDef.SlotGroup != "Default";
|
||||||
[ViewVariables]
|
[ViewVariables] public Vector2i ButtonOffset => SlotDef.UIWindowPosition;
|
||||||
public ContainerSlot? Container;
|
[ViewVariables] public string SlotName => SlotDef.Name;
|
||||||
public bool HasSlotGroup => SlotDef.SlotGroup != "Default";
|
[ViewVariables] public bool ShowInWindow => SlotDef.ShowInWindow;
|
||||||
public Vector2i ButtonOffset => SlotDef.UIWindowPosition;
|
[ViewVariables] public string SlotGroup => SlotDef.SlotGroup;
|
||||||
public string SlotName => SlotDef.Name;
|
[ViewVariables] public string SlotDisplayName => SlotDef.DisplayName;
|
||||||
public bool ShowInWindow => SlotDef.ShowInWindow;
|
[ViewVariables] public string TextureName => "Slots/" + SlotDef.TextureName;
|
||||||
public string SlotGroup => SlotDef.SlotGroup;
|
[ViewVariables] public string FullTextureName => SlotDef.FullTextureName;
|
||||||
public string SlotDisplayName => SlotDef.DisplayName;
|
|
||||||
public string TextureName => "Slots/" + SlotDef.TextureName;
|
|
||||||
public string FullTextureName => SlotDef.FullTextureName;
|
|
||||||
|
|
||||||
public SlotData(SlotDefinition slotDef, ContainerSlot? container = null, bool highlighted = false,
|
public SlotData(SlotDefinition slotDef, ContainerSlot? container = null, bool highlighted = false,
|
||||||
bool blocked = false)
|
bool blocked = false)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Client.Examine;
|
using Content.Client.Examine;
|
||||||
|
using Content.Client.Hands.Systems;
|
||||||
using Content.Client.Strip;
|
using Content.Client.Strip;
|
||||||
using Content.Client.Stylesheets;
|
using Content.Client.Stylesheets;
|
||||||
using Content.Client.UserInterface.Controls;
|
using Content.Client.UserInterface.Controls;
|
||||||
|
|
@ -34,6 +35,7 @@ namespace Content.Client.Inventory
|
||||||
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
||||||
|
|
||||||
private readonly ExamineSystem _examine;
|
private readonly ExamineSystem _examine;
|
||||||
|
private readonly HandsSystem _hands;
|
||||||
private readonly InventorySystem _inv;
|
private readonly InventorySystem _inv;
|
||||||
private readonly SharedCuffableSystem _cuffable;
|
private readonly SharedCuffableSystem _cuffable;
|
||||||
private readonly StrippableSystem _strippable;
|
private readonly StrippableSystem _strippable;
|
||||||
|
|
@ -65,6 +67,7 @@ namespace Content.Client.Inventory
|
||||||
public StrippableBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
public StrippableBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||||
{
|
{
|
||||||
_examine = EntMan.System<ExamineSystem>();
|
_examine = EntMan.System<ExamineSystem>();
|
||||||
|
_hands = EntMan.System<HandsSystem>();
|
||||||
_inv = EntMan.System<InventorySystem>();
|
_inv = EntMan.System<InventorySystem>();
|
||||||
_cuffable = EntMan.System<SharedCuffableSystem>();
|
_cuffable = EntMan.System<SharedCuffableSystem>();
|
||||||
_strippable = EntMan.System<StrippableSystem>();
|
_strippable = EntMan.System<StrippableSystem>();
|
||||||
|
|
@ -120,28 +123,28 @@ namespace Content.Client.Inventory
|
||||||
{
|
{
|
||||||
// good ol hands shit code. there is a GuiHands comparer that does the same thing... but these are hands
|
// good ol hands shit code. there is a GuiHands comparer that does the same thing... but these are hands
|
||||||
// and not gui hands... which are different...
|
// and not gui hands... which are different...
|
||||||
foreach (var hand in handsComp.Hands.Values)
|
foreach (var (id, hand) in handsComp.Hands)
|
||||||
{
|
{
|
||||||
if (hand.Location != HandLocation.Right)
|
if (hand.Location != HandLocation.Right)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
AddHandButton(hand);
|
AddHandButton((Owner, handsComp), id, hand);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var hand in handsComp.Hands.Values)
|
foreach (var (id, hand) in handsComp.Hands)
|
||||||
{
|
{
|
||||||
if (hand.Location != HandLocation.Middle)
|
if (hand.Location != HandLocation.Middle)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
AddHandButton(hand);
|
AddHandButton((Owner, handsComp), id, hand);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var hand in handsComp.Hands.Values)
|
foreach (var (id, hand) in handsComp.Hands)
|
||||||
{
|
{
|
||||||
if (hand.Location != HandLocation.Left)
|
if (hand.Location != HandLocation.Left)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
AddHandButton(hand);
|
AddHandButton((Owner, handsComp), id, hand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,20 +180,21 @@ namespace Content.Client.Inventory
|
||||||
_strippingMenu.SetSize = new Vector2(horizontalMenuSize, verticalMenuSize);
|
_strippingMenu.SetSize = new Vector2(horizontalMenuSize, verticalMenuSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddHandButton(Hand hand)
|
private void AddHandButton(Entity<HandsComponent> ent, string handId, Hand hand)
|
||||||
{
|
{
|
||||||
var button = new HandButton(hand.Name, hand.Location);
|
var button = new HandButton(handId, hand.Location);
|
||||||
|
|
||||||
button.Pressed += SlotPressed;
|
button.Pressed += SlotPressed;
|
||||||
|
|
||||||
if (EntMan.TryGetComponent<VirtualItemComponent>(hand.HeldEntity, out var virt))
|
var heldEntity = _hands.GetHeldItem(ent.AsNullable(), handId);
|
||||||
|
if (EntMan.TryGetComponent<VirtualItemComponent>(heldEntity, out var virt))
|
||||||
{
|
{
|
||||||
button.Blocked = true;
|
button.Blocked = true;
|
||||||
if (EntMan.TryGetComponent<CuffableComponent>(Owner, out var cuff) && _cuffable.GetAllCuffs(cuff).Contains(virt.BlockingEntity))
|
if (EntMan.TryGetComponent<CuffableComponent>(Owner, out var cuff) && _cuffable.GetAllCuffs(cuff).Contains(virt.BlockingEntity))
|
||||||
button.BlockedRect.MouseFilter = MouseFilterMode.Ignore;
|
button.BlockedRect.MouseFilter = MouseFilterMode.Ignore;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateEntityIcon(button, hand.HeldEntity);
|
UpdateEntityIcon(button, heldEntity);
|
||||||
_strippingMenu!.HandsContainer.AddChild(button);
|
_strippingMenu!.HandsContainer.AddChild(button);
|
||||||
LayoutContainer.SetPosition(button, new Vector2i(_handCount, 0) * (SlotControl.DefaultButtonSize + ButtonSeparation));
|
LayoutContainer.SetPosition(button, new Vector2i(_handCount, 0) * (SlotControl.DefaultButtonSize + ButtonSeparation));
|
||||||
_handCount++;
|
_handCount++;
|
||||||
|
|
|
||||||
|
|
@ -266,13 +266,14 @@ public sealed partial class LatheMenu : DefaultWindow
|
||||||
/// Populates the build queue list with all queued items
|
/// Populates the build queue list with all queued items
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="queue"></param>
|
/// <param name="queue"></param>
|
||||||
public void PopulateQueueList(List<LatheRecipePrototype> queue)
|
public void PopulateQueueList(IReadOnlyCollection<ProtoId<LatheRecipePrototype>> queue)
|
||||||
{
|
{
|
||||||
QueueList.DisposeAllChildren();
|
QueueList.DisposeAllChildren();
|
||||||
|
|
||||||
var idx = 1;
|
var idx = 1;
|
||||||
foreach (var recipe in queue)
|
foreach (var recipeProto in queue)
|
||||||
{
|
{
|
||||||
|
var recipe = _prototypeManager.Index(recipeProto);
|
||||||
var queuedRecipeBox = new BoxContainer();
|
var queuedRecipeBox = new BoxContainer();
|
||||||
queuedRecipeBox.Orientation = BoxContainer.LayoutOrientation.Horizontal;
|
queuedRecipeBox.Orientation = BoxContainer.LayoutOrientation.Horizontal;
|
||||||
|
|
||||||
|
|
@ -286,12 +287,14 @@ public sealed partial class LatheMenu : DefaultWindow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetQueueInfo(LatheRecipePrototype? recipe)
|
public void SetQueueInfo(ProtoId<LatheRecipePrototype>? recipeProto)
|
||||||
{
|
{
|
||||||
FabricatingContainer.Visible = recipe != null;
|
FabricatingContainer.Visible = recipeProto != null;
|
||||||
if (recipe == null)
|
if (recipeProto == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var recipe = _prototypeManager.Index(recipeProto.Value);
|
||||||
|
|
||||||
FabricatingDisplayContainer.Children.Clear();
|
FabricatingDisplayContainer.Children.Clear();
|
||||||
FabricatingDisplayContainer.AddChild(GetRecipeDisplayControl(recipe));
|
FabricatingDisplayContainer.AddChild(GetRecipeDisplayControl(recipe));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
using System.Numerics;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Maps;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Client.Light;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies ambient-occlusion to the viewport.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class AmbientOcclusionOverlay : Overlay
|
||||||
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||||
|
private static readonly ProtoId<ShaderPrototype> StencilMaskShader = "StencilMask";
|
||||||
|
private static readonly ProtoId<ShaderPrototype> StencilEqualDrawShader = "StencilEqualDraw";
|
||||||
|
|
||||||
|
[Dependency] private readonly IClyde _clyde = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
|
|
||||||
|
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowEntities;
|
||||||
|
|
||||||
|
private IRenderTexture? _aoTarget;
|
||||||
|
private IRenderTexture? _aoBlurBuffer;
|
||||||
|
|
||||||
|
// Couldn't figure out a way to avoid this so if you can then please do.
|
||||||
|
private IRenderTexture? _aoStencilTarget;
|
||||||
|
|
||||||
|
public AmbientOcclusionOverlay()
|
||||||
|
{
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
ZIndex = AfterLightTargetOverlay.ContentZIndex + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Draw(in OverlayDrawArgs args)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* tl;dr
|
||||||
|
* - we draw a black square on each "ambient occlusion" entity.
|
||||||
|
* - we blur this.
|
||||||
|
* - We apply it to the viewport.
|
||||||
|
*
|
||||||
|
* We do this while ignoring lighting because it will wash out the actual effect.
|
||||||
|
* In 3D ambient occlusion is more complicated due top having to calculate normals but in 2D
|
||||||
|
* we don't have a concept of depth / corners necessarily.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var viewport = args.Viewport;
|
||||||
|
var mapId = args.MapId;
|
||||||
|
var worldBounds = args.WorldBounds;
|
||||||
|
var worldHandle = args.WorldHandle;
|
||||||
|
var color = Color.FromHex(_cfgManager.GetCVar(CCVars.AmbientOcclusionColor));
|
||||||
|
var distance = _cfgManager.GetCVar(CCVars.AmbientOcclusionDistance);
|
||||||
|
//var color = Color.Red;
|
||||||
|
var target = viewport.RenderTarget;
|
||||||
|
var lightScale = target.Size / (Vector2) viewport.Size;
|
||||||
|
var scale = viewport.RenderScale / (Vector2.One / lightScale);
|
||||||
|
var maps = _entManager.System<SharedMapSystem>();
|
||||||
|
var lookups = _entManager.System<EntityLookupSystem>();
|
||||||
|
var query = _entManager.System<OccluderSystem>();
|
||||||
|
var xformSystem = _entManager.System<SharedTransformSystem>();
|
||||||
|
var turfSystem = _entManager.System<TurfSystem>();
|
||||||
|
var invMatrix = args.Viewport.GetWorldToLocalMatrix();
|
||||||
|
|
||||||
|
if (_aoTarget?.Texture.Size != target.Size)
|
||||||
|
{
|
||||||
|
_aoTarget?.Dispose();
|
||||||
|
_aoTarget = _clyde.CreateRenderTarget(target.Size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "ambient-occlusion-target");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_aoBlurBuffer?.Texture.Size != target.Size)
|
||||||
|
{
|
||||||
|
_aoBlurBuffer?.Dispose();
|
||||||
|
_aoBlurBuffer = _clyde.CreateRenderTarget(target.Size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "ambient-occlusion-blur-target");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_aoStencilTarget?.Texture.Size != target.Size)
|
||||||
|
{
|
||||||
|
_aoStencilTarget?.Dispose();
|
||||||
|
_aoStencilTarget = _clyde.CreateRenderTarget(target.Size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "ambient-occlusion-stencil-target");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the texture data to the texture.
|
||||||
|
args.WorldHandle.RenderInRenderTarget(_aoTarget,
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
worldHandle.UseShader(_proto.Index(UnshadedShader).Instance());
|
||||||
|
var invMatrix = _aoTarget.GetWorldToLocalMatrix(viewport.Eye!, scale);
|
||||||
|
|
||||||
|
foreach (var entry in query.QueryAabb(mapId, worldBounds))
|
||||||
|
{
|
||||||
|
DebugTools.Assert(entry.Component.Enabled);
|
||||||
|
var matrix = xformSystem.GetWorldMatrix(entry.Transform);
|
||||||
|
var localMatrix = Matrix3x2.Multiply(matrix, invMatrix);
|
||||||
|
|
||||||
|
worldHandle.SetTransform(localMatrix);
|
||||||
|
// 4 pixels
|
||||||
|
worldHandle.DrawRect(Box2.UnitCentered.Enlarged(distance / EyeManager.PixelsPerMeter), Color.White);
|
||||||
|
}
|
||||||
|
}, Color.Transparent);
|
||||||
|
|
||||||
|
_clyde.BlurRenderTarget(viewport, _aoTarget, _aoBlurBuffer, viewport.Eye!, 14f);
|
||||||
|
|
||||||
|
// Need to do stencilling after blur as it will nuke it.
|
||||||
|
// Draw stencil for the grid so we don't draw in space.
|
||||||
|
args.WorldHandle.RenderInRenderTarget(_aoStencilTarget,
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
// Don't want lighting affecting it.
|
||||||
|
worldHandle.UseShader(_proto.Index(UnshadedShader).Instance());
|
||||||
|
|
||||||
|
foreach (var grid in _mapManager.FindGridsIntersecting(mapId, worldBounds))
|
||||||
|
{
|
||||||
|
var transform = xformSystem.GetWorldMatrix(grid.Owner);
|
||||||
|
var worldToTextureMatrix = Matrix3x2.Multiply(transform, invMatrix);
|
||||||
|
var tiles = maps.GetTilesEnumerator(grid.Owner, grid, worldBounds);
|
||||||
|
worldHandle.SetTransform(worldToTextureMatrix);
|
||||||
|
while (tiles.MoveNext(out var tileRef))
|
||||||
|
{
|
||||||
|
if (turfSystem.IsSpace(tileRef))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var bounds = lookups.GetLocalBounds(tileRef, grid.TileSize);
|
||||||
|
worldHandle.DrawRect(bounds, Color.White);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, Color.Transparent);
|
||||||
|
|
||||||
|
// Draw the stencil texture to depth buffer.
|
||||||
|
worldHandle.UseShader(_proto.Index(StencilMaskShader).Instance());
|
||||||
|
worldHandle.DrawTextureRect(_aoStencilTarget!.Texture, worldBounds);
|
||||||
|
|
||||||
|
// Draw the Blurred AO texture finally.
|
||||||
|
worldHandle.UseShader(_proto.Index(StencilEqualDrawShader).Instance());
|
||||||
|
worldHandle.DrawTextureRect(_aoTarget!.Texture, worldBounds, color);
|
||||||
|
|
||||||
|
args.WorldHandle.SetTransform(Matrix3x2.Identity);
|
||||||
|
args.WorldHandle.UseShader(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -238,6 +238,9 @@ namespace Content.Client.Light.Components
|
||||||
|
|
||||||
public override void OnInitialize()
|
public override void OnInitialize()
|
||||||
{
|
{
|
||||||
|
// This is very janky. This could easily result in no visible animation at all if the random values happen
|
||||||
|
// to all be close to each other.
|
||||||
|
// TODO ANIMATIONS
|
||||||
_randomValue1 = (float)InterpolateLinear(StartValue, EndValue, (float)_random.NextDouble());
|
_randomValue1 = (float)InterpolateLinear(StartValue, EndValue, (float)_random.NextDouble());
|
||||||
_randomValue2 = (float)InterpolateLinear(StartValue, EndValue, (float)_random.NextDouble());
|
_randomValue2 = (float)InterpolateLinear(StartValue, EndValue, (float)_random.NextDouble());
|
||||||
_randomValue3 = (float)InterpolateLinear(StartValue, EndValue, (float)_random.NextDouble());
|
_randomValue3 = (float)InterpolateLinear(StartValue, EndValue, (float)_random.NextDouble());
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ public sealed class LightBehaviorSystem : EntitySystem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void CopyLightSettings(Entity<LightBehaviourComponent> entity, string property)
|
private void CopyLightSettings(Entity<LightBehaviourComponent> entity, string property)
|
||||||
{
|
{
|
||||||
if (EntityManager.TryGetComponent(entity, out PointLightComponent? light))
|
if (TryComp(entity, out PointLightComponent? light))
|
||||||
{
|
{
|
||||||
var propertyValue = AnimationHelper.GetAnimatableProperty(light, property);
|
var propertyValue = AnimationHelper.GetAnimatableProperty(light, property);
|
||||||
if (propertyValue != null)
|
if (propertyValue != null)
|
||||||
|
|
@ -73,7 +73,7 @@ public sealed class LightBehaviorSystem : EntitySystem
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Warning($"{EntityManager.GetComponent<MetaDataComponent>(entity).EntityName} has a {nameof(LightBehaviourComponent)} but it has no {nameof(PointLightComponent)}! Check the prototype!");
|
Log.Warning($"{Comp<MetaDataComponent>(entity).EntityName} has a {nameof(LightBehaviourComponent)} but it has no {nameof(PointLightComponent)}! Check the prototype!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,7 +84,7 @@ public sealed class LightBehaviorSystem : EntitySystem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void StartLightBehaviour(Entity<LightBehaviourComponent> entity, string id = "")
|
public void StartLightBehaviour(Entity<LightBehaviourComponent> entity, string id = "")
|
||||||
{
|
{
|
||||||
if (!EntityManager.TryGetComponent(entity, out AnimationPlayerComponent? animation))
|
if (!TryComp(entity, out AnimationPlayerComponent? animation))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +113,7 @@ public sealed class LightBehaviorSystem : EntitySystem
|
||||||
/// <param name="resetToOriginalSettings">Should the light have its original settings applied?</param>
|
/// <param name="resetToOriginalSettings">Should the light have its original settings applied?</param>
|
||||||
public void StopLightBehaviour(Entity<LightBehaviourComponent> entity, string id = "", bool removeBehaviour = false, bool resetToOriginalSettings = false)
|
public void StopLightBehaviour(Entity<LightBehaviourComponent> entity, string id = "", bool removeBehaviour = false, bool resetToOriginalSettings = false)
|
||||||
{
|
{
|
||||||
if (!EntityManager.TryGetComponent(entity, out AnimationPlayerComponent? animation))
|
if (!TryComp(entity, out AnimationPlayerComponent? animation))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -143,7 +143,7 @@ public sealed class LightBehaviorSystem : EntitySystem
|
||||||
comp.Animations.Remove(container);
|
comp.Animations.Remove(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resetToOriginalSettings && EntityManager.TryGetComponent(entity, out PointLightComponent? light))
|
if (resetToOriginalSettings && TryComp(entity, out PointLightComponent? light))
|
||||||
{
|
{
|
||||||
foreach (var (property, value) in comp.OriginalPropertyValues)
|
foreach (var (property, value) in comp.OriginalPropertyValues)
|
||||||
{
|
{
|
||||||
|
|
@ -161,7 +161,7 @@ public sealed class LightBehaviorSystem : EntitySystem
|
||||||
public bool HasRunningBehaviours(Entity<LightBehaviourComponent> entity)
|
public bool HasRunningBehaviours(Entity<LightBehaviourComponent> entity)
|
||||||
{
|
{
|
||||||
//var uid = Owner;
|
//var uid = Owner;
|
||||||
if (!EntityManager.TryGetComponent(entity, out AnimationPlayerComponent? animation))
|
if (!TryComp(entity, out AnimationPlayerComponent? animation))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,51 @@
|
||||||
|
using Content.Shared.CCVar;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
|
||||||
namespace Content.Client.Light.EntitySystems;
|
namespace Content.Client.Light.EntitySystems;
|
||||||
|
|
||||||
public sealed class PlanetLightSystem : EntitySystem
|
public sealed class PlanetLightSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
|
||||||
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables / disables the ambient occlusion overlay.
|
||||||
|
/// </summary>
|
||||||
|
public bool AmbientOcclusion
|
||||||
|
{
|
||||||
|
get => _ambientOcclusion;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_ambientOcclusion == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_ambientOcclusion = value;
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
_overlayMan.AddOverlay(new AmbientOcclusionOverlay());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_overlayMan.RemoveOverlay<AmbientOcclusionOverlay>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _ambientOcclusion;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<GetClearColorEvent>(OnClearColor);
|
SubscribeLocalEvent<GetClearColorEvent>(OnClearColor);
|
||||||
|
|
||||||
|
_cfgManager.OnValueChanged(CCVars.AmbientOcclusion, val =>
|
||||||
|
{
|
||||||
|
AmbientOcclusion = val;
|
||||||
|
}, true);
|
||||||
|
|
||||||
_overlayMan.AddOverlay(new BeforeLightTargetOverlay());
|
_overlayMan.AddOverlay(new BeforeLightTargetOverlay());
|
||||||
_overlayMan.AddOverlay(new RoofOverlay(EntityManager));
|
_overlayMan.AddOverlay(new RoofOverlay(EntityManager));
|
||||||
_overlayMan.AddOverlay(new TileEmissionOverlay(EntityManager));
|
_overlayMan.AddOverlay(new TileEmissionOverlay(EntityManager));
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
using Content.Client.Items.Systems;
|
using Content.Client.Items.Systems;
|
||||||
using Content.Shared.Clothing;
|
using Content.Shared.Clothing;
|
||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ public sealed class RoofOverlay : Overlay
|
||||||
worldHandle.RenderInRenderTarget(target,
|
worldHandle.RenderInRenderTarget(target,
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
|
var invMatrix = target.GetWorldToLocalMatrix(eye, scale);
|
||||||
|
|
||||||
for (var i = 0; i < _grids.Count; i++)
|
for (var i = 0; i < _grids.Count; i++)
|
||||||
{
|
{
|
||||||
var grid = _grids[i];
|
var grid = _grids[i];
|
||||||
|
|
@ -69,8 +71,6 @@ public sealed class RoofOverlay : Overlay
|
||||||
if (!_entManager.TryGetComponent(grid.Owner, out ImplicitRoofComponent? roof))
|
if (!_entManager.TryGetComponent(grid.Owner, out ImplicitRoofComponent? roof))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var invMatrix = target.GetWorldToLocalMatrix(eye, scale);
|
|
||||||
|
|
||||||
var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner);
|
var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner);
|
||||||
var matty = Matrix3x2.Multiply(gridMatrix, invMatrix);
|
var matty = Matrix3x2.Multiply(gridMatrix, invMatrix);
|
||||||
|
|
||||||
|
|
@ -94,13 +94,13 @@ public sealed class RoofOverlay : Overlay
|
||||||
worldHandle.RenderInRenderTarget(target,
|
worldHandle.RenderInRenderTarget(target,
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
|
var invMatrix = target.GetWorldToLocalMatrix(eye, scale);
|
||||||
|
|
||||||
foreach (var grid in _grids)
|
foreach (var grid in _grids)
|
||||||
{
|
{
|
||||||
if (!_entManager.TryGetComponent(grid.Owner, out RoofComponent? roof))
|
if (!_entManager.TryGetComponent(grid.Owner, out RoofComponent? roof))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var invMatrix = target.GetWorldToLocalMatrix(eye, scale);
|
|
||||||
|
|
||||||
var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner);
|
var gridMatrix = _xformSystem.GetWorldMatrix(grid.Owner);
|
||||||
var matty = Matrix3x2.Multiply(gridMatrix, invMatrix);
|
var matty = Matrix3x2.Multiply(gridMatrix, invMatrix);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ namespace Content.Client.Light;
|
||||||
|
|
||||||
public sealed class SunShadowOverlay : Overlay
|
public sealed class SunShadowOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> MixShader = "Mix";
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.BeforeLighting;
|
public override OverlaySpace Space => OverlaySpace.BeforeLighting;
|
||||||
|
|
||||||
[Dependency] private readonly IClyde _clyde = default!;
|
[Dependency] private readonly IClyde _clyde = default!;
|
||||||
|
|
@ -150,7 +152,7 @@ public sealed class SunShadowOverlay : Overlay
|
||||||
viewport.LightRenderTarget.GetWorldToLocalMatrix(eye, scale);
|
viewport.LightRenderTarget.GetWorldToLocalMatrix(eye, scale);
|
||||||
worldHandle.SetTransform(invMatrix);
|
worldHandle.SetTransform(invMatrix);
|
||||||
|
|
||||||
var maskShader = _protoManager.Index<ShaderPrototype>("Mix").Instance();
|
var maskShader = _protoManager.Index(MixShader).Instance();
|
||||||
worldHandle.UseShader(maskShader);
|
worldHandle.UseShader(maskShader);
|
||||||
|
|
||||||
worldHandle.DrawTextureRect(_target.Texture, worldBounds, Color.Black.WithAlpha(alpha));
|
worldHandle.DrawTextureRect(_target.Texture, worldBounds, Color.Black.WithAlpha(alpha));
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ namespace Content.Client.Lobby.UI
|
||||||
// End CD - Station Records
|
// End CD - Station Records
|
||||||
|
|
||||||
[ValidatePrototypeId<GuideEntryPrototype>]
|
[ValidatePrototypeId<GuideEntryPrototype>]
|
||||||
private const string DefaultSpeciesGuidebook = "Species";
|
private static readonly ProtoId<GuideEntryPrototype> DefaultSpeciesGuidebook = "Species";
|
||||||
|
|
||||||
public event Action<List<ProtoId<GuideEntryPrototype>>>? OnOpenGuidebook;
|
public event Action<List<ProtoId<GuideEntryPrototype>>>? OnOpenGuidebook;
|
||||||
|
|
||||||
|
|
@ -289,6 +289,7 @@ namespace Content.Client.Lobby.UI
|
||||||
};
|
};
|
||||||
|
|
||||||
RgbSkinColorContainer.AddChild(_rgbSkinColorSelector = new ColorSelectorSliders());
|
RgbSkinColorContainer.AddChild(_rgbSkinColorSelector = new ColorSelectorSliders());
|
||||||
|
_rgbSkinColorSelector.SelectorType = ColorSelectorSliders.ColorSelectorType.Hsv; // defaults color selector to HSV
|
||||||
_rgbSkinColorSelector.OnColorChanged += _ =>
|
_rgbSkinColorSelector.OnColorChanged += _ =>
|
||||||
{
|
{
|
||||||
OnSkinColorOnValueChanged();
|
OnSkinColorOnValueChanged();
|
||||||
|
|
@ -880,9 +881,9 @@ namespace Content.Client.Lobby.UI
|
||||||
var species = Profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies;
|
var species = Profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies;
|
||||||
var page = DefaultSpeciesGuidebook;
|
var page = DefaultSpeciesGuidebook;
|
||||||
if (_prototypeManager.HasIndex<GuideEntryPrototype>(species))
|
if (_prototypeManager.HasIndex<GuideEntryPrototype>(species))
|
||||||
page = species;
|
page = new ProtoId<GuideEntryPrototype>(species.Id); // Gross. See above todo comment.
|
||||||
|
|
||||||
if (_prototypeManager.TryIndex<GuideEntryPrototype>(DefaultSpeciesGuidebook, out var guideRoot))
|
if (_prototypeManager.TryIndex(DefaultSpeciesGuidebook, out var guideRoot))
|
||||||
{
|
{
|
||||||
var dict = new Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry>();
|
var dict = new Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry>();
|
||||||
dict.Add(DefaultSpeciesGuidebook, guideRoot);
|
dict.Add(DefaultSpeciesGuidebook, guideRoot);
|
||||||
|
|
@ -1561,17 +1562,13 @@ namespace Content.Client.Lobby.UI
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var hairMarking = Profile.Appearance.HairStyleId switch
|
var hairMarking = Profile.Appearance.HairStyleId == HairStyles.DefaultHairStyle
|
||||||
{
|
? new List<Marking>()
|
||||||
HairStyles.DefaultHairStyle => new List<Marking>(),
|
: new() { new(Profile.Appearance.HairStyleId, new List<Color>() { Profile.Appearance.HairColor }) };
|
||||||
_ => new() { new(Profile.Appearance.HairStyleId, new List<Color>() { Profile.Appearance.HairColor }) },
|
|
||||||
};
|
|
||||||
|
|
||||||
var facialHairMarking = Profile.Appearance.FacialHairStyleId switch
|
var facialHairMarking = Profile.Appearance.FacialHairStyleId == HairStyles.DefaultFacialHairStyle
|
||||||
{
|
? new List<Marking>()
|
||||||
HairStyles.DefaultFacialHairStyle => new List<Marking>(),
|
: new() { new(Profile.Appearance.FacialHairStyleId, new List<Color>() { Profile.Appearance.FacialHairColor }) };
|
||||||
_ => new() { new(Profile.Appearance.FacialHairStyleId, new List<Color>() { Profile.Appearance.FacialHairColor }) },
|
|
||||||
};
|
|
||||||
|
|
||||||
HairStylePicker.UpdateData(
|
HairStylePicker.UpdateData(
|
||||||
hairMarking,
|
hairMarking,
|
||||||
|
|
|
||||||
|
|
@ -144,8 +144,8 @@ public sealed partial class LoadoutGroupContainer : BoxContainer
|
||||||
{
|
{
|
||||||
subList.AddChild(proto);
|
subList.AddChild(proto);
|
||||||
}
|
}
|
||||||
|
var itemName = firstElement.Text ?? "";
|
||||||
UpdateToggleColor(toggle, subList);
|
UpdateSubGroupSelectedInfo(firstElement, itemName, subList);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -164,12 +164,14 @@ public sealed partial class LoadoutGroupContainer : BoxContainer
|
||||||
};
|
};
|
||||||
|
|
||||||
toggle.Text = subContainer.Visible ? OpenedGroupMark : ClosedGroupMark;
|
toggle.Text = subContainer.Visible ? OpenedGroupMark : ClosedGroupMark;
|
||||||
|
toggle.Pressed = subContainer.Visible;
|
||||||
|
|
||||||
toggle.OnPressed += _ =>
|
toggle.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
var willOpen = !subContainer.Visible;
|
var willOpen = !subContainer.Visible;
|
||||||
subContainer.Visible = willOpen;
|
subContainer.Visible = willOpen;
|
||||||
toggle.Text = willOpen ? OpenedGroupMark : ClosedGroupMark;
|
toggle.Text = willOpen ? OpenedGroupMark : ClosedGroupMark;
|
||||||
|
toggle.Pressed = willOpen;
|
||||||
_openedGroups[kvp.Key] = willOpen;
|
_openedGroups[kvp.Key] = willOpen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -178,15 +180,16 @@ public sealed partial class LoadoutGroupContainer : BoxContainer
|
||||||
return toggle;
|
return toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateToggleColor(Button toggle, BoxContainer subList)
|
private void UpdateSubGroupSelectedInfo(LoadoutContainer loadout, string itemName, BoxContainer subList)
|
||||||
{
|
{
|
||||||
var anyActive = subList.Children
|
var countSubSelected = subList.Children
|
||||||
.OfType<LoadoutContainer>()
|
.OfType<LoadoutContainer>()
|
||||||
.Any(c => c.Select.Pressed);
|
.Count(c => c.Select.Pressed);
|
||||||
|
|
||||||
toggle.Modulate = anyActive
|
if (countSubSelected > 0)
|
||||||
? Color.Green
|
{
|
||||||
: Color.White;
|
loadout.Text = Loc.GetString("loadouts-count-items-in-group", ("item", itemName), ("count", countSubSelected));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ namespace Content.Client.Mapping;
|
||||||
|
|
||||||
public sealed class MappingOverlay : Overlay
|
public sealed class MappingOverlay : Overlay
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||||
|
|
||||||
[Dependency] private readonly IEntityManager _entities = default!;
|
[Dependency] private readonly IEntityManager _entities = default!;
|
||||||
[Dependency] private readonly IPlayerManager _player = default!;
|
[Dependency] private readonly IPlayerManager _player = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
||||||
|
|
@ -35,7 +37,7 @@ public sealed class MappingOverlay : Overlay
|
||||||
_sprite = _entities.System<SpriteSystem>();
|
_sprite = _entities.System<SpriteSystem>();
|
||||||
|
|
||||||
_state = state;
|
_state = state;
|
||||||
_shader = _prototypes.Index<ShaderPrototype>("unshaded").Instance();
|
_shader = _prototypes.Index(UnshadedShader).Instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Draw(in OverlayDrawArgs args)
|
protected override void Draw(in OverlayDrawArgs args)
|
||||||
|
|
|
||||||
|
|
@ -793,7 +793,7 @@ public sealed class MappingState : GameplayStateBase
|
||||||
|
|
||||||
if (_mapMan.TryFindGridAt(mapPos, out var gridUid, out var grid) &&
|
if (_mapMan.TryFindGridAt(mapPos, out var gridUid, out var grid) &&
|
||||||
_entityManager.System<SharedMapSystem>().TryGetTileRef(gridUid, grid, coords, out var tileRef) &&
|
_entityManager.System<SharedMapSystem>().TryGetTileRef(gridUid, grid, coords, out var tileRef) &&
|
||||||
_allPrototypesDict.TryGetValue(tileRef.GetContentTileDefinition(), out button))
|
_allPrototypesDict.TryGetValue(_entityManager.System<TurfSystem>().GetContentTileDefinition(tileRef), out button))
|
||||||
{
|
{
|
||||||
OnSelected(button);
|
OnSelected(button);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ public sealed class MarkerSystem : EntitySystem
|
||||||
|
|
||||||
private void UpdateVisibility(EntityUid uid)
|
private void UpdateVisibility(EntityUid uid)
|
||||||
{
|
{
|
||||||
if (EntityManager.TryGetComponent(uid, out SpriteComponent? sprite))
|
if (TryComp(uid, out SpriteComponent? sprite))
|
||||||
{
|
{
|
||||||
_sprite.SetVisible((uid, sprite), MarkersVisible);
|
_sprite.SetVisible((uid, sprite), MarkersVisible);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,8 @@ public sealed class MouseRotatorSystem : SharedMouseRotatorSystem
|
||||||
rotation += 2 * Math.PI;
|
rotation += 2 * Math.PI;
|
||||||
RaisePredictiveEvent(new RequestMouseRotatorRotationEvent
|
RaisePredictiveEvent(new RequestMouseRotatorRotationEvent
|
||||||
{
|
{
|
||||||
Rotation = rotation
|
Rotation = rotation,
|
||||||
|
User = GetNetEntity(player)
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -77,7 +78,8 @@ public sealed class MouseRotatorSystem : SharedMouseRotatorSystem
|
||||||
|
|
||||||
RaisePredictiveEvent(new RequestMouseRotatorRotationEvent
|
RaisePredictiveEvent(new RequestMouseRotatorRotationEvent
|
||||||
{
|
{
|
||||||
Rotation = angle
|
Rotation = angle,
|
||||||
|
User = GetNetEntity(player)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ namespace Content.Client.Movement.Systems;
|
||||||
|
|
||||||
public sealed class FloorOcclusionSystem : SharedFloorOcclusionSystem
|
public sealed class FloorOcclusionSystem : SharedFloorOcclusionSystem
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> HorizontalCut = "HorizontalCut";
|
||||||
|
|
||||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
|
|
||||||
private EntityQuery<SpriteComponent> _spriteQuery;
|
private EntityQuery<SpriteComponent> _spriteQuery;
|
||||||
|
|
@ -48,7 +50,7 @@ public sealed class FloorOcclusionSystem : SharedFloorOcclusionSystem
|
||||||
if (!_spriteQuery.Resolve(sprite.Owner, ref sprite.Comp, false))
|
if (!_spriteQuery.Resolve(sprite.Owner, ref sprite.Comp, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var shader = _proto.Index<ShaderPrototype>("HorizontalCut").Instance();
|
var shader = _proto.Index(HorizontalCut).Instance();
|
||||||
|
|
||||||
if (sprite.Comp.PostShader is not null && sprite.Comp.PostShader != shader)
|
if (sprite.Comp.PostShader is not null && sprite.Comp.PostShader != shader)
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Numerics;
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
using Content.Client.UserInterface.Controls;
|
using Content.Client.UserInterface.Controls;
|
||||||
using Content.Shared.DeviceLinking;
|
using Content.Shared.DeviceLinking;
|
||||||
using Content.Shared.DeviceNetwork;
|
using Content.Shared.DeviceNetwork;
|
||||||
|
|
@ -14,6 +15,8 @@ namespace Content.Client.NetworkConfigurator;
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
|
public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
private const string PanelBgColor = "#202023";
|
private const string PanelBgColor = "#202023";
|
||||||
|
|
||||||
private readonly LinksRender _links;
|
private readonly LinksRender _links;
|
||||||
|
|
@ -33,6 +36,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
|
||||||
public NetworkConfiguratorLinkMenu()
|
public NetworkConfiguratorLinkMenu()
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
var footerStyleBox = new StyleBoxFlat()
|
var footerStyleBox = new StyleBoxFlat()
|
||||||
{
|
{
|
||||||
|
|
@ -61,7 +65,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
|
||||||
ButtonContainerRight.RemoveAllChildren();
|
ButtonContainerRight.RemoveAllChildren();
|
||||||
|
|
||||||
_sources.Clear();
|
_sources.Clear();
|
||||||
_sources.AddRange(linkState.Sources);
|
_sources.AddRange(linkState.Sources.Select(s => _prototypeManager.Index(s)));
|
||||||
_links.SourceButtons.Clear();
|
_links.SourceButtons.Clear();
|
||||||
var i = 0;
|
var i = 0;
|
||||||
foreach (var source in _sources)
|
foreach (var source in _sources)
|
||||||
|
|
@ -73,7 +77,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
_sinks.Clear();
|
_sinks.Clear();
|
||||||
_sinks.AddRange(linkState.Sinks);
|
_sinks.AddRange(linkState.Sinks.Select(s => _prototypeManager.Index(s)));
|
||||||
_links.SinkButtons.Clear();
|
_links.SinkButtons.Clear();
|
||||||
i = 0;
|
i = 0;
|
||||||
foreach (var sink in _sinks)
|
foreach (var sink in _sinks)
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,7 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
|
||||||
[Dependency] private readonly ActionsSystem _actions = default!;
|
[Dependency] private readonly ActionsSystem _actions = default!;
|
||||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||||
|
|
||||||
[ValidatePrototypeId<EntityPrototype>]
|
private static readonly EntProtoId Action = "ActionClearNetworkLinkOverlays";
|
||||||
private const string Action = "ActionClearNetworkLinkOverlays";
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Numerics;
|
||||||
using Content.Shared.Nyanotrasen.Kitchen.UI;
|
using Content.Shared.Nyanotrasen.Kitchen.UI;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,16 @@
|
||||||
Resizable="False">
|
Resizable="False">
|
||||||
|
|
||||||
<BoxContainer Orientation="Vertical" SeparationOverride="4" MinWidth="150">
|
<BoxContainer Orientation="Vertical" SeparationOverride="4" MinWidth="150">
|
||||||
<changelog:ChangelogButton Access="Public" Name="ChangelogButton"/>
|
|
||||||
<ui:VoteCallMenuButton />
|
<ui:VoteCallMenuButton />
|
||||||
<Button Access="Public" Name="OptionsButton" Text="{Loc 'ui-escape-options'}" />
|
<PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" />
|
||||||
<Button Access="Public" Name="RulesButton" Text="{Loc 'ui-escape-rules'}" />
|
<Button Access="Public" Name="RulesButton" Text="{Loc 'ui-escape-rules'}" />
|
||||||
<Button Access="Public" Name="GuidebookButton" Text="{Loc 'ui-escape-guidebook'}" />
|
<Button Access="Public" Name="GuidebookButton" Text="{Loc 'ui-escape-guidebook'}" />
|
||||||
<Button Access="Public" Name="WikiButton" Text="{Loc 'ui-escape-wiki'}" />
|
<Button Access="Public" Name="WikiButton" Text="{Loc 'ui-escape-wiki'}" />
|
||||||
|
<changelog:ChangelogButton Access="Public" Name="ChangelogButton" />
|
||||||
|
<PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" />
|
||||||
|
<Button Access="Public" Name="OptionsButton" Text="{Loc 'ui-escape-options'}" />
|
||||||
|
<PanelContainer StyleClasses="LowDivider" Margin="0 2.5 0 2.5" />
|
||||||
<Button Access="Public" Name="DisconnectButton" Text="{Loc 'ui-escape-disconnect'}" />
|
<Button Access="Public" Name="DisconnectButton" Text="{Loc 'ui-escape-disconnect'}" />
|
||||||
<Button Access="Public" Name="QuitButton" Text="{Loc 'ui-escape-quit'}" />
|
<Button Access="Public" Name="QuitButton" Text="{Loc 'ui-escape-quit'}" StyleClasses="ButtonColorRed" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</ui1:EscapeMenu>
|
</ui1:EscapeMenu>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
<ui:OptionDropDown Name="DropDownLightingQuality" Title="{Loc 'ui-options-lighting-label'}" />
|
<ui:OptionDropDown Name="DropDownLightingQuality" Title="{Loc 'ui-options-lighting-label'}" />
|
||||||
<CheckBox Name="ViewportLowResCheckBox" Text="{Loc 'ui-options-vp-low-res'}" />
|
<CheckBox Name="ViewportLowResCheckBox" Text="{Loc 'ui-options-vp-low-res'}" />
|
||||||
<CheckBox Name="ParallaxLowQualityCheckBox" Text="{Loc 'ui-options-parallax-low-quality'}" />
|
<CheckBox Name="ParallaxLowQualityCheckBox" Text="{Loc 'ui-options-parallax-low-quality'}" />
|
||||||
|
<CheckBox Name="AmbientOcclusionCheckBox" Text="{Loc 'ui-options-ambient-occlusion'}" />
|
||||||
|
|
||||||
<!-- Interface -->
|
<!-- Interface -->
|
||||||
<Label Text="{Loc 'ui-options-interface-label'}" StyleClasses="LabelKeyText"/>
|
<Label Text="{Loc 'ui-options-interface-label'}" StyleClasses="LabelKeyText"/>
|
||||||
|
|
@ -24,6 +25,7 @@
|
||||||
<CheckBox Name="IntegerScalingCheckBox"
|
<CheckBox Name="IntegerScalingCheckBox"
|
||||||
Text="{Loc 'ui-options-vp-integer-scaling'}"
|
Text="{Loc 'ui-options-vp-integer-scaling'}"
|
||||||
ToolTip="{Loc 'ui-options-vp-integer-scaling-tooltip'}" />
|
ToolTip="{Loc 'ui-options-vp-integer-scaling-tooltip'}" />
|
||||||
|
<ui:OptionDropDown Name="DropDownFilterMode" Title="{Loc 'ui-options-filter-label'}" />
|
||||||
<CheckBox Name="ViewportVerticalFitCheckBox"
|
<CheckBox Name="ViewportVerticalFitCheckBox"
|
||||||
Text="{Loc 'ui-options-vp-vertical-fit'}"
|
Text="{Loc 'ui-options-vp-vertical-fit'}"
|
||||||
ToolTip="{Loc 'ui-options-vp-vertical-fit-tooltip'}" />
|
ToolTip="{Loc 'ui-options-vp-vertical-fit-tooltip'}" />
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ public sealed partial class GraphicsTab : Control
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
Control.AddOptionCheckBox(CVars.DisplayVSync, VSyncCheckBox);
|
Control.AddOptionCheckBox(CVars.DisplayVSync, VSyncCheckBox);
|
||||||
|
Control.AddOptionCheckBox(CCVars.AmbientOcclusion, AmbientOcclusionCheckBox);
|
||||||
Control.AddOption(new OptionFullscreen(Control, _cfg, FullscreenCheckBox));
|
Control.AddOption(new OptionFullscreen(Control, _cfg, FullscreenCheckBox));
|
||||||
Control.AddOption(new OptionLightingQuality(Control, _cfg, DropDownLightingQuality));
|
Control.AddOption(new OptionLightingQuality(Control, _cfg, DropDownLightingQuality));
|
||||||
|
|
||||||
|
|
@ -38,6 +39,14 @@ public sealed partial class GraphicsTab : Control
|
||||||
new OptionDropDownCVar<float>.ValueOption(2.00f, Loc.GetString("ui-options-scale-200")),
|
new OptionDropDownCVar<float>.ValueOption(2.00f, Loc.GetString("ui-options-scale-200")),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
Control.AddOptionDropDown(
|
||||||
|
CCVars.ViewportScalingFilterMode,
|
||||||
|
DropDownFilterMode,
|
||||||
|
[
|
||||||
|
new OptionDropDownCVar<string>.ValueOption("nearest", Loc.GetString("ui-options-filter-nearest")),
|
||||||
|
new OptionDropDownCVar<string>.ValueOption("bilinear", Loc.GetString("ui-options-filter-bilinear")),
|
||||||
|
]);
|
||||||
|
|
||||||
var vpStretch = Control.AddOptionCheckBox(CCVars.ViewportStretch, ViewportStretchCheckBox);
|
var vpStretch = Control.AddOptionCheckBox(CCVars.ViewportStretch, ViewportStretchCheckBox);
|
||||||
var vpVertFit = Control.AddOptionCheckBox(CCVars.ViewportVerticalFit, ViewportVerticalFitCheckBox);
|
var vpVertFit = Control.AddOptionCheckBox(CCVars.ViewportVerticalFit, ViewportVerticalFitCheckBox);
|
||||||
Control.AddOptionSlider(
|
Control.AddOptionSlider(
|
||||||
|
|
@ -49,6 +58,7 @@ public sealed partial class GraphicsTab : Control
|
||||||
|
|
||||||
vpStretch.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
|
vpStretch.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
|
||||||
vpVertFit.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
|
vpVertFit.ImmediateValueChanged += _ => UpdateViewportSettingsVisibility();
|
||||||
|
IntegerScalingCheckBox.OnToggled += _ => UpdateViewportSettingsVisibility();
|
||||||
|
|
||||||
Control.AddOptionSlider(
|
Control.AddOptionSlider(
|
||||||
CCVars.ViewportWidth,
|
CCVars.ViewportWidth,
|
||||||
|
|
@ -76,6 +86,7 @@ public sealed partial class GraphicsTab : Control
|
||||||
IntegerScalingCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
IntegerScalingCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
||||||
ViewportVerticalFitCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
ViewportVerticalFitCheckBox.Visible = ViewportStretchCheckBox.Pressed;
|
||||||
ViewportWidthSlider.Visible = !ViewportStretchCheckBox.Pressed || !ViewportVerticalFitCheckBox.Pressed;
|
ViewportWidthSlider.Visible = !ViewportStretchCheckBox.Pressed || !ViewportVerticalFitCheckBox.Pressed;
|
||||||
|
DropDownFilterMode.Visible = !IntegerScalingCheckBox.Pressed && ViewportStretchCheckBox.Pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateViewportWidthRange()
|
private void UpdateViewportWidthRange()
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ public sealed class OrbitVisualsSystem : EntitySystem
|
||||||
{
|
{
|
||||||
base.FrameUpdate(frameTime);
|
base.FrameUpdate(frameTime);
|
||||||
|
|
||||||
var query = EntityManager.EntityQueryEnumerator<OrbitVisualsComponent, SpriteComponent>();
|
var query = EntityQueryEnumerator<OrbitVisualsComponent, SpriteComponent>();
|
||||||
while (query.MoveNext(out var uid, out var orbit, out var sprite))
|
while (query.MoveNext(out var uid, out var orbit, out var sprite))
|
||||||
{
|
{
|
||||||
var progress = (float)(_timing.CurTime.TotalSeconds / orbit.OrbitLength) % 1;
|
var progress = (float)(_timing.CurTime.TotalSeconds / orbit.OrbitLength) % 1;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ namespace Content.Client.Outline;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class TargetOutlineSystem : EntitySystem
|
public sealed class TargetOutlineSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> ShaderTargetValid = "SelectionOutlineInrange";
|
||||||
|
private static readonly ProtoId<ShaderPrototype> ShaderTargetInvalid = "SelectionOutline";
|
||||||
|
|
||||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
|
|
@ -70,12 +73,6 @@ public sealed class TargetOutlineSystem : EntitySystem
|
||||||
|
|
||||||
private Vector2 LookupVector => new(LookupSize, LookupSize);
|
private Vector2 LookupVector => new(LookupSize, LookupSize);
|
||||||
|
|
||||||
[ValidatePrototypeId<ShaderPrototype>]
|
|
||||||
private const string ShaderTargetValid = "SelectionOutlineInrange";
|
|
||||||
|
|
||||||
[ValidatePrototypeId<ShaderPrototype>]
|
|
||||||
private const string ShaderTargetInvalid = "SelectionOutline";
|
|
||||||
|
|
||||||
private ShaderInstance? _shaderTargetValid;
|
private ShaderInstance? _shaderTargetValid;
|
||||||
private ShaderInstance? _shaderTargetInvalid;
|
private ShaderInstance? _shaderTargetInvalid;
|
||||||
|
|
||||||
|
|
@ -85,8 +82,8 @@ public sealed class TargetOutlineSystem : EntitySystem
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
_shaderTargetValid = _prototypeManager.Index<ShaderPrototype>(ShaderTargetValid).InstanceUnique();
|
_shaderTargetValid = _prototypeManager.Index(ShaderTargetValid).InstanceUnique();
|
||||||
_shaderTargetInvalid = _prototypeManager.Index<ShaderPrototype>(ShaderTargetInvalid).InstanceUnique();
|
_shaderTargetInvalid = _prototypeManager.Index(ShaderTargetInvalid).InstanceUnique();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disable()
|
public void Disable()
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue