# Conflicts:
#	Content.Client/Administration/Managers/ClientAdminManager.cs
#	Content.Client/Administration/Systems/BwoinkSystem.cs
#	Content.Client/Alerts/ClientAlertsSystem.cs
#	Content.Client/Audio/BackgroundAudioSystem.cs
#	Content.Client/CardboardBox/CardboardBoxSystem.cs
#	Content.Client/Chemistry/UI/InjectorStatusControl.cs
#	Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml
#	Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
#	Content.Client/Clothing/ClientClothingSystem.cs
#	Content.Client/CriminalRecords/CriminalRecordsConsoleBoundUserInterface.cs
#	Content.Client/CriminalRecords/CriminalRecordsConsoleWindow.xaml.cs
#	Content.Client/Decals/Overlays/DecalOverlay.cs
#	Content.Client/DoAfter/DoAfterOverlay.cs
#	Content.Client/Doors/AirlockSystem.cs
#	Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml
#	Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs
#	Content.Client/Launcher/LauncherConnectingGui.xaml
#	Content.Client/Launcher/LauncherConnectingGui.xaml.cs
#	Content.Client/Lobby/LobbyState.cs
#	Content.Client/Lobby/UI/LobbyGui.xaml.cs
#	Content.Client/MainMenu/UI/MainMenuControl.xaml
#	Content.Client/MassMedia/Ui/MiniArticleCardControl.xaml
#	Content.Client/MassMedia/Ui/MiniArticleCardControl.xaml.cs
#	Content.Client/MassMedia/Ui/NewsWriteMenu.xaml
#	Content.Client/MassMedia/Ui/NewsWriteMenu.xaml.cs
#	Content.Client/Options/UI/Tabs/MiscTab.xaml
#	Content.Client/Options/UI/Tabs/MiscTab.xaml.cs
#	Content.Client/Outline/InteractionOutlineSystem.cs
#	Content.Client/Overlays/ShowSecurityIconsSystem.cs
#	Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs
#	Content.Client/Popups/PopupOverlay.cs
#	Content.Client/Popups/PopupSystem.cs
#	Content.Client/Preferences/ClientPreferencesManager.cs
#	Content.Client/Preferences/UI/HumanoidProfileEditor.xaml
#	Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs
#	Content.Client/StatusIcon/StatusIconOverlay.cs
#	Content.Client/Stylesheets/StyleNano.cs
#	Content.Client/UserInterface/Systems/Bwoink/AHelpUIController.cs
#	Content.Client/UserInterface/Systems/Chat/ChatUIController.cs
#	Content.Server/Access/Systems/IdCardConsoleSystem.cs
#	Content.Server/Administration/Commands/BanCommand.cs
#	Content.Server/Administration/Notes/AdminMessageEui.cs
#	Content.Server/Administration/Notes/AdminNotesSystem.cs
#	Content.Server/Administration/Notes/IAdminNotesManager.cs
#	Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs
#	Content.Server/Administration/Systems/BwoinkSystem.cs
#	Content.Server/Administration/UI/PermissionsEui.cs
#	Content.Server/Antag/AntagSelectionSystem.cs
#	Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs
#	Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs
#	Content.Server/Chat/Systems/ChatSystem.cs
#	Content.Server/Chemistry/EntitySystems/InjectorSystem.cs
#	Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
#	Content.Server/Connection/ConnectionManager.cs
#	Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs
#	Content.Server/Database/DatabaseRecords.cs
#	Content.Server/Database/ServerDbBase.cs
#	Content.Server/Database/ServerDbManager.cs
#	Content.Server/DeviceLinking/Systems/SignalTimerSystem.cs
#	Content.Server/Doors/Systems/DoorSystem.cs
#	Content.Server/Execution/ExecutionSystem.cs
#	Content.Server/Explosion/EntitySystems/ExplosionSystem.cs
#	Content.Server/Fax/FaxSystem.cs
#	Content.Server/Fluids/EntitySystems/PuddleSystem.Evaporation.cs
#	Content.Server/GameTicking/GameTicker.Replays.cs
#	Content.Server/GameTicking/GameTicker.RoundFlow.cs
#	Content.Server/GameTicking/Rules/Components/ThiefRuleComponent.cs
#	Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs
#	Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs
#	Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs
#	Content.Server/GameTicking/Rules/ThiefRuleSystem.cs
#	Content.Server/GameTicking/Rules/TraitorRuleSystem.cs
#	Content.Server/GameTicking/Rules/ZombieRuleSystem.cs
#	Content.Server/Hands/Systems/HandsSystem.cs
#	Content.Server/Holosign/HolosignSystem.cs
#	Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs
#	Content.Server/Info/InfoSystem.cs
#	Content.Server/Kitchen/EntitySystems/SharpSystem.cs
#	Content.Server/Magic/MagicSystem.cs
#	Content.Server/MagicMirror/MagicMirrorSystem.cs
#	Content.Server/Mapping/MappingSystem.cs
#	Content.Server/MassMedia/Systems/NewsSystem.cs
#	Content.Server/Medical/Components/HealthAnalyzerComponent.cs
#	Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs
#	Content.Server/Medical/CryoPodSystem.cs
#	Content.Server/Medical/HealthAnalyzerSystem.cs
#	Content.Server/Nutrition/EntitySystems/OpenableSystem.cs
#	Content.Server/Preferences/Managers/ServerPreferencesManager.cs
#	Content.Server/Remotes/DoorRemoteSystem.cs
#	Content.Server/Resist/EscapeInventorySystem.cs
#	Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs
#	Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs
#	Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs
#	Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs
#	Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs
#	Content.Server/Species/Systems/NymphSystem.cs
#	Content.Server/StationEvents/Components/GasLeakRuleComponent.cs
#	Content.Server/StationEvents/EventManagerSystem.cs
#	Content.Server/Store/Systems/StoreSystem.Ui.cs
#	Content.Server/Strip/StrippableSystem.cs
#	Content.Server/VendingMachines/VendingMachineSystem.cs
#	Content.Server/Weapons/Ranged/Systems/GunSystem.cs
#	Content.Shared.Database/LogType.cs
#	Content.Shared/Actions/SharedActionsSystem.cs
#	Content.Shared/Administration/AdminFlags.cs
#	Content.Shared/Administration/SharedBwoinkSystem.cs
#	Content.Shared/Anomaly/SharedAnomalySystem.cs
#	Content.Shared/Bed/Sleep/SharedSleepingSystem.cs
#	Content.Shared/Buckle/SharedBuckleSystem.Strap.cs
#	Content.Shared/Chat/ChatChannel.cs
#	Content.Shared/Chemistry/Components/InjectorComponent.cs
#	Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs
#	Content.Shared/Chemistry/SharedReagentDispenser.cs
#	Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs
#	Content.Shared/CriminalRecords/Systems/SharedCriminalRecordsConsoleSystem.cs
#	Content.Shared/Cuffs/SharedCuffableSystem.cs
#	Content.Shared/Doors/Systems/SharedDoorSystem.cs
#	Content.Shared/Friction/TileFrictionController.cs
#	Content.Shared/Humanoid/Prototypes/SpeciesPrototype.cs
#	Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs
#	Content.Shared/Implants/SharedImplanterSystem.cs
#	Content.Shared/Lock/LockSystem.cs
#	Content.Shared/MedicalScanner/HealthAnalyzerScannedUserMessage.cs
#	Content.Shared/Nutrition/Components/OpenableComponent.cs
#	Content.Shared/Nutrition/EntitySystems/SharedOpenableSystem.cs
#	Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs
#	Content.Shared/Preferences/HumanoidCharacterProfile.cs
#	Content.Shared/Preferences/ICharacterProfile.cs
#	Content.Shared/Projectiles/SharedProjectileSystem.cs
#	Content.Shared/Pulling/Systems/SharedPullingSystem.Actions.cs
#	Content.Shared/Security/SecurityStatus.cs
#	Content.Shared/Security/Systems/DeployableBarrierSystem.cs
#	Content.Shared/Slippery/SlipperySystem.cs
#	Content.Shared/Species/Systems/ReformSystem.cs
#	Content.Shared/Standing/StandingStateSystem.cs
#	Content.Shared/StatusIcon/StatusIconPrototype.cs
#	Content.Shared/Store/ListingPrototype.cs
#	Content.Shared/VendingMachines/SharedVendingMachineSystem.cs
#	Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
#	README.md
#	Resources/Audio/Ambience/Antag/pirate_start.ogg
#	Resources/Changelog/Changelog.yml
#	Resources/Credits/GitHub.txt
#	Resources/Locale/en-US/criminal-records/criminal-records.ftl
#	Resources/Locale/en-US/escape-menu/ui/options-menu.ftl
#	Resources/Locale/en-US/medical/components/health-analyzer-component.ftl
#	Resources/Locale/en-US/reagents/meta/biological.ftl
#	Resources/Locale/en-US/reagents/meta/fun.ftl
#	Resources/Locale/en-US/reagents/meta/physical-desc.ftl
#	Resources/Locale/en-US/seeds/seeds.ftl
#	Resources/Locale/en-US/wires/wire-names.ftl
#	Resources/Maps/Shuttles/cargo_fland.yml
#	Resources/Maps/core.yml
#	Resources/Maps/europa.yml
#	Resources/Maps/fland.yml
#	Resources/Maps/origin.yml
#	Resources/Maps/saltern.yml
#	Resources/Maps/train.yml
#	Resources/Prototypes/Actions/diona.yml
#	Resources/Prototypes/Atmospherics/gases.yml
#	Resources/Prototypes/Catalog/Cargo/cargo_emergency.yml
#	Resources/Prototypes/Catalog/Cargo/cargo_engines.yml
#	Resources/Prototypes/Catalog/Cargo/cargo_fun.yml
#	Resources/Prototypes/Catalog/Cargo/cargo_security.yml
#	Resources/Prototypes/Catalog/Cargo/cargo_service.yml
#	Resources/Prototypes/Catalog/Cargo/cargo_vending.yml
#	Resources/Prototypes/Catalog/Fills/Boxes/general.yml
#	Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml
#	Resources/Prototypes/Catalog/Fills/Crates/engines.yml
#	Resources/Prototypes/Catalog/Fills/Items/briefcases.yml
#	Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml
#	Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml
#	Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
#	Resources/Prototypes/Catalog/Fills/Lockers/security.yml
#	Resources/Prototypes/Catalog/VendingMachines/Inventories/bardrobe.yml
#	Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml
#	Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml
#	Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml
#	Resources/Prototypes/Catalog/VendingMachines/Inventories/medidrobe.yml
#	Resources/Prototypes/Catalog/VendingMachines/Inventories/robotics.yml
#	Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml
#	Resources/Prototypes/Catalog/uplink_catalog.yml
#	Resources/Prototypes/Datasets/Names/first_male.yml
#	Resources/Prototypes/Datasets/tips.yml
#	Resources/Prototypes/Entities/Clothing/Hands/colored.yml
#	Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml
#	Resources/Prototypes/Entities/Clothing/Head/hats.yml
#	Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
#	Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml
#	Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
#	Resources/Prototypes/Entities/Mobs/Player/silicon.yml
#	Resources/Prototypes/Entities/Mobs/Species/base.yml
#	Resources/Prototypes/Entities/Mobs/Species/slime.yml
#	Resources/Prototypes/Entities/Mobs/Species/vox.yml
#	Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml
#	Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml
#	Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml
#	Resources/Prototypes/Entities/Objects/Devices/Electronics/signaller.yml
#	Resources/Prototypes/Entities/Objects/Devices/nuke.yml
#	Resources/Prototypes/Entities/Objects/Devices/pda.yml
#	Resources/Prototypes/Entities/Objects/Fun/toys.yml
#	Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml
#	Resources/Prototypes/Entities/Objects/Materials/parts.yml
#	Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml
#	Resources/Prototypes/Entities/Objects/Misc/implanters.yml
#	Resources/Prototypes/Entities/Objects/Misc/kudzu.yml
#	Resources/Prototypes/Entities/Objects/Misc/rubber_stamp.yml
#	Resources/Prototypes/Entities/Objects/Shields/shields.yml
#	Resources/Prototypes/Entities/Objects/Specific/Hydroponics/tools.yml
#	Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml
#	Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml
#	Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml
#	Resources/Prototypes/Entities/Objects/Weapons/Bombs/firebomb.yml
#	Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/shotgun.yml
#	Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml
#	Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml
#	Resources/Prototypes/Entities/Structures/Decoration/curtains.yml
#	Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml
#	Resources/Prototypes/Entities/Structures/Doors/MaterialDoors/material_doors.yml
#	Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml
#	Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml
#	Resources/Prototypes/Entities/Structures/Machines/lathe.yml
#	Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml
#	Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml
#	Resources/Prototypes/Entities/Structures/Storage/glass_box.yml
#	Resources/Prototypes/Entities/Structures/Wallmounts/fireaxe_cabinet.yml
#	Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml
#	Resources/Prototypes/Entities/Structures/Walls/asteroid.yml
#	Resources/Prototypes/Entities/Structures/Walls/grille.yml
#	Resources/Prototypes/Entities/Structures/Walls/walls.yml
#	Resources/Prototypes/Entities/Structures/Windows/window.yml
#	Resources/Prototypes/Entities/Structures/stairs.yml
#	Resources/Prototypes/GameRules/events.yml
#	Resources/Prototypes/Hydroponics/seeds.yml
#	Resources/Prototypes/Maps/saltern.yml
#	Resources/Prototypes/Reagents/biological.yml
#	Resources/Prototypes/Reagents/fun.yml
#	Resources/Prototypes/Recipes/Construction/Graphs/utilities/solarpanel.yml
#	Resources/Prototypes/Recipes/Construction/weapons.yml
#	Resources/Prototypes/Recipes/Crafting/improvised.yml
#	Resources/Prototypes/Recipes/Lathes/clothing.yml
#	Resources/Prototypes/Recipes/Reactions/fun.yml
#	Resources/Prototypes/Research/arsenal.yml
#	Resources/Prototypes/Roles/Jobs/Engineering/technical_assistant.yml
#	Resources/Prototypes/Roles/Jobs/Fun/emergencyresponseteam.yml
#	Resources/Prototypes/Roles/Jobs/Medical/medical_intern.yml
#	Resources/Prototypes/Roles/Jobs/Medical/paramedic.yml
#	Resources/Prototypes/Roles/Jobs/Science/research_assistant.yml
#	Resources/Prototypes/Roles/Jobs/Security/detective.yml
#	Resources/Prototypes/Roles/Jobs/Security/security_cadet.yml
#	Resources/Prototypes/Roles/Jobs/departments.yml
#	Resources/Prototypes/Species/human.yml
#	Resources/Prototypes/Species/vox.yml
#	Resources/Prototypes/Stacks/Materials/materials.yml
#	Resources/Prototypes/StatusEffects/health.yml
#	Resources/Prototypes/Tiles/plating.yml
#	Resources/Prototypes/Voice/speech_emote_sounds.yml
#	Resources/Prototypes/Voice/speech_emotes.yml
#	Resources/Prototypes/explosion.yml
#	Resources/Prototypes/game_presets.yml
#	Resources/Prototypes/lobbyscreens.yml
#	Resources/Prototypes/secret_weights.yml
#	Resources/Prototypes/tags.yml
#	Resources/ServerInfo/Guidebook/Jobs.xml
#	Resources/ServerInfo/Guidebook/Science/ArtifactReports.xml
#	Resources/Textures/Clothing/Belt/emt.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hats/beret_medic.rsi/meta.json
#	Resources/Textures/Clothing/Head/Hats/beret_qm.rsi/meta.json
#	Resources/Textures/Clothing/Head/Soft/bluesoft_flipped.rsi/meta.json
#	Resources/Textures/Clothing/Head/Soft/corpsoft_flipped.rsi/meta.json
#	Resources/Textures/Clothing/Head/Soft/greensoft_flipped.rsi/meta.json
#	Resources/Textures/Clothing/Head/Soft/greysoft_flipped.rsi/meta.json
#	Resources/Textures/Clothing/Head/Soft/paramedicsoft_flipped.rsi/meta.json
#	Resources/Textures/Clothing/Mask/neckgaiterred.rsi/meta.json
#	Resources/Textures/Clothing/OuterClothing/Hardsuits/slayer.rsi/meta.json
#	Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/meta.json
#	Resources/Textures/Clothing/OuterClothing/Suits/syndicate.rsi/meta.json
#	Resources/Textures/Clothing/Uniforms/Jumpsuit/qmformal.rsi/meta.json
#	Resources/Textures/Decals/Overlays/greyscale.rsi/checkerNESW.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/checkerNWSE.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/fulltile_overlay.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/halftile_overlay.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/halftile_overlay_180.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/halftile_overlay_270.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/halftile_overlay_90.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/quartertile_overlay.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/quartertile_overlay_180.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/quartertile_overlay_270.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/quartertile_overlay_90.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/threequartertile_overlay.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/threequartertile_overlay_180.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/threequartertile_overlay_270.png
#	Resources/Textures/Decals/Overlays/greyscale.rsi/threequartertile_overlay_90.png
#	Resources/Textures/Interface/Misc/job_icons.rsi/meta.json
#	Resources/Textures/Interface/emotions.svg.192dpi.png.yml
#	Resources/Textures/LobbyScreens/dead-in-space.png.yml
#	Resources/Textures/LobbyScreens/doomed.webp.yml
#	Resources/Textures/LobbyScreens/pharmacy.png.yml
#	Resources/Textures/LobbyScreens/pharmacy.webp.yml
#	Resources/Textures/LobbyScreens/robotics.webp.yml
#	Resources/Textures/LobbyScreens/supermatter.png.yml
#	Resources/Textures/LobbyScreens/susstation.png.yml
#	Resources/Textures/LobbyScreens/warden.png.yml
#	Resources/Textures/LobbyScreens/warden.webp.yml
#	Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json
#	Resources/Textures/Mobs/Effects/brute_damage.rsi/LLeg_Brute_40.png
#	Resources/Textures/Mobs/Effects/brute_damage.rsi/RLeg_Brute_40.png
#	Resources/Textures/Objects/Devices/nuke.rsi/meta.json
#	Resources/Textures/Objects/Devices/nuke.rsi/nuclearbomb_deployed.png
#	Resources/Textures/Objects/Devices/nuke.rsi/nuclearbomb_exploding.png
#	Resources/Textures/Objects/Devices/nuke.rsi/nuclearbomb_timing.png
#	Resources/Textures/Objects/Misc/books.rsi/meta.json
#	Resources/Textures/Objects/Misc/bureaucracy.rsi/paper_stamp-lawyer.png
#	Resources/Textures/Objects/Storage/boxes.rsi/meta.json
#	Resources/Textures/Objects/Tools/t-ray.rsi/tray-off.png
#	Resources/Textures/Objects/Tools/t-ray.rsi/tray-on.png
#	Resources/Textures/Objects/Weapons/Guns/Battery/mini-ebow.rsi/bolt.png
#	Resources/Textures/Structures/Doors/Airlocks/Standard/external.rsi/emergency_open_unlit.png
#	Resources/Textures/Structures/Doors/Airlocks/Standard/shuttle_syndicate.rsi/emergency_open_unlit.png
#	Resources/Textures/Structures/Doors/Windoors/plasma.rsi/emergency_unlit.png
#	Resources/Textures/Structures/Doors/Windoors/uranium.rsi/emergency_unlit.png
#	Resources/Textures/Structures/Power/Generation/Singularity/emitter.rsi/locked.png
#	Resources/Textures/Tiles/attributions.yml
#	Resources/Textures/Tiles/shuttleblue.png
#	Resources/Textures/Tiles/shuttleorange.png
#	Resources/Textures/Tiles/shuttlepurple.png
#	Resources/Textures/Tiles/shuttlered.png
#	Resources/Textures/Tiles/shuttlewhite.png
#	Resources/Textures/White/Fluff/DOOMMAX/cap_cap.rsi/meta.json
#	Resources/Textures/White/Fluff/HSKveez/hardsuit.rsi/meta.json
#	Resources/Textures/White/Fluff/Vtergot/strictgloves.rsi/meta.json
#	Resources/clientCommandPerms.yml
#	Resources/migration.yml
This commit is contained in:
Remuchi
2024-03-26 15:52:23 +07:00
2922 changed files with 137356 additions and 80742 deletions

View File

@@ -94,6 +94,7 @@ namespace Content.Client.Actions
component.Container = EnsureEntity<T>(state.Container, uid);
component.EntityIcon = EnsureEntity<T>(state.EntityIcon, uid);
component.CheckCanInteract = state.CheckCanInteract;
component.CheckConsciousness = state.CheckConsciousness;
component.ClientExclusive = state.ClientExclusive;
component.Priority = state.Priority;
component.AttachedEntity = EnsureEntity<T>(state.AttachedEntity, uid);

View File

@@ -2,6 +2,7 @@ using Content.Shared.Administration;
using Content.Shared.Administration.Managers;
using Robust.Client.Console;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Shared.ContentPack;
using Robust.Shared.Network;
using Robust.Shared.Player;
@@ -16,6 +17,7 @@ namespace Content.Client.Administration.Managers
[Dependency] private readonly IClientConGroupController _conGroup = default!;
[Dependency] private readonly IResourceManager _res = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IUserInterfaceManager _userInterface = default!;
private AdminData? _adminData;
private readonly HashSet<string> _availableCommands = new();
@@ -101,6 +103,9 @@ namespace Content.Client.Administration.Managers
{
var flagsText = string.Join("|", AdminFlagsHelper.FlagsToNames(_adminData.Flags));
_sawmill.Info($"Updated admin status: {_adminData.Active}/{_adminData.Title}/{flagsText}");
if (_adminData.Active)
_userInterface.DebugMonitors.SetMonitor(DebugMonitor.Coords, true);
}
else
{

View File

@@ -19,11 +19,11 @@ namespace Content.Client.Administration.Systems
OnBwoinkTextMessageRecieved?.Invoke(this, message);
}
public void Send(NetUserId channelId, string text, bool isAdmin)
public void Send(NetUserId channelId, string text, bool isAdmin, bool playSound)
{
// Reuse the channel ID as the 'true sender'.
// Server will ignore this and if someone makes it not ignore this (which is bad, allows impersonation!!!), that will help.
RaiseNetworkEvent(new BwoinkTextMessage(channelId, channelId, text, isAdmin));
RaiseNetworkEvent(new BwoinkTextMessage(channelId, channelId, text, isAdmin, playSound: playSound));
SendInputTextUpdated(channelId, false);
}

View File

@@ -2,6 +2,7 @@ using Content.Client.Eui;
using Content.Shared.Administration.Notes;
using Content.Shared.Eui;
using JetBrains.Annotations;
using Robust.Client.UserInterface.Controls;
using static Content.Shared.Administration.Notes.AdminMessageEuiMsg;
namespace Content.Client.Administration.UI.AdminRemarks;
@@ -14,9 +15,8 @@ public sealed class AdminMessageEui : BaseEui
public AdminMessageEui()
{
_popup = new AdminMessagePopupWindow();
_popup.OnAcceptPressed += () => SendMessage(new Accept());
_popup.OnDismissPressed += () => SendMessage(new Dismiss());
_popup.OnClose += () => SendMessage(new CloseEuiMessage());
_popup.OnAcceptPressed += () => SendMessage(new Dismiss(true));
_popup.OnDismissPressed += () => SendMessage(new Dismiss(false));
}
public override void HandleState(EuiStateBase state)
@@ -26,13 +26,17 @@ public sealed class AdminMessageEui : BaseEui
return;
}
_popup.SetMessage(s.Message);
_popup.SetDetails(s.AdminName, s.AddedOn);
_popup.Timer = s.Time;
_popup.SetState(s);
}
public override void Opened()
{
_popup.OpenCentered();
_popup.UserInterfaceManager.WindowRoot.AddChild(_popup);
LayoutContainer.SetAnchorPreset(_popup, LayoutContainer.LayoutPreset.Wide);
}
public override void Closed()
{
_popup.Orphan();
}
}

View File

@@ -0,0 +1,6 @@
<Control xmlns="https://spacestation14.io" Margin="0 0 0 8">
<BoxContainer Orientation="Vertical">
<RichTextLabel Name="Admin" Margin="0 0 0 4" />
<RichTextLabel Name="Message" Margin="2 0 0 0" />
</BoxContainer>
</Control>

View File

@@ -0,0 +1,23 @@
using Content.Shared.Administration.Notes;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
namespace Content.Client.Administration.UI.AdminRemarks;
[GenerateTypedNameReferences]
public sealed partial class AdminMessagePopupMessage : Control
{
public AdminMessagePopupMessage(AdminMessageEuiState.Message message)
{
RobustXamlLoader.Load(this);
Admin.SetMessage(FormattedMessage.FromMarkup(Loc.GetString(
"admin-notes-message-admin",
("admin", message.AdminName),
("date", message.AddedOn.ToLocalTime()))));
Message.SetMessage(message.Text);
}
}

