Merge branch 'master' of https://github.com/space-wizards/space-station-14 into upstream
# 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:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -35,6 +35,8 @@ namespace Content.Client.Administration.UI.CustomControls
|
||||
|
||||
private readonly Font _fontOverride;
|
||||
|
||||
private PlayerInfo? _selectedPlayer;
|
||||
|
||||
public PlayerListControl()
|
||||
{
|
||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
90
Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs
Normal file
90
Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
34
Content.Client/Atmos/UI/SpaceHeaterWindow.xaml
Normal file
34
Content.Client/Atmos/UI/SpaceHeaterWindow.xaml
Normal 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>
|
||||
73
Content.Client/Atmos/UI/SpaceHeaterWindow.xaml.cs
Normal file
73
Content.Client/Atmos/UI/SpaceHeaterWindow.xaml.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
283
Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs
Normal file
283
Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs
Normal 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);
|
||||
@@ -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))
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
54
Content.Client/CartridgeLoader/Cartridges/NewsReaderUi.cs
Normal file
54
Content.Client/CartridgeLoader/Cartridges/NewsReaderUi.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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; };
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
7
Content.Client/Labels/EntitySystems/LabelSystem.cs
Normal file
7
Content.Client/Labels/EntitySystems/LabelSystem.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using Content.Shared.Labels.EntitySystems;
|
||||
|
||||
namespace Content.Client.Labels;
|
||||
|
||||
public sealed partial class LabelSystem : SharedLabelSystem
|
||||
{
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
71
Content.Client/MassMedia/Ui/ArticleEditorPanel.xaml
Normal file
71
Content.Client/MassMedia/Ui/ArticleEditorPanel.xaml
Normal 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>
|
||||
115
Content.Client/MassMedia/Ui/ArticleEditorPanel.xaml.cs
Normal file
115
Content.Client/MassMedia/Ui/ArticleEditorPanel.xaml.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
29
Content.Client/MassMedia/Ui/NewsArticleCard.xaml
Normal file
29
Content.Client/MassMedia/Ui/NewsArticleCard.xaml
Normal 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>
|
||||
47
Content.Client/MassMedia/Ui/NewsArticleCard.xaml.cs
Normal file
47
Content.Client/MassMedia/Ui/NewsArticleCard.xaml.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
84
Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs
Normal file
84
Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
45
Content.Client/MassMedia/Ui/NewsWriterMenu.xaml
Normal file
45
Content.Client/MassMedia/Ui/NewsWriterMenu.xaml
Normal 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>
|
||||
97
Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs
Normal file
97
Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
7
Content.Client/Nutrition/EntitySystems/OpenableSystem.cs
Normal file
7
Content.Client/Nutrition/EntitySystems/OpenableSystem.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
|
||||
namespace Content.Client.Nutrition.EntitySystems;
|
||||
|
||||
public sealed class OpenableSystem : SharedOpenableSystem
|
||||
{
|
||||
}
|
||||
@@ -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'}"
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
116
Content.Client/Paint/PaintVisualizerSystem.cs
Normal file
116
Content.Client/Paint/PaintVisualizerSystem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user