View File

@@ -1,22 +1,36 @@
<ui:FancyWindow xmlns="https://spacestation14.io"
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
VerticalExpand="True" HorizontalExpand="True"
Title="{Loc admin-notes-message-window-title}"
MinSize="600 170">
<PanelContainer VerticalExpand="True" HorizontalExpand="True" StyleClasses="BackgroundDark">
<ScrollContainer HScrollEnabled="False" VerticalExpand="True" HorizontalExpand="True" Margin="4">
<BoxContainer Orientation="Vertical" SeparationOverride="10" VerticalAlignment="Bottom">
<Label Name="AdminLabel" Text="Loading..." />
<RichTextLabel Name="MessageLabel" />
<Control xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client">
<PanelContainer MouseFilter="Stop">
<PanelContainer.PanelOverride>
<!-- semi-transparent background -->
<gfx:StyleBoxFlat BackgroundColor="#000000AA" />
</PanelContainer.PanelOverride>
<Control HorizontalAlignment="Center" VerticalAlignment="Center" MaxWidth="600">
<PanelContainer StyleClasses="AngleRect" />
<BoxContainer Orientation="Vertical" Margin="4">
<RichTextLabel Name="Description" />
<!-- Contains actual messages -->
<ScrollContainer HScrollEnabled="False" Margin="4" VerticalExpand="True" ReturnMeasure="True" MaxHeight="400">
<BoxContainer Orientation="Vertical" Name="MessageContainer" Margin="0 2 0 0" />
</ScrollContainer>
<Label Name="WaitLabel" />
<BoxContainer Orientation="Horizontal">
<Button Name="DismissButton"
Text="{Loc 'admin-notes-message-dismiss'}" />
Text="{Loc 'admin-notes-message-dismiss'}"
Disabled="True"
HorizontalExpand="True"
StyleClasses="OpenRight" />
<Button Name="AcceptButton"
Text="{Loc 'admin-notes-message-accept'}"
Disabled="True" />
Disabled="True"
HorizontalExpand="True"
StyleClasses="OpenLeft" />
</BoxContainer>
</BoxContainer>
</ScrollContainer>
</Control>
</PanelContainer>
</ui:FancyWindow>
</Control>

View File

@@ -1,56 +1,65 @@
using Content.Client.UserInterface.Controls;
using Content.Client.Stylesheets;
using Content.Shared.Administration.Notes;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.Administration.UI.AdminRemarks;
[GenerateTypedNameReferences]
public sealed partial class AdminMessagePopupWindow : FancyWindow
public sealed partial class AdminMessagePopupWindow : Control
{
private float _timer = float.MaxValue;
public float Timer
{
get => _timer;
set
{
WaitLabel.Text = Loc.GetString("admin-notes-message-wait", ("time", MathF.Floor(value)));
_timer = value;
}
}
public event Action? OnDismissPressed;
public event Action? OnAcceptPressed;
public AdminMessagePopupWindow()
{
RobustXamlLoader.Load(this);
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
AcceptButton.OnPressed += OnAcceptButtonPressed;
DismissButton.OnPressed += OnDismissButtonPressed;
}
public void SetMessage(string message)
public float Timer
{
MessageLabel.SetMessage(message);
get => _timer;
private set
{
WaitLabel.Text = Loc.GetString("admin-notes-message-wait", ("time", MathF.Floor(value)));
_timer = value;
}
}
public void SetDetails(string adminName, DateTime addedOn)
public void SetState(AdminMessageEuiState state)
{
AdminLabel.Text = Loc.GetString("admin-notes-message-admin", ("admin", adminName), ("date", addedOn));
Timer = (float) state.Time.TotalSeconds;
MessageContainer.RemoveAllChildren();
foreach (var message in state.Messages)
{
MessageContainer.AddChild(new AdminMessagePopupMessage(message));
}
Description.SetMessage(FormattedMessage.FromMarkup(Loc.GetString("admin-notes-message-desc", ("count", state.Messages.Length))));
}
private void OnDismissButtonPressed(BaseButton.ButtonEventArgs obj)
{
OnDismissPressed?.Invoke();
Close();
}
private void OnAcceptButtonPressed(BaseButton.ButtonEventArgs obj)
{
OnAcceptPressed?.Invoke();
Close();
}
protected override void FrameUpdate(FrameEventArgs args)
@@ -70,6 +79,7 @@ public sealed partial class AdminMessagePopupWindow : FancyWindow
else
{
AcceptButton.Disabled = false;
DismissButton.Disabled = false;
}
}
}

View File

@@ -7,6 +7,8 @@
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="2">
<BoxContainer Access="Public" Name="BwoinkArea" VerticalExpand="True" />
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<CheckBox Visible="True" Name="PlaySound" Access="Public" Text="{Loc 'admin-bwoink-play-sound'}" Pressed="True" />
<Control HorizontalExpand="True" MinWidth="5" />
<Button Visible="True" Name="PopOut" Access="Public" Text="{Loc 'admin-logs-pop-out'}" StyleClasses="OpenBoth" HorizontalAlignment="Left" />
<Control HorizontalExpand="True" />
<Button Visible="False" Name="Bans" Text="{Loc 'admin-player-actions-bans'}" StyleClasses="OpenRight" />

View File

@@ -35,6 +35,8 @@ namespace Content.Client.Administration.UI.CustomControls
private readonly Font _fontOverride;
private PlayerInfo? _selectedPlayer;
public PlayerListControl()
{
_entManager = IoCManager.Resolve<IEntityManager>();

View File

@@ -12,7 +12,7 @@
<BoxContainer Name="VolumeBox" Orientation="Vertical" HorizontalExpand="True" Margin="0 4"/>
<!-- The temperature / heat capacity / thermal energy of the solution -->
<Collapsible Orientation="Vertical">
<Collapsible>
<CollapsibleHeading Name="ThermalHeading" Title="{Loc 'admin-solutions-window-thermals'}" />
<CollapsibleBody>
<BoxContainer Name="ThermalBox" Orientation="Vertical" HorizontalExpand="True" Margin="0 4"/>
@@ -23,7 +23,7 @@
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" Margin="0 4">
<BoxContainer Name="ReagentList" Orientation="Vertical"/>
</ScrollContainer>
<Button Name="AddButton" Text="{Loc 'admin-solutions-window-add-new-button'}" HorizontalExpand="True" Margin="0 4"/>
</BoxContainer>
</DefaultWindow>

View File

@@ -4,6 +4,7 @@ using JetBrains.Annotations;
using Robust.Client.Player;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Client.Alerts;
@@ -12,6 +13,7 @@ public sealed class ClientAlertsSystem : AlertsSystem
{
public AlertOrderPrototype? AlertOrder { get; set; }
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
@@ -33,7 +35,7 @@ public sealed class ClientAlertsSystem : AlertsSystem
AlertOrder = _prototypeManager.EnumeratePrototypes<AlertOrderPrototype>().FirstOrDefault();
if (AlertOrder == null)
Log.Error("alert", "no alertOrder prototype found, alerts will be in random order");
Log.Error("No alertOrder prototype found, alerts will be in random order");
}
public IReadOnlyDictionary<AlertKey, AlertState>? ActiveAlerts
@@ -49,24 +51,23 @@ public sealed class ClientAlertsSystem : AlertsSystem
protected override void AfterShowAlert(Entity<AlertsComponent> alerts)
{
if (_playerManager.LocalEntity != alerts.Owner)
return;
SyncAlerts?.Invoke(this, alerts.Comp.Alerts);
UpdateHud(alerts);
}
protected override void AfterClearAlert(Entity<AlertsComponent> alertsComponent)
protected override void AfterClearAlert(Entity<AlertsComponent> alerts)
{
if (_playerManager.LocalEntity != alertsComponent.Owner)
return;
SyncAlerts?.Invoke(this, alertsComponent.Comp.Alerts);
UpdateHud(alerts);
}
private void ClientAlertsHandleState(EntityUid uid, AlertsComponent component, ref AfterAutoHandleStateEvent args)
private void ClientAlertsHandleState(Entity<AlertsComponent> alerts, ref AfterAutoHandleStateEvent args)
{
if (_playerManager.LocalEntity == uid)
SyncAlerts?.Invoke(this, component.Alerts);
UpdateHud(alerts);
}
private void UpdateHud(Entity<AlertsComponent> entity)
{
if (_playerManager.LocalEntity == entity.Owner)
SyncAlerts?.Invoke(this, entity.Comp.Alerts);
}
private void OnPlayerAttached(EntityUid uid, AlertsComponent component, LocalPlayerAttachedEvent args)

View File

@@ -1,6 +1,5 @@
using Content.Shared.Ame;
using Content.Shared.Ame.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
namespace Content.Client.Ame.UI
{

View File

@@ -1,5 +1,5 @@
using Content.Client.UserInterface;
using Content.Shared.Ame;
using Content.Shared.Ame.Components;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;

View File

@@ -22,6 +22,7 @@ public sealed class AntagStatusIconSystem : SharedStatusIconSystem
SubscribeLocalEvent<RevolutionaryComponent, GetStatusIconsEvent>(GetRevIcon);
SubscribeLocalEvent<ZombieComponent, GetStatusIconsEvent>(GetIcon);
SubscribeLocalEvent<HeadRevolutionaryComponent, GetStatusIconsEvent>(GetIcon);
SubscribeLocalEvent<InitialInfectedComponent, GetStatusIconsEvent>(GetIcon);
}
/// <summary>

View File

@@ -1,7 +1,7 @@
<BoxContainer xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Orientation="Vertical" Margin="2 0 2 4">
<Collapsible Orientation="Vertical">
<Collapsible>
<CollapsibleHeading Name="CAddress" />
<!-- Upper row: toggle, direction, checks -->
<CollapsibleBody Margin="20 0 0 0">

View File

@@ -1,7 +1,7 @@
<BoxContainer xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Orientation="Vertical" Margin="2 0 2 4">
<Collapsible Orientation="Vertical">
<Collapsible>
<CollapsibleHeading Name="CAddress" />
<CollapsibleBody Margin="20 0 0 0">
<BoxContainer Orientation="Vertical">
@@ -26,7 +26,7 @@
<Button Name="CCopySettings" Text="{Loc 'air-alarm-ui-widget-copy'}" ToolTip="{Loc 'air-alarm-ui-widget-copy-tooltip'}" />
</BoxContainer>
<!-- Lower row: every single gas -->
<Collapsible Orientation="Vertical" Margin="2 2 2 2">
<Collapsible Margin="2 2 2 2">
<CollapsibleHeading Title="Gas filters" />
<CollapsibleBody Margin="20 0 0 0">
<GridContainer HorizontalExpand="True" Name="CGasContainer" Columns="3" />

View File

@@ -1,5 +1,5 @@
<BoxContainer xmlns="https://spacestation14.io" HorizontalExpand="True">
<Collapsible Orientation="Vertical">
<Collapsible>
<CollapsibleHeading Name="SensorAddress" />
<CollapsibleBody Margin="20 2 2 2">
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
@@ -10,7 +10,7 @@
<RichTextLabel Name="TemperatureLabel" />
<Control Name="TemperatureThresholdContainer" Margin="20 0 2 0" />
</BoxContainer>
<Collapsible Orientation="Vertical" Margin="2">
<Collapsible Margin="2">
<CollapsibleHeading Title="{Loc 'air-alarm-ui-sensor-gases'}" />
<CollapsibleBody Margin="20 0 0 0">
<BoxContainer Name="GasContainer" Orientation="Vertical" Margin="2" />

View File

@@ -1,7 +1,7 @@
<BoxContainer xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Orientation="Vertical" Margin="0 0 0 4">
<Collapsible Orientation="Vertical">
<Collapsible>
<CollapsibleHeading Name="CName" />
<CollapsibleBody Margin="20 0 0 0">
<BoxContainer Orientation="Vertical">

View File

@@ -0,0 +1,90 @@
using Content.Shared.Atmos.Piping.Portable.Components;
using JetBrains.Annotations;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.Atmos.UI;
/// <summary>
/// Initializes a <see cref="SpaceHeaterWindow"/> and updates it when new server messages are received.
/// </summary>
[UsedImplicitly]
public sealed class SpaceHeaterBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private SpaceHeaterWindow? _window;
public SpaceHeaterBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = new SpaceHeaterWindow();
if (State != null)
UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed();
_window.IncreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(_window.TemperatureChangeDelta);
_window.DecreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(-_window.TemperatureChangeDelta);
_window.ModeSelector.OnItemSelected += OnModeChanged;
_window.PowerLevelSelector.OnItemSelected += OnPowerLevelChange;
}
private void OnToggleStatusButtonPressed()
{
_window?.SetActive(!_window.Active);
SendMessage(new SpaceHeaterToggleMessage());
}
private void OnTemperatureRangeChanged(float changeAmount)
{
SendMessage(new SpaceHeaterChangeTemperatureMessage(changeAmount));
}
private void OnModeChanged(OptionButton.ItemSelectedEventArgs args)
{
_window?.ModeSelector.SelectId(args.Id);
SendMessage(new SpaceHeaterChangeModeMessage((SpaceHeaterMode)args.Id));
}
private void OnPowerLevelChange(RadioOptionItemSelectedEventArgs<int> args)
{
_window?.PowerLevelSelector.Select(args.Id);
SendMessage(new SpaceHeaterChangePowerLevelMessage((SpaceHeaterPowerLevel)args.Id));
}
/// <summary>
/// Update the UI state based on server-sent info
/// </summary>
/// <param name="state"></param>
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (_window == null || state is not SpaceHeaterBoundUserInterfaceState cast)
return;
_window.SetActive(cast.Enabled);
_window.ModeSelector.SelectId((int)cast.Mode);
_window.PowerLevelSelector.Select((int)cast.PowerLevel);
_window.MinTemp = cast.MinTemperature;
_window.MaxTemp = cast.MaxTemperature;
_window.SetTemperature(cast.TargetTemperature);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_window?.Dispose();
}
}

View File

@@ -0,0 +1,34 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MinSize="280 160" Title="Temperature Control Unit">
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Button Text="{Loc comp-space-heater-ui-status-disabled}" Access="Public" Name="ToggleStatusButton"/>
</BoxContainer>
<BoxContainer Orientation="Horizontal" SeparationOverride="5">
<Label Text="{Loc comp-space-heater-ui-mode}"/>
<OptionButton Access="Public" Name="ModeSelector"/>
</BoxContainer>
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" SeparationOverride="5">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label Text="{Loc comp-space-heater-ui-thermostat}"/>
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" HorizontalAlignment="Right">
<Button Text="{Loc comp-space-heater-ui-decrease-temperature-range}" Access="Public" Name="DecreaseTempRange" StyleClasses="OpenRight"/>
<LineEdit Name ="Thermostat" MinSize="55 0"></LineEdit>
<Button Text="{Loc comp-space-heater-ui-increase-temperature-range}" Access="Public" Name="IncreaseTempRange" StyleClasses="OpenLeft"/>
</BoxContainer>
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" SeparationOverride="5">
<Label Text="{Loc comp-space-heater-ui-power-consumption}"/>
<BoxContainer Name="PowerLevelSelectorHBox" Access="Public" SeparationOverride="2"/>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -0,0 +1,73 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Portable.Components;
namespace Content.Client.Atmos.UI;
/// <summary>
/// Client-side UI used to control a space heater.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class SpaceHeaterWindow : DefaultWindow
{
// To account for a minimum delta temperature for atmos equalization to trigger we use a fixed step for target temperature increment/decrement
public int TemperatureChangeDelta = 5;
public bool Active;
// Temperatures range bounds in Kelvin (K)
public float MinTemp;
public float MaxTemp;
public RadioOptions<int> PowerLevelSelector;
public SpaceHeaterWindow()
{
RobustXamlLoader.Load(this);
// Add the Mode selector list
foreach (var value in Enum.GetValues<SpaceHeaterMode>())
{
ModeSelector.AddItem(Loc.GetString($"comp-space-heater-mode-{value}"), (int)value);
}
// Add the Power level radio buttons
PowerLevelSelectorHBox.AddChild(PowerLevelSelector = new RadioOptions<int>(RadioOptionsLayout.Horizontal));
PowerLevelSelector.FirstButtonStyle = "OpenRight";
PowerLevelSelector.LastButtonStyle = "OpenLeft";
PowerLevelSelector.ButtonStyle = "OpenBoth";
foreach (var value in Enum.GetValues<SpaceHeaterPowerLevel>())
{
PowerLevelSelector.AddItem(Loc.GetString($"comp-space-heater-ui-{value}-power-consumption"), (int)value);
}
// Only allow temperature increment/decrement of TemperatureChangeDelta
Thermostat.Editable = false;
}
public void SetActive(bool active)
{
Active = active;
ToggleStatusButton.Pressed = active;
if (active)
{
ToggleStatusButton.Text = Loc.GetString("comp-space-heater-ui-status-enabled");
}
else
{
ToggleStatusButton.Text = Loc.GetString("comp-space-heater-ui-status-disabled");
}
}
public void SetTemperature(float targetTemperature)
{
Thermostat.SetText($"{targetTemperature - Atmospherics.T0C} °C");
IncreaseTempRange.Disabled = targetTemperature + TemperatureChangeDelta > MaxTemp;
DecreaseTempRange.Disabled = targetTemperature - TemperatureChangeDelta < MinTemp;
}
}

View File

@@ -1,156 +0,0 @@
using Content.Client.GameTicking.Managers;
using Content.Client.Lobby;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using JetBrains.Annotations;
using Robust.Client;
using Robust.Client.State;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
namespace Content.Client.Audio;
[UsedImplicitly]
public sealed class BackgroundAudioSystem : EntitySystem
{
/*
* TODO: Nuke this system and merge into contentaudiosystem
*/
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly IBaseClient _client = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly ClientGameTicker _gameTicker = default!;
[Dependency] private readonly IStateManager _stateManager = default!;
private readonly AudioParams _lobbyParams = new(-5f, 1, "Master", 0, 0, 0, true, 0f);
private readonly AudioParams _roundEndParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f);
public EntityUid? LobbyMusicStream;
public EntityUid? LobbyRoundRestartAudioStream;
public override void Initialize()
{
base.Initialize();
Subs.CVar(_configManager, CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
Subs.CVar(_configManager, CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
_stateManager.OnStateChanged += StateManagerOnStateChanged;
_client.PlayerLeaveServer += OnLeave;
_gameTicker.LobbySongUpdated += LobbySongUpdated;
SubscribeNetworkEvent<RoundRestartCleanupEvent>(PlayRestartSound);
}
public override void Shutdown()
{
base.Shutdown();
_stateManager.OnStateChanged -= StateManagerOnStateChanged;
_client.PlayerLeaveServer -= OnLeave;
_gameTicker.LobbySongUpdated -= LobbySongUpdated;
EndLobbyMusic();
}
private void StateManagerOnStateChanged(StateChangedEventArgs args)
{
switch (args.NewState)
{
case LobbyState:
StartLobbyMusic();
break;
default:
EndLobbyMusic();
break;
}
}
private void OnLeave(object? sender, PlayerEventArgs args)
{
EndLobbyMusic();
}
private void LobbyMusicVolumeCVarChanged(float volume)
{
if (_stateManager.CurrentState is LobbyState)
{
RestartLobbyMusic();
}
}
private void LobbyMusicCVarChanged(bool musicEnabled)
{
if (!musicEnabled)
{
EndLobbyMusic();
}
else if (_stateManager.CurrentState is LobbyState)
{
StartLobbyMusic();
}
else
{
EndLobbyMusic();
}
}
private void LobbySongUpdated()
{
RestartLobbyMusic();
}
public void RestartLobbyMusic()
{
EndLobbyMusic();
StartLobbyMusic();
}
public void StartLobbyMusic()
{
if (LobbyMusicStream != null || !_configManager.GetCVar(CCVars.LobbyMusicEnabled))
return;
var file = _gameTicker.LobbySong;
if (file == null) // We have not received the lobby song yet.
{
return;
}
LobbyMusicStream = _audio.PlayGlobal(
file,
Filter.Local(),
false,
_lobbyParams.WithVolume(_lobbyParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume))))?.Entity;
}
private void EndLobbyMusic()
{
LobbyMusicStream = _audio.Stop(LobbyMusicStream);
}
private void PlayRestartSound(RoundRestartCleanupEvent ev)
{
if (!_configManager.GetCVar(CCVars.RestartSoundsEnabled))
return;
var file = _gameTicker.RestartSound;
if (string.IsNullOrEmpty(file))
{
return;
}
LobbyRoundRestartAudioStream = _audio.PlayGlobal(
file,
Filter.Local(),
false,
_roundEndParams.WithVolume(_roundEndParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume)))
)?.Entity;
}
}

View File

@@ -0,0 +1,283 @@
using System.Linq;
using Content.Client.GameTicking.Managers;
using Content.Client.Lobby;
using Content.Shared.Audio.Events;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Robust.Client;
using Robust.Client.ResourceManagement;
using Robust.Client.State;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.Audio;
// Part of ContentAudioSystem that is responsible for lobby music playing/stopping and round-end sound-effect.
public sealed partial class ContentAudioSystem
{
[Dependency] private readonly IBaseClient _client = default!;
[Dependency] private readonly ClientGameTicker _gameTicker = default!;
[Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
private readonly AudioParams _lobbySoundtrackParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f);
private readonly AudioParams _roundEndSoundEffectParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f);
/// <summary>
/// EntityUid of lobby restart sound component.
/// </summary>
private EntityUid? _lobbyRoundRestartAudioStream;
/// <summary>
/// Shuffled list of soundtrack file-names.
/// </summary>
private string[]? _lobbyPlaylist;
/// <summary>
/// Short info about lobby soundtrack currently playing. Is null if soundtrack is not playing.
/// </summary>
private LobbySoundtrackInfo? _lobbySoundtrackInfo;
private Action<LobbySoundtrackChangedEvent>? _lobbySoundtrackChanged;
/// <summary>
/// Event for subscription on lobby soundtrack changes.
/// </summary>
public event Action<LobbySoundtrackChangedEvent>? LobbySoundtrackChanged
{
add
{
if (value != null)
{
if (_lobbySoundtrackInfo != null)
{
value(new LobbySoundtrackChangedEvent(_lobbySoundtrackInfo.Filename));
}
_lobbySoundtrackChanged += value;
}
}
remove => _lobbySoundtrackChanged -= value;
}
/// <summary>
/// Initializes subscriptions that are related to lobby music.
/// </summary>
private void InitializeLobbyMusic()
{
Subs.CVar(_configManager, CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
Subs.CVar(_configManager, CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
_stateManager.OnStateChanged += StateManagerOnStateChanged;
_client.PlayerLeaveServer += OnLeave;
SubscribeNetworkEvent<LobbyMusicStopEvent>(OnLobbySongStopped);
SubscribeNetworkEvent<LobbyPlaylistChangedEvent>(OnLobbySongChanged);
}
private void OnLobbySongStopped(LobbyMusicStopEvent ev)
{
EndLobbyMusic();
}
private void StateManagerOnStateChanged(StateChangedEventArgs args)
{
switch (args.NewState)
{
case LobbyState:
StartLobbyMusic();
break;
default:
EndLobbyMusic();
break;
}
}
private void OnLeave(object? sender, PlayerEventArgs args)
{
EndLobbyMusic();
}
private void LobbyMusicVolumeCVarChanged(float volume)
{
if (_lobbySoundtrackInfo != null)
{
_audio.SetVolume(
_lobbySoundtrackInfo.MusicStreamEntityUid,
_lobbySoundtrackParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume))
);
}
}
private void LobbyMusicCVarChanged(bool musicEnabled)
{
if (musicEnabled && _stateManager.CurrentState is LobbyState)
{
StartLobbyMusic();
}
else
{
EndLobbyMusic();
}
}
private void OnLobbySongChanged(LobbyPlaylistChangedEvent playlistChangedEvent)
{
var playlist = playlistChangedEvent.Playlist;
//playlist is already playing, no need to restart it
if (_lobbySoundtrackInfo != null
&& _lobbyPlaylist != null
&& _lobbyPlaylist.SequenceEqual(playlist)
)
{
return;
}
EndLobbyMusic();
StartLobbyMusic(playlistChangedEvent.Playlist);
}
/// <summary>
/// Re-starts playing lobby music from playlist, last sent from server. if there is currently none - does nothing.
/// </summary>
private void StartLobbyMusic()
{
if (_lobbyPlaylist == null || _lobbyPlaylist.Length == 0)
{
return;
}
StartLobbyMusic(_lobbyPlaylist);
}
/// <summary>
/// Starts playing lobby music from playlist. If playlist is empty, or lobby music setting is turned off - does nothing.
/// </summary>
/// <param name="playlist">Array of soundtrack filenames for lobby playlist.</param>
private void StartLobbyMusic(string[] playlist)
{
if (_lobbySoundtrackInfo != null || !_configManager.GetCVar(CCVars.LobbyMusicEnabled))
return;
_lobbyPlaylist = playlist;
if (_lobbyPlaylist.Length == 0)
{
return;
}
PlaySoundtrack(playlist[0]);
}
private void PlaySoundtrack(string soundtrackFilename)
{
if (!_resourceCache.TryGetResource(new ResPath(soundtrackFilename), out AudioResource? audio))
{
return;
}
var playResult = _audio.PlayGlobal(
soundtrackFilename,
Filter.Local(),
false,
_lobbySoundtrackParams.WithVolume(_lobbySoundtrackParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume)))
);
if (playResult.Value.Entity == default)
{
_sawmill.Warning(
$"Tried to play lobby soundtrack '{{Filename}}' using {nameof(SharedAudioSystem)}.{nameof(SharedAudioSystem.PlayGlobal)} but it returned default value of EntityUid!",
soundtrackFilename);
return;
}
var nextTrackOn = _timing.CurTime + audio.AudioStream.Length;
_lobbySoundtrackInfo = new LobbySoundtrackInfo(soundtrackFilename, nextTrackOn, playResult.Value.Entity);
var lobbySongChangedEvent = new LobbySoundtrackChangedEvent(soundtrackFilename);
_lobbySoundtrackChanged?.Invoke(lobbySongChangedEvent);
}
private void EndLobbyMusic()
{
if (_lobbySoundtrackInfo == null)
{
return;
}
_audio.Stop(_lobbySoundtrackInfo.MusicStreamEntityUid);
_lobbySoundtrackInfo = null;
var lobbySongChangedEvent = new LobbySoundtrackChangedEvent();
_lobbySoundtrackChanged?.Invoke(lobbySongChangedEvent);
}
private void PlayRestartSound(RoundRestartCleanupEvent ev)
{
if (!_configManager.GetCVar(CCVars.RestartSoundsEnabled))
return;
var file = _gameTicker.RestartSound;
if (string.IsNullOrEmpty(file))
{
return;
}
_lobbyRoundRestartAudioStream = _audio.PlayGlobal(
file,
Filter.Local(),
false,
_roundEndSoundEffectParams.WithVolume(_roundEndSoundEffectParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume)))
)?.Entity;
}
private void ShutdownLobbyMusic()
{
_stateManager.OnStateChanged -= StateManagerOnStateChanged;
_client.PlayerLeaveServer -= OnLeave;
EndLobbyMusic();
}
private void UpdateLobbyMusic()
{
if (
_lobbySoundtrackInfo != null
&& _timing.CurTime >= _lobbySoundtrackInfo.NextTrackOn
&& _lobbyPlaylist?.Length > 0
)
{
var nextSoundtrackFilename = GetNextSoundtrackFromPlaylist(_lobbySoundtrackInfo.Filename, _lobbyPlaylist);
PlaySoundtrack(nextSoundtrackFilename);
}
}
private static string GetNextSoundtrackFromPlaylist(string currentSoundtrackFilename, string[] playlist)
{
var indexOfCurrent = Array.IndexOf(playlist, currentSoundtrackFilename);
var nextTrackIndex = indexOfCurrent + 1;
if (nextTrackIndex > playlist.Length - 1)
{
nextTrackIndex = 0;
}
return playlist[nextTrackIndex];
}
/// <summary> Container for lobby soundtrack information. </summary>
/// <param name="Filename">Soundtrack filename.</param>
/// <param name="NextTrackOn">Time (based on <see cref="IGameTiming.CurTime"/>) when this track is going to finish playing and next track have to be started.</param>
/// <param name="MusicStreamEntityUid">
/// EntityUid of launched soundtrack (from <see cref="SharedAudioSystem.PlayGlobal(string,Robust.Shared.Player.Filter,bool,System.Nullable{Robust.Shared.Audio.AudioParams})"/>).
/// </param>
private sealed record LobbySoundtrackInfo(string Filename, TimeSpan NextTrackOn, EntityUid MusicStreamEntityUid);
}
/// <summary>
/// Event of changing lobby soundtrack (or stopping lobby music - will pass null for <paramref name="SoundtrackFilename"/> in that case).
/// Is used by <see cref="ContentAudioSystem.LobbySoundtrackChanged"/> and <see cref="LobbyState.UpdateLobbySoundtrackInfo"/>.
/// </summary>
/// <param name="SoundtrackFilename">Filename of newly set soundtrack, or null if soundtrack playback is stopped.</param>
public sealed record LobbySoundtrackChangedEvent(string? SoundtrackFilename = null);

View File

@@ -29,12 +29,14 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
public const float AmbientMusicMultiplier = 3f;
public const float LobbyMultiplier = 3f;
public const float InterfaceMultiplier = 2f;
public override void Initialize()
{
base.Initialize();
UpdatesOutsidePrediction = true;
InitializeAmbientMusic();
InitializeLobbyMusic();
SubscribeNetworkEvent<RoundRestartCleanupEvent>(OnRoundCleanup);
}
@@ -43,11 +45,11 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
_fadingOut.Clear();
// Preserve lobby music but everything else should get dumped.
var lobbyMusic = EntityManager.System<BackgroundAudioSystem>().LobbyMusicStream;
var lobbyMusic = _lobbySoundtrackInfo?.MusicStreamEntityUid;
TryComp(lobbyMusic, out AudioComponent? lobbyMusicComp);
var oldMusicGain = lobbyMusicComp?.Gain;
var restartAudio = EntityManager.System<BackgroundAudioSystem>().LobbyRoundRestartAudioStream;
var restartAudio = _lobbyRoundRestartAudioStream;
TryComp(restartAudio, out AudioComponent? restartComp);
var oldAudioGain = restartComp?.Gain;
@@ -62,12 +64,14 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
{
Audio.SetGain(restartAudio, oldAudioGain.Value, restartComp);
}
PlayRestartSound(ev);
}
public override void Shutdown()
{
base.Shutdown();
ShutdownAmbientMusic();
ShutdownLobbyMusic();
}
public override void Update(float frameTime)
@@ -78,6 +82,7 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
return;
UpdateAmbientMusic();
UpdateLobbyMusic();
UpdateFades(frameTime);
}
@@ -102,7 +107,7 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
_fadingOut.Remove(stream.Value);
var curVolume = component.Volume;
var change = (curVolume - MinVolume) / duration;
var change = (MinVolume - curVolume) / duration;
_fadingIn.Add(stream.Value, (change, component.Volume));
component.Volume = MinVolume;
}
@@ -146,8 +151,8 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
continue;
}
var volume = component.Volume + change * frameTime;
volume = MathF.Max(target, volume);
var volume = component.Volume - change * frameTime;
volume = MathF.Min(target, volume);
_audio.SetVolume(stream, volume, component);
if (component.Volume.Equals(target))

View File

@@ -11,7 +11,7 @@
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BackgroundColor="{xNamespace:Static style:StyleNano.ButtonColorDisabled}" />
</PanelContainer.PanelOverride>
<Collapsible Orientation="Vertical" Name="Collapsible">
<Collapsible Name="Collapsible">
<CollapsibleHeading Name="Heading" MinHeight="35"/>
<CollapsibleBody Name="Body">
<BoxContainer Name="ItemsContainer" Orientation="Vertical" HorizontalExpand="True"/>

View File

@@ -1,4 +1,4 @@
using System.Numerics;
using System.Numerics;
using Content.Shared.CardboardBox;
using Content.Shared.CardboardBox.Components;
using Content.Shared.Examine;
@@ -11,6 +11,7 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
{
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly ExamineSystemShared _examine = default!;
public override void Initialize()
{
@@ -55,7 +56,7 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
foreach (var mob in mobMoverEntities)
{
var mapPos = _transform.GetMapCoordinates(mob);
if (!ExamineSystemShared.InRangeUnOccluded(sourcePos, mapPos, box.Distance, null))
if (!_examine.InRangeUnOccluded(sourcePos, mapPos, box.Distance, null))
continue;
var ent = Spawn(box.Effect, mapPos);

View File

@@ -92,7 +92,8 @@ namespace Content.Client.Cargo.UI
// else if category and not search
if (search.Length == 0 && _category == null ||
search.Length != 0 && prototype.Name.ToLowerInvariant().Contains(search) ||
search.Length == 0 && _category != null && prototype.Category.Equals(_category))
search.Length != 0 && prototype.Description.ToLowerInvariant().Contains(search) ||
search.Length == 0 && _category != null && Loc.GetString(prototype.Category).Equals(_category))
{
var button = new CargoProductRow
{
@@ -121,7 +122,7 @@ namespace Content.Client.Cargo.UI
foreach (var prototype in ProductPrototypes)
{
if (!_categoryStrings.Contains(prototype.Category))
if (!_categoryStrings.Contains(Loc.GetString(prototype.Category)))
{
_categoryStrings.Add(Loc.GetString(prototype.Category));
}

View File

@@ -1,50 +0,0 @@
using Content.Client.UserInterface.Fragments;
using Content.Shared.CartridgeLoader.Cartridges;
using Content.Shared.CartridgeLoader;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.CartridgeLoader.Cartridges;
public sealed partial class NewsReadUi : UIFragment
{
private NewsReadUiFragment? _fragment;
public override Control GetUIFragmentRoot()
{
return _fragment!;
}
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
{
_fragment = new NewsReadUiFragment();
_fragment.OnNextButtonPressed += () =>
{
SendNewsReadMessage(NewsReadUiAction.Next, userInterface);
};
_fragment.OnPrevButtonPressed += () =>
{
SendNewsReadMessage(NewsReadUiAction.Prev, userInterface);
};
_fragment.OnNotificationSwithPressed += () =>
{
SendNewsReadMessage(NewsReadUiAction.NotificationSwith, userInterface);
};
}
public override void UpdateState(BoundUserInterfaceState state)
{
if (state is NewsReadBoundUserInterfaceState cast)
_fragment?.UpdateState(cast.Article, cast.TargetNum, cast.TotalNum, cast.NotificationOn);
else if (state is NewsReadEmptyBoundUserInterfaceState empty)
_fragment?.UpdateEmptyState(empty.NotificationOn);
}
private void SendNewsReadMessage(NewsReadUiAction action, BoundUserInterface userInterface)
{
var newsMessage = new NewsReadUiMessageEvent(action);
var message = new CartridgeUiMessage(newsMessage);
userInterface.SendMessage(message);
}
}

View File

@@ -0,0 +1,54 @@
using Content.Client.UserInterface.Fragments;
using Content.Shared.CartridgeLoader.Cartridges;
using Content.Shared.CartridgeLoader;
using Robust.Client.UserInterface;
namespace Content.Client.CartridgeLoader.Cartridges;
public sealed partial class NewsReaderUi : UIFragment
{
private NewsReaderUiFragment? _fragment;
public override Control GetUIFragmentRoot()
{
return _fragment!;
}
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
{
_fragment = new NewsReaderUiFragment();
_fragment.OnNextButtonPressed += () =>
{
SendNewsReaderMessage(NewsReaderUiAction.Next, userInterface);
};
_fragment.OnPrevButtonPressed += () =>
{
SendNewsReaderMessage(NewsReaderUiAction.Prev, userInterface);
};
_fragment.OnNotificationSwithPressed += () =>
{
SendNewsReaderMessage(NewsReaderUiAction.NotificationSwitch, userInterface);
};
}
public override void UpdateState(BoundUserInterfaceState state)
{
switch (state)
{
case NewsReaderBoundUserInterfaceState cast:
_fragment?.UpdateState(cast.Article, cast.TargetNum, cast.TotalNum, cast.NotificationOn);
break;
case NewsReaderEmptyBoundUserInterfaceState empty:
_fragment?.UpdateEmptyState(empty.NotificationOn);
break;
}
}
private void SendNewsReaderMessage(NewsReaderUiAction action, BoundUserInterface userInterface)
{
var newsMessage = new NewsReaderUiMessageEvent(action);
var message = new CartridgeUiMessage(newsMessage);
userInterface.SendMessage(message);
}
}

View File

@@ -1,21 +1,30 @@
<cartridges:NewsReadUiFragment xmlns:cartridges="clr-namespace:Content.Client.CartridgeLoader.Cartridges"
<cartridges:NewsReaderUiFragment xmlns:cartridges="clr-namespace:Content.Client.CartridgeLoader.Cartridges"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns="https://spacestation14.io" Margin="1 0 2 0">
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
xmlns="https://spacestation14.io"
Margin="1 0 2 0"
Orientation="Vertical"
HorizontalExpand="True"
VerticalExpand="True">
<PanelContainer StyleClasses="BackgroundDark"></PanelContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="5,5,5,5">
<Button
Name="Prev"
MinWidth="64"
Disabled="True"
HorizontalAlignment="Left"
Text="{Loc 'news-read-ui-past-text'}"
Text="{Loc 'news-read-ui-prev-text'}"
ToolTip="{Loc 'news-read-ui-prev-tooltip'}"
Access="Public"
HorizontalExpand="True"/>
<Button
Name="Next"
MinWidth="64"
Disabled="True"
HorizontalAlignment="Right"
Text="{Loc 'news-read-ui-next-text'}" />
Text="{Loc 'news-read-ui-next-text'}"
ToolTip="{Loc 'news-read-ui-next-tooltip'}"/>
</BoxContainer>
<controls:StripeBack Name="АrticleNameContainer">
<PanelContainer>
@@ -46,9 +55,11 @@
</PanelContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="5,5,5,5">
<Button
Name="NotificationSwith"
Name="NotificationSwitch"
ToolTip="{Loc news-reader-ui-mute-tooltip}"
MinWidth="20"/>
<RichTextLabel Margin="5,2,2,2" Name="ShareTime" VerticalAlignment="Top"/>
<customControls:VSeparator Margin="2 0"/>
<RichTextLabel Margin="5,2,2,2" Name="Author" VerticalAlignment="Top" HorizontalAlignment="Right"/>
</BoxContainer>
</cartridges:NewsReadUiFragment>
</cartridges:NewsReaderUiFragment>

View File

@@ -7,23 +7,20 @@ using Robust.Client.UserInterface.XAML;
namespace Content.Client.CartridgeLoader.Cartridges;
[GenerateTypedNameReferences]
public sealed partial class NewsReadUiFragment : BoxContainer
public sealed partial class NewsReaderUiFragment : BoxContainer
{
public event Action? OnNextButtonPressed;
public event Action? OnPrevButtonPressed;
public event Action? OnNotificationSwithPressed;
public NewsReadUiFragment()
public NewsReaderUiFragment()
{
RobustXamlLoader.Load(this);
Orientation = LayoutOrientation.Vertical;
HorizontalExpand = true;
VerticalExpand = true;
Next.OnPressed += _ => OnNextButtonPressed?.Invoke();
Prev.OnPressed += _ => OnPrevButtonPressed?.Invoke();
NotificationSwith.OnPressed += _ => OnNotificationSwithPressed?.Invoke();
NotificationSwitch.OnPressed += _ => OnNotificationSwithPressed?.Invoke();
}
public void UpdateState(NewsArticle article, int targetNum, int totalNum, bool notificationOn)
@@ -33,17 +30,20 @@ public sealed partial class NewsReadUiFragment : BoxContainer
ShareTime.Visible = true;
Author.Visible = true;
PageName.Text = article.Name;
PageName.Text = article.Title;
PageText.SetMarkup(article.Content);
PageNum.Text = $"{targetNum}/{totalNum}";
NotificationSwith.Text = Loc.GetString(notificationOn ? "news-read-ui-notification-on" : "news-read-ui-notification-off");
NotificationSwitch.Text = Loc.GetString(notificationOn ? "news-read-ui-notification-on" : "news-read-ui-notification-off");
string shareTime = article.ShareTime.ToString("hh\\:mm\\:ss");
string shareTime = article.ShareTime.ToString(@"hh\:mm\:ss");
ShareTime.SetMarkup(Loc.GetString("news-read-ui-time-prefix-text") + " " + shareTime);
Author.SetMarkup(Loc.GetString("news-read-ui-author-prefix") + " " + (article.Author != null ? article.Author : Loc.GetString("news-read-ui-no-author")));
Prev.Disabled = targetNum <= 1;
Next.Disabled = targetNum >= totalNum;
}
public void UpdateEmptyState(bool notificationOn)
@@ -55,6 +55,6 @@ public sealed partial class NewsReadUiFragment : BoxContainer
PageName.Text = Loc.GetString("news-read-ui-not-found-text");
NotificationSwith.Text = Loc.GetString(notificationOn ? "news-read-ui-notification-on" : "news-read-ui-notification-off");
NotificationSwitch.Text = Loc.GetString(notificationOn ? "news-read-ui-notification-on" : "news-read-ui-notification-off");
}
}

View File

@@ -252,7 +252,8 @@ namespace Content.Client.Chat.UI
var bubbleContent = new RichTextLabel
{
MaxWidth = SpeechMaxWidth,
Margin = new Thickness(2, 6, 2, 2)
Margin = new Thickness(2, 6, 2, 2),
StyleClasses = { "bubbleContent" }
};
//We'll be honest. *Yes* this is hacky. Doing this in a cleaner way would require a bottom-up refactor of how saycode handles sending chat messages. -Myr

View File

@@ -2,6 +2,7 @@ using Content.Client.Message;
using Content.Client.Stylesheets;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.FixedPoint;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
@@ -14,6 +15,10 @@ public sealed class InjectorStatusControl : Control
private readonly SharedSolutionContainerSystem _solutionContainers;
private readonly RichTextLabel _label;
private FixedPoint2 _prevVolume;
private FixedPoint2 _prevMaxVolume;
private InjectorToggleMode _prevToggleState;
public InjectorStatusControl(Entity<InjectorComponent> parent, SharedSolutionContainerSystem solutionContainers)
{
_parent = parent;
@@ -29,6 +34,16 @@ public sealed class InjectorStatusControl : Control
if (!_solutionContainers.TryGetSolution(_parent.Owner, InjectorComponent.SolutionName, out _, out var solution))
return;
// only updates the UI if any of the details are different than they previously were
if (_prevVolume == solution.Volume
&& _prevMaxVolume == solution.MaxVolume
&& _prevToggleState == _parent.Comp.ToggleState)
return;
_prevVolume = solution.Volume;
_prevMaxVolume = solution.MaxVolume;
_prevToggleState = _parent.Comp.ToggleState;
// Update current volume and injector state
var modeStringLocalized = Loc.GetString(_parent.Comp.ToggleState switch
{

View File

@@ -1,8 +1,7 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
Title="{Loc 'reagent-dispenser-bound-user-interface-title'}"
SetSize="620 450"
MinSize="620 450">
MinSize="680 450">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'reagent-dispenser-window-amount-to-dispense-label'}"/>
@@ -18,10 +17,8 @@
<Button Name="DispenseButton100" Access="Public" Text="100" StyleClasses="OpenLeft"/>
</BoxContainer>
<Control MinSize="0 10"/>
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" MinSize="0 170">
<GridContainer Name="ChemicalList" Access="Public" Columns="4">
</GridContainer>
</ScrollContainer>
<GridContainer Name="ChemicalList" HorizontalExpand="True" VerticalExpand="True" Access="Public" Columns="6">
</GridContainer>
<Control MinSize="0 10"/>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'reagent-dispenser-window-container-label'}"/>
@@ -35,19 +32,22 @@
StyleClasses="OpenLeft"/>
</BoxContainer>
<Control MinSize="0 10"/>
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True" MinSize="0 160">
<PanelContainer VerticalExpand="True"
SizeFlagsStretchRatio="6"
MinSize="0 150">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#050505" />
</PanelContainer.PanelOverride>
<BoxContainer Name="ContainerInfo"
Orientation="Vertical"
HorizontalExpand="True">
<Label Text="{Loc 'reagent-dispenser-window-no-container-loaded-text'}"/>
</BoxContainer>
</PanelContainer>
</ScrollContainer>
<BoxContainer Orientation="Horizontal">
<SpriteView Name="View" Scale="4 4" MinSize="150 150"/>
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True" MinSize="0 160">
<PanelContainer VerticalExpand="True"
SizeFlagsStretchRatio="6"
MinSize="0 150">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#1b1b1e" />
</PanelContainer.PanelOverride>
<BoxContainer Name="ContainerInfo"
Orientation="Vertical"
HorizontalExpand="True">
<Label Text="{Loc 'reagent-dispenser-window-no-container-loaded-text'}"/>
</BoxContainer>
</PanelContainer>
</ScrollContainer>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -19,6 +19,8 @@ namespace Content.Client.Chemistry.UI
public sealed partial class ReagentDispenserWindow : DefaultWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public event Action<BaseButton.ButtonEventArgs, DispenseReagentButton>? OnDispenseReagentButtonPressed;
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseEntered;
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseExited;
@@ -55,8 +57,11 @@ namespace Content.Client.Chemistry.UI
ChemicalList.Children.Clear();
foreach (var entry in inventory
.OrderBy(r => {_prototypeManager.TryIndex(r.Prototype, out ReagentPrototype? p); return p?.LocalizedName;}))
foreach (var entry in inventory.OrderBy(r =>
{
_prototypeManager.TryIndex(r.Prototype, out ReagentPrototype? p);
return p?.LocalizedName;
}))
{
var localizedName = _prototypeManager.TryIndex(entry.Prototype, out ReagentPrototype? p)
? p.LocalizedName
@@ -80,6 +85,9 @@ namespace Content.Client.Chemistry.UI
UpdateContainerInfo(castState);
UpdateReagentsList(castState.Inventory);
_entityManager.TryGetEntity(castState.OutputContainerEntity, out var outputContainerEnt);
View.SetEntity(outputContainerEnt);
// Disable the Clear & Eject button if no beaker
ClearButton.Disabled = castState.OutputContainer is null;
EjectButton.Disabled = castState.OutputContainer is null;
@@ -129,7 +137,7 @@ namespace Content.Client.Chemistry.UI
if (state.OutputContainer is null)
{
ContainerInfo.Children.Add(new Label {Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text") });
ContainerInfo.Children.Add(new Label { Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text") });
return;
}
@@ -154,11 +162,11 @@ namespace Content.Client.Chemistry.UI
? p.LocalizedName
: Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
var nameLabel = new Label {Text = $"{localizedName}: "};
var nameLabel = new Label { Text = $"{localizedName}: " };
var quantityLabel = new Label
{
Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", quantity)),
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor},
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor },
};
// Check if the reagent is being moused over. If so, color it green.

View File

@@ -186,7 +186,7 @@ public sealed class ClientClothingSystem : ClothingSystem
State = state
};
layers = new List<PrototypeLayerData> { layer };
layers = [layer];
return true;
}
@@ -302,8 +302,7 @@ public sealed class ClientClothingSystem : ClothingSystem
{
if (!revealedLayers.Add(key))
{
Logger.Warning(
$"Duplicate key for clothing visuals: {key}. Are multiple components attempting to modify the same layer? Equipment: {ToPrettyString(equipment)}");
Log.Warning($"Duplicate key for clothing visuals: {key}. Are multiple components attempting to modify the same layer? Equipment: {ToPrettyString(equipment)}");
continue;
}
@@ -314,6 +313,9 @@ public sealed class ClientClothingSystem : ClothingSystem
// note that every insertion requires reshuffling & remapping all the existing layers.
sprite.AddBlankLayer(index);
sprite.LayerMapSet(key, index);
if (layerData.Color != null)
sprite.LayerSetColor(key, layerData.Color.Value);
}
else
index = sprite.LayerMapReserveBlank(key);

View File

@@ -27,6 +27,7 @@ namespace Content.Client.Construction
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
private readonly Dictionary<int, EntityUid> _ghosts = new();
@@ -195,7 +196,7 @@ namespace Content.Client.Construction
return false;
// This InRangeUnobstructed should probably be replaced with "is there something blocking us in that tile?"
var predicate = GetPredicate(prototype.CanBuildInImpassable, loc.ToMap(EntityManager));
var predicate = GetPredicate(prototype.CanBuildInImpassable, loc.ToMap(EntityManager, _transformSystem));
if (!_interactionSystem.InRangeUnobstructed(user, loc, 20f, predicate: predicate))
return false;

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<!-- Work around https://github.com/dotnet/project-system/issues/4314 -->
<TargetFramework>$(TargetFramework)</TargetFramework>
<LangVersion>11</LangVersion>
<LangVersion>12</LangVersion>
<IsPackable>false</IsPackable>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<OutputPath>..\bin\Content.Client\</OutputPath>

View File

@@ -170,7 +170,7 @@ namespace Content.Client.ContextMenu.UI
if (_combatMode.IsInCombatMode(args.Session?.AttachedEntity))
return false;
var coords = args.Coordinates.ToMap(_entityManager);
var coords = args.Coordinates.ToMap(_entityManager, _xform);
if (_verbSystem.TryGetEntityMenuEntities(coords, out var entities))
OpenRootMenu(entities);

View File

@@ -1,18 +1,14 @@
using Content.Shared.CCVar;
using Content.Shared.CrewManifest;
using Content.Shared.CrewManifest;
using Content.Shared.Roles;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using System.Linq;
namespace Content.Client.CrewManifest.UI;
public sealed class CrewManifestListing : BoxContainer
{
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IEntitySystemManager _entitySystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly SpriteSystem _spriteSystem;
@@ -25,7 +21,7 @@ public sealed class CrewManifestListing : BoxContainer
public void AddCrewManifestEntries(CrewManifestEntries entries)
{
var entryDict = new Dictionary<string, List<CrewManifestEntry>>();
var entryDict = new Dictionary<DepartmentPrototype, List<CrewManifestEntry>>();
foreach (var entry in entries.Entries)
{
@@ -34,37 +30,19 @@ public sealed class CrewManifestListing : BoxContainer
// this is a little expensive, and could be better
if (department.Roles.Contains(entry.JobPrototype))
{
entryDict.GetOrNew(department.ID).Add(entry);
entryDict.GetOrNew(department).Add(entry);
}
}
}
var entryList = new List<(string section, List<CrewManifestEntry> entries)>();
var entryList = new List<(DepartmentPrototype section, List<CrewManifestEntry> entries)>();
foreach (var (section, listing) in entryDict)
{
entryList.Add((section, listing));
}
var sortOrder = _configManager.GetCVar(CCVars.CrewManifestOrdering).Split(",").ToList();
entryList.Sort((a, b) =>
{
var ai = sortOrder.IndexOf(a.section);
var bi = sortOrder.IndexOf(b.section);
// this is up here so -1 == -1 occurs first
if (ai == bi)
return 0;
if (ai == -1)
return -1;
if (bi == -1)
return 1;
return ai.CompareTo(bi);
});
entryList.Sort((a, b) => DepartmentUIComparer.Instance.Compare(a.section, b.section));
foreach (var item in entryList)
{

View File

@@ -4,24 +4,25 @@ using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Prototypes;
using System.Numerics;
using Content.Shared.Roles;
namespace Content.Client.CrewManifest.UI;
public sealed class CrewManifestSection : BoxContainer
{
public CrewManifestSection(IPrototypeManager prototypeManager, SpriteSystem spriteSystem, string sectionTitle,
public CrewManifestSection(
IPrototypeManager prototypeManager,
SpriteSystem spriteSystem,
DepartmentPrototype section,
List<CrewManifestEntry> entries)
{
Orientation = LayoutOrientation.Vertical;
HorizontalExpand = true;
if (Loc.TryGetString($"department-{sectionTitle}", out var localizedDepart))
sectionTitle = localizedDepart;
AddChild(new Label()
{
StyleClasses = { "LabelBig" },
Text = Loc.GetString(sectionTitle)
Text = Loc.GetString($"department-{section.ID}")
});
var gridContainer = new GridContainer()
@@ -55,8 +56,9 @@ public sealed class CrewManifestSection : BoxContainer
var icon = new TextureRect()
{
TextureScale = new Vector2(2, 2),
Stretch = TextureRect.StretchMode.KeepCentered,
VerticalAlignment = VAlignment.Center,
Texture = spriteSystem.Frame0(jobIcon.Icon),
Margin = new Thickness(0, 0, 4, 0)
};
titleContainer.AddChild(icon);

View File

@@ -30,20 +30,20 @@ public sealed class CriminalRecordsConsoleBoundUserInterface : BoundUserInterfac
var comp = EntMan.GetComponent<CriminalRecordsConsoleComponent>(Owner);
_window = new(Owner, comp.MaxStringLength, _playerManager, _proto, _random, _accessReader);
_window = new CriminalRecordsConsoleWindow(Owner, comp.MaxStringLength, _playerManager, _proto, _random, _accessReader);
_window.OnKeySelected += key =>
SendMessage(new SelectStationRecord(key));
_window.OnFiltersChanged += (type, filterValue) =>
SendMessage(new SetStationRecordFilter(type, filterValue));
_window.OnStatusSelected += status =>
SendMessage(new CriminalRecordChangeStatus(status, null));
_window.OnDialogConfirmed += (status, reason) => // WD EDIT
SendMessage(new CriminalRecordChangeStatus(status, reason)); // WD EDIT
_window.OnDialogConfirmed += (status, reason) =>
SendMessage(new CriminalRecordChangeStatus(status, reason));
_window.OnHistoryUpdated += UpdateHistory;
_window.OnHistoryClosed += () => _historyWindow?.Close();
_window.OnClose += Close;
_historyWindow = new(comp.MaxStringLength);
_historyWindow = new CrimeHistoryWindow(comp.MaxStringLength);
_historyWindow.OnAddHistory += line => SendMessage(new CriminalRecordAddHistory(line));
_historyWindow.OnDeleteHistory += index => SendMessage(new CriminalRecordDeleteHistory(index));

View File

@@ -219,16 +219,16 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
private void SetStatus(SecurityStatus status)
{
if (status is SecurityStatus.Wanted or SecurityStatus.Suspected) // WD EDIT
if (status == SecurityStatus.Wanted || status == SecurityStatus.Suspected)
{
GetWantedReason(status); // WD EDIT
GetReason(status);
return;
}
OnStatusSelected?.Invoke(status);
}
private void GetWantedReason(SecurityStatus status = SecurityStatus.Wanted) // WD EDIT
private void GetReason(SecurityStatus status)
{
if (_reasonDialog != null)
{
@@ -237,7 +237,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
}
var field = "reason";
var title = Loc.GetString($"criminal-records-status-{status.ToString().ToLower()}"); // WD EDIT
var title = Loc.GetString("criminal-records-status-" + status.ToString().ToLower());
var placeholders = _proto.Index<DatasetPrototype>(ReasonPlaceholders);
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders.Values))); // just funny it doesn't actually get used
var prompt = Loc.GetString("criminal-records-console-reason");
@@ -251,7 +251,7 @@ public sealed partial class CriminalRecordsConsoleWindow : FancyWindow
if (reason.Length < 1 || reason.Length > _maxLength)
return;
OnDialogConfirmed?.Invoke(status, reason); // WD EDIT
OnDialogConfirmed?.Invoke(status, reason);
};
_reasonDialog.OnClose += () => { _reasonDialog = null; };

View File

@@ -50,16 +50,8 @@ namespace Content.Client.Decals
protected override void OnDecalRemoved(EntityUid gridId, uint decalId, DecalGridComponent component, Vector2i indices, DecalChunk chunk)
{
base.OnDecalRemoved(gridId, decalId, component, indices, chunk);
if (!component.DecalZIndexIndex.Remove(decalId, out var zIndex))
return;
if (!component.DecalRenderIndex.TryGetValue(zIndex, out var renderIndex))
return;
renderIndex.Remove(decalId);
if (renderIndex.Count == 0)
component.DecalRenderIndex.Remove(zIndex);
DebugTools.Assert(chunk.Decals.ContainsKey(decalId));
chunk.Decals.Remove(decalId);
}
private void OnHandleState(EntityUid gridUid, DecalGridComponent gridComp, ref ComponentHandleState args)
@@ -133,8 +125,6 @@ namespace Content.Client.Decals
private void UpdateChunks(EntityUid gridId, DecalGridComponent gridComp, Dictionary<Vector2i, DecalChunk> updatedGridChunks)
{
var chunkCollection = gridComp.ChunkCollection.ChunkCollection;
var renderIndex = gridComp.DecalRenderIndex;
var zIndexIndex = gridComp.DecalZIndexIndex;
// Update any existing data / remove decals we didn't receive data for.
foreach (var (indices, newChunkData) in updatedGridChunks)
@@ -155,11 +145,6 @@ namespace Content.Client.Decals
foreach (var (uid, decal) in newChunkData.Decals)
{
if (zIndexIndex.TryGetValue(uid, out var zIndex))
renderIndex[zIndex].Remove(uid);
renderIndex.GetOrNew(decal.ZIndex)[uid] = decal;
zIndexIndex[uid] = decal.ZIndex;
gridComp.DecalIndex[uid] = indices;
}
}

View File

@@ -1,39 +1,31 @@
using Content.Shared.Decals;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Map.Enumerators;
using Robust.Shared.Prototypes;
namespace Content.Client.Decals.Overlays
{
public sealed class DecalOverlay : GridOverlay
public sealed class DecalOverlay(
SpriteSystem sprites,
IEntityManager entManager,
IPrototypeManager prototypeManager)
: GridOverlay
{
private readonly SpriteSystem _sprites;
private readonly IEntityManager _entManager;
private readonly IPrototypeManager _prototypeManager;
private readonly Dictionary<string, (Texture Texture, bool SnapCardinals)> _cachedTextures = new(64);
public DecalOverlay(
SpriteSystem sprites,
IEntityManager entManager,
IPrototypeManager prototypeManager)
{
_sprites = sprites;
_entManager = entManager;
_prototypeManager = prototypeManager;
}
private readonly List<(uint Id, Decal Decal)> _decals = [];
protected override void Draw(in OverlayDrawArgs args)
{
if (args.MapId == MapId.Nullspace)
return;
var grid = Grid;
var owner = Grid.Owner;
if (!_entManager.TryGetComponent(grid, out DecalGridComponent? decalGrid) ||
!_entManager.TryGetComponent(grid, out TransformComponent? xform))
if (!entManager.TryGetComponent(owner, out DecalGridComponent? decalGrid) ||
!entManager.TryGetComponent(owner, out TransformComponent? xform))
{
return;
}
@@ -43,49 +35,71 @@ namespace Content.Client.Decals.Overlays
// Shouldn't need to clear cached textures unless the prototypes get reloaded.
var handle = args.WorldHandle;
var xformSystem = _entManager.System<TransformSystem>();
var xformSystem = entManager.System<TransformSystem>();
var eyeAngle = args.Viewport.Eye?.Rotation ?? Angle.Zero;
var zIndexDictionary = decalGrid.DecalRenderIndex;
var gridAABB = xformSystem.GetInvWorldMatrix(xform).TransformBox(args.WorldBounds.Enlarged(1f));
var chunkEnumerator = new ChunkIndicesEnumerator(gridAABB, SharedDecalSystem.ChunkSize);
_decals.Clear();
if (zIndexDictionary.Count == 0)
while (chunkEnumerator.MoveNext(out var index))
{
if (!decalGrid.ChunkCollection.ChunkCollection.TryGetValue(index.Value, out var chunk))
continue;
foreach (var (id, decal) in chunk.Decals)
{
if (!gridAABB.Contains(decal.Coordinates))
continue;
_decals.Add((id, decal));
}
}
if (_decals.Count == 0)
return;
var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform);
_decals.Sort((x, y) =>
{
var zComp = x.Decal.ZIndex.CompareTo(y.Decal.ZIndex);
if (zComp != 0)
return zComp;
return x.Id.CompareTo(y.Id);
});
var (_, worldRot, worldMatrix) = xformSystem.GetWorldPositionRotationMatrix(xform);
handle.SetTransform(worldMatrix);
foreach (var decals in zIndexDictionary.Values)
foreach (var (_, decal) in _decals)
{
foreach (var decal in decals.Values)
if (!_cachedTextures.TryGetValue(decal.Id, out var cache))
{
if (!_cachedTextures.TryGetValue(decal.Id, out var cache))
// Nothing to cache someone messed up
if (!prototypeManager.TryIndex<DecalPrototype>(decal.Id, out var decalProto))
{
// Nothing to cache someone messed up
if (!_prototypeManager.TryIndex<DecalPrototype>(decal.Id, out var decalProto))
{
continue;
}
cache = (_sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals);
_cachedTextures[decal.Id] = cache;
continue;
}
var cardinal = Angle.Zero;
if (cache.SnapCardinals)
{
var worldAngle = eyeAngle + worldRot;
cardinal = worldAngle.GetCardinalDir().ToAngle();
}
var angle = decal.Angle - cardinal;
if (angle.Equals(Angle.Zero))
handle.DrawTexture(cache.Texture, decal.Coordinates, decal.Color);
else
handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color);
cache = (sprites.Frame0(decalProto.Sprite), decalProto.SnapCardinals);
_cachedTextures[decal.Id] = cache;
}
var cardinal = Angle.Zero;
if (cache.SnapCardinals)
{
var worldAngle = eyeAngle + worldRot;
cardinal = worldAngle.GetCardinalDir().ToAngle();
}
var angle = decal.Angle - cardinal;
if (angle.Equals(Angle.Zero))
handle.DrawTexture(cache.Texture, decal.Coordinates, decal.Color);
else
handle.DrawTexture(cache.Texture, decal.Coordinates, angle, decal.Color);
}
handle.SetTransform(Matrix3.Identity);

View File

@@ -1,9 +1,9 @@
using System.Numerics;
using Content.Shared.DoAfter;
using Content.Client.UserInterface.Systems;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Graphics;
using Robust.Client.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
@@ -18,6 +18,7 @@ public sealed class DoAfterOverlay : Overlay
private readonly IPlayerManager _player;
private readonly SharedTransformSystem _transform;
private readonly MetaDataSystem _meta;
private readonly ProgressColorSystem _progressColor;
private readonly Texture _barTexture;
@@ -39,7 +40,7 @@ public sealed class DoAfterOverlay : Overlay
_player = player;
_transform = _entManager.EntitySysManager.GetEntitySystem<SharedTransformSystem>();
_meta = _entManager.EntitySysManager.GetEntitySystem<MetaDataSystem>();
_progressColor = _entManager.System<ProgressColorSystem>();
var sprite = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Misc/progress_bar.rsi"), "icon");
_barTexture = _entManager.EntitySysManager.GetEntitySystem<SpriteSystem>().Frame0(sprite);
}
@@ -124,7 +125,7 @@ public sealed class DoAfterOverlay : Overlay
elapsedRatio = (float) Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds);
var cancelElapsed = (time - doAfter.CancelledTime.Value).TotalSeconds;
var flash = Math.Floor(cancelElapsed / FlashTime) % 2 == 0;
color = new Color(1f, 0f, 0f, flash ? alpha : 0f);
color = GetProgressColor(0, flash ? alpha : 0);
}
else
{
@@ -147,15 +148,8 @@ public sealed class DoAfterOverlay : Overlay
handle.SetTransform(Matrix3.Identity);
}
public static Color GetProgressColor(float progress, float alpha = 1f)
public Color GetProgressColor(float progress, float alpha = 1f)
{
if (progress >= 1.0f)
{
return new Color(0f, 1f, 0f, alpha);
}
// lerp
var hue = (5f / 18f) * progress;
return Color.FromHsv((hue, 1f, 0.75f, alpha));
return _progressColor.GetProgressColor(progress).WithAlpha(alpha);
}
}

View File

@@ -2,7 +2,6 @@ using Content.Client.Wires.Visualizers;
using Content.Shared.Doors;
using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Content.Shared.Prying.Components;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
@@ -17,13 +16,6 @@ public sealed class AirlockSystem : SharedAirlockSystem
base.Initialize();
SubscribeLocalEvent<AirlockComponent, ComponentStartup>(OnComponentStartup);
SubscribeLocalEvent<AirlockComponent, AppearanceChangeEvent>(OnAppearanceChange);
SubscribeLocalEvent<AirlockComponent, BeforePryEvent>(OnAirlockPryAttempt);
}
private void OnAirlockPryAttempt(EntityUid uid, AirlockComponent component, ref BeforePryEvent args)
{
// TODO: Temporary until airlocks predicted.
args.Cancelled = true;
}
protected override void OnBeforeDoorClosed(EntityUid uid, AirlockComponent airlock, BeforeDoorClosedEvent args)
@@ -141,5 +133,17 @@ public sealed class AirlockSystem : SharedAirlockSystem
&& !boltedVisible
);
}
switch (state)
{
case DoorState.Open:
args.Sprite.LayerSetState(DoorVisualLayers.BaseUnlit, comp.ClosingSpriteState);
args.Sprite.LayerSetAnimationTime(DoorVisualLayers.BaseUnlit, 0);
break;
case DoorState.Closed:
args.Sprite.LayerSetState(DoorVisualLayers.BaseUnlit, comp.OpeningSpriteState);
args.Sprite.LayerSetAnimationTime(DoorVisualLayers.BaseUnlit, 0);
break;
}
}
}

View File

@@ -1,12 +0,0 @@
using Content.Client.Wires.Visualizers;
using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
namespace Content.Client.Doors;
public sealed class DoorBoltSystem : SharedDoorBoltSystem
{
// Instantiate sub-class on client for prediction.
}

View File

@@ -3,8 +3,6 @@ using Content.Shared.Doors.Systems;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.ResourceManagement;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Robust.Shared.Timing;
@@ -73,7 +71,7 @@ public sealed class DoorSystem : SharedDoorSystem
private void OnAppearanceChange(EntityUid uid, DoorComponent comp, ref AppearanceChangeEvent args)
{
if (args.Sprite == null || !_gameTiming.IsFirstTimePredicted)
if (args.Sprite == null)
return;
if(!AppearanceSystem.TryGetData<DoorState>(uid, DoorVisuals.State, out var state, args.Component))
@@ -83,9 +81,9 @@ public sealed class DoorSystem : SharedDoorSystem
{
if (!_resourceCache.TryGetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / baseRsi, out var res))
{
Logger.Error("Unable to load RSI '{0}'. Trace:\n{1}", baseRsi, Environment.StackTrace);
Log.Error("Unable to load RSI '{0}'. Trace:\n{1}", baseRsi, Environment.StackTrace);
}
foreach (ISpriteLayer layer in args.Sprite.AllLayers)
foreach (var layer in args.Sprite.AllLayers)
{
layer.Rsi = res?.RSI;
}
@@ -113,31 +111,24 @@ public sealed class DoorSystem : SharedDoorSystem
break;
case DoorState.Opening:
if (animPlayer != null && comp.OpeningAnimationTime != 0.0)
_animationSystem.Play(uid, animPlayer, (Animation)comp.OpeningAnimation, DoorComponent.AnimationKey);
_animationSystem.Play((uid, animPlayer), (Animation)comp.OpeningAnimation, DoorComponent.AnimationKey);
break;
case DoorState.Closing:
if (animPlayer != null && comp.ClosingAnimationTime != 0.0 && comp.CurrentlyCrushing.Count == 0)
_animationSystem.Play(uid, animPlayer, (Animation)comp.ClosingAnimation, DoorComponent.AnimationKey);
_animationSystem.Play((uid, animPlayer), (Animation)comp.ClosingAnimation, DoorComponent.AnimationKey);
break;
case DoorState.Denying:
if (animPlayer != null && comp.DenyingAnimation != default)
_animationSystem.Play(uid, animPlayer, (Animation)comp.DenyingAnimation, DoorComponent.AnimationKey);
if (animPlayer != null)
_animationSystem.Play((uid, animPlayer), (Animation)comp.DenyingAnimation, DoorComponent.AnimationKey);
break;
case DoorState.Welded:
break;
case DoorState.Emagging:
if (animPlayer != null && comp.EmaggingAnimation != default)
_animationSystem.Play(uid, animPlayer, (Animation)comp.EmaggingAnimation, DoorComponent.AnimationKey);
if (animPlayer != null)
_animationSystem.Play((uid, animPlayer), (Animation)comp.EmaggingAnimation, DoorComponent.AnimationKey);
break;
default:
throw new ArgumentOutOfRangeException($"Invalid door visual state {state}");
}
}
// TODO AUDIO PREDICT see comments in server-side PlaySound()
protected override void PlaySound(EntityUid uid, SoundSpecifier soundSpecifier, AudioParams audioParams, EntityUid? predictingPlayer, bool predicted)
{
if (GameTiming.InPrediction && GameTiming.IsFirstTimePredicted)
Audio.PlayEntity(soundSpecifier, Filter.Local(), uid, false, audioParams);
}
}

View File

@@ -38,6 +38,7 @@ public sealed class DrugOverlaySystem : EntitySystem
private void OnPlayerDetached(EntityUid uid, SeeingRainbowsComponent component, LocalPlayerDetachedEvent args)
{
_overlay.Intoxication = 0;
_overlay.TimeTicker = 0;
_overlayMan.RemoveOverlay(_overlay);
}
@@ -52,6 +53,7 @@ public sealed class DrugOverlaySystem : EntitySystem
if (_player.LocalEntity == uid)
{
_overlay.Intoxication = 0;
_overlay.TimeTicker = 0;
_overlayMan.RemoveOverlay(_overlay);
}
}

View File

@@ -20,6 +20,7 @@ public sealed class RainbowOverlay : Overlay
private readonly ShaderInstance _rainbowShader;
public float Intoxication = 0.0f;
public float TimeTicker = 0.0f;
private const float VisualThreshold = 10.0f;
private const float PowerDivisor = 250.0f;
@@ -48,7 +49,17 @@ public sealed class RainbowOverlay : Overlay
return;
var timeLeft = (float) (time.Value.Item2 - time.Value.Item1).TotalSeconds;
Intoxication += (timeLeft - Intoxication) * args.DeltaSeconds / 16f;
TimeTicker += args.DeltaSeconds;
if (timeLeft - TimeTicker > timeLeft / 16f)
{
Intoxication += (timeLeft - Intoxication) * args.DeltaSeconds / 16f;
}
else
{
Intoxication -= Intoxication/(timeLeft - TimeTicker) * args.DeltaSeconds;
}
}
protected override bool BeforeDraw(in OverlayDrawArgs args)

View File

@@ -28,7 +28,7 @@ using Content.Client.Singularity;
using Content.Client.Stylesheets;
using Content.Client.Viewport;
using Content.Client.Voting;
using Content.Shared.Ame;
using Content.Shared.Ame.Components;
using Content.Shared.Gravity;
using Content.Shared.Localizations;
using Robust.Client;
@@ -77,6 +77,7 @@ namespace Content.Client.Entry
[Dependency] private readonly IResourceManager _resourceManager = default!;
[Dependency] private readonly IReplayLoadManager _replayLoad = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly ContentReplayPlaybackManager _replayMan = default!;
//WD-EDIT
[Dependency] private readonly SponsorsManager _sponsorsManager = default!;
@@ -116,12 +117,10 @@ namespace Content.Client.Entry
_prototypeManager.RegisterIgnore("seed"); // Seeds prototypes are server-only.
_prototypeManager.RegisterIgnore("objective");
_prototypeManager.RegisterIgnore("holiday");
_prototypeManager.RegisterIgnore("aiFaction");
_prototypeManager.RegisterIgnore("htnCompound");
_prototypeManager.RegisterIgnore("htnPrimitive");
_prototypeManager.RegisterIgnore("gameMap");
_prototypeManager.RegisterIgnore("gameMapPool");
_prototypeManager.RegisterIgnore("npcFaction");
_prototypeManager.RegisterIgnore("lobbyBackground");
_prototypeManager.RegisterIgnore("advertisementsPack");
_prototypeManager.RegisterIgnore("gamePreset");
@@ -227,6 +226,7 @@ namespace Content.Client.Entry
_resourceManager,
ReplayConstants.ReplayZipFolder.ToRootedPath());
_replayMan.LastLoad = (null, ReplayConstants.ReplayZipFolder.ToRootedPath());
_replayLoad.LoadAndStartReplay(reader);
}
else if (_gameController.LaunchState.FromLauncher)

View File

@@ -1,16 +1,11 @@
using Content.Client.Gameplay;
using Content.Client.Lobby;
using Content.Client.RoundEnd;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Content.Shared.GameWindow;
using JetBrains.Annotations;
using Robust.Client.Graphics;
using Robust.Client.State;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
using Robust.Shared.Utility;
namespace Content.Client.GameTicking.Managers
@@ -32,7 +27,6 @@ namespace Content.Client.GameTicking.Managers
[ViewVariables] public bool AreWeReady { get; private set; }
[ViewVariables] public bool IsGameStarted { get; private set; }
[ViewVariables] public string? LobbySong { get; private set; }
[ViewVariables] public string? RestartSound { get; private set; }
[ViewVariables] public string? LobbyBackground { get; private set; }
[ViewVariables] public bool DisallowedLateJoin { get; private set; }
@@ -45,7 +39,6 @@ namespace Content.Client.GameTicking.Managers
public event Action? InfoBlobUpdated;
public event Action? LobbyStatusUpdated;
public event Action? LobbySongUpdated;
public event Action? LobbyLateJoinStatusUpdated;
public event Action<IReadOnlyDictionary<NetEntity, Dictionary<string, uint?>>>? LobbyJobsAvailableUpdated;
@@ -70,16 +63,6 @@ namespace Content.Client.GameTicking.Managers
_initialized = true;
}
public void SetLobbySong(string? song, bool forceUpdate = false)
{
var updated = song != LobbySong;
LobbySong = song;
if (updated || forceUpdate)
LobbySongUpdated?.Invoke();
}
private void LateJoinStatus(TickerLateJoinStatusEvent message)
{
DisallowedLateJoin = message.Disallowed;
@@ -120,7 +103,6 @@ namespace Content.Client.GameTicking.Managers
RoundStartTimeSpan = message.RoundStartTimeSpan;
IsGameStarted = message.IsRoundStarted;
AreWeReady = message.YouAreReady;
SetLobbySong(message.LobbySong);
LobbyBackground = message.LobbyBackground;
Paused = message.Paused;
@@ -148,7 +130,6 @@ namespace Content.Client.GameTicking.Managers
private void RoundEnd(RoundEndMessageEvent message)
{
// Force an update in the event of this song being the same as the last.
SetLobbySong(message.LobbySong, true);
RestartSound = message.RestartSound;
// Don't open duplicate windows (mainly for replays).

View File

@@ -104,7 +104,7 @@ namespace Content.Client.Gameplay
public IEnumerable<EntityUid> GetClickableEntities(EntityCoordinates coordinates)
{
return GetClickableEntities(coordinates.ToMap(_entityManager));
return GetClickableEntities(coordinates.ToMap(_entityManager, _entitySystemManager.GetEntitySystem<SharedTransformSystem>()));
}
public IEnumerable<EntityUid> GetClickableEntities(MapCoordinates coordinates)

View File

@@ -11,7 +11,7 @@
<RichTextLabel Name="ReagentName" HorizontalAlignment="Center"/>
</PanelContainer>
<BoxContainer Name="RecipesContainer" HorizontalExpand="True">
<Collapsible Orientation="Vertical" HorizontalExpand="True">
<Collapsible HorizontalExpand="True">
<CollapsibleHeading Title="{Loc 'guidebook-reagent-recipes-header'}"/>
<CollapsibleBody>
<GridContainer Name="RecipesDescriptionContainer"
@@ -24,7 +24,7 @@
</Collapsible>
</BoxContainer>
<BoxContainer Name="SourcesContainer" HorizontalExpand="True">
<Collapsible Orientation="Vertical" HorizontalExpand="True">
<Collapsible HorizontalExpand="True">
<CollapsibleHeading Title="{Loc 'guidebook-reagent-sources-header'}"/>
<CollapsibleBody>
<GridContainer Name="SourcesDescriptionContainer"
@@ -37,7 +37,7 @@
</Collapsible>
</BoxContainer>
<BoxContainer Name="EffectsContainer" HorizontalExpand="True">
<Collapsible Orientation="Vertical">
<Collapsible>
<CollapsibleHeading Title="{Loc 'guidebook-reagent-effects-header'}"/>
<CollapsibleBody>
<BoxContainer Name="EffectsDescriptionContainer"

View File

@@ -1,26 +1,48 @@
<!-- WD start -->
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
Title="{Loc 'gravity-generator-window-title'}"
MinSize="260 300">
<BoxContainer Margin="4 0" Orientation="Vertical">
<controls:StripeBack>
<Label Name="EntityNameLabel" Text="N/A" StyleClasses="LabelBig" Align="Center"/>
</controls:StripeBack>
<GridContainer Columns="2">
<Label Text="{Loc 'health-analyzer-window-entity-current-alive-status-text'}" StyleClasses="StatusFieldTitle"/>
<Label Name="AliveStatusLabel" Text="{Loc 'health-analyzer-window-no-data'}" Margin="4 0 0 0"/>
<Label Text="{Loc 'health-analyzer-window-entity-temperature-text'}" StyleClasses="StatusFieldTitle"/>
<Label Name="TemperatureLabel" Text="{Loc 'health-analyzer-window-no-data'}" Margin="4 0 0 0"/>
<Label Text="{Loc 'health-analyzer-window-entity-blood-level-text'}" StyleClasses="StatusFieldTitle"/>
<Label Name="BloodLevelLabel" Text="{Loc 'health-analyzer-window-no-data'}" Margin="4 0 0 0"/>
<Label Text="{Loc 'health-analyzer-window-entity-damage-total-text'}" StyleClasses="StatusFieldTitle"/>
<Label Name="TotalDamageLabel" Text="{Loc 'health-analyzer-window-no-data'}" Margin="4 0 0 0"/>
</GridContainer>
<customControls:HSeparator StyleClasses="LowDivider" Margin="0 0 0 10"/>
<!-- Filled by code -->
<GridContainer Name="DamageGroupsContainer" Columns="2"/>
</BoxContainer>
<controls:FancyWindow
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
SetSize="250 100">
<ScrollContainer
VerticalExpand="True">
<BoxContainer
Name="RootContainer"
Orientation="Vertical">
<Label
Name="NoPatientDataText"
Text="{Loc health-analyzer-window-no-patient-data-text}" />
<BoxContainer
Name="PatientDataContainer"
Orientation="Vertical"
Margin="0 0 5 10">
<BoxContainer Name="ScanModePanel" HorizontalExpand="True" Visible="False" Margin="0 5 0 0">
<Label
Name="ScanMode"
Align="Left"
Text="{Loc health-analyzer-window-scan-mode-text}"/>
<Label
Name="ScanModeText"
Align="Right"
HorizontalExpand="True"/>
</BoxContainer>
<Label
Name="PatientName"/>
<Label
Name="Temperature"
Margin="0 5 0 0"/>
<Label
Name="BloodLevel"
Margin="0 5 0 0"/>
<Label
Name="Bleeding"
Margin="0 5 0 0"/>
<Label
Name="patientDamageAmount"
Margin="0 15 0 0"/>
</BoxContainer>
<BoxContainer
Name="GroupsContainer"
Orientation="Vertical">
</BoxContainer>
</BoxContainer>
</ScrollContainer>
</controls:FancyWindow>
<!-- WD end -->

View File

@@ -1,81 +1,225 @@
using Content.Client._White.Medical.BodyScanner;
using System.Linq;
using System.Numerics;
using Content.Client.UserInterface.Controls;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.FixedPoint;
using Content.Shared.IdentityManagement;
using Content.Shared.MedicalScanner;
using Content.Shared.Mobs.Components;
using Content.Shared.Nutrition.Components;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.HealthAnalyzer.UI
{
// WD start
[GenerateTypedNameReferences]
public sealed partial class HealthAnalyzerWindow : FancyWindow
{
private readonly IEntityManager _entityManager;
private readonly SpriteSystem _spriteSystem;
private readonly IPrototypeManager _prototypes;
private readonly IResourceCache _cache;
private const int AnalyzerHeight = 430;
private const int AnalyzerWidth = 300;
public HealthAnalyzerWindow()
{
RobustXamlLoader.Load(this);
var dependencies = IoCManager.Instance!;
_entityManager = dependencies.Resolve<IEntityManager>();
_spriteSystem = _entityManager.System<SpriteSystem>();
_prototypes = dependencies.Resolve<IPrototypeManager>();
_cache = dependencies.Resolve<IResourceCache>();
}
public void Populate(HealthAnalyzerScannedUserMessage msg)
{
var entities = IoCManager.Resolve<IEntityManager>();
GroupsContainer.RemoveAllChildren();
if (msg.TargetEntity == null || !entities.TryGetComponent(entities.GetEntity(msg.TargetEntity),
out DamageableComponent? damageable))
var target = _entityManager.GetEntity(msg.TargetEntity);
if (target == null
|| !_entityManager.TryGetComponent<DamageableComponent>(target, out var damageable))
{
NoPatientDataText.Visible = true;
return;
}
EntityNameLabel.Text = Identity.Name(entities.GetEntity(msg.TargetEntity.Value), entities);
TemperatureLabel.Text = float.IsNaN(msg.Temperature)
? Loc.GetString("health-analyzer-window-no-data")
: $"{msg.Temperature - 273f:F1} \u00B0C";
NoPatientDataText.Visible = false;
BloodLevelLabel.Text = float.IsNaN(msg.BloodLevel)
? Loc.GetString("health-analyzer-window-no-data")
: $"{msg.BloodLevel * 100:F1} %";
TotalDamageLabel.Text = damageable.TotalDamage.ToString();
entities.TryGetComponent<MobStateComponent>(entities.GetEntity(msg.TargetEntity),
out var mobStateComponent);
AliveStatusLabel.Text = mobStateComponent?.CurrentState switch
string entityName = Loc.GetString("health-analyzer-window-entity-unknown-text");
if (_entityManager.HasComponent<MetaDataComponent>(target.Value))
{
Shared.Mobs.MobState.Alive => Loc.GetString(
"health-analyzer-window-entity-current-alive-status-alive-text"),
Shared.Mobs.MobState.Critical => Loc.GetString(
"health-analyzer-window-entity-current-alive-status-critical-text"),
Shared.Mobs.MobState.Dead => Loc.GetString(
"health-analyzer-window-entity-current-alive-status-dead-text"),
_ => Loc.GetString("health-analyzer-window-no-data"),
};
entityName = Identity.Name(target.Value, _entityManager);
}
IReadOnlyDictionary<string, FixedPoint2> damagePerGroup = damageable.DamagePerGroup;
if (msg.ScanMode.HasValue)
{
ScanModePanel.Visible = true;
ScanModeText.Text = Loc.GetString(msg.ScanMode.Value ? "health-analyzer-window-scan-mode-active" : "health-analyzer-window-scan-mode-inactive");
ScanModeText.FontColorOverride = msg.ScanMode.Value ? Color.Green : Color.Red;
}
else
{
ScanModePanel.Visible = false;
}
PatientName.Text = Loc.GetString(
"health-analyzer-window-entity-health-text",
("entityName", entityName)
);
Temperature.Text = Loc.GetString("health-analyzer-window-entity-temperature-text",
("temperature", float.IsNaN(msg.Temperature) ? "N/A" : $"{msg.Temperature - 273f:F1} °C ({msg.Temperature:F1} °K)")
);
BloodLevel.Text = Loc.GetString("health-analyzer-window-entity-blood-level-text",
("bloodLevel", float.IsNaN(msg.BloodLevel) ? "N/A" : $"{msg.BloodLevel * 100:F1} %")
);
if (msg.Bleeding == true)
{
Bleeding.Text = Loc.GetString("health-analyzer-window-entity-bleeding-text");
Bleeding.FontColorOverride = Color.Red;
}
else
{
Bleeding.Text = string.Empty; // Clear the text
}
patientDamageAmount.Text = Loc.GetString(
"health-analyzer-window-entity-damage-total-text",
("amount", damageable.TotalDamage)
);
var damageSortedGroups =
damageable.DamagePerGroup.OrderBy(damage => damage.Value)
.ToDictionary(x => x.Key, x => x.Value);
IReadOnlyDictionary<string, FixedPoint2> damagePerType = damageable.Damage.DamageDict;
DamageGroupsContainer.RemoveAllChildren();
DrawDiagnosticGroups(damageSortedGroups, damagePerType);
if (_entityManager.TryGetComponent(target, out HungerComponent? hunger)
&& hunger.StarvationDamage != null
&& hunger.CurrentThreshold <= HungerThreshold.Starving)
{
var box = new Control { Margin = new Thickness(0, 0, 0, 15) };
box.AddChild(CreateDiagnosticGroupTitle(
Loc.GetString("health-analyzer-window-malnutrition"),
"malnutrition"));
GroupsContainer.AddChild(box);
}
SetHeight = AnalyzerHeight;
SetWidth = AnalyzerWidth;
}
private void DrawDiagnosticGroups(
Dictionary<string, FixedPoint2> groups, IReadOnlyDictionary<string, FixedPoint2> damageDict)
{
HashSet<string> shownTypes = new();
// Show the total damage and type breakdown for each damage group.
foreach (var (damageGroupId, damageAmount) in damagePerGroup)
foreach (var (damageGroupId, damageAmount) in groups.Reverse())
{
if (damageAmount == 0)
{
continue;
var groupTitleText = $"{Loc.GetString(
"health-analyzer-window-damage-group-text",
("damageGroup", Loc.GetString("health-analyzer-window-damage-group-" + damageGroupId)),
("amount", damageAmount)
)}";
var groupContainer = new BoxContainer
{
Margin = new Thickness(0, 0, 0, 15),
Align = BoxContainer.AlignMode.Begin,
Orientation = BoxContainer.LayoutOrientation.Vertical,
};
groupContainer.AddChild(CreateDiagnosticGroupTitle(groupTitleText, damageGroupId));
GroupsContainer.AddChild(groupContainer);
// Show the damage for each type in that group.
var group = _prototypes.Index<DamageGroupPrototype>(damageGroupId);
foreach (var type in group.DamageTypes)
{
if (damageDict.TryGetValue(type, out var typeAmount) && typeAmount > 0)
{
// If damage types are allowed to belong to more than one damage group,
// they may appear twice here. Mark them as duplicate.
if (shownTypes.Contains(type))
continue;
shownTypes.Add(type);
var damageString = Loc.GetString(
"health-analyzer-window-damage-type-text",
("damageType", Loc.GetString("health-analyzer-window-damage-type-" + type)),
("amount", typeAmount)
);
groupContainer.AddChild(CreateDiagnosticItemLabel(damageString.Insert(0, "- ")));
}
}
var damageGroupTitle = Loc.GetString("health-analyzer-window-damage-group-" + damageGroupId,
("amount", damageAmount));
DamageGroupsContainer.AddChild(new GroupDamageCardComponent(damageGroupTitle, damageGroupId,
damagePerType));
}
}
private Texture GetTexture(string texture)
{
var rsiPath = new ResPath("/Textures/Objects/Devices/health_analyzer.rsi");
var rsiSprite = new SpriteSpecifier.Rsi(rsiPath, texture);
var rsi = _cache.GetResource<RSIResource>(rsiSprite.RsiPath).RSI;
if (!rsi.TryGetState(rsiSprite.RsiState, out var state))
{
rsiSprite = new SpriteSpecifier.Rsi(rsiPath, "unknown");
}
return _spriteSystem.Frame0(rsiSprite);
}
private static Label CreateDiagnosticItemLabel(string text)
{
return new Label
{
Margin = new Thickness(2, 2),
Text = text,
};
}
private BoxContainer CreateDiagnosticGroupTitle(string text, string id)
{
var rootContainer = new BoxContainer
{
VerticalAlignment = VAlignment.Bottom,
Orientation = BoxContainer.LayoutOrientation.Horizontal
};
rootContainer.AddChild(new TextureRect
{
Margin = new Thickness(0, 3),
SetSize = new Vector2(30, 30),
Texture = GetTexture(id.ToLower())
});
rootContainer.AddChild(CreateDiagnosticItemLabel(text));
return rootContainer;
}
}
// WD end
}

View File

@@ -7,7 +7,7 @@
<CheckBox Name="MarkingForced" Text="Force" Pressed="True" />
<CheckBox Name="MarkingIgnoreSpecies" Text="Ignore Species" Pressed="True" />
</BoxContainer>
<Collapsible Orientation="Vertical" HorizontalExpand="True">
<Collapsible HorizontalExpand="True">
<CollapsibleHeading Title="Base layers" />
<CollapsibleBody HorizontalExpand="True">
<BoxContainer Name="BaseLayersContainer" Orientation="Vertical" HorizontalExpand="True" />

View File

@@ -47,7 +47,7 @@ namespace Content.Client.IconSmoothing
var xform = Transform(uid);
if (xform.Anchored)
{
component.LastPosition = _mapManager.TryGetGrid(xform.GridUid, out var grid)
component.LastPosition = TryComp<MapGridComponent>(xform.GridUid, out var grid)
? (xform.GridUid.Value, grid.TileIndicesFor(xform.Coordinates))
: (null, new Vector2i(0, 0));
@@ -134,7 +134,7 @@ namespace Content.Client.IconSmoothing
Vector2i pos;
if (transform.Anchored && _mapManager.TryGetGrid(transform.GridUid, out var grid))
if (transform.Anchored && TryComp<MapGridComponent>(transform.GridUid, out var grid))
{
pos = grid.CoordinatesToTile(transform.Coordinates);
}
@@ -144,7 +144,7 @@ namespace Content.Client.IconSmoothing
if (comp.LastPosition is not (EntityUid gridId, Vector2i oldPos))
return;
if (!_mapManager.TryGetGrid(gridId, out grid))
if (!TryComp(gridId, out grid))
return;
pos = oldPos;
@@ -206,7 +206,7 @@ namespace Content.Client.IconSmoothing
{
var directions = DirectionFlag.None;
if (_mapManager.TryGetGrid(xform.GridUid, out grid))
if (TryComp(xform.GridUid, out grid))
{
var pos = grid.TileIndicesFor(xform.Coordinates);
@@ -231,7 +231,7 @@ namespace Content.Client.IconSmoothing
if (!spriteQuery.TryGetComponent(uid, out var sprite))
{
Logger.Error($"Encountered a icon-smoothing entity without a sprite: {ToPrettyString(uid)}");
Log.Error($"Encountered a icon-smoothing entity without a sprite: {ToPrettyString(uid)}");
RemCompDeferred(uid, smooth);
return;
}
@@ -240,9 +240,9 @@ namespace Content.Client.IconSmoothing
if (xform.Anchored)
{
if (!_mapManager.TryGetGrid(xform.GridUid, out grid))
if (!TryComp(xform.GridUid, out grid))
{
Logger.Error($"Failed to calculate IconSmoothComponent sprite in {uid} because grid {xform.GridUid} was missing.");
Log.Error($"Failed to calculate IconSmoothComponent sprite in {uid} because grid {xform.GridUid} was missing.");
return;
}
}

View File

@@ -12,13 +12,13 @@ public sealed class InfoSystem : EntitySystem
{
base.Initialize();
SubscribeNetworkEvent<RulesMessage>(OnRulesReceived);
Logger.DebugS("info", "Requested server info.");
Log.Debug("Requested server info.");
RaiseNetworkEvent(new RequestRulesMessage());
}
private void OnRulesReceived(RulesMessage message, EntitySessionEventArgs eventArgs)
{
Logger.DebugS("info", "Received server rules.");
Log.Debug("Received server rules.");
Rules = message;
_rules.UpdateRules();
}

View File

@@ -0,0 +1,7 @@
using Content.Shared.Labels.EntitySystems;
namespace Content.Client.Labels;
public sealed partial class LabelSystem : SharedLabelSystem
{
}

View File

@@ -1,3 +1,4 @@
using System.Linq;
using System.Numerics;
using Content.Client.CrewManifest;
using Content.Client.GameTicking.Managers;
@@ -159,8 +160,10 @@ namespace Content.Client.LateJoin
};
var firstCategory = true;
var departments = _prototypeManager.EnumeratePrototypes<DepartmentPrototype>().ToArray();
Array.Sort(departments, DepartmentUIComparer.Instance);
foreach (var department in _prototypeManager.EnumeratePrototypes<DepartmentPrototype>())
foreach (var department in departments)
{
var departmentName = Loc.GetString($"department-{department.ID}");
_jobCategories[id] = new Dictionary<string, BoxContainer>();
@@ -176,7 +179,7 @@ namespace Content.Client.LateJoin
jobsAvailable.Add(_prototypeManager.Index<JobPrototype>(jobId));
}
jobsAvailable.Sort((x, y) => -string.Compare(x.LocalizedName, y.LocalizedName, StringComparison.CurrentCultureIgnoreCase));
jobsAvailable.Sort(JobUIComparer.Instance);
// Do not display departments with no jobs available.
if (jobsAvailable.Count == 0)
@@ -231,7 +234,7 @@ namespace Content.Client.LateJoin
var icon = new TextureRect
{
TextureScale = new Vector2(2, 2),
Stretch = TextureRect.StretchMode.KeepCentered
VerticalAlignment = VAlignment.Center
};
var jobIcon = _prototypeManager.Index<StatusIconPrototype>(prototype.Icon);

View File

@@ -54,6 +54,7 @@ namespace Content.Client.Launcher
public event Action<Page>? PageChanged;
public event Action<string?>? ConnectFailReasonChanged;
public event Action<ClientConnectionState>? ConnectionStateChanged;
public event Action<NetConnectFailArgs>? ConnectFailed;
protected override void Startup()
{
@@ -85,6 +86,7 @@ namespace Content.Client.Launcher
}
ConnectFailReason = args.Reason;
CurrentPage = Page.ConnectFailed;
ConnectFailed?.Invoke(args);
}
private void OnConnectStateChanged(ClientConnectionState state)

View File

@@ -146,7 +146,7 @@ namespace Content.Client.Light
else
{
// admeme fuck-ups or bad yaml?
Logger.Warning($"RGB light attempted to use invalid sprite index {index} on entity {ToPrettyString(uid)}");
Log.Warning($"RGB light attempted to use invalid sprite index {index} on entity {ToPrettyString(uid)}");
rgb.Layers.Remove(index);
}
}

View File

@@ -0,0 +1,71 @@
<Control xmlns="https://spacestation14.io"
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
MouseFilter="Stop">
<PanelContainer StyleClasses="BackgroundOpenLeft"/>
<PanelContainer>
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BorderColor="#25252A" BorderThickness="0 0 0 3"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<Control Margin="0 0 1 0">
<PanelContainer StyleClasses="WindowHeadingBackground" />
<BoxContainer Margin="4 2 8 0" Orientation="Horizontal">
<Label Name="Title" Text="{Loc news-write-ui-new-article}"
HorizontalExpand="True" VAlign="Center" StyleClasses="FancyWindowTitle" />
</BoxContainer>
</Control>
<PanelContainer StyleClasses="LowDivider" Margin="0 0 1 0"/>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc news-write-ui-article-name-label}" Margin="17 10 0 9" VerticalAlignment="Center"/>
<LineEdit Name="TitleField" Margin="6 10 0 9" MinWidth="260" MinHeight="23" Access="Public"/>
<Control HorizontalExpand="True" />
<Label Name="RichTextInfoLabel" Text="?" MouseFilter="Pass" Margin="14 0" StyleClasses="LabelSecondaryColor"/>
</BoxContainer>
<Control Name="TextEditPanel" VerticalExpand="True" Margin="11 0 11 0">
<PanelContainer>
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BackgroundColor="#202023" BorderThickness="1" BorderColor="#3B3E56"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<TextEdit Name="ContentField" Margin="0 1" Access="Public"/>
</Control>
<Control Name="PreviewPanel" Visible="False" VerticalExpand="True" Margin="11 0 11 0">
<PanelContainer>
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BorderThickness="1" BorderColor="#3B3E56"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<ScrollContainer HScrollEnabled="True">
<RichTextLabel Name="PreviewLabel" VerticalAlignment="Top" Margin="9 3" MaxWidth="360"/>
</ScrollContainer>
</Control>
<BoxContainer Orientation="Horizontal" Margin="12 5 12 8">
<Control>
<Button Name="ButtonCancel" SetHeight="32" SetWidth="85"
StyleClasses="ButtonColorRed" Text="{Loc news-write-ui-cancel-text}"/>
</Control>
<Control HorizontalExpand="True"/>
<BoxContainer Orientation="Horizontal">
<Button Name="ButtonPreview" SetHeight="32" SetWidth="85"
StyleClasses="OpenRight" Text="{Loc news-write-ui-preview-text}"/>
<Button Name="ButtonPublish" SetHeight="32" SetWidth="85" Text="{Loc news-write-ui-publish-text}" Access="Public"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
<PanelContainer>
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BorderThickness="2 0 0 0" BorderColor="#1d1d22"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<PanelContainer HorizontalAlignment="Left" VerticalAlignment="Top" SetHeight="27" SetWidth="2">
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BorderColor="#2a2a2d" BorderThickness="0 0 0 2"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<PanelContainer HorizontalAlignment="Left" VerticalAlignment="Top" SetHeight="25" SetWidth="2">
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BackgroundColor="#1b1b1f"/>
</PanelContainer.PanelOverride>
</PanelContainer>
</Control>

View File

@@ -0,0 +1,115 @@
using Content.Client.Message;
using Content.Client.Stylesheets;
using Content.Shared.MassMedia.Systems;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
namespace Content.Client.MassMedia.Ui;
[GenerateTypedNameReferences]
public sealed partial class ArticleEditorPanel : Control
{
public event Action? PublishButtonPressed;
private bool _preview;
public ArticleEditorPanel()
{
RobustXamlLoader.Load(this);
ButtonPublish.StyleClasses.Add(StyleBase.ButtonOpenLeft);
ButtonPublish.StyleClasses.Add(StyleNano.StyleClassButtonColorGreen);
ContentField.GetChild(0).Margin = new Thickness(9, 3);
// Customize scrollbar width and margin. This is not possible in xaml
var scrollbar = ContentField.GetChild(1);
scrollbar.SetWidth = 6f;
scrollbar.Margin = new Thickness(9, 0, 2 , 0);
RichTextInfoLabel.TooltipSupplier = sender =>
{
var label = new RichTextLabel();
label.SetMarkup(Loc.GetString("news-write-ui-richtext-tooltip"));
var tooltip = new Tooltip();
tooltip.GetChild(0).Children.Clear();
tooltip.GetChild(0).Children.Add(label);
return tooltip;
};
ButtonPreview.OnPressed += OnPreview;
ButtonCancel.OnPressed += OnCancel;
ButtonPublish.OnPressed += OnPublish;
TitleField.OnTextChanged += args => OnTextChanged(args.Text.Length, args.Control, SharedNewsSystem.MaxTitleLength);
ContentField.OnTextChanged += args => OnTextChanged(Rope.CalcTotalLength(args.TextRope), args.Control, SharedNewsSystem.MaxContentLength);
}
private void OnTextChanged(long length, Control control, long maxLength)
{
if (length > maxLength)
{
control.ModulateSelfOverride = Color.Red;
control.ToolTip = Loc.GetString("news-writer-text-length-exceeded");
ButtonPublish.Disabled = true;
ButtonPreview.Disabled = true;
}
else
{
control.ModulateSelfOverride = null;
control.ToolTip = string.Empty;
ButtonPublish.Disabled = false;
ButtonPreview.Disabled = false;
}
}
private void OnPreview(BaseButton.ButtonEventArgs eventArgs)
{
_preview = !_preview;
TextEditPanel.Visible = !_preview;
PreviewPanel.Visible = _preview;
PreviewLabel.SetMarkup(Rope.Collapse(ContentField.TextRope));
}
private void OnCancel(BaseButton.ButtonEventArgs eventArgs)
{
Reset();
Visible = false;
}
private void OnPublish(BaseButton.ButtonEventArgs eventArgs)
{
PublishButtonPressed?.Invoke();
Reset();
Visible = false;
}
private void Reset()
{
_preview = false;
TextEditPanel.Visible = true;
PreviewPanel.Visible = false;
PreviewLabel.SetMarkup("");
TitleField.Text = "";
ContentField.TextRope = Rope.Leaf.Empty;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
ButtonPreview.OnPressed -= OnPreview;
ButtonCancel.OnPressed -= OnCancel;
ButtonPublish.OnPressed -= OnPublish;
}
}

View File

@@ -1,26 +0,0 @@
<Control xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="0 0 0 12">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
<PanelContainer HorizontalExpand="True" VerticalExpand="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#4c6530"/>
</PanelContainer.PanelOverride>
<Label Name="NameLabel" Margin="6 6 6 6" HorizontalAlignment="Center"/>
</PanelContainer>
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<PanelContainer HorizontalExpand="True" VerticalExpand="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#33333f"/>
</PanelContainer.PanelOverride>
<RichTextLabel Name="Author" HorizontalExpand="True" VerticalAlignment="Bottom" Margin="6 6 6 6"/>
<Button Name="Delete"
Text="{Loc 'news-write-ui-delete-text'}"
HorizontalAlignment="Right"
Margin="8 6 6 6"
Access="Public"/>
</PanelContainer>
</BoxContainer>
</BoxContainer>
</Control>

View File

@@ -1,27 +0,0 @@
using Content.Client.Message;
using Content.Shared.Research.Prototypes;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.MassMedia.Ui;
[GenerateTypedNameReferences]
public sealed partial class MiniArticleCardControl : Control
{
public Action? OnDeletePressed;
public int ArticleNum;
public MiniArticleCardControl(string name, string author)
{
RobustXamlLoader.Load(this);
NameLabel.Text = name;
Author.SetMarkup(author);
Delete.OnPressed += _ => OnDeletePressed?.Invoke();
}
}

View File

@@ -0,0 +1,29 @@
<Control xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Margin="0 0 0 8">
<PanelContainer StyleClasses="AngleRect" ModulateSelfOverride="#2b2b31"/>
<BoxContainer Orientation="Vertical" SetHeight="60">
<Control HorizontalExpand="True" SetHeight="27">
<PanelContainer>
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BorderColor="#3B3E56" BorderThickness="0 0 0 1"/>
</PanelContainer.PanelOverride>
</PanelContainer>
<Label Name="TitleLabel" Margin="12 0 6 0" HorizontalAlignment="Left"/>
</Control>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label FontColorOverride="#b1b1b2" StyleClasses="LabelSmall" Name="AuthorLabel" Margin="14 6 6 6"/>
<Control HorizontalExpand="True"/>
<Label FontColorOverride="#b1b1b2" StyleClasses="LabelSmall" Name="PublishTimeLabel" Margin="6 6 6 6"/>
<controls:ConfirmButton Name="DeleteButton" Text="{Loc news-write-ui-delete-text}"
HorizontalAlignment="Right" Margin="8 6 6 6" SetHeight="19" SetWidth="52" Access="Public">
<Button.StyleClasses>
<system:String>ButtonSmall</system:String>
<system:String>ButtonColorRed</system:String>
</Button.StyleClasses>
</controls:ConfirmButton>
</BoxContainer>
</BoxContainer>
</Control>

View File

@@ -0,0 +1,47 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.MassMedia.Ui;
[GenerateTypedNameReferences]
public sealed partial class NewsArticleCard : Control
{
private string? _authorMarkup;
private TimeSpan? _publicationTime;
public Action? OnDeletePressed;
public int ArtcileNumber;
public string? Title
{
get => TitleLabel.Text;
set => TitleLabel.Text = value?.Length <= 30 ? value : $"{value?[..30]}...";
}
public string? Author
{
get => _authorMarkup;
set
{
_authorMarkup = value;
AuthorLabel.Text = _authorMarkup ?? "";
}
}
public TimeSpan? PublicationTime
{
get => _publicationTime;
set
{
_publicationTime = value;
PublishTimeLabel.Text = value?.ToString(@"hh\:mm\:ss") ?? "";
}
}
public NewsArticleCard()
{
RobustXamlLoader.Load(this);
DeleteButton.OnPressed += _ => OnDeletePressed?.Invoke();
}
}

View File

@@ -1,79 +0,0 @@
using JetBrains.Annotations;
using Content.Shared.MassMedia.Components;
using Content.Shared.MassMedia.Systems;
using Robust.Shared.Utility;
namespace Content.Client.MassMedia.Ui
{
[UsedImplicitly]
public sealed class NewsWriteBoundUserInterface : BoundUserInterface
{
[ViewVariables]
private NewsWriteMenu? _menu;
[ViewVariables]
private string _windowName = Loc.GetString("news-read-ui-default-title");
public NewsWriteBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
_menu = new NewsWriteMenu(_windowName);
_menu.OpenCentered();
_menu.OnClose += Close;
_menu.ShareButtonPressed += OnShareButtonPressed;
_menu.DeleteButtonPressed += OnDeleteButtonPressed;
SendMessage(new NewsWriteArticlesRequestMessage());
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Close();
_menu?.Dispose();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (_menu == null || state is not NewsWriteBoundUserInterfaceState cast)
return;
_menu.UpdateUI(cast.Articles, cast.ShareAvalible);
}
private void OnShareButtonPressed()
{
if (_menu == null || _menu.NameInput.Text.Length == 0)
return;
var stringContent = Rope.Collapse(_menu.ContentInput.TextRope);
if (stringContent.Length == 0)
return;
var stringName = _menu.NameInput.Text.Trim();
var name = stringName[..Math.Min(stringName.Length, (SharedNewsSystem.MaxNameLength))];
var content = stringContent[..Math.Min(stringContent.Length, (SharedNewsSystem.MaxArticleLength))];
_menu.ContentInput.TextRope = new Rope.Leaf(string.Empty);
_menu.NameInput.Text = string.Empty;
SendMessage(new NewsWriteShareMessage(name, content));
}
private void OnDeleteButtonPressed(int articleNum)
{
if (_menu == null)
return;
SendMessage(new NewsWriteDeleteMessage(articleNum));
}
}
}

View File

@@ -1,68 +0,0 @@
<DefaultWindow
xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
Title="{Loc 'news-write-ui-default-title'}"
MinSize="680 512"
SetSize="680 512">
<BoxContainer Orientation="Horizontal"
HorizontalExpand="True"
VerticalExpand="True">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
SizeFlagsStretchRatio="2"
Margin="10 0 10 10"
MinWidth="350">
<Label Text="{Loc 'news-write-ui-articles-label'}" HorizontalAlignment="Center"/>
<customControls:HSeparator StyleClasses="LowDivider" Margin="0 0 0 10"/>
<PanelContainer VerticalExpand="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#212121" />
</PanelContainer.PanelOverride>
<ScrollContainer
HScrollEnabled="False"
HorizontalExpand="True"
VerticalExpand="True">
<BoxContainer
Name="ArticleCardsContainer"
Orientation="Vertical"
VerticalExpand="True">
</BoxContainer>
</ScrollContainer>
</PanelContainer>
</BoxContainer>
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
Margin="15 0 0 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label Text="{Loc 'news-write-ui-article-name-label'}"/>
<LineEdit Name="NameInput"
MinSize="60 0"
VerticalAlignment="Top"
Margin="4 0 0 0"
Access="Public"
HorizontalExpand="True"/>
</BoxContainer>
<customControls:HSeparator StyleClasses="LowDivider" Margin="0 5 0 5"/>
<Label Text="{Loc 'news-write-ui-article-content-label'}" Margin="0 0 0 5"/>
<PanelContainer Name="InputContainer"
VerticalAlignment="Stretch"
VerticalExpand="True"
HorizontalExpand="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#333237"/>
</PanelContainer.PanelOverride>
<TextEdit Name="ContentInput" Access="Public" />
</PanelContainer>
<Button Name="Share"
MinWidth="30"
HorizontalAlignment="Left"
Text="{Loc 'news-write-ui-share-text'}"
Access="Public"
Margin="0 4 4 4">
</Button>
</BoxContainer>
</BoxContainer>
</DefaultWindow>

View File

@@ -1,42 +0,0 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Content.Shared.MassMedia.Systems;
namespace Content.Client.MassMedia.Ui;
[GenerateTypedNameReferences]
public sealed partial class NewsWriteMenu : DefaultWindow
{
public event Action? ShareButtonPressed;
public event Action<int>? DeleteButtonPressed;
public NewsWriteMenu(string name)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
if (Window != null)
Window.Title = name;
Share.OnPressed += _ => ShareButtonPressed?.Invoke();
}
public void UpdateUI(NewsArticle[] articles, bool shareAvalible)
{
ArticleCardsContainer.Children.Clear();
for (int i = 0; i < articles.Length; i++)
{
var article = articles[i];
var mini = new MiniArticleCardControl(article.Name, (article.Author != null ? article.Author : Loc.GetString("news-read-ui-no-author")));
mini.ArticleNum = i;
mini.OnDeletePressed += () => DeleteButtonPressed?.Invoke(mini.ArticleNum);
ArticleCardsContainer.AddChild(mini);
}
Share.Disabled = !shareAvalible;
}
}

View File

@@ -0,0 +1,84 @@
using JetBrains.Annotations;
using Content.Shared.MassMedia.Systems;
using Content.Shared.MassMedia.Components;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.MassMedia.Ui;
[UsedImplicitly]
public sealed class NewsWriterBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[ViewVariables]
private NewsWriterMenu? _menu;
public NewsWriterBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
_menu = new NewsWriterMenu(_gameTiming);
_menu.OpenCentered();
_menu.OnClose += Close;
_menu.ArticleEditorPanel.PublishButtonPressed += OnPublishButtonPressed;
_menu.DeleteButtonPressed += OnDeleteButtonPressed;
SendMessage(new NewsWriterArticlesRequestMessage());
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Close();
_menu?.Dispose();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (state is not NewsWriterBoundUserInterfaceState cast)
return;
_menu?.UpdateUI(cast.Articles, cast.PublishEnabled, cast.NextPublish);
}
private void OnPublishButtonPressed()
{
var title = _menu?.ArticleEditorPanel.TitleField.Text.Trim() ?? "";
if (_menu == null || title.Length == 0)
return;
var stringContent = Rope.Collapse(_menu.ArticleEditorPanel.ContentField.TextRope).Trim();
if (stringContent.Length == 0)
return;
var name = title.Length <= SharedNewsSystem.MaxTitleLength
? title
: $"{title[..(SharedNewsSystem.MaxTitleLength - 3)]}...";
var content = stringContent.Length <= SharedNewsSystem.MaxContentLength
? stringContent
: $"{stringContent[..(SharedNewsSystem.MaxContentLength - 3)]}...";
SendMessage(new NewsWriterPublishMessage(name, content));
}
private void OnDeleteButtonPressed(int articleNum)
{
if (_menu == null)
return;
SendMessage(new NewsWriterDeleteMessage(articleNum));
}
}

View File

@@ -0,0 +1,45 @@
<controls:FancyWindow
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:ui="clr-namespace:Content.Client.MassMedia.Ui"
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
Title="{Loc 'news-write-ui-default-title'}"
MinSize="348 443"
SetSize="348 443">
<ui:ArticleEditorPanel Name="ArticleEditorPanel" HorizontalAlignment="Left" VerticalExpand="True"
MinWidth="410" MinHeight="370" Margin="0 0 0 30" Access="Public" Visible="False"/>
<BoxContainer Orientation="Vertical" VerticalExpand="True">
<Control VerticalExpand="True" HorizontalExpand="True" Margin="10 10 10 0">
<PanelContainer Name="MainPanel" HorizontalExpand="False" VerticalExpand="True">
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BackgroundColor="#202023" />
</PanelContainer.PanelOverride>
</PanelContainer>
<ScrollContainer Name="ArticleListScrollbar" HorizontalExpand="True" VerticalExpand="True" HScrollEnabled="True">
<BoxContainer Name="ArticlesContainer" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="6 6 6 6">
</BoxContainer>
</ScrollContainer>
</Control>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="12 7 12 9">
<BoxContainer Orientation="Horizontal">
<Label Name="ArticleCount" Text="{Loc news-write-ui-article-count-0}"/>
</BoxContainer>
<Control HorizontalExpand="True"/>
<Control>
<Button Name="ButtonCreate" SetHeight="26" MinWidth="83" Text="{Loc news-write-ui-create-text}"/>
</Control>
</BoxContainer>
<Control SetHeight="30" Margin="2 0 0 0">
<PanelContainer Name="FooterPanel">
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BorderColor="#5A5A5A" BorderThickness="0 2 0 0" />
</PanelContainer.PanelOverride>
</PanelContainer>
<BoxContainer Name="ContentFooter" HorizontalExpand="True" SetHeight="28">
<Label Text="{Loc news-write-ui-footer-text}" VerticalAlignment="Center" Margin="6 0" StyleClasses="PdaContentFooterText"/>
</BoxContainer>
</Control>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -0,0 +1,97 @@
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
using Content.Shared.MassMedia.Systems;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
namespace Content.Client.MassMedia.Ui;
[GenerateTypedNameReferences]
public sealed partial class NewsWriterMenu : FancyWindow
{
private readonly IGameTiming _gameTiming;
private TimeSpan? _nextPublish;
public event Action<int>? DeleteButtonPressed;
public NewsWriterMenu(IGameTiming gameTiming)
{
RobustXamlLoader.Load(this);
_gameTiming = gameTiming;
ContentsContainer.RectClipContent = false;
// Customize scrollbar width and margin. This is not possible in xaml
var scrollbar = ArticleListScrollbar.GetChild(1);
scrollbar.SetWidth = 6f;
scrollbar.Margin = new Thickness(0, 0, 2 , 0);
ButtonCreate.OnPressed += OnCreate;
}
public void UpdateUI(NewsArticle[] articles, bool publishEnabled, TimeSpan nextPublish)
{
ArticlesContainer.Children.Clear();
ArticleCount.Text = Loc.GetString("news-write-ui-article-count-text", ("count", articles.Length));
//Iterate backwards to have the newest article at the top
for (var i = articles.Length - 1; i >= 0 ; i--)
{
var article = articles[i];
var control = new NewsArticleCard
{
Title = article.Title,
Author = article.Author ?? Loc.GetString("news-read-ui-no-author"),
PublicationTime = article.ShareTime,
ArtcileNumber = i
};
control.OnDeletePressed += () => DeleteButtonPressed?.Invoke(control.ArtcileNumber);
ArticlesContainer.AddChild(control);
}
ButtonCreate.Disabled = !publishEnabled;
_nextPublish = nextPublish;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (!_nextPublish.HasValue)
return;
var remainingTime = _nextPublish.Value.Subtract(_gameTiming.CurTime);
if (remainingTime.TotalSeconds <= 0)
{
_nextPublish = null;
ButtonCreate.Text = Loc.GetString("news-write-ui-create-text");
return;
}
ButtonCreate.Text = remainingTime.Seconds.ToString("D2");
}
protected override void Resized()
{
base.Resized();
var margin = ArticleEditorPanel.Margin;
// Bandaid for the funny 1 pixel margin differences
ArticleEditorPanel.Margin = new Thickness(Width - 1, margin.Top, margin.Right, margin.Bottom);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
ButtonCreate.OnPressed -= OnCreate;
}
private void OnCreate(BaseButton.ButtonEventArgs buttonEventArgs)
{
ArticleEditorPanel.Visible = true;
}
}

View File

@@ -1,6 +1,7 @@
using Content.Client.Pinpointer.UI;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
namespace Content.Client.Medical.CrewMonitoring;
@@ -16,7 +17,7 @@ public sealed partial class CrewMonitoringNavMapControl : NavMapControl
{
WallColor = new Color(192, 122, 196);
TileColor = new(71, 42, 72);
_backgroundColor = Color.FromSrgb(TileColor.WithAlpha(_backgroundOpacity));
BackgroundColor = Color.FromSrgb(TileColor.WithAlpha(BackgroundOpacity));
_trackedEntityLabel = new Label
{
@@ -30,7 +31,7 @@ public sealed partial class CrewMonitoringNavMapControl : NavMapControl
{
PanelOverride = new StyleBoxFlat
{
BackgroundColor = _backgroundColor,
BackgroundColor = BackgroundColor,
},
Margin = new Thickness(5f, 10f),
@@ -43,9 +44,9 @@ public sealed partial class CrewMonitoringNavMapControl : NavMapControl
this.AddChild(_trackedEntityPanel);
}
protected override void Draw(DrawingHandleScreen handle)
protected override void FrameUpdate(FrameEventArgs args)
{
base.Draw(handle);
base.FrameUpdate(args);
if (Focus == null)
{

View File

@@ -23,7 +23,6 @@ namespace Content.Client.Medical.CrewMonitoring;
[GenerateTypedNameReferences]
public sealed partial class CrewMonitoringWindow : FancyWindow
{
private List<Control> _rowsContent = new();
private readonly IEntityManager _entManager;
private readonly IPrototypeManager _prototypeManager;
private readonly SpriteSystem _spriteSystem;
@@ -100,7 +99,6 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
};
SensorsTable.AddChild(spacer);
_rowsContent.Add(spacer);
}
var deparmentLabel = new RichTextLabel()
@@ -113,7 +111,6 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
deparmentLabel.StyleClasses.Add(StyleNano.StyleClassTooltipActionDescription);
SensorsTable.AddChild(deparmentLabel);
_rowsContent.Add(deparmentLabel);
PopulateDepartmentList(departmentSensors);
}
@@ -129,7 +126,6 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
};
SensorsTable.AddChild(spacer);
_rowsContent.Add(spacer);
var deparmentLabel = new RichTextLabel()
{
@@ -141,7 +137,6 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
deparmentLabel.StyleClasses.Add(StyleNano.StyleClassTooltipActionDescription);
SensorsTable.AddChild(deparmentLabel);
_rowsContent.Add(deparmentLabel);
PopulateDepartmentList(remainingSensors);
}
@@ -175,7 +170,6 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
sensorButton.AddStyleClass(StyleNano.StyleClassButtonColorGreen);
SensorsTable.AddChild(sensorButton);
_rowsContent.Add(sensorButton);
// Primary container to hold the button UI elements
var mainContainer = new BoxContainer()
@@ -265,7 +259,7 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
var jobIcon = new TextureRect()
{
TextureScale = new Vector2(2f, 2f),
Stretch = TextureRect.StretchMode.KeepCentered,
VerticalAlignment = VAlignment.Center,
Texture = _spriteSystem.Frame0(proto.Icon),
Margin = new Thickness(5, 0, 5, 0),
};
@@ -422,7 +416,6 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
private void ClearOutDatedData()
{
SensorsTable.RemoveAllChildren();
_rowsContent.Clear();
NavMap.TrackedCoordinates.Clear();
NavMap.TrackedEntities.Clear();
NavMap.LocalizedNames.Clear();

View File

@@ -43,9 +43,14 @@ public sealed class FloorOcclusionSystem : SharedFloorOcclusionSystem
private void SetShader(SpriteComponent sprite, bool enabled)
{
var shader = _proto.Index<ShaderPrototype>("HorizontalCut").Instance();
if (sprite.PostShader is not null && sprite.PostShader != shader)
return;
if (enabled)
{
sprite.PostShader = _proto.Index<ShaderPrototype>("HorizontalCut").Instance();
sprite.PostShader = shader;
}
else
{

View File

@@ -4,6 +4,7 @@ using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Robust.Client.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Timing;
@@ -12,7 +13,6 @@ namespace Content.Client.Movement.Systems;
public sealed class JetpackSystem : SharedJetpackSystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly ClothingSystem _clothing = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
@@ -75,7 +75,7 @@ public sealed class JetpackSystem : SharedJetpackSystem
var coordinates = uidXform.Coordinates;
var gridUid = coordinates.GetGridUid(EntityManager);
if (_mapManager.TryGetGrid(gridUid, out var grid))
if (TryComp<MapGridComponent>(gridUid, out var grid))
{
coordinates = new EntityCoordinates(gridUid.Value, grid.WorldToLocal(coordinates.ToMapPos(EntityManager, _transform)));
}

View File

@@ -23,6 +23,7 @@ namespace Content.Client.NPC
[Dependency] private readonly IResourceCache _cache = default!;
[Dependency] private readonly NPCSteeringSystem _steering = default!;
[Dependency] private readonly MapSystem _mapSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
public PathfindingDebugMode Modes
{
@@ -39,7 +40,7 @@ namespace Content.Client.NPC
}
else if (!overlayManager.HasOverlay<PathfindingOverlay>())
{
overlayManager.AddOverlay(new PathfindingOverlay(EntityManager, _eyeManager, _inputManager, _mapManager, _cache, this, _mapSystem));
overlayManager.AddOverlay(new PathfindingOverlay(EntityManager, _eyeManager, _inputManager, _mapManager, _cache, this, _mapSystem, _transformSystem));
}
if ((value & PathfindingDebugMode.Steering) != 0x0)
@@ -140,6 +141,7 @@ namespace Content.Client.NPC
private readonly IMapManager _mapManager;
private readonly PathfindingSystem _system;
private readonly MapSystem _mapSystem;
private readonly SharedTransformSystem _transformSystem;
public override OverlaySpace Space => OverlaySpace.ScreenSpace | OverlaySpace.WorldSpace;
@@ -153,7 +155,8 @@ namespace Content.Client.NPC
IMapManager mapManager,
IResourceCache cache,
PathfindingSystem system,
MapSystem mapSystem)
MapSystem mapSystem,
SharedTransformSystem transformSystem)
{
_entManager = entManager;
_eyeManager = eyeManager;
@@ -161,6 +164,7 @@ namespace Content.Client.NPC
_mapManager = mapManager;
_system = system;
_mapSystem = mapSystem;
_transformSystem = transformSystem;
_font = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
}
@@ -480,7 +484,7 @@ namespace Content.Client.NPC
if (neighborPoly.NetEntity != poly.GraphUid)
{
color = Color.Green;
var neighborMap = _entManager.GetCoordinates(neighborPoly).ToMap(_entManager);
var neighborMap = _entManager.GetCoordinates(neighborPoly).ToMap(_entManager, _transformSystem);
if (neighborMap.MapId != args.MapId)
continue;

View File

@@ -80,7 +80,7 @@ namespace Content.Client.NodeContainer
var xform = _entityManager.GetComponent<TransformComponent>(_entityManager.GetEntity(node.Entity));
if (!_mapManager.TryGetGrid(xform.GridUid, out var grid))
if (!_entityManager.TryGetComponent<MapGridComponent>(xform.GridUid, out var grid))
return;
var gridTile = grid.TileIndicesFor(xform.Coordinates);
@@ -145,7 +145,7 @@ namespace Content.Client.NodeContainer
foreach (var (gridId, gridDict) in _gridIndex)
{
var grid = _mapManager.GetGrid(gridId);
var grid = _entityManager.GetComponent<MapGridComponent>(gridId);
var (_, _, worldMatrix, invMatrix) = _entityManager.GetComponent<TransformComponent>(gridId).GetWorldPositionRotationMatrixWithInv();
var lCursorBox = invMatrix.TransformBox(cursorBox);

View File

@@ -3,6 +3,7 @@ using Content.Shared.Chat;
using Content.Shared.NukeOps;
using JetBrains.Annotations;
using Robust.Shared.Configuration;
using Robust.Shared.Timing;
namespace Content.Client.NukeOps;
@@ -10,6 +11,8 @@ namespace Content.Client.NukeOps;
public sealed class WarDeclaratorBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly ILocalizationManager _localizationManager = default!;
[ViewVariables]
private WarDeclaratorWindow? _window;
@@ -20,7 +23,7 @@ public sealed class WarDeclaratorBoundUserInterface : BoundUserInterface
{
base.Open();
_window = new WarDeclaratorWindow();
_window = new WarDeclaratorWindow(_gameTiming, _localizationManager);
if (State != null)
UpdateState(State);
@@ -42,7 +45,8 @@ public sealed class WarDeclaratorBoundUserInterface : BoundUserInterface
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing) _window?.Dispose();
if (disposing)
_window?.Dispose();
}
private void OnWarDeclaratorActivated(string message)

View File

@@ -1,4 +1,5 @@
<DefaultWindow xmlns="https://spacestation14.io"
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="{Loc 'war-declarator-ui-header'}">
<BoxContainer Orientation="Vertical" SeparationOverride="4" MinWidth="440">
@@ -7,12 +8,16 @@
MinHeight="200"
Access="Public" />
<Button Name="WarButton"
Text="{Loc 'war-declarator-ui-war-button'}"
Text="{Loc 'war-declarator-ui-try-war-button'}"
StyleClasses="Caution"
Access="Public"/>
<Label Name="StatusLabel"
Access="Public"/>
<Label Name="InfoLabel"
Access="Public"/>
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<Label Name="StatusLabel"
Align="Center"
Access="Public"/>
<Label Name="InfoLabel"
Align="Center"
Access="Public"/>
</BoxContainer>
</BoxContainer>
</DefaultWindow>
</controls:FancyWindow>

View File

@@ -1,8 +1,7 @@
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Content.Shared.NukeOps;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -10,74 +9,83 @@ using Robust.Shared.Utility;
namespace Content.Client.NukeOps;
[GenerateTypedNameReferences]
public sealed partial class WarDeclaratorWindow : DefaultWindow
public sealed partial class WarDeclaratorWindow : FancyWindow
{
private readonly IGameTiming _gameTiming;
public event Action<string>? OnActivated;
private TimeSpan _endTime;
private TimeSpan _timeStamp;
private TimeSpan _shuttleDisabledTime;
private WarConditionStatus _status;
public WarDeclaratorWindow()
public WarDeclaratorWindow(IGameTiming gameTiming, ILocalizationManager localizationManager)
{
RobustXamlLoader.Load(this);
_gameTiming = IoCManager.Resolve<IGameTiming>();
_gameTiming = gameTiming;
WarButton.OnPressed += (_) => OnActivated?.Invoke(Rope.Collapse(MessageEdit.TextRope));
var loc = IoCManager.Resolve<ILocalizationManager>();
MessageEdit.Placeholder = new Rope.Leaf(loc.GetString("war-declarator-message-placeholder"));
MessageEdit.Placeholder = new Rope.Leaf(localizationManager.GetString("war-declarator-message-placeholder"));
}
protected override void Draw(DrawingHandleScreen handle)
protected override void FrameUpdate(FrameEventArgs args)
{
base.Draw(handle);
UpdateTimer();
}
public void UpdateState(WarDeclaratorBoundUserInterfaceState state)
{
WarButton.Disabled = state.Status != WarConditionStatus.YES_WAR;
if (state.Status == null)
return;
WarButton.Disabled = state.Status == WarConditionStatus.WarReady;
_timeStamp = state.Delay;
_endTime = state.EndTime;
_status = state.Status;
_shuttleDisabledTime = state.ShuttleDisabledTime;
_status = state.Status.Value;
switch(state.Status)
UpdateStatus(state.Status.Value);
}
private void UpdateStatus(WarConditionStatus status)
{
switch (status)
{
case WarConditionStatus.WAR_READY:
case WarConditionStatus.WarReady:
WarButton.Disabled = true;
StatusLabel.Text = Loc.GetString("war-declarator-boost-declared");
InfoLabel.Text = Loc.GetString("war-declarator-conditions-ready");
StatusLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateLow);
break;
case WarConditionStatus.WAR_DELAY:
StatusLabel.Text = Loc.GetString("war-declarator-boost-declared-delay");
UpdateTimer();
StatusLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateLow);
break;
case WarConditionStatus.YES_WAR:
case WarConditionStatus.YesWar:
WarButton.Text = Loc.GetString("war-declarator-ui-war-button");
StatusLabel.Text = Loc.GetString("war-declarator-boost-possible");
UpdateTimer();
StatusLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateGood);
break;
case WarConditionStatus.NO_WAR_SMALL_CREW:
case WarConditionStatus.NoWarSmallCrew:
StatusLabel.Text = Loc.GetString("war-declarator-boost-impossible");
InfoLabel.Text = Loc.GetString("war-declarator-conditions-small-crew", ("min", state.MinCrew));
InfoLabel.Text = Loc.GetString("war-declarator-conditions-small-crew");
StatusLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateNone);
break;
case WarConditionStatus.NO_WAR_SHUTTLE_DEPARTED:
case WarConditionStatus.NoWarShuttleDeparted:
StatusLabel.Text = Loc.GetString("war-declarator-boost-impossible");
InfoLabel.Text = Loc.GetString("war-declarator-conditions-left-outpost");
StatusLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateNone);
break;
case WarConditionStatus.NO_WAR_TIMEOUT:
case WarConditionStatus.NoWarTimeout:
StatusLabel.Text = Loc.GetString("war-declarator-boost-impossible");
InfoLabel.Text = Loc.GetString("war-declarator-conditions-time-out");
StatusLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateNone);
break;
case WarConditionStatus.NoWarUnknown:
StatusLabel.Text = Loc.GetString("war-declarator-boost-impossible");
InfoLabel.Text = Loc.GetString("war-declarator-conditions-unknown");
StatusLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateNone);
break;
default:
StatusLabel.Text = Loc.GetString("war-declarator-boost-impossible");
InfoLabel.Text = Loc.GetString("war-declarator-conditions-unknown");
@@ -86,43 +94,24 @@ public sealed partial class WarDeclaratorWindow : DefaultWindow
}
}
public void UpdateTimer()
private void UpdateTimer()
{
switch(_status)
{
case WarConditionStatus.YES_WAR:
var gameruleTime = _gameTiming.CurTime.Subtract(_timeStamp);
var timeLeft = _endTime.Subtract(gameruleTime);
case WarConditionStatus.YesWar:
var timeLeft = _endTime.Subtract(_gameTiming.CurTime);
if (timeLeft > TimeSpan.Zero)
{
InfoLabel.Text = Loc.GetString("war-declarator-boost-timer", ("minutes", timeLeft.Minutes), ("seconds", timeLeft.Seconds));
}
InfoLabel.Text = Loc.GetString("war-declarator-boost-timer", ("time", timeLeft.ToString("mm\\:ss")));
else
{
_status = WarConditionStatus.NO_WAR_TIMEOUT;
StatusLabel.Text = Loc.GetString("war-declarator-boost-impossible");
InfoLabel.Text = Loc.GetString("war-declarator-conditions-time-out");
StatusLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateNone);
WarButton.Disabled = true;
}
UpdateStatus(WarConditionStatus.NoWarTimeout);
break;
case WarConditionStatus.WAR_DELAY:
var timeAfterDeclaration = _gameTiming.CurTime.Subtract(_timeStamp);
var timeRemain = _endTime.Subtract(timeAfterDeclaration);
if (timeRemain > TimeSpan.Zero)
{
InfoLabel.Text = Loc.GetString("war-declarator-boost-timer", ("minutes", timeRemain.Minutes), ("seconds", timeRemain.Seconds));
}
case WarConditionStatus.WarReady:
var time = _shuttleDisabledTime.Subtract(_gameTiming.CurTime);
if (time > TimeSpan.Zero)
InfoLabel.Text = Loc.GetString("war-declarator-boost-timer", ("time", time.ToString("mm\\:ss")));
else
{
_status = WarConditionStatus.WAR_READY;
StatusLabel.Text = Loc.GetString("war-declarator-boost-declared");
InfoLabel.Text = Loc.GetString("war-declarator-conditions-ready");
StatusLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateLow);
WarButton.Disabled = true;
}
break;
default:
return;

View File

@@ -0,0 +1,7 @@
using Content.Shared.Nutrition.EntitySystems;
namespace Content.Client.Nutrition.EntitySystems;
public sealed class OpenableSystem : SharedOpenableSystem
{
}

View File

@@ -4,57 +4,59 @@
xmlns:xNamespace="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:Content.Client.Stylesheets">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
<Label Text="{Loc 'ui-options-general-ui-style'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-hud-theme'}" />
<Control MinSize="4 0" />
<OptionButton Name="HudThemeOption" />
<ScrollContainer VerticalExpand="True" HorizontalExpand="True">
<BoxContainer Orientation="Vertical" Margin="8 8 8 8" VerticalExpand="True">
<Label Text="{Loc 'ui-options-general-ui-style'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-hud-theme'}" />
<Control MinSize="4 0" />
<OptionButton Name="HudThemeOption" />
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-hud-layout'}" />
<Control MinSize="4 0" />
<OptionButton Name="HudLayoutOption" />
</BoxContainer>
<Label Text="{Loc 'ui-options-general-accessibility'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
<CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
<CheckBox Name="ColorblindFriendlyCheckBox" Text="{Loc 'ui-options-colorblind-friendly'}" />
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-screen-shake-intensity'}" Margin="8 0" />
<Slider Name="ScreenShakeIntensitySlider"
MinValue="0"
MaxValue="100"
Rounded="True"
MinWidth="200" />
<Label Name="ScreenShakeIntensityLabel" Margin="8 0" />
</BoxContainer>
<Label Text="{Loc 'ui-options-general-discord'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="DiscordRich" Text="{Loc 'ui-options-discordrich'}" />
<Label Text="{Loc 'ui-options-general-speech'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ShowLoocAboveHeadCheckBox" Text="{Loc 'ui-options-show-looc-on-head'}" />
<CheckBox Name="FancySpeechBubblesCheckBox" Text="{Loc 'ui-options-fancy-speech'}" />
<CheckBox Name="FancyNameBackgroundsCheckBox" Text="{Loc 'ui-options-fancy-name-background'}" />
<Label Text="{Loc 'ui-options-general-cursor'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ShowHeldItemCheckBox" Text="{Loc 'ui-options-show-held-item'}" />
<CheckBox Name="ShowCombatModeIndicatorsCheckBox" Text="{Loc 'ui-options-show-combat-mode-indicators'}" />
<Label Text="{Loc 'ui-options-general-storage'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="OpaqueStorageWindowCheckBox" Text="{Loc 'ui-options-opaque-storage-window'}" />
<CheckBox Name="StaticStorageUI" Text="{Loc 'ui-options-static-storage-ui'}" />
<!-- <CheckBox Name="ToggleWalk" Text="{Loc 'ui-options-hotkey-toggle-walk'}" /> -->
</BoxContainer>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-hud-layout'}" />
<Control MinSize="4 0" />
<OptionButton Name="HudLayoutOption" />
</BoxContainer>
<Label Text="{Loc 'ui-options-general-accessibility'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ReducedMotionCheckBox" Text="{Loc 'ui-options-reduced-motion'}" />
<CheckBox Name="EnableColorNameCheckBox" Text="{Loc 'ui-options-enable-color-name'}" />
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-screen-shake-intensity'}" Margin="8 0" />
<Slider Name="ScreenShakeIntensitySlider"
MinValue="0"
MaxValue="100"
Rounded="True"
MinWidth="200" />
<Label Name="ScreenShakeIntensityLabel" Margin="8 0" />
</BoxContainer>
<Label Text="{Loc 'ui-options-general-discord'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="DiscordRich" Text="{Loc 'ui-options-discordrich'}" />
<Label Text="{Loc 'ui-options-general-speech'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ShowLoocAboveHeadCheckBox" Text="{Loc 'ui-options-show-looc-on-head'}" />
<CheckBox Name="FancySpeechBubblesCheckBox" Text="{Loc 'ui-options-fancy-speech'}" />
<CheckBox Name="FancyNameBackgroundsCheckBox" Text="{Loc 'ui-options-fancy-name-background'}" />
<Label Text="{Loc 'ui-options-general-cursor'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="ShowHeldItemCheckBox" Text="{Loc 'ui-options-show-held-item'}" />
<CheckBox Name="ShowCombatModeIndicatorsCheckBox" Text="{Loc 'ui-options-show-combat-mode-indicators'}" />
<Label Text="{Loc 'ui-options-general-storage'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
<CheckBox Name="OpaqueStorageWindowCheckBox" Text="{Loc 'ui-options-opaque-storage-window'}" />
<CheckBox Name="StaticStorageUI" Text="{Loc 'ui-options-static-storage-ui'}" />
<!-- <CheckBox Name="ToggleWalk" Text="{Loc 'ui-options-hotkey-toggle-walk'}" /> -->
</BoxContainer>
</ScrollContainer>
<controls:StripeBack HasBottomEdge="False" HasMargins="False">
<Button Name="ApplyButton"
Text="{Loc 'ui-options-apply'}"

View File

@@ -64,6 +64,7 @@ namespace Content.Client.Options.UI.Tabs
FancySpeechBubblesCheckBox.OnToggled += OnCheckBoxToggled;
FancyNameBackgroundsCheckBox.OnToggled += OnCheckBoxToggled;
EnableColorNameCheckBox.OnToggled += OnCheckBoxToggled;
ColorblindFriendlyCheckBox.OnToggled += OnCheckBoxToggled;
ReducedMotionCheckBox.OnToggled += OnCheckBoxToggled;
ScreenShakeIntensitySlider.OnValueChanged += OnScreenShakeIntensitySliderChanged;
// ToggleWalk.OnToggled += OnCheckBoxToggled;
@@ -78,6 +79,7 @@ namespace Content.Client.Options.UI.Tabs
FancySpeechBubblesCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatEnableFancyBubbles);
FancyNameBackgroundsCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatFancyNameBackground);
EnableColorNameCheckBox.Pressed = _cfg.GetCVar(CCVars.ChatEnableColorName);
ColorblindFriendlyCheckBox.Pressed = _cfg.GetCVar(CCVars.AccessibilityColorblindFriendly);
ReducedMotionCheckBox.Pressed = _cfg.GetCVar(CCVars.ReducedMotion);
ScreenShakeIntensitySlider.Value = _cfg.GetCVar(CCVars.ScreenShakeIntensity) * 100f;
// ToggleWalk.Pressed = _cfg.GetCVar(CCVars.ToggleWalk);
@@ -123,6 +125,7 @@ namespace Content.Client.Options.UI.Tabs
_cfg.SetCVar(CCVars.ChatEnableFancyBubbles, FancySpeechBubblesCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatFancyNameBackground, FancyNameBackgroundsCheckBox.Pressed);
_cfg.SetCVar(CCVars.ChatEnableColorName, EnableColorNameCheckBox.Pressed);
_cfg.SetCVar(CCVars.AccessibilityColorblindFriendly, ColorblindFriendlyCheckBox.Pressed);
_cfg.SetCVar(CCVars.ReducedMotion, ReducedMotionCheckBox.Pressed);
_cfg.SetCVar(CCVars.ScreenShakeIntensity, ScreenShakeIntensitySlider.Value / 100f);
// _cfg.SetCVar(CCVars.ToggleWalk, ToggleWalk.Pressed);
@@ -149,6 +152,7 @@ namespace Content.Client.Options.UI.Tabs
var isFancyChatSame = FancySpeechBubblesCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableFancyBubbles);
var isFancyBackgroundSame = FancyNameBackgroundsCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatFancyNameBackground);
var isEnableColorNameSame = EnableColorNameCheckBox.Pressed == _cfg.GetCVar(CCVars.ChatEnableColorName);
var isColorblindFriendly = ColorblindFriendlyCheckBox.Pressed == _cfg.GetCVar(CCVars.AccessibilityColorblindFriendly);
var isReducedMotionSame = ReducedMotionCheckBox.Pressed == _cfg.GetCVar(CCVars.ReducedMotion);
var isScreenShakeIntensitySame = Math.Abs(ScreenShakeIntensitySlider.Value / 100f - _cfg.GetCVar(CCVars.ScreenShakeIntensity)) < 0.01f;
// var isToggleWalkSame = ToggleWalk.Pressed == _cfg.GetCVar(CCVars.ToggleWalk);
@@ -164,6 +168,7 @@ namespace Content.Client.Options.UI.Tabs
isFancyChatSame &&
isFancyBackgroundSame &&
isEnableColorNameSame &&
isColorblindFriendly &&
isReducedMotionSame &&
isScreenShakeIntensitySame &&
// isToggleWalkSame &&

View File

@@ -8,6 +8,8 @@ using Robust.Client.Graphics;
using Robust.Shared.Enums;
using System.Numerics;
using Content.Shared.StatusIcon.Components;
using Content.Client.UserInterface.Systems;
using Robust.Shared.Prototypes;
using static Robust.Shared.Maths.Color;
namespace Content.Client.Overlays;
@@ -17,19 +19,25 @@ namespace Content.Client.Overlays;
/// </summary>
public sealed class EntityHealthBarOverlay : Overlay
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
private readonly IEntityManager _entManager;
private readonly SharedTransformSystem _transform;
private readonly MobStateSystem _mobStateSystem;
private readonly MobThresholdSystem _mobThresholdSystem;
private readonly ProgressColorSystem _progressColor;
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
public HashSet<string> DamageContainers = new();
private readonly ShaderInstance _shader;
public EntityHealthBarOverlay(IEntityManager entManager)
{
IoCManager.InjectDependencies(this);
_entManager = entManager;
_transform = _entManager.EntitySysManager.GetEntitySystem<SharedTransformSystem>();
_mobStateSystem = _entManager.EntitySysManager.GetEntitySystem<MobStateSystem>();
_mobThresholdSystem = _entManager.EntitySysManager.GetEntitySystem<MobThresholdSystem>();
_transform = _entManager.System<SharedTransformSystem>();
_mobStateSystem = _entManager.System<MobStateSystem>();
_mobThresholdSystem = _entManager.System<MobThresholdSystem>();
_progressColor = _entManager.System<ProgressColorSystem>();
_shader = _prototype.Index<ShaderPrototype>("unshaded").Instance();
}
protected override void Draw(in OverlayDrawArgs args)
@@ -42,6 +50,8 @@ public sealed class EntityHealthBarOverlay : Overlay
var scaleMatrix = Matrix3.CreateScale(new Vector2(scale, scale));
var rotationMatrix = Matrix3.CreateRotation(-rotation);
handle.UseShader(_shader);
var query = _entManager.AllEntityQueryEnumerator<MobThresholdsComponent, MobStateComponent, DamageableComponent, SpriteComponent>();
while (query.MoveNext(out var uid,
out var mobThresholdsComponent,
@@ -147,26 +157,11 @@ public sealed class EntityHealthBarOverlay : Overlay
return (0, true);
}
public static Color GetProgressColor(float progress, bool crit)
public Color GetProgressColor(float progress, bool crit)
{
if (progress >= 1.0f)
{
return SeaBlue;
}
if (crit)
progress = 0;
if (!crit)
{
switch (progress)
{
case > 0.90F:
return SeaBlue;
case > 0.50F:
return Violet;
case > 0.15F:
return Ruber;
}
}
return VividGamboge;
return _progressColor.GetProgressColor(progress);
}
}

View File

@@ -1,5 +1,7 @@
using Content.Shared.Atmos.Rotting;
using Content.Shared.Damage;
using Content.Shared.Inventory.Events;
using Content.Shared.Mobs.Components;
using Content.Shared.Overlays;
using Content.Shared.StatusIcon;
using Content.Shared.StatusIcon.Components;
@@ -17,9 +19,6 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
public HashSet<string> DamageContainers = new();
[ValidatePrototypeId<StatusIconPrototype>]
private const string HealthIconFine = "HealthIconFine";
public override void Initialize()
{
base.Initialize();
@@ -45,18 +44,20 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
DamageContainers.Clear();
}
private void OnGetStatusIconsEvent(EntityUid uid, DamageableComponent damageableComponent, ref GetStatusIconsEvent args)
private void OnGetStatusIconsEvent(Entity<DamageableComponent> entity, ref GetStatusIconsEvent args)
{
if (!IsActive || args.InContainer)
return;
var healthIcons = DecideHealthIcons(damageableComponent);
var healthIcons = DecideHealthIcons(entity);
args.StatusIcons.AddRange(healthIcons);
}
private IReadOnlyList<StatusIconPrototype> DecideHealthIcons(DamageableComponent damageableComponent)
private IReadOnlyList<StatusIconPrototype> DecideHealthIcons(Entity<DamageableComponent> entity)
{
var damageableComponent = entity.Comp;
if (damageableComponent.DamageContainerID == null ||
!DamageContainers.Contains(damageableComponent.DamageContainerID))
{
@@ -66,10 +67,16 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
var result = new List<StatusIconPrototype>();
// Here you could check health status, diseases, mind status, etc. and pick a good icon, or multiple depending on whatever.
if (damageableComponent?.DamageContainerID == "Biological" &&
_prototypeMan.TryIndex<StatusIconPrototype>(HealthIconFine, out var healthyIcon))
if (damageableComponent?.DamageContainerID == "Biological")
{
result.Add(healthyIcon);
if (TryComp<MobStateComponent>(entity, out var state))
{
// Since there is no MobState for a rotting mob, we have to deal with this case first.
if (HasComp<RottingComponent>(entity) && _prototypeMan.TryIndex(damageableComponent.RottingIcon, out var rottingIcon))
result.Add(rottingIcon);
else if (damageableComponent.HealthIcons.TryGetValue(state.CurrentState, out var value) && _prototypeMan.TryIndex(value, out var icon))
result.Add(icon);
}
}
return result;

View File

@@ -1,14 +1,9 @@
using System.Linq;
using Content.Shared._Miracle.Components;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Humanoid;
using Content.Shared.IdentityManagement.Components;
using Content.Shared.Inventory;
using Content.Shared.Mindshield.Components;
using Content.Shared.Overlays;
using Content.Shared.PDA;
using Content.Shared.Security;
using Content.Shared.Security.Components;
using Content.Shared.StatusIcon;
using Content.Shared.StatusIcon.Components;
using Robust.Shared.Prototypes;
@@ -19,11 +14,6 @@ public sealed class ShowSecurityIconsSystem : EquipmentHudSystem<ShowSecurityIco
{
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
// WD EDIT START
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly SharedIdCardSystem _idCard = default!;
// WD EDIT END
[ValidatePrototypeId<StatusIconPrototype>]
private const string JobIconForNoId = "JobIconNoId";
@@ -32,10 +22,10 @@ public sealed class ShowSecurityIconsSystem : EquipmentHudSystem<ShowSecurityIco
{
base.Initialize();
SubscribeLocalEvent<HumanoidAppearanceComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
SubscribeLocalEvent<StatusIconComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
}
private void OnGetStatusIconsEvent(EntityUid uid, HumanoidAppearanceComponent _, ref GetStatusIconsEvent @event)
private void OnGetStatusIconsEvent(EntityUid uid, StatusIconComponent _, ref GetStatusIconsEvent @event)
{
if (!IsActive || @event.InContainer)
{
@@ -90,65 +80,12 @@ public sealed class ShowSecurityIconsSystem : EquipmentHudSystem<ShowSecurityIco
result.Add(icon);
}
// WD EDIT START
string? protoId;
switch (GetRecord(uid))
if (TryComp<CriminalRecordComponent>(uid, out var record))
{
case SecurityStatus.Detained:
protoId = "CriminalRecordIconIncarcerated";
break;
case SecurityStatus.Released:
protoId = "CriminalRecordIconReleased";
break;
case SecurityStatus.Suspected:
protoId = "CriminalRecordIconSuspected";
break;
case SecurityStatus.Wanted:
protoId = "CriminalRecordIconWanted";
break;
case SecurityStatus.None:
default:
return result;
if(_prototypeMan.TryIndex<StatusIconPrototype>(record.StatusIcon.Id, out var criminalIcon))
result.Add(criminalIcon);
}
if (_prototypeMan.TryIndex<StatusIconPrototype>(protoId, out var recordIcon))
result.Add(recordIcon);
// WD EDIT END
return result;
}
// WD EDIT START
private SecurityStatus GetRecord(EntityUid uid)
{
if (!_entManager.TryGetComponent(uid, out MetaDataComponent? meta))
return SecurityStatus.None;
var name = meta.EntityName;
var ev = new SeeIdentityAttemptEvent();
RaiseLocalEvent(uid, ev);
if (ev.Cancelled)
{
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid) &&
_idCard.TryGetIdCard(idUid.Value, out var idCard))
name = idCard.Comp.FullName;
else
return SecurityStatus.None;
}
if (name == null)
return SecurityStatus.None;
var query = EntityQuery<CriminalStatusDataComponent>();
foreach (var data in query)
{
if (data.Statuses.TryGetValue(name, out var status))
return status;
}
return SecurityStatus.None;
}
// WD EDIT END
}

View File

@@ -0,0 +1,116 @@
using System.Linq;
using Robust.Client.GameObjects;
using static Robust.Client.GameObjects.SpriteComponent;
using Content.Shared.Clothing;
using Content.Shared.Hands;
using Content.Shared.Paint;
using Robust.Client.Graphics;
using Robust.Shared.Prototypes;
namespace Content.Client.Paint;
public sealed class PaintedVisualizerSystem : VisualizerSystem<PaintedComponent>
{
/// <summary>
/// Visualizer for Paint which applies a shader and colors the entity.
/// </summary>
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PaintedComponent, HeldVisualsUpdatedEvent>(OnHeldVisualsUpdated);
SubscribeLocalEvent<PaintedComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<PaintedComponent, EquipmentVisualsUpdatedEvent>(OnEquipmentVisualsUpdated);
}
protected override void OnAppearanceChange(EntityUid uid, PaintedComponent component, ref AppearanceChangeEvent args)
{
var shader = _protoMan.Index<ShaderPrototype>(component.ShaderName).Instance();
if (args.Sprite == null)
return;
// What is this even doing? It's not even checking what the value is.
if (!_appearance.TryGetData(uid, PaintVisuals.Painted, out bool isPainted))
return;
var sprite = args.Sprite;
foreach (var spriteLayer in sprite.AllLayers)
{
if (spriteLayer is not Layer layer)
continue;
if (layer.Shader == null) // If shader isn't null we dont want to replace the original shader.
{
layer.Shader = shader;
layer.Color = component.Color;
}
}
}
private void OnHeldVisualsUpdated(EntityUid uid, PaintedComponent component, HeldVisualsUpdatedEvent args)
{
if (args.RevealedLayers.Count == 0)
return;
if (!TryComp(args.User, out SpriteComponent? sprite))
return;
foreach (var revealed in args.RevealedLayers)
{
if (!sprite.LayerMapTryGet(revealed, out var layer))
continue;
sprite.LayerSetShader(layer, component.ShaderName);
sprite.LayerSetColor(layer, component.Color);
}
}
private void OnEquipmentVisualsUpdated(EntityUid uid, PaintedComponent component, EquipmentVisualsUpdatedEvent args)
{
if (args.RevealedLayers.Count == 0)
return;
if (!TryComp(args.Equipee, out SpriteComponent? sprite))
return;
foreach (var revealed in args.RevealedLayers)
{
if (!sprite.LayerMapTryGet(revealed, out var layer))
continue;
sprite.LayerSetShader(layer, component.ShaderName);
sprite.LayerSetColor(layer, component.Color);
}
}
private void OnShutdown(EntityUid uid, PaintedComponent component, ref ComponentShutdown args)
{
if (!TryComp(uid, out SpriteComponent? sprite))
return;
component.BeforeColor = sprite.Color;
var shader = _protoMan.Index<ShaderPrototype>(component.ShaderName).Instance();
if (!Terminating(uid))
{
foreach (var spriteLayer in sprite.AllLayers)
{
if (spriteLayer is not Layer layer)
continue;
if (layer.Shader == shader) // If shader isn't same as one in component we need to ignore it.
{
layer.Shader = null;
if (layer.Color == component.Color) // If color isn't the same as one in component we don't want to change it.
layer.Color = component.BeforeColor;
}
}
}
}
}

View File

@@ -1,6 +1,5 @@
using JetBrains.Annotations;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.Utility;
using static Content.Shared.Paper.SharedPaperComponent;
@@ -22,15 +21,7 @@ public sealed class PaperBoundUserInterface : BoundUserInterface
_window = new PaperWindow();
_window.OnClose += Close;
_window.Input.OnKeyBindDown += args => // Solution while TextEdit don't have events
{
if (args.Function == EngineKeyFunctions.TextSubmit)
{
var text = Rope.Collapse(_window.Input.TextRope);
Input_OnTextEntered(text);
args.Handle();
}
};
_window.OnSaved += Input_OnTextEntered;
if (EntMan.TryGetComponent<PaperVisualsComponent>(Owner, out var visuals))
{

View File

@@ -25,5 +25,9 @@
</PanelContainer>
</ScrollContainer>
</PanelContainer>
<!-- Bottom buttons for editing -->
<BoxContainer Name="EditButtons" Orientation="Horizontal" HorizontalAlignment="Right" Margin="6">
<Button Name="SaveButton" />
</BoxContainer>
</BoxContainer>
</paper:PaperWindow>

View File

@@ -2,18 +2,22 @@ using System.Numerics;
using Content.Shared.Paper;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
using Robust.Client.UserInterface.RichText;
using Robust.Shared.Input;
namespace Content.Client.Paper.UI
{
[GenerateTypedNameReferences]
public sealed partial class PaperWindow : BaseWindow
{
[Dependency] private readonly IInputManager _inputManager = default!;
private static Color DefaultTextColor = new(25, 25, 25);
// <summary>
@@ -41,8 +45,11 @@ namespace Content.Client.Paper.UI
typeof(ItalicTag)
};
public event Action<string>? OnSaved;
public PaperWindow()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
// We can't configure the RichTextLabel contents from xaml, so do it here:
@@ -50,6 +57,23 @@ namespace Content.Client.Paper.UI
// Hook up the close button:
CloseButton.OnPressed += _ => Close();
Input.OnKeyBindDown += args => // Solution while TextEdit don't have events
{
if (args.Function == EngineKeyFunctions.MultilineTextSubmit)
{
RunOnSaved();
args.Handle();
}
};
SaveButton.OnPressed += _ =>
{
RunOnSaved();
};
SaveButton.Text = Loc.GetString("paper-ui-save-button",
("keybind", _inputManager.GetKeyFunctionButtonString(EngineKeyFunctions.MultilineTextSubmit)));
}
/// <summary>
@@ -196,6 +220,7 @@ namespace Content.Client.Paper.UI
bool isEditing = state.Mode == SharedPaperComponent.PaperAction.Write;
bool wasEditing = InputContainer.Visible;
InputContainer.Visible = isEditing;
EditButtons.Visible = isEditing;
var msg = new FormattedMessage();
msg.AddMarkupPermissive(state.Text);
@@ -266,5 +291,10 @@ namespace Content.Client.Paper.UI
}
return mode & _allowedResizeModes;
}
private void RunOnSaved()
{
OnSaved?.Invoke(Rope.Collapse(Input.TextRope));
}
}
}

View File

@@ -1,6 +1,7 @@
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Systems;
using Content.Shared.Pulling.Components;
using Robust.Client.GameObjects;
using Robust.Client.Physics;
using Robust.Client.Player;
using Robust.Shared.Physics.Components;
@@ -24,7 +25,7 @@ namespace Content.Client.Physics.Controllers
SubscribeLocalEvent<InputMoverComponent, UpdateIsPredictedEvent>(OnUpdatePredicted);
SubscribeLocalEvent<MovementRelayTargetComponent, UpdateIsPredictedEvent>(OnUpdateRelayTargetPredicted);
SubscribeLocalEvent<SharedPullableComponent, UpdateIsPredictedEvent>(OnUpdatePullablePredicted);
SubscribeLocalEvent<PullableComponent, UpdateIsPredictedEvent>(OnUpdatePullablePredicted);
}
private void OnUpdatePredicted(EntityUid uid, InputMoverComponent component, ref UpdateIsPredictedEvent args)
@@ -40,7 +41,7 @@ namespace Content.Client.Physics.Controllers
args.IsPredicted = true;
}
private void OnUpdatePullablePredicted(EntityUid uid, SharedPullableComponent component, ref UpdateIsPredictedEvent args)
private void OnUpdatePullablePredicted(EntityUid uid, PullableComponent component, ref UpdateIsPredictedEvent args)
{
// Enable prediction if an entity is being pulled by the player.
// Disable prediction if an entity is being pulled by some non-player entity.

View File

@@ -25,12 +25,14 @@ namespace Content.Client.Pinpointer.UI;
[UsedImplicitly, Virtual]
public partial class NavMapControl : MapGridControl
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private IResourceCache _cache = default!;
private readonly SharedTransformSystem _transformSystem;
public EntityUid? Owner;
public EntityUid? MapUid;
protected override bool Draggable => true;
// Actions
public event Action<NetEntity?>? TrackedEntitySelectedAction;
public event Action<DrawingHandleScreen>? PostWallDrawingAction;
@@ -47,23 +49,17 @@ public partial class NavMapControl : MapGridControl
// Constants
protected float UpdateTime = 1.0f;
protected float MaxSelectableDistance = 10f;
protected float RecenterMinimum = 0.05f;
protected float MinDragDistance = 5f;
protected static float MinDisplayedRange = 8f;
protected static float MaxDisplayedRange = 128f;
protected static float DefaultDisplayedRange = 48f;
// Local variables
private Vector2 _offset;
private bool _draggin;
private Vector2 _startDragPosition = default!;
private bool _recentering = false;
private float _updateTimer = 0.25f;
private Dictionary<Color, Color> _sRGBLookUp = new Dictionary<Color, Color>();
public Color _backgroundColor;
public float _backgroundOpacity = 0.9f;
private Dictionary<Color, Color> _sRGBLookUp = new();
protected Color BackgroundColor;
protected float BackgroundOpacity = 0.9f;
private int _targetFontsize = 8;
private IResourceCache _cache;
// Components
private NavMapComponent? _navMap;
@@ -100,10 +96,9 @@ public partial class NavMapControl : MapGridControl
public NavMapControl() : base(MinDisplayedRange, MaxDisplayedRange, DefaultDisplayedRange)
{
IoCManager.InjectDependencies(this);
_cache = IoCManager.Resolve<IResourceCache>();
_transformSystem = _entManager.System<SharedTransformSystem>();
_backgroundColor = Color.FromSrgb(TileColor.WithAlpha(_backgroundOpacity));
_transformSystem = EntManager.System<SharedTransformSystem>();
BackgroundColor = Color.FromSrgb(TileColor.WithAlpha(BackgroundOpacity));
RectClipContent = true;
HorizontalExpand = true;
@@ -145,21 +140,16 @@ public partial class NavMapControl : MapGridControl
_recenter.OnPressed += args =>
{
_recentering = true;
Recentering = true;
};
ForceNavMapUpdate();
}
public void ForceRecenter()
{
_recentering = true;
}
public void ForceNavMapUpdate()
{
_entManager.TryGetComponent(MapUid, out _navMap);
_entManager.TryGetComponent(MapUid, out _grid);
EntManager.TryGetComponent(MapUid, out _navMap);
EntManager.TryGetComponent(MapUid, out _grid);
UpdateNavMap();
}
@@ -167,29 +157,15 @@ public partial class NavMapControl : MapGridControl
public void CenterToCoordinates(EntityCoordinates coordinates)
{
if (_physics != null)
_offset = new Vector2(coordinates.X, coordinates.Y) - _physics.LocalCenter;
Offset = new Vector2(coordinates.X, coordinates.Y) - _physics.LocalCenter;
_recenter.Disabled = false;
}
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
{
base.KeyBindDown(args);
if (args.Function == EngineKeyFunctions.Use)
{
_startDragPosition = args.PointerLocation.Position;
_draggin = true;
}
}
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
{
base.KeyBindUp(args);
if (args.Function == EngineKeyFunctions.Use)
_draggin = false;
if (args.Function == EngineKeyFunctions.UIClick)
{
if (TrackedEntitySelectedAction == null)
@@ -199,15 +175,15 @@ public partial class NavMapControl : MapGridControl
return;
// If the cursor has moved a significant distance, exit
if ((_startDragPosition - args.PointerLocation.Position).Length() > MinDragDistance)
if ((StartDragPosition - args.PointerLocation.Position).Length() > MinDragDistance)
return;
// Get the clicked position
var offset = _offset + _physics.LocalCenter;
var offset = Offset + _physics.LocalCenter;
var localPosition = args.PointerLocation.Position - GlobalPixelPosition;
// Convert to a world position
var unscaledPosition = (localPosition - MidpointVector) / MinimapScale;
var unscaledPosition = (localPosition - MidPointVector) / MinimapScale;
var worldPosition = _transformSystem.GetWorldMatrix(_xform).Transform(new Vector2(unscaledPosition.X, -unscaledPosition.Y) + offset);
// Find closest tracked entity in range
@@ -219,7 +195,7 @@ public partial class NavMapControl : MapGridControl
if (!blip.Selectable)
continue;
var currentDistance = (blip.Coordinates.ToMapPos(_entManager, _transformSystem) - worldPosition).Length();
var currentDistance = (blip.Coordinates.ToMapPos(EntManager, _transformSystem) - worldPosition).Length();
if (closestDistance < currentDistance || currentDistance * MinimapScale > MaxSelectableDistance)
continue;
@@ -251,15 +227,8 @@ public partial class NavMapControl : MapGridControl
{
base.MouseMove(args);
if (!_draggin)
return;
_recentering = false;
_offset -= new Vector2(args.Relative.X, -args.Relative.Y) / MidPoint * WorldRange;
if (_offset != Vector2.Zero)
if (Offset != Vector2.Zero)
_recenter.Disabled = false;
else
_recenter.Disabled = true;
}
@@ -269,36 +238,21 @@ public partial class NavMapControl : MapGridControl
base.Draw(handle);
// Get the components necessary for drawing the navmap
_entManager.TryGetComponent(MapUid, out _navMap);
_entManager.TryGetComponent(MapUid, out _grid);
_entManager.TryGetComponent(MapUid, out _xform);
_entManager.TryGetComponent(MapUid, out _physics);
_entManager.TryGetComponent(MapUid, out _fixtures);
EntManager.TryGetComponent(MapUid, out _navMap);
EntManager.TryGetComponent(MapUid, out _grid);
EntManager.TryGetComponent(MapUid, out _xform);
EntManager.TryGetComponent(MapUid, out _physics);
EntManager.TryGetComponent(MapUid, out _fixtures);
// Map re-centering
if (_recentering)
{
var frameTime = Timing.FrameTime;
var diff = _offset * (float) frameTime.TotalSeconds;
if (_offset.LengthSquared() < RecenterMinimum)
{
_offset = Vector2.Zero;
_recentering = false;
_recenter.Disabled = true;
}
else
{
_offset -= diff * 5f;
}
}
_recenter.Disabled = DrawRecenter();
_zoom.Text = Loc.GetString("navmap-zoom", ("value", $"{(DefaultDisplayedRange / WorldRange ):0.0}"));
if (_navMap == null || _xform == null)
return;
var offset = _offset;
var offset = Offset;
if (_physics != null)
offset += _physics.LocalCenter;
@@ -317,7 +271,7 @@ public partial class NavMapControl : MapGridControl
{
var vert = poly.Vertices[i] - offset;
verts[i] = Scale(new Vector2(vert.X, -vert.Y));
verts[i] = ScalePosition(new Vector2(vert.X, -vert.Y));
}
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, verts[..poly.VertexCount], TileColor);
@@ -348,8 +302,8 @@ public partial class NavMapControl : MapGridControl
foreach (var chunkedLine in chunkedLines)
{
var start = Scale(chunkedLine.Origin - new Vector2(offset.X, -offset.Y));
var end = Scale(chunkedLine.Terminus - new Vector2(offset.X, -offset.Y));
var start = ScalePosition(chunkedLine.Origin - new Vector2(offset.X, -offset.Y));
var end = ScalePosition(chunkedLine.Terminus - new Vector2(offset.X, -offset.Y));
walls.Add(start);
walls.Add(end);
@@ -375,7 +329,7 @@ public partial class NavMapControl : MapGridControl
foreach (var airlock in _navMap.Airlocks)
{
var position = airlock.Position - offset;
position = Scale(position with { Y = -position.Y });
position = ScalePosition(position with { Y = -position.Y });
airlockLines.Add(position + airlockBuffer);
airlockLines.Add(position - airlockBuffer * foobarVec);
@@ -418,10 +372,10 @@ public partial class NavMapControl : MapGridControl
foreach (var beacon in _navMap.Beacons)
{
var position = beacon.Position - offset;
position = Scale(position with { Y = -position.Y });
position = ScalePosition(position with { Y = -position.Y });
var textDimensions = handle.GetDimensions(font, beacon.Text, 1f);
handle.DrawRect(new UIBox2(position - textDimensions / 2 - rectBuffer, position + textDimensions / 2 + rectBuffer), _backgroundColor);
handle.DrawRect(new UIBox2(position - textDimensions / 2 - rectBuffer, position + textDimensions / 2 + rectBuffer), BackgroundColor);
handle.DrawString(font, position - textDimensions / 2, beacon.Text, beacon.Color);
}
}
@@ -435,12 +389,12 @@ public partial class NavMapControl : MapGridControl
{
if (lit && value.Visible)
{
var mapPos = coord.ToMap(_entManager, _transformSystem);
var mapPos = coord.ToMap(EntManager, _transformSystem);
if (mapPos.MapId != MapId.Nullspace)
{
var position = _transformSystem.GetInvWorldMatrix(_xform).Transform(mapPos.Position) - offset;
position = Scale(new Vector2(position.X, -position.Y));
position = ScalePosition(new Vector2(position.X, -position.Y));
handle.DrawCircle(position, float.Sqrt(MinimapScale) * 2f, value.Color);
}
@@ -461,12 +415,12 @@ public partial class NavMapControl : MapGridControl
if (!iconVertexUVs.TryGetValue((blip.Texture, blip.Color), out var vertexUVs))
vertexUVs = new();
var mapPos = blip.Coordinates.ToMap(_entManager, _transformSystem);
var mapPos = blip.Coordinates.ToMap(EntManager, _transformSystem);
if (mapPos.MapId != MapId.Nullspace)
{
var position = _transformSystem.GetInvWorldMatrix(_xform).Transform(mapPos.Position) - offset;
position = Scale(new Vector2(position.X, -position.Y));
position = ScalePosition(new Vector2(position.X, -position.Y));
var scalingCoefficient = 2.5f;
var positionOffset = scalingCoefficient * float.Sqrt(MinimapScale);
@@ -628,14 +582,9 @@ public partial class NavMapControl : MapGridControl
return decodedOutput;
}
protected Vector2 Scale(Vector2 position)
{
return position * MinimapScale + MidpointVector;
}
protected Vector2 GetOffset()
{
return _offset + (_physics != null ? _physics.LocalCenter : new Vector2());
return Offset + (_physics?.LocalCenter ?? new Vector2());
}
}

View File

@@ -91,27 +91,19 @@ public sealed class JobRequirementsManager
return false;
}
if (job.Requirements == null ||
!_cfg.GetCVar(CCVars.GameRoleTimers))
{
return true;
}
var player = _playerManager.LocalSession;
if (player == null)
return true;
if (_adminManager.IsActive()) // WD
return true;
return CheckRoleTime(job.Requirements, out reason);
return _adminManager.IsActive() || // WD
CheckRoleTime(job.Requirements, out reason);
}
public bool CheckRoleTime(HashSet<JobRequirement>? requirements, [NotNullWhen(false)] out FormattedMessage? reason)
{
reason = null;
if (requirements == null)
if (requirements == null || !_cfg.GetCVar(CCVars.GameRoleTimers))
return true;
var reasons = new List<string>();

View File

@@ -1,13 +1,11 @@
using System.Numerics;
using Content.Shared.Examine;
using Content.Shared.Popups;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Client.Popups;
@@ -15,38 +13,22 @@ namespace Content.Client.Popups;
/// <summary>
/// Draws popup text, either in world or on screen.
/// </summary>
public sealed class PopupOverlay : Overlay
public sealed class PopupOverlay(
IConfigurationManager configManager,
IEntityManager entManager,
ISharedPlayerManager playerMgr,
IPrototypeManager protoManager,
IUserInterfaceManager uiManager,
PopupUIController controller,
ExamineSystemShared examine,
SharedTransformSystem transform,
PopupSystem popup)
: Overlay
{
private readonly IConfigurationManager _configManager;
private readonly IEntityManager _entManager;
private readonly IPlayerManager _playerMgr;
private readonly IUserInterfaceManager _uiManager;
private readonly PopupSystem _popup;
private readonly PopupUIController _controller;
private readonly ShaderInstance _shader;
private readonly ShaderInstance _shader = protoManager.Index<ShaderPrototype>("unshaded").Instance();
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
public PopupOverlay(
IConfigurationManager configManager,
IEntityManager entManager,
IPlayerManager playerMgr,
IPrototypeManager protoManager,
IUserInterfaceManager uiManager,
PopupUIController controller,
PopupSystem popup)
{
_configManager = configManager;
_entManager = entManager;
_playerMgr = playerMgr;
_uiManager = uiManager;
_popup = popup;
_controller = controller;
_shader = protoManager.Index<ShaderPrototype>("unshaded").Instance();
}
protected override void Draw(in OverlayDrawArgs args)
{
if (args.ViewportControl == null)
@@ -54,10 +36,10 @@ public sealed class PopupOverlay : Overlay
args.DrawingHandle.SetTransform(Matrix3.Identity);
args.DrawingHandle.UseShader(_shader);
var scale = _configManager.GetCVar(CVars.DisplayUIScale);
var scale = configManager.GetCVar(CVars.DisplayUIScale);
if (scale == 0f)
scale = _uiManager.DefaultUIScale;
scale = uiManager.DefaultUIScale;
DrawWorld(args.ScreenHandle, args, scale);
@@ -66,16 +48,16 @@ public sealed class PopupOverlay : Overlay
private void DrawWorld(DrawingHandleScreen worldHandle, OverlayDrawArgs args, float scale)
{
if (_popup.WorldLabels.Count == 0 || args.ViewportControl == null)
if (popup.WorldLabels.Count == 0 || args.ViewportControl == null)
return;
var matrix = args.ViewportControl.GetWorldToScreenMatrix();
var viewPos = new MapCoordinates(args.WorldAABB.Center, args.MapId);
var ourEntity = _playerMgr.LocalEntity;
var ourEntity = playerMgr.LocalEntity;
foreach (var popup in _popup.WorldLabels)
foreach (var popup1 in popup.WorldLabels)
{
var mapPos = popup.InitialPos.ToMap(_entManager);
var mapPos = popup1.InitialPos.ToMap(entManager, transform);
if (mapPos.MapId != args.MapId)
continue;
@@ -83,12 +65,12 @@ public sealed class PopupOverlay : Overlay
var distance = (mapPos.Position - args.WorldBounds.Center).Length();
// Should handle fade here too wyci.
if (!args.WorldBounds.Contains(mapPos.Position) || !ExamineSystemShared.InRangeUnOccluded(viewPos, mapPos, distance,
e => e == popup.InitialPos.EntityId || e == ourEntity, entMan: _entManager))
if (!args.WorldBounds.Contains(mapPos.Position) || !examine.InRangeUnOccluded(viewPos, mapPos, distance,
e => e == popup1.InitialPos.EntityId || e == ourEntity, entMan: entManager))
continue;
var pos = matrix.Transform(mapPos.Position);
_controller.DrawPopup(popup, worldHandle, pos, scale);
controller.DrawPopup(popup1, worldHandle, pos, scale);
}
}
}

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