From f95774b3ce4300012b8dbaa60829499ba6a68203 Mon Sep 17 00:00:00 2001 From: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com> Date: Sun, 17 Nov 2024 15:47:11 -0400 Subject: [PATCH] Mass Engine Update (#1220) <!-- This is a semi-strict format, you can add/remove sections as needed but the order/format should be kept the same Remove these comments before submitting --> # Description <!-- Explain this PR in as much detail as applicable Some example prompts to consider: How might this affect the game? The codebase? What might be some alternatives to this? How/Who does this benefit/hurt [the game/codebase]? --> An attempt to do all engine updates in one go. Not focusing on content associated, only what's needed for it to run and any bug fixes. --- # TODO - [x] Fix bug where unbuckling resets you to lying down. - [x] Fix bug where you can no longer get up after lying down. - [x] See what else I broke. --- --------- Signed-off-by: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Co-authored-by: Tayrtahn <tayrtahn@gmail.com> Co-authored-by: VMSolidus <evilexecutive@gmail.com> Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Co-authored-by: Plykiya <58439124+Plykiya@users.noreply.github.com> Co-authored-by: plykiya <plykiya@protonmail.com> Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com> Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com> Co-authored-by: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> --- Content.Client/Alerts/ClientAlertsSystem.cs | 2 +- Content.Client/Audio/AmbientSoundSystem.cs | 6 +- .../Audio/ClientGlobalSoundSystem.cs | 4 +- .../Audio/ContentAudioSystem.AmbientMusic.cs | 2 +- .../Audio/ContentAudioSystem.LobbyMusic.cs | 6 +- Content.Client/Buckle/BuckleSystem.cs | 66 +- .../Clickable/ClickableComponent.cs | 152 +- Content.Client/Clickable/ClickableSystem.cs | 168 ++ Content.Client/Entry/EntryPoint.cs | 3 - Content.Client/Explosion/ExplosionOverlay.cs | 3 +- Content.Client/Gameplay/GameplayStateBase.cs | 44 +- .../Guidebook/Controls/GuidebookWindow.xaml | 2 +- .../Guidebook/DocumentParsingManager.cs | 19 + Content.Client/Info/InfoSystem.cs | 25 - Content.Client/Info/RulesAndInfoWindow.cs | 14 +- Content.Client/Info/RulesControl.xaml | 24 +- Content.Client/Info/RulesControl.xaml.cs | 45 +- Content.Client/Info/RulesManager.cs | 105 - Content.Client/Info/RulesPopup.xaml | 10 +- Content.Client/Info/RulesPopup.xaml.cs | 2 - Content.Client/IoC/ClientContentIoC.cs | 40 +- .../Movement/Systems/WaddleAnimationSystem.cs | 4 +- .../Visualizers/DeepFriedVisualizer.cs | 3 +- .../Visualizers/DeepFryerVisualizer.cs | 4 +- Content.Client/Nyanotrasen/Mail/MailSystem.cs | 3 +- .../Outline/InteractionOutlineSystem.cs | 6 +- Content.Client/Revenant/RevenantSystem.cs | 3 +- Content.Client/Sandbox/SandboxSystem.cs | 2 +- Content.Client/Shuttles/FtlArrivalOverlay.cs | 82 + .../Systems/ShuttleSystem.EmergencyConsole.cs | 3 +- .../Shuttles/Systems/ShuttleSystem.cs | 21 + Content.Client/Traits/ParacusiaSystem.cs | 6 +- .../Systems/Alerts/AlertsUIController.cs | 3 +- .../Systems/Alerts/Widgets/AlertsUI.xaml.cs | 13 +- .../Systems/Info/InfoUIController.cs | 101 +- .../Systems/Storage/Controls/ItemGridPiece.cs | 4 +- Content.Client/Weather/WeatherSystem.cs | 14 +- .../Tests/Actions/ActionPvsDetachTest.cs | 22 +- .../Tests/Actions/ActionsAddedTest.cs | 2 +- .../Tests/Body/GibTest.cs | 2 +- .../Tests/Body/LegTest.cs | 8 +- .../Tests/Body/LungTest.cs | 8 +- .../Tests/Body/SaveLoadReparentTest.cs | 5 +- .../Tests/Buckle/BuckleDragTest.cs | 60 + .../Tests/Buckle/BuckleTest.Interact.cs | 108 + .../Tests/Buckle/BuckleTest.cs | 22 +- Content.IntegrationTests/Tests/CargoTest.cs | 19 +- .../Tests/Chemistry/DispenserTest.cs | 2 +- .../Chemistry/FixedPoint2SerializationTest.cs | 8 +- .../Tests/Chemistry/SolutionRoundingTest.cs | 4 +- .../Tests/Chemistry/SolutionSystemTests.cs | 12 +- .../Tests/Chemistry/TryAllReactionsTest.cs | 4 +- .../Tests/ClickableTest.cs | 4 +- .../Tests/Climbing/ClimbingTest.cs | 1 + .../Tests/Commands/PardonCommand.cs | 10 +- .../Tests/Commands/RejuvenateTest.cs | 6 +- .../Tests/Commands/RestartRoundTest.cs | 2 +- .../Interaction/ComputerContruction.cs | 10 +- .../Construction/Interaction/CraftingTests.cs | 56 +- .../Interaction/GrilleWindowConstruction.cs | 13 +- .../Interaction/MachineConstruction.cs | 7 +- .../Construction/Interaction/PanelScrewing.cs | 12 +- .../Interaction/PlaceableDeconstruction.cs | 4 +- .../Interaction/WallConstruction.cs | 9 +- .../Interaction/WindowConstruction.cs | 8 +- .../Construction/Interaction/WindowRepair.cs | 2 +- .../Tests/ContainerOcclusionTest.cs | 18 +- .../Tests/Damageable/DamageSpecifierTest.cs | 44 +- .../Tests/Damageable/DamageableTest.cs | 5 +- .../DestructibleDestructionTest.cs | 1 + .../Tests/DoAfter/DoAfterCancellationTests.cs | 39 +- .../Tests/Doors/AirlockTest.cs | 20 +- .../Tests/DummyIconTest.cs | 2 +- .../EncryptionKeys/RemoveEncryptionKeys.cs | 16 +- Content.IntegrationTests/Tests/EntityTest.cs | 12 +- .../Tests/Fluids/FluidSpillTest.cs | 27 +- .../Tests/Fluids/PuddleTest.cs | 14 +- .../Tests/FollowerSystemTest.cs | 5 +- .../Components/ActionBlocking/HandCuffTest.cs | 7 +- .../Components/Mobs/AlertsComponentTests.cs | 15 +- .../Tests/GameRules/AntagPreferenceTest.cs | 2 +- .../Tests/GameRules/FailAndStartPresetTest.cs | 24 +- .../Tests/GameRules/RuleMaxTimeRestartTest.cs | 10 +- .../Tests/Gravity/WeightlessStatusTests.cs | 8 +- .../Tests/GravityGridTest.cs | 30 +- .../Click/InteractionSystemTests.cs | 50 +- .../Tests/Interaction/InRangeUnobstructed.cs | 5 +- .../InteractionTest.EntitySpecifier.cs | 8 +- .../Interaction/InteractionTest.Helpers.cs | 403 +++- .../Tests/Interaction/InteractionTest.cs | 48 +- .../Tests/Linter/StaticFieldValidationTest.cs | 118 +- .../Tests/MachineBoardTest.cs | 11 +- .../Tests/Mapping/MappingTests.cs | 2 +- .../Tests/MaterialArbitrageTest.cs | 17 +- .../Tests/Minds/GhostTests.cs | 44 +- .../Tests/Minds/MindTests.Helpers.cs | 2 +- .../Tests/Movement/BuckleMovementTest.cs | 63 + .../{Interaction => Movement}/MovementTest.cs | 5 +- .../Tests/Movement/PullingTest.cs | 73 + .../{Slipping => Movement}/SlippingTest.cs | 6 +- .../Tests/Networking/PvsCommandTest.cs | 4 +- .../Networking/SimplePredictReconcileTest.cs | 9 +- .../Tests/Payload/ModularGrenadeTests.cs | 14 +- .../Tests/PostMapInitTest.cs | 33 +- .../Tests/Power/PowerTest.cs | 272 ++- .../Tests/PrototypeSaveTest.cs | 5 +- .../Tests/Puller/PullerTest.cs | 2 +- .../Tests/ResearchTest.cs | 4 +- Content.IntegrationTests/Tests/SalvageTest.cs | 4 +- .../Tests/SaveLoadMapTest.cs | 21 +- .../Tests/SaveLoadSaveTest.cs | 20 +- .../Tests/Serialization/SerializationTest.cs | 16 +- .../Tests/Shuttle/DockTest.cs | 5 +- Content.IntegrationTests/Tests/ShuttleTest.cs | 19 +- .../Tests/Sprite/ItemSpriteTest.cs | 10 +- .../Tests/{Minds => Station}/JobTests.cs | 0 .../Tests/Storage/StorageInteractionTest.cs | 75 + Content.IntegrationTests/Tests/Tag/TagTest.cs | 26 +- .../Tests/Tiles/TileConstructionTests.cs | 16 +- .../Tests/Toolshed/ToolshedTest.cs | 8 +- .../Tests/VendingMachineRestockTest.cs | 3 +- .../Tests/Weldable/WeldableTests.cs | 2 +- ...0606065731_RemoveLastReadRules.Designer.cs | 1909 +++++++++++++++++ .../20240606065731_RemoveLastReadRules.cs | 29 + .../PostgresServerDbContextModelSnapshot.cs | 4 - ...0606065717_RemoveLastReadRules.Designer.cs | 1834 ++++++++++++++++ .../20240606065717_RemoveLastReadRules.cs | 29 + .../SqliteServerDbContextModelSnapshot.cs | 4 - Content.Server.Database/Model.cs | 2 - .../Abilities/Mime/MimePowersComponent.cs | 8 + .../Abilities/Mime/MimePowersSystem.cs | 11 +- .../Administration/Managers/AdminManager.cs | 2 + Content.Server/Administration/ServerApi.cs | 2 +- .../Systems/AdminVerbSystem.Smites.cs | 6 +- Content.Server/Alert/Commands/ClearAlert.cs | 7 +- Content.Server/Alert/Commands/ShowAlert.cs | 7 +- Content.Server/Antag/AntagSelectionSystem.cs | 2 +- .../Components/AntagSelectionComponent.cs | 2 +- .../Antag/MobReplacementRuleSystem.cs | 11 +- .../Atmos/Components/BarotraumaComponent.cs | 10 + .../Atmos/Components/FlammableComponent.cs | 4 + .../Atmos/EntitySystems/BarotraumaSystem.cs | 11 +- .../Atmos/EntitySystems/FlammableSystem.cs | 4 +- .../Atmos/EntitySystems/GasAnalyzerSystem.cs | 6 +- .../EntitySystems/GasTileOverlaySystem.cs | 12 +- .../Unary/EntitySystems/GasPortableSystem.cs | 8 +- .../BarSign/Systems/BarSignSystem.cs | 2 +- Content.Server/Bed/BedSystem.cs | 49 +- .../Bed/Components/HealOnBuckleComponent.cs | 21 +- .../Bed/Components/HealOnBuckleHealing.cs | 1 + .../Bed/Components/StasisBedComponent.cs | 3 +- .../Body/Components/BloodstreamComponent.cs | 4 + .../Body/Components/InternalsComponent.cs | 6 + .../Body/Components/LungComponent.cs | 4 +- .../Body/Systems/BloodstreamSystem.cs | 7 +- .../Body/Systems/InternalsSystem.cs | 14 +- .../Body/Systems/MetabolizerSystem.cs | 6 + .../Body/Systems/RespiratorSystem.cs | 3 + .../Cargo/Systems/CargoSystem.Shuttle.cs | 42 +- Content.Server/Cargo/Systems/CargoSystem.cs | 3 + Content.Server/Carrying/CarryingSystem.cs | 4 +- Content.Server/Chat/Systems/ChatSystem.cs | 6 +- Content.Server/Chat/TelepathicChatSystem.cs | 10 +- .../Chemistry/ReagentEffects/AdjustAlert.cs | 8 +- Content.Server/Clothing/MagbootsSystem.cs | 4 +- .../Systems/ChameleonClothingSystem.cs | 4 +- .../Construction/PartExchangerSystem.cs | 7 +- Content.Server/Database/ServerDbBase.cs | 24 - Content.Server/Database/ServerDbManager.cs | 19 - Content.Server/Decals/DecalSystem.cs | 5 +- .../Behaviors/SpawnEntitiesBehavior.cs | 7 +- .../Destructible/Thresholds/MinMax.cs | 26 - .../Systems/NetworkConfiguratorSystem.cs | 2 +- .../Disposal/Tube/DisposalTubeSystem.cs | 16 +- .../Unit/EntitySystems/DisposalUnitSystem.cs | 11 +- Content.Server/Dragon/DragonRiftSystem.cs | 2 +- .../Ensnaring/EnsnareableSystem.Ensnaring.cs | 10 +- Content.Server/Ensnaring/EnsnareableSystem.cs | 2 +- Content.Server/Entry/EntryPoint.cs | 2 - .../GameTicking/GameTicker.GameRule.cs | 3 +- .../GameTicking/GameTicker.Spawning.cs | 15 +- .../GameTicking/Rules/DeathMatchRuleSystem.cs | 2 +- .../GameTicking/Rules/GameRulePrototype.cs | 15 - .../Rules/GameRuleSystem.Utility.cs | 2 +- .../GameTicking/Rules/GameRuleSystem.cs | 2 +- .../Rules/InactivityTimeRestartRuleSystem.cs | 2 +- .../Rules/KillCalloutRuleSystem.cs | 2 +- .../GameTicking/Rules/LoadMapRuleSystem.cs | 4 +- .../Rules/MaxTimeRestartRuleSystem.cs | 2 +- .../GameTicking/Rules/NukeopsRuleSystem.cs | 6 +- .../GameTicking/Rules/RespawnRuleSystem.cs | 3 +- .../Rules/RevolutionaryRuleSystem.cs | 2 +- .../RoundstartStationVariationRuleSystem.cs | 2 +- .../GameTicking/Rules/SandboxRuleSystem.cs | 2 +- .../GameTicking/Rules/SecretRuleSystem.cs | 2 +- .../GameTicking/Rules/SubGamemodesSystem.cs | 2 +- .../GameTicking/Rules/TraitorRuleSystem.cs | 6 +- .../GameTicking/Rules/ZombieRuleSystem.cs | 4 +- Content.Server/Geras/GerasComponent.cs | 2 +- Content.Server/Ghost/GhostSystem.cs | 28 +- Content.Server/Gravity/GravitySystem.cs | 4 +- .../Holiday/Christmas/RandomGiftSystem.cs | 2 +- Content.Server/HotPotato/HotPotatoSystem.cs | 4 +- .../HumanoidAppearanceSystem.Modifier.cs | 6 +- .../Systems/HumanoidAppearanceSystem.cs | 13 +- Content.Server/Info/InfoSystem.cs | 35 - Content.Server/Info/RulesManager.cs | 48 - Content.Server/Info/ShowRulesCommand.cs | 14 +- .../Instruments/SwappableInstrumentSystem.cs | 2 +- .../Actions/ChangeStandingStateAction.cs | 2 +- Content.Server/IoC/ServerContentIoC.cs | 2 - .../Kitchen/EntitySystems/MicrowaveSystem.cs | 8 +- .../EntitySystems/ReagentGrinderSystem.cs | 10 +- .../EntitySystems/RotatingLightSystem.cs | 2 +- Content.Server/Lightning/LightningSystem.cs | 22 +- .../Materials/MaterialReclaimerSystem.cs | 2 +- .../EntitySystems/MechGrabberSystem.cs | 10 +- Content.Server/Mech/Systems/MechSystem.cs | 10 +- Content.Server/Mood/MoodComponent.cs | 30 +- Content.Server/Mood/MoodSystem.cs | 4 +- .../Operators/Combat/UnbuckleOperator.cs | 7 +- Content.Server/NPC/Systems/NPCJukeSystem.cs | 10 +- .../Systems/NPCSteeringSystem.Obstacles.cs | 2 +- .../NPC/Systems/NPCSteeringSystem.cs | 1 + .../NameIdentifier/NameIdentifierSystem.cs | 2 +- .../Ninja/Systems/SpaceNinjaSystem.cs | 11 +- .../Commands/TileWindowsCommand.cs | 20 +- .../PlayTimeTrackingManager.Whitelist.cs | 2 +- .../StationEvents/Events/MidRoundAntagRule.cs | 2 +- Content.Server/Objectives/ObjectivesSystem.cs | 2 +- Content.Server/OfferItem/OfferItemSystem.cs | 4 +- .../Physics/Controllers/ConveyorController.cs | 4 +- Content.Server/Pinpointer/NavMapSystem.cs | 14 +- .../PowerMonitoringConsoleSystem.cs | 2 +- .../PowerCell/PowerCellSystem.Draw.cs | 4 +- Content.Server/Psionics/Dreams/DreamSystem.cs | 2 +- .../Research/Systems/ResearchSystem.Server.cs | 8 +- .../Systems/ResearchSystem.Technology.cs | 8 +- .../Revenant/EntitySystems/RevenantSystem.cs | 2 +- .../Salvage/SalvageSystem.Runner.cs | 8 +- Content.Server/Shadowkin/ShadowkinSystem.cs | 12 +- .../Shuttles/Systems/ShuttleConsoleSystem.cs | 6 +- .../Systems/ShuttleSystem.FasterThanLight.cs | 32 +- .../Shuttles/Systems/ShuttleSystem.cs | 2 + .../Charge/Systems/SiliconChargeSystem.cs | 12 +- Content.Server/Silicons/Borgs/BorgSystem.cs | 22 +- .../Components/EntityTableSpawnerComponent.cs | 30 + .../EntitySystems/ConditionalSpawnerSystem.cs | 31 +- Content.Server/Sprite/RandomSpriteSystem.cs | 2 +- .../BasicStationEventSchedulerSystem.cs | 4 +- .../Events/AlertLevelInterceptionRule.cs | 4 +- .../StationEvents/Events/AnomalySpawnRule.cs | 5 +- .../Events/BluespaceArtifactRule.cs | 3 +- .../Events/BluespaceLockerRule.cs | 2 +- .../StationEvents/Events/BreakerFlipRule.cs | 3 +- .../Events/BureaucraticErrorRule.cs | 2 +- .../StationEvents/Events/CargoGiftsRule.cs | 3 +- .../StationEvents/Events/ClericalErrorRule.cs | 2 +- .../StationEvents/Events/FalseAlarmRule.cs | 3 +- .../StationEvents/Events/FreeProberRule.cs | 15 +- .../StationEvents/Events/GasLeakRule.cs | 2 +- .../Events/GlimmerEventSystem.cs | 2 +- .../Events/GlimmerMobSpawnRule.cs | 2 +- .../Events/GlimmerRandomSentienceRule.cs | 2 +- .../Events/GlimmerRevenantSpawnRule.cs | 2 +- .../StationEvents/Events/ImmovableRodRule.cs | 4 +- .../StationEvents/Events/IonStormRule.cs | 2 +- .../StationEvents/Events/KudzuGrowthRule.cs | 2 +- .../Events/MassHallucinationsRule.cs | 2 +- .../StationEvents/Events/MassMindSwapRule.cs | 2 +- .../StationEvents/Events/MeteorSwarmRule.cs | 2 +- .../StationEvents/Events/NinjaSpawnRule.cs | 2 +- .../StationEvents/Events/NoosphericFryRule.cs | 13 +- .../Events/NoosphericStormRule.cs | 2 +- .../StationEvents/Events/NoosphericZapRule.cs | 2 +- .../Events/PirateRadioSpawnRule.cs | 2 +- .../Events/PowerGridCheckRule.cs | 2 +- .../Events/PsionicCatGotYourTongueRule.cs | 2 +- .../Events/RandomEntityStorageSpawnRule.cs | 2 +- .../Events/RandomSentienceRule.cs | 7 +- .../StationEvents/Events/RandomSpawnRule.cs | 2 +- .../StationEvents/Events/SolarFlareRule.cs | 2 +- .../Events/StationEventSystem.cs | 2 +- .../StationEvents/Events/VentClogRule.cs | 2 +- .../StationEvents/Events/VentCrittersRule.cs | 2 +- .../OscillatingStationEventScheduler.cs | 2 +- .../RampingStationEventSchedulerSystem.cs | 2 +- .../Components/TemperatureComponent.cs | 8 + .../Temperature/Systems/TemperatureSystem.cs | 14 +- .../Assorted/ForeignerTraitComponent.cs | 2 +- .../Traits/Assorted/ParacusiaSystem.cs | 6 +- .../Ranged/Systems/GunSystem.Battery.cs | 2 +- .../Ranged/Systems/GunSystem.Revolver.cs | 2 +- .../Systems/RandomInstrumentArtifactSystem.cs | 2 +- .../Zombies/ZombieSystem.Transform.cs | 2 +- .../Actions/Events/FabricateActionEvent.cs | 2 +- Content.Shared/Alert/AlertCategory.cs | 21 - .../Alert/AlertCategoryPrototype.cs | 14 + Content.Shared/Alert/AlertKey.cs | 12 +- Content.Shared/Alert/AlertOrderPrototype.cs | 35 +- Content.Shared/Alert/AlertPrototype.cs | 206 +- Content.Shared/Alert/AlertState.cs | 3 +- Content.Shared/Alert/AlertType.cs | 78 - Content.Shared/Alert/AlertsSystem.cs | 26 +- Content.Shared/Alert/ClickAlertEvent.cs | 7 +- .../Buckle/Components/BuckleComponent.cs | 113 +- .../Buckle/Components/StrapComponent.cs | 53 +- .../Buckle/SharedBuckleSystem.Buckle.cs | 571 +++-- .../Buckle/SharedBuckleSystem.Interaction.cs | 200 ++ .../Buckle/SharedBuckleSystem.Strap.cs | 257 +-- Content.Shared/Buckle/SharedBuckleSystem.cs | 49 +- Content.Shared/CCVar/CCVars.cs | 18 +- .../Chapel/SharedSacrificialAltarSystem.cs | 4 +- .../Climbing/Systems/ClimbSystem.cs | 6 +- .../SharedChameleonClothingSystem.cs | 2 +- .../Loadouts/Systems/LoadoutSystem.cs | 3 +- Content.Shared/Clothing/MagbootsComponent.cs | 4 + .../Pacification/PacificationSystem.cs | 5 +- .../Pacification/PacifiedComponent.cs | 4 + .../Containers/ContainerFillSystem.cs | 37 + .../EntityTableContainerFillComponent.cs | 13 + .../Containers/ItemSlot/ItemSlotsSystem.cs | 6 +- .../Cuffs/Components/CuffableComponent.cs | 5 + Content.Shared/Cuffs/SharedCuffableSystem.cs | 34 +- .../Damage/Components/StaminaComponent.cs | 7 +- .../Damage/Systems/StaminaSystem.cs | 17 +- Content.Shared/Decals/SharedDecalSystem.cs | 2 +- .../Destructible/Thresholds/MinMax.cs | 24 + Content.Shared/Dice/SharedDiceSystem.cs | 2 +- .../SharedElectrocutionSystem.cs | 2 +- Content.Shared/Emoting/EmoteSystem.cs | 2 +- .../Components/EnsnareableComponent.cs | 5 + .../EntitySelectors/AllSelector.cs | 25 + .../EntitySelectors/EntSelector.cs | 27 + .../EntitySelectors/EntityTableSelector.cs | 49 + .../EntitySelectors/GroupSelector.cs | 28 + .../EntitySelectors/NestedSelector.cs | 20 + .../EntitySelectors/NoneSelector.cs | 16 + .../EntityTable/EntityTablePrototype.cs | 18 + .../EntityTable/EntityTableSystem.cs | 20 + .../ValueSelector/ConstantNumberSelector.cs | 22 + .../ValueSelector/NumberSelector.cs | 16 + .../ValueSelector/RangeNumberSelector.cs | 19 + Content.Shared/Examine/ExamineSystemShared.cs | 30 +- .../OnTrigger/SmokeOnTriggerComponent.cs | 2 +- Content.Shared/Foldable/FoldableSystem.cs | 6 +- .../Friction/TileFrictionController.cs | 2 +- .../Components/ActiveGameRuleComponent.cs | 6 +- .../Components/DelayedStartRuleComponent.cs | 2 +- .../Components/EndedGameRuleComponent.cs | 6 +- .../Components/GameRuleComponent.cs | 5 +- .../Gravity/SharedFloatingVisualizerSystem.cs | 2 +- .../Gravity/SharedGravitySystem.Shake.cs | 4 +- Content.Shared/Gravity/SharedGravitySystem.cs | 15 +- .../EntitySystems/SharedHandsSystem.Drop.cs | 4 +- .../SharedHumanoidAppearanceSystem.cs | 24 +- .../Implants/SharedImplanterSystem.cs | 4 +- Content.Shared/Info/RulesMessages.cs | 25 + Content.Shared/Info/SharedInfo.cs | 28 - Content.Shared/Info/SharedRulesManager.cs | 60 - .../Instruments/SharedInstrumentSystem.cs | 4 +- .../Interaction/RotateToFaceSystem.cs | 32 +- .../Interaction/SharedInteractionSystem.cs | 2 +- .../Item/ItemToggle/SharedItemToggleSystem.cs | 19 +- .../Light/SharedHandheldLightSystem.cs | 2 +- .../Light/SharedRgbLightControllerSystem.cs | 6 +- .../Mech/EntitySystems/SharedMechSystem.cs | 6 +- .../Medical/CPR/Systems/CPRSystem.cs | 8 +- .../Mobs/Components/MobThresholdsComponent.cs | 28 +- .../Systems/MobStateSystem.Subscribers.cs | 18 +- .../Mobs/Systems/MobThresholdSystem.cs | 2 +- .../Pulling/Components/PullableComponent.cs | 4 + .../Pulling/Components/PullerComponent.cs | 6 +- .../Pulling/Events/PullStartedMessage.cs | 11 +- .../Pulling/Events/PullStoppedMessage.cs | 13 +- .../Movement/Pulling/Systems/PullingSystem.cs | 66 +- .../Movement/Systems/SharedMoverController.cs | 2 +- .../Systems/SpeedModifierContactsSystem.cs | 2 +- .../Ninja/Components/SpaceNinjaComponent.cs | 4 + .../Nutrition/Components/HungerComponent.cs | 14 +- .../Nutrition/Components/ThirstComponent.cs | 12 +- .../Nutrition/EntitySystems/HungerSystem.cs | 8 +- .../Nutrition/EntitySystems/ThirstSystem.cs | 2 +- .../OfferItem/OfferItemComponent.cs | 5 + Content.Shared/PAI/PAIComponent.cs | 2 +- .../Controllers/SharedConveyorController.cs | 4 +- .../Preferences/HumanoidCharacterProfile.cs | 36 +- Content.Shared/RCD/Systems/RCDAmmoSystem.cs | 4 +- .../Random/Helpers/SharedRandomExtensions.cs | 48 +- .../Revenant/Components/RevenantComponent.cs | 4 + .../Shadowkin/ShadowkinComponent.cs | 5 + Content.Shared/Showers/SharedShowerSystem.cs | 7 +- .../Shuttles/Components/FTLComponent.cs | 16 +- .../Components/FtlVisualizerComponent.cs | 23 + .../Shuttles/Components/PilotComponent.cs | 5 + .../Silicon/Systems/SharedSiliconSystem.cs | 4 +- .../Borgs/Components/BorgChassisComponent.cs | 10 +- .../EntitySystems/SharedEventHorizonSystem.cs | 8 +- Content.Shared/Stacks/SharedStackSystem.cs | 6 +- .../Standing/SharedLayingDownSystem.cs | 4 +- .../Standing/StandingStateSystem.cs | 6 +- .../StationRecordKeyStorageSystem.cs | 2 +- .../StatusEffect/StatusEffectPrototype.cs | 2 +- .../StatusEffect/StatusEffectsSystem.cs | 14 +- .../Storage/EntitySystems/BinSystem.cs | 6 +- Content.Shared/Stunnable/SharedStunSystem.cs | 24 +- .../SubFloor/SharedTrayScannerSystem.cs | 2 +- Content.Shared/Tag/TagSystem.cs | 54 +- .../Systems/LinkedEntitySystem.cs | 6 +- .../Assorted/Systems/LegsParalyzedSystem.cs | 27 +- .../Assorted/Systems/SharedSingerSystem.cs | 2 +- .../Marker/SharedDamageMarkerSystem.cs | 4 +- .../Weapons/Misc/SharedTetherGunSystem.cs | 22 +- .../Systems/RechargeBasicEntityAmmoSystem.cs | 8 +- .../Ranged/Systems/RechargeCycleAmmoSystem.cs | 2 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 2 +- .../Weapons/Reflect/ReflectSystem.cs | 7 +- Content.Shared/Weather/SharedWeatherSystem.cs | 20 +- .../Shared/Alert/AlertManagerTests.cs | 17 +- .../Shared/Alert/AlertOrderPrototypeTests.cs | 26 +- .../Shared/Alert/AlertPrototypeTests.cs | 6 +- .../EinsteinEngines/default.toml | 3 +- Resources/Locale/en-US/guidebook/guides.ftl | 55 + Resources/Locale/en-US/info/rules.ftl | 3 + Resources/Prototypes/Actions/borgs.yml | 2 +- Resources/Prototypes/Actions/crit.yml | 6 +- Resources/Prototypes/Actions/diona.yml | 4 +- Resources/Prototypes/Actions/internals.yml | 2 +- Resources/Prototypes/Actions/mech.yml | 6 +- Resources/Prototypes/Actions/misc.yml | 2 +- Resources/Prototypes/Actions/ninja.yml | 12 +- Resources/Prototypes/Actions/polymorph.yml | 8 +- Resources/Prototypes/Actions/psionics.yml | 40 +- Resources/Prototypes/Actions/revenant.yml | 10 +- Resources/Prototypes/Actions/speech.yml | 2 +- Resources/Prototypes/Actions/spider.yml | 4 +- Resources/Prototypes/Actions/types.yml | 60 +- Resources/Prototypes/Alerts/categories.yml | 38 + .../Prototypes/Body/Organs/Animal/animal.yml | 12 +- .../Body/Organs/Animal/bloodsucker.yml | 6 +- .../Body/Organs/Animal/ruminant.yml | 2 +- .../Prototypes/Body/Organs/Friendstomach.yml | 2 +- Resources/Prototypes/Body/Organs/arachnid.yml | 4 +- Resources/Prototypes/Body/Organs/diona.yml | 12 +- Resources/Prototypes/Body/Organs/moth.yml | 2 +- .../Prototypes/Body/Organs/reptilian.yml | 2 +- Resources/Prototypes/Body/Parts/animal.yml | 8 +- Resources/Prototypes/Body/Parts/rat.yml | 2 +- Resources/Prototypes/Body/Parts/silicon.yml | 2 +- .../Fills/Backpacks/StarterGear/backpack.yml | 67 +- .../Fills/Backpacks/StarterGear/duffelbag.yml | 54 +- .../Fills/Backpacks/StarterGear/satchel.yml | 56 +- .../Prototypes/Catalog/Fills/Crates/fun.yml | 98 + .../Catalog/Fills/Crates/salvage.yml | 2 +- .../Prototypes/Catalog/Fills/Lockers/misc.yml | 461 ++-- .../DeltaV/Body/Organs/vulpkanin.yml | 2 +- .../Fills/Backpacks/StarterGear/backpack.yml | 6 +- .../Fills/Backpacks/StarterGear/duffelbag.yml | 6 +- .../Fills/Backpacks/StarterGear/satchel.yml | 6 +- .../Clothing/Head/hardsuit-helmets.yml | 8 +- .../Entities/Markers/Spawners/ghost_roles.yml | 2 +- .../DeltaV/Entities/Mobs/Player/human.yml | 2 +- .../Entities/Mobs/Species/vulpkanin.yml | 2 +- .../Objects/Misc/subdermal_implants.yml | 2 +- .../Entities/Objects/Specific/Mail/mail.yml | 120 +- .../Objects/Specific/Mail/mail_civilian.yml | 24 +- .../Objects/Specific/Mail/mail_command.yml | 6 +- .../Specific/Mail/mail_engineering.yml | 14 +- .../Specific/Mail/mail_epistemology.yml | 8 +- .../Objects/Specific/Mail/mail_medical.yml | 14 +- .../Objects/Specific/Mail/mail_security.yml | 14 +- .../Ammunition/Projectiles/replicated.yml | 2 +- .../Guns/Ammunition/Projectiles/special.yml | 14 +- .../Weapons/Guns/Projectiles/impacts.yml | 2 +- .../Prototypes/DeltaV/GameRules/events.yml | 8 +- .../Prototypes/DeltaV/GameRules/midround.yml | 2 +- .../DeltaV/Objectives/paradox_anomaly.yml | 6 +- .../Prototypes/DeltaV/Objectives/traitor.yml | 6 +- .../DeltaV/Roles/Jobs/NPC/syndicateNPCs.yml | 2 +- .../Prototypes/Entities/Clothing/Eyes/hud.yml | 2 +- .../Clothing/Head/base_clothinghead.yml | 8 +- .../Clothing/Head/hardsuit-helmets.yml | 2 +- .../Entities/Clothing/Head/hoods.yml | 56 +- .../Clothing/Masks/base_clothingmask.yml | 2 +- .../Entities/Clothing/Neck/misc.yml | 2 +- .../Clothing/OuterClothing/wintercoats.yml | 2 +- .../Entities/Clothing/Shoes/magboots.yml | 10 +- .../Entities/Clothing/Shoes/misc.yml | 2 +- .../Entities/Debugging/clicktest.yml | 2 +- .../Entities/Debugging/debug_sweps.yml | 2 +- .../Prototypes/Entities/Debugging/tippy.yml | 2 +- .../Entities/Effects/ambient_sounds.yml | 2 +- .../Entities/Effects/bluespace_flash.yml | 14 +- .../Entities/Effects/chemistry_effects.yml | 10 +- .../Entities/Effects/emp_effects.yml | 4 +- .../Entities/Effects/exclamation.yml | 4 +- .../Entities/Effects/explosion_light.yml | 2 +- .../Prototypes/Entities/Effects/hearts.yml | 2 +- .../Prototypes/Entities/Effects/lightning.yml | 12 +- .../Prototypes/Entities/Effects/mobspawn.yml | 2 +- .../Prototypes/Entities/Effects/radiation.yml | 2 +- Resources/Prototypes/Entities/Effects/rcd.yml | 22 +- .../Prototypes/Entities/Effects/shuttle.yml | 12 + .../Prototypes/Entities/Effects/sparks.yml | 4 +- .../Entities/Effects/weapon_arc.yml | 22 +- .../Markers/Spawners/Random/maintenance.yml | 792 ++++--- .../Entities/Markers/Spawners/corpses.yml | 2 +- .../Entities/Markers/Spawners/ghost_roles.yml | 6 +- .../Entities/Markers/clientsideclone.yml | 2 +- .../Entities/Markers/construction_ghost.yml | 2 +- .../Entities/Markers/drag_shadow.yml | 2 +- .../Entities/Markers/hover_entity.yml | 2 +- .../Entities/Mobs/Corpses/corpses.yml | 2 +- .../Prototypes/Entities/Mobs/NPCs/Rslimes.yml | 2 +- .../Prototypes/Entities/Mobs/NPCs/animals.yml | 2 +- .../Entities/Mobs/NPCs/regalrat.yml | 14 +- .../Prototypes/Entities/Mobs/NPCs/slimes.yml | 2 +- .../Prototypes/Entities/Mobs/NPCs/xenopet.yml | 14 +- .../Entities/Mobs/Player/admin_ghost.yml | 14 +- .../Prototypes/Entities/Mobs/Player/diona.yml | 2 +- .../Entities/Mobs/Player/dragon.yml | 8 +- .../Entities/Mobs/Player/guardian.yml | 2 +- .../Prototypes/Entities/Mobs/Player/human.yml | 6 +- .../Prototypes/Entities/Mobs/Player/ipc.yml | 2 +- .../Entities/Mobs/Player/observer.yml | 12 +- .../Entities/Mobs/Player/replay_observer.yml | 2 +- .../Entities/Mobs/Player/silicon.yml | 2 +- .../Entities/Mobs/Species/arachne.yml | 2 +- .../Entities/Mobs/Species/arachnid.yml | 2 +- .../Entities/Mobs/Species/diona.yml | 2 +- .../Entities/Mobs/Species/dwarf.yml | 2 +- .../Entities/Mobs/Species/gingerbread.yml | 2 +- .../Entities/Mobs/Species/harpy.yml | 6 +- .../Entities/Mobs/Species/human.yml | 2 +- .../Prototypes/Entities/Mobs/Species/moth.yml | 2 +- .../Entities/Mobs/Species/reptilian.yml | 2 +- .../Entities/Mobs/Species/shadowkin.yml | 2 +- .../Entities/Mobs/Species/skeleton.yml | 2 +- .../Entities/Mobs/Species/slime.yml | 2 +- .../Prototypes/Entities/Mobs/Species/vox.yml | 2 +- .../Consumable/Food/Containers/box.yml | 2 +- .../Objects/Consumable/Food/snacks.yml | 60 +- .../Consumable/Smokeables/Vapes/vape.yml | 2 +- .../Entities/Objects/Decoration/present.yml | 2 +- .../Objects/Devices/chameleon_projector.yml | 6 +- .../Objects/Devices/translator_implants.yml | 22 +- .../Entities/Objects/Devices/translators.yml | 8 +- .../Objects/Fun/Tabletop/backgammon.yml | 2 +- .../Entities/Objects/Fun/Tabletop/base.yml | 2 +- .../Objects/Fun/Tabletop/checkers.yml | 2 +- .../Entities/Objects/Fun/Tabletop/chess.yml | 2 +- .../Entities/Objects/Fun/Tabletop/dnd.yml | 10 +- .../Entities/Objects/Fun/Tabletop/parchis.yml | 2 +- .../Prototypes/Entities/Objects/Fun/pai.yml | 4 +- .../Entities/Objects/Fun/spray_paint.yml | 2 +- .../Entities/Objects/Misc/buffering.yml | 2 +- .../Objects/Misc/fire_extinguisher.yml | 2 +- .../Entities/Objects/Misc/paper.yml | 2 +- .../Objects/Misc/subdermal_implants.yml | 30 +- .../Entities/Objects/Power/lights.yml | 2 +- .../Objects/Specific/Chapel/bibles.yml | 2 +- .../Objects/Specific/Forensics/forensics.yml | 2 +- .../Objects/Specific/Janitorial/soap.yml | 2 +- .../Objects/Specific/Janitorial/spray.yml | 4 +- .../Objects/Specific/Mail/Items/misc.yml | 6 +- .../Objects/Specific/Mail/base_mail_large.yml | 2 +- .../Specific/Robotics/borg_modules.yml | 2 +- .../Objects/Specific/chemical-containers.yml | 48 +- .../Entities/Objects/Tools/fulton.yml | 2 +- .../Entities/Objects/Tools/glowstick.yml | 12 +- .../Entities/Objects/Tools/jetpacks.yml | 4 +- .../Entities/Objects/Weapons/Bombs/funny.yml | 2 +- .../Ammunition/Projectiles/antimateriel.yml | 2 +- .../Ammunition/Projectiles/caseless_rifle.yml | 6 +- .../Guns/Ammunition/Projectiles/grenade.yml | 6 +- .../Ammunition/Projectiles/heavy_rifle.yml | 4 +- .../Ammunition/Projectiles/light_rifle.yml | 10 +- .../Guns/Ammunition/Projectiles/magnum.yml | 12 +- .../Guns/Ammunition/Projectiles/pistol.yml | 10 +- .../Guns/Ammunition/Projectiles/rifle.yml | 10 +- .../Guns/Ammunition/Projectiles/shotgun.yml | 22 +- .../Weapons/Guns/Projectiles/hitscan.yml | 2 +- .../Weapons/Guns/Projectiles/impacts.yml | 8 +- .../Weapons/Guns/Projectiles/magic.yml | 24 +- .../Weapons/Guns/Projectiles/meteors.yml | 2 +- .../Weapons/Guns/Projectiles/projectiles.yml | 80 +- .../Objects/Weapons/Throwable/grenades.yml | 4 +- .../Entities/Stations/nanotrasen.yml | 8 +- .../Entities/Stations/syndicate.yml | 2 +- .../Prototypes/Entities/Stations/test.yml | 2 +- .../Entities/Structures/Furniture/chairs.yml | 2 + .../Structures/Furniture/rollerbeds.yml | 7 + .../Structures/Piping/Disposal/pipes.yml | 2 +- .../Power/Generation/PA/particles.yml | 4 +- .../Structures/Power/Generation/ame.yml | 2 +- .../Power/Generation/generators.yml | 2 +- .../Structures/Power/Generation/solar.yml | 2 +- .../Structures/Power/Generation/teg.yml | 2 +- .../Entities/Structures/Power/apc.yml | 4 +- .../Entities/Structures/Power/substation.yml | 4 +- .../Storage/Canisters/gas_canisters.yml | 22 +- .../Storage/Crates/base_structurecrates.yml | 4 +- .../Structures/Wallmounts/Signs/bar_sign.yml | 2 +- .../Entities/Structures/Wallmounts/switch.yml | 4 +- .../Entities/Structures/Wallmounts/timer.yml | 2 +- .../Prototypes/Entities/Virtual/beam.yml | 2 +- .../Entities/Virtual/electrocution.yml | 6 +- .../Entities/Virtual/stripping_hidden.yml | 2 +- .../Prototypes/Entities/Virtual/tether.yml | 2 +- .../Entities/Virtual/virtual_item.yml | 2 +- .../Entities/World/Debris/asteroids.yml | 16 +- .../Entities/World/Debris/wrecks.yml | 6 +- Resources/Prototypes/Entities/World/chunk.yml | 2 +- .../Prototypes/GameRules/cargo_gifts.yml | 20 +- Resources/Prototypes/GameRules/events.yml | 60 +- Resources/Prototypes/GameRules/midround.yml | 8 +- Resources/Prototypes/GameRules/roundstart.yml | 34 +- .../Prototypes/GameRules/unknown_shuttles.yml | 10 +- Resources/Prototypes/GameRules/variation.yml | 16 +- Resources/Prototypes/Guidebook/rules.yml | 362 ++++ Resources/Prototypes/Guidebook/ss14.yml | 1 + Resources/Prototypes/Magic/event_spells.yml | 2 +- .../Prototypes/Magic/forcewall_spells.yml | 2 +- Resources/Prototypes/Magic/knock_spell.yml | 2 +- .../Prototypes/Magic/projectile_spells.yml | 6 +- Resources/Prototypes/Magic/rune_spells.yml | 8 +- Resources/Prototypes/Magic/smite_spells.yml | 2 +- Resources/Prototypes/Magic/spawn_spells.yml | 2 +- Resources/Prototypes/Magic/staves.yml | 2 +- .../Prototypes/Magic/teleport_spells.yml | 2 +- Resources/Prototypes/Magic/utility_spells.yml | 2 +- .../Prototypes/Nyanotrasen/Actions/types.yml | 4 +- .../Fills/Backpacks/StarterGear/backpack.yml | 2 +- .../Fills/Backpacks/StarterGear/duffelbag.yml | 2 +- .../Fills/Backpacks/StarterGear/satchel.yml | 2 +- .../Nyanotrasen/Catalog/Fills/Books/lore.yml | 2 +- .../Catalog/Fills/Paper/salvage_lore.yml | 8 +- .../Clothing/Head/hardsuit-helmets.yml | 6 +- .../Entities/Effects/lightning.yml | 2 +- .../Entities/Markers/Spawners/ghost_roles.yml | 6 +- .../Entities/Mobs/Player/special.yml | 2 +- .../Nyanotrasen/Entities/Mobs/Species/Oni.yml | 2 +- .../Entities/Mobs/Species/felinid.yml | 2 +- .../Objects/Consumable/Food/ration.yml | 2 +- .../Objects/Specific/Mail/base_mail.yml | 2 +- .../Weapons/Guns/Projectiles/shotgun.yml | 2 +- .../Nyanotrasen/GameRules/events.yml | 30 +- .../Nyanotrasen/Objectives/traitor.yml | 6 +- Resources/Prototypes/Objectives/dragon.yml | 4 +- Resources/Prototypes/Objectives/ninja.yml | 12 +- Resources/Prototypes/Objectives/thief.yml | 82 +- Resources/Prototypes/Objectives/traitor.yml | 42 +- .../Prototypes/Roles/Jobs/Civilian/mime.yml | 2 +- .../Guidebook/ServerRules/BanDurations.xml | 17 + .../Guidebook/ServerRules/BanTypes.xml | 11 + .../ServerRules/CoreRules/RuleC0.xml | 19 + .../ServerRules/CoreRules/RuleC10AHelp.xml | 29 + .../CoreRules/RuleC11AhelpThreats.xml | 20 + .../ServerRules/CoreRules/RuleC12MinAge.xml | 6 + .../CoreRules/RuleC13CharacterNames.xml | 66 + .../ServerRules/CoreRules/RuleC14ICinOOC.xml | 13 + .../ServerRules/CoreRules/RuleC1Admins.xml | 6 + .../ServerRules/CoreRules/RuleC2DBAD.xml | 7 + .../ServerRules/CoreRules/RuleC3NoHate.xml | 20 + .../ServerRules/CoreRules/RuleC4NoERP.xml | 23 + .../ServerRules/CoreRules/RuleC5Metacomms.xml | 18 + .../CoreRules/RuleC6BanEvasion.xml | 15 + .../CoreRules/RuleC7EnglishOnly.xml | 10 + .../ServerRules/CoreRules/RuleC8Exploits.xml | 12 + .../ServerRules/CoreRules/RuleC9Multikey.xml | 7 + .../Guidebook/ServerRules/DefaultRules.xml | 5 + .../Guidebook/ServerRules/README.txt | 5 + .../Guidebook/ServerRules/RoleTypes.xml | 21 + .../ServerRules/RoleplayRules/RuleR0.xml | 26 + .../RoleplayRules/RuleR10Subordination.xml | 26 + .../RuleR11-1AnimalEscalation.xml | 36 + .../RoleplayRules/RuleR11-2ConflictTypes.xml | 30 + .../RoleplayRules/RuleR11Escalation.xml | 67 + .../RoleplayRules/RuleR12RoleAbandonment.xml | 28 + .../RoleplayRules/RuleR13PerformRole.xml | 26 + .../RoleplayRules/RuleR14SecComStandard.xml | 37 + .../RoleplayRules/RuleR15SpaceLaw.xml | 21 + .../RoleplayRules/RuleR1Silicons.xml | 4 + .../RoleplayRules/RuleR2Familiars.xml | 6 + .../RoleplayRules/RuleR3NormalRP.xml | 20 + .../RoleplayRules/RuleR4Metashield.xml | 103 + .../RoleplayRules/RuleR5Arrivals.xml | 22 + .../RoleplayRules/RuleR6SelfAntag.xml | 22 + .../RoleplayRules/RuleR7RoundStalling.xml | 16 + .../RoleplayRules/RuleR8NoFriendlyAntag.xml | 22 + .../RoleplayRules/RuleR9MassSabotage.xml | 23 + .../ServerRules/SiliconRules/RuleS0.xml | 15 + .../SiliconRules/RuleS10OrderConflicts.xml | 9 + .../ServerRules/SiliconRules/RuleS1Laws.xml | 6 + .../SiliconRules/RuleS2LawPriority.xml | 9 + .../SiliconRules/RuleS3LawRedefinition.xml | 8 + .../SiliconRules/RuleS4RequestChanges.xml | 6 + .../SiliconRules/RuleS5FreeSilicon.xml | 4 + .../SiliconRules/RuleS6UnreasonableOrders.xml | 22 + .../SiliconRules/RuleS7Consistency.xml | 6 + .../RuleS8DefaultCrewDefinition.xml | 4 + .../RuleS9DefaultHarmDefinition.xml | 25 + .../SpaceLaw/SLControlledSubstances.xml | 14 + .../ServerRules/SpaceLaw/SLRestrictedGear.xml | 21 + .../SpaceLaw/SLRestrictedWeapons.xml | 11 + .../ServerRules/SpaceLaw/SpaceLaw.xml | 67 + .../ServerRules/WizDenCoreOnlyRules.xml | 26 + .../Guidebook/ServerRules/WizDenLRPRules.xml | 65 + .../Guidebook/ServerRules/WizDenMRPRules.xml | 65 + Resources/ServerInfo/Rules.txt | 60 - .../Effects/medi_holo.rsi/medi_holo.png | Bin 0 -> 1286 bytes .../Textures/Effects/medi_holo.rsi/meta.json | 26 + RobustToolbox | 2 +- 713 files changed, 11681 insertions(+), 4685 deletions(-) create mode 100644 Content.Client/Clickable/ClickableSystem.cs delete mode 100644 Content.Client/Info/InfoSystem.cs delete mode 100644 Content.Client/Info/RulesManager.cs create mode 100644 Content.Client/Shuttles/FtlArrivalOverlay.cs create mode 100644 Content.Client/Shuttles/Systems/ShuttleSystem.cs create mode 100644 Content.IntegrationTests/Tests/Buckle/BuckleDragTest.cs create mode 100644 Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs create mode 100644 Content.IntegrationTests/Tests/Movement/BuckleMovementTest.cs rename Content.IntegrationTests/Tests/{Interaction => Movement}/MovementTest.cs (93%) create mode 100644 Content.IntegrationTests/Tests/Movement/PullingTest.cs rename Content.IntegrationTests/Tests/{Slipping => Movement}/SlippingTest.cs (92%) rename Content.IntegrationTests/Tests/{Minds => Station}/JobTests.cs (100%) create mode 100644 Content.IntegrationTests/Tests/Storage/StorageInteractionTest.cs create mode 100644 Content.Server.Database/Migrations/Postgres/20240606065731_RemoveLastReadRules.Designer.cs create mode 100644 Content.Server.Database/Migrations/Postgres/20240606065731_RemoveLastReadRules.cs create mode 100644 Content.Server.Database/Migrations/Sqlite/20240606065717_RemoveLastReadRules.Designer.cs create mode 100644 Content.Server.Database/Migrations/Sqlite/20240606065717_RemoveLastReadRules.cs delete mode 100644 Content.Server/Destructible/Thresholds/MinMax.cs delete mode 100644 Content.Server/GameTicking/Rules/GameRulePrototype.cs delete mode 100644 Content.Server/Info/InfoSystem.cs delete mode 100644 Content.Server/Info/RulesManager.cs create mode 100644 Content.Server/Spawners/Components/EntityTableSpawnerComponent.cs delete mode 100644 Content.Shared/Alert/AlertCategory.cs create mode 100644 Content.Shared/Alert/AlertCategoryPrototype.cs delete mode 100644 Content.Shared/Alert/AlertType.cs create mode 100644 Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs create mode 100644 Content.Shared/Containers/EntityTableContainerFillComponent.cs create mode 100644 Content.Shared/Destructible/Thresholds/MinMax.cs create mode 100644 Content.Shared/EntityTable/EntitySelectors/AllSelector.cs create mode 100644 Content.Shared/EntityTable/EntitySelectors/EntSelector.cs create mode 100644 Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs create mode 100644 Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs create mode 100644 Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs create mode 100644 Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs create mode 100644 Content.Shared/EntityTable/EntityTablePrototype.cs create mode 100644 Content.Shared/EntityTable/EntityTableSystem.cs create mode 100644 Content.Shared/EntityTable/ValueSelector/ConstantNumberSelector.cs create mode 100644 Content.Shared/EntityTable/ValueSelector/NumberSelector.cs create mode 100644 Content.Shared/EntityTable/ValueSelector/RangeNumberSelector.cs rename {Content.Server => Content.Shared}/GameTicking/Components/ActiveGameRuleComponent.cs (67%) rename {Content.Server => Content.Shared}/GameTicking/Components/DelayedStartRuleComponent.cs (91%) rename {Content.Server => Content.Shared}/GameTicking/Components/EndedGameRuleComponent.cs (61%) rename {Content.Server => Content.Shared}/GameTicking/Components/GameRuleComponent.cs (92%) create mode 100644 Content.Shared/Info/RulesMessages.cs delete mode 100644 Content.Shared/Info/SharedInfo.cs delete mode 100644 Content.Shared/Info/SharedRulesManager.cs rename {Content.Server => Content.Shared}/Shuttles/Components/FTLComponent.cs (81%) create mode 100644 Content.Shared/Shuttles/Components/FtlVisualizerComponent.cs create mode 100644 Resources/Prototypes/Alerts/categories.yml create mode 100644 Resources/Prototypes/Entities/Effects/shuttle.yml create mode 100644 Resources/Prototypes/Guidebook/rules.yml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/BanDurations.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/BanTypes.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC0.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC10AHelp.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC11AhelpThreats.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC12MinAge.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC13CharacterNames.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC14ICinOOC.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC1Admins.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC2DBAD.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC3NoHate.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC4NoERP.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC5Metacomms.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC6BanEvasion.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC7EnglishOnly.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC8Exploits.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC9Multikey.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/DefaultRules.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/README.txt create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleTypes.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR0.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR10Subordination.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11-1AnimalEscalation.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11-2ConflictTypes.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11Escalation.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR12RoleAbandonment.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR13PerformRole.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR14SecComStandard.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR15SpaceLaw.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR1Silicons.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR2Familiars.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR3NormalRP.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR4Metashield.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR5Arrivals.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR6SelfAntag.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR7RoundStalling.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR8NoFriendlyAntag.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR9MassSabotage.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS0.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS10OrderConflicts.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS1Laws.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS2LawPriority.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS3LawRedefinition.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS4RequestChanges.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS5FreeSilicon.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS6UnreasonableOrders.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS7Consistency.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS8DefaultCrewDefinition.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS9DefaultHarmDefinition.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLControlledSubstances.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLRestrictedGear.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLRestrictedWeapons.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SpaceLaw.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/WizDenCoreOnlyRules.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/WizDenLRPRules.xml create mode 100644 Resources/ServerInfo/Guidebook/ServerRules/WizDenMRPRules.xml delete mode 100644 Resources/ServerInfo/Rules.txt create mode 100644 Resources/Textures/Effects/medi_holo.rsi/medi_holo.png create mode 100644 Resources/Textures/Effects/medi_holo.rsi/meta.json diff --git a/Content.Client/Alerts/ClientAlertsSystem.cs b/Content.Client/Alerts/ClientAlertsSystem.cs index 223bf7876ac..359c8957f9d 100644 --- a/Content.Client/Alerts/ClientAlertsSystem.cs +++ b/Content.Client/Alerts/ClientAlertsSystem.cs @@ -91,7 +91,7 @@ private void OnPlayerDetached(EntityUid uid, AlertsComponent component, LocalPla ClearAlerts?.Invoke(this, EventArgs.Empty); } - public void AlertClicked(AlertType alertType) + public void AlertClicked(ProtoId<AlertPrototype> alertType) { RaiseNetworkEvent(new ClickAlertEvent(alertType)); } diff --git a/Content.Client/Audio/AmbientSoundSystem.cs b/Content.Client/Audio/AmbientSoundSystem.cs index 0206017baef..f4e755a013c 100644 --- a/Content.Client/Audio/AmbientSoundSystem.cs +++ b/Content.Client/Audio/AmbientSoundSystem.cs @@ -303,7 +303,11 @@ private void ProcessNearbyAmbience(TransformComponent playerXform) .WithMaxDistance(comp.Range); var stream = _audio.PlayEntity(comp.Sound, Filter.Local(), uid, false, audioParams); - _playingSounds[comp] = (stream.Value.Entity, comp.Sound, key); + + if (stream == null) + continue; + + _playingSounds[comp] = (stream!.Value.Entity, comp.Sound, key); playingCount++; if (_playingSounds.Count >= _maxAmbientCount) diff --git a/Content.Client/Audio/ClientGlobalSoundSystem.cs b/Content.Client/Audio/ClientGlobalSoundSystem.cs index 7c77865f741..6619285a96a 100644 --- a/Content.Client/Audio/ClientGlobalSoundSystem.cs +++ b/Content.Client/Audio/ClientGlobalSoundSystem.cs @@ -67,7 +67,7 @@ private void PlayAdminSound(AdminSoundEvent soundEvent) if(!_adminAudioEnabled) return; var stream = _audio.PlayGlobal(soundEvent.Filename, Filter.Local(), false, soundEvent.AudioParams); - _adminAudio.Add(stream.Value.Entity); + _adminAudio.Add(stream!.Value.Entity); } private void PlayStationEventMusic(StationEventMusicEvent soundEvent) @@ -76,7 +76,7 @@ private void PlayStationEventMusic(StationEventMusicEvent soundEvent) if(!_eventAudioEnabled || _eventAudio.ContainsKey(soundEvent.Type)) return; var stream = _audio.PlayGlobal(soundEvent.Filename, Filter.Local(), false, soundEvent.AudioParams); - _eventAudio.Add(soundEvent.Type, stream.Value.Entity); + _eventAudio.Add(soundEvent.Type, stream!.Value.Entity); } private void PlayGameSound(GameGlobalSoundEvent soundEvent) diff --git a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs index 84b787a4ec9..58cd026da49 100644 --- a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs +++ b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs @@ -210,7 +210,7 @@ private void UpdateAmbientMusic() track.ToString(), Filter.Local(), false, - AudioParams.Default.WithVolume(_musicProto.Sound.Params.Volume + _volumeSlider)); + AudioParams.Default.WithVolume(_musicProto.Sound.Params.Volume + _volumeSlider))!; _ambientMusicStream = strim.Value.Entity; diff --git a/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs b/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs index 92c5b7a4191..60b81b1c2df 100644 --- a/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs +++ b/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs @@ -185,7 +185,11 @@ private void PlaySoundtrack(string soundtrackFilename) false, _lobbySoundtrackParams.WithVolume(_lobbySoundtrackParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume))) ); - if (playResult.Value.Entity == default) + + if (playResult == null) + return; + + 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!", diff --git a/Content.Client/Buckle/BuckleSystem.cs b/Content.Client/Buckle/BuckleSystem.cs index d4614210d9f..4429996aca3 100644 --- a/Content.Client/Buckle/BuckleSystem.cs +++ b/Content.Client/Buckle/BuckleSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Buckle.Components; using Content.Shared.Rotation; using Robust.Client.GameObjects; +using Robust.Shared.GameStates; namespace Content.Client.Buckle; @@ -14,40 +15,63 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent<BuckleComponent, AfterAutoHandleStateEvent>(OnBuckleAfterAutoHandleState); + SubscribeLocalEvent<BuckleComponent, ComponentHandleState>(OnHandleState); SubscribeLocalEvent<BuckleComponent, AppearanceChangeEvent>(OnAppearanceChange); + SubscribeLocalEvent<StrapComponent, MoveEvent>(OnStrapMoveEvent); } - private void OnBuckleAfterAutoHandleState(EntityUid uid, BuckleComponent component, ref AfterAutoHandleStateEvent args) + private void OnStrapMoveEvent(EntityUid uid, StrapComponent component, ref MoveEvent args) { - ActionBlocker.UpdateCanMove(uid); + // I'm moving this to the client-side system, but for the sake of posterity let's keep this comment: + // > This is mega cursed. Please somebody save me from Mr Buckle's wild ride - if (!TryComp<SpriteComponent>(uid, out var ownerSprite)) + // The nice thing is its still true, this is quite cursed, though maybe not omega cursed anymore. + // This code is garbage, it doesn't work with rotated viewports. I need to finally get around to reworking + // sprite rendering for entity layers & direction dependent sorting. + + if (args.NewRotation == args.OldRotation) return; - // Adjust draw depth when the chair faces north so that the seat back is drawn over the player. - // Reset the draw depth when rotated in any other direction. - // TODO when ECSing, make this a visualizer - // This code was written before rotatable viewports were introduced, so hard-coding Direction.North - // and comparing it against LocalRotation now breaks this in other rotations. This is a FIXME, but - // better to get it working for most people before we look at a more permanent solution. - if (component is { Buckled: true, LastEntityBuckledTo: { } } && - Transform(component.LastEntityBuckledTo.Value).LocalRotation.GetCardinalDir() == Direction.North && - TryComp<SpriteComponent>(component.LastEntityBuckledTo, out var buckledSprite)) - { - component.OriginalDrawDepth ??= ownerSprite.DrawDepth; - ownerSprite.DrawDepth = buckledSprite.DrawDepth - 1; + if (!TryComp<SpriteComponent>(uid, out var strapSprite)) return; - } - // If here, we're not turning north and should restore the saved draw depth. - if (component.OriginalDrawDepth.HasValue) + var isNorth = Transform(uid).LocalRotation.GetCardinalDir() == Direction.North; + foreach (var buckledEntity in component.BuckledEntities) { - ownerSprite.DrawDepth = component.OriginalDrawDepth.Value; - component.OriginalDrawDepth = null; + if (!TryComp<BuckleComponent>(buckledEntity, out var buckle)) + continue; + + if (!TryComp<SpriteComponent>(buckledEntity, out var buckledSprite)) + continue; + + if (isNorth) + { + buckle.OriginalDrawDepth ??= buckledSprite.DrawDepth; + buckledSprite.DrawDepth = strapSprite.DrawDepth - 1; + } + else if (buckle.OriginalDrawDepth.HasValue) + { + buckledSprite.DrawDepth = buckle.OriginalDrawDepth.Value; + buckle.OriginalDrawDepth = null; + } } } + private void OnHandleState(Entity<BuckleComponent> ent, ref ComponentHandleState args) + { + if (args.Current is not BuckleState state) + return; + + ent.Comp.DontCollide = state.DontCollide; + ent.Comp.BuckleTime = state.BuckleTime; + var strapUid = EnsureEntity<BuckleComponent>(state.BuckledTo, ent); + + SetBuckledTo(ent, strapUid == null ? null : new (strapUid.Value, null)); + + var (uid, component) = ent; + + } + private void OnAppearanceChange(EntityUid uid, BuckleComponent component, ref AppearanceChangeEvent args) { if (!TryComp<RotationVisualsComponent>(uid, out var rotVisuals) diff --git a/Content.Client/Clickable/ClickableComponent.cs b/Content.Client/Clickable/ClickableComponent.cs index 6f75df46830..da81ed4c841 100644 --- a/Content.Client/Clickable/ClickableComponent.cs +++ b/Content.Client/Clickable/ClickableComponent.cs @@ -1,145 +1,17 @@ -using System.Numerics; -using Robust.Client.GameObjects; -using Robust.Client.Graphics; -using Robust.Client.Utility; -using Robust.Shared.Graphics; -using static Robust.Client.GameObjects.SpriteComponent; -using Direction = Robust.Shared.Maths.Direction; +namespace Content.Client.Clickable; -namespace Content.Client.Clickable +[RegisterComponent] +public sealed partial class ClickableComponent : Component { - [RegisterComponent] - public sealed partial class ClickableComponent : Component - { - [Dependency] private readonly IClickMapManager _clickMapManager = default!; - - [DataField("bounds")] public DirBoundData? Bounds; - - /// <summary> - /// Used to check whether a click worked. Will first check if the click falls inside of some explicit bounding - /// boxes (see <see cref="Bounds"/>). If that fails, attempts to use automatically generated click maps. - /// </summary> - /// <param name="worldPos">The world position that was clicked.</param> - /// <param name="drawDepth"> - /// The draw depth for the sprite that captured the click. - /// </param> - /// <returns>True if the click worked, false otherwise.</returns> - public bool CheckClick(SpriteComponent sprite, TransformComponent transform, EntityQuery<TransformComponent> xformQuery, Vector2 worldPos, IEye eye, out int drawDepth, out uint renderOrder, out float bottom) - { - if (!sprite.Visible) - { - drawDepth = default; - renderOrder = default; - bottom = default; - return false; - } - - drawDepth = sprite.DrawDepth; - renderOrder = sprite.RenderOrder; - var (spritePos, spriteRot) = transform.GetWorldPositionRotation(xformQuery); - var spriteBB = sprite.CalculateRotatedBoundingBox(spritePos, spriteRot, eye.Rotation); - bottom = Matrix3Helpers.CreateRotation(eye.Rotation).TransformBox(spriteBB).Bottom; - - Matrix3x2.Invert(sprite.GetLocalMatrix(), out var invSpriteMatrix); - - // This should have been the rotation of the sprite relative to the screen, but this is not the case with no-rot or directional sprites. - var relativeRotation = (spriteRot + eye.Rotation).Reduced().FlipPositive(); - - Angle cardinalSnapping = sprite.SnapCardinals ? relativeRotation.GetCardinalDir().ToAngle() : Angle.Zero; - - // First we get `localPos`, the clicked location in the sprite-coordinate frame. - var entityXform = Matrix3Helpers.CreateInverseTransform(transform.WorldPosition, sprite.NoRotation ? -eye.Rotation : spriteRot - cardinalSnapping); - var localPos = Vector2.Transform(Vector2.Transform(worldPos, entityXform), invSpriteMatrix); - - // Check explicitly defined click-able bounds - if (CheckDirBound(sprite, relativeRotation, localPos)) - return true; - - // Next check each individual sprite layer using automatically computed click maps. - foreach (var spriteLayer in sprite.AllLayers) - { - if (!spriteLayer.Visible || spriteLayer is not Layer layer) - continue; - - // Check the layer's texture, if it has one - if (layer.Texture != null) - { - // Convert to image coordinates - var imagePos = (Vector2i) (localPos * EyeManager.PixelsPerMeter * new Vector2(1, -1) + layer.Texture.Size / 2f); - - if (_clickMapManager.IsOccluding(layer.Texture, imagePos)) - return true; - } - - // Either we weren't clicking on the texture, or there wasn't one. In which case: check the RSI next - if (layer.ActualRsi is not { } rsi || !rsi.TryGetState(layer.State, out var rsiState)) - continue; - - var dir = Layer.GetDirection(rsiState.RsiDirections, relativeRotation); + [DataField] public DirBoundData? Bounds; - // convert to layer-local coordinates - layer.GetLayerDrawMatrix(dir, out var matrix); - Matrix3x2.Invert(matrix, out var inverseMatrix); - var layerLocal = Vector2.Transform(localPos, inverseMatrix); - - // Convert to image coordinates - var layerImagePos = (Vector2i) (layerLocal * EyeManager.PixelsPerMeter * new Vector2(1, -1) + rsiState.Size / 2f); - - // Next, to get the right click map we need the "direction" of this layer that is actually being used to draw the sprite on the screen. - // This **can** differ from the dir defined before, but can also just be the same. - if (sprite.EnableDirectionOverride) - dir = sprite.DirectionOverride.Convert(rsiState.RsiDirections); - dir = dir.OffsetRsiDir(layer.DirOffset); - - if (_clickMapManager.IsOccluding(layer.ActualRsi!, layer.State, dir, layer.AnimationFrame, layerImagePos)) - return true; - } - - drawDepth = default; - renderOrder = default; - bottom = default; - return false; - } - - public bool CheckDirBound(SpriteComponent sprite, Angle relativeRotation, Vector2 localPos) - { - if (Bounds == null) - return false; - - // These explicit bounds only work for either 1 or 4 directional sprites. - - // This would be the orientation of a 4-directional sprite. - var direction = relativeRotation.GetCardinalDir(); - - var modLocalPos = sprite.NoRotation - ? localPos - : direction.ToAngle().RotateVec(localPos); - - // First, check the bounding box that is valid for all orientations - if (Bounds.All.Contains(modLocalPos)) - return true; - - // Next, get and check the appropriate bounding box for the current sprite orientation - var boundsForDir = (sprite.EnableDirectionOverride ? sprite.DirectionOverride : direction) switch - { - Direction.East => Bounds.East, - Direction.North => Bounds.North, - Direction.South => Bounds.South, - Direction.West => Bounds.West, - _ => throw new InvalidOperationException() - }; - - return boundsForDir.Contains(modLocalPos); - } - - [DataDefinition] - public sealed partial class DirBoundData - { - [DataField("all")] public Box2 All; - [DataField("north")] public Box2 North; - [DataField("south")] public Box2 South; - [DataField("east")] public Box2 East; - [DataField("west")] public Box2 West; - } + [DataDefinition] + public sealed partial class DirBoundData + { + [DataField] public Box2 All; + [DataField] public Box2 North; + [DataField] public Box2 South; + [DataField] public Box2 East; + [DataField] public Box2 West; } } diff --git a/Content.Client/Clickable/ClickableSystem.cs b/Content.Client/Clickable/ClickableSystem.cs new file mode 100644 index 00000000000..15d13df625c --- /dev/null +++ b/Content.Client/Clickable/ClickableSystem.cs @@ -0,0 +1,168 @@ +using System.Numerics; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Utility; +using Robust.Shared.Graphics; + +namespace Content.Client.Clickable; + +/// <summary> +/// Handles click detection for sprites. +/// </summary> +public sealed class ClickableSystem : EntitySystem +{ + [Dependency] private readonly IClickMapManager _clickMapManager = default!; + [Dependency] private readonly SharedTransformSystem _transforms = default!; + [Dependency] private readonly SpriteSystem _sprites = default!; + + private EntityQuery<ClickableComponent> _clickableQuery; + private EntityQuery<TransformComponent> _xformQuery; + + public override void Initialize() + { + base.Initialize(); + _clickableQuery = GetEntityQuery<ClickableComponent>(); + _xformQuery = GetEntityQuery<TransformComponent>(); + } + + /// <summary> + /// Used to check whether a click worked. Will first check if the click falls inside of some explicit bounding + /// boxes (see <see cref="Bounds"/>). If that fails, attempts to use automatically generated click maps. + /// </summary> + /// <param name="worldPos">The world position that was clicked.</param> + /// <param name="drawDepth"> + /// The draw depth for the sprite that captured the click. + /// </param> + /// <returns>True if the click worked, false otherwise.</returns> + public bool CheckClick(Entity<ClickableComponent?, SpriteComponent, TransformComponent?> entity, Vector2 worldPos, IEye eye, out int drawDepth, out uint renderOrder, out float bottom) + { + if (!_clickableQuery.Resolve(entity.Owner, ref entity.Comp1, false)) + { + drawDepth = default; + renderOrder = default; + bottom = default; + return false; + } + + if (!_xformQuery.Resolve(entity.Owner, ref entity.Comp3)) + { + drawDepth = default; + renderOrder = default; + bottom = default; + return false; + } + + var sprite = entity.Comp2; + var transform = entity.Comp3; + + if (!sprite.Visible) + { + drawDepth = default; + renderOrder = default; + bottom = default; + return false; + } + + drawDepth = sprite.DrawDepth; + renderOrder = sprite.RenderOrder; + var (spritePos, spriteRot) = _transforms.GetWorldPositionRotation(transform); + var spriteBB = sprite.CalculateRotatedBoundingBox(spritePos, spriteRot, eye.Rotation); + bottom = Matrix3Helpers.CreateRotation(eye.Rotation).TransformBox(spriteBB).Bottom; + + Matrix3x2.Invert(sprite.GetLocalMatrix(), out var invSpriteMatrix); + + // This should have been the rotation of the sprite relative to the screen, but this is not the case with no-rot or directional sprites. + var relativeRotation = (spriteRot + eye.Rotation).Reduced().FlipPositive(); + + var cardinalSnapping = sprite.SnapCardinals ? relativeRotation.GetCardinalDir().ToAngle() : Angle.Zero; + + // First we get `localPos`, the clicked location in the sprite-coordinate frame. + var entityXform = Matrix3Helpers.CreateInverseTransform(spritePos, sprite.NoRotation ? -eye.Rotation : spriteRot - cardinalSnapping); + var localPos = Vector2.Transform(Vector2.Transform(worldPos, entityXform), invSpriteMatrix); + + // Check explicitly defined click-able bounds + if (CheckDirBound((entity.Owner, entity.Comp1, entity.Comp2), relativeRotation, localPos)) + return true; + + // Next check each individual sprite layer using automatically computed click maps. + foreach (var spriteLayer in sprite.AllLayers) + { + if (spriteLayer is not SpriteComponent.Layer layer || !_sprites.IsVisible(layer)) + { + continue; + } + + // Check the layer's texture, if it has one + if (layer.Texture != null) + { + // Convert to image coordinates + var imagePos = (Vector2i) (localPos * EyeManager.PixelsPerMeter * new Vector2(1, -1) + layer.Texture.Size / 2f); + + if (_clickMapManager.IsOccluding(layer.Texture, imagePos)) + return true; + } + + // Either we weren't clicking on the texture, or there wasn't one. In which case: check the RSI next + if (layer.ActualRsi is not { } rsi || !rsi.TryGetState(layer.State, out var rsiState)) + continue; + + var dir = SpriteComponent.Layer.GetDirection(rsiState.RsiDirections, relativeRotation); + + // convert to layer-local coordinates + layer.GetLayerDrawMatrix(dir, out var matrix); + Matrix3x2.Invert(matrix, out var inverseMatrix); + var layerLocal = Vector2.Transform(localPos, inverseMatrix); + + // Convert to image coordinates + var layerImagePos = (Vector2i) (layerLocal * EyeManager.PixelsPerMeter * new Vector2(1, -1) + rsiState.Size / 2f); + + // Next, to get the right click map we need the "direction" of this layer that is actually being used to draw the sprite on the screen. + // This **can** differ from the dir defined before, but can also just be the same. + if (sprite.EnableDirectionOverride) + dir = sprite.DirectionOverride.Convert(rsiState.RsiDirections); + dir = dir.OffsetRsiDir(layer.DirOffset); + + if (_clickMapManager.IsOccluding(layer.ActualRsi!, layer.State, dir, layer.AnimationFrame, layerImagePos)) + return true; + } + + drawDepth = default; + renderOrder = default; + bottom = default; + return false; + } + + public bool CheckDirBound(Entity<ClickableComponent, SpriteComponent> entity, Angle relativeRotation, Vector2 localPos) + { + var clickable = entity.Comp1; + var sprite = entity.Comp2; + + if (clickable.Bounds == null) + return false; + + // These explicit bounds only work for either 1 or 4 directional sprites. + + // This would be the orientation of a 4-directional sprite. + var direction = relativeRotation.GetCardinalDir(); + + var modLocalPos = sprite.NoRotation + ? localPos + : direction.ToAngle().RotateVec(localPos); + + // First, check the bounding box that is valid for all orientations + if (clickable.Bounds.All.Contains(modLocalPos)) + return true; + + // Next, get and check the appropriate bounding box for the current sprite orientation + var boundsForDir = (sprite.EnableDirectionOverride ? sprite.DirectionOverride : direction) switch + { + Direction.East => clickable.Bounds.East, + Direction.North => clickable.Bounds.North, + Direction.South => clickable.Bounds.South, + Direction.West => clickable.Bounds.West, + _ => throw new InvalidOperationException() + }; + + return boundsForDir.Contains(modLocalPos); + } +} diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs index 1ab213ae0a3..bf5f021be3d 100644 --- a/Content.Client/Entry/EntryPoint.cs +++ b/Content.Client/Entry/EntryPoint.cs @@ -8,7 +8,6 @@ using Content.Client.Fullscreen; using Content.Client.GhostKick; using Content.Client.Guidebook; -using Content.Client.Info; using Content.Client.Input; using Content.Client.IoC; using Content.Client.Launcher; @@ -54,7 +53,6 @@ public sealed class EntryPoint : GameClient [Dependency] private readonly IScreenshotHook _screenshotHook = default!; [Dependency] private readonly FullscreenHook _fullscreenHook = default!; [Dependency] private readonly ChangelogManager _changelogManager = default!; - [Dependency] private readonly RulesManager _rulesManager = default!; [Dependency] private readonly ViewportManager _viewportManager = default!; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; [Dependency] private readonly IInputManager _inputManager = default!; @@ -131,7 +129,6 @@ public override void Init() _screenshotHook.Initialize(); _fullscreenHook.Initialize(); _changelogManager.Initialize(); - _rulesManager.Initialize(); _viewportManager.Initialize(); _ghostKick.Initialize(); _extendedDisconnectInformation.Initialize(); diff --git a/Content.Client/Explosion/ExplosionOverlay.cs b/Content.Client/Explosion/ExplosionOverlay.cs index 8cf7447a5d8..f8f8ae53623 100644 --- a/Content.Client/Explosion/ExplosionOverlay.cs +++ b/Content.Client/Explosion/ExplosionOverlay.cs @@ -29,6 +29,7 @@ public ExplosionOverlay() protected override void Draw(in OverlayDrawArgs args) { + var appearanceSystem = _entMan.System<SharedAppearanceSystem>(); var drawHandle = args.WorldHandle; drawHandle.UseShader(_shader); @@ -41,7 +42,7 @@ protected override void Draw(in OverlayDrawArgs args) if (visuals.Epicenter.MapId != args.MapId) continue; - if (!appearance.TryGetData(ExplosionAppearanceData.Progress, out int index)) + if (!appearanceSystem.TryGetData(appearance.Owner, ExplosionAppearanceData.Progress, out int index)) continue; index = Math.Min(index, visuals.Intensity.Count - 1); diff --git a/Content.Client/Gameplay/GameplayStateBase.cs b/Content.Client/Gameplay/GameplayStateBase.cs index 6236cd8e958..315c053d935 100644 --- a/Content.Client/Gameplay/GameplayStateBase.cs +++ b/Content.Client/Gameplay/GameplayStateBase.cs @@ -2,6 +2,7 @@ using System.Numerics; using Content.Client.Clickable; using Content.Client.UserInterface; +using Content.Client.Viewport; using Content.Shared.Input; using Robust.Client.ComponentTrees; using Robust.Client.GameObjects; @@ -13,11 +14,13 @@ using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.Console; +using Robust.Shared.Graphics; using Robust.Shared.Input; using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Timing; +using YamlDotNet.Serialization.TypeInspectors; namespace Content.Client.Gameplay { @@ -98,7 +101,15 @@ private bool HandleInspect(ICommonSession? session, EntityCoordinates coords, En public EntityUid? GetClickedEntity(MapCoordinates coordinates) { - var first = GetClickableEntities(coordinates).FirstOrDefault(); + return GetClickedEntity(coordinates, _eyeManager.CurrentEye); + } + + public EntityUid? GetClickedEntity(MapCoordinates coordinates, IEye? eye) + { + if (eye == null) + return null; + + var first = GetClickableEntities(coordinates, eye).FirstOrDefault(); return first.IsValid() ? first : null; } @@ -109,6 +120,20 @@ public IEnumerable<EntityUid> GetClickableEntities(EntityCoordinates coordinates public IEnumerable<EntityUid> GetClickableEntities(MapCoordinates coordinates) { + return GetClickableEntities(coordinates, _eyeManager.CurrentEye); + } + + public IEnumerable<EntityUid> GetClickableEntities(MapCoordinates coordinates, IEye? eye) + { + /* + * TODO: + * 1. Stuff like MeleeWeaponSystem need an easy way to hook into viewport specific entities / entities under mouse + * 2. Cleanup the mess around InteractionOutlineSystem + below the keybind click detection. + */ + + if (eye == null) + return Array.Empty<EntityUid>(); + // Find all the entities intersecting our click var spriteTree = _entityManager.EntitySysManager.GetEntitySystem<SpriteTreeSystem>(); var entities = spriteTree.QueryAabb(coordinates.MapId, Box2.CenteredAround(coordinates.Position, new Vector2(1, 1))); @@ -116,15 +141,12 @@ public IEnumerable<EntityUid> GetClickableEntities(MapCoordinates coordinates) // Check the entities against whether or not we can click them var foundEntities = new List<(EntityUid, int, uint, float)>(entities.Count); var clickQuery = _entityManager.GetEntityQuery<ClickableComponent>(); - var xformQuery = _entityManager.GetEntityQuery<TransformComponent>(); - - // TODO: Smelly - var eye = _eyeManager.CurrentEye; + var clickables = _entityManager.System<ClickableSystem>(); foreach (var entity in entities) { if (clickQuery.TryGetComponent(entity.Uid, out var component) && - component.CheckClick(entity.Component, entity.Transform, xformQuery, coordinates.Position, eye, out var drawDepthClicked, out var renderOrder, out var bottom)) + clickables.CheckClick((entity.Uid, component, entity.Component, entity.Transform), coordinates.Position, eye, out var drawDepthClicked, out var renderOrder, out var bottom)) { foundEntities.Add((entity.Uid, drawDepthClicked, renderOrder, bottom)); } @@ -187,7 +209,15 @@ protected virtual void OnKeyBindStateChanged(ViewportBoundKeyEventArgs args) if (args.Viewport is IViewportControl vp) { var mousePosWorld = vp.PixelToMap(kArgs.PointerLocation.Position); - entityToClick = GetClickedEntity(mousePosWorld); + + if (vp is ScalingViewport svp) + { + entityToClick = GetClickedEntity(mousePosWorld, svp.Eye); + } + else + { + entityToClick = GetClickedEntity(mousePosWorld); + } coordinates = _mapManager.TryFindGridAt(mousePosWorld, out _, out var grid) ? grid.MapToGrid(mousePosWorld) : diff --git a/Content.Client/Guidebook/Controls/GuidebookWindow.xaml b/Content.Client/Guidebook/Controls/GuidebookWindow.xaml index 8dbfde3c475..cc6cc6e82b0 100644 --- a/Content.Client/Guidebook/Controls/GuidebookWindow.xaml +++ b/Content.Client/Guidebook/Controls/GuidebookWindow.xaml @@ -18,7 +18,7 @@ Name="SearchBar" PlaceHolder="{Loc 'guidebook-filter-placeholder-text'}" HorizontalExpand="True" - Margin="0 5 10 5"> + Margin="0 5 10 5"> </LineEdit> </BoxContainer> <ScrollContainer Name="Scroll" HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True"> diff --git a/Content.Client/Guidebook/DocumentParsingManager.cs b/Content.Client/Guidebook/DocumentParsingManager.cs index b81866a6260..9c9e569eb41 100644 --- a/Content.Client/Guidebook/DocumentParsingManager.cs +++ b/Content.Client/Guidebook/DocumentParsingManager.cs @@ -2,6 +2,8 @@ using Content.Client.Guidebook.Richtext; using Pidgin; using Robust.Client.UserInterface; +using Robust.Shared.ContentPack; +using Robust.Shared.Prototypes; using Robust.Shared.Reflection; using Robust.Shared.Sandboxing; using static Pidgin.Parser; @@ -13,7 +15,9 @@ namespace Content.Client.Guidebook; /// </summary> public sealed partial class DocumentParsingManager { + [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IReflectionManager _reflectionManager = default!; + [Dependency] private readonly IResourceManager _resourceManager = default!; [Dependency] private readonly ISandboxHelper _sandboxHelper = default!; private readonly Dictionary<string, Parser<char, Control>> _tagControlParsers = new(); @@ -37,6 +41,21 @@ public void Initialize() ControlParser = SkipWhitespaces.Then(_controlParser.Many()); } + public bool TryAddMarkup(Control control, ProtoId<GuideEntryPrototype> entryId, bool log = true) + { + if (!_prototype.TryIndex(entryId, out var entry)) + return false; + + using var file = _resourceManager.ContentFileReadText(entry.Text); + return TryAddMarkup(control, file.ReadToEnd(), log); + } + + public bool TryAddMarkup(Control control, GuideEntry entry, bool log = true) + { + using var file = _resourceManager.ContentFileReadText(entry.Text); + return TryAddMarkup(control, file.ReadToEnd(), log); + } + public bool TryAddMarkup(Control control, string text, bool log = true) { try diff --git a/Content.Client/Info/InfoSystem.cs b/Content.Client/Info/InfoSystem.cs deleted file mode 100644 index b6979949818..00000000000 --- a/Content.Client/Info/InfoSystem.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Content.Shared.Info; -using Robust.Shared.Log; - -namespace Content.Client.Info; - -public sealed class InfoSystem : EntitySystem -{ - public RulesMessage Rules = new RulesMessage("Server Rules", "The server did not send any rules."); - [Dependency] private readonly RulesManager _rules = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeNetworkEvent<RulesMessage>(OnRulesReceived); - Log.Debug("Requested server info."); - RaiseNetworkEvent(new RequestRulesMessage()); - } - - private void OnRulesReceived(RulesMessage message, EntitySessionEventArgs eventArgs) - { - Log.Debug("Received server rules."); - Rules = message; - _rules.UpdateRules(); - } -} diff --git a/Content.Client/Info/RulesAndInfoWindow.cs b/Content.Client/Info/RulesAndInfoWindow.cs index 7a763a1d6f4..b9131dcb3c0 100644 --- a/Content.Client/Info/RulesAndInfoWindow.cs +++ b/Content.Client/Info/RulesAndInfoWindow.cs @@ -1,10 +1,8 @@ using System.Numerics; using Content.Client.UserInterface.Systems.EscapeMenu; -using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; -using Robust.Shared.Configuration; using Robust.Shared.ContentPack; namespace Content.Client.Info @@ -12,7 +10,6 @@ namespace Content.Client.Info public sealed class RulesAndInfoWindow : DefaultWindow { [Dependency] private readonly IResourceManager _resourceManager = default!; - [Dependency] private readonly RulesManager _rules = default!; public RulesAndInfoWindow() { @@ -22,8 +19,14 @@ public RulesAndInfoWindow() var rootContainer = new TabContainer(); - var rulesList = new Info(); - var tutorialList = new Info(); + var rulesList = new RulesControl + { + Margin = new Thickness(10) + }; + var tutorialList = new Info + { + Margin = new Thickness(10) + }; rootContainer.AddChild(rulesList); rootContainer.AddChild(tutorialList); @@ -31,7 +34,6 @@ public RulesAndInfoWindow() TabContainer.SetTabTitle(rulesList, Loc.GetString("ui-info-tab-rules")); TabContainer.SetTabTitle(tutorialList, Loc.GetString("ui-info-tab-tutorial")); - AddSection(rulesList, _rules.RulesSection()); PopulateTutorial(tutorialList); Contents.AddChild(rootContainer); diff --git a/Content.Client/Info/RulesControl.xaml b/Content.Client/Info/RulesControl.xaml index 3b247646884..04fa7191234 100644 --- a/Content.Client/Info/RulesControl.xaml +++ b/Content.Client/Info/RulesControl.xaml @@ -1,6 +1,18 @@ -<BoxContainer xmlns="https://spacestation14.io" - Name="InfoContainer" - Orientation="Vertical" - Margin="2 2 0 0" - SeparationOverride="10" - Access="Public"/> +<BoxContainer xmlns="https://spacestation14.io" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True"> + <Control HorizontalExpand="True" VerticalExpand="True" HorizontalAlignment="Stretch"> + <ScrollContainer Name="Scroll" HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True"> + <BoxContainer Name="RulesContainer" VerticalExpand="True" Margin="0 0 5 0"/> + </ScrollContainer> + <BoxContainer Margin="0 0 15 0" HorizontalExpand="True" HorizontalAlignment="Right"> + <Button Name="BackButton" + Text="{Loc 'ui-rules-button-back'}" + HorizontalAlignment="Right" + VerticalAlignment="Top"/> + <Control MinWidth="5"/> + <Button Name="HomeButton" + Text="{Loc 'ui-rules-button-home'}" + HorizontalAlignment="Right" + VerticalAlignment="Top"/> + </BoxContainer> + </Control> +</BoxContainer> diff --git a/Content.Client/Info/RulesControl.xaml.cs b/Content.Client/Info/RulesControl.xaml.cs index 6086735e0ea..5e259074968 100644 --- a/Content.Client/Info/RulesControl.xaml.cs +++ b/Content.Client/Info/RulesControl.xaml.cs @@ -1,22 +1,53 @@ -using System.IO; -using Content.Shared.CCVar; +using Content.Client.Guidebook; +using Content.Client.Guidebook.RichText; +using Content.Client.UserInterface.Systems.Info; using Robust.Client.AutoGenerated; -using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; -using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; namespace Content.Client.Info; [GenerateTypedNameReferences] -public sealed partial class RulesControl : BoxContainer +public sealed partial class RulesControl : BoxContainer, ILinkClickHandler { - [Dependency] private readonly RulesManager _rules = default!; + [Dependency] private readonly DocumentParsingManager _parsingMan = default!; + + private string? _currentEntry; + private readonly Stack<string> _priorEntries = new(); public RulesControl() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - AddChild(_rules.RulesSection()); + + SetGuide(); + + HomeButton.OnPressed += _ => SetGuide(); + + BackButton.OnPressed += _ => SetGuide(_priorEntries.Pop(), false); + } + + public void HandleClick(string link) + { + SetGuide(link); + } + + private void SetGuide(ProtoId<GuideEntryPrototype>? entry = null, bool addToPrior = true) + { + var coreEntry = UserInterfaceManager.GetUIController<InfoUIController>().GetCoreRuleEntry(); + entry ??= coreEntry; + + Scroll.SetScrollValue(default); + RulesContainer.Children.Clear(); + if (!_parsingMan.TryAddMarkup(RulesContainer, entry.Value)) + return; + + if (addToPrior && _currentEntry != null) + _priorEntries.Push(_currentEntry); + _currentEntry = entry.Value; + + HomeButton.Visible = entry.Value != coreEntry.Id; + BackButton.Visible = _priorEntries.Count != 0 && _priorEntries.Peek() != entry.Value; } } diff --git a/Content.Client/Info/RulesManager.cs b/Content.Client/Info/RulesManager.cs deleted file mode 100644 index 76e7c34e5f2..00000000000 --- a/Content.Client/Info/RulesManager.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Content.Client.Lobby; -using Content.Client.Gameplay; -using Content.Shared.CCVar; -using Content.Shared.Info; -using Robust.Client.Console; -using Robust.Client.State; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Shared.Configuration; -using Robust.Shared.Network; - -namespace Content.Client.Info; - -public sealed class RulesManager : SharedRulesManager -{ - [Dependency] private readonly IConfigurationManager _configManager = default!; - [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; - [Dependency] private readonly IStateManager _stateManager = default!; - [Dependency] private readonly IClientConsoleHost _consoleHost = default!; - [Dependency] private readonly INetManager _netManager = default!; - [Dependency] private readonly IEntitySystemManager _sysMan = default!; - - private InfoSection rulesSection = new InfoSection("", "", false); - private bool _shouldShowRules = false; - - private RulesPopup? _activePopup; - - public void Initialize() - { - _netManager.RegisterNetMessage<ShouldShowRulesPopupMessage>(OnShouldShowRules); - _netManager.RegisterNetMessage<ShowRulesPopupMessage>(OnShowRulesPopupMessage); - _netManager.RegisterNetMessage<RulesAcceptedMessage>(); - _stateManager.OnStateChanged += OnStateChanged; - - _consoleHost.RegisterCommand("fuckrules", "", "", (_, _, _) => - { - OnAcceptPressed(); - }); - } - - private void OnShouldShowRules(ShouldShowRulesPopupMessage message) - { - _shouldShowRules = true; - } - - private void OnShowRulesPopupMessage(ShowRulesPopupMessage message) - { - ShowRules(message.PopupTime); - } - - private void OnStateChanged(StateChangedEventArgs args) - { - if (args.NewState is not (GameplayState or LobbyState)) - return; - - if (!_shouldShowRules) - return; - - _shouldShowRules = false; - - ShowRules(_configManager.GetCVar(CCVars.RulesWaitTime)); - } - - private void ShowRules(float time) - { - if (_activePopup != null) - return; - - _activePopup = new RulesPopup - { - Timer = time - }; - - _activePopup.OnQuitPressed += OnQuitPressed; - _activePopup.OnAcceptPressed += OnAcceptPressed; - _userInterfaceManager.WindowRoot.AddChild(_activePopup); - LayoutContainer.SetAnchorPreset(_activePopup, LayoutContainer.LayoutPreset.Wide); - } - - private void OnQuitPressed() - { - _consoleHost.ExecuteCommand("quit"); - } - - private void OnAcceptPressed() - { - _netManager.ClientSendMessage(new RulesAcceptedMessage()); - - _activePopup?.Orphan(); - _activePopup = null; - } - - public void UpdateRules() - { - var rules = _sysMan.GetEntitySystem<InfoSystem>().Rules; - rulesSection.SetText(rules.Title, rules.Text, true); - } - - public Control RulesSection() - { - rulesSection = new InfoSection("", "", false); - UpdateRules(); - return rulesSection; - } -} diff --git a/Content.Client/Info/RulesPopup.xaml b/Content.Client/Info/RulesPopup.xaml index dc004af5a2b..ca1e35f08ed 100644 --- a/Content.Client/Info/RulesPopup.xaml +++ b/Content.Client/Info/RulesPopup.xaml @@ -5,20 +5,20 @@ MouseFilter="Stop"> <parallax:ParallaxControl /> <Control VerticalExpand="True" - MaxWidth="650"> + MaxWidth="800" + MaxHeight="900"> <PanelContainer StyleClasses="windowPanel" /> - <ScrollContainer HScrollEnabled="False"> - <BoxContainer Orientation="Vertical" SeparationOverride="10"> - <info:RulesControl /> + <BoxContainer Orientation="Vertical" SeparationOverride="10" Margin="10 10 5 10"> + <info:RulesControl/> <Label Name="WaitLabel" /> <BoxContainer Orientation="Horizontal"> <Button Name="AcceptButton" Text="{Loc 'ui-rules-accept'}" Disabled="True" /> <Button Name="QuitButton" + StyleClasses="Caution" Text="{Loc 'ui-escape-quit'}" /> </BoxContainer> </BoxContainer> - </ScrollContainer> </Control> </Control> diff --git a/Content.Client/Info/RulesPopup.xaml.cs b/Content.Client/Info/RulesPopup.xaml.cs index 1e090049366..d770b83dc23 100644 --- a/Content.Client/Info/RulesPopup.xaml.cs +++ b/Content.Client/Info/RulesPopup.xaml.cs @@ -1,9 +1,7 @@ -using System; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; -using Robust.Shared.Localization; using Robust.Shared.Timing; namespace Content.Client.Info; diff --git a/Content.Client/IoC/ClientContentIoC.cs b/Content.Client/IoC/ClientContentIoC.cs index 8c2b676c2e2..80c04cda044 100644 --- a/Content.Client/IoC/ClientContentIoC.cs +++ b/Content.Client/IoC/ClientContentIoC.cs @@ -6,7 +6,6 @@ using Content.Client.JoinQueue; using Content.Client.Eui; using Content.Client.GhostKick; -using Content.Client.Info; using Content.Client.Launcher; using Content.Client.Parallax.Managers; using Content.Client.Players.PlayTimeTracking; @@ -31,26 +30,25 @@ public static void Register() { var collection = IoCManager.Instance!; - IoCManager.Register<IParallaxManager, ParallaxManager>(); - IoCManager.Register<IChatManager, ChatManager>(); - IoCManager.Register<IClientPreferencesManager, ClientPreferencesManager>(); - IoCManager.Register<IStylesheetManager, StylesheetManager>(); - IoCManager.Register<IScreenshotHook, ScreenshotHook>(); - IoCManager.Register<FullscreenHook, FullscreenHook>(); - IoCManager.Register<IClickMapManager, ClickMapManager>(); - IoCManager.Register<IClientAdminManager, ClientAdminManager>(); - IoCManager.Register<ISharedAdminManager, ClientAdminManager>(); - IoCManager.Register<EuiManager, EuiManager>(); - IoCManager.Register<IVoteManager, VoteManager>(); - IoCManager.Register<ChangelogManager, ChangelogManager>(); - IoCManager.Register<RulesManager, RulesManager>(); - IoCManager.Register<ViewportManager, ViewportManager>(); - IoCManager.Register<ISharedAdminLogManager, SharedAdminLogManager>(); - IoCManager.Register<GhostKickManager>(); - IoCManager.Register<ExtendedDisconnectInformationManager>(); - IoCManager.Register<JobRequirementsManager>(); - IoCManager.Register<DocumentParsingManager>(); - IoCManager.Register<ContentReplayPlaybackManager, ContentReplayPlaybackManager>(); + collection.Register<IParallaxManager, ParallaxManager>(); + collection.Register<IChatManager, ChatManager>(); + collection.Register<IClientPreferencesManager, ClientPreferencesManager>(); + collection.Register<IStylesheetManager, StylesheetManager>(); + collection.Register<IScreenshotHook, ScreenshotHook>(); + collection.Register<FullscreenHook, FullscreenHook>(); + collection.Register<IClickMapManager, ClickMapManager>(); + collection.Register<IClientAdminManager, ClientAdminManager>(); + collection.Register<ISharedAdminManager, ClientAdminManager>(); + collection.Register<EuiManager, EuiManager>(); + collection.Register<IVoteManager, VoteManager>(); + collection.Register<ChangelogManager, ChangelogManager>(); + collection.Register<ViewportManager, ViewportManager>(); + collection.Register<ISharedAdminLogManager, SharedAdminLogManager>(); + collection.Register<GhostKickManager>(); + collection.Register<ExtendedDisconnectInformationManager>(); + collection.Register<JobRequirementsManager>(); + collection.Register<DocumentParsingManager>(); + collection.Register<ContentReplayPlaybackManager, ContentReplayPlaybackManager>(); collection.Register<ISharedPlaytimeManager, JobRequirementsManager>(); IoCManager.Register<JoinQueueManager>(); IoCManager.Register<DiscordAuthManager>(); diff --git a/Content.Client/Movement/Systems/WaddleAnimationSystem.cs b/Content.Client/Movement/Systems/WaddleAnimationSystem.cs index 9555c1f6b9e..9b45e445fbb 100644 --- a/Content.Client/Movement/Systems/WaddleAnimationSystem.cs +++ b/Content.Client/Movement/Systems/WaddleAnimationSystem.cs @@ -32,7 +32,7 @@ public override void Initialize() SubscribeLocalEvent<WaddleAnimationComponent, AnimationCompletedEvent>(OnAnimationCompleted); SubscribeLocalEvent<WaddleAnimationComponent, StunnedEvent>(OnStunned); SubscribeLocalEvent<WaddleAnimationComponent, KnockedDownEvent>(OnKnockedDown); - SubscribeLocalEvent<WaddleAnimationComponent, BuckleChangeEvent>(OnBuckleChange); + SubscribeLocalEvent<WaddleAnimationComponent, BuckledEvent>(OnBuckled); } private void OnMovementInput(EntityUid entity, WaddleAnimationComponent component, MoveInputEvent args) @@ -148,7 +148,7 @@ private void OnKnockedDown(EntityUid uid, WaddleAnimationComponent component, Kn StopWaddling(uid, component); } - private void OnBuckleChange(EntityUid uid, WaddleAnimationComponent component, BuckleChangeEvent args) + private void OnBuckled(EntityUid uid, WaddleAnimationComponent component, BuckledEvent args) { StopWaddling(uid, component); } diff --git a/Content.Client/Nyanotrasen/Kitchen/Visualizers/DeepFriedVisualizer.cs b/Content.Client/Nyanotrasen/Kitchen/Visualizers/DeepFriedVisualizer.cs index 97fea3d0ca9..c5f0123bddb 100644 --- a/Content.Client/Nyanotrasen/Kitchen/Visualizers/DeepFriedVisualizer.cs +++ b/Content.Client/Nyanotrasen/Kitchen/Visualizers/DeepFriedVisualizer.cs @@ -11,6 +11,7 @@ namespace Content.Client.Kitchen.Visualizers { public sealed class DeepFriedVisualizerSystem : VisualizerSystem<DeepFriedComponent> { + [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; private readonly static string ShaderName = "Crispy"; public override void Initialize() @@ -26,7 +27,7 @@ protected override void OnAppearanceChange(EntityUid uid, DeepFriedComponent com if (args.Sprite == null) return; - if (!args.Component.TryGetData(DeepFriedVisuals.Fried, out bool isFried)) + if (!_appearanceSystem.TryGetData(uid, DeepFriedVisuals.Fried, out bool isFried)) return; for (var i = 0; i < args.Sprite.AllLayers.Count(); ++i) diff --git a/Content.Client/Nyanotrasen/Kitchen/Visualizers/DeepFryerVisualizer.cs b/Content.Client/Nyanotrasen/Kitchen/Visualizers/DeepFryerVisualizer.cs index 5d208d09598..ae7a89d6869 100644 --- a/Content.Client/Nyanotrasen/Kitchen/Visualizers/DeepFryerVisualizer.cs +++ b/Content.Client/Nyanotrasen/Kitchen/Visualizers/DeepFryerVisualizer.cs @@ -9,9 +9,11 @@ namespace Content.Client.Kitchen.Visualizers { public sealed class DeepFryerVisualizerSystem : VisualizerSystem<DeepFryerComponent> { + [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; + protected override void OnAppearanceChange(EntityUid uid, DeepFryerComponent component, ref AppearanceChangeEvent args) { - if (!args.Component.TryGetData(DeepFryerVisuals.Bubbling, out bool isBubbling) || + if (!_appearanceSystem.TryGetData(uid, DeepFryerVisuals.Bubbling, out bool isBubbling) || !TryComp<SolutionContainerVisualsComponent>(uid, out var scvComponent)) { return; diff --git a/Content.Client/Nyanotrasen/Mail/MailSystem.cs b/Content.Client/Nyanotrasen/Mail/MailSystem.cs index c8d764a22f4..de63d74099b 100644 --- a/Content.Client/Nyanotrasen/Mail/MailSystem.cs +++ b/Content.Client/Nyanotrasen/Mail/MailSystem.cs @@ -28,13 +28,14 @@ public sealed class MailJobVisualizerSystem : VisualizerSystem<MailComponent> [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SpriteSystem _stateManager = default!; [Dependency] private readonly SpriteSystem _spriteSystem = default!; + [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; protected override void OnAppearanceChange(EntityUid uid, MailComponent component, ref AppearanceChangeEvent args) { if (args.Sprite == null) return; - args.Component.TryGetData(MailVisuals.JobIcon, out string job); + _appearanceSystem.TryGetData(uid, MailVisuals.JobIcon, out string job); if (string.IsNullOrEmpty(job)) job = "JobIconUnknown"; diff --git a/Content.Client/Outline/InteractionOutlineSystem.cs b/Content.Client/Outline/InteractionOutlineSystem.cs index 3dbbafbcaa3..40cb5dfd4a6 100644 --- a/Content.Client/Outline/InteractionOutlineSystem.cs +++ b/Content.Client/Outline/InteractionOutlineSystem.cs @@ -110,11 +110,15 @@ public override void FrameUpdate(float frameTime) && _inputManager.MouseScreenPosition.IsValid) { var mousePosWorld = vp.PixelToMap(_inputManager.MouseScreenPosition.Position); - entityToClick = screen.GetClickedEntity(mousePosWorld); if (vp is ScalingViewport svp) { renderScale = svp.CurrentRenderScale; + entityToClick = screen.GetClickedEntity(mousePosWorld, svp.Eye); + } + else + { + entityToClick = screen.GetClickedEntity(mousePosWorld); } } else if (_uiManager.CurrentlyHovered is EntityMenuElement element) diff --git a/Content.Client/Revenant/RevenantSystem.cs b/Content.Client/Revenant/RevenantSystem.cs index 49d29d8a5f4..e050fe35aa2 100644 --- a/Content.Client/Revenant/RevenantSystem.cs +++ b/Content.Client/Revenant/RevenantSystem.cs @@ -1,5 +1,4 @@ using Content.Client.Alerts; -using Content.Shared.Alert; using Content.Shared.Revenant; using Content.Shared.Revenant.Components; using Robust.Client.GameObjects; @@ -42,7 +41,7 @@ private void OnAppearanceChange(EntityUid uid, RevenantComponent component, ref private void OnUpdateAlert(Entity<RevenantComponent> ent, ref UpdateAlertSpriteEvent args) { - if (args.Alert.AlertType != AlertType.Essence) + if (args.Alert.ID != ent.Comp.EssenceAlert) return; var sprite = args.SpriteViewEnt.Comp; diff --git a/Content.Client/Sandbox/SandboxSystem.cs b/Content.Client/Sandbox/SandboxSystem.cs index 6a1129bb75d..b4b7d854412 100644 --- a/Content.Client/Sandbox/SandboxSystem.cs +++ b/Content.Client/Sandbox/SandboxSystem.cs @@ -92,7 +92,7 @@ public bool Copy(ICommonSession? session, EntityCoordinates coords, EntityUid ui && EntityManager.TryGetComponent(uid, out MetaDataComponent? comp) && !comp.EntityDeleted) { - if (comp.EntityPrototype == null || comp.EntityPrototype.NoSpawn || comp.EntityPrototype.Abstract) + if (comp.EntityPrototype == null || comp.EntityPrototype.HideSpawnMenu || comp.EntityPrototype.Abstract) return false; if (_placement.Eraser) diff --git a/Content.Client/Shuttles/FtlArrivalOverlay.cs b/Content.Client/Shuttles/FtlArrivalOverlay.cs new file mode 100644 index 00000000000..f24a1e96488 --- /dev/null +++ b/Content.Client/Shuttles/FtlArrivalOverlay.cs @@ -0,0 +1,82 @@ +using System.Numerics; +using Content.Shared.Shuttles.Components; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Shared.Enums; +using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Client.Shuttles; + +/// <summary> +/// Plays a visualization whenever a shuttle is arriving from FTL. +/// </summary> +public sealed class FtlArrivalOverlay : Overlay +{ + public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowEntities; + + private EntityLookupSystem _lookups; + private SharedMapSystem _maps; + private SharedTransformSystem _transforms; + private SpriteSystem _sprites; + [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPrototypeManager _protos = default!; + + private readonly HashSet<Entity<FtlVisualizerComponent>> _visualizers = new(); + + private ShaderInstance _shader; + + public FtlArrivalOverlay() + { + IoCManager.InjectDependencies(this); + _lookups = _entManager.System<EntityLookupSystem>(); + _transforms = _entManager.System<SharedTransformSystem>(); + _maps = _entManager.System<SharedMapSystem>(); + _sprites = _entManager.System<SpriteSystem>(); + + _shader = _protos.Index<ShaderPrototype>("unshaded").Instance(); + } + + protected override bool BeforeDraw(in OverlayDrawArgs args) + { + _visualizers.Clear(); + _lookups.GetEntitiesOnMap(args.MapId, _visualizers); + + return _visualizers.Count > 0; + } + + protected override void Draw(in OverlayDrawArgs args) + { + args.WorldHandle.UseShader(_shader); + + foreach (var (uid, comp) in _visualizers) + { + var grid = comp.Grid; + + if (!_entManager.TryGetComponent(grid, out MapGridComponent? mapGrid)) + continue; + + var texture = _sprites.GetFrame(comp.Sprite, TimeSpan.FromSeconds(comp.Elapsed), loop: false); + comp.Elapsed += (float) _timing.FrameTime.TotalSeconds; + + // Need to manually transform the viewport in terms of the visualizer entity as the grid isn't in position. + var (_, _, worldMatrix, invMatrix) = _transforms.GetWorldPositionRotationMatrixWithInv(uid); + args.WorldHandle.SetTransform(worldMatrix); + var localAABB = invMatrix.TransformBox(args.WorldBounds); + + var tilesEnumerator = _maps.GetLocalTilesEnumerator(grid, mapGrid, localAABB); + + while (tilesEnumerator.MoveNext(out var tile)) + { + var bounds = _lookups.GetLocalBounds(tile, mapGrid.TileSize); + + args.WorldHandle.DrawTextureRect(texture, bounds); + } + } + + args.WorldHandle.UseShader(null); + args.WorldHandle.SetTransform(Matrix3x2.Identity); + } +} diff --git a/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs b/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs index d5154a87bef..73c11de2795 100644 --- a/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs +++ b/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs @@ -38,9 +38,8 @@ public bool EnableShuttlePosition private bool _enableShuttlePosition; private EmergencyShuttleOverlay? _overlay; - public override void Initialize() + private void InitializeEmergency() { - base.Initialize(); SubscribeNetworkEvent<EmergencyShuttlePositionMessage>(OnShuttlePosMessage); } diff --git a/Content.Client/Shuttles/Systems/ShuttleSystem.cs b/Content.Client/Shuttles/Systems/ShuttleSystem.cs new file mode 100644 index 00000000000..a2c048ff90e --- /dev/null +++ b/Content.Client/Shuttles/Systems/ShuttleSystem.cs @@ -0,0 +1,21 @@ +using Robust.Client.Graphics; + +namespace Content.Client.Shuttles.Systems; + +public sealed partial class ShuttleSystem +{ + [Dependency] private readonly IOverlayManager _overlays = default!; + + public override void Initialize() + { + base.Initialize(); + InitializeEmergency(); + _overlays.AddOverlay(new FtlArrivalOverlay()); + } + + public override void Shutdown() + { + base.Shutdown(); + _overlays.RemoveOverlay<FtlArrivalOverlay>(); + } +} diff --git a/Content.Client/Traits/ParacusiaSystem.cs b/Content.Client/Traits/ParacusiaSystem.cs index d01c7c0005c..da60f1d65e1 100644 --- a/Content.Client/Traits/ParacusiaSystem.cs +++ b/Content.Client/Traits/ParacusiaSystem.cs @@ -68,9 +68,13 @@ private void PlayParacusiaSounds(EntityUid uid) ); var newCoords = Transform(uid).Coordinates.Offset(randomOffset); + var sound = _audio.PlayStatic(paracusia.Sounds, uid, newCoords); + + if (sound == null) + return; // Play the sound - paracusia.Stream = _audio.PlayStatic(paracusia.Sounds, uid, newCoords).Value.Entity; + paracusia.Stream = sound!.Value.Entity; } } diff --git a/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs b/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs index 3b85972a9b2..5c195120389 100644 --- a/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs +++ b/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs @@ -7,6 +7,7 @@ using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controllers; +using Robust.Shared.Prototypes; namespace Content.Client.UserInterface.Systems.Alerts; @@ -43,7 +44,7 @@ private void OnScreenLoad() SyncAlerts(); } - private void OnAlertPressed(object? sender, AlertType e) + private void OnAlertPressed(object? sender, ProtoId<AlertPrototype> e) { _alertsSystem?.AlertClicked(e); } diff --git a/Content.Client/UserInterface/Systems/Alerts/Widgets/AlertsUI.xaml.cs b/Content.Client/UserInterface/Systems/Alerts/Widgets/AlertsUI.xaml.cs index a1a494c47b3..d6a79a81c46 100644 --- a/Content.Client/UserInterface/Systems/Alerts/Widgets/AlertsUI.xaml.cs +++ b/Content.Client/UserInterface/Systems/Alerts/Widgets/AlertsUI.xaml.cs @@ -4,6 +4,7 @@ using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Input; +using Robust.Shared.Prototypes; namespace Content.Client.UserInterface.Systems.Alerts.Widgets; @@ -21,8 +22,10 @@ public AlertsUI() RobustXamlLoader.Load(this); } - public void SyncControls(AlertsSystem alertsSystem, AlertOrderPrototype? alertOrderPrototype, - IReadOnlyDictionary<AlertKey, AlertState> alertStates) + public void SyncControls(AlertsSystem alertsSystem, + AlertOrderPrototype? alertOrderPrototype, + IReadOnlyDictionary<AlertKey, + AlertState> alertStates) { // remove any controls with keys no longer present if (SyncRemoveControls(alertStates)) @@ -46,7 +49,7 @@ public void ClearAllControls() _alertControls.Clear(); } - public event EventHandler<AlertType>? AlertPressed; + public event EventHandler<ProtoId<AlertPrototype>>? AlertPressed; private bool SyncRemoveControls(IReadOnlyDictionary<AlertKey, AlertState> alertStates) { @@ -88,7 +91,7 @@ private void SyncUpdateControls(AlertsSystem alertsSystem, AlertOrderPrototype? } if (_alertControls.TryGetValue(newAlert.AlertKey, out var existingAlertControl) && - existingAlertControl.Alert.AlertType == newAlert.AlertType) + existingAlertControl.Alert.ID == newAlert.ID) { // key is the same, simply update the existing control severity / cooldown existingAlertControl.SetSeverity(alertState.Severity); @@ -155,6 +158,6 @@ private void AlertControlPressed(BaseButton.ButtonEventArgs args) if (args.Event.Function != EngineKeyFunctions.UIClick) return; - AlertPressed?.Invoke(this, control.Alert.AlertType); + AlertPressed?.Invoke(this, control.Alert.ID); } } diff --git a/Content.Client/UserInterface/Systems/Info/InfoUIController.cs b/Content.Client/UserInterface/Systems/Info/InfoUIController.cs index d7f2d8e5fed..6d398ec6aa5 100644 --- a/Content.Client/UserInterface/Systems/Info/InfoUIController.cs +++ b/Content.Client/UserInterface/Systems/Info/InfoUIController.cs @@ -1,13 +1,73 @@ -using Content.Client.Gameplay; +using System.Globalization; +using Content.Client.Gameplay; +using Content.Client.Guidebook; using Content.Client.Info; +using Content.Shared.Administration.Managers; +using Content.Shared.CCVar; +using Content.Shared.Info; +using Robust.Client; +using Robust.Client.Console; +using Robust.Client.Player; using Robust.Client.UserInterface.Controllers; +using Robust.Client.UserInterface.Controls; +using Robust.Shared.Configuration; +using Robust.Shared.Network; +using Robust.Shared.Prototypes; namespace Content.Client.UserInterface.Systems.Info; public sealed class InfoUIController : UIController, IOnStateExited<GameplayState> { + [Dependency] private readonly IBaseClient _client = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IClientConsoleHost _consoleHost = default!; + [Dependency] private readonly INetManager _netManager = default!; + [Dependency] private readonly ISharedAdminManager _adminManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + + private RulesPopup? _rulesPopup; private RulesAndInfoWindow? _infoWindow; + private static DateTime NextRulesReadTime => DateTime.UtcNow + TimeSpan.FromDays(60); + + public override void Initialize() + { + base.Initialize(); + + _client.PlayerJoinedServer += OnJoinedServer; + _netManager.RegisterNetMessage<ShowRulesPopupMessage>(OnShowRulesPopupMessage); + + _consoleHost.RegisterCommand("fuckrules", + "", + "", + (_, _, _) => + { + OnAcceptPressed(); + }); + } + + private void OnJoinedServer(object? sender, PlayerEventArgs args) + { + if (_playerManager.LocalSession is not { } localSession) + return; + + if (_adminManager.IsAdmin(localSession) && _cfg.GetCVar(CCVars.RulesExemptLocal)) + return; + + var nextReadTarget = DateTime.Parse(_cfg.GetCVar(CCVars.RulesNextPopupTime)); + if (nextReadTarget >= DateTime.UtcNow) + return; + + var time = _cfg.GetCVar(CCVars.RulesWaitTime); + ShowRules(time); + } + + private void OnShowRulesPopupMessage(ShowRulesPopupMessage message) + { + ShowRules(message.PopupTime); + } + public void OnStateExited(GameplayState state) { if (_infoWindow == null) @@ -17,12 +77,47 @@ public void OnStateExited(GameplayState state) _infoWindow = null; } + private void ShowRules(float time) + { + if (_rulesPopup != null) + return; + + _rulesPopup = new RulesPopup + { + Timer = time + }; + + _rulesPopup.OnQuitPressed += OnQuitPressed; + _rulesPopup.OnAcceptPressed += OnAcceptPressed; + UIManager.WindowRoot.AddChild(_rulesPopup); + LayoutContainer.SetAnchorPreset(_rulesPopup, LayoutContainer.LayoutPreset.Wide); + } + + private void OnQuitPressed() + { + _consoleHost.ExecuteCommand("quit"); + } + + private void OnAcceptPressed() + { + _cfg.SetCVar(CCVars.RulesNextPopupTime, NextRulesReadTime.ToString(CultureInfo.InvariantCulture)); + _cfg.SaveToFile(); + + _rulesPopup?.Orphan(); + _rulesPopup = null; + } + + public GuideEntryPrototype GetCoreRuleEntry() + { + var guide = _cfg.GetCVar(CCVars.RulesFile); + var guideEntryPrototype = _prototype.Index<GuideEntryPrototype>(guide); + return guideEntryPrototype; + } + public void OpenWindow() { if (_infoWindow == null || _infoWindow.Disposed) - { _infoWindow = UIManager.CreateWindow<RulesAndInfoWindow>(); - } _infoWindow?.OpenCentered(); } diff --git a/Content.Client/UserInterface/Systems/Storage/Controls/ItemGridPiece.cs b/Content.Client/UserInterface/Systems/Storage/Controls/ItemGridPiece.cs index f436cc8c39b..dd9986e4c6e 100644 --- a/Content.Client/UserInterface/Systems/Storage/Controls/ItemGridPiece.cs +++ b/Content.Client/UserInterface/Systems/Storage/Controls/ItemGridPiece.cs @@ -9,7 +9,7 @@ namespace Content.Client.UserInterface.Systems.Storage.Controls; -public sealed class ItemGridPiece : Control +public sealed class ItemGridPiece : Control, IEntityControl { private readonly IEntityManager _entityManager; private readonly StorageUIController _storageController; @@ -287,6 +287,8 @@ public static Vector2 GetCenterOffset(Entity<ItemComponent?> entity, ItemStorage var actualSize = new Vector2(boxSize.X + 1, boxSize.Y + 1); return actualSize * new Vector2i(8, 8); } + + public EntityUid? UiEntity => Entity; } public enum ItemGridPieceMarks diff --git a/Content.Client/Weather/WeatherSystem.cs b/Content.Client/Weather/WeatherSystem.cs index 24de0bc8c4c..64ce64415d9 100644 --- a/Content.Client/Weather/WeatherSystem.cs +++ b/Content.Client/Weather/WeatherSystem.cs @@ -2,16 +2,11 @@ using Content.Shared.Weather; using Robust.Client.Audio; using Robust.Client.GameObjects; -using Robust.Client.Graphics; using Robust.Client.Player; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Systems; using Robust.Shared.Player; using AudioComponent = Robust.Shared.Audio.Components.AudioComponent; @@ -52,7 +47,8 @@ protected override void Run(EntityUid uid, WeatherData weather, WeatherPrototype if (!Timing.IsFirstTimePredicted || weatherProto.Sound == null) return; - weather.Stream ??= _audio.PlayGlobal(weatherProto.Sound, Filter.Local(), true).Value.Entity; + var playStream = _audio.PlayGlobal(weatherProto.Sound, Filter.Local(), true); + weather.Stream ??= playStream!.Value.Entity; var stream = weather.Stream.Value; var comp = Comp<AudioComponent>(stream); @@ -124,9 +120,9 @@ protected override void Run(EntityUid uid, WeatherData weather, WeatherPrototype comp.Occlusion = occlusion; } - protected override bool SetState(WeatherState state, WeatherComponent comp, WeatherData weather, WeatherPrototype weatherProto) + protected override bool SetState(EntityUid uid, WeatherState state, WeatherComponent comp, WeatherData weather, WeatherPrototype weatherProto) { - if (!base.SetState(state, comp, weather, weatherProto)) + if (!base.SetState(uid, state, comp, weather, weatherProto)) return false; if (!Timing.IsFirstTimePredicted) @@ -164,7 +160,7 @@ private void OnWeatherHandleState(EntityUid uid, WeatherComponent component, ref continue; // New weather - StartWeather(component, ProtoMan.Index<WeatherPrototype>(proto), weather.EndTime); + StartWeather(uid, component, ProtoMan.Index<WeatherPrototype>(proto), weather.EndTime); } } } diff --git a/Content.IntegrationTests/Tests/Actions/ActionPvsDetachTest.cs b/Content.IntegrationTests/Tests/Actions/ActionPvsDetachTest.cs index 420a90a50bd..45addff00bf 100644 --- a/Content.IntegrationTests/Tests/Actions/ActionPvsDetachTest.cs +++ b/Content.IntegrationTests/Tests/Actions/ActionPvsDetachTest.cs @@ -32,11 +32,14 @@ public async Task TestActionDetach() // PVS-detach action entities // We do this by just giving them the ghost layer var visSys = server.System<VisibilitySystem>(); - var enumerator = server.Transform(ent).ChildEnumerator; - while (enumerator.MoveNext(out var child)) + server.Post(() => { - visSys.AddLayer(child, (int) VisibilityFlags.Ghost); - } + var enumerator = server.Transform(ent).ChildEnumerator; + while (enumerator.MoveNext(out var child)) + { + visSys.AddLayer(child, (int) VisibilityFlags.Ghost); + } + }); await pair.RunTicksSync(5); // Client's actions have left been detached / are out of view, but action comp state has not changed @@ -44,11 +47,14 @@ public async Task TestActionDetach() Assert.That(cSys.GetActions(cEnt).Count(), Is.EqualTo(initActions)); // Re-enter PVS view - enumerator = server.Transform(ent).ChildEnumerator; - while (enumerator.MoveNext(out var child)) + server.Post(() => { - visSys.RemoveLayer(child, (int) VisibilityFlags.Ghost); - } + var enumerator = server.Transform(ent).ChildEnumerator; + while (enumerator.MoveNext(out var child)) + { + visSys.RemoveLayer(child, (int) VisibilityFlags.Ghost); + } + }); await pair.RunTicksSync(5); Assert.That(sys.GetActions(ent).Count(), Is.EqualTo(initActions)); Assert.That(cSys.GetActions(cEnt).Count(), Is.EqualTo(initActions)); diff --git a/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs b/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs index 32b15252261..c232e823132 100644 --- a/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs +++ b/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs @@ -18,7 +18,7 @@ public sealed class ActionsAddedTest [Test] public async Task TestCombatActionsAdded() { - await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, DummyTicker = false}); + await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, DummyTicker = false }); var server = pair.Server; var client = pair.Client; var sEntMan = server.ResolveDependency<IEntityManager>(); diff --git a/Content.IntegrationTests/Tests/Body/GibTest.cs b/Content.IntegrationTests/Tests/Body/GibTest.cs index c0032a85244..4627c79f64d 100644 --- a/Content.IntegrationTests/Tests/Body/GibTest.cs +++ b/Content.IntegrationTests/Tests/Body/GibTest.cs @@ -5,7 +5,7 @@ namespace Content.IntegrationTests.Tests.Body; [TestFixture] -public sealed class GibTest +public sealed class GibTest { [Test] public async Task TestGib() diff --git a/Content.IntegrationTests/Tests/Body/LegTest.cs b/Content.IntegrationTests/Tests/Body/LegTest.cs index e86966f8f54..7b49bbe84a3 100644 --- a/Content.IntegrationTests/Tests/Body/LegTest.cs +++ b/Content.IntegrationTests/Tests/Body/LegTest.cs @@ -5,7 +5,6 @@ using Content.Shared.Rotation; using Robust.Shared.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Maths; namespace Content.IntegrationTests.Tests.Body { @@ -40,13 +39,14 @@ public async Task RemoveLegsFallTest() var appearanceSystem = entityManager.System<SharedAppearanceSystem>(); var xformSystem = entityManager.System<SharedTransformSystem>(); + var map = await pair.CreateTestMap(); + await server.WaitAssertion(() => { - var mapId = mapManager.CreateMap(); BodyComponent body = null; human = entityManager.SpawnEntity("HumanBodyAndAppearanceDummy", - new MapCoordinates(Vector2.Zero, mapId)); + new MapCoordinates(Vector2.Zero, map.MapId)); Assert.Multiple(() => { @@ -61,7 +61,7 @@ await server.WaitAssertion(() => foreach (var leg in legs) { - xformSystem.DetachParentToNull(leg.Id, entityManager.GetComponent<TransformComponent>(leg.Id)); + xformSystem.DetachEntity(leg.Id, entityManager.GetComponent<TransformComponent>(leg.Id)); } }); diff --git a/Content.IntegrationTests/Tests/Body/LungTest.cs b/Content.IntegrationTests/Tests/Body/LungTest.cs index dce3741c98d..9b5ee431f1f 100644 --- a/Content.IntegrationTests/Tests/Body/LungTest.cs +++ b/Content.IntegrationTests/Tests/Body/LungTest.cs @@ -60,8 +60,8 @@ public async Task AirConsistencyTest() var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); var mapLoader = entityManager.System<MapLoaderSystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); - MapId mapId; EntityUid? grid = null; BodyComponent body = default; RespiratorComponent resp = default; @@ -73,7 +73,7 @@ public async Task AirConsistencyTest() await server.WaitPost(() => { - mapId = mapManager.CreateMap(); + mapSys.CreateMap(out var mapId); Assert.That(mapLoader.TryLoad(mapId, testMapName, out var roots)); var query = entityManager.GetEntityQuery<MapGridComponent>(); @@ -142,8 +142,8 @@ public async Task NoSuffocationTest() var entityManager = server.ResolveDependency<IEntityManager>(); var cfg = server.ResolveDependency<IConfigurationManager>(); var mapLoader = entityManager.System<MapLoaderSystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); - MapId mapId; EntityUid? grid = null; RespiratorComponent respirator = null; EntityUid human = default; @@ -152,7 +152,7 @@ public async Task NoSuffocationTest() await server.WaitPost(() => { - mapId = mapManager.CreateMap(); + mapSys.CreateMap(out var mapId); Assert.That(mapLoader.TryLoad(mapId, testMapName, out var ents), Is.True); var query = entityManager.GetEntityQuery<MapGridComponent>(); diff --git a/Content.IntegrationTests/Tests/Body/SaveLoadReparentTest.cs b/Content.IntegrationTests/Tests/Body/SaveLoadReparentTest.cs index 670ce1a474d..01482ba8ee2 100644 --- a/Content.IntegrationTests/Tests/Body/SaveLoadReparentTest.cs +++ b/Content.IntegrationTests/Tests/Body/SaveLoadReparentTest.cs @@ -33,10 +33,11 @@ public async Task Test() var mapLoader = entities.System<MapLoaderSystem>(); var bodySystem = entities.System<SharedBodySystem>(); var containerSystem = entities.System<SharedContainerSystem>(); + var mapSys = entities.System<SharedMapSystem>(); await server.WaitAssertion(() => { - var mapId = maps.CreateMap(); + mapSys.CreateMap(out var mapId); maps.CreateGrid(mapId); var human = entities.SpawnEntity("HumanBodyDummy", new MapCoordinates(0, 0, mapId)); @@ -115,7 +116,7 @@ await server.WaitAssertion(() => mapLoader.SaveMap(mapId, mapPath); maps.DeleteMap(mapId); - mapId = maps.CreateMap(); + mapSys.CreateMap(out mapId); Assert.That(mapLoader.TryLoad(mapId, mapPath, out _), Is.True); var query = EnumerateQueryEnumerator( diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleDragTest.cs b/Content.IntegrationTests/Tests/Buckle/BuckleDragTest.cs new file mode 100644 index 00000000000..19e8aba1824 --- /dev/null +++ b/Content.IntegrationTests/Tests/Buckle/BuckleDragTest.cs @@ -0,0 +1,60 @@ +using Content.IntegrationTests.Tests.Interaction; +using Content.Shared.Buckle; +using Content.Shared.Buckle.Components; +using Content.Shared.Input; +using Content.Shared.Movement.Pulling.Components; + +namespace Content.IntegrationTests.Tests.Buckle; + +public sealed class BuckleDragTest : InteractionTest +{ + // Check that dragging a buckled player unbuckles them. + [Test] + public async Task BucklePullTest() + { + var urist = await SpawnTarget("MobHuman"); + var sUrist = ToServer(urist); + await SpawnTarget("Chair"); + + var buckle = Comp<BuckleComponent>(urist); + var strap = Comp<StrapComponent>(Target); + var puller = Comp<PullerComponent>(Player); + var pullable = Comp<PullableComponent>(urist); + +#pragma warning disable RA0002 + buckle.Delay = TimeSpan.Zero; +#pragma warning restore RA0002 + + // Initially not buckled to the chair and not pulling anything + Assert.That(buckle.Buckled, Is.False); + Assert.That(buckle.BuckledTo, Is.Null); + Assert.That(strap.BuckledEntities, Is.Empty); + Assert.That(puller.Pulling, Is.Null); + Assert.That(pullable.Puller, Is.Null); + Assert.That(pullable.BeingPulled, Is.False); + + // Strap the human to the chair + await Server.WaitAssertion(() => + { + Assert.That(Server.System<SharedBuckleSystem>().TryBuckle(sUrist, SPlayer, STarget.Value)); + }); + + await RunTicks(5); + Assert.That(buckle.Buckled, Is.True); + Assert.That(buckle.BuckledTo, Is.EqualTo(STarget)); + Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[] { sUrist })); + Assert.That(puller.Pulling, Is.Null); + Assert.That(pullable.Puller, Is.Null); + Assert.That(pullable.BeingPulled, Is.False); + + // Start pulling, and thus unbuckle them + await PressKey(ContentKeyFunctions.TryPullObject, cursorEntity: urist); + await RunTicks(5); + Assert.That(buckle.Buckled, Is.False); + Assert.That(buckle.BuckledTo, Is.Null); + Assert.That(strap.BuckledEntities, Is.Empty); + Assert.That(puller.Pulling, Is.EqualTo(sUrist)); + Assert.That(pullable.Puller, Is.EqualTo(SPlayer)); + Assert.That(pullable.BeingPulled, Is.True); + } +} diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs new file mode 100644 index 00000000000..d9cce764ab7 --- /dev/null +++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs @@ -0,0 +1,108 @@ +using Content.Shared.Buckle; +using Content.Shared.Buckle.Components; +using Content.Shared.Interaction; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; + +namespace Content.IntegrationTests.Tests.Buckle; + +public sealed partial class BuckleTest +{ + [Test] + public async Task BuckleInteractUnbuckleOther() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.ResolveDependency<IServerEntityManager>(); + var buckleSystem = entMan.System<SharedBuckleSystem>(); + + EntityUid user = default; + EntityUid victim = default; + EntityUid chair = default; + BuckleComponent buckle = null; + StrapComponent strap = null; + + await server.WaitAssertion(() => + { + user = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace); + victim = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace); + chair = entMan.SpawnEntity(StrapDummyId, MapCoordinates.Nullspace); + + Assert.That(entMan.TryGetComponent(victim, out buckle)); + Assert.That(entMan.TryGetComponent(chair, out strap)); + +#pragma warning disable RA0002 + buckle.Delay = TimeSpan.Zero; +#pragma warning restore RA0002 + + // Buckle victim to chair + Assert.That(buckleSystem.TryBuckle(victim, user, chair, buckle)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.EqualTo(chair), "Victim did not get buckled to the chair."); + Assert.That(buckle.Buckled, "Victim is not buckled."); + Assert.That(strap.BuckledEntities, Does.Contain(victim), "Chair does not have victim buckled to it."); + }); + + // InteractHand with chair to unbuckle victim + entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.Null); + Assert.That(buckle.Buckled, Is.False); + Assert.That(strap.BuckledEntities, Does.Not.Contain(victim)); + }); + }); + + await pair.CleanReturnAsync(); + } + + [Test] + public async Task BuckleInteractBuckleUnbuckleSelf() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.ResolveDependency<IServerEntityManager>(); + + EntityUid user = default; + EntityUid chair = default; + BuckleComponent buckle = null; + StrapComponent strap = null; + + await server.WaitAssertion(() => + { + user = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace); + chair = entMan.SpawnEntity(StrapDummyId, MapCoordinates.Nullspace); + + Assert.That(entMan.TryGetComponent(user, out buckle)); + Assert.That(entMan.TryGetComponent(chair, out strap)); + +#pragma warning disable RA0002 + buckle.Delay = TimeSpan.Zero; +#pragma warning restore RA0002 + + // Buckle user to chair + entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.EqualTo(chair), "Victim did not get buckled to the chair."); + Assert.That(buckle.Buckled, "Victim is not buckled."); + Assert.That(strap.BuckledEntities, Does.Contain(user), "Chair does not have victim buckled to it."); + }); + + // InteractHand with chair to unbuckle + entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.Null); + Assert.That(buckle.Buckled, Is.False); + Assert.That(strap.BuckledEntities, Does.Not.Contain(user)); + }); + }); + + await pair.CleanReturnAsync(); + } +} diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs index 7c700d9fb8a..94572da4989 100644 --- a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs +++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs @@ -15,7 +15,7 @@ namespace Content.IntegrationTests.Tests.Buckle [TestFixture] [TestOf(typeof(BuckleComponent))] [TestOf(typeof(StrapComponent))] - public sealed class BuckleTest + public sealed partial class BuckleTest { private const string BuckleDummyId = "BuckleDummy"; private const string StrapDummyId = "StrapDummy"; @@ -90,7 +90,6 @@ await server.WaitAssertion(() => { Assert.That(strap, Is.Not.Null); Assert.That(strap.BuckledEntities, Is.Empty); - Assert.That(strap.OccupiedSize, Is.Zero); }); // Side effects of buckling @@ -110,8 +109,6 @@ await server.WaitAssertion(() => // Side effects of buckling for the strap Assert.That(strap.BuckledEntities, Does.Contain(human)); - Assert.That(strap.OccupiedSize, Is.EqualTo(buckle.Size)); - Assert.That(strap.OccupiedSize, Is.Positive); }); #pragma warning disable NUnit2045 // Interdependent asserts. @@ -121,7 +118,7 @@ await server.WaitAssertion(() => // Trying to unbuckle too quickly fails Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False); Assert.That(buckle.Buckled); - Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False); + Assert.That(buckleSystem.TryUnbuckle(human, human), Is.False); Assert.That(buckle.Buckled); #pragma warning restore NUnit2045 }); @@ -148,7 +145,6 @@ await server.WaitAssertion(() => // Unbuckle, strap Assert.That(strap.BuckledEntities, Is.Empty); - Assert.That(strap.OccupiedSize, Is.Zero); }); #pragma warning disable NUnit2045 // Interdependent asserts. @@ -159,9 +155,9 @@ await server.WaitAssertion(() => // On cooldown Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False); Assert.That(buckle.Buckled); - Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False); + Assert.That(buckleSystem.TryUnbuckle(human, human), Is.False); Assert.That(buckle.Buckled); - Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False); + Assert.That(buckleSystem.TryUnbuckle(human, human), Is.False); Assert.That(buckle.Buckled); #pragma warning restore NUnit2045 }); @@ -188,7 +184,6 @@ await server.WaitAssertion(() => #pragma warning disable NUnit2045 // Interdependent asserts. Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle), Is.False); Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False); - Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False); #pragma warning restore NUnit2045 // Move near the chair @@ -201,12 +196,10 @@ await server.WaitAssertion(() => Assert.That(buckle.Buckled); Assert.That(buckleSystem.TryUnbuckle(human, human, buckleComp: buckle), Is.False); Assert.That(buckle.Buckled); - Assert.That(buckleSystem.ToggleBuckle(human, human, chair, buckle: buckle), Is.False); - Assert.That(buckle.Buckled); #pragma warning restore NUnit2045 // Force unbuckle - Assert.That(buckleSystem.TryUnbuckle(human, human, true, buckleComp: buckle)); + buckleSystem.Unbuckle(human, human); Assert.Multiple(() => { Assert.That(buckle.Buckled, Is.False); @@ -310,7 +303,7 @@ await server.WaitAssertion(() => // Break our guy's kneecaps foreach (var leg in legs) { - xformSystem.DetachParentToNull(leg.Id, entityManager.GetComponent<TransformComponent>(leg.Id)); + entityManager.DeleteEntity(leg.Id); } }); @@ -327,7 +320,8 @@ await server.WaitAssertion(() => Assert.That(hand.HeldEntity, Is.Null); } - buckleSystem.TryUnbuckle(human, human, true, buckleComp: buckle); + buckleSystem.Unbuckle(human, human); + Assert.That(buckle.Buckled, Is.False); }); await pair.CleanReturnAsync(); diff --git a/Content.IntegrationTests/Tests/CargoTest.cs b/Content.IntegrationTests/Tests/CargoTest.cs index 09f179cf4f5..99160df3c66 100644 --- a/Content.IntegrationTests/Tests/CargoTest.cs +++ b/Content.IntegrationTests/Tests/CargoTest.cs @@ -14,11 +14,11 @@ namespace Content.IntegrationTests.Tests; [TestFixture] public sealed class CargoTest { - public static HashSet<ProtoId<CargoProductPrototype>> Ignored = new () - { + private static readonly HashSet<ProtoId<CargoProductPrototype>> Ignored = + [ // This is ignored because it is explicitly intended to be able to sell for more than it costs. new("FunCrateGambling") - }; + ]; [Test] public async Task NoCargoOrderArbitrage() @@ -174,13 +174,16 @@ public async Task StackPrice() { await using var pair = await PoolManager.GetServerClient(); var server = pair.Server; - var entManager = server.ResolveDependency<IEntityManager>(); - var priceSystem = entManager.System<PricingSystem>(); - var ent = entManager.SpawnEntity("StackEnt", MapCoordinates.Nullspace); - var price = priceSystem.GetPrice(ent); - Assert.That(price, Is.EqualTo(100.0)); + await server.WaitAssertion(() => + { + var priceSystem = entManager.System<PricingSystem>(); + + var ent = entManager.SpawnEntity("StackEnt", MapCoordinates.Nullspace); + var price = priceSystem.GetPrice(ent); + Assert.That(price, Is.EqualTo(100.0)); + }); await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/Chemistry/DispenserTest.cs b/Content.IntegrationTests/Tests/Chemistry/DispenserTest.cs index a5449308be4..52b7e555a9d 100644 --- a/Content.IntegrationTests/Tests/Chemistry/DispenserTest.cs +++ b/Content.IntegrationTests/Tests/Chemistry/DispenserTest.cs @@ -18,7 +18,7 @@ public async Task InsertEjectBuiTest() ToggleNeedPower(); // Insert beaker - await Interact("Beaker"); + await InteractUsing("Beaker"); Assert.That(Hands.ActiveHandEntity, Is.Null); // Open BUI diff --git a/Content.IntegrationTests/Tests/Chemistry/FixedPoint2SerializationTest.cs b/Content.IntegrationTests/Tests/Chemistry/FixedPoint2SerializationTest.cs index 8e3b89bff11..0e3f89c2825 100644 --- a/Content.IntegrationTests/Tests/Chemistry/FixedPoint2SerializationTest.cs +++ b/Content.IntegrationTests/Tests/Chemistry/FixedPoint2SerializationTest.cs @@ -9,10 +9,10 @@ namespace Content.IntegrationTests.Tests.Chemistry { public sealed class FixedPoint2SerializationTest : SerializationTest { - protected override Assembly[] Assemblies => new[] - { + protected override Assembly[] Assemblies => + [ typeof(FixedPoint2SerializationTest).Assembly - }; + ]; [Test] public void DeserializeNullTest() @@ -53,6 +53,6 @@ public void DeserializeNullDefinitionTest() [DataDefinition] public sealed partial class FixedPoint2TestDefinition { - [DataField("unit")] public FixedPoint2? Unit { get; set; } = FixedPoint2.New(5); + [DataField] public FixedPoint2? Unit { get; set; } = FixedPoint2.New(5); } } diff --git a/Content.IntegrationTests/Tests/Chemistry/SolutionRoundingTest.cs b/Content.IntegrationTests/Tests/Chemistry/SolutionRoundingTest.cs index 4d19a96d9e7..89d33186a27 100644 --- a/Content.IntegrationTests/Tests/Chemistry/SolutionRoundingTest.cs +++ b/Content.IntegrationTests/Tests/Chemistry/SolutionRoundingTest.cs @@ -1,5 +1,5 @@ -using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; @@ -76,7 +76,7 @@ public async Task Test() await server.WaitPost(() => { - var system = server.System<SolutionContainerSystem>(); + var system = server.System<SharedSolutionContainerSystem>(); var beaker = server.EntMan.SpawnEntity("SolutionRoundingTestContainer", testMap.GridCoords); system.TryGetSolution(beaker, "beaker", out var newSolutionEnt, out var newSolution); diff --git a/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs b/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs index d96a035b2dc..6b71dd08be0 100644 --- a/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs +++ b/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs @@ -1,5 +1,5 @@ -using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.EntitySystems; using Content.Shared.FixedPoint; using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; @@ -11,7 +11,7 @@ namespace Content.IntegrationTests.Tests.Chemistry; // To ensure volume(A) + volume(B) = volume(A+B) // reactions can change this assumption [TestFixture] -[TestOf(typeof(SolutionContainerSystem))] +[TestOf(typeof(SharedSolutionContainerSystem))] public sealed class SolutionSystemTests { [TestPrototypes] @@ -51,7 +51,7 @@ public async Task TryAddTwoNonReactiveReagent() var entityManager = server.ResolveDependency<IEntityManager>(); var protoMan = server.ResolveDependency<IPrototypeManager>(); - var containerSystem = entityManager.System<SolutionContainerSystem>(); + var containerSystem = entityManager.System<SharedSolutionContainerSystem>(); var testMap = await pair.CreateTestMap(); var coordinates = testMap.GridCoords; @@ -97,7 +97,7 @@ public async Task TryAddTooMuchNonReactiveReagent() var entityManager = server.ResolveDependency<IEntityManager>(); var protoMan = server.ResolveDependency<IPrototypeManager>(); - var containerSystem = entityManager.System<SolutionContainerSystem>(); + var containerSystem = entityManager.System<SharedSolutionContainerSystem>(); var coordinates = testMap.GridCoords; EntityUid beaker; @@ -141,7 +141,7 @@ public async Task TryMixAndOverflowTooMuchReagent() var entityManager = server.ResolveDependency<IEntityManager>(); var protoMan = server.ResolveDependency<IPrototypeManager>(); var testMap = await pair.CreateTestMap(); - var containerSystem = entityManager.System<SolutionContainerSystem>(); + var containerSystem = entityManager.System<SharedSolutionContainerSystem>(); var coordinates = testMap.GridCoords; EntityUid beaker; @@ -194,7 +194,7 @@ public async Task TryMixAndOverflowTooBigOverflow() var entityManager = server.ResolveDependency<IEntityManager>(); var protoMan = server.ResolveDependency<IPrototypeManager>(); - var containerSystem = entityManager.System<SolutionContainerSystem>(); + var containerSystem = entityManager.System<SharedSolutionContainerSystem>(); var testMap = await pair.CreateTestMap(); var coordinates = testMap.GridCoords; diff --git a/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs index ddfe7b3481e..3664cda922a 100644 --- a/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs +++ b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs @@ -1,4 +1,3 @@ -using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Components; using Robust.Shared.GameObjects; @@ -6,6 +5,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Utility; using System.Linq; +using Content.Shared.Chemistry.EntitySystems; namespace Content.IntegrationTests.Tests.Chemistry { @@ -34,7 +34,7 @@ public async Task TryAllTest() var prototypeManager = server.ResolveDependency<IPrototypeManager>(); var testMap = await pair.CreateTestMap(); var coordinates = testMap.GridCoords; - var solutionContainerSystem = entityManager.System<SolutionContainerSystem>(); + var solutionContainerSystem = entityManager.System<SharedSolutionContainerSystem>(); foreach (var reactionPrototype in prototypeManager.EnumeratePrototypes<ReactionPrototype>()) { diff --git a/Content.IntegrationTests/Tests/ClickableTest.cs b/Content.IntegrationTests/Tests/ClickableTest.cs index 76085381852..59836509081 100644 --- a/Content.IntegrationTests/Tests/ClickableTest.cs +++ b/Content.IntegrationTests/Tests/ClickableTest.cs @@ -52,7 +52,6 @@ public async Task<bool> Test(string prototype, float clickPosX, float clickPosY, var serverEntManager = server.ResolveDependency<IEntityManager>(); var eyeManager = client.ResolveDependency<IEyeManager>(); var spriteQuery = clientEntManager.GetEntityQuery<SpriteComponent>(); - var xformQuery = clientEntManager.GetEntityQuery<TransformComponent>(); var eye = client.ResolveDependency<IEyeManager>().CurrentEye; var testMap = await pair.CreateTestMap(); @@ -80,9 +79,8 @@ await client.WaitPost(() => eyeManager.CurrentEye.Rotation = 0; var pos = clientEntManager.System<SharedTransformSystem>().GetWorldPosition(clientEnt); - var clickable = clientEntManager.GetComponent<ClickableComponent>(clientEnt); - hit = clickable.CheckClick(sprite, xformQuery.GetComponent(clientEnt), xformQuery, new Vector2(clickPosX, clickPosY) + pos, eye, out _, out _, out _); + hit = clientEntManager.System<ClickableSystem>().CheckClick((clientEnt, null, sprite, null), new Vector2(clickPosX, clickPosY) + pos, eye, out _, out _, out _); }); await server.WaitPost(() => diff --git a/Content.IntegrationTests/Tests/Climbing/ClimbingTest.cs b/Content.IntegrationTests/Tests/Climbing/ClimbingTest.cs index d8d3086520e..2db0a9acd3d 100644 --- a/Content.IntegrationTests/Tests/Climbing/ClimbingTest.cs +++ b/Content.IntegrationTests/Tests/Climbing/ClimbingTest.cs @@ -1,5 +1,6 @@ #nullable enable using Content.IntegrationTests.Tests.Interaction; +using Content.IntegrationTests.Tests.Movement; using Robust.Shared.Maths; using ClimbingComponent = Content.Shared.Climbing.Components.ClimbingComponent; using ClimbSystem = Content.Shared.Climbing.Systems.ClimbSystem; diff --git a/Content.IntegrationTests/Tests/Commands/PardonCommand.cs b/Content.IntegrationTests/Tests/Commands/PardonCommand.cs index b3a66e3211c..4db9eabf5c6 100644 --- a/Content.IntegrationTests/Tests/Commands/PardonCommand.cs +++ b/Content.IntegrationTests/Tests/Commands/PardonCommand.cs @@ -28,7 +28,7 @@ public async Task PardonTest() Assert.That(netMan.IsConnected); - Assert.That(sPlayerManager.Sessions.Count(), Is.EqualTo(1)); + Assert.That(sPlayerManager.Sessions, Has.Length.EqualTo(1)); // No bans on record Assert.Multiple(async () => { @@ -50,7 +50,7 @@ public async Task PardonTest() var banReason = "test"; - Assert.That(sPlayerManager.Sessions.Count(), Is.EqualTo(1)); + Assert.That(sPlayerManager.Sessions, Has.Length.EqualTo(1)); // Ban the client for 24 hours await server.WaitPost(() => sConsole.ExecuteCommand($"ban {clientSession.Name} {banReason} 1440")); @@ -63,7 +63,7 @@ public async Task PardonTest() }); await pair.RunTicksSync(5); - Assert.That(sPlayerManager.Sessions.Count(), Is.EqualTo(0)); + Assert.That(sPlayerManager.Sessions, Has.Length.EqualTo(0)); Assert.That(!netMan.IsConnected); // Try to pardon a ban that does not exist @@ -143,11 +143,11 @@ public async Task PardonTest() }); // Reconnect client. Slightly faster than dirtying the pair. - Assert.That(sPlayerManager.Sessions.Count(), Is.EqualTo(0)); + Assert.That(sPlayerManager.Sessions, Is.Empty); client.SetConnectTarget(server); await client.WaitPost(() => netMan.ClientConnect(null!, 0, null!)); await pair.RunTicksSync(5); - Assert.That(sPlayerManager.Sessions.Count(), Is.EqualTo(1)); + Assert.That(sPlayerManager.Sessions, Has.Length.EqualTo(1)); await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs b/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs index 2fda3ad58e6..cfc80073066 100644 --- a/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs +++ b/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs @@ -37,9 +37,9 @@ public async Task RejuvenateDeadTest() var server = pair.Server; var entManager = server.ResolveDependency<IEntityManager>(); var prototypeManager = server.ResolveDependency<IPrototypeManager>(); - var mobStateSystem = entManager.EntitySysManager.GetEntitySystem<MobStateSystem>(); - var damSystem = entManager.EntitySysManager.GetEntitySystem<DamageableSystem>(); - var rejuvenateSystem = entManager.EntitySysManager.GetEntitySystem<RejuvenateSystem>(); + var mobStateSystem = entManager.System<MobStateSystem>(); + var damSystem = entManager.System<DamageableSystem>(); + var rejuvenateSystem = entManager.System<RejuvenateSystem>(); await server.WaitAssertion(() => { diff --git a/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs b/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs index 74d014b7724..b94cd7807cf 100644 --- a/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs +++ b/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs @@ -25,7 +25,7 @@ public async Task RestartRoundAfterStart(bool lobbyEnabled) var configManager = server.ResolveDependency<IConfigurationManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); - var gameTicker = entityManager.EntitySysManager.GetEntitySystem<GameTicker>(); + var gameTicker = entityManager.System<GameTicker>(); await pair.RunTicksSync(5); diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/ComputerContruction.cs b/Content.IntegrationTests/Tests/Construction/Interaction/ComputerContruction.cs index 5412469ac5d..8af5edaf316 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/ComputerContruction.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/ComputerContruction.cs @@ -16,10 +16,8 @@ public async Task ConstructComputer() await StartConstruction(Computer); // Initial interaction (ghost turns into real entity) - await Interact(Steel, 5); - ClientAssertPrototype(ComputerFrame, ClientTarget); - Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()]; - ClientTarget = null; + await InteractUsing(Steel, 5); + ClientAssertPrototype(ComputerFrame, Target); // Perform construction steps await Interact( @@ -41,7 +39,7 @@ public async Task DeconstructComputer() await StartDeconstruction(ComputerId); // Initial interaction turns id computer into generic computer - await Interact(Screw); + await InteractUsing(Screw); AssertPrototype(ComputerFrame); // Perform deconstruction steps @@ -71,7 +69,7 @@ public async Task ChangeComputer() await SpawnTarget(ComputerId); // Initial interaction turns id computer into generic computer - await Interact(Screw); + await InteractUsing(Screw); AssertPrototype(ComputerFrame); // Perform partial deconstruction steps diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/CraftingTests.cs b/Content.IntegrationTests/Tests/Construction/Interaction/CraftingTests.cs index 76911eba5f7..74d0e924217 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/CraftingTests.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/CraftingTests.cs @@ -59,11 +59,6 @@ public async Task CraftSpear() await AssertEntityLookup((Rod, 2), (Cable, 7), (ShardGlass, 2), (Spear, 1)); } - // The following is wrapped in an if DEBUG. This is because of cursed state handling bugs. Tests don't (de)serialize - // net messages and just copy objects by reference. This means that the server will directly modify cached server - // states on the client's end. Crude fix at the moment is to used modified state handling while in debug mode - // Otherwise, this test cannot work. -#if DEBUG /// <summary> /// Cancel crafting a complex recipe. /// </summary> @@ -93,28 +88,22 @@ public async Task CancelCraft() await RunTicks(1); // DoAfter is in progress. Entity not spawned, stacks have been split and someingredients are in a container. - Assert.Multiple(async () => - { - Assert.That(ActiveDoAfters.Count(), Is.EqualTo(1)); - Assert.That(sys.IsEntityInContainer(shard), Is.True); - Assert.That(sys.IsEntityInContainer(rods), Is.False); - Assert.That(sys.IsEntityInContainer(wires), Is.False); - Assert.That(rodStack, Has.Count.EqualTo(8)); - Assert.That(wireStack, Has.Count.EqualTo(7)); + Assert.That(ActiveDoAfters.Count(), Is.EqualTo(1)); + Assert.That(sys.IsEntityInContainer(shard), Is.True); + Assert.That(sys.IsEntityInContainer(rods), Is.False); + Assert.That(sys.IsEntityInContainer(wires), Is.False); + Assert.That(rodStack, Has.Count.EqualTo(8)); + Assert.That(wireStack, Has.Count.EqualTo(7)); - await FindEntity(Spear, shouldSucceed: false); - }); + await FindEntity(Spear, shouldSucceed: false); // Cancel the DoAfter. Should drop ingredients to the floor. await CancelDoAfters(); - Assert.Multiple(async () => - { - Assert.That(sys.IsEntityInContainer(rods), Is.False); - Assert.That(sys.IsEntityInContainer(wires), Is.False); - Assert.That(sys.IsEntityInContainer(shard), Is.False); - await FindEntity(Spear, shouldSucceed: false); - await AssertEntityLookup((Rod, 10), (Cable, 10), (ShardGlass, 1)); - }); + Assert.That(sys.IsEntityInContainer(rods), Is.False); + Assert.That(sys.IsEntityInContainer(wires), Is.False); + Assert.That(sys.IsEntityInContainer(shard), Is.False); + await FindEntity(Spear, shouldSucceed: false); + await AssertEntityLookup((Rod, 10), (Cable, 10), (ShardGlass, 1)); // Re-attempt the do-after #pragma warning disable CS4014 // Legacy construction code uses DoAfterAwait. See above. @@ -123,24 +112,17 @@ public async Task CancelCraft() await RunTicks(1); // DoAfter is in progress. Entity not spawned, ingredients are in a container. - Assert.Multiple(async () => - { - Assert.That(ActiveDoAfters.Count(), Is.EqualTo(1)); - Assert.That(sys.IsEntityInContainer(shard), Is.True); - await FindEntity(Spear, shouldSucceed: false); - }); + Assert.That(ActiveDoAfters.Count(), Is.EqualTo(1)); + Assert.That(sys.IsEntityInContainer(shard), Is.True); + await FindEntity(Spear, shouldSucceed: false); // Finish the DoAfter await AwaitDoAfters(); // Spear has been crafted. Rods and wires are no longer contained. Glass has been consumed. - Assert.Multiple(async () => - { - await FindEntity(Spear); - Assert.That(sys.IsEntityInContainer(rods), Is.False); - Assert.That(sys.IsEntityInContainer(wires), Is.False); - Assert.That(SEntMan.Deleted(shard)); - }); + await FindEntity(Spear); + Assert.That(sys.IsEntityInContainer(rods), Is.False); + Assert.That(sys.IsEntityInContainer(wires), Is.False); + Assert.That(SEntMan.Deleted(shard)); } -#endif } diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/GrilleWindowConstruction.cs b/Content.IntegrationTests/Tests/Construction/Interaction/GrilleWindowConstruction.cs index 0de39d27577..ef6a7b09ae3 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/GrilleWindowConstruction.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/GrilleWindowConstruction.cs @@ -17,17 +17,14 @@ public async Task WindowOnGrille() { // Construct Grille await StartConstruction(Grille); - await Interact(Rod, 10); - ClientAssertPrototype(Grille, ClientTarget); - - Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()]; + await InteractUsing(Rod, 10); + ClientAssertPrototype(Grille, Target); var grille = Target; // Construct Window await StartConstruction(Window); - await Interact(Glass, 10); - ClientAssertPrototype(Window, ClientTarget); - Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()]; + await InteractUsing(Glass, 10); + ClientAssertPrototype(Window, Target); // Deconstruct Window await Interact(Screw, Wrench); @@ -35,7 +32,7 @@ public async Task WindowOnGrille() // Deconstruct Grille Target = grille; - await Interact(Cut); + await InteractUsing(Cut); AssertDeleted(); } diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/MachineConstruction.cs b/Content.IntegrationTests/Tests/Construction/Interaction/MachineConstruction.cs index cd95a85f205..98db51b4078 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/MachineConstruction.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/MachineConstruction.cs @@ -14,9 +14,8 @@ public sealed class MachineConstruction : InteractionTest public async Task ConstructProtolathe() { await StartConstruction(MachineFrame); - await Interact(Steel, 5); - ClientAssertPrototype(Unfinished, ClientTarget); - Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()]; + await InteractUsing(Steel, 5); + ClientAssertPrototype(Unfinished, Target); await Interact(Wrench, Cable); AssertPrototype(MachineFrame); await Interact(ProtolatheBoard, Bin1, Bin1, Manipulator1, Manipulator1, Beaker, Beaker, Screw); @@ -51,7 +50,7 @@ public async Task ChangeMachine() AssertPrototype(MachineFrame); // Change it into an autolathe - await Interact("AutolatheMachineCircuitboard"); + await InteractUsing("AutolatheMachineCircuitboard"); AssertPrototype(MachineFrame); await Interact(Bin1, Bin1, Bin1, Manipulator1, Glass, Screw); AssertPrototype("Autolathe"); diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/PanelScrewing.cs b/Content.IntegrationTests/Tests/Construction/Interaction/PanelScrewing.cs index b6d960e2882..636d58bf96f 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/PanelScrewing.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/PanelScrewing.cs @@ -19,21 +19,21 @@ public async Task WiresPanelScrewing(string prototype) // Open & close panel Assert.That(comp.Open, Is.False); - await Interact(Screw); + await InteractUsing(Screw); Assert.That(comp.Open, Is.True); - await Interact(Screw); + await InteractUsing(Screw); Assert.That(comp.Open, Is.False); // Interrupted DoAfters - await Interact(Screw, awaitDoAfters: false); + await InteractUsing(Screw, awaitDoAfters: false); await CancelDoAfters(); Assert.That(comp.Open, Is.False); - await Interact(Screw); + await InteractUsing(Screw); Assert.That(comp.Open, Is.True); - await Interact(Screw, awaitDoAfters: false); + await InteractUsing(Screw, awaitDoAfters: false); await CancelDoAfters(); Assert.That(comp.Open, Is.True); - await Interact(Screw); + await InteractUsing(Screw); Assert.That(comp.Open, Is.False); } } diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/PlaceableDeconstruction.cs b/Content.IntegrationTests/Tests/Construction/Interaction/PlaceableDeconstruction.cs index bc0cb9bcef3..783c14c0682 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/PlaceableDeconstruction.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/PlaceableDeconstruction.cs @@ -13,9 +13,9 @@ public async Task DeconstructTable() { await StartDeconstruction("Table"); Assert.That(Comp<PlaceableSurfaceComponent>().IsPlaceable); - await Interact(Wrench); + await InteractUsing(Wrench); AssertPrototype("TableFrame"); - await Interact(Wrench); + await InteractUsing(Wrench); AssertDeleted(); await AssertEntityLookup((Steel, 1), (Rod, 2)); } diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/WallConstruction.cs b/Content.IntegrationTests/Tests/Construction/Interaction/WallConstruction.cs index 67a2f8025dc..292bf0c55ab 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/WallConstruction.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/WallConstruction.cs @@ -12,11 +12,10 @@ public sealed class WallConstruction : InteractionTest public async Task ConstructWall() { await StartConstruction(Wall); - await Interact(Steel, 2); + await InteractUsing(Steel, 2); Assert.That(Hands.ActiveHandEntity, Is.Null); - ClientAssertPrototype(Girder, ClientTarget); - Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()]; - await Interact(Steel, 2); + ClientAssertPrototype(Girder, Target); + await InteractUsing(Steel, 2); Assert.That(Hands.ActiveHandEntity, Is.Null); AssertPrototype(WallSolid); } @@ -25,7 +24,7 @@ public async Task ConstructWall() public async Task DeconstructWall() { await StartDeconstruction(WallSolid); - await Interact(Weld); + await InteractUsing(Weld); AssertPrototype(Girder); await Interact(Wrench, Screw); AssertDeleted(); diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/WindowConstruction.cs b/Content.IntegrationTests/Tests/Construction/Interaction/WindowConstruction.cs index 46bb892ed99..2ece6b3e397 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/WindowConstruction.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/WindowConstruction.cs @@ -11,8 +11,8 @@ public sealed class WindowConstruction : InteractionTest public async Task ConstructWindow() { await StartConstruction(Window); - await Interact(Glass, 5); - ClientAssertPrototype(Window, ClientTarget); + await InteractUsing(Glass, 5); + ClientAssertPrototype(Window, Target); } [Test] @@ -28,8 +28,8 @@ public async Task DeconstructWindow() public async Task ConstructReinforcedWindow() { await StartConstruction(RWindow); - await Interact(RGlass, 5); - ClientAssertPrototype(RWindow, ClientTarget); + await InteractUsing(RGlass, 5); + ClientAssertPrototype(RWindow, Target); } [Test] diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs b/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs index abd4bc265b3..6eea519af3b 100644 --- a/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs +++ b/Content.IntegrationTests/Tests/Construction/Interaction/WindowRepair.cs @@ -24,7 +24,7 @@ public async Task RepairReinforcedWindow() Assert.That(comp.Damage.GetTotal(), Is.GreaterThan(FixedPoint2.Zero)); // Repair the entity - await Interact(Weld); + await InteractUsing(Weld); Assert.That(comp.Damage.GetTotal(), Is.EqualTo(FixedPoint2.Zero)); // Validate that we can still deconstruct the entity (i.e., that welding deconstruction is not blocked). diff --git a/Content.IntegrationTests/Tests/ContainerOcclusionTest.cs b/Content.IntegrationTests/Tests/ContainerOcclusionTest.cs index c61a70faf0b..c907f6bb1f3 100644 --- a/Content.IntegrationTests/Tests/ContainerOcclusionTest.cs +++ b/Content.IntegrationTests/Tests/ContainerOcclusionTest.cs @@ -43,11 +43,11 @@ public async Task TestA() EntityUid dummy = default; var mapManager = server.ResolveDependency<IMapManager>(); - var mapId = mapManager.CreateMap(); + var map = await pair.CreateTestMap(); await server.WaitPost(() => { - var pos = new MapCoordinates(Vector2.Zero, mapId); + var pos = new MapCoordinates(Vector2.Zero, map.MapId); var entStorage = serverEntManager.EntitySysManager.GetEntitySystem<EntityStorageSystem>(); var container = serverEntManager.SpawnEntity("ContainerOcclusionA", pos); dummy = serverEntManager.SpawnEntity("ContainerOcclusionDummy", pos); @@ -85,11 +85,12 @@ public async Task TestB() EntityUid dummy = default; var mapManager = server.ResolveDependency<IMapManager>(); - var mapId = mapManager.CreateMap(); + + var map = await pair.CreateTestMap(); await server.WaitPost(() => { - var pos = new MapCoordinates(Vector2.Zero, mapId); + var pos = new MapCoordinates(Vector2.Zero, map.MapId); var entStorage = serverEntManager.EntitySysManager.GetEntitySystem<EntityStorageSystem>(); var container = serverEntManager.SpawnEntity("ContainerOcclusionB", pos); dummy = serverEntManager.SpawnEntity("ContainerOcclusionDummy", pos); @@ -99,10 +100,12 @@ await server.WaitPost(() => await pair.RunTicksSync(5); - var clientEnt = clientEntManager.GetEntity(serverEntManager.GetNetEntity(dummy)); + EntityUid clientEnt = default!; await client.WaitAssertion(() => { + clientEnt = clientEntManager.GetEntity(serverEntManager.GetNetEntity(dummy)); + var sprite = clientEntManager.GetComponent<SpriteComponent>(clientEnt); var light = clientEntManager.GetComponent<PointLightComponent>(clientEnt); Assert.Multiple(() => @@ -127,11 +130,12 @@ public async Task TestAb() EntityUid dummy = default; var mapManager = server.ResolveDependency<IMapManager>(); - var mapId = mapManager.CreateMap(); + + var map = await pair.CreateTestMap(); await server.WaitPost(() => { - var pos = new MapCoordinates(Vector2.Zero, mapId); + var pos = new MapCoordinates(Vector2.Zero, map.MapId); var entStorage = serverEntManager.EntitySysManager.GetEntitySystem<EntityStorageSystem>(); var containerA = serverEntManager.SpawnEntity("ContainerOcclusionA", pos); var containerB = serverEntManager.SpawnEntity("ContainerOcclusionB", pos); diff --git a/Content.IntegrationTests/Tests/Damageable/DamageSpecifierTest.cs b/Content.IntegrationTests/Tests/Damageable/DamageSpecifierTest.cs index 41d17ddedae..bd5cac05dd1 100644 --- a/Content.IntegrationTests/Tests/Damageable/DamageSpecifierTest.cs +++ b/Content.IntegrationTests/Tests/Damageable/DamageSpecifierTest.cs @@ -14,39 +14,39 @@ public void TestDamageSpecifierOperations() // Test basic math operations. // I've already nearly broken these once. When editing the operators. - DamageSpecifier input1 = new() { DamageDict = _input1 }; - DamageSpecifier input2 = new() { DamageDict = _input2 }; - DamageSpecifier output1 = new() { DamageDict = _output1 }; - DamageSpecifier output2 = new() { DamageDict = _output2 }; - DamageSpecifier output3 = new() { DamageDict = _output3 }; - DamageSpecifier output4 = new() { DamageDict = _output4 }; - DamageSpecifier output5 = new() { DamageDict = _output5 }; + DamageSpecifier input1 = new() { DamageDict = Input1 }; + DamageSpecifier input2 = new() { DamageDict = Input2 }; + DamageSpecifier output1 = new() { DamageDict = Output1 }; + DamageSpecifier output2 = new() { DamageDict = Output2 }; + DamageSpecifier output3 = new() { DamageDict = Output3 }; + DamageSpecifier output4 = new() { DamageDict = Output4 }; + DamageSpecifier output5 = new() { DamageDict = Output5 }; Assert.Multiple(() => { - Assert.That((-input1).Equals(output1)); - Assert.That((input1 / 2).Equals(output2)); - Assert.That((input1 * 2).Equals(output3)); + Assert.That(-input1, Is.EqualTo(output1)); + Assert.That(input1 / 2, Is.EqualTo(output2)); + Assert.That(input1 * 2, Is.EqualTo(output3)); }); - var difference = (input1 - input2); - Assert.That(difference.Equals(output4)); + var difference = input1 - input2; + Assert.That(difference, Is.EqualTo(output4)); - var difference2 = (-input2) + input1; - Assert.That(difference.Equals(difference2)); + var difference2 = -input2 + input1; + Assert.That(difference, Is.EqualTo(difference2)); difference.Clamp(-0.25f, 0.25f); - Assert.That(difference.Equals(output5)); + Assert.That(difference, Is.EqualTo(output5)); } - static Dictionary<string, FixedPoint2> _input1 = new() + private static readonly Dictionary<string, FixedPoint2> Input1 = new() { { "A", 1.5f }, { "B", 2 }, { "C", 3 } }; - static Dictionary<string, FixedPoint2> _input2 = new() + private static readonly Dictionary<string, FixedPoint2> Input2 = new() { { "A", 1 }, { "B", 2 }, @@ -54,28 +54,28 @@ public void TestDamageSpecifierOperations() { "D", 0.05f } }; - static Dictionary<string, FixedPoint2> _output1 = new() + private static readonly Dictionary<string, FixedPoint2> Output1 = new() { { "A", -1.5f }, { "B", -2 }, { "C", -3 } }; - static Dictionary<string, FixedPoint2> _output2 = new() + private static readonly Dictionary<string, FixedPoint2> Output2 = new() { { "A", 0.75f }, { "B", 1 }, { "C", 1.5 } }; - static Dictionary<string, FixedPoint2> _output3 = new() + private static readonly Dictionary<string, FixedPoint2> Output3 = new() { { "A", 3f }, { "B", 4 }, { "C", 6 } }; - static Dictionary<string, FixedPoint2> _output4 = new() + private static readonly Dictionary<string, FixedPoint2> Output4 = new() { { "A", 0.5f }, { "B", 0 }, @@ -83,7 +83,7 @@ public void TestDamageSpecifierOperations() { "D", -0.05f } }; - static Dictionary<string, FixedPoint2> _output5 = new() + private static readonly Dictionary<string, FixedPoint2> Output5 = new() { { "A", 0.25f }, { "B", 0 }, diff --git a/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs b/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs index c40b8ed286f..69069fc82fe 100644 --- a/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs +++ b/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs @@ -107,10 +107,11 @@ public async Task TestDamageableComponents() FixedPoint2 typeDamage; + var map = await pair.CreateTestMap(); + await server.WaitPost(() => { - var map = sMapManager.CreateMap(); - var coordinates = new MapCoordinates(0, 0, map); + var coordinates = map.MapCoords; sDamageableEntity = sEntityManager.SpawnEntity("TestDamageableEntityId", coordinates); sDamageableComponent = sEntityManager.GetComponent<DamageableComponent>(sDamageableEntity); diff --git a/Content.IntegrationTests/Tests/Destructible/DestructibleDestructionTest.cs b/Content.IntegrationTests/Tests/Destructible/DestructibleDestructionTest.cs index e14a8264678..a50238d8f50 100644 --- a/Content.IntegrationTests/Tests/Destructible/DestructibleDestructionTest.cs +++ b/Content.IntegrationTests/Tests/Destructible/DestructibleDestructionTest.cs @@ -3,6 +3,7 @@ using Content.Server.Destructible.Thresholds.Behaviors; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; +using Content.Shared.Destructible.Thresholds; using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; using static Content.IntegrationTests.Tests.Destructible.DestructibleTestPrototypes; diff --git a/Content.IntegrationTests/Tests/DoAfter/DoAfterCancellationTests.cs b/Content.IntegrationTests/Tests/DoAfter/DoAfterCancellationTests.cs index 0ebd17d8879..1aaf4a5184c 100644 --- a/Content.IntegrationTests/Tests/DoAfter/DoAfterCancellationTests.cs +++ b/Content.IntegrationTests/Tests/DoAfter/DoAfterCancellationTests.cs @@ -16,31 +16,31 @@ public sealed class DoAfterCancellationTests : InteractionTest public async Task CancelWallDeconstruct() { await StartDeconstruction(WallConstruction.WallSolid); - await Interact(Weld, awaitDoAfters: false); + await InteractUsing(Weld, awaitDoAfters: false); // Failed do-after has no effect await CancelDoAfters(); AssertPrototype(WallConstruction.WallSolid); // Second attempt works fine - await Interact(Weld); + await InteractUsing(Weld); AssertPrototype(WallConstruction.Girder); // Repeat for wrenching interaction AssertAnchored(); - await Interact(Wrench, awaitDoAfters: false); + await InteractUsing(Wrench, awaitDoAfters: false); await CancelDoAfters(); AssertAnchored(); AssertPrototype(WallConstruction.Girder); - await Interact(Wrench); + await InteractUsing(Wrench); AssertAnchored(false); // Repeat for screwdriver interaction. AssertExists(); - await Interact(Screw, awaitDoAfters: false); + await InteractUsing(Screw, awaitDoAfters: false); await CancelDoAfters(); AssertExists(); - await Interact(Screw); + await InteractUsing(Screw); AssertDeleted(); } @@ -48,17 +48,16 @@ public async Task CancelWallDeconstruct() public async Task CancelWallConstruct() { await StartConstruction(WallConstruction.Wall); - await Interact(Steel, 5, awaitDoAfters: false); + await InteractUsing(Steel, 5, awaitDoAfters: false); await CancelDoAfters(); - await Interact(Steel, 5); - ClientAssertPrototype(WallConstruction.Girder, ClientTarget); - Target = CTestSystem.Ghosts[ClientTarget!.Value.GetHashCode()]; - await Interact(Steel, 5, awaitDoAfters: false); + await InteractUsing(Steel, 5); + ClientAssertPrototype(WallConstruction.Girder, Target); + await InteractUsing(Steel, 5, awaitDoAfters: false); await CancelDoAfters(); AssertPrototype(WallConstruction.Girder); - await Interact(Steel, 5); + await InteractUsing(Steel, 5); AssertPrototype(WallConstruction.WallSolid); } @@ -66,11 +65,11 @@ public async Task CancelWallConstruct() public async Task CancelTilePry() { await SetTile(Floor); - await Interact(Pry, awaitDoAfters: false); + await InteractUsing(Pry, awaitDoAfters: false); await CancelDoAfters(); await AssertTile(Floor); - await Interact(Pry); + await InteractUsing(Pry); await AssertTile(Plating); } @@ -78,7 +77,7 @@ public async Task CancelTilePry() public async Task CancelRepeatedTilePry() { await SetTile(Floor); - await Interact(Pry, awaitDoAfters: false); + await InteractUsing(Pry, awaitDoAfters: false); await RunTicks(1); Assert.That(ActiveDoAfters.Count(), Is.EqualTo(1)); await AssertTile(Floor); @@ -89,7 +88,7 @@ public async Task CancelRepeatedTilePry() await AssertTile(Floor); // Third do after will work fine - await Interact(Pry); + await InteractUsing(Pry); Assert.That(ActiveDoAfters.Count(), Is.EqualTo(0)); await AssertTile(Plating); } @@ -102,7 +101,7 @@ public async Task CancelRepeatedWeld() Assert.That(comp.IsWelded, Is.False); - await Interact(Weld, awaitDoAfters: false); + await InteractUsing(Weld, awaitDoAfters: false); await RunTicks(1); Assert.Multiple(() => { @@ -120,7 +119,7 @@ public async Task CancelRepeatedWeld() }); // Third do after will work fine - await Interact(Weld); + await InteractUsing(Weld); Assert.Multiple(() => { Assert.That(ActiveDoAfters.Count(), Is.EqualTo(0)); @@ -128,7 +127,7 @@ public async Task CancelRepeatedWeld() }); // Repeat test for un-welding - await Interact(Weld, awaitDoAfters: false); + await InteractUsing(Weld, awaitDoAfters: false); await RunTicks(1); Assert.Multiple(() => { @@ -141,7 +140,7 @@ public async Task CancelRepeatedWeld() Assert.That(ActiveDoAfters.Count(), Is.EqualTo(0)); Assert.That(comp.IsWelded, Is.True); }); - await Interact(Weld); + await InteractUsing(Weld); Assert.Multiple(() => { Assert.That(ActiveDoAfters.Count(), Is.EqualTo(0)); diff --git a/Content.IntegrationTests/Tests/Doors/AirlockTest.cs b/Content.IntegrationTests/Tests/Doors/AirlockTest.cs index 9f31231091f..fb77bf18d83 100644 --- a/Content.IntegrationTests/Tests/Doors/AirlockTest.cs +++ b/Content.IntegrationTests/Tests/Doors/AirlockTest.cs @@ -123,24 +123,24 @@ public async Task AirlockBlockTest() var xformSystem = entityManager.System<SharedTransformSystem>(); PhysicsComponent physBody = null; - EntityUid AirlockPhysicsDummy = default; + EntityUid airlockPhysicsDummy = default; EntityUid airlock = default; DoorComponent doorComponent = null; - var AirlockPhysicsDummyStartingX = -1; + var airlockPhysicsDummyStartingX = -1; + + var map = await pair.CreateTestMap(); await server.WaitAssertion(() => { - var mapId = mapManager.CreateMap(); - - var humanCoordinates = new MapCoordinates(new Vector2(AirlockPhysicsDummyStartingX, 0), mapId); - AirlockPhysicsDummy = entityManager.SpawnEntity("AirlockPhysicsDummy", humanCoordinates); + var humanCoordinates = new MapCoordinates(new Vector2(airlockPhysicsDummyStartingX, 0), map.MapId); + airlockPhysicsDummy = entityManager.SpawnEntity("AirlockPhysicsDummy", humanCoordinates); - airlock = entityManager.SpawnEntity("AirlockDummy", new MapCoordinates(new Vector2(0, 0), mapId)); + airlock = entityManager.SpawnEntity("AirlockDummy", new MapCoordinates(new Vector2(0, 0), map.MapId)); Assert.Multiple(() => { - Assert.That(entityManager.TryGetComponent(AirlockPhysicsDummy, out physBody), Is.True); + Assert.That(entityManager.TryGetComponent(airlockPhysicsDummy, out physBody), Is.True); Assert.That(entityManager.TryGetComponent(airlock, out doorComponent), Is.True); }); Assert.That(doorComponent.State, Is.EqualTo(DoorState.Closed)); @@ -152,7 +152,7 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => Assert.That(physBody, Is.Not.EqualTo(null))); await server.WaitPost(() => { - physicsSystem.SetLinearVelocity(AirlockPhysicsDummy, new Vector2(0.5f, 0f), body: physBody); + physicsSystem.SetLinearVelocity(airlockPhysicsDummy, new Vector2(0.5f, 0f), body: physBody); }); for (var i = 0; i < 240; i += 10) @@ -176,7 +176,7 @@ await server.WaitPost(() => // Blocked by the airlock await server.WaitAssertion(() => { - Assert.That(Math.Abs(xformSystem.GetWorldPosition(AirlockPhysicsDummy).X - 1), Is.GreaterThan(0.01f)); + Assert.That(Math.Abs(xformSystem.GetWorldPosition(airlockPhysicsDummy).X - 1), Is.GreaterThan(0.01f)); }); await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/DummyIconTest.cs b/Content.IntegrationTests/Tests/DummyIconTest.cs index a11191a51ea..df2d28a2ea2 100644 --- a/Content.IntegrationTests/Tests/DummyIconTest.cs +++ b/Content.IntegrationTests/Tests/DummyIconTest.cs @@ -21,7 +21,7 @@ await client.WaitAssertion(() => { foreach (var proto in prototypeManager.EnumeratePrototypes<EntityPrototype>()) { - if (proto.NoSpawn || proto.Abstract || pair.IsTestPrototype(proto) || !proto.Components.ContainsKey("Sprite")) + if (proto.HideSpawnMenu || proto.Abstract || pair.IsTestPrototype(proto) || !proto.Components.ContainsKey("Sprite")) continue; Assert.DoesNotThrow(() => diff --git a/Content.IntegrationTests/Tests/EncryptionKeys/RemoveEncryptionKeys.cs b/Content.IntegrationTests/Tests/EncryptionKeys/RemoveEncryptionKeys.cs index 9e3dbd8863e..f5e8c22242e 100644 --- a/Content.IntegrationTests/Tests/EncryptionKeys/RemoveEncryptionKeys.cs +++ b/Content.IntegrationTests/Tests/EncryptionKeys/RemoveEncryptionKeys.cs @@ -22,7 +22,7 @@ public async Task HeadsetKeys() }); // Remove the key - await Interact(Screw); + await InteractUsing(Screw); Assert.Multiple(() => { Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.EqualTo(0)); @@ -34,7 +34,7 @@ public async Task HeadsetKeys() await AssertEntityLookup(("EncryptionKeyCommon", 1)); // Re-insert a key. - await Interact("EncryptionKeyCentCom"); + await InteractUsing("EncryptionKeyCentCom"); Assert.Multiple(() => { Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.EqualTo(1)); @@ -59,7 +59,7 @@ public async Task CommsServerKeys() }); // cannot remove keys without opening panel - await Interact(Pry); + await InteractUsing(Pry); Assert.Multiple(() => { Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.GreaterThan(0)); @@ -68,7 +68,7 @@ public async Task CommsServerKeys() }); // Open panel - await Interact(Screw); + await InteractUsing(Screw); Assert.Multiple(() => { Assert.That(panel.Open, Is.True); @@ -79,7 +79,7 @@ public async Task CommsServerKeys() }); // Now remove the keys - await Interact(Pry); + await InteractUsing(Pry); Assert.Multiple(() => { Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.EqualTo(0)); @@ -87,7 +87,7 @@ public async Task CommsServerKeys() }); // Reinsert a key - await Interact("EncryptionKeyCentCom"); + await InteractUsing("EncryptionKeyCentCom"); Assert.Multiple(() => { Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.EqualTo(1)); @@ -97,7 +97,7 @@ public async Task CommsServerKeys() }); // Remove it again - await Interact(Pry); + await InteractUsing(Pry); Assert.Multiple(() => { Assert.That(comp.KeyContainer.ContainedEntities, Has.Count.EqualTo(0)); @@ -106,7 +106,7 @@ public async Task CommsServerKeys() // Prying again will start deconstructing the machine. AssertPrototype("TelecomServerFilled"); - await Interact(Pry); + await InteractUsing(Pry); AssertPrototype("MachineFrame"); } } diff --git a/Content.IntegrationTests/Tests/EntityTest.cs b/Content.IntegrationTests/Tests/EntityTest.cs index 926374cf050..56645660673 100644 --- a/Content.IntegrationTests/Tests/EntityTest.cs +++ b/Content.IntegrationTests/Tests/EntityTest.cs @@ -1,15 +1,11 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; -using Content.Server.Humanoid.Components; -using Content.Shared.Coordinates; -using Content.Shared.Prototypes; using Robust.Shared; using Robust.Shared.Configuration; using Robust.Shared.GameObjects; using Robust.Shared.Log; using Robust.Shared.Map; -using Robust.Shared.Map.Components; using Robust.Shared.Maths; using Robust.Shared.Prototypes; @@ -47,7 +43,7 @@ await server.WaitPost(() => foreach (var protoId in protoIds) { - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); var grid = mapManager.CreateGridEntity(mapId); // TODO: Fix this better in engine. mapSystem.SetTile(grid.Owner, grid.Comp, Vector2i.Zero, new Tile(1)); @@ -155,6 +151,7 @@ public async Task SpawnAndDirtyAllEntities() var prototypeMan = server.ResolveDependency<IPrototypeManager>(); var mapManager = server.ResolveDependency<IMapManager>(); var sEntMan = server.ResolveDependency<IEntityManager>(); + var mapSys = server.System<SharedMapSystem>(); Assert.That(cfg.GetCVar(CVars.NetPVS), Is.False); @@ -170,7 +167,7 @@ await server.WaitPost(() => { foreach (var protoId in protoIds) { - var mapId = mapManager.CreateMap(); + mapSys.CreateMap(out var mapId); var grid = mapManager.CreateGridEntity(mapId); var ent = sEntMan.SpawnEntity(protoId, new EntityCoordinates(grid.Owner, 0.5f, 0.5f)); foreach (var (_, component) in sEntMan.GetNetComponents(ent)) @@ -227,6 +224,7 @@ public async Task SpawnAndDeleteEntityCountTest() var settings = new PoolSettings { Connected = true, Dirty = true }; await using var pair = await PoolManager.GetServerClient(settings); var mapManager = pair.Server.ResolveDependency<IMapManager>(); + var mapSys = pair.Server.System<SharedMapSystem>(); var server = pair.Server; var client = pair.Client; @@ -256,7 +254,7 @@ public async Task SpawnAndDeleteEntityCountTest() await server.WaitPost(() => { - mapId = mapManager.CreateMap(); + mapSys.CreateMap(out mapId); }); var coords = new MapCoordinates(Vector2.Zero, mapId); diff --git a/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs b/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs index 6e88d6928e6..d6f9bf35986 100644 --- a/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs +++ b/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs @@ -16,14 +16,15 @@ namespace Content.IntegrationTests.Tests.Fluids; [TestOf(typeof(SpreaderSystem))] public sealed class FluidSpill { - private static PuddleComponent? GetPuddle(IEntityManager entityManager, MapGridComponent mapGrid, Vector2i pos) + private static PuddleComponent? GetPuddle(IEntityManager entityManager, Entity<MapGridComponent> mapGrid, Vector2i pos) { return GetPuddleEntity(entityManager, mapGrid, pos)?.Comp; } - private static Entity<PuddleComponent>? GetPuddleEntity(IEntityManager entityManager, MapGridComponent mapGrid, Vector2i pos) + private static Entity<PuddleComponent>? GetPuddleEntity(IEntityManager entityManager, Entity<MapGridComponent> mapGrid, Vector2i pos) { - foreach (var uid in mapGrid.GetAnchoredEntities(pos)) + var mapSys = entityManager.System<SharedMapSystem>(); + foreach (var uid in mapSys.GetAnchoredEntities(mapGrid, mapGrid.Comp, pos)) { if (entityManager.TryGetComponent(uid, out PuddleComponent? puddleComponent)) return (uid, puddleComponent); @@ -39,9 +40,9 @@ public async Task SpillCorner() var server = pair.Server; var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); - var puddleSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<PuddleSystem>(); + var puddleSystem = server.System<PuddleSystem>(); + var mapSystem = server.System<SharedMapSystem>(); var gameTiming = server.ResolveDependency<IGameTiming>(); - MapId mapId; EntityUid gridId = default; /* @@ -52,7 +53,7 @@ . . . */ await server.WaitPost(() => { - mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); var grid = mapManager.CreateGridEntity(mapId); gridId = grid.Owner; @@ -60,12 +61,12 @@ await server.WaitPost(() => { for (var y = 0; y < 3; y++) { - grid.Comp.SetTile(new Vector2i(x, y), new Tile(1)); + mapSystem.SetTile(grid, new Vector2i(x, y), new Tile(1)); } } - entityManager.SpawnEntity("WallReinforced", grid.Comp.GridTileToLocal(new Vector2i(0, 1))); - entityManager.SpawnEntity("WallReinforced", grid.Comp.GridTileToLocal(new Vector2i(1, 0))); + entityManager.SpawnEntity("WallReinforced", mapSystem.GridTileToLocal(grid, grid.Comp, new Vector2i(0, 1))); + entityManager.SpawnEntity("WallReinforced", mapSystem.GridTileToLocal(grid, grid.Comp, new Vector2i(1, 0))); }); @@ -74,10 +75,10 @@ await server.WaitAssertion(() => { var grid = entityManager.GetComponent<MapGridComponent>(gridId); var solution = new Solution("Blood", FixedPoint2.New(100)); - var tileRef = grid.GetTileRef(puddleOrigin); + var tileRef = mapSystem.GetTileRef(gridId, grid, puddleOrigin); #pragma warning disable NUnit2045 // Interdependent tests Assert.That(puddleSystem.TrySpillAt(tileRef, solution, out _), Is.True); - Assert.That(GetPuddle(entityManager, grid, puddleOrigin), Is.Not.Null); + Assert.That(GetPuddle(entityManager, (gridId, grid), puddleOrigin), Is.Not.Null); #pragma warning restore NUnit2045 }); @@ -87,7 +88,7 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { var grid = entityManager.GetComponent<MapGridComponent>(gridId); - var puddle = GetPuddleEntity(entityManager, grid, puddleOrigin); + var puddle = GetPuddleEntity(entityManager, (gridId, grid), puddleOrigin); #pragma warning disable NUnit2045 // Interdependent tests Assert.That(puddle, Is.Not.Null); @@ -104,7 +105,7 @@ await server.WaitAssertion(() => } var newPos = new Vector2i(x, y); - var sidePuddle = GetPuddle(entityManager, grid, newPos); + var sidePuddle = GetPuddle(entityManager, (gridId, grid), newPos); Assert.That(sidePuddle, Is.Null); } } diff --git a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs index a9069892dff..ee2d0cb1f7a 100644 --- a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs +++ b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs @@ -5,7 +5,6 @@ using Content.Shared.Fluids.Components; using Robust.Shared.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Map.Components; namespace Content.IntegrationTests.Tests.Fluids { @@ -21,8 +20,7 @@ public async Task TilePuddleTest() var testMap = await pair.CreateTestMap(); - var entitySystemManager = server.ResolveDependency<IEntitySystemManager>(); - var spillSystem = entitySystemManager.GetEntitySystem<PuddleSystem>(); + var spillSystem = server.System<PuddleSystem>(); await server.WaitAssertion(() => { @@ -46,17 +44,19 @@ public async Task SpaceNoPuddleTest() var server = pair.Server; var testMap = await pair.CreateTestMap(); - var grid = testMap.Grid.Comp; + var grid = testMap.Grid; var entitySystemManager = server.ResolveDependency<IEntitySystemManager>(); - var spillSystem = entitySystemManager.GetEntitySystem<PuddleSystem>(); + var spillSystem = server.System<PuddleSystem>(); + var mapSystem = server.System<SharedMapSystem>(); // Remove all tiles await server.WaitPost(() => { - foreach (var tile in grid.GetAllTiles()) + var tiles = mapSystem.GetAllTiles(grid.Owner, grid.Comp); + foreach (var tile in tiles) { - grid.SetTile(tile.GridIndices, Tile.Empty); + mapSystem.SetTile(grid, tile.GridIndices, Tile.Empty); } }); diff --git a/Content.IntegrationTests/Tests/FollowerSystemTest.cs b/Content.IntegrationTests/Tests/FollowerSystemTest.cs index 4d308c6d911..f4447426c77 100644 --- a/Content.IntegrationTests/Tests/FollowerSystemTest.cs +++ b/Content.IntegrationTests/Tests/FollowerSystemTest.cs @@ -22,6 +22,7 @@ public async Task FollowerMapDeleteTest() var mapMan = server.ResolveDependency<IMapManager>(); var sysMan = server.ResolveDependency<IEntitySystemManager>(); var logMan = server.ResolveDependency<ILogManager>(); + var mapSys = server.System<SharedMapSystem>(); var logger = logMan.RootSawmill; await server.WaitPost(() => @@ -29,7 +30,7 @@ await server.WaitPost(() => var followerSystem = sysMan.GetEntitySystem<FollowerSystem>(); // Create a map to spawn the observers on. - var map = mapMan.CreateMap(); + mapSys.CreateMap(out var map); // Spawn an observer to be followed. var followed = entMan.SpawnEntity(GameTicker.ObserverPrototypeName, new MapCoordinates(0, 0, map)); @@ -41,7 +42,7 @@ await server.WaitPost(() => followerSystem.StartFollowingEntity(follower, followed); - entMan.DeleteEntity(mapMan.GetMapEntityId(map)); + entMan.DeleteEntity(mapSys.GetMap(map)); }); await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs b/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs index c6a8e618cc1..02245c783e8 100644 --- a/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs +++ b/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs @@ -1,5 +1,4 @@ #nullable enable -using System.Numerics; using Content.Server.Cuffs; using Content.Shared.Body.Components; using Content.Shared.Cuffs.Components; @@ -7,7 +6,6 @@ using Robust.Server.Console; using Robust.Shared.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Maths; namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking { @@ -51,10 +49,11 @@ public async Task Test() var mapManager = server.ResolveDependency<IMapManager>(); var host = server.ResolveDependency<IServerConsoleHost>(); + var map = await pair.CreateTestMap(); + await server.WaitAssertion(() => { - var mapId = mapManager.CreateMap(); - var coordinates = new MapCoordinates(Vector2.Zero, mapId); + var coordinates = map.MapCoords; var cuffableSys = entityManager.System<CuffableSystem>(); var xformSys = entityManager.System<SharedTransformSystem>(); diff --git a/Content.IntegrationTests/Tests/GameObjects/Components/Mobs/AlertsComponentTests.cs b/Content.IntegrationTests/Tests/GameObjects/Components/Mobs/AlertsComponentTests.cs index b0aceacc03d..9f04660008c 100644 --- a/Content.IntegrationTests/Tests/GameObjects/Components/Mobs/AlertsComponentTests.cs +++ b/Content.IntegrationTests/Tests/GameObjects/Components/Mobs/AlertsComponentTests.cs @@ -5,7 +5,6 @@ using Robust.Client.UserInterface; using Robust.Server.Player; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; namespace Content.IntegrationTests.Tests.GameObjects.Components.Mobs { @@ -45,8 +44,8 @@ await server.WaitAssertion(() => Assert.That(alerts, Is.Not.Null); var alertCount = alerts.Count; - alertsSystem.ShowAlert(playerUid, AlertType.Debug1); - alertsSystem.ShowAlert(playerUid, AlertType.Debug2); + alertsSystem.ShowAlert(playerUid, "Debug1"); + alertsSystem.ShowAlert(playerUid, "Debug2"); Assert.That(alerts, Has.Count.EqualTo(alertCount + 2)); }); @@ -89,14 +88,14 @@ static AlertsUI FindAlertsUI(Control control) // We should be seeing 2 alerts - the 2 debug alerts, in a specific order. Assert.That(clientAlertsUI.AlertContainer.ChildCount, Is.GreaterThanOrEqualTo(2)); var alertControls = clientAlertsUI.AlertContainer.Children.Select(c => (AlertControl) c); - var alertIDs = alertControls.Select(ac => ac.Alert.AlertType).ToArray(); - var expectedIDs = new[] { AlertType.Debug1, AlertType.Debug2 }; + var alertIDs = alertControls.Select(ac => ac.Alert.ID).ToArray(); + var expectedIDs = new[] { "HumanHealth", "Debug1", "Debug2" }; Assert.That(alertIDs, Is.SupersetOf(expectedIDs)); }); await server.WaitAssertion(() => { - alertsSystem.ClearAlert(playerUid, AlertType.Debug1); + alertsSystem.ClearAlert(playerUid, "Debug1"); }); await pair.RunTicksSync(5); @@ -106,8 +105,8 @@ await client.WaitAssertion(() => // We should be seeing 1 alert now because one was cleared Assert.That(clientAlertsUI.AlertContainer.ChildCount, Is.GreaterThanOrEqualTo(1)); var alertControls = clientAlertsUI.AlertContainer.Children.Select(c => (AlertControl) c); - var alertIDs = alertControls.Select(ac => ac.Alert.AlertType).ToArray(); - var expectedIDs = new[] { AlertType.Debug2 }; + var alertIDs = alertControls.Select(ac => ac.Alert.ID).ToArray(); + var expectedIDs = new[] { "HumanHealth", "Debug2" }; Assert.That(alertIDs, Is.SupersetOf(expectedIDs)); }); diff --git a/Content.IntegrationTests/Tests/GameRules/AntagPreferenceTest.cs b/Content.IntegrationTests/Tests/GameRules/AntagPreferenceTest.cs index 662ea3b9747..889c7868d7c 100644 --- a/Content.IntegrationTests/Tests/GameRules/AntagPreferenceTest.cs +++ b/Content.IntegrationTests/Tests/GameRules/AntagPreferenceTest.cs @@ -47,7 +47,7 @@ public async Task TestLobbyPlayersValid() Assert.That(sys.IsEntityValid(client.AttachedEntity, def), Is.True); // By default, traitor/antag preferences are disabled, so the pool should be empty. - var sessions = new List<ICommonSession>{pair.Player!}; + var sessions = new List<ICommonSession> { pair.Player! }; var pool = sys.GetPlayerPool(rule, sessions, def); Assert.That(pool.Count, Is.EqualTo(0)); diff --git a/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs b/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs index d0e0255ae77..b0039144c9c 100644 --- a/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs +++ b/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs @@ -1,6 +1,6 @@ -// #nullable enable +// #nullable enable // using Content.Server.GameTicking; -// using Content.Server.GameTicking.Components; +// using Content.Shared.GameTicking.Components; // using Content.Server.GameTicking.Presets; // using Content.Shared.CCVar; // using Content.Shared.GameTicking; @@ -36,7 +36,7 @@ // - type: entity // id: TestRule // parent: BaseGameRule -// noSpawn: true +// categories: [ HideSpawnMenu ] // components: // - type: GameRule // minPlayers: 0 @@ -45,7 +45,7 @@ // - type: entity // id: TestRuleTenPlayers // parent: BaseGameRule -// noSpawn: true +// categories: [ HideSpawnMenu ] // components: // - type: GameRule // minPlayers: 10 @@ -110,14 +110,14 @@ // player = pair.Player!.AttachedEntity!.Value; // Assert.That(entMan.EntityExists(player)); -// ticker.SetGamePreset((GamePresetPrototype?)null); -// server.CfgMan.SetCVar(CCVars.GridFill, false); -// server.CfgMan.SetCVar(CCVars.GameLobbyFallbackEnabled, true); -// server.CfgMan.SetCVar(CCVars.GameLobbyDefaultPreset, "secret"); -// server.System<TestRuleSystem>().Run = false; -// await pair.CleanReturnAsync(); -// } -// } +// ticker.SetGamePreset((GamePresetPrototype?) null); +// server.CfgMan.SetCVar(CCVars.GridFill, false); +// server.CfgMan.SetCVar(CCVars.GameLobbyFallbackEnabled, true); +// server.CfgMan.SetCVar(CCVars.GameLobbyDefaultPreset, "secret"); +// server.System<TestRuleSystem>().Run = false; +// await pair.CleanReturnAsync(); +// } +//} // public sealed class TestRuleSystem : EntitySystem // { diff --git a/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs b/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs index 20a157e33e8..611b038309b 100644 --- a/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs +++ b/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs @@ -1,9 +1,9 @@ using Content.Server.GameTicking; using Content.Server.GameTicking.Commands; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules; using Content.Server.GameTicking.Rules.Components; using Content.Shared.CCVar; +using Content.Shared.GameTicking.Components; using Robust.Shared.Configuration; using Robust.Shared.GameObjects; using Robust.Shared.Timing; @@ -27,8 +27,12 @@ public async Task RestartTest() var sGameTicker = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<GameTicker>(); var sGameTiming = server.ResolveDependency<IGameTiming>(); - sGameTicker.StartGameRule("MaxTimeRestart", out var ruleEntity); - Assert.That(entityManager.TryGetComponent<MaxTimeRestartRuleComponent>(ruleEntity, out var maxTime)); + MaxTimeRestartRuleComponent maxTime = null; + await server.WaitPost(() => + { + sGameTicker.StartGameRule("MaxTimeRestart", out var ruleEntity); + Assert.That(entityManager.TryGetComponent<MaxTimeRestartRuleComponent>(ruleEntity, out maxTime)); + }); Assert.That(server.EntMan.Count<GameRuleComponent>(), Is.EqualTo(1)); Assert.That(server.EntMan.Count<ActiveGameRuleComponent>(), Is.EqualTo(1)); diff --git a/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs b/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs index 0ad198d6ef2..74641126aee 100644 --- a/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs +++ b/Content.IntegrationTests/Tests/Gravity/WeightlessStatusTests.cs @@ -1,5 +1,6 @@ using Content.Server.Gravity; using Content.Shared.Alert; +using Content.Shared.Gravity; using Robust.Shared.GameObjects; namespace Content.IntegrationTests.Tests.Gravity @@ -38,6 +39,7 @@ public async Task WeightlessStatusTest() var entityManager = server.ResolveDependency<IEntityManager>(); var alertsSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<AlertsSystem>(); + var weightlessAlert = SharedGravitySystem.WeightlessAlert; EntityUid human = default; @@ -56,7 +58,7 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { // No gravity without a gravity generator - Assert.That(alertsSystem.IsShowingAlert(human, AlertType.Weightless)); + Assert.That(alertsSystem.IsShowingAlert(human, weightlessAlert)); generatorUid = entityManager.SpawnEntity("WeightlessGravityGeneratorDummy", entityManager.GetComponent<TransformComponent>(human).Coordinates); }); @@ -66,7 +68,7 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { - Assert.That(alertsSystem.IsShowingAlert(human, AlertType.Weightless), Is.False); + Assert.That(alertsSystem.IsShowingAlert(human, weightlessAlert), Is.False); // This should kill gravity entityManager.DeleteEntity(generatorUid); @@ -76,7 +78,7 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { - Assert.That(alertsSystem.IsShowingAlert(human, AlertType.Weightless)); + Assert.That(alertsSystem.IsShowingAlert(human, weightlessAlert)); }); await pair.RunTicksSync(10); diff --git a/Content.IntegrationTests/Tests/GravityGridTest.cs b/Content.IntegrationTests/Tests/GravityGridTest.cs index 7f817e8a1e0..64f7a6d0820 100644 --- a/Content.IntegrationTests/Tests/GravityGridTest.cs +++ b/Content.IntegrationTests/Tests/GravityGridTest.cs @@ -34,29 +34,25 @@ public async Task Test() var testMap = await pair.CreateTestMap(); - EntityUid generator = default; - var entityMan = server.ResolveDependency<IEntityManager>(); - var mapMan = server.ResolveDependency<IMapManager>(); + var entityMan = server.EntMan; + var mapMan = server.MapMan; var mapSys = entityMan.System<SharedMapSystem>(); - MapGridComponent grid1 = null; - MapGridComponent grid2 = null; - EntityUid grid1Entity = default!; - EntityUid grid2Entity = default!; + EntityUid generator = default; + Entity<MapGridComponent> grid1 = default; + Entity<MapGridComponent> grid2 = default; // Create grids await server.WaitAssertion(() => { var mapId = testMap.MapId; - grid1 = mapMan.CreateGrid(mapId); - grid2 = mapMan.CreateGrid(mapId); - grid1Entity = grid1.Owner; - grid2Entity = grid2.Owner; + grid1 = mapMan.CreateGridEntity(mapId); + grid2 = mapMan.CreateGridEntity(mapId); - mapSys.SetTile(grid1Entity, grid1, Vector2i.Zero, new Tile(1)); - mapSys.SetTile(grid2Entity, grid2, Vector2i.Zero, new Tile(1)); + mapSys.SetTile(grid1, grid1, Vector2i.Zero, new Tile(1)); + mapSys.SetTile(grid2, grid2, Vector2i.Zero, new Tile(1)); - generator = entityMan.SpawnEntity("GridGravityGeneratorDummy", new EntityCoordinates(grid1Entity, 0.5f, 0.5f)); + generator = entityMan.SpawnEntity("GridGravityGeneratorDummy", new EntityCoordinates(grid1, 0.5f, 0.5f)); Assert.Multiple(() => { Assert.That(entityMan.HasComponent<GravityGeneratorComponent>(generator)); @@ -77,8 +73,8 @@ await server.WaitAssertion(() => Assert.Multiple(() => { Assert.That(generatorComponent.GravityActive, Is.True); - Assert.That(!entityMan.GetComponent<GravityComponent>(grid1Entity).EnabledVV); - Assert.That(entityMan.GetComponent<GravityComponent>(grid2Entity).EnabledVV); + Assert.That(!entityMan.GetComponent<GravityComponent>(grid1).EnabledVV); + Assert.That(entityMan.GetComponent<GravityComponent>(grid2).EnabledVV); }); // Re-enable needs power so it turns off again. @@ -95,7 +91,7 @@ await server.WaitAssertion(() => Assert.Multiple(() => { Assert.That(generatorComponent.GravityActive, Is.False); - Assert.That(entityMan.GetComponent<GravityComponent>(grid2Entity).EnabledVV, Is.False); + Assert.That(entityMan.GetComponent<GravityComponent>(grid2).EnabledVV, Is.False); }); }); diff --git a/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs b/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs index 4415eddf376..456df3b2f31 100644 --- a/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs +++ b/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs @@ -47,13 +47,9 @@ public async Task InteractionTest() var sysMan = server.ResolveDependency<IEntitySystemManager>(); var handSys = sysMan.GetEntitySystem<SharedHandsSystem>(); - var mapId = MapId.Nullspace; - var coords = MapCoordinates.Nullspace; - await server.WaitAssertion(() => - { - mapId = mapManager.CreateMap(); - coords = new MapCoordinates(Vector2.Zero, mapId); - }); + var map = await pair.CreateTestMap(); + var mapId = map.MapId; + var coords = map.MapCoords; await server.WaitIdleAsync(); EntityUid user = default; @@ -117,13 +113,9 @@ public async Task InteractionObstructionTest() var sysMan = server.ResolveDependency<IEntitySystemManager>(); var handSys = sysMan.GetEntitySystem<SharedHandsSystem>(); - var mapId = MapId.Nullspace; - var coords = MapCoordinates.Nullspace; - await server.WaitAssertion(() => - { - mapId = mapManager.CreateMap(); - coords = new MapCoordinates(Vector2.Zero, mapId); - }); + var map = await pair.CreateTestMap(); + var mapId = map.MapId; + var coords = map.MapCoords; await server.WaitIdleAsync(); EntityUid user = default; @@ -188,13 +180,9 @@ public async Task InteractionInRangeTest() var sysMan = server.ResolveDependency<IEntitySystemManager>(); var handSys = sysMan.GetEntitySystem<SharedHandsSystem>(); - var mapId = MapId.Nullspace; - var coords = MapCoordinates.Nullspace; - await server.WaitAssertion(() => - { - mapId = mapManager.CreateMap(); - coords = new MapCoordinates(Vector2.Zero, mapId); - }); + var map = await pair.CreateTestMap(); + var mapId = map.MapId; + var coords = map.MapCoords; await server.WaitIdleAsync(); EntityUid user = default; @@ -258,13 +246,9 @@ public async Task InteractionOutOfRangeTest() var sysMan = server.ResolveDependency<IEntitySystemManager>(); var handSys = sysMan.GetEntitySystem<SharedHandsSystem>(); - var mapId = MapId.Nullspace; - var coords = MapCoordinates.Nullspace; - await server.WaitAssertion(() => - { - mapId = mapManager.CreateMap(); - coords = new MapCoordinates(Vector2.Zero, mapId); - }); + var map = await pair.CreateTestMap(); + var mapId = map.MapId; + var coords = map.MapCoords; await server.WaitIdleAsync(); EntityUid user = default; @@ -328,13 +312,9 @@ public async Task InsideContainerInteractionBlockTest() var handSys = sysMan.GetEntitySystem<SharedHandsSystem>(); var conSystem = sysMan.GetEntitySystem<SharedContainerSystem>(); - var mapId = MapId.Nullspace; - var coords = MapCoordinates.Nullspace; - await server.WaitAssertion(() => - { - mapId = mapManager.CreateMap(); - coords = new MapCoordinates(Vector2.Zero, mapId); - }); + var map = await pair.CreateTestMap(); + var mapId = map.MapId; + var coords = map.MapCoords; await server.WaitIdleAsync(); EntityUid user = default; diff --git a/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs b/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs index b8828763a23..e5ac0f785aa 100644 --- a/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs +++ b/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs @@ -37,10 +37,11 @@ public async Task EntityEntityTest() EntityUid other = default; MapCoordinates mapCoordinates = default; + var map = await pair.CreateTestMap(); + await server.WaitAssertion(() => { - var mapId = mapManager.CreateMap(); - var coordinates = new MapCoordinates(Vector2.Zero, mapId); + var coordinates = map.MapCoords; origin = sEntities.SpawnEntity(HumanId, coordinates); other = sEntities.SpawnEntity(HumanId, coordinates); diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifier.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifier.cs index 37dca721373..194bc54fba6 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifier.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifier.cs @@ -33,7 +33,7 @@ protected sealed class EntitySpecifier public int Quantity; /// <summary> - /// If true, a check has been performed to see if the prototype ia an entity prototype with a stack component, + /// If true, a check has been performed to see if the prototype is an entity prototype with a stack component, /// in which case the specifier was converted into a stack-specifier /// </summary> public bool Converted; @@ -100,7 +100,7 @@ await Server.WaitPost(() => if (!ProtoMan.TryIndex<EntityPrototype>(spec.Prototype, out var entProto)) { - Assert.Fail($"Unkown prototype: {spec.Prototype}"); + Assert.Fail($"Unknown prototype: {spec.Prototype}"); return default; } @@ -114,13 +114,13 @@ await Server.WaitPost(() => return await SpawnEntity((stack.StackTypeId, spec.Quantity), coords); Assert.That(spec.Quantity, Is.EqualTo(1), "SpawnEntity only supports returning a singular entity"); - await Server.WaitPost(() => uid = SEntMan.SpawnEntity(spec.Prototype, coords)); + await Server.WaitPost(() => uid = SEntMan.SpawnAtPosition(spec.Prototype, coords)); return uid; } /// <summary> /// Convert an entity-uid to a matching entity specifier. Useful when doing entity lookups & checking that the - /// right quantity of entities/materials werre produced. Returns null if passed an entity with a null prototype. + /// right quantity of entities/materials were produced. Returns null if passed an entity with a null prototype. /// </summary> protected EntitySpecifier? ToEntitySpecifier(EntityUid uid) { diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs index 19ca83a9715..a19b62cd70a 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs @@ -14,6 +14,7 @@ using Content.Shared.Gravity; using Content.Shared.Item; using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.GameObjects; using Robust.Shared.Input; @@ -44,8 +45,9 @@ await Client.WaitPost(() => return; var comp = CEntMan.GetComponent<ConstructionGhostComponent>(clientTarget!.Value); - ClientTarget = clientTarget; - ConstructionGhostId = comp.Owner.Id; + Target = CEntMan.GetNetEntity(clientTarget.Value); + Assert.That(Target.Value.IsClientSide()); + ConstructionGhostId = clientTarget.Value.GetHashCode(); }); await RunTicks(1); @@ -82,18 +84,21 @@ protected async Task CraftItem(string prototype, bool shouldSucceed = true) /// <summary> /// Spawn an entity entity and set it as the target. /// </summary> - [MemberNotNull(nameof(Target))] - protected async Task SpawnTarget(string prototype) + [MemberNotNull(nameof(Target), nameof(STarget), nameof(CTarget))] +#pragma warning disable CS8774 // Member must have a non-null value when exiting. + protected async Task<NetEntity> SpawnTarget(string prototype) { Target = NetEntity.Invalid; await Server.WaitPost(() => { - Target = SEntMan.GetNetEntity(SEntMan.SpawnEntity(prototype, SEntMan.GetCoordinates(TargetCoords))); + Target = SEntMan.GetNetEntity(SEntMan.SpawnAtPosition(prototype, SEntMan.GetCoordinates(TargetCoords))); }); await RunTicks(5); AssertPrototype(prototype); + return Target!.Value; } +#pragma warning restore CS8774 // Member must have a non-null value when exiting. /// <summary> /// Spawn an entity in preparation for deconstruction @@ -129,21 +134,20 @@ await Server.WaitPost(() => /// <summary> /// Place an entity prototype into the players hand. Deletes any currently held entity. /// </summary> - /// <remarks> - /// Automatically enables welders. - /// </remarks> - protected async Task<NetEntity> PlaceInHands(string id, int quantity = 1, bool enableWelder = true) + /// <param name="id">The entity or stack prototype to spawn and place into the users hand</param> + /// <param name="quantity">The number of entities to spawn. If the prototype is a stack, this sets the stack count.</param> + /// <param name="enableToggleable">Whether or not to automatically enable any toggleable items</param> + protected async Task<NetEntity> PlaceInHands(string id, int quantity = 1, bool enableToggleable = true) { - return await PlaceInHands((id, quantity), enableWelder); + return await PlaceInHands((id, quantity), enableToggleable); } /// <summary> /// Place an entity prototype into the players hand. Deletes any currently held entity. /// </summary> - /// <remarks> - /// Automatically enables welders. - /// </remarks> - protected async Task<NetEntity> PlaceInHands(EntitySpecifier entity, bool enableWelder = true) + /// <param name="entity">The entity type & quantity to spawn and place into the users hand</param> + /// <param name="enableToggleable">Whether or not to automatically enable any toggleable items</param> + protected async Task<NetEntity> PlaceInHands(EntitySpecifier entity, bool enableToggleable = true) { if (Hands.ActiveHand == null) { @@ -165,7 +169,7 @@ await Server.WaitPost(() => Assert.That(HandSys.TryPickup(playerEnt, item, Hands.ActiveHand, false, false, Hands)); // turn on welders - if (enableWelder && SEntMan.TryGetComponent(item, out itemToggle) && !itemToggle.Activated) + if (enableToggleable && SEntMan.TryGetComponent(item, out itemToggle) && !itemToggle.Activated) { Assert.That(ItemToggleSys.TryActivate(item, playerEnt, itemToggle: itemToggle)); } @@ -173,7 +177,7 @@ await Server.WaitPost(() => await RunTicks(1); Assert.That(Hands.ActiveHandEntity, Is.EqualTo(item)); - if (enableWelder && itemToggle != null) + if (enableToggleable && itemToggle != null) Assert.That(itemToggle.Activated); return SEntMan.GetNetEntity(item); @@ -254,21 +258,20 @@ await Server.WaitPost(() => /// <summary> /// Place an entity prototype into the players hand and interact with the given entity (or target position) /// </summary> - /// <remarks> - /// Empty strings imply empty hands. - /// </remarks> - protected async Task Interact(string id, int quantity = 1, bool shouldSucceed = true, bool awaitDoAfters = true) + /// <param name="id">The entity or stack prototype to spawn and place into the users hand</param> + /// <param name="quantity">The number of entities to spawn. If the prototype is a stack, this sets the stack count.</param> + /// <param name="awaitDoAfters">Whether or not to wait for any do-afters to complete</param> + protected async Task InteractUsing(string id, int quantity = 1, bool awaitDoAfters = true) { - await Interact((id, quantity), shouldSucceed, awaitDoAfters); + await InteractUsing((id, quantity), awaitDoAfters); } /// <summary> - /// Place an entity prototype into the players hand and interact with the given entity (or target position) + /// Place an entity prototype into the players hand and interact with the given entity (or target position). /// </summary> - /// <remarks> - /// Empty strings imply empty hands. - /// </remarks> - protected async Task Interact(EntitySpecifier entity, bool shouldSucceed = true, bool awaitDoAfters = true) + /// <param name="entity">The entity type & quantity to spawn and place into the users hand</param> + /// <param name="awaitDoAfters">Whether or not to wait for any do-afters to complete</param> + protected async Task InteractUsing(EntitySpecifier entity, bool awaitDoAfters = true) { // For every interaction, we will also examine the entity, just in case this breaks something, somehow. // (e.g., servers attempt to assemble construction examine hints). @@ -278,38 +281,80 @@ protected async Task Interact(EntitySpecifier entity, bool shouldSucceed = true, } await PlaceInHands(entity); - await Interact(shouldSucceed, awaitDoAfters); + await Interact(awaitDoAfters); } /// <summary> /// Interact with an entity using the currently held entity. /// </summary> - protected async Task Interact(bool shouldSucceed = true, bool awaitDoAfters = true) + /// <param name="awaitDoAfters">Whether or not to wait for any do-afters to complete</param> + protected async Task Interact(bool awaitDoAfters = true) { - var clientTarget = ClientTarget; - - if ((clientTarget?.IsValid() != true || CEntMan.Deleted(clientTarget)) && (Target == null || Target.Value.IsValid())) + if (Target == null || !Target.Value.IsClientSide()) { - await Server.WaitPost(() => InteractSys.UserInteraction(SEntMan.GetEntity(Player), SEntMan.GetCoordinates(TargetCoords), SEntMan.GetEntity(Target))); - await RunTicks(1); + await Interact(Target, TargetCoords, awaitDoAfters); + return; } - else - { - // The entity is client-side, so attempt to start construction - var clientEnt = ClientTarget ?? CEntMan.GetEntity(Target); - await Client.WaitPost(() => CConSys.TryStartConstruction(clientEnt!.Value)); - await RunTicks(5); - } + // The target is a client-side entity, so we will just attempt to start construction under the assumption that + // it is a construction ghost. + + await Client.WaitPost(() => CConSys.TryStartConstruction(CTarget!.Value)); + await RunTicks(5); + + if (awaitDoAfters) + await AwaitDoAfters(); + + await CheckTargetChange(); + } + + /// <inheritdoc cref="Interact(EntityUid?,EntityCoordinates,bool)"/> + protected async Task Interact(NetEntity? target, NetCoordinates coordinates, bool awaitDoAfters = true) + { + Assert.That(SEntMan.TryGetEntity(target, out var sTarget) || target == null); + var coords = SEntMan.GetCoordinates(coordinates); + Assert.That(coords.IsValid(SEntMan)); + await Interact(sTarget, coords, awaitDoAfters); + } + + /// <summary> + /// Interact with an entity using the currently held entity. + /// </summary> + protected async Task Interact(EntityUid? target, EntityCoordinates coordinates, bool awaitDoAfters = true) + { + Assert.That(SEntMan.TryGetEntity(Player, out var player)); + + await Server.WaitPost(() => InteractSys.UserInteraction(player!.Value, coordinates, target)); + await RunTicks(1); if (awaitDoAfters) - await AwaitDoAfters(shouldSucceed); + await AwaitDoAfters(); - await CheckTargetChange(shouldSucceed && awaitDoAfters); + await CheckTargetChange(); } /// <summary> - /// Variant of <see cref="InteractUsing"/> that performs several interactions using different entities. + /// Activate an entity. + /// </summary> + protected async Task Activate(NetEntity? target = null, bool awaitDoAfters = true) + { + target ??= Target; + Assert.That(target, Is.Not.Null); + Assert.That(SEntMan.TryGetEntity(target!.Value, out var sTarget)); + Assert.That(SEntMan.TryGetEntity(Player, out var player)); + + await Server.WaitPost(() => InteractSys.InteractionActivate(player!.Value, sTarget!.Value)); + await RunTicks(1); + + if (awaitDoAfters) + await AwaitDoAfters(); + + await CheckTargetChange(); + } + + /// <summary> + /// Variant of <see cref="InteractUsing(string,int,bool)"/> that performs several interactions using different entities. + /// Useful for quickly finishing multiple construction steps. /// </summary> /// <remarks> /// Empty strings imply empty hands. @@ -318,7 +363,7 @@ protected async Task Interact(params EntitySpecifier[] specifiers) { foreach (var spec in specifiers) { - await Interact(spec); + await InteractUsing(spec); } } @@ -338,7 +383,7 @@ protected async Task<bool> ThrowItem(NetCoordinates? target = null, float minDis /// <summary> /// Wait for any currently active DoAfters to finish. /// </summary> - protected async Task AwaitDoAfters(bool shouldSucceed = true, int maxExpected = 1) + protected async Task AwaitDoAfters(int maxExpected = 1) { if (!ActiveDoAfters.Any()) return; @@ -353,13 +398,12 @@ protected async Task AwaitDoAfters(bool shouldSucceed = true, int maxExpected = await RunTicks(10); } - if (!shouldSucceed) - return; - foreach (var doAfter in doAfters) { Assert.That(!doAfter.Cancelled); } + + await RunTicks(5); } /// <summary> @@ -398,39 +442,28 @@ await Server.WaitPost(() => /// Check if the test's target entity has changed. E.g., construction interactions will swap out entities while /// a structure is being built. /// </summary> - protected async Task CheckTargetChange(bool shouldSucceed) + protected async Task CheckTargetChange() { if (Target == null) return; - var target = Target.Value; + var originalTarget = Target.Value; await RunTicks(5); - if (ClientTarget != null && CEntMan.IsClientSide(ClientTarget.Value)) + if (Target.Value.IsClientSide() && CTestSystem.Ghosts.TryGetValue(ConstructionGhostId, out var newWeh)) { - Assert.That(CEntMan.Deleted(ClientTarget.Value), Is.EqualTo(shouldSucceed), - $"Construction ghost was {(shouldSucceed ? "not deleted" : "deleted")}."); - - if (shouldSucceed) - { - Assert.That(CTestSystem.Ghosts.TryGetValue(ConstructionGhostId, out var newWeh), - $"Failed to get construction entity from ghost Id"); - - await Client.WaitPost(() => CLogger.Debug($"Construction ghost {ConstructionGhostId} became entity {newWeh}")); - Target = newWeh; - } + CLogger.Debug($"Construction ghost {ConstructionGhostId} became entity {newWeh}"); + Target = newWeh; } if (STestSystem.EntChanges.TryGetValue(Target.Value, out var newServerWeh)) { - await Server.WaitPost( - () => SLogger.Debug($"Construction entity {Target.Value} changed to {newServerWeh}")); - + SLogger.Debug($"Construction entity {Target.Value} changed to {newServerWeh}"); Target = newServerWeh; } - if (Target != target) - await CheckTargetChange(shouldSucceed); + if (Target != originalTarget) + await CheckTargetChange(); } #region Asserts @@ -444,16 +477,10 @@ protected void ClientAssertPrototype(string? prototype, NetEntity? target = null return; } - var meta = SEntMan.GetComponent<MetaDataComponent>(SEntMan.GetEntity(target.Value)); + var meta = CEntMan.GetComponent<MetaDataComponent>(CEntMan.GetEntity(target.Value)); Assert.That(meta.EntityPrototype?.ID, Is.EqualTo(prototype)); } - protected void ClientAssertPrototype(string? prototype, EntityUid? target) - { - var netEnt = CTestSystem.Ghosts[target.GetHashCode()]; - AssertPrototype(prototype, netEnt); - } - protected void AssertPrototype(string? prototype, NetEntity? target = null) { target ??= Target; @@ -544,11 +571,11 @@ protected async Task AssertTile(string? proto, NetCoordinates? coords = null) var tile = Tile.Empty; var serverCoords = SEntMan.GetCoordinates(coords ?? TargetCoords); - var pos = serverCoords.ToMap(SEntMan, Transform); + var pos = Transform.ToMapCoordinates(serverCoords); await Server.WaitPost(() => { - if (MapMan.TryFindGridAt(pos, out _, out var grid)) - tile = grid.GetTileRef(serverCoords).Tile; + if (MapMan.TryFindGridAt(pos, out var gridUid, out var grid)) + tile = MapSystem.GetTileRef(gridUid, grid, serverCoords).Tile; }); Assert.That(tile.TypeId, Is.EqualTo(targetTile.TypeId)); @@ -699,6 +726,8 @@ protected async Task<EntityUid> FindEntity( protected IEnumerable<Shared.DoAfter.DoAfter> ActiveDoAfters => DoAfters.DoAfters.Values.Where(x => !x.Cancelled && !x.Completed); + #region Component + /// <summary> /// Convenience method to get components on the target. Returns SERVER-SIDE components. /// </summary> @@ -708,39 +737,61 @@ protected T Comp<T>(NetEntity? target = null) where T : IComponent if (target == null) Assert.Fail("No target specified"); - return SEntMan.GetComponent<T>(SEntMan.GetEntity(target!.Value)); + return SEntMan.GetComponent<T>(ToServer(target!.Value)); } + /// <inheritdoc cref="Comp{T}"/> + protected bool TryComp<T>(NetEntity? target, [NotNullWhen(true)] out T? comp) where T : IComponent + { + return SEntMan.TryGetComponent(ToServer(target), out comp); + } + + /// <inheritdoc cref="Comp{T}"/> + protected bool TryComp<T>([NotNullWhen(true)] out T? comp) where T : IComponent + { + return SEntMan.TryGetComponent(STarget, out comp); + } + + #endregion + /// <summary> /// Set the tile at the target position to some prototype. /// </summary> - protected async Task SetTile(string? proto, NetCoordinates? coords = null, MapGridComponent? grid = null) + protected async Task SetTile(string? proto, NetCoordinates? coords = null, Entity<MapGridComponent>? grid = null) { var tile = proto == null ? Tile.Empty : new Tile(TileMan[proto].TileId); - var pos = SEntMan.GetCoordinates(coords ?? TargetCoords).ToMap(SEntMan, Transform); + var pos = Transform.ToMapCoordinates(SEntMan.GetCoordinates(coords ?? TargetCoords)); + EntityUid gridUid; + MapGridComponent? gridComp; await Server.WaitPost(() => { - if (grid != null || MapMan.TryFindGridAt(pos, out var gridUid, out grid)) + if (grid is { } gridEnt) + { + MapSystem.SetTile(gridEnt, SEntMan.GetCoordinates(coords ?? TargetCoords), tile); + return; + } + else if (MapMan.TryFindGridAt(pos, out var gUid, out var gComp)) { - grid.SetTile(SEntMan.GetCoordinates(coords ?? TargetCoords), tile); + MapSystem.SetTile(gUid, gComp, SEntMan.GetCoordinates(coords ?? TargetCoords), tile); return; } if (proto == null) return; - var gridEnt = MapMan.CreateGridEntity(MapData.MapId); + gridEnt = MapMan.CreateGridEntity(MapData.MapId); grid = gridEnt; gridUid = gridEnt; + gridComp = gridEnt.Comp; var gridXform = SEntMan.GetComponent<TransformComponent>(gridUid); Transform.SetWorldPosition(gridXform, pos.Position); - grid.SetTile(SEntMan.GetCoordinates(coords ?? TargetCoords), tile); + MapSystem.SetTile((gridUid, gridComp), SEntMan.GetCoordinates(coords ?? TargetCoords), tile); - if (!MapMan.TryFindGridAt(pos, out _, out grid)) + if (!MapMan.TryFindGridAt(pos, out _, out _)) Assert.Fail("Failed to create grid?"); }); await AssertTile(proto, coords); @@ -833,23 +884,70 @@ protected bool TryGetBui(Enum key, [NotNullWhen(true)] out BoundUserInterface? b return true; } + protected bool IsUiOpen(Enum key) + { + if (!TryComp(Player, out UserInterfaceUserComponent? user)) + return false; + + foreach (var keys in user.OpenInterfaces.Values) + { + if (keys.Contains(key)) + return true; + } + + return false; + } + #endregion #region UI /// <summary> - /// Presses and releases a button on some client-side window. Will fail if the button cannot be found. + /// Attempts to find, and then presses and releases a control on some client-side window. + /// Will fail if the control cannot be found. /// </summary> - protected async Task ClickControl<TWindow>(string name) where TWindow : BaseWindow + protected async Task ClickControl<TWindow, TControl>(string name, BoundKeyFunction? function = null) + where TWindow : BaseWindow + where TControl : Control { - await ClickControl(GetControl<TWindow, Control>(name)); + var window = GetWindow<TWindow>(); + var control = GetControlFromField<TControl>(name, window); + await ClickControl(control, function); } /// <summary> - /// Simulates a click and release at the center of some UI Constrol. + /// Attempts to find, and then presses and releases a control on some client-side widget. + /// Will fail if the control cannot be found. /// </summary> - protected async Task ClickControl(Control control) + protected async Task ClickWidgetControl<TWidget, TControl>(string name, BoundKeyFunction? function = null) + where TWidget : UIWidget, new() + where TControl : Control { + var widget = GetWidget<TWidget>(); + var control = GetControlFromField<TControl>(name, widget); + await ClickControl(control, function); + } + + /// <inheritdoc cref="ClickControl{TWindow,TControl}"/> + protected async Task ClickControl<TWindow>(string name, BoundKeyFunction? function = null) + where TWindow : BaseWindow + { + await ClickControl<TWindow, Control>(name, function); + } + + /// <inheritdoc cref="ClickWidgetControl{TWidget,TControl}"/> + protected async Task ClickWidgetControl<TWidget>(string name, BoundKeyFunction? function = null) + where TWidget : UIWidget, new() + { + await ClickWidgetControl<TWidget, Control>(name, function); + } + + /// <summary> + /// Simulates a click and release at the center of some UI control. + /// </summary> + protected async Task ClickControl(Control control, BoundKeyFunction? function = null) + { + function ??= EngineKeyFunctions.UIClick; var screenCoords = new ScreenCoordinates( control.GlobalPixelPosition + control.PixelSize / 2, control.Window?.Id ?? default); @@ -858,7 +956,7 @@ protected async Task ClickControl(Control control) var relativePixelPos = screenCoords.Position - control.GlobalPixelPosition; var args = new GUIBoundKeyEventArgs( - EngineKeyFunctions.UIClick, + function.Value, BoundKeyState.Down, screenCoords, default, @@ -869,7 +967,7 @@ protected async Task ClickControl(Control control) await RunTicks(1); args = new GUIBoundKeyEventArgs( - EngineKeyFunctions.UIClick, + function.Value, BoundKeyState.Up, screenCoords, default, @@ -881,31 +979,26 @@ protected async Task ClickControl(Control control) } /// <summary> - /// Attempts to find a control on some client-side window. Will fail if the control cannot be found. + /// Attempt to retrieve a control by looking for a field on some other control. /// </summary> - protected TControl GetControl<TWindow, TControl>(string name) - where TWindow : BaseWindow + /// <remarks> + /// Will fail if the control cannot be found. + /// </remarks> + protected TControl GetControlFromField<TControl>(string name, Control parent) where TControl : Control - { - var control = GetControl<TWindow>(name); - Assert.That(control.GetType().IsAssignableTo(typeof(TControl))); - return (TControl) control; - } - - protected Control GetControl<TWindow>(string name) where TWindow : BaseWindow { const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; - var field = typeof(TWindow).GetField(name, flags); - var prop = typeof(TWindow).GetProperty(name, flags); + var parentType = parent.GetType(); + var field = parentType.GetField(name, flags); + var prop = parentType.GetProperty(name, flags); if (field == null && prop == null) { - Assert.Fail($"Window {typeof(TWindow).Name} does not have a field or property named {name}"); + Assert.Fail($"Window {parentType.Name} does not have a field or property named {name}"); return default!; } - var window = GetWindow<TWindow>(); - var fieldOrProp = field?.GetValue(window) ?? prop?.GetValue(window); + var fieldOrProp = field?.GetValue(parent) ?? prop?.GetValue(parent); if (fieldOrProp is not Control control) { @@ -913,7 +1006,59 @@ protected Control GetControl<TWindow>(string name) where TWindow : BaseWindow return default!; } - return control; + Assert.That(control.GetType().IsAssignableTo(typeof(TControl))); + return (TControl) control; + } + + /// <summary> + /// Attempt to retrieve a control that matches some predicate by iterating through a control's children. + /// </summary> + /// <remarks> + /// Will fail if the control cannot be found. + /// </remarks> + protected TControl GetControlFromChildren<TControl>(Func<TControl, bool> predicate, Control parent, bool recursive = true) + where TControl : Control + { + if (TryGetControlFromChildren(predicate, parent, out var control, recursive)) + return control; + + Assert.Fail($"Failed to find a {nameof(TControl)} that satisfies the predicate in {parent.Name}"); + return default!; + } + + /// <summary> + /// Attempt to retrieve a control of a given type by iterating through a control's children. + /// </summary> + protected TControl GetControlFromChildren<TControl>(Control parent, bool recursive = false) + where TControl : Control + { + return GetControlFromChildren<TControl>(static _ => true, parent, recursive); + } + + /// <summary> + /// Attempt to retrieve a control that matches some predicate by iterating through a control's children. + /// </summary> + protected bool TryGetControlFromChildren<TControl>( + Func<TControl, bool> predicate, + Control parent, + [NotNullWhen(true)] out TControl? control, + bool recursive = true) + where TControl : Control + { + foreach (var ctrl in parent.Children) + { + if (ctrl is TControl cast && predicate(cast)) + { + control = cast; + return true; + } + + if (recursive && TryGetControlFromChildren(predicate, ctrl, out control)) + return true; + } + + control = null; + return false; } /// <summary> @@ -944,7 +1089,6 @@ protected bool TryFindWindow<TWindow>([NotNullWhen(true)] out TWindow? window) w return window != null; } - /// <summary> /// Attempts to find a currently open client-side window. /// </summary> @@ -962,6 +1106,34 @@ protected bool TryFindWindow(Type type, [NotNullWhen(true)] out BaseWindow? wind return window != null; } + + /// <summary> + /// Attempts to find client-side UI widget. + /// </summary> + protected UIWidget GetWidget<TWidget>() + where TWidget : UIWidget, new() + { + if (TryFindWidget(out TWidget? widget)) + return widget; + + Assert.Fail($"Could not find a {typeof(TWidget).Name} widget"); + return default!; + } + + /// <summary> + /// Attempts to find client-side UI widget. + /// </summary> + private bool TryFindWidget<TWidget>([NotNullWhen(true)] out TWidget? uiWidget) + where TWidget : UIWidget, new() + { + uiWidget = null; + var screen = UiMan.ActiveScreen; + if (screen == null) + return false; + + return screen.TryGetWidget(out uiWidget); + } + #endregion #region Power @@ -1009,14 +1181,17 @@ await Server.WaitPost(() => #region Inputs + + /// <summary> /// Make the client press and then release a key. This assumes the key is currently released. + /// This will default to using the <see cref="Target"/> entity and <see cref="TargetCoords"/> coordinates. /// </summary> protected async Task PressKey( BoundKeyFunction key, int ticks = 1, NetCoordinates? coordinates = null, - NetEntity cursorEntity = default) + NetEntity? cursorEntity = null) { await SetKey(key, BoundKeyState.Down, coordinates, cursorEntity); await RunTicks(ticks); @@ -1025,15 +1200,17 @@ protected async Task PressKey( } /// <summary> - /// Make the client press or release a key + /// Make the client press or release a key. + /// This will default to using the <see cref="Target"/> entity and <see cref="TargetCoords"/> coordinates. /// </summary> protected async Task SetKey( BoundKeyFunction key, BoundKeyState state, NetCoordinates? coordinates = null, - NetEntity cursorEntity = default) + NetEntity? cursorEntity = null) { var coords = coordinates ?? TargetCoords; + var target = cursorEntity ?? Target ?? default; ScreenCoordinates screen = default; var funcId = InputManager.NetworkBindMap.KeyFunctionID(key); @@ -1042,7 +1219,7 @@ protected async Task SetKey( State = state, Coordinates = CEntMan.GetCoordinates(coords), ScreenCoordinates = screen, - Uid = CEntMan.GetEntity(cursorEntity), + Uid = CEntMan.GetEntity(target), }; await Client.WaitPost(() => InputSystem.HandleInputCommand(ClientSession, key, message)); diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs index 42f64b344cd..f07f23d84c8 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs @@ -3,6 +3,7 @@ using System.Numerics; using Content.Client.Construction; using Content.Client.Examine; +using Content.Client.Gameplay; using Content.IntegrationTests.Pair; using Content.Server.Body.Systems; using Content.Server.Hands.Systems; @@ -24,6 +25,7 @@ using Robust.Shared.Timing; using Robust.UnitTesting; using Content.Shared.Item.ItemToggle; +using Robust.Client.State; namespace Content.IntegrationTests.Tests.Interaction; @@ -64,15 +66,12 @@ public abstract partial class InteractionTest /// The player entity that performs all these interactions. Defaults to an admin-observer with 1 hand. /// </summary> protected NetEntity Player; - - protected EntityUid SPlayer => ToServer(Player); - protected EntityUid CPlayer => ToClient(Player); + protected EntityUid SPlayer; + protected EntityUid CPlayer; protected ICommonSession ClientSession = default!; protected ICommonSession ServerSession = default!; - public EntityUid? ClientTarget; - /// <summary> /// The current target entity. This is the default entity for various helper functions. /// </summary> @@ -84,6 +83,7 @@ public abstract partial class InteractionTest protected NetEntity? Target; protected EntityUid? STarget => ToServer(Target); + protected EntityUid? CTarget => ToClient(Target); /// <summary> @@ -107,7 +107,9 @@ public abstract partial class InteractionTest protected SharedItemToggleSystem ItemToggleSys = default!; protected InteractionTestSystem STestSystem = default!; protected SharedTransformSystem Transform = default!; + protected SharedMapSystem MapSystem = default!; protected ISawmill SLogger = default!; + protected SharedUserInterfaceSystem SUiSys = default!; // CLIENT dependencies protected IEntityManager CEntMan = default!; @@ -119,6 +121,7 @@ public abstract partial class InteractionTest protected ExamineSystem ExamineSys = default!; protected InteractionTestSystem CTestSystem = default!; protected ISawmill CLogger = default!; + protected SharedUserInterfaceSystem CUiSys = default!; // player components protected HandsComponent Hands = default!; @@ -126,7 +129,6 @@ public abstract partial class InteractionTest public float TickPeriod => (float) STiming.TickPeriod.TotalSeconds; - // Simple mob that has one hand and can perform misc interactions. [TestPrototypes] private const string TestPrototypes = @" @@ -139,6 +141,8 @@ public abstract partial class InteractionTest - type: Hands - type: MindContainer - type: Stripping + - type: Puller + - type: Physics - type: Tag tags: - CanPilot @@ -148,7 +152,7 @@ public abstract partial class InteractionTest [SetUp] public virtual async Task Setup() { - Pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, Dirty = true}); + Pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, Dirty = true }); // server dependencies SEntMan = Server.ResolveDependency<IEntityManager>(); @@ -163,10 +167,12 @@ public virtual async Task Setup() ItemToggleSys = SEntMan.System<SharedItemToggleSystem>(); DoAfterSys = SEntMan.System<SharedDoAfterSystem>(); Transform = SEntMan.System<SharedTransformSystem>(); + MapSystem = SEntMan.System<SharedMapSystem>(); SConstruction = SEntMan.System<Server.Construction.ConstructionSystem>(); STestSystem = SEntMan.System<InteractionTestSystem>(); Stack = SEntMan.System<StackSystem>(); SLogger = Server.ResolveDependency<ILogManager>().RootSawmill; + SUiSys = Client.System<SharedUserInterfaceSystem>(); // client dependencies CEntMan = Client.ResolveDependency<IEntityManager>(); @@ -178,12 +184,14 @@ public virtual async Task Setup() CConSys = CEntMan.System<ConstructionSystem>(); ExamineSys = CEntMan.System<ExamineSystem>(); CLogger = Client.ResolveDependency<ILogManager>().RootSawmill; + CUiSys = Client.System<SharedUserInterfaceSystem>(); // Setup map. await Pair.CreateTestMap(); - PlayerCoords = SEntMan.GetNetCoordinates(MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)).WithEntityId(MapData.MapUid, Transform, SEntMan)); - TargetCoords = SEntMan.GetNetCoordinates(MapData.GridCoords.Offset(new Vector2(1.5f, 0.5f)).WithEntityId(MapData.MapUid, Transform, SEntMan)); - await SetTile(Plating, grid: MapData.Grid.Comp); + + PlayerCoords = SEntMan.GetNetCoordinates(Transform.WithEntityId(MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)), MapData.MapUid)); + TargetCoords = SEntMan.GetNetCoordinates(Transform.WithEntityId(MapData.GridCoords.Offset(new Vector2(1.5f, 0.5f)), MapData.MapUid)); + await SetTile(Plating, grid: MapData.Grid); // Get player data var sPlayerMan = Server.ResolveDependency<Robust.Server.Player.IPlayerManager>(); @@ -202,16 +210,17 @@ await Server.WaitPost(() => SEntMan.System<SharedMindSystem>().WipeMind(ServerSession.ContentData()?.Mind); old = cPlayerMan.LocalEntity; - Player = SEntMan.GetNetEntity(SEntMan.SpawnEntity(PlayerPrototype, SEntMan.GetCoordinates(PlayerCoords))); - var serverPlayerEnt = SEntMan.GetEntity(Player); - Server.PlayerMan.SetAttachedEntity(ServerSession, serverPlayerEnt); - Hands = SEntMan.GetComponent<HandsComponent>(serverPlayerEnt); - DoAfters = SEntMan.GetComponent<DoAfterComponent>(serverPlayerEnt); + SPlayer = SEntMan.SpawnEntity(PlayerPrototype, SEntMan.GetCoordinates(PlayerCoords)); + Player = SEntMan.GetNetEntity(SPlayer); + Server.PlayerMan.SetAttachedEntity(ServerSession, SPlayer); + Hands = SEntMan.GetComponent<HandsComponent>(SPlayer); + DoAfters = SEntMan.GetComponent<DoAfterComponent>(SPlayer); }); // Check player got attached. await RunTicks(5); - Assert.That(CEntMan.GetNetEntity(cPlayerMan.LocalEntity), Is.EqualTo(Player)); + CPlayer = ToClient(Player); + Assert.That(cPlayerMan.LocalEntity, Is.EqualTo(CPlayer)); // Delete old player entity. await Server.WaitPost(() => @@ -234,6 +243,10 @@ await Server.WaitPost(() => } }); + // Change UI state to in-game. + var state = Client.ResolveDependency<IStateManager>(); + await Client.WaitPost(() => state.RequestStateChange<GameplayState>()); + // Final player asserts/checks. await Pair.ReallyBeIdle(5); Assert.Multiple(() => @@ -251,7 +264,8 @@ public async Task TearDownInternal() await TearDown(); } - protected virtual async Task TearDown() + protected virtual Task TearDown() { + return Task.CompletedTask; } } diff --git a/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs b/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs index 30724b50a6d..0632fe1347c 100644 --- a/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs +++ b/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs @@ -26,26 +26,26 @@ public async Task TestStaticFieldValidation() protos.Add(kind, ids); } - Assert.That(protoMan.ValidateStaticFields(typeof(StringValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayValid), protos).Count, Is.Zero); - - Assert.That(protoMan.ValidateStaticFields(typeof(StringInvalid), protos).Count, Is.EqualTo(1)); - Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayInvalid), protos).Count, Is.EqualTo(2)); - Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdInvalid), protos).Count, Is.EqualTo(1)); - Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestInvalid), protos).Count, Is.EqualTo(1)); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListInvalid), protos).Count, Is.EqualTo(2)); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetInvalid), protos).Count, Is.EqualTo(2)); - Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); - + Assert.That(protoMan.ValidateStaticFields(typeof(StringValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayValid), protos), Is.Empty); + + Assert.That(protoMan.ValidateStaticFields(typeof(StringInvalid), protos), Has.Count.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayInvalid), protos), Has.Count.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdInvalid), protos), Has.Count.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayInvalid), protos), Has.Count.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestInvalid), protos), Has.Count.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayInvalid), protos), Has.Count.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListInvalid), protos), Has.Count.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetInvalid), protos), Has.Count.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayInvalid), protos), Has.Count.EqualTo(2)); + await pair.CleanReturnAsync(); } @@ -58,93 +58,111 @@ public async Task TestStaticFieldValidation() id: StaticFieldTestTag "; - [Reflect(false)] private sealed class StringValid + [Reflect(false)] + private sealed class StringValid { [ValidatePrototypeId<TagPrototype>] public static string Tag = "StaticFieldTestTag"; } - [Reflect(false)] private sealed class StringInvalid + [Reflect(false)] + private sealed class StringInvalid { [ValidatePrototypeId<TagPrototype>] public static string Tag = string.Empty; } - [Reflect(false)] private sealed class StringArrayValid + [Reflect(false)] + private sealed class StringArrayValid { - [ValidatePrototypeId<TagPrototype>] public static string[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + [ValidatePrototypeId<TagPrototype>] public static string[] Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } - [Reflect(false)] private sealed class StringArrayInvalid + [Reflect(false)] + private sealed class StringArrayInvalid { - [ValidatePrototypeId<TagPrototype>] public static string[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + [ValidatePrototypeId<TagPrototype>] public static string[] Tag = [string.Empty, "StaticFieldTestTag", string.Empty]; } - [Reflect(false)] private sealed class EntProtoIdValid + [Reflect(false)] + private sealed class EntProtoIdValid { public static EntProtoId Tag = "StaticFieldTestEnt"; } - [Reflect(false)] private sealed class EntProtoIdInvalid + [Reflect(false)] + private sealed class EntProtoIdInvalid { public static EntProtoId Tag = string.Empty; } - [Reflect(false)] private sealed class EntProtoIdArrayValid + [Reflect(false)] + private sealed class EntProtoIdArrayValid { - public static EntProtoId[] Tag = {"StaticFieldTestEnt", "StaticFieldTestEnt"}; + public static EntProtoId[] Tag = ["StaticFieldTestEnt", "StaticFieldTestEnt"]; } - [Reflect(false)] private sealed class EntProtoIdArrayInvalid + [Reflect(false)] + private sealed class EntProtoIdArrayInvalid { - public static EntProtoId[] Tag = {string.Empty, "StaticFieldTestEnt", string.Empty}; + public static EntProtoId[] Tag = [string.Empty, "StaticFieldTestEnt", string.Empty]; } - [Reflect(false)] private sealed class ProtoIdTestValid + [Reflect(false)] + private sealed class ProtoIdTestValid { public static ProtoId<TagPrototype> Tag = "StaticFieldTestTag"; } - [Reflect(false)] private sealed class ProtoIdTestInvalid + [Reflect(false)] + private sealed class ProtoIdTestInvalid { public static ProtoId<TagPrototype> Tag = string.Empty; } - [Reflect(false)] private sealed class ProtoIdArrayValid + [Reflect(false)] + private sealed class ProtoIdArrayValid { - public static ProtoId<TagPrototype>[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + public static ProtoId<TagPrototype>[] Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } - [Reflect(false)] private sealed class ProtoIdArrayInvalid + [Reflect(false)] + private sealed class ProtoIdArrayInvalid { - public static ProtoId<TagPrototype>[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + public static ProtoId<TagPrototype>[] Tag = [string.Empty, "StaticFieldTestTag", string.Empty]; } - [Reflect(false)] private sealed class ProtoIdListValid + [Reflect(false)] + private sealed class ProtoIdListValid { - public static List<ProtoId<TagPrototype>> Tag = new() {"StaticFieldTestTag", "StaticFieldTestTag"}; + public static List<ProtoId<TagPrototype>> Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } - [Reflect(false)] private sealed class ProtoIdListInvalid + [Reflect(false)] + private sealed class ProtoIdListInvalid { - public static List<ProtoId<TagPrototype>> Tag = new() {string.Empty, "StaticFieldTestTag", string.Empty}; + public static List<ProtoId<TagPrototype>> Tag = [string.Empty, "StaticFieldTestTag", string.Empty]; } - [Reflect(false)] private sealed class ProtoIdSetValid + [Reflect(false)] + private sealed class ProtoIdSetValid { - public static HashSet<ProtoId<TagPrototype>> Tag = new() {"StaticFieldTestTag", "StaticFieldTestTag"}; + public static HashSet<ProtoId<TagPrototype>> Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } - [Reflect(false)] private sealed class ProtoIdSetInvalid + [Reflect(false)] + private sealed class ProtoIdSetInvalid { - public static HashSet<ProtoId<TagPrototype>> Tag = new() {string.Empty, "StaticFieldTestTag", string.Empty, " "}; + public static HashSet<ProtoId<TagPrototype>> Tag = [string.Empty, "StaticFieldTestTag", string.Empty, " "]; } - [Reflect(false)] private sealed class PrivateProtoIdArrayValid + [Reflect(false)] + private sealed class PrivateProtoIdArrayValid { - private static ProtoId<TagPrototype>[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + private static readonly ProtoId<TagPrototype>[] Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } - [Reflect(false)] private sealed class PrivateProtoIdArrayInvalid + [Reflect(false)] + private sealed class PrivateProtoIdArrayInvalid { - private static ProtoId<TagPrototype>[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + private static readonly ProtoId<TagPrototype>[] Tag = [string.Empty, "StaticFieldTestTag", string.Empty]; } } diff --git a/Content.IntegrationTests/Tests/MachineBoardTest.cs b/Content.IntegrationTests/Tests/MachineBoardTest.cs index bd3a72f4c1d..097f38af420 100644 --- a/Content.IntegrationTests/Tests/MachineBoardTest.cs +++ b/Content.IntegrationTests/Tests/MachineBoardTest.cs @@ -2,6 +2,7 @@ using System.Linq; using Content.Server.Construction.Components; using Content.Shared.Construction.Components; +using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; namespace Content.IntegrationTests.Tests; @@ -35,6 +36,7 @@ public async Task TestMachineBoardHasValidMachine() var server = pair.Server; var protoMan = server.ResolveDependency<IPrototypeManager>(); + var compFact = server.ResolveDependency<IComponentFactory>(); await server.WaitAssertion(() => { @@ -43,7 +45,7 @@ await server.WaitAssertion(() => .Where(p => !pair.IsTestPrototype(p)) .Where(p => !_ignoredPrototypes.Contains(p.ID))) { - if (!p.TryGetComponent<MachineBoardComponent>(out var mbc)) + if (!p.TryGetComponent<MachineBoardComponent>(out var mbc, compFact)) continue; var mId = mbc.Prototype; @@ -52,7 +54,7 @@ await server.WaitAssertion(() => Assert.That(mId, Is.Not.Null, $"Machine board {p.ID} does not have a corresponding machine."); Assert.That(protoMan.TryIndex<EntityPrototype>(mId, out var mProto), $"Machine board {p.ID}'s corresponding machine has an invalid prototype."); - Assert.That(mProto.TryGetComponent<MachineComponent>(out var mComp), + Assert.That(mProto.TryGetComponent<MachineComponent>(out var mComp, compFact), $"Machine board {p.ID}'s corresponding machine {mId} does not have MachineComponent"); Assert.That(mComp.BoardPrototype, Is.EqualTo(p.ID), $"Machine {mId}'s BoardPrototype is not equal to it's corresponding machine board, {p.ID}"); @@ -74,6 +76,7 @@ public async Task TestComputerBoardHasValidComputer() var server = pair.Server; var protoMan = server.ResolveDependency<IPrototypeManager>(); + var compFact = server.ResolveDependency<IComponentFactory>(); await server.WaitAssertion(() => { @@ -82,7 +85,7 @@ await server.WaitAssertion(() => .Where(p => !pair.IsTestPrototype(p)) .Where(p => !_ignoredPrototypes.Contains(p.ID))) { - if (!p.TryGetComponent<ComputerBoardComponent>(out var cbc)) + if (!p.TryGetComponent<ComputerBoardComponent>(out var cbc, compFact)) continue; var cId = cbc.Prototype; @@ -91,7 +94,7 @@ await server.WaitAssertion(() => Assert.That(cId, Is.Not.Null, $"Computer board \"{p.ID}\" does not have a corresponding computer."); Assert.That(protoMan.TryIndex<EntityPrototype>(cId, out var cProto), $"Computer board \"{p.ID}\"'s corresponding computer has an invalid prototype."); - Assert.That(cProto.TryGetComponent<ComputerComponent>(out var cComp), + Assert.That(cProto.TryGetComponent<ComputerComponent>(out var cComp, compFact), $"Computer board {p.ID}'s corresponding computer \"{cId}\" does not have ComputerComponent"); Assert.That(cComp.BoardPrototype, Is.EqualTo(p.ID), $"Computer \"{cId}\"'s BoardPrototype is not equal to it's corresponding computer board, \"{p.ID}\""); diff --git a/Content.IntegrationTests/Tests/Mapping/MappingTests.cs b/Content.IntegrationTests/Tests/Mapping/MappingTests.cs index 287e30eb8b1..be8bad229b4 100644 --- a/Content.IntegrationTests/Tests/Mapping/MappingTests.cs +++ b/Content.IntegrationTests/Tests/Mapping/MappingTests.cs @@ -13,7 +13,7 @@ public sealed class MappingTests [Test] public async Task MappingTest() { - await using var pair = await PoolManager.GetServerClient(new PoolSettings {Dirty = true, Connected = true, DummyTicker = false}); + await using var pair = await PoolManager.GetServerClient(new PoolSettings { Dirty = true, Connected = true, DummyTicker = false }); var server = pair.Server; var entMan = server.EntMan; diff --git a/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs b/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs index 7f9c02fc13b..12b395f86d3 100644 --- a/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs +++ b/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs @@ -38,15 +38,16 @@ public async Task NoMaterialArbitrage() await server.WaitIdleAsync(); var entManager = server.ResolveDependency<IEntityManager>(); - var sysManager = server.ResolveDependency<IEntitySystemManager>(); var mapManager = server.ResolveDependency<IMapManager>(); - Assert.That(mapManager.IsMapInitialized(testMap.MapId)); - var protoManager = server.ResolveDependency<IPrototypeManager>(); - var pricing = sysManager.GetEntitySystem<PricingSystem>(); - var stackSys = sysManager.GetEntitySystem<StackSystem>(); + + var pricing = entManager.System<PricingSystem>(); + var stackSys = entManager.System<StackSystem>(); + var mapSystem = server.System<SharedMapSystem>(); var compFact = server.ResolveDependency<IComponentFactory>(); + Assert.That(mapSystem.IsInitialized(testMap.MapId)); + var constructionName = compFact.GetComponentName(typeof(ConstructionComponent)); var compositionName = compFact.GetComponentName(typeof(PhysicalCompositionComponent)); var materialName = compFact.GetComponentName(typeof(MaterialComponent)); @@ -66,7 +67,7 @@ public async Task NoMaterialArbitrage() Dictionary<string, ConstructionComponent> constructionRecipes = new(); foreach (var proto in protoManager.EnumeratePrototypes<EntityPrototype>()) { - if (proto.NoSpawn || proto.Abstract || pair.IsTestPrototype(proto)) + if (proto.HideSpawnMenu || proto.Abstract || pair.IsTestPrototype(proto)) continue; if (!proto.Components.TryGetValue(constructionName, out var destructible)) @@ -126,7 +127,7 @@ public async Task NoMaterialArbitrage() // Here we get the set of entities/materials spawned when destroying an entity. foreach (var proto in protoManager.EnumeratePrototypes<EntityPrototype>()) { - if (proto.NoSpawn || proto.Abstract || pair.IsTestPrototype(proto)) + if (proto.HideSpawnMenu || proto.Abstract || pair.IsTestPrototype(proto)) continue; if (!proto.Components.TryGetValue(destructibleName, out var destructible)) @@ -297,7 +298,7 @@ public async Task NoMaterialArbitrage() Dictionary<string, PhysicalCompositionComponent> physicalCompositions = new(); foreach (var proto in protoManager.EnumeratePrototypes<EntityPrototype>()) { - if (proto.NoSpawn || proto.Abstract || pair.IsTestPrototype(proto)) + if (proto.HideSpawnMenu || proto.Abstract || pair.IsTestPrototype(proto)) continue; if (!proto.Components.TryGetValue(compositionName, out var composition)) diff --git a/Content.IntegrationTests/Tests/Minds/GhostTests.cs b/Content.IntegrationTests/Tests/Minds/GhostTests.cs index ad9d53a70db..3a860267e55 100644 --- a/Content.IntegrationTests/Tests/Minds/GhostTests.cs +++ b/Content.IntegrationTests/Tests/Minds/GhostTests.cs @@ -14,7 +14,7 @@ namespace Content.IntegrationTests.Tests.Minds; [TestFixture] public sealed class GhostTests { - struct GhostTestData + private struct GhostTestData { public IEntityManager SEntMan; public Robust.Server.Player.IPlayerManager SPlayerMan; @@ -23,10 +23,10 @@ struct GhostTestData public TestPair Pair = default!; - public TestMapData MapData => Pair.TestMap!; + public readonly TestMapData MapData => Pair.TestMap!; - public RobustIntegrationTest.ServerIntegrationInstance Server => Pair.Server; - public RobustIntegrationTest.ClientIntegrationInstance Client => Pair.Client; + public readonly RobustIntegrationTest.ServerIntegrationInstance Server => Pair.Server; + public readonly RobustIntegrationTest.ClientIntegrationInstance Client => Pair.Client; /// <summary> /// Initial player coordinates. Note that this does not necessarily correspond to the position of the @@ -47,15 +47,16 @@ public GhostTestData() private async Task<GhostTestData> SetupData() { - var data = new GhostTestData(); - - // Client is needed to create a session for the ghost system. Creating a dummy session was too difficult. - data.Pair = await PoolManager.GetServerClient(new PoolSettings + var data = new GhostTestData { - DummyTicker = false, - Connected = true, - Dirty = true - }); + // Client is needed to create a session for the ghost system. Creating a dummy session was too difficult. + Pair = await PoolManager.GetServerClient(new PoolSettings + { + DummyTicker = false, + Connected = true, + Dirty = true + }) + }; data.SEntMan = data.Pair.Server.ResolveDependency<IServerEntityManager>(); data.SPlayerMan = data.Pair.Server.ResolveDependency<Robust.Server.Player.IPlayerManager>(); @@ -64,7 +65,8 @@ private async Task<GhostTestData> SetupData() // Setup map. await data.Pair.CreateTestMap(); - data.PlayerCoords = data.SEntMan.GetNetCoordinates(data.MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)).WithEntityId(data.MapData.MapUid, data.STransformSys, data.SEntMan)); + var test = data.MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)); + data.PlayerCoords = data.SEntMan.GetNetCoordinates(data.STransformSys.WithEntityId(data.MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)), data.MapData.MapUid)); if (data.Client.Session == null) Assert.Fail("No player"); @@ -156,4 +158,20 @@ public async Task TestGridGhostOnQueueDelete() await data.Pair.CleanReturnAsync(); } + [Test] + public async Task TestGhostGridNotTerminating() + { + var data = await SetupData(); + + Assert.DoesNotThrowAsync(async () => + { + // Delete the grid + await data.Server.WaitPost(() => data.SEntMan.DeleteEntity(data.MapData.Grid.Owner)); + }); + + await data.Pair.RunTicksSync(5); + + await data.Pair.CleanReturnAsync(); + } + } diff --git a/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs b/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs index 428380631d7..b12c90e16e2 100644 --- a/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs +++ b/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs @@ -169,7 +169,7 @@ private static async Task Connect(Pair.TestPair pair, string username) { var netManager = pair.Client.ResolveDependency<IClientNetManager>(); var playerMan = pair.Server.ResolveDependency<IPlayerManager>(); - Assert.That(!playerMan.Sessions.Any()); + Assert.That(playerMan.Sessions, Is.Empty); await Task.WhenAll(pair.Client.WaitIdleAsync(), pair.Client.WaitIdleAsync()); pair.Client.SetConnectTarget(pair.Server); diff --git a/Content.IntegrationTests/Tests/Movement/BuckleMovementTest.cs b/Content.IntegrationTests/Tests/Movement/BuckleMovementTest.cs new file mode 100644 index 00000000000..3119ee55924 --- /dev/null +++ b/Content.IntegrationTests/Tests/Movement/BuckleMovementTest.cs @@ -0,0 +1,63 @@ +using Content.Shared.Alert; +using Content.Shared.Buckle.Components; +using Robust.Shared.Maths; + +namespace Content.IntegrationTests.Tests.Movement; + +public sealed class BuckleMovementTest : MovementTest +{ + // Check that interacting with a chair straps you to it and prevents movement. + [Test] + public async Task ChairTest() + { + await SpawnTarget("Chair"); + + var cAlert = Client.System<AlertsSystem>(); + var sAlert = Server.System<AlertsSystem>(); + var buckle = Comp<BuckleComponent>(Player); + var strap = Comp<StrapComponent>(Target); + +#pragma warning disable RA0002 + buckle.Delay = TimeSpan.Zero; +#pragma warning restore RA0002 + + // Initially not buckled to the chair, and standing off to the side + Assert.That(Delta(), Is.InRange(0.9f, 1.1f)); + Assert.That(buckle.Buckled, Is.False); + Assert.That(buckle.BuckledTo, Is.Null); + Assert.That(strap.BuckledEntities, Is.Empty); + Assert.That(cAlert.IsShowingAlert(CPlayer, strap.BuckledAlertType), Is.False); + Assert.That(sAlert.IsShowingAlert(SPlayer, strap.BuckledAlertType), Is.False); + + // Interact results in being buckled to the chair + await Interact(); + Assert.That(Delta(), Is.InRange(-0.01f, 0.01f)); + Assert.That(buckle.Buckled, Is.True); + Assert.That(buckle.BuckledTo, Is.EqualTo(STarget)); + Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[] { SPlayer })); + Assert.That(cAlert.IsShowingAlert(CPlayer, strap.BuckledAlertType), Is.True); + Assert.That(sAlert.IsShowingAlert(SPlayer, strap.BuckledAlertType), Is.True); + + // Attempting to walk away does nothing + await Move(DirectionFlag.East, 1); + Assert.That(Delta(), Is.InRange(-0.01f, 0.01f)); + Assert.That(buckle.Buckled, Is.True); + Assert.That(buckle.BuckledTo, Is.EqualTo(STarget)); + Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[] { SPlayer })); + Assert.That(cAlert.IsShowingAlert(CPlayer, strap.BuckledAlertType), Is.True); + Assert.That(sAlert.IsShowingAlert(SPlayer, strap.BuckledAlertType), Is.True); + + // Interacting again will unbuckle the player + await Interact(); + Assert.That(Delta(), Is.InRange(-0.5f, 0.5f)); + Assert.That(buckle.Buckled, Is.False); + Assert.That(buckle.BuckledTo, Is.Null); + Assert.That(strap.BuckledEntities, Is.Empty); + Assert.That(cAlert.IsShowingAlert(CPlayer, strap.BuckledAlertType), Is.False); + Assert.That(sAlert.IsShowingAlert(SPlayer, strap.BuckledAlertType), Is.False); + + // And now they can move away + await Move(DirectionFlag.SouthEast, 1); + Assert.That(Delta(), Is.LessThan(-1)); + } +} diff --git a/Content.IntegrationTests/Tests/Interaction/MovementTest.cs b/Content.IntegrationTests/Tests/Movement/MovementTest.cs similarity index 93% rename from Content.IntegrationTests/Tests/Interaction/MovementTest.cs rename to Content.IntegrationTests/Tests/Movement/MovementTest.cs index dc5aec92cfc..eba92530388 100644 --- a/Content.IntegrationTests/Tests/Interaction/MovementTest.cs +++ b/Content.IntegrationTests/Tests/Movement/MovementTest.cs @@ -1,8 +1,9 @@ #nullable enable using System.Numerics; +using Content.IntegrationTests.Tests.Interaction; using Robust.Shared.GameObjects; -namespace Content.IntegrationTests.Tests.Interaction; +namespace Content.IntegrationTests.Tests.Movement; /// <summary> /// This is a variation of <see cref="InteractionTest"/> that sets up the player with a normal human entity and a simple @@ -31,7 +32,7 @@ public override async Task Setup() for (var i = -Tiles; i <= Tiles; i++) { - await SetTile(Plating, SEntMan.GetNetCoordinates(pCoords.Offset(new Vector2(i, 0))), MapData.Grid.Comp); + await SetTile(Plating, SEntMan.GetNetCoordinates(pCoords.Offset(new Vector2(i, 0))), MapData.Grid); } AssertGridCount(1); diff --git a/Content.IntegrationTests/Tests/Movement/PullingTest.cs b/Content.IntegrationTests/Tests/Movement/PullingTest.cs new file mode 100644 index 00000000000..d96c4ea0e56 --- /dev/null +++ b/Content.IntegrationTests/Tests/Movement/PullingTest.cs @@ -0,0 +1,73 @@ +#nullable enable +using Content.Shared.Alert; +using Content.Shared.Input; +using Content.Shared.Movement.Pulling.Components; +using Robust.Shared.Maths; + +namespace Content.IntegrationTests.Tests.Movement; + +public sealed class PullingTest : MovementTest +{ + protected override int Tiles => 4; + + [Test] + public async Task PullTest() + { + var cAlert = Client.System<AlertsSystem>(); + var sAlert = Server.System<AlertsSystem>(); + await SpawnTarget("MobHuman"); + + var puller = Comp<PullerComponent>(Player); + var pullable = Comp<PullableComponent>(Target); + + // Player is initially to the left of the target and not pulling anything + Assert.That(Delta(), Is.InRange(0.9f, 1.1f)); + Assert.That(puller.Pulling, Is.Null); + Assert.That(pullable.Puller, Is.Null); + Assert.That(pullable.BeingPulled, Is.False); + Assert.That(cAlert.IsShowingAlert(CPlayer, puller.PullingAlert), Is.False); + Assert.That(sAlert.IsShowingAlert(SPlayer, puller.PullingAlert), Is.False); + + // Start pulling + await PressKey(ContentKeyFunctions.TryPullObject); + await RunTicks(5); + Assert.That(puller.Pulling, Is.EqualTo(STarget)); + Assert.That(pullable.Puller, Is.EqualTo(SPlayer)); + Assert.That(pullable.BeingPulled, Is.True); + Assert.That(cAlert.IsShowingAlert(CPlayer, puller.PullingAlert), Is.True); + Assert.That(sAlert.IsShowingAlert(SPlayer, puller.PullingAlert), Is.True); + + // Move to the left and check that the target moves with the player and is still being pulled. + await Move(DirectionFlag.West, 1); + Assert.That(Delta(), Is.InRange(0.9f, 1.3f)); + Assert.That(puller.Pulling, Is.EqualTo(STarget)); + Assert.That(pullable.Puller, Is.EqualTo(SPlayer)); + Assert.That(pullable.BeingPulled, Is.True); + Assert.That(cAlert.IsShowingAlert(CPlayer, puller.PullingAlert), Is.True); + Assert.That(sAlert.IsShowingAlert(SPlayer, puller.PullingAlert), Is.True); + + // Move in the other direction + await Move(DirectionFlag.East, 2); + Assert.That(Delta(), Is.InRange(-1.3f, -0.9f)); + Assert.That(puller.Pulling, Is.EqualTo(STarget)); + Assert.That(pullable.Puller, Is.EqualTo(SPlayer)); + Assert.That(pullable.BeingPulled, Is.True); + Assert.That(cAlert.IsShowingAlert(CPlayer, puller.PullingAlert), Is.True); + Assert.That(sAlert.IsShowingAlert(SPlayer, puller.PullingAlert), Is.True); + + // Stop pulling + await PressKey(ContentKeyFunctions.ReleasePulledObject); + await RunTicks(5); + Assert.That(Delta(), Is.InRange(-1.3f, -0.9f)); + Assert.That(puller.Pulling, Is.Null); + Assert.That(pullable.Puller, Is.Null); + Assert.That(pullable.BeingPulled, Is.False); + Assert.That(cAlert.IsShowingAlert(CPlayer, puller.PullingAlert), Is.False); + Assert.That(sAlert.IsShowingAlert(SPlayer, puller.PullingAlert), Is.False); + + // Move back to the left and ensure the target is no longer following us. + await Move(DirectionFlag.West, 2); + Assert.That(Delta(), Is.GreaterThan(2f)); + } +} + diff --git a/Content.IntegrationTests/Tests/Slipping/SlippingTest.cs b/Content.IntegrationTests/Tests/Movement/SlippingTest.cs similarity index 92% rename from Content.IntegrationTests/Tests/Slipping/SlippingTest.cs rename to Content.IntegrationTests/Tests/Movement/SlippingTest.cs index 28da7a94658..9ac84a0a586 100644 --- a/Content.IntegrationTests/Tests/Slipping/SlippingTest.cs +++ b/Content.IntegrationTests/Tests/Movement/SlippingTest.cs @@ -11,7 +11,7 @@ using Robust.Shared.IoC; using Robust.Shared.Maths; -namespace Content.IntegrationTests.Tests.Slipping; +namespace Content.IntegrationTests.Tests.Movement; public sealed class SlippingTest : MovementTest { @@ -41,18 +41,14 @@ public async Task BananaSlipTest() // Assert.That(modifier, Is.EqualTo(1), "Player is not moving at full speed."); // Yeeting this pointless Assert because it's not actually important. // Player is to the left of the banana peel and has not slipped. -#pragma warning disable NUnit2045 Assert.That(Delta(), Is.GreaterThan(0.5f)); Assert.That(sys.Slipped, Does.Not.Contain(SEntMan.GetEntity(Player))); -#pragma warning restore NUnit2045 // Walking over the banana slowly does not trigger a slip. await SetKey(EngineKeyFunctions.Walk, sprintWalks ? BoundKeyState.Up : BoundKeyState.Down); await Move(DirectionFlag.East, 1f); -#pragma warning disable NUnit2045 Assert.That(Delta(), Is.LessThan(0.5f)); Assert.That(sys.Slipped, Does.Not.Contain(SEntMan.GetEntity(Player))); -#pragma warning restore NUnit2045 AssertComp<KnockedDownComponent>(false, Player); // Moving at normal speeds does trigger a slip. diff --git a/Content.IntegrationTests/Tests/Networking/PvsCommandTest.cs b/Content.IntegrationTests/Tests/Networking/PvsCommandTest.cs index 4783d21a053..b3955698489 100644 --- a/Content.IntegrationTests/Tests/Networking/PvsCommandTest.cs +++ b/Content.IntegrationTests/Tests/Networking/PvsCommandTest.cs @@ -7,12 +7,12 @@ namespace Content.IntegrationTests.Tests.Networking; [TestFixture] public sealed class PvsCommandTest { - public static EntProtoId TestEnt = "MobHuman"; + private static readonly EntProtoId TestEnt = "MobHuman"; [Test] public async Task TestPvsCommands() { - await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, DummyTicker = false}); + await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, DummyTicker = false }); var (server, client) = pair; await pair.RunTicksSync(5); diff --git a/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs b/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs index 52d464fa41e..29f2573c2d9 100644 --- a/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs +++ b/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs @@ -51,11 +51,12 @@ public async Task Test() PredictionTestComponent clientComponent = default!; var serverSystem = sEntityManager.System<PredictionTestEntitySystem>(); var clientSystem = cEntityManager.System<PredictionTestEntitySystem>(); + var sMapSys = sEntityManager.System<SharedMapSystem>(); await server.WaitPost(() => { // Spawn dummy component entity. - var map = sMapManager.CreateMap(); + sMapSys.CreateMap(out var map); serverEnt = sEntityManager.SpawnEntity(null, new MapCoordinates(new Vector2(0, 0), map)); serverComponent = sEntityManager.AddComponent<PredictionTestComponent>(serverEnt); }); @@ -67,7 +68,7 @@ await server.WaitPost(() => Assert.That(sGameTiming.TickTimingAdjustment, Is.EqualTo(0)); // Check client buffer is full - Assert.That(cGameStateManager.CurrentBufferSize, Is.EqualTo(cGameStateManager.TargetBufferSize)); + Assert.That(cGameStateManager.GetApplicableStateCount(), Is.EqualTo(cGameStateManager.TargetBufferSize)); Assert.That(cGameStateManager.TargetBufferSize, Is.EqualTo(2)); // This isn't required anymore, but the test had this for the sake of "technical things", and I cbf shifting @@ -99,7 +100,7 @@ await client.WaitPost(() => // Client last ran tick 15 meaning it's ahead of the last server tick it processed (12) Assert.That(cGameTiming.CurTick, Is.EqualTo(expected)); - Assert.That(cGameTiming.LastProcessedTick, Is.EqualTo(new GameTick((uint)(baseTick - cGameStateManager.TargetBufferSize)))); + Assert.That(cGameTiming.LastProcessedTick, Is.EqualTo(new GameTick((uint) (baseTick - cGameStateManager.TargetBufferSize)))); }); // *** I am using block scopes to visually distinguish these sections of the test to make it more readable. @@ -264,7 +265,7 @@ await client.WaitPost(() => // Assert timing is still correct. Assert.That(sGameTiming.CurTick, Is.EqualTo(new GameTick(baseTick + 8))); Assert.That(cGameTiming.CurTick, Is.EqualTo(new GameTick(baseTick + 8 + delta))); - Assert.That(cGameTiming.LastProcessedTick, Is.EqualTo(new GameTick((uint)(baseTick + 8 - cGameStateManager.TargetBufferSize)))); + Assert.That(cGameTiming.LastProcessedTick, Is.EqualTo(new GameTick((uint) (baseTick + 8 - cGameStateManager.TargetBufferSize)))); }); { diff --git a/Content.IntegrationTests/Tests/Payload/ModularGrenadeTests.cs b/Content.IntegrationTests/Tests/Payload/ModularGrenadeTests.cs index 70179fdec1a..4db79373d38 100644 --- a/Content.IntegrationTests/Tests/Payload/ModularGrenadeTests.cs +++ b/Content.IntegrationTests/Tests/Payload/ModularGrenadeTests.cs @@ -22,32 +22,32 @@ public async Task AssembleAndDetonateGrenade() Target = SEntMan.GetNetEntity(await FindEntity("ModularGrenade")); await Drop(); - await Interact(Cable); + await InteractUsing(Cable); // Insert & remove trigger AssertComp<OnUseTimerTriggerComponent>(false); - await Interact(Trigger); + await InteractUsing(Trigger); AssertComp<OnUseTimerTriggerComponent>(); await FindEntity(Trigger, LookupFlags.Uncontained, shouldSucceed: false); - await Interact(Pry); + await InteractUsing(Pry); AssertComp<OnUseTimerTriggerComponent>(false); // Trigger was dropped to floor, not deleted. await FindEntity(Trigger, LookupFlags.Uncontained); // Re-insert - await Interact(Trigger); + await InteractUsing(Trigger); AssertComp<OnUseTimerTriggerComponent>(); // Insert & remove payload. - await Interact(Payload); + await InteractUsing(Payload); await FindEntity(Payload, LookupFlags.Uncontained, shouldSucceed: false); - await Interact(Pry); + await InteractUsing(Pry); var ent = await FindEntity(Payload, LookupFlags.Uncontained); await Delete(ent); // successfully insert a second time - await Interact(Payload); + await InteractUsing(Payload); ent = await FindEntity(Payload); var sys = SEntMan.System<SharedContainerSystem>(); Assert.That(sys.IsEntityInContainer(ent)); diff --git a/Content.IntegrationTests/Tests/PostMapInitTest.cs b/Content.IntegrationTests/Tests/PostMapInitTest.cs index 05f603408b3..aebe3a1c0eb 100644 --- a/Content.IntegrationTests/Tests/PostMapInitTest.cs +++ b/Content.IntegrationTests/Tests/PostMapInitTest.cs @@ -16,6 +16,7 @@ using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Prototypes; +using FastAccessors; using Robust.Shared.Utility; using YamlDotNet.RepresentationModel; @@ -77,13 +78,14 @@ public async Task GridsLoadableTest(string mapFile) var entManager = server.ResolveDependency<IEntityManager>(); var mapLoader = entManager.System<MapLoaderSystem>(); + var mapSystem = entManager.System<SharedMapSystem>(); var mapManager = server.ResolveDependency<IMapManager>(); var cfg = server.ResolveDependency<IConfigurationManager>(); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False); await server.WaitPost(() => { - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); try { #pragma warning disable NUnit2045 @@ -164,6 +166,7 @@ public async Task GameMapsLoadableTest(string mapProto) var mapManager = server.ResolveDependency<IMapManager>(); var entManager = server.ResolveDependency<IEntityManager>(); var mapLoader = entManager.System<MapLoaderSystem>(); + var mapSystem = entManager.System<SharedMapSystem>(); var protoManager = server.ResolveDependency<IPrototypeManager>(); var ticker = entManager.EntitySysManager.GetEntitySystem<GameTicker>(); var shuttleSystem = entManager.EntitySysManager.GetEntitySystem<ShuttleSystem>(); @@ -173,7 +176,7 @@ public async Task GameMapsLoadableTest(string mapProto) await server.WaitPost(() => { - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); try { ticker.LoadGameMap(protoManager.Index<GameMapPrototype>(mapProto), mapId, null); @@ -183,7 +186,7 @@ await server.WaitPost(() => throw new Exception($"Failed to load map {mapProto}", ex); } - var shuttleMap = mapManager.CreateMap(); + mapSystem.CreateMap(out var shuttleMap); var largest = 0f; EntityUid? targetGrid = null; var memberQuery = entManager.GetEntityQuery<StationMemberComponent>(); @@ -242,24 +245,17 @@ await server.WaitPost(() => Assert.That(lateSpawns, Is.GreaterThan(0), $"Found no latejoin spawn points on {mapProto}"); } + var comp = entManager.GetComponent<StationJobsComponent>(station); + var jobs = new HashSet<string>(comp.SetupAvailableJobs.Keys); + // Test all availableJobs have spawnPoints // This is done inside gamemap test because loading the map takes ages and we already have it. - var jobList = entManager.GetComponent<StationJobsComponent>(station).RoundStartJobList - .Where(x => x.Value != 0) - .Select(x => x.Key); var spawnPoints = entManager.EntityQuery<SpawnPointComponent>() - .Where(spawnpoint => spawnpoint.SpawnType == SpawnPointType.Job) - .Select(spawnpoint => spawnpoint.Job.ID) - .Distinct(); - List<string> missingSpawnPoints = new(); - foreach (var spawnpoint in jobList.Except(spawnPoints)) - { - if (protoManager.Index<JobPrototype>(spawnpoint).SetPreference) - missingSpawnPoints.Add(spawnpoint); - } + .Where(x => x.SpawnType == SpawnPointType.Job) + .Select(x => x.Job!.ID); - Assert.That(missingSpawnPoints, Has.Count.EqualTo(0), - $"There is no spawnpoint for {string.Join(", ", missingSpawnPoints)} on {mapProto}."); + jobs.ExceptWith(spawnPoints); + Assert.That(jobs, Is.Empty, $"There is no spawnpoints for {string.Join(", ", jobs)} on {mapProto}."); } try @@ -332,6 +328,7 @@ public async Task NonGameMapsLoadableTest() var resourceManager = server.ResolveDependency<IResourceManager>(); var protoManager = server.ResolveDependency<IPrototypeManager>(); var cfg = server.ResolveDependency<IConfigurationManager>(); + var mapSystem = server.System<SharedMapSystem>(); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False); var gameMaps = protoManager.EnumeratePrototypes<GameMapPrototype>().Select(o => o.MapPath).ToHashSet(); @@ -362,7 +359,7 @@ await server.WaitPost(() => { foreach (var mapName in mapNames) { - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); try { Assert.That(mapLoader.TryLoad(mapId, mapName, out _)); diff --git a/Content.IntegrationTests/Tests/Power/PowerTest.cs b/Content.IntegrationTests/Tests/Power/PowerTest.cs index a94e94489c0..55bb42f8ced 100644 --- a/Content.IntegrationTests/Tests/Power/PowerTest.cs +++ b/Content.IntegrationTests/Tests/Power/PowerTest.cs @@ -166,6 +166,7 @@ public async Task TestSimpleSurplus() var server = pair.Server; var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); + var mapSys = entityManager.System<SharedMapSystem>(); const float loadPower = 200; PowerSupplierComponent supplier = default!; PowerConsumerComponent consumer1 = default!; @@ -173,21 +174,19 @@ public async Task TestSimpleSurplus() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates()); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 1)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent<PowerSupplierComponent>(generatorEnt); consumer1 = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt1); @@ -229,6 +228,7 @@ public async Task TestSimpleDeficit() var server = pair.Server; var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); + var mapSys = entityManager.System<SharedMapSystem>(); const float loadPower = 200; PowerSupplierComponent supplier = default!; PowerConsumerComponent consumer1 = default!; @@ -236,21 +236,19 @@ public async Task TestSimpleDeficit() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates()); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 1)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent<PowerSupplierComponent>(generatorEnt); consumer1 = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt1); @@ -288,25 +286,25 @@ public async Task TestSupplyRamp() var server = pair.Server; var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); + var mapSys = entityManager.System<SharedMapSystem>(); var gameTiming = server.ResolveDependency<IGameTiming>(); PowerSupplierComponent supplier = default!; PowerConsumerComponent consumer = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates()); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent<PowerSupplierComponent>(generatorEnt); consumer = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt); @@ -378,6 +376,7 @@ public async Task TestBatteryRamp() var entityManager = server.ResolveDependency<IEntityManager>(); var gameTiming = server.ResolveDependency<IGameTiming>(); var batterySys = entityManager.System<BatterySystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); const float startingCharge = 100_000; PowerNetworkBatteryComponent netBattery = default!; @@ -386,19 +385,18 @@ public async Task TestBatteryRamp() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("DischargingBatteryDummy", gridOwner.ToCoordinates()); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("DischargingBatteryDummy", grid.Owner.ToCoordinates()); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 2)); netBattery = entityManager.GetComponent<PowerNetworkBatteryComponent>(generatorEnt); battery = entityManager.GetComponent<BatteryComponent>(generatorEnt); @@ -479,6 +477,7 @@ public async Task TestNoDemandRampdown() var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); var batterySys = entityManager.System<BatterySystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); PowerSupplierComponent supplier = default!; PowerNetworkBatteryComponent netBattery = default!; BatteryComponent battery = default!; @@ -490,20 +489,19 @@ public async Task TestNoDemandRampdown() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1)); - var batteryEnt = entityManager.SpawnEntity("DischargingBatteryDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates()); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 1)); + var batteryEnt = entityManager.SpawnEntity("DischargingBatteryDummy", grid.Owner.ToCoordinates(0, 2)); netBattery = entityManager.GetComponent<PowerNetworkBatteryComponent>(batteryEnt); battery = entityManager.GetComponent<BatteryComponent>(batteryEnt); supplier = entityManager.GetComponent<PowerSupplierComponent>(generatorEnt); @@ -577,24 +575,24 @@ public async Task TestSimpleBatteryChargeDeficit() var gameTiming = server.ResolveDependency<IGameTiming>(); var entityManager = server.ResolveDependency<IEntityManager>(); var batterySys = entityManager.System<BatterySystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); PowerSupplierComponent supplier = default!; BatteryComponent battery = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); - var batteryEnt = entityManager.SpawnEntity("ChargingBatteryDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates()); + var batteryEnt = entityManager.SpawnEntity("ChargingBatteryDummy", grid.Owner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent<PowerSupplierComponent>(generatorEnt); var netBattery = entityManager.GetComponent<PowerNetworkBatteryComponent>(batteryEnt); @@ -634,6 +632,7 @@ public async Task TestFullBattery() var entityManager = server.ResolveDependency<IEntityManager>(); var gameTiming = server.ResolveDependency<IGameTiming>(); var batterySys = entityManager.System<BatterySystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); PowerConsumerComponent consumer = default!; PowerSupplierComponent supplier = default!; PowerNetworkBatteryComponent netBattery = default!; @@ -641,23 +640,22 @@ public async Task TestFullBattery() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 4; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1)); entityManager.GetComponent<TransformComponent>(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3)); + var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 3)); consumer = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt); supplier = entityManager.GetComponent<PowerSupplierComponent>(supplyEnt); @@ -712,6 +710,7 @@ public async Task TestFullBatteryEfficiencyPassThrough() var entityManager = server.ResolveDependency<IEntityManager>(); var gameTiming = server.ResolveDependency<IGameTiming>(); var batterySys = entityManager.System<BatterySystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); PowerConsumerComponent consumer = default!; PowerSupplierComponent supplier = default!; PowerNetworkBatteryComponent netBattery = default!; @@ -719,23 +718,22 @@ public async Task TestFullBatteryEfficiencyPassThrough() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 4; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1)); entityManager.GetComponent<TransformComponent>(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3)); + var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 3)); consumer = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt); supplier = entityManager.GetComponent<PowerSupplierComponent>(supplyEnt); @@ -789,15 +787,15 @@ public async Task TestFullBatteryEfficiencyDemandPassThrough() var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); var batterySys = entityManager.System<BatterySystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); PowerConsumerComponent consumer1 = default!; PowerConsumerComponent consumer2 = default!; PowerSupplierComponent supplier = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Map layout here is // C - consumer @@ -810,19 +808,19 @@ await server.WaitAssertion(() => // Power only works when anchored for (var i = 0; i < 5; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); + entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 2)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 2)); entityManager.GetComponent<TransformComponent>(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 1)); - var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 3)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 2)); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 4)); + var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 1)); + var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 3)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 2)); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 0)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 4)); consumer1 = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt1); consumer2 = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt2); @@ -887,6 +885,7 @@ public async Task TestSupplyPrioritized() var entityManager = server.ResolveDependency<IEntityManager>(); var gameTiming = server.ResolveDependency<IGameTiming>(); var batterySys = entityManager.System<BatterySystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); PowerConsumerComponent consumer = default!; PowerSupplierComponent supplier1 = default!; PowerSupplierComponent supplier2 = default!; @@ -897,9 +896,8 @@ public async Task TestSupplyPrioritized() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Layout is two generators, two batteries, and one load. As to why two: because previously this test // would fail ONLY if there were more than two batteries present, because each of them tries to supply @@ -911,17 +909,17 @@ await server.WaitAssertion(() => // Place cables for (var i = -2; i <= 2; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); - var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, -2)); + var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2)); + var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, -2)); - var supplyEnt1 = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 1)); - var supplyEnt2 = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, -1)); + var supplyEnt1 = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 1)); + var supplyEnt2 = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, -1)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 0)); consumer = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt); supplier1 = entityManager.GetComponent<PowerSupplierComponent>(supplyEnt1); @@ -985,15 +983,15 @@ public async Task TestBatteriesProportional() var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); var batterySys = entityManager.System<BatterySystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); PowerConsumerComponent consumer1 = default!; PowerConsumerComponent consumer2 = default!; PowerSupplierComponent supplier = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Map layout here is // C - consumer @@ -1006,19 +1004,19 @@ await server.WaitAssertion(() => // Power only works when anchored for (var i = 0; i < 5; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); + entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 2)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 2)); entityManager.GetComponent<TransformComponent>(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 1)); - var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 3)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 2)); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 4)); + var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 1)); + var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 3)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 2)); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 0)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 4)); consumer1 = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt1); consumer2 = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt2); @@ -1073,29 +1071,29 @@ public async Task TestBatteryEngineCut() var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); var batterySys = entityManager.System<BatterySystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); PowerConsumerComponent consumer = default!; PowerSupplierComponent supplier = default!; PowerNetworkBatteryComponent netBattery = default!; await server.WaitPost(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 4; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1)); entityManager.GetComponent<TransformComponent>(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3)); + var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 3)); consumer = entityManager.GetComponent<PowerConsumerComponent>(consumerEnt); supplier = entityManager.GetComponent<PowerSupplierComponent>(supplyEnt); @@ -1158,6 +1156,7 @@ public async Task TestTerminalNodeGroups() var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); var nodeContainer = entityManager.System<NodeContainerSystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); CableNode leftNode = default!; CableNode rightNode = default!; Node batteryInput = default!; @@ -1165,25 +1164,24 @@ public async Task TestTerminalNodeGroups() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 4; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); } - var leftEnt = entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 0)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 2)); - var rightEnt = entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 3)); + var leftEnt = entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 0)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 2)); + var rightEnt = entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 3)); - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1)); entityManager.GetComponent<TransformComponent>(terminal).LocalRotation = Angle.FromDegrees(180); - var battery = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); + var battery = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2)); var batteryNodeContainer = entityManager.GetComponent<NodeContainerComponent>(battery); if (nodeContainer.TryGetNode<CableNode>(entityManager.GetComponent<NodeContainerComponent>(leftEnt), @@ -1224,29 +1222,29 @@ public async Task ApcChargingTest() var mapManager = server.ResolveDependency<IMapManager>(); var entityManager = server.ResolveDependency<IEntityManager>(); var batterySys = entityManager.System<BatterySystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); PowerNetworkBatteryComponent substationNetBattery = default!; BatteryComponent apcBattery = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); } - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 0)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 1)); - entityManager.SpawnEntity("CableMV", gridOwner.ToCoordinates(0, 1)); - entityManager.SpawnEntity("CableMV", gridOwner.ToCoordinates(0, 2)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 0)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 1)); + entityManager.SpawnEntity("CableMV", grid.Owner.ToCoordinates(0, 1)); + entityManager.SpawnEntity("CableMV", grid.Owner.ToCoordinates(0, 2)); - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); - var substationEnt = entityManager.SpawnEntity("SubstationDummy", gridOwner.ToCoordinates(0, 1)); - var apcEnt = entityManager.SpawnEntity("ApcDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0)); + var substationEnt = entityManager.SpawnEntity("SubstationDummy", grid.Owner.ToCoordinates(0, 1)); + var apcEnt = entityManager.SpawnEntity("ApcDummy", grid.Owner.ToCoordinates(0, 2)); var generatorSupplier = entityManager.GetComponent<PowerSupplierComponent>(generatorEnt); substationNetBattery = entityManager.GetComponent<PowerNetworkBatteryComponent>(substationEnt); @@ -1281,33 +1279,33 @@ public async Task ApcNetTest() var entityManager = server.ResolveDependency<IEntityManager>(); var batterySys = entityManager.System<BatterySystem>(); var extensionCableSystem = entityManager.System<ExtensionCableSystem>(); + var mapSys = entityManager.System<SharedMapSystem>(); PowerNetworkBatteryComponent apcNetBattery = default!; ApcPowerReceiverComponent receiver = default!; ApcPowerReceiverComponent unpoweredReceiver = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); const int range = 5; // Power only works when anchored for (var i = 0; i < range; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); } - var apcEnt = entityManager.SpawnEntity("ApcDummy", gridOwner.ToCoordinates(0, 0)); - var apcExtensionEnt = entityManager.SpawnEntity("CableApcExtension", gridOwner.ToCoordinates(0, 0)); + var apcEnt = entityManager.SpawnEntity("ApcDummy", grid.Owner.ToCoordinates(0, 0)); + var apcExtensionEnt = entityManager.SpawnEntity("CableApcExtension", grid.Owner.ToCoordinates(0, 0)); // Create a powered receiver in range (range is 0 indexed) - var powerReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", gridOwner.ToCoordinates(0, range - 1)); + var powerReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.Owner.ToCoordinates(0, range - 1)); receiver = entityManager.GetComponent<ApcPowerReceiverComponent>(powerReceiverEnt); // Create an unpowered receiver outside range - var unpoweredReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", gridOwner.ToCoordinates(0, range)); + var unpoweredReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.Owner.ToCoordinates(0, range)); unpoweredReceiver = entityManager.GetComponent<ApcPowerReceiverComponent>(unpoweredReceiverEnt); var battery = entityManager.GetComponent<BatteryComponent>(apcEnt); diff --git a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs index 9e26fa5eaa2..1ef34365ea3 100644 --- a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs +++ b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs @@ -40,6 +40,7 @@ public async Task UninitializedSaveTest() var prototypeMan = server.ResolveDependency<IPrototypeManager>(); var seriMan = server.ResolveDependency<ISerializationManager>(); var compFact = server.ResolveDependency<IComponentFactory>(); + var mapSystem = server.System<SharedMapSystem>(); var prototypes = new List<EntityPrototype>(); EntityUid uid; @@ -77,7 +78,7 @@ public async Task UninitializedSaveTest() await server.WaitAssertion(() => { - Assert.That(!mapManager.IsMapInitialized(mapId)); + Assert.That(!mapSystem.IsInitialized(mapId)); var testLocation = grid.Owner.ToCoordinates(); Assert.Multiple(() => @@ -184,7 +185,7 @@ public DataNode Write(ISerializationManager serializationManager, EntityUid valu IDependencyCollection dependencies, bool alwaysWrite = false, ISerializationContext? context = null) { - if (WritingComponent != "Transform" && (Prototype?.NoSpawn == false)) + if (WritingComponent != "Transform" && Prototype?.HideSpawnMenu == false) { // Maybe this will be necessary in the future, but at the moment it just indicates that there is some // issue, like a non-nullable entityUid data-field. If a component MUST have an entity uid to work with, diff --git a/Content.IntegrationTests/Tests/Puller/PullerTest.cs b/Content.IntegrationTests/Tests/Puller/PullerTest.cs index 87d174f7272..a4fde86dbfb 100644 --- a/Content.IntegrationTests/Tests/Puller/PullerTest.cs +++ b/Content.IntegrationTests/Tests/Puller/PullerTest.cs @@ -29,7 +29,7 @@ await server.WaitAssertion(() => { foreach (var proto in protoManager.EnumeratePrototypes<EntityPrototype>()) { - if (!proto.TryGetComponent(out PullerComponent? puller)) + if (!proto.TryGetComponent(out PullerComponent? puller, compFactory)) continue; if (!puller.NeedsHands) diff --git a/Content.IntegrationTests/Tests/ResearchTest.cs b/Content.IntegrationTests/Tests/ResearchTest.cs index ee319daa436..7ae29a79ffd 100644 --- a/Content.IntegrationTests/Tests/ResearchTest.cs +++ b/Content.IntegrationTests/Tests/ResearchTest.cs @@ -2,6 +2,7 @@ using System.Linq; using Content.Shared.Lathe; using Content.Shared.Research.Prototypes; +using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; namespace Content.IntegrationTests.Tests; @@ -52,6 +53,7 @@ public async Task AllTechPrintableTest() var server = pair.Server; var protoManager = server.ResolveDependency<IPrototypeManager>(); + var compFact = server.ResolveDependency<IComponentFactory>(); await server.WaitAssertion(() => { @@ -65,7 +67,7 @@ await server.WaitAssertion(() => if (pair.IsTestPrototype(proto)) continue; - if (!proto.TryGetComponent<LatheComponent>(out var lathe)) + if (!proto.TryGetComponent<LatheComponent>(out var lathe, compFact)) continue; allLathes.Add(lathe); } diff --git a/Content.IntegrationTests/Tests/SalvageTest.cs b/Content.IntegrationTests/Tests/SalvageTest.cs index 9d75428beb7..5dfba82308f 100644 --- a/Content.IntegrationTests/Tests/SalvageTest.cs +++ b/Content.IntegrationTests/Tests/SalvageTest.cs @@ -1,5 +1,4 @@ using System.Linq; -using Content.Server.Salvage; using Content.Shared.CCVar; using Content.Shared.Salvage; using Robust.Server.GameObjects; @@ -28,6 +27,7 @@ public async Task AllSalvageMapsLoadableTest() var mapManager = server.ResolveDependency<IMapManager>(); var prototypeManager = server.ResolveDependency<IPrototypeManager>(); var cfg = server.ResolveDependency<IConfigurationManager>(); + var mapSystem = entManager.System<SharedMapSystem>(); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False); await server.WaitPost(() => @@ -36,7 +36,7 @@ await server.WaitPost(() => { var mapFile = salvage.MapPath; - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); try { Assert.That(mapLoader.TryLoad(mapId, mapFile.ToString(), out var roots)); diff --git a/Content.IntegrationTests/Tests/SaveLoadMapTest.cs b/Content.IntegrationTests/Tests/SaveLoadMapTest.cs index db2109ca599..213da5d7862 100644 --- a/Content.IntegrationTests/Tests/SaveLoadMapTest.cs +++ b/Content.IntegrationTests/Tests/SaveLoadMapTest.cs @@ -23,6 +23,7 @@ public async Task SaveLoadMultiGridMap() var mapManager = server.ResolveDependency<IMapManager>(); var sEntities = server.ResolveDependency<IEntityManager>(); var mapLoader = sEntities.System<MapLoaderSystem>(); + var mapSystem = sEntities.System<SharedMapSystem>(); var xformSystem = sEntities.EntitySysManager.GetEntitySystem<SharedTransformSystem>(); var resManager = server.ResolveDependency<IResourceManager>(); var cfg = server.ResolveDependency<IConfigurationManager>(); @@ -33,19 +34,17 @@ await server.WaitAssertion(() => var dir = new ResPath(mapPath).Directory; resManager.UserData.CreateDir(dir); - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); { - var mapGrid = mapManager.CreateGrid(mapId); - var mapGridEnt = mapGrid.Owner; - xformSystem.SetWorldPosition(mapGridEnt, new Vector2(10, 10)); - mapGrid.SetTile(new Vector2i(0, 0), new Tile(1, (TileRenderFlag) 1, 255)); + var mapGrid = mapManager.CreateGridEntity(mapId); + xformSystem.SetWorldPosition(mapGrid, new Vector2(10, 10)); + mapSystem.SetTile(mapGrid, new Vector2i(0, 0), new Tile(1, (TileRenderFlag) 1, 255)); } { - var mapGrid = mapManager.CreateGrid(mapId); - var mapGridEnt = mapGrid.Owner; - xformSystem.SetWorldPosition(mapGridEnt, new Vector2(-8, -8)); - mapGrid.SetTile(new Vector2i(0, 0), new Tile(2, (TileRenderFlag) 1, 254)); + var mapGrid = mapManager.CreateGridEntity(mapId); + xformSystem.SetWorldPosition(mapGrid, new Vector2(-8, -8)); + mapSystem.SetTile(mapGrid, new Vector2i(0, 0), new Tile(2, (TileRenderFlag) 1, 254)); } Assert.Multiple(() => mapLoader.SaveMap(mapId, mapPath)); @@ -74,7 +73,7 @@ await server.WaitAssertion(() => Assert.Multiple(() => { Assert.That(xformSystem.GetWorldPosition(gridXform), Is.EqualTo(new Vector2(10, 10))); - Assert.That(mapGrid.GetTileRef(new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(1, (TileRenderFlag) 1, 255))); + Assert.That(mapSystem.GetTileRef(gridUid, mapGrid, new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(1, (TileRenderFlag) 1, 255))); }); } { @@ -88,7 +87,7 @@ await server.WaitAssertion(() => Assert.Multiple(() => { Assert.That(xformSystem.GetWorldPosition(gridXform), Is.EqualTo(new Vector2(-8, -8))); - Assert.That(mapGrid.GetTileRef(new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(2, (TileRenderFlag) 1, 254))); + Assert.That(mapSystem.GetTileRef(gridUid, mapGrid, new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(2, (TileRenderFlag) 1, 254))); }); } }); diff --git a/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs b/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs index 01c03aace71..af60db55322 100644 --- a/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs +++ b/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs @@ -25,17 +25,18 @@ public async Task SaveLoadSave() var server = pair.Server; var entManager = server.ResolveDependency<IEntityManager>(); var mapLoader = entManager.System<MapLoaderSystem>(); + var mapSystem = entManager.System<SharedMapSystem>(); var mapManager = server.ResolveDependency<IMapManager>(); var cfg = server.ResolveDependency<IConfigurationManager>(); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False); await server.WaitPost(() => { - var mapId0 = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId0); // TODO: Properly find the "main" station grid. - var grid0 = mapManager.CreateGrid(mapId0); + var grid0 = mapManager.CreateGridEntity(mapId0); mapLoader.Save(grid0.Owner, "save load save 1.yml"); - var mapId1 = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId1); EntityUid grid1 = default!; #pragma warning disable NUnit2045 Assert.That(mapLoader.TryLoad(mapId1, "save load save 1.yml", out var roots, new MapLoadOptions() { LoadMap = false }), $"Failed to load test map {TestMap}"); @@ -101,6 +102,7 @@ public async Task LoadSaveTicksSavePebble() var server = pair.Server; var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>(); var mapManager = server.ResolveDependency<IMapManager>(); + var mapSystem = server.System<SharedMapSystem>(); MapId mapId = default; var cfg = server.ResolveDependency<IConfigurationManager>(); @@ -109,8 +111,7 @@ public async Task LoadSaveTicksSavePebble() // Load pebble.yml as uninitialized map, and save it to ensure it's up to date. server.Post(() => { - mapId = mapManager.CreateMap(); - mapManager.AddUninitializedMap(mapId); + mapSystem.CreateMap(out mapId, runMapInit: false); mapManager.SetMapPaused(mapId, true); Assert.That(mapLoader.TryLoad(mapId, TestMap, out _), $"Failed to load test map {TestMap}"); mapLoader.SaveMap(mapId, "load save ticks save 1.yml"); @@ -182,7 +183,8 @@ public async Task LoadTickLoadPebble() await using var pair = await PoolManager.GetServerClient(); var server = pair.Server; - var mapLoader = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<MapLoaderSystem>(); + var mapLoader = server.System<MapLoaderSystem>(); + var mapSystem = server.System<SharedMapSystem>(); var mapManager = server.ResolveDependency<IMapManager>(); var userData = server.ResolveDependency<IResourceManager>().UserData; var cfg = server.ResolveDependency<IConfigurationManager>(); @@ -197,8 +199,7 @@ public async Task LoadTickLoadPebble() // Load & save the first map server.Post(() => { - mapId = mapManager.CreateMap(); - mapManager.AddUninitializedMap(mapId); + mapSystem.CreateMap(out mapId, runMapInit: false); mapManager.SetMapPaused(mapId, true); Assert.That(mapLoader.TryLoad(mapId, TestMap, out _), $"Failed to load test map {TestMap}"); mapLoader.SaveMap(mapId, fileA); @@ -217,8 +218,7 @@ public async Task LoadTickLoadPebble() server.Post(() => { mapManager.DeleteMap(mapId); - mapManager.CreateMap(mapId); - mapManager.AddUninitializedMap(mapId); + mapSystem.CreateMap(out mapId, runMapInit: false); mapManager.SetMapPaused(mapId, true); Assert.That(mapLoader.TryLoad(mapId, TestMap, out _), $"Failed to load test map {TestMap}"); mapLoader.SaveMap(mapId, fileB); diff --git a/Content.IntegrationTests/Tests/Serialization/SerializationTest.cs b/Content.IntegrationTests/Tests/Serialization/SerializationTest.cs index 052ea997c0d..339420362c1 100644 --- a/Content.IntegrationTests/Tests/Serialization/SerializationTest.cs +++ b/Content.IntegrationTests/Tests/Serialization/SerializationTest.cs @@ -24,7 +24,7 @@ public async Task SerializeGenericEnums() Enum value = TestEnum.Bb; - var node = seriMan.WriteValue(value, notNullableOverride:true); + var node = seriMan.WriteValue(value, notNullableOverride: true); var valueNode = node as ValueDataNode; Assert.That(valueNode, Is.Not.Null); @@ -34,22 +34,22 @@ public async Task SerializeGenericEnums() var errors = seriMan.ValidateNode<Enum>(valueNode).GetErrors(); Assert.That(errors.Any(), Is.False); - var deserialized = seriMan.Read<Enum>(node, notNullableOverride:true); + var deserialized = seriMan.Read<Enum>(node, notNullableOverride: true); Assert.That(deserialized, Is.EqualTo(value)); // Repeat test with enums in a data definitions. var data = new TestData { Value = TestEnum.Cc, - Sequence = new() {TestEnum.Dd, TestEnum.Aa} + Sequence = [TestEnum.Dd, TestEnum.Aa] }; - node = seriMan.WriteValue(data, notNullableOverride:true); + node = seriMan.WriteValue(data, notNullableOverride: true); errors = seriMan.ValidateNode<TestData>(node).GetErrors(); Assert.That(errors.Any(), Is.False); - var deserializedData = seriMan.Read<TestData>(node, notNullableOverride:false); + var deserializedData = seriMan.Read<TestData>(node, notNullableOverride: false); Assert.That(deserializedData.Value, Is.EqualTo(data.Value)); Assert.That(deserializedData.Sequence.Count, Is.EqualTo(data.Sequence.Count)); @@ -60,7 +60,7 @@ public async Task SerializeGenericEnums() Enum genericValue = TestEnum.Bb; TestEnum typedValue = TestEnum.Bb; - var genericNode = seriMan.WriteValue(genericValue, notNullableOverride:true); + var genericNode = seriMan.WriteValue(genericValue, notNullableOverride: true); var typedNode = seriMan.WriteValue(typedValue); Assert.That(seriMan.ValidateNode<Enum>(genericNode).GetErrors().Any(), Is.False); @@ -76,7 +76,7 @@ private enum TestEnum : byte { Aa, Bb, Cc, Dd } [DataDefinition] private sealed partial class TestData { - [DataField("value")] public Enum Value = default!; - [DataField("sequence")] public List<Enum> Sequence = default!; + [DataField] public Enum Value = default!; + [DataField] public List<Enum> Sequence = default!; } } diff --git a/Content.IntegrationTests/Tests/Shuttle/DockTest.cs b/Content.IntegrationTests/Tests/Shuttle/DockTest.cs index a1aa462a697..d91d18793e5 100644 --- a/Content.IntegrationTests/Tests/Shuttle/DockTest.cs +++ b/Content.IntegrationTests/Tests/Shuttle/DockTest.cs @@ -97,13 +97,14 @@ public async Task TestPlanetDock() var entManager = server.ResolveDependency<IEntityManager>(); var dockingSystem = entManager.System<DockingSystem>(); var mapSystem = entManager.System<SharedMapSystem>(); + MapGridComponent mapGrid = default!; - var mapGrid = entManager.AddComponent<MapGridComponent>(map.MapUid); var shuttle = EntityUid.Invalid; // Spawn shuttle and affirm no valid docks. await server.WaitAssertion(() => { + mapGrid = entManager.AddComponent<MapGridComponent>(map.MapUid); entManager.DeleteEntity(map.Grid); Assert.That(entManager.System<MapLoaderSystem>().TryLoad(otherMap.MapId, "/Maps/Shuttles/emergency.yml", out var rootUids)); shuttle = rootUids[0]; @@ -125,4 +126,4 @@ await server.WaitAssertion(() => await pair.CleanReturnAsync(); } -} +} \ No newline at end of file diff --git a/Content.IntegrationTests/Tests/ShuttleTest.cs b/Content.IntegrationTests/Tests/ShuttleTest.cs index fb786373a5a..da5b82d91e7 100644 --- a/Content.IntegrationTests/Tests/ShuttleTest.cs +++ b/Content.IntegrationTests/Tests/ShuttleTest.cs @@ -2,7 +2,6 @@ using Content.Server.Shuttles.Components; using Robust.Shared.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Maths; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; @@ -23,33 +22,33 @@ public async Task Test() var entManager = server.ResolveDependency<IEntityManager>(); var physicsSystem = entManager.System<SharedPhysicsSystem>(); - EntityUid gridEnt = default; PhysicsComponent gridPhys = null; + var map = await pair.CreateTestMap(); + await server.WaitAssertion(() => { - var mapId = mapMan.CreateMap(); - var grid = mapMan.CreateGridEntity(mapId); - gridEnt = grid.Owner; + var mapId = map.MapId; + var grid = map.Grid; Assert.Multiple(() => { - Assert.That(entManager.HasComponent<ShuttleComponent>(gridEnt)); - Assert.That(entManager.TryGetComponent(gridEnt, out gridPhys)); + Assert.That(entManager.HasComponent<ShuttleComponent>(grid)); + Assert.That(entManager.TryGetComponent(grid, out gridPhys)); }); Assert.Multiple(() => { Assert.That(gridPhys.BodyType, Is.EqualTo(BodyType.Dynamic)); - Assert.That(entManager.GetComponent<TransformComponent>(gridEnt).LocalPosition, Is.EqualTo(Vector2.Zero)); + Assert.That(entManager.GetComponent<TransformComponent>(grid).LocalPosition, Is.EqualTo(Vector2.Zero)); }); - physicsSystem.ApplyLinearImpulse(gridEnt, Vector2.One, body: gridPhys); + physicsSystem.ApplyLinearImpulse(grid, Vector2.One, body: gridPhys); }); await server.WaitRunTicks(1); await server.WaitAssertion(() => { - Assert.That(entManager.GetComponent<TransformComponent>(gridEnt).LocalPosition, Is.Not.EqualTo(Vector2.Zero)); + Assert.That(entManager.GetComponent<TransformComponent>(map.Grid).LocalPosition, Is.Not.EqualTo(Vector2.Zero)); }); await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs b/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs index 1762c4213c4..bf75188f029 100644 --- a/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs +++ b/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs @@ -19,12 +19,12 @@ namespace Content.IntegrationTests.Tests.Sprite; /// - Shouldn't have an item component /// - Is missing the required sprite information. /// If none of the abveo are true, it might need to be added to the list of ignored components, see -/// <see cref="_ignored"/> +/// <see cref="Ignored"/> /// </remarks> [TestFixture] public sealed class PrototypeSaveTest { - private static HashSet<string> _ignored = new() + private static readonly HashSet<string> Ignored = new() { // The only prototypes that should get ignored are those that REQUIRE setup to get a sprite. At that point it is // the responsibility of the spawner to ensure that a valid sprite is set. @@ -34,13 +34,13 @@ public sealed class PrototypeSaveTest [Test] public async Task AllItemsHaveSpritesTest() { - var settings = new PoolSettings() {Connected = true}; // client needs to be in-game + var settings = new PoolSettings() { Connected = true }; // client needs to be in-game await using var pair = await PoolManager.GetServerClient(settings); - List<EntityPrototype> badPrototypes = new(); + List<EntityPrototype> badPrototypes = []; await pair.Client.WaitPost(() => { - foreach (var proto in pair.GetPrototypesWithComponent<ItemComponent>(_ignored)) + foreach (var proto in pair.GetPrototypesWithComponent<ItemComponent>(Ignored)) { var dummy = pair.Client.EntMan.Spawn(proto.ID); pair.Client.EntMan.RunMapInit(dummy, pair.Client.MetaData(dummy)); diff --git a/Content.IntegrationTests/Tests/Minds/JobTests.cs b/Content.IntegrationTests/Tests/Station/JobTests.cs similarity index 100% rename from Content.IntegrationTests/Tests/Minds/JobTests.cs rename to Content.IntegrationTests/Tests/Station/JobTests.cs diff --git a/Content.IntegrationTests/Tests/Storage/StorageInteractionTest.cs b/Content.IntegrationTests/Tests/Storage/StorageInteractionTest.cs new file mode 100644 index 00000000000..34402dd5e62 --- /dev/null +++ b/Content.IntegrationTests/Tests/Storage/StorageInteractionTest.cs @@ -0,0 +1,75 @@ +using Content.Client.UserInterface.Systems.Hotbar.Widgets; +using Content.Client.UserInterface.Systems.Storage.Controls; +using Content.IntegrationTests.Tests.Interaction; +using Content.Shared.Input; +using Content.Shared.PDA; +using Content.Shared.Storage; +using Robust.Client.UserInterface; +using Robust.Shared.Containers; +using Robust.Shared.GameObjects; + +namespace Content.IntegrationTests.Tests.Storage; + +public sealed class StorageInteractionTest : InteractionTest +{ + /// <summary> + /// Check that players can interact with items in storage if the storage UI is open + /// </summary> + [Test] + public async Task UiInteractTest() + { + var sys = Server.System<SharedContainerSystem>(); + + await SpawnTarget("ClothingBackpack"); + var backpack = ToServer(Target); + + // Initially no BUI is open. + Assert.That(IsUiOpen(StorageComponent.StorageUiKey.Key), Is.False); + Assert.That(IsUiOpen(PdaUiKey.Key), Is.False); + + // Activating the backpack opens the UI + await Activate(); + Assert.That(IsUiOpen(StorageComponent.StorageUiKey.Key), Is.True); + Assert.That(IsUiOpen(PdaUiKey.Key), Is.False); + + // Pick up a PDA + var pda = await PlaceInHands("PassengerPDA"); + var sPda = ToServer(pda); + Assert.That(sys.IsEntityInContainer(sPda), Is.True); + Assert.That(sys.TryGetContainingContainer((sPda, null), out var container)); + Assert.That(container!.Owner, Is.EqualTo(SPlayer)); + + // Insert the PDA into the backpack + await Interact(); + Assert.That(sys.TryGetContainingContainer((sPda, null), out container)); + Assert.That(container!.Owner, Is.EqualTo(backpack)); + + // Use "e" / ActivateInWorld to open the PDA UI while it is still in the backpack. + var ctrl = GetStorageControl(pda); + await ClickControl(ctrl, ContentKeyFunctions.ActivateItemInWorld); + await RunTicks(10); + Assert.That(IsUiOpen(StorageComponent.StorageUiKey.Key), Is.True); + Assert.That(IsUiOpen(PdaUiKey.Key), Is.True); + + // Click on the pda to pick it up and remove it from the backpack. + await ClickControl(ctrl, ContentKeyFunctions.MoveStoredItem); + await RunTicks(10); + Assert.That(sys.TryGetContainingContainer((sPda, null), out container)); + Assert.That(container!.Owner, Is.EqualTo(SPlayer)); + + // UIs should still be open + Assert.That(IsUiOpen(StorageComponent.StorageUiKey.Key), Is.True); + Assert.That(IsUiOpen(PdaUiKey.Key), Is.True); + } + + /// <summary> + /// Retrieve the control that corresponds to the given entity in the currently open storage UI. + /// </summary> + private ItemGridPiece GetStorageControl(NetEntity target) + { + var uid = ToClient(target); + var hotbar = GetWidget<HotbarGui>(); + var storageContainer = GetControlFromField<Control>(nameof(HotbarGui.StorageContainer), hotbar); + return GetControlFromChildren<ItemGridPiece>(c => c.Entity == uid, storageContainer); + } +} diff --git a/Content.IntegrationTests/Tests/Tag/TagTest.cs b/Content.IntegrationTests/Tests/Tag/TagTest.cs index ed3c484b435..cbcdd1c6c62 100644 --- a/Content.IntegrationTests/Tests/Tag/TagTest.cs +++ b/Content.IntegrationTests/Tests/Tag/TagTest.cs @@ -130,9 +130,9 @@ await server.WaitAssertion(() => Assert.Multiple(() => { // Cannot add the starting tag again - Assert.That(tagSystem.AddTag(sTagComponent, StartingTag), Is.False); - Assert.That(tagSystem.AddTags(sTagComponent, StartingTag, StartingTag), Is.False); - Assert.That(tagSystem.AddTags(sTagComponent, new List<string> { StartingTag, StartingTag }), Is.False); + Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, StartingTag), Is.False); + Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, StartingTag, StartingTag), Is.False); + Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, new List<string> { StartingTag, StartingTag }), Is.False); // Has the starting tag Assert.That(tagSystem.HasTag(sTagComponent, StartingTag), Is.True); @@ -157,22 +157,22 @@ await server.WaitAssertion(() => Assert.That(tagSystem.HasAllTags(sTagComponent, new List<string> { StartingTag, AddedTag }), Is.False); // Cannot remove a tag that does not exist - Assert.That(tagSystem.RemoveTag(sTagComponent, AddedTag), Is.False); - Assert.That(tagSystem.RemoveTags(sTagComponent, AddedTag, AddedTag), Is.False); - Assert.That(tagSystem.RemoveTags(sTagComponent, new List<string> { AddedTag, AddedTag }), Is.False); + Assert.That(tagSystem.RemoveTag(sTagDummy, sTagComponent, AddedTag), Is.False); + Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, AddedTag, AddedTag), Is.False); + Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, new List<string> { AddedTag, AddedTag }), Is.False); }); // Can add the new tag - Assert.That(tagSystem.AddTag(sTagComponent, AddedTag), Is.True); + Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, AddedTag), Is.True); Assert.Multiple(() => { // Cannot add it twice - Assert.That(tagSystem.AddTag(sTagComponent, AddedTag), Is.False); + Assert.That(tagSystem.AddTag(sTagDummy, sTagComponent, AddedTag), Is.False); // Cannot add existing tags - Assert.That(tagSystem.AddTags(sTagComponent, StartingTag, AddedTag), Is.False); - Assert.That(tagSystem.AddTags(sTagComponent, new List<string> { StartingTag, AddedTag }), Is.False); + Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, StartingTag, AddedTag), Is.False); + Assert.That(tagSystem.AddTags(sTagDummy, sTagComponent, new List<string> { StartingTag, AddedTag }), Is.False); // Now has two tags Assert.That(sTagComponent.Tags, Has.Count.EqualTo(2)); @@ -191,16 +191,16 @@ await server.WaitAssertion(() => Assert.Multiple(() => { // Remove the existing starting tag - Assert.That(tagSystem.RemoveTag(sTagComponent, StartingTag), Is.True); + Assert.That(tagSystem.RemoveTag(sTagDummy, sTagComponent, StartingTag), Is.True); // Remove the existing added tag - Assert.That(tagSystem.RemoveTags(sTagComponent, AddedTag, AddedTag), Is.True); + Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, AddedTag, AddedTag), Is.True); }); Assert.Multiple(() => { // No tags left to remove - Assert.That(tagSystem.RemoveTags(sTagComponent, new List<string> { StartingTag, AddedTag }), Is.False); + Assert.That(tagSystem.RemoveTags(sTagDummy, sTagComponent, new List<string> { StartingTag, AddedTag }), Is.False); // No tags left in the component Assert.That(sTagComponent.Tags, Is.Empty); diff --git a/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs b/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs index 083e817d697..6ea8b6882ad 100644 --- a/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs +++ b/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs @@ -15,10 +15,10 @@ public async Task PlaceThenCutLattice() await AssertTile(Plating, PlayerCoords); AssertGridCount(1); await SetTile(null); - await Interact(Rod); + await InteractUsing(Rod); await AssertTile(Lattice); Assert.That(Hands.ActiveHandEntity, Is.Null); - await Interact(Cut); + await InteractUsing(Cut); await AssertTile(null); await AssertEntityLookup((Rod, 1)); AssertGridCount(1); @@ -43,14 +43,14 @@ public async Task CutThenPlaceLatticeNewGrid() // Place Lattice var oldPos = TargetCoords; TargetCoords = SEntMan.GetNetCoordinates(new EntityCoordinates(MapData.MapUid, 1, 0)); - await Interact(Rod); + await InteractUsing(Rod); TargetCoords = oldPos; await AssertTile(Lattice); AssertGridCount(1); // Cut lattice Assert.That(Hands.ActiveHandEntity, Is.Null); - await Interact(Cut); + await InteractUsing(Cut); await AssertTile(null); AssertGridCount(0); @@ -76,25 +76,25 @@ public async Task FloorConstructDeconstruct() // Space -> Lattice var oldPos = TargetCoords; TargetCoords = SEntMan.GetNetCoordinates(new EntityCoordinates(MapData.MapUid, 1, 0)); - await Interact(Rod); + await InteractUsing(Rod); TargetCoords = oldPos; await AssertTile(Lattice); AssertGridCount(1); // Lattice -> Plating - await Interact(Steel); + await InteractUsing(Steel); Assert.That(Hands.ActiveHandEntity, Is.Null); await AssertTile(Plating); AssertGridCount(1); // Plating -> Tile - await Interact(FloorItem); + await InteractUsing(FloorItem); Assert.That(Hands.ActiveHandEntity, Is.Null); await AssertTile(Floor); AssertGridCount(1); // Tile -> Plating - await Interact(Pry); + await InteractUsing(Pry); await AssertTile(Plating); AssertGridCount(1); diff --git a/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs b/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs index dd68ff1ccf1..7de81fb3dc2 100644 --- a/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs +++ b/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs @@ -36,16 +36,18 @@ public async Task TearDownInternal() await TearDown(); } - protected virtual async Task TearDown() + protected virtual Task TearDown() { Assert.That(_expectedErrors, Is.Empty); ClearErrors(); + + return Task.CompletedTask; } [SetUp] public virtual async Task Setup() { - Pair = await PoolManager.GetServerClient(new PoolSettings {Connected = Connected}); + Pair = await PoolManager.GetServerClient(new PoolSettings { Connected = Connected }); Server = Pair.Server; if (Connected) @@ -142,7 +144,7 @@ public void ReportError(IConError err) ); } - done: + done: _errors.Add(err); } diff --git a/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs b/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs index 99481db70e7..5bfebfbd530 100644 --- a/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs +++ b/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs @@ -110,6 +110,7 @@ public async Task TestAllRestocksAreAvailableToBuy() await server.WaitIdleAsync(); var prototypeManager = server.ResolveDependency<IPrototypeManager>(); + var compFact = server.ResolveDependency<IComponentFactory>(); await server.WaitAssertion(() => { @@ -132,7 +133,7 @@ await server.WaitAssertion(() => // Collect all the prototypes with StorageFills referencing those entities. foreach (var proto in prototypeManager.EnumeratePrototypes<EntityPrototype>()) { - if (!proto.TryGetComponent<StorageFillComponent>(out var storage)) + if (!proto.TryGetComponent<StorageFillComponent>(out var storage, compFact)) continue; List<string> restockStore = new(); diff --git a/Content.IntegrationTests/Tests/Weldable/WeldableTests.cs b/Content.IntegrationTests/Tests/Weldable/WeldableTests.cs index 6227f3dee1b..e7eadeda0a4 100644 --- a/Content.IntegrationTests/Tests/Weldable/WeldableTests.cs +++ b/Content.IntegrationTests/Tests/Weldable/WeldableTests.cs @@ -18,7 +18,7 @@ public async Task WeldLocker() Assert.That(comp.IsWelded, Is.False); - await Interact(Weld); + await InteractUsing(Weld); Assert.That(comp.IsWelded, Is.True); AssertPrototype(Locker); // Prototype did not change. } diff --git a/Content.Server.Database/Migrations/Postgres/20240606065731_RemoveLastReadRules.Designer.cs b/Content.Server.Database/Migrations/Postgres/20240606065731_RemoveLastReadRules.Designer.cs new file mode 100644 index 00000000000..222fe126d99 --- /dev/null +++ b/Content.Server.Database/Migrations/Postgres/20240606065731_RemoveLastReadRules.Designer.cs @@ -0,0 +1,1909 @@ +// <auto-generated /> +using System; +using System.Net; +using System.Text.Json; +using Content.Server.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using NpgsqlTypes; + +#nullable disable + +namespace Content.Server.Database.Migrations.Postgres +{ + [DbContext(typeof(PostgresServerDbContext))] + [Migration("20240606065731_RemoveLastReadRules")] + partial class RemoveLastReadRules + { + /// <inheritdoc /> + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.Property<Guid>("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property<int?>("AdminRankId") + .HasColumnType("integer") + .HasColumnName("admin_rank_id"); + + b.Property<string>("Title") + .HasColumnType("text") + .HasColumnName("title"); + + b.HasKey("UserId") + .HasName("PK_admin"); + + b.HasIndex("AdminRankId") + .HasDatabaseName("IX_admin_admin_rank_id"); + + b.ToTable("admin", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminFlag", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("admin_flag_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<Guid>("AdminId") + .HasColumnType("uuid") + .HasColumnName("admin_id"); + + b.Property<string>("Flag") + .IsRequired() + .HasColumnType("text") + .HasColumnName("flag"); + + b.Property<bool>("Negative") + .HasColumnType("boolean") + .HasColumnName("negative"); + + b.HasKey("Id") + .HasName("PK_admin_flag"); + + b.HasIndex("AdminId") + .HasDatabaseName("IX_admin_flag_admin_id"); + + b.HasIndex("Flag", "AdminId") + .IsUnique(); + + b.ToTable("admin_flag", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminLog", b => + { + b.Property<int>("RoundId") + .HasColumnType("integer") + .HasColumnName("round_id"); + + b.Property<int>("Id") + .HasColumnType("integer") + .HasColumnName("admin_log_id"); + + b.Property<DateTime>("Date") + .HasColumnType("timestamp with time zone") + .HasColumnName("date"); + + b.Property<short>("Impact") + .HasColumnType("smallint") + .HasColumnName("impact"); + + b.Property<JsonDocument>("Json") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("json"); + + b.Property<string>("Message") + .IsRequired() + .HasColumnType("text") + .HasColumnName("message"); + + b.Property<int>("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("RoundId", "Id") + .HasName("PK_admin_log"); + + b.HasIndex("Date"); + + b.HasIndex("Message") + .HasAnnotation("Npgsql:TsVectorConfig", "english"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Message"), "GIN"); + + b.HasIndex("Type") + .HasDatabaseName("IX_admin_log_type"); + + b.ToTable("admin_log", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b => + { + b.Property<int>("RoundId") + .HasColumnType("integer") + .HasColumnName("round_id"); + + b.Property<int>("LogId") + .HasColumnType("integer") + .HasColumnName("log_id"); + + b.Property<Guid>("PlayerUserId") + .HasColumnType("uuid") + .HasColumnName("player_user_id"); + + b.HasKey("RoundId", "LogId", "PlayerUserId") + .HasName("PK_admin_log_player"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_admin_log_player_player_user_id"); + + b.ToTable("admin_log_player", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminMessage", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("admin_messages_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<DateTime>("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property<Guid?>("CreatedById") + .HasColumnType("uuid") + .HasColumnName("created_by_id"); + + b.Property<bool>("Deleted") + .HasColumnType("boolean") + .HasColumnName("deleted"); + + b.Property<DateTime?>("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property<Guid?>("DeletedById") + .HasColumnType("uuid") + .HasColumnName("deleted_by_id"); + + b.Property<bool>("Dismissed") + .HasColumnType("boolean") + .HasColumnName("dismissed"); + + b.Property<DateTime?>("ExpirationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiration_time"); + + b.Property<DateTime?>("LastEditedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_edited_at"); + + b.Property<Guid?>("LastEditedById") + .HasColumnType("uuid") + .HasColumnName("last_edited_by_id"); + + b.Property<string>("Message") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("message"); + + b.Property<Guid?>("PlayerUserId") + .HasColumnType("uuid") + .HasColumnName("player_user_id"); + + b.Property<TimeSpan>("PlaytimeAtNote") + .HasColumnType("interval") + .HasColumnName("playtime_at_note"); + + b.Property<int?>("RoundId") + .HasColumnType("integer") + .HasColumnName("round_id"); + + b.Property<bool>("Seen") + .HasColumnType("boolean") + .HasColumnName("seen"); + + b.HasKey("Id") + .HasName("PK_admin_messages"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DeletedById"); + + b.HasIndex("LastEditedById"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_admin_messages_player_user_id"); + + b.HasIndex("RoundId") + .HasDatabaseName("IX_admin_messages_round_id"); + + b.ToTable("admin_messages", null, t => + { + t.HasCheckConstraint("NotDismissedAndSeen", "NOT dismissed OR seen"); + }); + }); + + modelBuilder.Entity("Content.Server.Database.AdminNote", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("admin_notes_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<DateTime>("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property<Guid?>("CreatedById") + .HasColumnType("uuid") + .HasColumnName("created_by_id"); + + b.Property<bool>("Deleted") + .HasColumnType("boolean") + .HasColumnName("deleted"); + + b.Property<DateTime?>("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property<Guid?>("DeletedById") + .HasColumnType("uuid") + .HasColumnName("deleted_by_id"); + + b.Property<DateTime?>("ExpirationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiration_time"); + + b.Property<DateTime?>("LastEditedAt") + .IsRequired() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_edited_at"); + + b.Property<Guid?>("LastEditedById") + .HasColumnType("uuid") + .HasColumnName("last_edited_by_id"); + + b.Property<string>("Message") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("message"); + + b.Property<Guid?>("PlayerUserId") + .HasColumnType("uuid") + .HasColumnName("player_user_id"); + + b.Property<TimeSpan>("PlaytimeAtNote") + .HasColumnType("interval") + .HasColumnName("playtime_at_note"); + + b.Property<int?>("RoundId") + .HasColumnType("integer") + .HasColumnName("round_id"); + + b.Property<bool>("Secret") + .HasColumnType("boolean") + .HasColumnName("secret"); + + b.Property<int>("Severity") + .HasColumnType("integer") + .HasColumnName("severity"); + + b.HasKey("Id") + .HasName("PK_admin_notes"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DeletedById"); + + b.HasIndex("LastEditedById"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_admin_notes_player_user_id"); + + b.HasIndex("RoundId") + .HasDatabaseName("IX_admin_notes_round_id"); + + b.ToTable("admin_notes", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRank", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("admin_rank_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("PK_admin_rank"); + + b.ToTable("admin_rank", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("admin_rank_flag_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("AdminRankId") + .HasColumnType("integer") + .HasColumnName("admin_rank_id"); + + b.Property<string>("Flag") + .IsRequired() + .HasColumnType("text") + .HasColumnName("flag"); + + b.HasKey("Id") + .HasName("PK_admin_rank_flag"); + + b.HasIndex("AdminRankId"); + + b.HasIndex("Flag", "AdminRankId") + .IsUnique(); + + b.ToTable("admin_rank_flag", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminWatchlist", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("admin_watchlists_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<DateTime>("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property<Guid?>("CreatedById") + .HasColumnType("uuid") + .HasColumnName("created_by_id"); + + b.Property<bool>("Deleted") + .HasColumnType("boolean") + .HasColumnName("deleted"); + + b.Property<DateTime?>("DeletedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_at"); + + b.Property<Guid?>("DeletedById") + .HasColumnType("uuid") + .HasColumnName("deleted_by_id"); + + b.Property<DateTime?>("ExpirationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiration_time"); + + b.Property<DateTime?>("LastEditedAt") + .IsRequired() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_edited_at"); + + b.Property<Guid?>("LastEditedById") + .HasColumnType("uuid") + .HasColumnName("last_edited_by_id"); + + b.Property<string>("Message") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("character varying(4096)") + .HasColumnName("message"); + + b.Property<Guid?>("PlayerUserId") + .HasColumnType("uuid") + .HasColumnName("player_user_id"); + + b.Property<TimeSpan>("PlaytimeAtNote") + .HasColumnType("interval") + .HasColumnName("playtime_at_note"); + + b.Property<int?>("RoundId") + .HasColumnType("integer") + .HasColumnName("round_id"); + + b.HasKey("Id") + .HasName("PK_admin_watchlists"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DeletedById"); + + b.HasIndex("LastEditedById"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_admin_watchlists_player_user_id"); + + b.HasIndex("RoundId") + .HasDatabaseName("IX_admin_watchlists_round_id"); + + b.ToTable("admin_watchlists", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("antag_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("AntagName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("antag_name"); + + b.Property<int>("ProfileId") + .HasColumnType("integer") + .HasColumnName("profile_id"); + + b.HasKey("Id") + .HasName("PK_antag"); + + b.HasIndex("ProfileId", "AntagName") + .IsUnique(); + + b.ToTable("antag", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AssignedUserId", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("assigned_user_id_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<Guid>("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property<string>("UserName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("user_name"); + + b.HasKey("Id") + .HasName("PK_assigned_user_id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.HasIndex("UserName") + .IsUnique(); + + b.ToTable("assigned_user_id", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ConnectionLog", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("connection_log_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<IPAddress>("Address") + .IsRequired() + .HasColumnType("inet") + .HasColumnName("address"); + + b.Property<byte?>("Denied") + .HasColumnType("smallint") + .HasColumnName("denied"); + + b.Property<byte[]>("HWId") + .HasColumnType("bytea") + .HasColumnName("hwid"); + + b.Property<int>("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0) + .HasColumnName("server_id"); + + b.Property<DateTime>("Time") + .HasColumnType("timestamp with time zone") + .HasColumnName("time"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property<string>("UserName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("user_name"); + + b.HasKey("Id") + .HasName("PK_connection_log"); + + b.HasIndex("ServerId") + .HasDatabaseName("IX_connection_log_server_id"); + + b.HasIndex("UserId"); + + b.ToTable("connection_log", null, t => + { + t.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address"); + }); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("job_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("JobName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("job_name"); + + b.Property<int>("Priority") + .HasColumnType("integer") + .HasColumnName("priority"); + + b.Property<int>("ProfileId") + .HasColumnType("integer") + .HasColumnName("profile_id"); + + b.HasKey("Id") + .HasName("PK_job"); + + b.HasIndex("ProfileId"); + + b.HasIndex("ProfileId", "JobName") + .IsUnique(); + + b.HasIndex(new[] { "ProfileId" }, "IX_job_one_high_priority") + .IsUnique() + .HasFilter("priority = 3"); + + b.ToTable("job", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.PlayTime", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("play_time_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<Guid>("PlayerId") + .HasColumnType("uuid") + .HasColumnName("player_id"); + + b.Property<TimeSpan>("TimeSpent") + .HasColumnType("interval") + .HasColumnName("time_spent"); + + b.Property<string>("Tracker") + .IsRequired() + .HasColumnType("text") + .HasColumnName("tracker"); + + b.HasKey("Id") + .HasName("PK_play_time"); + + b.HasIndex("PlayerId", "Tracker") + .IsUnique(); + + b.ToTable("play_time", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Player", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("player_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<DateTime>("FirstSeenTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("first_seen_time"); + + b.Property<IPAddress>("LastSeenAddress") + .IsRequired() + .HasColumnType("inet") + .HasColumnName("last_seen_address"); + + b.Property<byte[]>("LastSeenHWId") + .HasColumnType("bytea") + .HasColumnName("last_seen_hwid"); + + b.Property<DateTime>("LastSeenTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_seen_time"); + + b.Property<string>("LastSeenUserName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("last_seen_user_name"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("PK_player"); + + b.HasAlternateKey("UserId") + .HasName("ak_player_user_id"); + + b.HasIndex("LastSeenUserName"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("player", null, t => + { + t.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address"); + }); + }); + + modelBuilder.Entity("Content.Server.Database.Preference", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("preference_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("AdminOOCColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("admin_ooc_color"); + + b.Property<int>("SelectedCharacterSlot") + .HasColumnType("integer") + .HasColumnName("selected_character_slot"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("PK_preference"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("preference", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("profile_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("Age") + .HasColumnType("integer") + .HasColumnName("age"); + + b.Property<string>("CharacterName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("char_name"); + + b.Property<string>("EyeColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("eye_color"); + + b.Property<string>("FacialHairColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("facial_hair_color"); + + b.Property<string>("FacialHairName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("facial_hair_name"); + + b.Property<string>("FlavorText") + .IsRequired() + .HasColumnType("text") + .HasColumnName("flavor_text"); + + b.Property<string>("Gender") + .IsRequired() + .HasColumnType("text") + .HasColumnName("gender"); + + b.Property<string>("HairColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("hair_color"); + + b.Property<string>("HairName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("hair_name"); + + b.Property<JsonDocument>("Markings") + .HasColumnType("jsonb") + .HasColumnName("markings"); + + b.Property<int>("PreferenceId") + .HasColumnType("integer") + .HasColumnName("preference_id"); + + b.Property<int>("PreferenceUnavailable") + .HasColumnType("integer") + .HasColumnName("pref_unavailable"); + + b.Property<string>("Sex") + .IsRequired() + .HasColumnType("text") + .HasColumnName("sex"); + + b.Property<string>("SkinColor") + .IsRequired() + .HasColumnType("text") + .HasColumnName("skin_color"); + + b.Property<int>("Slot") + .HasColumnType("integer") + .HasColumnName("slot"); + + b.Property<int>("SpawnPriority") + .HasColumnType("integer") + .HasColumnName("spawn_priority"); + + b.Property<string>("Species") + .IsRequired() + .HasColumnType("text") + .HasColumnName("species"); + + b.HasKey("Id") + .HasName("PK_profile"); + + b.HasIndex("PreferenceId") + .HasDatabaseName("IX_profile_preference_id"); + + b.HasIndex("Slot", "PreferenceId") + .IsUnique(); + + b.ToTable("profile", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("profile_loadout_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("LoadoutName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("loadout_name"); + + b.Property<int>("ProfileLoadoutGroupId") + .HasColumnType("integer") + .HasColumnName("profile_loadout_group_id"); + + b.HasKey("Id") + .HasName("PK_profile_loadout"); + + b.HasIndex("ProfileLoadoutGroupId"); + + b.ToTable("profile_loadout", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("profile_loadout_group_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("GroupName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("group_name"); + + b.Property<int>("ProfileRoleLoadoutId") + .HasColumnType("integer") + .HasColumnName("profile_role_loadout_id"); + + b.HasKey("Id") + .HasName("PK_profile_loadout_group"); + + b.HasIndex("ProfileRoleLoadoutId"); + + b.ToTable("profile_loadout_group", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("profile_role_loadout_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("ProfileId") + .HasColumnType("integer") + .HasColumnName("profile_id"); + + b.Property<string>("RoleName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("role_name"); + + b.HasKey("Id") + .HasName("PK_profile_role_loadout"); + + b.HasIndex("ProfileId"); + + b.ToTable("profile_role_loadout", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.RoleWhitelist", b => + { + b.Property<Guid>("PlayerUserId") + .HasColumnType("uuid") + .HasColumnName("player_user_id"); + + b.Property<string>("RoleId") + .HasColumnType("text") + .HasColumnName("role_id"); + + b.HasKey("PlayerUserId", "RoleId") + .HasName("PK_role_whitelists"); + + b.ToTable("role_whitelists", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Round", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("round_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("ServerId") + .HasColumnType("integer") + .HasColumnName("server_id"); + + b.Property<DateTime?>("StartDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_date"); + + b.HasKey("Id") + .HasName("PK_round"); + + b.HasIndex("ServerId") + .HasDatabaseName("IX_round_server_id"); + + b.HasIndex("StartDate"); + + b.ToTable("round", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Server", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("server_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("PK_server"); + + b.ToTable("server", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBan", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("server_ban_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<NpgsqlInet?>("Address") + .HasColumnType("inet") + .HasColumnName("address"); + + b.Property<bool>("AutoDelete") + .HasColumnType("boolean") + .HasColumnName("auto_delete"); + + b.Property<DateTime>("BanTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("ban_time"); + + b.Property<Guid?>("BanningAdmin") + .HasColumnType("uuid") + .HasColumnName("banning_admin"); + + b.Property<int>("ExemptFlags") + .HasColumnType("integer") + .HasColumnName("exempt_flags"); + + b.Property<DateTime?>("ExpirationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiration_time"); + + b.Property<byte[]>("HWId") + .HasColumnType("bytea") + .HasColumnName("hwid"); + + b.Property<bool>("Hidden") + .HasColumnType("boolean") + .HasColumnName("hidden"); + + b.Property<DateTime?>("LastEditedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_edited_at"); + + b.Property<Guid?>("LastEditedById") + .HasColumnType("uuid") + .HasColumnName("last_edited_by_id"); + + b.Property<Guid?>("PlayerUserId") + .HasColumnType("uuid") + .HasColumnName("player_user_id"); + + b.Property<TimeSpan>("PlaytimeAtNote") + .HasColumnType("interval") + .HasColumnName("playtime_at_note"); + + b.Property<string>("Reason") + .IsRequired() + .HasColumnType("text") + .HasColumnName("reason"); + + b.Property<int?>("RoundId") + .HasColumnType("integer") + .HasColumnName("round_id"); + + b.Property<int>("Severity") + .HasColumnType("integer") + .HasColumnName("severity"); + + b.HasKey("Id") + .HasName("PK_server_ban"); + + b.HasIndex("Address"); + + b.HasIndex("BanningAdmin"); + + b.HasIndex("LastEditedById"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_server_ban_player_user_id"); + + b.HasIndex("RoundId") + .HasDatabaseName("IX_server_ban_round_id"); + + b.ToTable("server_ban", null, t => + { + t.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address"); + + t.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR player_user_id IS NOT NULL OR hwid IS NOT NULL"); + }); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBanExemption", b => + { + b.Property<Guid>("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property<int>("Flags") + .HasColumnType("integer") + .HasColumnName("flags"); + + b.HasKey("UserId") + .HasName("PK_server_ban_exemption"); + + b.ToTable("server_ban_exemption", null, t => + { + t.HasCheckConstraint("FlagsNotZero", "flags != 0"); + }); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBanHit", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("server_ban_hit_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("BanId") + .HasColumnType("integer") + .HasColumnName("ban_id"); + + b.Property<int>("ConnectionId") + .HasColumnType("integer") + .HasColumnName("connection_id"); + + b.HasKey("Id") + .HasName("PK_server_ban_hit"); + + b.HasIndex("BanId") + .HasDatabaseName("IX_server_ban_hit_ban_id"); + + b.HasIndex("ConnectionId") + .HasDatabaseName("IX_server_ban_hit_connection_id"); + + b.ToTable("server_ban_hit", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("server_role_ban_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<NpgsqlInet?>("Address") + .HasColumnType("inet") + .HasColumnName("address"); + + b.Property<DateTime>("BanTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("ban_time"); + + b.Property<Guid?>("BanningAdmin") + .HasColumnType("uuid") + .HasColumnName("banning_admin"); + + b.Property<DateTime?>("ExpirationTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiration_time"); + + b.Property<byte[]>("HWId") + .HasColumnType("bytea") + .HasColumnName("hwid"); + + b.Property<bool>("Hidden") + .HasColumnType("boolean") + .HasColumnName("hidden"); + + b.Property<DateTime?>("LastEditedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_edited_at"); + + b.Property<Guid?>("LastEditedById") + .HasColumnType("uuid") + .HasColumnName("last_edited_by_id"); + + b.Property<Guid?>("PlayerUserId") + .HasColumnType("uuid") + .HasColumnName("player_user_id"); + + b.Property<TimeSpan>("PlaytimeAtNote") + .HasColumnType("interval") + .HasColumnName("playtime_at_note"); + + b.Property<string>("Reason") + .IsRequired() + .HasColumnType("text") + .HasColumnName("reason"); + + b.Property<string>("RoleId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("role_id"); + + b.Property<int?>("RoundId") + .HasColumnType("integer") + .HasColumnName("round_id"); + + b.Property<int>("Severity") + .HasColumnType("integer") + .HasColumnName("severity"); + + b.HasKey("Id") + .HasName("PK_server_role_ban"); + + b.HasIndex("Address"); + + b.HasIndex("BanningAdmin"); + + b.HasIndex("LastEditedById"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_server_role_ban_player_user_id"); + + b.HasIndex("RoundId") + .HasDatabaseName("IX_server_role_ban_round_id"); + + b.ToTable("server_role_ban", null, t => + { + t.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address"); + + t.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR player_user_id IS NOT NULL OR hwid IS NOT NULL"); + }); + }); + + modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("role_unban_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("BanId") + .HasColumnType("integer") + .HasColumnName("ban_id"); + + b.Property<DateTime>("UnbanTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("unban_time"); + + b.Property<Guid?>("UnbanningAdmin") + .HasColumnType("uuid") + .HasColumnName("unbanning_admin"); + + b.HasKey("Id") + .HasName("PK_server_role_unban"); + + b.HasIndex("BanId") + .IsUnique(); + + b.ToTable("server_role_unban", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ServerUnban", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("unban_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("BanId") + .HasColumnType("integer") + .HasColumnName("ban_id"); + + b.Property<DateTime>("UnbanTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("unban_time"); + + b.Property<Guid?>("UnbanningAdmin") + .HasColumnType("uuid") + .HasColumnName("unbanning_admin"); + + b.HasKey("Id") + .HasName("PK_server_unban"); + + b.HasIndex("BanId") + .IsUnique(); + + b.ToTable("server_unban", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Trait", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("trait_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<int>("ProfileId") + .HasColumnType("integer") + .HasColumnName("profile_id"); + + b.Property<string>("TraitName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("trait_name"); + + b.HasKey("Id") + .HasName("PK_trait"); + + b.HasIndex("ProfileId", "TraitName") + .IsUnique(); + + b.ToTable("trait", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.UploadedResourceLog", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("uploaded_resource_log_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id")); + + b.Property<byte[]>("Data") + .IsRequired() + .HasColumnType("bytea") + .HasColumnName("data"); + + b.Property<DateTime>("Date") + .HasColumnType("timestamp with time zone") + .HasColumnName("date"); + + b.Property<string>("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property<Guid>("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("PK_uploaded_resource_log"); + + b.ToTable("uploaded_resource_log", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Whitelist", b => + { + b.Property<Guid>("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("UserId") + .HasName("PK_whitelist"); + + b.ToTable("whitelist", (string)null); + }); + + modelBuilder.Entity("PlayerRound", b => + { + b.Property<int>("PlayersId") + .HasColumnType("integer") + .HasColumnName("players_id"); + + b.Property<int>("RoundsId") + .HasColumnType("integer") + .HasColumnName("rounds_id"); + + b.HasKey("PlayersId", "RoundsId") + .HasName("PK_player_round"); + + b.HasIndex("RoundsId") + .HasDatabaseName("IX_player_round_rounds_id"); + + b.ToTable("player_round", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.HasOne("Content.Server.Database.AdminRank", "AdminRank") + .WithMany("Admins") + .HasForeignKey("AdminRankId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_admin_rank_admin_rank_id"); + + b.Navigation("AdminRank"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminFlag", b => + { + b.HasOne("Content.Server.Database.Admin", "Admin") + .WithMany("Flags") + .HasForeignKey("AdminId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_admin_flag_admin_admin_id"); + + b.Navigation("Admin"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminLog", b => + { + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany("AdminLogs") + .HasForeignKey("RoundId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_admin_log_round_round_id"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b => + { + b.HasOne("Content.Server.Database.Player", "Player") + .WithMany("AdminLogs") + .HasForeignKey("PlayerUserId") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_admin_log_player_player_player_user_id"); + + b.HasOne("Content.Server.Database.AdminLog", "Log") + .WithMany("Players") + .HasForeignKey("RoundId", "LogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_admin_log_player_admin_log_round_id_log_id"); + + b.Navigation("Log"); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminMessage", b => + { + b.HasOne("Content.Server.Database.Player", "CreatedBy") + .WithMany("AdminMessagesCreated") + .HasForeignKey("CreatedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_messages_player_created_by_id"); + + b.HasOne("Content.Server.Database.Player", "DeletedBy") + .WithMany("AdminMessagesDeleted") + .HasForeignKey("DeletedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_messages_player_deleted_by_id"); + + b.HasOne("Content.Server.Database.Player", "LastEditedBy") + .WithMany("AdminMessagesLastEdited") + .HasForeignKey("LastEditedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_messages_player_last_edited_by_id"); + + b.HasOne("Content.Server.Database.Player", "Player") + .WithMany("AdminMessagesReceived") + .HasForeignKey("PlayerUserId") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("FK_admin_messages_player_player_user_id"); + + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .HasConstraintName("FK_admin_messages_round_round_id"); + + b.Navigation("CreatedBy"); + + b.Navigation("DeletedBy"); + + b.Navigation("LastEditedBy"); + + b.Navigation("Player"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminNote", b => + { + b.HasOne("Content.Server.Database.Player", "CreatedBy") + .WithMany("AdminNotesCreated") + .HasForeignKey("CreatedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_notes_player_created_by_id"); + + b.HasOne("Content.Server.Database.Player", "DeletedBy") + .WithMany("AdminNotesDeleted") + .HasForeignKey("DeletedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_notes_player_deleted_by_id"); + + b.HasOne("Content.Server.Database.Player", "LastEditedBy") + .WithMany("AdminNotesLastEdited") + .HasForeignKey("LastEditedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_notes_player_last_edited_by_id"); + + b.HasOne("Content.Server.Database.Player", "Player") + .WithMany("AdminNotesReceived") + .HasForeignKey("PlayerUserId") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("FK_admin_notes_player_player_user_id"); + + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .HasConstraintName("FK_admin_notes_round_round_id"); + + b.Navigation("CreatedBy"); + + b.Navigation("DeletedBy"); + + b.Navigation("LastEditedBy"); + + b.Navigation("Player"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b => + { + b.HasOne("Content.Server.Database.AdminRank", "Rank") + .WithMany("Flags") + .HasForeignKey("AdminRankId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_admin_rank_flag_admin_rank_admin_rank_id"); + + b.Navigation("Rank"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminWatchlist", b => + { + b.HasOne("Content.Server.Database.Player", "CreatedBy") + .WithMany("AdminWatchlistsCreated") + .HasForeignKey("CreatedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_watchlists_player_created_by_id"); + + b.HasOne("Content.Server.Database.Player", "DeletedBy") + .WithMany("AdminWatchlistsDeleted") + .HasForeignKey("DeletedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_watchlists_player_deleted_by_id"); + + b.HasOne("Content.Server.Database.Player", "LastEditedBy") + .WithMany("AdminWatchlistsLastEdited") + .HasForeignKey("LastEditedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_watchlists_player_last_edited_by_id"); + + b.HasOne("Content.Server.Database.Player", "Player") + .WithMany("AdminWatchlistsReceived") + .HasForeignKey("PlayerUserId") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("FK_admin_watchlists_player_player_user_id"); + + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .HasConstraintName("FK_admin_watchlists_round_round_id"); + + b.Navigation("CreatedBy"); + + b.Navigation("DeletedBy"); + + b.Navigation("LastEditedBy"); + + b.Navigation("Player"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Antags") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_antag_profile_profile_id"); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Content.Server.Database.ConnectionLog", b => + { + b.HasOne("Content.Server.Database.Server", "Server") + .WithMany("ConnectionLogs") + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.SetNull) + .IsRequired() + .HasConstraintName("FK_connection_log_server_server_id"); + + b.Navigation("Server"); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Jobs") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_job_profile_profile_id"); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.HasOne("Content.Server.Database.Preference", "Preference") + .WithMany("Profiles") + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_profile_preference_preference_id"); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b => + { + b.HasOne("Content.Server.Database.ProfileLoadoutGroup", "ProfileLoadoutGroup") + .WithMany("Loadouts") + .HasForeignKey("ProfileLoadoutGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_profile_loadout_profile_loadout_group_profile_loadout_group~"); + + b.Navigation("ProfileLoadoutGroup"); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b => + { + b.HasOne("Content.Server.Database.ProfileRoleLoadout", "ProfileRoleLoadout") + .WithMany("Groups") + .HasForeignKey("ProfileRoleLoadoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_profile_loadout_group_profile_role_loadout_profile_role_loa~"); + + b.Navigation("ProfileRoleLoadout"); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Loadouts") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_profile_role_loadout_profile_profile_id"); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Content.Server.Database.RoleWhitelist", b => + { + b.HasOne("Content.Server.Database.Player", "Player") + .WithMany("JobWhitelists") + .HasForeignKey("PlayerUserId") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_role_whitelists_player_player_user_id"); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("Content.Server.Database.Round", b => + { + b.HasOne("Content.Server.Database.Server", "Server") + .WithMany("Rounds") + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_round_server_server_id"); + + b.Navigation("Server"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBan", b => + { + b.HasOne("Content.Server.Database.Player", "CreatedBy") + .WithMany("AdminServerBansCreated") + .HasForeignKey("BanningAdmin") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_server_ban_player_banning_admin"); + + b.HasOne("Content.Server.Database.Player", "LastEditedBy") + .WithMany("AdminServerBansLastEdited") + .HasForeignKey("LastEditedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_server_ban_player_last_edited_by_id"); + + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .HasConstraintName("FK_server_ban_round_round_id"); + + b.Navigation("CreatedBy"); + + b.Navigation("LastEditedBy"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBanHit", b => + { + b.HasOne("Content.Server.Database.ServerBan", "Ban") + .WithMany("BanHits") + .HasForeignKey("BanId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_server_ban_hit_server_ban_ban_id"); + + b.HasOne("Content.Server.Database.ConnectionLog", "Connection") + .WithMany("BanHits") + .HasForeignKey("ConnectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_server_ban_hit_connection_log_connection_id"); + + b.Navigation("Ban"); + + b.Navigation("Connection"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b => + { + b.HasOne("Content.Server.Database.Player", "CreatedBy") + .WithMany("AdminServerRoleBansCreated") + .HasForeignKey("BanningAdmin") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_server_role_ban_player_banning_admin"); + + b.HasOne("Content.Server.Database.Player", "LastEditedBy") + .WithMany("AdminServerRoleBansLastEdited") + .HasForeignKey("LastEditedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_server_role_ban_player_last_edited_by_id"); + + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .HasConstraintName("FK_server_role_ban_round_round_id"); + + b.Navigation("CreatedBy"); + + b.Navigation("LastEditedBy"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b => + { + b.HasOne("Content.Server.Database.ServerRoleBan", "Ban") + .WithOne("Unban") + .HasForeignKey("Content.Server.Database.ServerRoleUnban", "BanId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_server_role_unban_server_role_ban_ban_id"); + + b.Navigation("Ban"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerUnban", b => + { + b.HasOne("Content.Server.Database.ServerBan", "Ban") + .WithOne("Unban") + .HasForeignKey("Content.Server.Database.ServerUnban", "BanId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_server_unban_server_ban_ban_id"); + + b.Navigation("Ban"); + }); + + modelBuilder.Entity("Content.Server.Database.Trait", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Traits") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_trait_profile_profile_id"); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("PlayerRound", b => + { + b.HasOne("Content.Server.Database.Player", null) + .WithMany() + .HasForeignKey("PlayersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_player_round_player_players_id"); + + b.HasOne("Content.Server.Database.Round", null) + .WithMany() + .HasForeignKey("RoundsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_player_round_round_rounds_id"); + }); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.Navigation("Flags"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminLog", b => + { + b.Navigation("Players"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRank", b => + { + b.Navigation("Admins"); + + b.Navigation("Flags"); + }); + + modelBuilder.Entity("Content.Server.Database.ConnectionLog", b => + { + b.Navigation("BanHits"); + }); + + modelBuilder.Entity("Content.Server.Database.Player", b => + { + b.Navigation("AdminLogs"); + + b.Navigation("AdminMessagesCreated"); + + b.Navigation("AdminMessagesDeleted"); + + b.Navigation("AdminMessagesLastEdited"); + + b.Navigation("AdminMessagesReceived"); + + b.Navigation("AdminNotesCreated"); + + b.Navigation("AdminNotesDeleted"); + + b.Navigation("AdminNotesLastEdited"); + + b.Navigation("AdminNotesReceived"); + + b.Navigation("AdminServerBansCreated"); + + b.Navigation("AdminServerBansLastEdited"); + + b.Navigation("AdminServerRoleBansCreated"); + + b.Navigation("AdminServerRoleBansLastEdited"); + + b.Navigation("AdminWatchlistsCreated"); + + b.Navigation("AdminWatchlistsDeleted"); + + b.Navigation("AdminWatchlistsLastEdited"); + + b.Navigation("AdminWatchlistsReceived"); + + b.Navigation("JobWhitelists"); + }); + + modelBuilder.Entity("Content.Server.Database.Preference", b => + { + b.Navigation("Profiles"); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.Navigation("Antags"); + + b.Navigation("Jobs"); + + b.Navigation("Loadouts"); + + b.Navigation("Traits"); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b => + { + b.Navigation("Loadouts"); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b => + { + b.Navigation("Groups"); + }); + + modelBuilder.Entity("Content.Server.Database.Round", b => + { + b.Navigation("AdminLogs"); + }); + + modelBuilder.Entity("Content.Server.Database.Server", b => + { + b.Navigation("ConnectionLogs"); + + b.Navigation("Rounds"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBan", b => + { + b.Navigation("BanHits"); + + b.Navigation("Unban"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b => + { + b.Navigation("Unban"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Content.Server.Database/Migrations/Postgres/20240606065731_RemoveLastReadRules.cs b/Content.Server.Database/Migrations/Postgres/20240606065731_RemoveLastReadRules.cs new file mode 100644 index 00000000000..1982197f62e --- /dev/null +++ b/Content.Server.Database/Migrations/Postgres/20240606065731_RemoveLastReadRules.cs @@ -0,0 +1,29 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Content.Server.Database.Migrations.Postgres +{ + /// <inheritdoc /> + public partial class RemoveLastReadRules : Migration + { + /// <inheritdoc /> + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "last_read_rules", + table: "player"); + } + + /// <inheritdoc /> + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn<DateTime>( + name: "last_read_rules", + table: "player", + type: "timestamp with time zone", + nullable: true); + } + } +} diff --git a/Content.Server.Database/Migrations/Postgres/PostgresServerDbContextModelSnapshot.cs b/Content.Server.Database/Migrations/Postgres/PostgresServerDbContextModelSnapshot.cs index 0282063649b..e06793fee11 100644 --- a/Content.Server.Database/Migrations/Postgres/PostgresServerDbContextModelSnapshot.cs +++ b/Content.Server.Database/Migrations/Postgres/PostgresServerDbContextModelSnapshot.cs @@ -720,10 +720,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("timestamp with time zone") .HasColumnName("first_seen_time"); - b.Property<DateTime?>("LastReadRules") - .HasColumnType("timestamp with time zone") - .HasColumnName("last_read_rules"); - b.Property<IPAddress>("LastSeenAddress") .IsRequired() .HasColumnType("inet") diff --git a/Content.Server.Database/Migrations/Sqlite/20240606065717_RemoveLastReadRules.Designer.cs b/Content.Server.Database/Migrations/Sqlite/20240606065717_RemoveLastReadRules.Designer.cs new file mode 100644 index 00000000000..fceb831f00e --- /dev/null +++ b/Content.Server.Database/Migrations/Sqlite/20240606065717_RemoveLastReadRules.Designer.cs @@ -0,0 +1,1834 @@ +// <auto-generated /> +using System; +using Content.Server.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Content.Server.Database.Migrations.Sqlite +{ + [DbContext(typeof(SqliteServerDbContext))] + [Migration("20240606065717_RemoveLastReadRules")] + partial class RemoveLastReadRules + { + /// <inheritdoc /> + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.0"); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.Property<Guid>("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.Property<int?>("AdminRankId") + .HasColumnType("INTEGER") + .HasColumnName("admin_rank_id"); + + b.Property<string>("Title") + .HasColumnType("TEXT") + .HasColumnName("title"); + + b.HasKey("UserId") + .HasName("PK_admin"); + + b.HasIndex("AdminRankId") + .HasDatabaseName("IX_admin_admin_rank_id"); + + b.ToTable("admin", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminFlag", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("admin_flag_id"); + + b.Property<Guid>("AdminId") + .HasColumnType("TEXT") + .HasColumnName("admin_id"); + + b.Property<string>("Flag") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("flag"); + + b.Property<bool>("Negative") + .HasColumnType("INTEGER") + .HasColumnName("negative"); + + b.HasKey("Id") + .HasName("PK_admin_flag"); + + b.HasIndex("AdminId") + .HasDatabaseName("IX_admin_flag_admin_id"); + + b.HasIndex("Flag", "AdminId") + .IsUnique(); + + b.ToTable("admin_flag", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminLog", b => + { + b.Property<int>("RoundId") + .HasColumnType("INTEGER") + .HasColumnName("round_id"); + + b.Property<int>("Id") + .HasColumnType("INTEGER") + .HasColumnName("admin_log_id"); + + b.Property<DateTime>("Date") + .HasColumnType("TEXT") + .HasColumnName("date"); + + b.Property<sbyte>("Impact") + .HasColumnType("INTEGER") + .HasColumnName("impact"); + + b.Property<string>("Json") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("json"); + + b.Property<string>("Message") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("message"); + + b.Property<int>("Type") + .HasColumnType("INTEGER") + .HasColumnName("type"); + + b.HasKey("RoundId", "Id") + .HasName("PK_admin_log"); + + b.HasIndex("Date"); + + b.HasIndex("Type") + .HasDatabaseName("IX_admin_log_type"); + + b.ToTable("admin_log", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b => + { + b.Property<int>("RoundId") + .HasColumnType("INTEGER") + .HasColumnName("round_id"); + + b.Property<int>("LogId") + .HasColumnType("INTEGER") + .HasColumnName("log_id"); + + b.Property<Guid>("PlayerUserId") + .HasColumnType("TEXT") + .HasColumnName("player_user_id"); + + b.HasKey("RoundId", "LogId", "PlayerUserId") + .HasName("PK_admin_log_player"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_admin_log_player_player_user_id"); + + b.ToTable("admin_log_player", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminMessage", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("admin_messages_id"); + + b.Property<DateTime>("CreatedAt") + .HasColumnType("TEXT") + .HasColumnName("created_at"); + + b.Property<Guid?>("CreatedById") + .HasColumnType("TEXT") + .HasColumnName("created_by_id"); + + b.Property<bool>("Deleted") + .HasColumnType("INTEGER") + .HasColumnName("deleted"); + + b.Property<DateTime?>("DeletedAt") + .HasColumnType("TEXT") + .HasColumnName("deleted_at"); + + b.Property<Guid?>("DeletedById") + .HasColumnType("TEXT") + .HasColumnName("deleted_by_id"); + + b.Property<bool>("Dismissed") + .HasColumnType("INTEGER") + .HasColumnName("dismissed"); + + b.Property<DateTime?>("ExpirationTime") + .HasColumnType("TEXT") + .HasColumnName("expiration_time"); + + b.Property<DateTime?>("LastEditedAt") + .HasColumnType("TEXT") + .HasColumnName("last_edited_at"); + + b.Property<Guid?>("LastEditedById") + .HasColumnType("TEXT") + .HasColumnName("last_edited_by_id"); + + b.Property<string>("Message") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("TEXT") + .HasColumnName("message"); + + b.Property<Guid?>("PlayerUserId") + .HasColumnType("TEXT") + .HasColumnName("player_user_id"); + + b.Property<TimeSpan>("PlaytimeAtNote") + .HasColumnType("TEXT") + .HasColumnName("playtime_at_note"); + + b.Property<int?>("RoundId") + .HasColumnType("INTEGER") + .HasColumnName("round_id"); + + b.Property<bool>("Seen") + .HasColumnType("INTEGER") + .HasColumnName("seen"); + + b.HasKey("Id") + .HasName("PK_admin_messages"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DeletedById"); + + b.HasIndex("LastEditedById"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_admin_messages_player_user_id"); + + b.HasIndex("RoundId") + .HasDatabaseName("IX_admin_messages_round_id"); + + b.ToTable("admin_messages", null, t => + { + t.HasCheckConstraint("NotDismissedAndSeen", "NOT dismissed OR seen"); + }); + }); + + modelBuilder.Entity("Content.Server.Database.AdminNote", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("admin_notes_id"); + + b.Property<DateTime>("CreatedAt") + .HasColumnType("TEXT") + .HasColumnName("created_at"); + + b.Property<Guid?>("CreatedById") + .HasColumnType("TEXT") + .HasColumnName("created_by_id"); + + b.Property<bool>("Deleted") + .HasColumnType("INTEGER") + .HasColumnName("deleted"); + + b.Property<DateTime?>("DeletedAt") + .HasColumnType("TEXT") + .HasColumnName("deleted_at"); + + b.Property<Guid?>("DeletedById") + .HasColumnType("TEXT") + .HasColumnName("deleted_by_id"); + + b.Property<DateTime?>("ExpirationTime") + .HasColumnType("TEXT") + .HasColumnName("expiration_time"); + + b.Property<DateTime?>("LastEditedAt") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("last_edited_at"); + + b.Property<Guid?>("LastEditedById") + .HasColumnType("TEXT") + .HasColumnName("last_edited_by_id"); + + b.Property<string>("Message") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("TEXT") + .HasColumnName("message"); + + b.Property<Guid?>("PlayerUserId") + .HasColumnType("TEXT") + .HasColumnName("player_user_id"); + + b.Property<TimeSpan>("PlaytimeAtNote") + .HasColumnType("TEXT") + .HasColumnName("playtime_at_note"); + + b.Property<int?>("RoundId") + .HasColumnType("INTEGER") + .HasColumnName("round_id"); + + b.Property<bool>("Secret") + .HasColumnType("INTEGER") + .HasColumnName("secret"); + + b.Property<int>("Severity") + .HasColumnType("INTEGER") + .HasColumnName("severity"); + + b.HasKey("Id") + .HasName("PK_admin_notes"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DeletedById"); + + b.HasIndex("LastEditedById"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_admin_notes_player_user_id"); + + b.HasIndex("RoundId") + .HasDatabaseName("IX_admin_notes_round_id"); + + b.ToTable("admin_notes", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRank", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("admin_rank_id"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("PK_admin_rank"); + + b.ToTable("admin_rank", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("admin_rank_flag_id"); + + b.Property<int>("AdminRankId") + .HasColumnType("INTEGER") + .HasColumnName("admin_rank_id"); + + b.Property<string>("Flag") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("flag"); + + b.HasKey("Id") + .HasName("PK_admin_rank_flag"); + + b.HasIndex("AdminRankId"); + + b.HasIndex("Flag", "AdminRankId") + .IsUnique(); + + b.ToTable("admin_rank_flag", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AdminWatchlist", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("admin_watchlists_id"); + + b.Property<DateTime>("CreatedAt") + .HasColumnType("TEXT") + .HasColumnName("created_at"); + + b.Property<Guid?>("CreatedById") + .HasColumnType("TEXT") + .HasColumnName("created_by_id"); + + b.Property<bool>("Deleted") + .HasColumnType("INTEGER") + .HasColumnName("deleted"); + + b.Property<DateTime?>("DeletedAt") + .HasColumnType("TEXT") + .HasColumnName("deleted_at"); + + b.Property<Guid?>("DeletedById") + .HasColumnType("TEXT") + .HasColumnName("deleted_by_id"); + + b.Property<DateTime?>("ExpirationTime") + .HasColumnType("TEXT") + .HasColumnName("expiration_time"); + + b.Property<DateTime?>("LastEditedAt") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("last_edited_at"); + + b.Property<Guid?>("LastEditedById") + .HasColumnType("TEXT") + .HasColumnName("last_edited_by_id"); + + b.Property<string>("Message") + .IsRequired() + .HasMaxLength(4096) + .HasColumnType("TEXT") + .HasColumnName("message"); + + b.Property<Guid?>("PlayerUserId") + .HasColumnType("TEXT") + .HasColumnName("player_user_id"); + + b.Property<TimeSpan>("PlaytimeAtNote") + .HasColumnType("TEXT") + .HasColumnName("playtime_at_note"); + + b.Property<int?>("RoundId") + .HasColumnType("INTEGER") + .HasColumnName("round_id"); + + b.HasKey("Id") + .HasName("PK_admin_watchlists"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DeletedById"); + + b.HasIndex("LastEditedById"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_admin_watchlists_player_user_id"); + + b.HasIndex("RoundId") + .HasDatabaseName("IX_admin_watchlists_round_id"); + + b.ToTable("admin_watchlists", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("antag_id"); + + b.Property<string>("AntagName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("antag_name"); + + b.Property<int>("ProfileId") + .HasColumnType("INTEGER") + .HasColumnName("profile_id"); + + b.HasKey("Id") + .HasName("PK_antag"); + + b.HasIndex("ProfileId", "AntagName") + .IsUnique(); + + b.ToTable("antag", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.AssignedUserId", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("assigned_user_id_id"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.Property<string>("UserName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("user_name"); + + b.HasKey("Id") + .HasName("PK_assigned_user_id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.HasIndex("UserName") + .IsUnique(); + + b.ToTable("assigned_user_id", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ConnectionLog", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("connection_log_id"); + + b.Property<string>("Address") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("address"); + + b.Property<byte?>("Denied") + .HasColumnType("INTEGER") + .HasColumnName("denied"); + + b.Property<byte[]>("HWId") + .HasColumnType("BLOB") + .HasColumnName("hwid"); + + b.Property<int>("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0) + .HasColumnName("server_id"); + + b.Property<DateTime>("Time") + .HasColumnType("TEXT") + .HasColumnName("time"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.Property<string>("UserName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("user_name"); + + b.HasKey("Id") + .HasName("PK_connection_log"); + + b.HasIndex("ServerId") + .HasDatabaseName("IX_connection_log_server_id"); + + b.HasIndex("UserId"); + + b.ToTable("connection_log", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("job_id"); + + b.Property<string>("JobName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("job_name"); + + b.Property<int>("Priority") + .HasColumnType("INTEGER") + .HasColumnName("priority"); + + b.Property<int>("ProfileId") + .HasColumnType("INTEGER") + .HasColumnName("profile_id"); + + b.HasKey("Id") + .HasName("PK_job"); + + b.HasIndex("ProfileId"); + + b.HasIndex("ProfileId", "JobName") + .IsUnique(); + + b.HasIndex(new[] { "ProfileId" }, "IX_job_one_high_priority") + .IsUnique() + .HasFilter("priority = 3"); + + b.ToTable("job", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.PlayTime", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("play_time_id"); + + b.Property<Guid>("PlayerId") + .HasColumnType("TEXT") + .HasColumnName("player_id"); + + b.Property<TimeSpan>("TimeSpent") + .HasColumnType("TEXT") + .HasColumnName("time_spent"); + + b.Property<string>("Tracker") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("tracker"); + + b.HasKey("Id") + .HasName("PK_play_time"); + + b.HasIndex("PlayerId", "Tracker") + .IsUnique(); + + b.ToTable("play_time", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Player", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("player_id"); + + b.Property<DateTime>("FirstSeenTime") + .HasColumnType("TEXT") + .HasColumnName("first_seen_time"); + + b.Property<string>("LastSeenAddress") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("last_seen_address"); + + b.Property<byte[]>("LastSeenHWId") + .HasColumnType("BLOB") + .HasColumnName("last_seen_hwid"); + + b.Property<DateTime>("LastSeenTime") + .HasColumnType("TEXT") + .HasColumnName("last_seen_time"); + + b.Property<string>("LastSeenUserName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("last_seen_user_name"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("PK_player"); + + b.HasAlternateKey("UserId") + .HasName("ak_player_user_id"); + + b.HasIndex("LastSeenUserName"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("player", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Preference", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("preference_id"); + + b.Property<string>("AdminOOCColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("admin_ooc_color"); + + b.Property<int>("SelectedCharacterSlot") + .HasColumnType("INTEGER") + .HasColumnName("selected_character_slot"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("PK_preference"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("preference", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("profile_id"); + + b.Property<int>("Age") + .HasColumnType("INTEGER") + .HasColumnName("age"); + + b.Property<string>("CharacterName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("char_name"); + + b.Property<string>("EyeColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("eye_color"); + + b.Property<string>("FacialHairColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("facial_hair_color"); + + b.Property<string>("FacialHairName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("facial_hair_name"); + + b.Property<string>("FlavorText") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("flavor_text"); + + b.Property<string>("Gender") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("gender"); + + b.Property<string>("HairColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("hair_color"); + + b.Property<string>("HairName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("hair_name"); + + b.Property<byte[]>("Markings") + .HasColumnType("jsonb") + .HasColumnName("markings"); + + b.Property<int>("PreferenceId") + .HasColumnType("INTEGER") + .HasColumnName("preference_id"); + + b.Property<int>("PreferenceUnavailable") + .HasColumnType("INTEGER") + .HasColumnName("pref_unavailable"); + + b.Property<string>("Sex") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("sex"); + + b.Property<string>("SkinColor") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("skin_color"); + + b.Property<int>("Slot") + .HasColumnType("INTEGER") + .HasColumnName("slot"); + + b.Property<int>("SpawnPriority") + .HasColumnType("INTEGER") + .HasColumnName("spawn_priority"); + + b.Property<string>("Species") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("species"); + + b.HasKey("Id") + .HasName("PK_profile"); + + b.HasIndex("PreferenceId") + .HasDatabaseName("IX_profile_preference_id"); + + b.HasIndex("Slot", "PreferenceId") + .IsUnique(); + + b.ToTable("profile", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("profile_loadout_id"); + + b.Property<string>("LoadoutName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("loadout_name"); + + b.Property<int>("ProfileLoadoutGroupId") + .HasColumnType("INTEGER") + .HasColumnName("profile_loadout_group_id"); + + b.HasKey("Id") + .HasName("PK_profile_loadout"); + + b.HasIndex("ProfileLoadoutGroupId"); + + b.ToTable("profile_loadout", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("profile_loadout_group_id"); + + b.Property<string>("GroupName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("group_name"); + + b.Property<int>("ProfileRoleLoadoutId") + .HasColumnType("INTEGER") + .HasColumnName("profile_role_loadout_id"); + + b.HasKey("Id") + .HasName("PK_profile_loadout_group"); + + b.HasIndex("ProfileRoleLoadoutId"); + + b.ToTable("profile_loadout_group", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("profile_role_loadout_id"); + + b.Property<int>("ProfileId") + .HasColumnType("INTEGER") + .HasColumnName("profile_id"); + + b.Property<string>("RoleName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("role_name"); + + b.HasKey("Id") + .HasName("PK_profile_role_loadout"); + + b.HasIndex("ProfileId"); + + b.ToTable("profile_role_loadout", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.RoleWhitelist", b => + { + b.Property<Guid>("PlayerUserId") + .HasColumnType("TEXT") + .HasColumnName("player_user_id"); + + b.Property<string>("RoleId") + .HasColumnType("TEXT") + .HasColumnName("role_id"); + + b.HasKey("PlayerUserId", "RoleId") + .HasName("PK_role_whitelists"); + + b.ToTable("role_whitelists", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Round", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("round_id"); + + b.Property<int>("ServerId") + .HasColumnType("INTEGER") + .HasColumnName("server_id"); + + b.Property<DateTime?>("StartDate") + .HasColumnType("TEXT") + .HasColumnName("start_date"); + + b.HasKey("Id") + .HasName("PK_round"); + + b.HasIndex("ServerId") + .HasDatabaseName("IX_round_server_id"); + + b.HasIndex("StartDate"); + + b.ToTable("round", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Server", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("server_id"); + + b.Property<string>("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("PK_server"); + + b.ToTable("server", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBan", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("server_ban_id"); + + b.Property<string>("Address") + .HasColumnType("TEXT") + .HasColumnName("address"); + + b.Property<bool>("AutoDelete") + .HasColumnType("INTEGER") + .HasColumnName("auto_delete"); + + b.Property<DateTime>("BanTime") + .HasColumnType("TEXT") + .HasColumnName("ban_time"); + + b.Property<Guid?>("BanningAdmin") + .HasColumnType("TEXT") + .HasColumnName("banning_admin"); + + b.Property<int>("ExemptFlags") + .HasColumnType("INTEGER") + .HasColumnName("exempt_flags"); + + b.Property<DateTime?>("ExpirationTime") + .HasColumnType("TEXT") + .HasColumnName("expiration_time"); + + b.Property<byte[]>("HWId") + .HasColumnType("BLOB") + .HasColumnName("hwid"); + + b.Property<bool>("Hidden") + .HasColumnType("INTEGER") + .HasColumnName("hidden"); + + b.Property<DateTime?>("LastEditedAt") + .HasColumnType("TEXT") + .HasColumnName("last_edited_at"); + + b.Property<Guid?>("LastEditedById") + .HasColumnType("TEXT") + .HasColumnName("last_edited_by_id"); + + b.Property<Guid?>("PlayerUserId") + .HasColumnType("TEXT") + .HasColumnName("player_user_id"); + + b.Property<TimeSpan>("PlaytimeAtNote") + .HasColumnType("TEXT") + .HasColumnName("playtime_at_note"); + + b.Property<string>("Reason") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("reason"); + + b.Property<int?>("RoundId") + .HasColumnType("INTEGER") + .HasColumnName("round_id"); + + b.Property<int>("Severity") + .HasColumnType("INTEGER") + .HasColumnName("severity"); + + b.HasKey("Id") + .HasName("PK_server_ban"); + + b.HasIndex("Address"); + + b.HasIndex("BanningAdmin"); + + b.HasIndex("LastEditedById"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_server_ban_player_user_id"); + + b.HasIndex("RoundId") + .HasDatabaseName("IX_server_ban_round_id"); + + b.ToTable("server_ban", null, t => + { + t.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR player_user_id IS NOT NULL OR hwid IS NOT NULL"); + }); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBanExemption", b => + { + b.Property<Guid>("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.Property<int>("Flags") + .HasColumnType("INTEGER") + .HasColumnName("flags"); + + b.HasKey("UserId") + .HasName("PK_server_ban_exemption"); + + b.ToTable("server_ban_exemption", null, t => + { + t.HasCheckConstraint("FlagsNotZero", "flags != 0"); + }); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBanHit", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("server_ban_hit_id"); + + b.Property<int>("BanId") + .HasColumnType("INTEGER") + .HasColumnName("ban_id"); + + b.Property<int>("ConnectionId") + .HasColumnType("INTEGER") + .HasColumnName("connection_id"); + + b.HasKey("Id") + .HasName("PK_server_ban_hit"); + + b.HasIndex("BanId") + .HasDatabaseName("IX_server_ban_hit_ban_id"); + + b.HasIndex("ConnectionId") + .HasDatabaseName("IX_server_ban_hit_connection_id"); + + b.ToTable("server_ban_hit", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("server_role_ban_id"); + + b.Property<string>("Address") + .HasColumnType("TEXT") + .HasColumnName("address"); + + b.Property<DateTime>("BanTime") + .HasColumnType("TEXT") + .HasColumnName("ban_time"); + + b.Property<Guid?>("BanningAdmin") + .HasColumnType("TEXT") + .HasColumnName("banning_admin"); + + b.Property<DateTime?>("ExpirationTime") + .HasColumnType("TEXT") + .HasColumnName("expiration_time"); + + b.Property<byte[]>("HWId") + .HasColumnType("BLOB") + .HasColumnName("hwid"); + + b.Property<bool>("Hidden") + .HasColumnType("INTEGER") + .HasColumnName("hidden"); + + b.Property<DateTime?>("LastEditedAt") + .HasColumnType("TEXT") + .HasColumnName("last_edited_at"); + + b.Property<Guid?>("LastEditedById") + .HasColumnType("TEXT") + .HasColumnName("last_edited_by_id"); + + b.Property<Guid?>("PlayerUserId") + .HasColumnType("TEXT") + .HasColumnName("player_user_id"); + + b.Property<TimeSpan>("PlaytimeAtNote") + .HasColumnType("TEXT") + .HasColumnName("playtime_at_note"); + + b.Property<string>("Reason") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("reason"); + + b.Property<string>("RoleId") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("role_id"); + + b.Property<int?>("RoundId") + .HasColumnType("INTEGER") + .HasColumnName("round_id"); + + b.Property<int>("Severity") + .HasColumnType("INTEGER") + .HasColumnName("severity"); + + b.HasKey("Id") + .HasName("PK_server_role_ban"); + + b.HasIndex("Address"); + + b.HasIndex("BanningAdmin"); + + b.HasIndex("LastEditedById"); + + b.HasIndex("PlayerUserId") + .HasDatabaseName("IX_server_role_ban_player_user_id"); + + b.HasIndex("RoundId") + .HasDatabaseName("IX_server_role_ban_round_id"); + + b.ToTable("server_role_ban", null, t => + { + t.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR player_user_id IS NOT NULL OR hwid IS NOT NULL"); + }); + }); + + modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("role_unban_id"); + + b.Property<int>("BanId") + .HasColumnType("INTEGER") + .HasColumnName("ban_id"); + + b.Property<DateTime>("UnbanTime") + .HasColumnType("TEXT") + .HasColumnName("unban_time"); + + b.Property<Guid?>("UnbanningAdmin") + .HasColumnType("TEXT") + .HasColumnName("unbanning_admin"); + + b.HasKey("Id") + .HasName("PK_server_role_unban"); + + b.HasIndex("BanId") + .IsUnique(); + + b.ToTable("server_role_unban", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.ServerUnban", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("unban_id"); + + b.Property<int>("BanId") + .HasColumnType("INTEGER") + .HasColumnName("ban_id"); + + b.Property<DateTime>("UnbanTime") + .HasColumnType("TEXT") + .HasColumnName("unban_time"); + + b.Property<Guid?>("UnbanningAdmin") + .HasColumnType("TEXT") + .HasColumnName("unbanning_admin"); + + b.HasKey("Id") + .HasName("PK_server_unban"); + + b.HasIndex("BanId") + .IsUnique(); + + b.ToTable("server_unban", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Trait", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("trait_id"); + + b.Property<int>("ProfileId") + .HasColumnType("INTEGER") + .HasColumnName("profile_id"); + + b.Property<string>("TraitName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("trait_name"); + + b.HasKey("Id") + .HasName("PK_trait"); + + b.HasIndex("ProfileId", "TraitName") + .IsUnique(); + + b.ToTable("trait", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.UploadedResourceLog", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasColumnName("uploaded_resource_log_id"); + + b.Property<byte[]>("Data") + .IsRequired() + .HasColumnType("BLOB") + .HasColumnName("data"); + + b.Property<DateTime>("Date") + .HasColumnType("TEXT") + .HasColumnName("date"); + + b.Property<string>("Path") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("path"); + + b.Property<Guid>("UserId") + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("PK_uploaded_resource_log"); + + b.ToTable("uploaded_resource_log", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Whitelist", b => + { + b.Property<Guid>("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT") + .HasColumnName("user_id"); + + b.HasKey("UserId") + .HasName("PK_whitelist"); + + b.ToTable("whitelist", (string)null); + }); + + modelBuilder.Entity("PlayerRound", b => + { + b.Property<int>("PlayersId") + .HasColumnType("INTEGER") + .HasColumnName("players_id"); + + b.Property<int>("RoundsId") + .HasColumnType("INTEGER") + .HasColumnName("rounds_id"); + + b.HasKey("PlayersId", "RoundsId") + .HasName("PK_player_round"); + + b.HasIndex("RoundsId") + .HasDatabaseName("IX_player_round_rounds_id"); + + b.ToTable("player_round", (string)null); + }); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.HasOne("Content.Server.Database.AdminRank", "AdminRank") + .WithMany("Admins") + .HasForeignKey("AdminRankId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_admin_rank_admin_rank_id"); + + b.Navigation("AdminRank"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminFlag", b => + { + b.HasOne("Content.Server.Database.Admin", "Admin") + .WithMany("Flags") + .HasForeignKey("AdminId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_admin_flag_admin_admin_id"); + + b.Navigation("Admin"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminLog", b => + { + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany("AdminLogs") + .HasForeignKey("RoundId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_admin_log_round_round_id"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b => + { + b.HasOne("Content.Server.Database.Player", "Player") + .WithMany("AdminLogs") + .HasForeignKey("PlayerUserId") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_admin_log_player_player_player_user_id"); + + b.HasOne("Content.Server.Database.AdminLog", "Log") + .WithMany("Players") + .HasForeignKey("RoundId", "LogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_admin_log_player_admin_log_round_id_log_id"); + + b.Navigation("Log"); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminMessage", b => + { + b.HasOne("Content.Server.Database.Player", "CreatedBy") + .WithMany("AdminMessagesCreated") + .HasForeignKey("CreatedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_messages_player_created_by_id"); + + b.HasOne("Content.Server.Database.Player", "DeletedBy") + .WithMany("AdminMessagesDeleted") + .HasForeignKey("DeletedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_messages_player_deleted_by_id"); + + b.HasOne("Content.Server.Database.Player", "LastEditedBy") + .WithMany("AdminMessagesLastEdited") + .HasForeignKey("LastEditedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_messages_player_last_edited_by_id"); + + b.HasOne("Content.Server.Database.Player", "Player") + .WithMany("AdminMessagesReceived") + .HasForeignKey("PlayerUserId") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("FK_admin_messages_player_player_user_id"); + + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .HasConstraintName("FK_admin_messages_round_round_id"); + + b.Navigation("CreatedBy"); + + b.Navigation("DeletedBy"); + + b.Navigation("LastEditedBy"); + + b.Navigation("Player"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminNote", b => + { + b.HasOne("Content.Server.Database.Player", "CreatedBy") + .WithMany("AdminNotesCreated") + .HasForeignKey("CreatedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_notes_player_created_by_id"); + + b.HasOne("Content.Server.Database.Player", "DeletedBy") + .WithMany("AdminNotesDeleted") + .HasForeignKey("DeletedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_notes_player_deleted_by_id"); + + b.HasOne("Content.Server.Database.Player", "LastEditedBy") + .WithMany("AdminNotesLastEdited") + .HasForeignKey("LastEditedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_notes_player_last_edited_by_id"); + + b.HasOne("Content.Server.Database.Player", "Player") + .WithMany("AdminNotesReceived") + .HasForeignKey("PlayerUserId") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("FK_admin_notes_player_player_user_id"); + + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .HasConstraintName("FK_admin_notes_round_round_id"); + + b.Navigation("CreatedBy"); + + b.Navigation("DeletedBy"); + + b.Navigation("LastEditedBy"); + + b.Navigation("Player"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b => + { + b.HasOne("Content.Server.Database.AdminRank", "Rank") + .WithMany("Flags") + .HasForeignKey("AdminRankId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_admin_rank_flag_admin_rank_admin_rank_id"); + + b.Navigation("Rank"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminWatchlist", b => + { + b.HasOne("Content.Server.Database.Player", "CreatedBy") + .WithMany("AdminWatchlistsCreated") + .HasForeignKey("CreatedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_watchlists_player_created_by_id"); + + b.HasOne("Content.Server.Database.Player", "DeletedBy") + .WithMany("AdminWatchlistsDeleted") + .HasForeignKey("DeletedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_watchlists_player_deleted_by_id"); + + b.HasOne("Content.Server.Database.Player", "LastEditedBy") + .WithMany("AdminWatchlistsLastEdited") + .HasForeignKey("LastEditedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_admin_watchlists_player_last_edited_by_id"); + + b.HasOne("Content.Server.Database.Player", "Player") + .WithMany("AdminWatchlistsReceived") + .HasForeignKey("PlayerUserId") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("FK_admin_watchlists_player_player_user_id"); + + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .HasConstraintName("FK_admin_watchlists_round_round_id"); + + b.Navigation("CreatedBy"); + + b.Navigation("DeletedBy"); + + b.Navigation("LastEditedBy"); + + b.Navigation("Player"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.Antag", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Antags") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_antag_profile_profile_id"); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Content.Server.Database.ConnectionLog", b => + { + b.HasOne("Content.Server.Database.Server", "Server") + .WithMany("ConnectionLogs") + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.SetNull) + .IsRequired() + .HasConstraintName("FK_connection_log_server_server_id"); + + b.Navigation("Server"); + }); + + modelBuilder.Entity("Content.Server.Database.Job", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Jobs") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_job_profile_profile_id"); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.HasOne("Content.Server.Database.Preference", "Preference") + .WithMany("Profiles") + .HasForeignKey("PreferenceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_profile_preference_preference_id"); + + b.Navigation("Preference"); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileLoadout", b => + { + b.HasOne("Content.Server.Database.ProfileLoadoutGroup", "ProfileLoadoutGroup") + .WithMany("Loadouts") + .HasForeignKey("ProfileLoadoutGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_profile_loadout_profile_loadout_group_profile_loadout_group_id"); + + b.Navigation("ProfileLoadoutGroup"); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b => + { + b.HasOne("Content.Server.Database.ProfileRoleLoadout", "ProfileRoleLoadout") + .WithMany("Groups") + .HasForeignKey("ProfileRoleLoadoutId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_profile_loadout_group_profile_role_loadout_profile_role_loadout_id"); + + b.Navigation("ProfileRoleLoadout"); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Loadouts") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_profile_role_loadout_profile_profile_id"); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("Content.Server.Database.RoleWhitelist", b => + { + b.HasOne("Content.Server.Database.Player", "Player") + .WithMany("JobWhitelists") + .HasForeignKey("PlayerUserId") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_role_whitelists_player_player_user_id"); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("Content.Server.Database.Round", b => + { + b.HasOne("Content.Server.Database.Server", "Server") + .WithMany("Rounds") + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_round_server_server_id"); + + b.Navigation("Server"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBan", b => + { + b.HasOne("Content.Server.Database.Player", "CreatedBy") + .WithMany("AdminServerBansCreated") + .HasForeignKey("BanningAdmin") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_server_ban_player_banning_admin"); + + b.HasOne("Content.Server.Database.Player", "LastEditedBy") + .WithMany("AdminServerBansLastEdited") + .HasForeignKey("LastEditedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_server_ban_player_last_edited_by_id"); + + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .HasConstraintName("FK_server_ban_round_round_id"); + + b.Navigation("CreatedBy"); + + b.Navigation("LastEditedBy"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBanHit", b => + { + b.HasOne("Content.Server.Database.ServerBan", "Ban") + .WithMany("BanHits") + .HasForeignKey("BanId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_server_ban_hit_server_ban_ban_id"); + + b.HasOne("Content.Server.Database.ConnectionLog", "Connection") + .WithMany("BanHits") + .HasForeignKey("ConnectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_server_ban_hit_connection_log_connection_id"); + + b.Navigation("Ban"); + + b.Navigation("Connection"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b => + { + b.HasOne("Content.Server.Database.Player", "CreatedBy") + .WithMany("AdminServerRoleBansCreated") + .HasForeignKey("BanningAdmin") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_server_role_ban_player_banning_admin"); + + b.HasOne("Content.Server.Database.Player", "LastEditedBy") + .WithMany("AdminServerRoleBansLastEdited") + .HasForeignKey("LastEditedById") + .HasPrincipalKey("UserId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("FK_server_role_ban_player_last_edited_by_id"); + + b.HasOne("Content.Server.Database.Round", "Round") + .WithMany() + .HasForeignKey("RoundId") + .HasConstraintName("FK_server_role_ban_round_round_id"); + + b.Navigation("CreatedBy"); + + b.Navigation("LastEditedBy"); + + b.Navigation("Round"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b => + { + b.HasOne("Content.Server.Database.ServerRoleBan", "Ban") + .WithOne("Unban") + .HasForeignKey("Content.Server.Database.ServerRoleUnban", "BanId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_server_role_unban_server_role_ban_ban_id"); + + b.Navigation("Ban"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerUnban", b => + { + b.HasOne("Content.Server.Database.ServerBan", "Ban") + .WithOne("Unban") + .HasForeignKey("Content.Server.Database.ServerUnban", "BanId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_server_unban_server_ban_ban_id"); + + b.Navigation("Ban"); + }); + + modelBuilder.Entity("Content.Server.Database.Trait", b => + { + b.HasOne("Content.Server.Database.Profile", "Profile") + .WithMany("Traits") + .HasForeignKey("ProfileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_trait_profile_profile_id"); + + b.Navigation("Profile"); + }); + + modelBuilder.Entity("PlayerRound", b => + { + b.HasOne("Content.Server.Database.Player", null) + .WithMany() + .HasForeignKey("PlayersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_player_round_player_players_id"); + + b.HasOne("Content.Server.Database.Round", null) + .WithMany() + .HasForeignKey("RoundsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("FK_player_round_round_rounds_id"); + }); + + modelBuilder.Entity("Content.Server.Database.Admin", b => + { + b.Navigation("Flags"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminLog", b => + { + b.Navigation("Players"); + }); + + modelBuilder.Entity("Content.Server.Database.AdminRank", b => + { + b.Navigation("Admins"); + + b.Navigation("Flags"); + }); + + modelBuilder.Entity("Content.Server.Database.ConnectionLog", b => + { + b.Navigation("BanHits"); + }); + + modelBuilder.Entity("Content.Server.Database.Player", b => + { + b.Navigation("AdminLogs"); + + b.Navigation("AdminMessagesCreated"); + + b.Navigation("AdminMessagesDeleted"); + + b.Navigation("AdminMessagesLastEdited"); + + b.Navigation("AdminMessagesReceived"); + + b.Navigation("AdminNotesCreated"); + + b.Navigation("AdminNotesDeleted"); + + b.Navigation("AdminNotesLastEdited"); + + b.Navigation("AdminNotesReceived"); + + b.Navigation("AdminServerBansCreated"); + + b.Navigation("AdminServerBansLastEdited"); + + b.Navigation("AdminServerRoleBansCreated"); + + b.Navigation("AdminServerRoleBansLastEdited"); + + b.Navigation("AdminWatchlistsCreated"); + + b.Navigation("AdminWatchlistsDeleted"); + + b.Navigation("AdminWatchlistsLastEdited"); + + b.Navigation("AdminWatchlistsReceived"); + + b.Navigation("JobWhitelists"); + }); + + modelBuilder.Entity("Content.Server.Database.Preference", b => + { + b.Navigation("Profiles"); + }); + + modelBuilder.Entity("Content.Server.Database.Profile", b => + { + b.Navigation("Antags"); + + b.Navigation("Jobs"); + + b.Navigation("Loadouts"); + + b.Navigation("Traits"); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileLoadoutGroup", b => + { + b.Navigation("Loadouts"); + }); + + modelBuilder.Entity("Content.Server.Database.ProfileRoleLoadout", b => + { + b.Navigation("Groups"); + }); + + modelBuilder.Entity("Content.Server.Database.Round", b => + { + b.Navigation("AdminLogs"); + }); + + modelBuilder.Entity("Content.Server.Database.Server", b => + { + b.Navigation("ConnectionLogs"); + + b.Navigation("Rounds"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerBan", b => + { + b.Navigation("BanHits"); + + b.Navigation("Unban"); + }); + + modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b => + { + b.Navigation("Unban"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Content.Server.Database/Migrations/Sqlite/20240606065717_RemoveLastReadRules.cs b/Content.Server.Database/Migrations/Sqlite/20240606065717_RemoveLastReadRules.cs new file mode 100644 index 00000000000..7f98fc2410e --- /dev/null +++ b/Content.Server.Database/Migrations/Sqlite/20240606065717_RemoveLastReadRules.cs @@ -0,0 +1,29 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Content.Server.Database.Migrations.Sqlite +{ + /// <inheritdoc /> + public partial class RemoveLastReadRules : Migration + { + /// <inheritdoc /> + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "last_read_rules", + table: "player"); + } + + /// <inheritdoc /> + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn<DateTime>( + name: "last_read_rules", + table: "player", + type: "TEXT", + nullable: true); + } + } +} diff --git a/Content.Server.Database/Migrations/Sqlite/SqliteServerDbContextModelSnapshot.cs b/Content.Server.Database/Migrations/Sqlite/SqliteServerDbContextModelSnapshot.cs index c7a79b97171..9494b646eb7 100644 --- a/Content.Server.Database/Migrations/Sqlite/SqliteServerDbContextModelSnapshot.cs +++ b/Content.Server.Database/Migrations/Sqlite/SqliteServerDbContextModelSnapshot.cs @@ -676,10 +676,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("TEXT") .HasColumnName("first_seen_time"); - b.Property<DateTime?>("LastReadRules") - .HasColumnType("TEXT") - .HasColumnName("last_read_rules"); - b.Property<string>("LastSeenAddress") .IsRequired() .HasColumnType("TEXT") diff --git a/Content.Server.Database/Model.cs b/Content.Server.Database/Model.cs index e698805cfce..eb6ce3434b8 100644 --- a/Content.Server.Database/Model.cs +++ b/Content.Server.Database/Model.cs @@ -447,8 +447,6 @@ public class Player public List<Round> Rounds { get; set; } = null!; public List<AdminLogPlayer> AdminLogs { get; set; } = null!; - public DateTime? LastReadRules { get; set; } - public List<AdminNote> AdminNotesReceived { get; set; } = null!; public List<AdminNote> AdminNotesCreated { get; set; } = null!; public List<AdminNote> AdminNotesLastEdited { get; set; } = null!; diff --git a/Content.Server/Abilities/Mime/MimePowersComponent.cs b/Content.Server/Abilities/Mime/MimePowersComponent.cs index fd4fc2c2af9..d56644ed191 100644 --- a/Content.Server/Abilities/Mime/MimePowersComponent.cs +++ b/Content.Server/Abilities/Mime/MimePowersComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Alert; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -47,5 +48,12 @@ public sealed partial class MimePowersComponent : Component /// </summary> [DataField("vowCooldown")] public TimeSpan VowCooldown = TimeSpan.FromMinutes(5); + + [DataField] + public ProtoId<AlertPrototype> VowAlert = "VowOfSilence"; + + [DataField] + public ProtoId<AlertPrototype> VowBrokenAlert = "VowBroken"; + } } diff --git a/Content.Server/Abilities/Mime/MimePowersSystem.cs b/Content.Server/Abilities/Mime/MimePowersSystem.cs index 57163a96a50..a1e50228ae2 100644 --- a/Content.Server/Abilities/Mime/MimePowersSystem.cs +++ b/Content.Server/Abilities/Mime/MimePowersSystem.cs @@ -1,5 +1,4 @@ using Content.Server.Popups; -using Content.Server.Speech.Muting; using Content.Shared.Actions; using Content.Shared.Actions.Events; using Content.Shared.Alert; @@ -56,7 +55,7 @@ public override void Update(float frameTime) private void OnComponentInit(EntityUid uid, MimePowersComponent component, ComponentInit args) { EnsureComp<MutedComponent>(uid); - _alertsSystem.ShowAlert(uid, AlertType.VowOfSilence); + _alertsSystem.ShowAlert(uid, component.VowAlert); _actionsSystem.AddAction(uid, ref component.InvisibleWallActionEntity, component.InvisibleWallAction, uid); } @@ -120,8 +119,8 @@ public void BreakVow(EntityUid uid, MimePowersComponent? mimePowers = null) mimePowers.VowBroken = true; mimePowers.VowRepentTime = _timing.CurTime + mimePowers.VowCooldown; RemComp<MutedComponent>(uid); - _alertsSystem.ClearAlert(uid, AlertType.VowOfSilence); - _alertsSystem.ShowAlert(uid, AlertType.VowBroken); + _alertsSystem.ClearAlert(uid, mimePowers.VowAlert); + _alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert); _actionsSystem.RemoveAction(uid, mimePowers.InvisibleWallActionEntity); } @@ -143,8 +142,8 @@ public void RetakeVow(EntityUid uid, MimePowersComponent? mimePowers = null) mimePowers.ReadyToRepent = false; mimePowers.VowBroken = false; AddComp<MutedComponent>(uid); - _alertsSystem.ClearAlert(uid, AlertType.VowBroken); - _alertsSystem.ShowAlert(uid, AlertType.VowOfSilence); + _alertsSystem.ClearAlert(uid, mimePowers.VowAlert); + _alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert); _actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid); } } diff --git a/Content.Server/Administration/Managers/AdminManager.cs b/Content.Server/Administration/Managers/AdminManager.cs index ec284fcadce..205024a71e4 100644 --- a/Content.Server/Administration/Managers/AdminManager.cs +++ b/Content.Server/Administration/Managers/AdminManager.cs @@ -7,6 +7,7 @@ using Content.Server.Players; using Content.Shared.Administration; using Content.Shared.CCVar; +using Content.Shared.Info; using Content.Shared.Players; using Robust.Server.Console; using Robust.Server.Player; @@ -233,6 +234,7 @@ public void Initialize() _sawmill = _logManager.GetSawmill("admin"); _netMgr.RegisterNetMessage<MsgUpdateAdminStatus>(); + _netMgr.RegisterNetMessage<ShowRulesPopupMessage>(); // Cache permissions for loaded console commands with the requisite attributes. foreach (var (cmdName, cmd) in _consoleHost.AvailableCommands) diff --git a/Content.Server/Administration/ServerApi.cs b/Content.Server/Administration/ServerApi.cs index 04fd38598fb..d0f23db637b 100644 --- a/Content.Server/Administration/ServerApi.cs +++ b/Content.Server/Administration/ServerApi.cs @@ -8,13 +8,13 @@ using System.Threading.Tasks; using Content.Server.Administration.Systems; using Content.Server.GameTicking; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Presets; using Content.Server.GameTicking.Rules.Components; using Content.Server.Maps; using Content.Server.RoundEnd; using Content.Shared.Administration.Managers; using Content.Shared.CCVar; +using Content.Shared.GameTicking.Components; using Content.Shared.Prototypes; using Robust.Server.ServerStatus; using Robust.Shared.Asynchronous; diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index 4e6af6ceea5..bda60e9449a 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -635,13 +635,13 @@ private void AddSmiteVerbs(GetVerbsEvent<Verb> args) { Text = "Remove gravity", Category = VerbCategory.Smite, - Icon = new SpriteSpecifier.Rsi(new ("/Textures/Structures/Machines/gravity_generator.rsi"), "off"), + Icon = new SpriteSpecifier.Rsi(new("/Textures/Structures/Machines/gravity_generator.rsi"), "off"), Act = () => { var grav = EnsureComp<MovementIgnoreGravityComponent>(args.Target); grav.Weightless = true; - Dirty(grav); + Dirty(args.Target, grav); }, Impact = LogImpact.Extreme, Message = Loc.GetString("admin-smite-remove-gravity-description"), @@ -738,7 +738,7 @@ private void AddSmiteVerbs(GetVerbsEvent<Verb> args) var movementSpeed = EnsureComp<MovementSpeedModifierComponent>(args.Target); (movementSpeed.BaseSprintSpeed, movementSpeed.BaseWalkSpeed) = (movementSpeed.BaseWalkSpeed, movementSpeed.BaseSprintSpeed); - Dirty(movementSpeed); + Dirty(args.Target, movementSpeed); _popupSystem.PopupEntity(Loc.GetString("admin-smite-run-walk-swap-prompt"), args.Target, args.Target, PopupType.LargeCaution); diff --git a/Content.Server/Alert/Commands/ClearAlert.cs b/Content.Server/Alert/Commands/ClearAlert.cs index 1759612702f..929c343b50f 100644 --- a/Content.Server/Alert/Commands/ClearAlert.cs +++ b/Content.Server/Alert/Commands/ClearAlert.cs @@ -9,6 +9,7 @@ namespace Content.Server.Alert.Commands [AdminCommand(AdminFlags.Debug)] public sealed class ClearAlert : IConsoleCommand { + [Dependency] private readonly IEntityManager _e = default!; public string Command => "clearalert"; public string Description => "Clears an alert for a player, defaulting to current player"; public string Help => "clearalert <alertType> <name or userID, omit for current player>"; @@ -37,14 +38,14 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) } var alertType = args[0]; - var alertsSystem = EntitySystem.Get<AlertsSystem>(); - if (!alertsSystem.TryGet(Enum.Parse<AlertType>(alertType), out var alert)) + var alertsSystem = _e.System<AlertsSystem>(); + if (!alertsSystem.TryGet(alertType, out var alert)) { shell.WriteLine("unrecognized alertType " + alertType); return; } - alertsSystem.ClearAlert(attachedEntity, alert.AlertType); + alertsSystem.ClearAlert(attachedEntity, alert.ID); } } } diff --git a/Content.Server/Alert/Commands/ShowAlert.cs b/Content.Server/Alert/Commands/ShowAlert.cs index 11901e9af00..a275dab4fa5 100644 --- a/Content.Server/Alert/Commands/ShowAlert.cs +++ b/Content.Server/Alert/Commands/ShowAlert.cs @@ -9,6 +9,7 @@ namespace Content.Server.Alert.Commands [AdminCommand(AdminFlags.Debug)] public sealed class ShowAlert : IConsoleCommand { + [Dependency] private readonly IEntityManager _e = default!; public string Command => "showalert"; public string Description => "Shows an alert for a player, defaulting to current player"; public string Help => "showalert <alertType> <severity, -1 if no severity> <name or userID, omit for current player>"; @@ -38,8 +39,8 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) var alertType = args[0]; var severity = args[1]; - var alertsSystem = EntitySystem.Get<AlertsSystem>(); - if (!alertsSystem.TryGet(Enum.Parse<AlertType>(alertType), out var alert)) + var alertsSystem = _e.System<AlertsSystem>(); + if (!alertsSystem.TryGet(alertType, out var alert)) { shell.WriteLine("unrecognized alertType " + alertType); return; @@ -51,7 +52,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) } short? severity1 = sevint == -1 ? null : sevint; - alertsSystem.ShowAlert(attachedEntity, alert.AlertType, severity1, null); + alertsSystem.ShowAlert(attachedEntity, alert.ID, severity1, null); } } } diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index cd4d836e683..f5e6de64e53 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -2,7 +2,6 @@ using Content.Server.Antag.Components; using Content.Server.Chat.Managers; using Content.Server.GameTicking; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules; using Content.Server.Ghost.Roles; using Content.Server.Ghost.Roles.Components; @@ -14,6 +13,7 @@ using Content.Server.Station.Systems; using Content.Shared.Antag; using Content.Shared.GameTicking; +using Content.Shared.GameTicking.Components; using Content.Shared.Ghost; using Content.Shared.Humanoid; using Content.Shared.Players; diff --git a/Content.Server/Antag/Components/AntagSelectionComponent.cs b/Content.Server/Antag/Components/AntagSelectionComponent.cs index 096be14049a..5b6699dab76 100644 --- a/Content.Server/Antag/Components/AntagSelectionComponent.cs +++ b/Content.Server/Antag/Components/AntagSelectionComponent.cs @@ -1,6 +1,6 @@ using Content.Server.Administration.Systems; -using Content.Server.Destructible.Thresholds; using Content.Shared.Antag; +using Content.Shared.Destructible.Thresholds; using Content.Shared.Roles; using Content.Shared.Storage; using Content.Shared.Whitelist; diff --git a/Content.Server/Antag/MobReplacementRuleSystem.cs b/Content.Server/Antag/MobReplacementRuleSystem.cs index dc8103497ee..b2ad984884b 100644 --- a/Content.Server/Antag/MobReplacementRuleSystem.cs +++ b/Content.Server/Antag/MobReplacementRuleSystem.cs @@ -1,11 +1,8 @@ using System.Numerics; using Content.Server.Antag.Mimic; -using Content.Server.Chat.Systems; using Content.Server.GameTicking.Rules; -using Content.Server.GameTicking.Components; -using Content.Server.NPC.Systems; -using Content.Server.Station.Systems; -using Content.Server.GameTicking; +using Content.Server.GameTicking.Rules.Components; +using Content.Shared.GameTicking.Components; using Content.Shared.VendingMachines; using Robust.Shared.Map; using Robust.Shared.Prototypes; @@ -23,6 +20,10 @@ using Content.Server.Advertise.Components; using Content.Server.Power.Components; using Content.Shared.CombatMode; +using Content.Server.Station.Systems; +using Content.Server.GameTicking; +using Content.Server.Chat.Systems; +using Content.Server.NPC.Systems; namespace Content.Server.Antag; diff --git a/Content.Server/Atmos/Components/BarotraumaComponent.cs b/Content.Server/Atmos/Components/BarotraumaComponent.cs index 4e29699872e..d261c5ab030 100644 --- a/Content.Server/Atmos/Components/BarotraumaComponent.cs +++ b/Content.Server/Atmos/Components/BarotraumaComponent.cs @@ -1,5 +1,7 @@ +using Content.Shared.Alert; using Content.Shared.Damage; using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; namespace Content.Server.Atmos.Components { @@ -46,5 +48,13 @@ public sealed partial class BarotraumaComponent : Component [ViewVariables(VVAccess.ReadWrite)] public bool HasImmunity = false; + [DataField] + public ProtoId<AlertPrototype> HighPressureAlert = "HighPressure"; + + [DataField] + public ProtoId<AlertPrototype> LowPressureAlert = "LowPressure"; + + [DataField] + public ProtoId<AlertCategoryPrototype> PressureAlertCategory = "Pressure"; } } diff --git a/Content.Server/Atmos/Components/FlammableComponent.cs b/Content.Server/Atmos/Components/FlammableComponent.cs index 9f39af540dd..e1c7974307b 100644 --- a/Content.Server/Atmos/Components/FlammableComponent.cs +++ b/Content.Server/Atmos/Components/FlammableComponent.cs @@ -1,5 +1,7 @@ +using Content.Shared.Alert; using Content.Shared.Damage; using Robust.Shared.Physics.Collision.Shapes; +using Robust.Shared.Prototypes; namespace Content.Server.Atmos.Components { @@ -83,5 +85,7 @@ public sealed partial class FlammableComponent : Component /// </summary> [DataField] public float FireStackIncreaseMultiplier = 1f; + [DataField] + public ProtoId<AlertPrototype> FireAlert = "Fire"; } } diff --git a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs index 35f5ec8a3bc..6bf76221c11 100644 --- a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs +++ b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs @@ -241,7 +241,7 @@ public override void Update(float frameTime) _adminLogger.Add(LogType.Barotrauma, $"{ToPrettyString(uid):entity} started taking low pressure damage"); } RaiseLocalEvent(uid, new MoodEffectEvent("MobLowPressure")); - _alertsSystem.ShowAlert(uid, AlertType.LowPressure, 2); + _alertsSystem.ShowAlert(uid, barotrauma.LowPressureAlert, 2); } else if (pressure >= Atmospherics.HazardHighPressure) { @@ -255,7 +255,8 @@ public override void Update(float frameTime) barotrauma.TakingDamage = true; _adminLogger.Add(LogType.Barotrauma, $"{ToPrettyString(uid):entity} started taking high pressure damage"); } - _alertsSystem.ShowAlert(uid, AlertType.HighPressure, 2); + + _alertsSystem.ShowAlert(uid, barotrauma.HighPressureAlert, 2); } else { @@ -269,13 +270,13 @@ public override void Update(float frameTime) switch (pressure) { case <= Atmospherics.WarningLowPressure: - _alertsSystem.ShowAlert(uid, AlertType.LowPressure, 1); + _alertsSystem.ShowAlert(uid, barotrauma.LowPressureAlert, 1); break; case >= Atmospherics.WarningHighPressure: - _alertsSystem.ShowAlert(uid, AlertType.HighPressure, 1); + _alertsSystem.ShowAlert(uid, barotrauma.HighPressureAlert, 1); break; default: - _alertsSystem.ClearAlertCategory(uid, AlertCategory.Pressure); + _alertsSystem.ClearAlertCategory(uid, barotrauma.PressureAlertCategory); break; } } diff --git a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs index ec0e7b07092..cf6287d7001 100644 --- a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs +++ b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs @@ -423,12 +423,12 @@ public override void Update(float frameTime) if (!flammable.OnFire) { - _alertsSystem.ClearAlert(uid, AlertType.Fire); + _alertsSystem.ClearAlert(uid, flammable.FireAlert); RaiseLocalEvent(uid, new MoodRemoveEffectEvent("OnFire")); continue; } - _alertsSystem.ShowAlert(uid, AlertType.Fire); + _alertsSystem.ShowAlert(uid, flammable.FireAlert); RaiseLocalEvent(uid, new MoodEffectEvent("OnFire")); if (flammable.FireStacks > 0) diff --git a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs index 65977f8c140..b42f3626293 100644 --- a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs @@ -93,7 +93,7 @@ private void ActivateAnalyzer(EntityUid uid, GasAnalyzerComponent component, Ent else component.LastPosition = null; component.Enabled = true; - Dirty(component); + Dirty(uid, component); UpdateAppearance(uid, component); EnsureComp<ActiveGasAnalyzerComponent>(uid); UpdateAnalyzer(uid, component); @@ -105,7 +105,7 @@ private void ActivateAnalyzer(EntityUid uid, GasAnalyzerComponent component, Ent /// </summary> private void OnDropped(EntityUid uid, GasAnalyzerComponent component, DroppedEvent args) { - if(args.User is var userId && component.Enabled) + if (args.User is var userId && component.Enabled) _popup.PopupEntity(Loc.GetString("gas-analyzer-shutoff"), userId, userId); DisableAnalyzer(uid, component, args.User); } @@ -121,7 +121,7 @@ private void DisableAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nu _userInterface.CloseUi(uid, GasAnalyzerUiKey.Key, user); component.Enabled = false; - Dirty(component); + Dirty(uid, component); UpdateAppearance(uid, component); RemCompDeferred<ActiveGasAnalyzerComponent>(uid); } diff --git a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs index c46701a6a07..89b9c520787 100644 --- a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -122,10 +122,11 @@ private void OnPvsToggle(bool value) } // PVS was turned off, ensure data gets sent to all clients. - foreach (var (grid, meta) in EntityQuery<GasTileOverlayComponent, MetaDataComponent>(true)) + var query = EntityQueryEnumerator<GasTileOverlayComponent, MetaDataComponent>(); + while (query.MoveNext(out var uid, out var grid, out var meta)) { grid.ForceTick = _gameTiming.CurTick; - Dirty(grid, meta); + Dirty(uid, grid, meta); } } @@ -268,9 +269,10 @@ private bool UpdateChunkTile(GridAtmosphereComponent gridAtmosphere, GasOverlayC private void UpdateOverlayData() { // TODO parallelize? - foreach (var (overlay, gam, meta) in EntityQuery<GasTileOverlayComponent, GridAtmosphereComponent, MetaDataComponent>(true)) + var query = EntityQueryEnumerator<GasTileOverlayComponent, GridAtmosphereComponent, MetaDataComponent>(); + while (query.MoveNext(out var uid, out var overlay, out var gam, out var meta)) { - bool changed = false; + var changed = false; foreach (var index in overlay.InvalidTiles) { var chunkIndex = GetGasChunkIndices(index); @@ -282,7 +284,7 @@ private void UpdateOverlayData() } if (changed) - Dirty(overlay, meta); + Dirty(uid, overlay, meta); overlay.InvalidTiles.Clear(); } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs index 7cb8102a388..bf973e34c8e 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs @@ -17,6 +17,7 @@ public sealed class GasPortableSystem : EntitySystem { [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly NodeContainerSystem _nodeContainer = default!; + [Dependency] private readonly SharedMapSystem _sharedMapSystem = default!; public override void Initialize() { @@ -33,7 +34,7 @@ private void OnPortableAnchorAttempt(EntityUid uid, GasPortableComponent compone return; // If we can't find any ports, cancel the anchoring. - if(!FindGasPortIn(transform.GridUid, transform.Coordinates, out _)) + if (!FindGasPortIn(transform.GridUid, transform.Coordinates, out _)) args.Cancel(); } @@ -54,10 +55,13 @@ public bool FindGasPortIn(EntityUid? gridId, EntityCoordinates coordinates, [Not { port = null; + if (gridId == null) + return false; + if (!TryComp<MapGridComponent>(gridId, out var grid)) return false; - foreach (var entityUid in grid.GetLocal(coordinates)) + foreach (var entityUid in _sharedMapSystem.GetLocal((EntityUid) gridId, grid, coordinates)) { if (EntityManager.TryGetComponent(entityUid, out port)) { diff --git a/Content.Server/BarSign/Systems/BarSignSystem.cs b/Content.Server/BarSign/Systems/BarSignSystem.cs index 4a481408452..e42394f5a30 100644 --- a/Content.Server/BarSign/Systems/BarSignSystem.cs +++ b/Content.Server/BarSign/Systems/BarSignSystem.cs @@ -34,7 +34,7 @@ private void OnMapInit(EntityUid uid, BarSignComponent component, MapInitEvent a _metaData.SetEntityDescription(uid, Loc.GetString(newPrototype.Description), meta); component.Current = newPrototype.ID; - Dirty(component); + Dirty(uid, component); } } } diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs index 976ef5139c3..089ce322366 100644 --- a/Content.Server/Bed/BedSystem.cs +++ b/Content.Server/Bed/BedSystem.cs @@ -15,6 +15,7 @@ using Content.Shared.Mobs.Systems; using Robust.Shared.Timing; using Content.Shared.Silicon.Components; // I shouldn't have to modify this. +using Robust.Shared.Utility; namespace Content.Server.Bed { @@ -30,27 +31,31 @@ public sealed class BedSystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent<HealOnBuckleComponent, BuckleChangeEvent>(ManageUpdateList); - SubscribeLocalEvent<StasisBedComponent, BuckleChangeEvent>(OnBuckleChange); + SubscribeLocalEvent<HealOnBuckleComponent, StrappedEvent>(OnStrapped); + SubscribeLocalEvent<HealOnBuckleComponent, UnstrappedEvent>(OnUnstrapped); + SubscribeLocalEvent<StasisBedComponent, StrappedEvent>(OnStasisStrapped); + SubscribeLocalEvent<StasisBedComponent, UnstrappedEvent>(OnStasisUnstrapped); SubscribeLocalEvent<StasisBedComponent, PowerChangedEvent>(OnPowerChanged); SubscribeLocalEvent<StasisBedComponent, GotEmaggedEvent>(OnEmagged); SubscribeLocalEvent<StasisBedComponent, RefreshPartsEvent>(OnRefreshParts); SubscribeLocalEvent<StasisBedComponent, UpgradeExamineEvent>(OnUpgradeExamine); } - private void ManageUpdateList(EntityUid uid, HealOnBuckleComponent component, ref BuckleChangeEvent args) + private void OnStrapped(Entity<HealOnBuckleComponent> bed, ref StrappedEvent args) { - if (args.Buckling) - { - AddComp<HealOnBuckleHealingComponent>(uid); - component.NextHealTime = _timing.CurTime + TimeSpan.FromSeconds(component.HealTime); - _actionsSystem.AddAction(args.BuckledEntity, ref component.SleepAction, SleepingSystem.SleepActionId, uid); - return; - } + EnsureComp<HealOnBuckleHealingComponent>(bed); + bed.Comp.NextHealTime = _timing.CurTime + TimeSpan.FromSeconds(bed.Comp.HealTime); + _actionsSystem.AddAction(args.Buckle, ref bed.Comp.SleepAction, SleepingSystem.SleepActionId, bed); - _actionsSystem.RemoveAction(args.BuckledEntity, component.SleepAction); - _sleepingSystem.TryWaking(args.BuckledEntity); - RemComp<HealOnBuckleHealingComponent>(uid); + // Single action entity, cannot strap multiple entities to the same bed. + DebugTools.AssertEqual(args.Strap.Comp.BuckledEntities.Count, 1); + } + + private void OnUnstrapped(Entity<HealOnBuckleComponent> bed, ref UnstrappedEvent args) + { + _actionsSystem.RemoveAction(args.Buckle, bed.Comp.SleepAction); + _sleepingSystem.TryWaking(args.Buckle.Owner); + RemComp<HealOnBuckleHealingComponent>(bed); } public override void Update(float frameTime) @@ -89,18 +94,22 @@ private void UpdateAppearance(EntityUid uid, bool isOn) _appearance.SetData(uid, StasisBedVisuals.IsOn, isOn); } - private void OnBuckleChange(EntityUid uid, StasisBedComponent component, ref BuckleChangeEvent args) + private void OnStasisStrapped(Entity<StasisBedComponent> bed, ref StrappedEvent args) { - // In testing this also received an unbuckle event when the bed is destroyed - // So don't worry about that - if (!HasComp<BodyComponent>(args.BuckledEntity)) + if (!HasComp<BodyComponent>(args.Buckle) || !this.IsPowered(bed, EntityManager)) return; - if (!this.IsPowered(uid, EntityManager)) + var metabolicEvent = new ApplyMetabolicMultiplierEvent(args.Buckle, bed.Comp.Multiplier, true); + RaiseLocalEvent(args.Buckle, ref metabolicEvent); + } + + private void OnStasisUnstrapped(Entity<StasisBedComponent> bed, ref UnstrappedEvent args) + { + if (!HasComp<BodyComponent>(args.Buckle) || !this.IsPowered(bed, EntityManager)) return; - var metabolicEvent = new ApplyMetabolicMultiplierEvent(args.BuckledEntity, component.Multiplier, args.Buckling); - RaiseLocalEvent(args.BuckledEntity, ref metabolicEvent); + var metabolicEvent = new ApplyMetabolicMultiplierEvent(args.Buckle, bed.Comp.Multiplier, false); + RaiseLocalEvent(args.Buckle, ref metabolicEvent); } private void OnPowerChanged(EntityUid uid, StasisBedComponent component, ref PowerChangedEvent args) diff --git a/Content.Server/Bed/Components/HealOnBuckleComponent.cs b/Content.Server/Bed/Components/HealOnBuckleComponent.cs index f29fe30429f..3c6f3a4382b 100644 --- a/Content.Server/Bed/Components/HealOnBuckleComponent.cs +++ b/Content.Server/Bed/Components/HealOnBuckleComponent.cs @@ -5,19 +5,26 @@ namespace Content.Server.Bed.Components [RegisterComponent] public sealed partial class HealOnBuckleComponent : Component { - [DataField("damage", required: true)] - [ViewVariables(VVAccess.ReadWrite)] + /// <summary> + /// Damage to apply to entities that are strapped to this entity. + /// </summary> + [DataField(required: true)] public DamageSpecifier Damage = default!; - [DataField("healTime", required: false)] - [ViewVariables(VVAccess.ReadWrite)] - public float HealTime = 1f; // How often the bed applies the damage + /// <summary> + /// How frequently the damage should be applied, in seconds. + /// </summary> + [DataField(required: false)] + public float HealTime = 1f; - [DataField("sleepMultiplier")] + /// <summary> + /// Damage multiplier that gets applied if the entity is sleeping. + /// </summary> + [DataField] public float SleepMultiplier = 3f; public TimeSpan NextHealTime = TimeSpan.Zero; //Next heal - [DataField("sleepAction")] public EntityUid? SleepAction; + [DataField] public EntityUid? SleepAction; } } diff --git a/Content.Server/Bed/Components/HealOnBuckleHealing.cs b/Content.Server/Bed/Components/HealOnBuckleHealing.cs index a944e67e12d..aaa82c737c5 100644 --- a/Content.Server/Bed/Components/HealOnBuckleHealing.cs +++ b/Content.Server/Bed/Components/HealOnBuckleHealing.cs @@ -1,5 +1,6 @@ namespace Content.Server.Bed.Components { + // TODO rename this component [RegisterComponent] public sealed partial class HealOnBuckleHealingComponent : Component {} diff --git a/Content.Server/Bed/Components/StasisBedComponent.cs b/Content.Server/Bed/Components/StasisBedComponent.cs index bb4096a2a5e..6e0042b2df8 100644 --- a/Content.Server/Bed/Components/StasisBedComponent.cs +++ b/Content.Server/Bed/Components/StasisBedComponent.cs @@ -12,7 +12,8 @@ public sealed partial class StasisBedComponent : Component /// <summary> /// What the metabolic update rate will be multiplied by (higher = slower metabolism) /// </summary> - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables(VVAccess.ReadOnly)] // Writing is is not supported. ApplyMetabolicMultiplierEvent needs to be refactored first + [DataField] public float Multiplier = 10f; [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<MachinePartPrototype>))] diff --git a/Content.Server/Body/Components/BloodstreamComponent.cs b/Content.Server/Body/Components/BloodstreamComponent.cs index f7024a63951..ee0de4aa4dc 100644 --- a/Content.Server/Body/Components/BloodstreamComponent.cs +++ b/Content.Server/Body/Components/BloodstreamComponent.cs @@ -2,6 +2,7 @@ using Content.Server.Chemistry.EntitySystems; using Content.Server.Traits; using Content.Server.Traits.Assorted; +using Content.Shared.Alert; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.Damage; @@ -181,5 +182,8 @@ public sealed partial class BloodstreamComponent : Component /// </summary> [ViewVariables(VVAccess.ReadWrite)] public TimeSpan StatusTime; + + [DataField] + public ProtoId<AlertPrototype> BleedingAlert = "Bleed"; } } diff --git a/Content.Server/Body/Components/InternalsComponent.cs b/Content.Server/Body/Components/InternalsComponent.cs index 18caab8dcf0..098f1789218 100644 --- a/Content.Server/Body/Components/InternalsComponent.cs +++ b/Content.Server/Body/Components/InternalsComponent.cs @@ -1,3 +1,6 @@ +using Content.Shared.Alert; +using Robust.Shared.Prototypes; + namespace Content.Server.Body.Components { /// <summary> @@ -18,5 +21,8 @@ public sealed partial class InternalsComponent : Component [ViewVariables(VVAccess.ReadWrite)] [DataField] public TimeSpan Delay = TimeSpan.FromSeconds(3); + + [DataField] + public ProtoId<AlertPrototype> InternalsAlert = "Internals"; } } diff --git a/Content.Server/Body/Components/LungComponent.cs b/Content.Server/Body/Components/LungComponent.cs index 46600b30207..72af4d9e63a 100644 --- a/Content.Server/Body/Components/LungComponent.cs +++ b/Content.Server/Body/Components/LungComponent.cs @@ -1,8 +1,8 @@ -using Content.Server.Atmos; using Content.Server.Body.Systems; using Content.Shared.Alert; using Content.Shared.Atmos; using Content.Shared.Chemistry.Components; +using Robust.Shared.Prototypes; namespace Content.Server.Body.Components; @@ -33,5 +33,5 @@ public sealed partial class LungComponent : Component /// The type of gas this lung needs. Used only for the breathing alerts, not actual metabolism. /// </summary> [DataField] - public AlertType Alert = AlertType.LowOxygen; + public ProtoId<AlertPrototype> Alert = "LowOxygen"; } diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs index d1fad6541ba..095018f9b9a 100644 --- a/Content.Server/Body/Systems/BloodstreamSystem.cs +++ b/Content.Server/Body/Systems/BloodstreamSystem.cs @@ -280,6 +280,9 @@ private void OnApplyMetabolicMultiplier( Entity<BloodstreamComponent> ent, ref ApplyMetabolicMultiplierEvent args) { + // TODO REFACTOR THIS + // This will slowly drift over time due to floating point errors. + // Instead, raise an event with the base rates and allow modifiers to get applied to it. if (args.Apply) { ent.Comp.UpdateInterval *= args.Multiplier; @@ -412,11 +415,11 @@ public bool TryModifyBleedAmount(EntityUid uid, float amount, BloodstreamCompone component.BleedAmount = Math.Clamp(component.BleedAmount, 0, component.MaxBleedAmount); if (component.BleedAmount == 0) - _alertsSystem.ClearAlert(uid, AlertType.Bleed); + _alertsSystem.ClearAlert(uid, component.BleedingAlert); else { var severity = (short) Math.Clamp(Math.Round(component.BleedAmount, MidpointRounding.ToZero), 0, 10); - _alertsSystem.ShowAlert(uid, AlertType.Bleed, severity); + _alertsSystem.ShowAlert(uid, component.BleedingAlert, severity); } return true; diff --git a/Content.Server/Body/Systems/InternalsSystem.cs b/Content.Server/Body/Systems/InternalsSystem.cs index db078e2f291..fdcc76718cf 100644 --- a/Content.Server/Body/Systems/InternalsSystem.cs +++ b/Content.Server/Body/Systems/InternalsSystem.cs @@ -145,12 +145,12 @@ private void OnDoAfter(Entity<InternalsComponent> ent, ref InternalsDoAfterEvent private void OnInternalsStartup(Entity<InternalsComponent> ent, ref ComponentStartup args) { - _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); + _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent)); } private void OnInternalsShutdown(Entity<InternalsComponent> ent, ref ComponentShutdown args) { - _alerts.ClearAlert(ent, AlertType.Internals); + _alerts.ClearAlert(ent, ent.Comp.InternalsAlert); } private void OnInhaleLocation(Entity<InternalsComponent> ent, ref InhaleLocationEvent args) @@ -160,7 +160,7 @@ private void OnInhaleLocation(Entity<InternalsComponent> ent, ref InhaleLocation var gasTank = Comp<GasTankComponent>(ent.Comp.GasTankEntity!.Value); args.Gas = _gasTank.RemoveAirVolume((ent.Comp.GasTankEntity.Value, gasTank), Atmospherics.BreathVolume); // TODO: Should listen to gas tank updates instead I guess? - _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); + _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent)); } } public void DisconnectBreathTool(Entity<InternalsComponent> ent) @@ -174,7 +174,7 @@ public void DisconnectBreathTool(Entity<InternalsComponent> ent) DisconnectTank(ent); } - _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); + _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent)); } public void ConnectBreathTool(Entity<InternalsComponent> ent, EntityUid toolEntity) @@ -185,7 +185,7 @@ public void ConnectBreathTool(Entity<InternalsComponent> ent, EntityUid toolEnti } ent.Comp.BreathToolEntity = toolEntity; - _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); + _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent)); } public void DisconnectTank(InternalsComponent? component) @@ -197,7 +197,7 @@ public void DisconnectTank(InternalsComponent? component) _gasTank.DisconnectFromInternals((component.GasTankEntity.Value, tank)); component.GasTankEntity = null; - _alerts.ShowAlert(component.Owner, AlertType.Internals, GetSeverity(component)); + _alerts.ShowAlert(component.Owner, component.InternalsAlert, GetSeverity(component)); } public bool TryConnectTank(Entity<InternalsComponent> ent, EntityUid tankEntity) @@ -209,7 +209,7 @@ public bool TryConnectTank(Entity<InternalsComponent> ent, EntityUid tankEntity) _gasTank.DisconnectFromInternals((ent.Comp.GasTankEntity.Value, tank)); ent.Comp.GasTankEntity = tankEntity; - _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); + _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent)); return true; } diff --git a/Content.Server/Body/Systems/MetabolizerSystem.cs b/Content.Server/Body/Systems/MetabolizerSystem.cs index 066bf0a1c5b..a7eec8e3c02 100644 --- a/Content.Server/Body/Systems/MetabolizerSystem.cs +++ b/Content.Server/Body/Systems/MetabolizerSystem.cs @@ -67,6 +67,9 @@ private void OnApplyMetabolicMultiplier( Entity<MetabolizerComponent> ent, ref ApplyMetabolicMultiplierEvent args) { + // TODO REFACTOR THIS + // This will slowly drift over time due to floating point errors. + // Instead, raise an event with the base rates and allow modifiers to get applied to it. if (args.Apply) { ent.Comp.UpdateInterval *= args.Multiplier; @@ -232,6 +235,9 @@ private void TryMetabolize(Entity<MetabolizerComponent, OrganComponent?, Solutio } } + // TODO REFACTOR THIS + // This will cause rates to slowly drift over time due to floating point errors. + // Instead, the system that raised this should trigger an update and subscribe to get-modifier events. [ByRefEvent] public readonly record struct ApplyMetabolicMultiplierEvent( EntityUid Uid, diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index 8b2b19a2ac0..4b669009f59 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -218,6 +218,9 @@ private void OnApplyMetabolicMultiplier( Entity<RespiratorComponent> ent, ref ApplyMetabolicMultiplierEvent args) { + // TODO REFACTOR THIS + // This will slowly drift over time due to floating point errors. + // Instead, raise an event with the base rates and allow modifiers to get applied to it. if (args.Apply) { ent.Comp.UpdateInterval *= args.Multiplier; diff --git a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs index 1c5c7ed1c0d..1480c28bf22 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs @@ -20,6 +20,7 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Utility; using Robust.Shared.Configuration; +using Robust.Shared.Map.Components; namespace Content.Server.Cargo.Systems; @@ -91,14 +92,7 @@ private void UpdatePalletConsoleInterface(EntityUid uid) } private void OnPalletUIOpen(EntityUid uid, CargoPalletConsoleComponent component, BoundUIOpenedEvent args) - { - var player = args.Actor; - - if (player == null) - return; - - UpdatePalletConsoleInterface(uid); - } + => UpdatePalletConsoleInterface(uid); /// <summary> /// Ok so this is just the same thing as opening the UI, its a refresh button. @@ -109,20 +103,10 @@ private void OnPalletUIOpen(EntityUid uid, CargoPalletConsoleComponent component /// </summary> private void OnPalletAppraise(EntityUid uid, CargoPalletConsoleComponent component, CargoPalletAppraiseMessage args) - { - var player = args.Actor; - - if (player == null) - return; - - UpdatePalletConsoleInterface(uid); - } + => UpdatePalletConsoleInterface(uid); private void OnCargoShuttleConsoleStartup(EntityUid uid, CargoShuttleConsoleComponent component, ComponentStartup args) - { - var station = _station.GetOwningStation(uid); - UpdateShuttleState(uid, station); - } + => UpdateShuttleState(uid, _station.GetOwningStation(uid)); private void UpdateShuttleState(EntityUid uid, EntityUid? station = null) { @@ -339,10 +323,6 @@ private bool CanSell(EntityUid uid, TransformComponent xform) private void OnPalletSale(EntityUid uid, CargoPalletConsoleComponent component, CargoPalletSellMessage args) { var player = args.Actor; - - if (player == null) - return; - var xform = Transform(uid); if (xform.GridUid is not EntityUid gridUid) @@ -380,7 +360,7 @@ private void OnStationInitialize(StationInitializedEvent args) private void CleanupTradeStation() { - if (CargoMap == null || !_mapManager.MapExists(CargoMap.Value)) + if (CargoMap == null || !_sharedMapSystem.MapExists(CargoMap.Value)) { CargoMap = null; DebugTools.Assert(!EntityQuery<CargoShuttleComponent>().Any()); @@ -393,13 +373,14 @@ private void CleanupTradeStation() private void SetupTradePost() { - if (CargoMap != null && _mapManager.MapExists(CargoMap.Value)) + if (CargoMap != null && _sharedMapSystem.MapExists(CargoMap.Value)) { return; } // It gets mapinit which is okay... buuutt we still want it paused to avoid power draining. - CargoMap = _mapManager.CreateMap(); + var mapEntId = _mapSystem.CreateMap(); + CargoMap = _entityManager.GetComponent<MapComponent>(mapEntId).MapId; var options = new MapLoadOptions { @@ -420,11 +401,12 @@ private void SetupTradePost() var shuttleComponent = EnsureComp<ShuttleComponent>(grid); shuttleComponent.AngularDamping = 10000; shuttleComponent.LinearDamping = 10000; - Dirty(shuttleComponent); + Dirty(grid, shuttleComponent); } - var mapUid = _mapManager.GetMapEntityId(CargoMap.Value); - var ftl = EnsureComp<FTLDestinationComponent>(_mapManager.GetMapEntityId(CargoMap.Value)); + var mapUid = _sharedMapSystem.GetMap(CargoMap.Value); + var ftl = EnsureComp<FTLDestinationComponent>(mapUid); + ftl.Whitelist = new EntityWhitelist() { Components = diff --git a/Content.Server/Cargo/Systems/CargoSystem.cs b/Content.Server/Cargo/Systems/CargoSystem.cs index e593299321e..16597fa1bcd 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.cs @@ -47,7 +47,10 @@ public sealed partial class CargoSystem : SharedCargoSystem [Dependency] private readonly MetaDataSystem _metaSystem = default!; [Dependency] private readonly RadioSystem _radio = default!; [Dependency] private readonly IConfigurationManager _cfgManager = default!; + [Dependency] private readonly SharedMapSystem _sharedMapSystem = default!; + [Dependency] private readonly MapSystem _mapSystem = default!; [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly MapLoaderSystem _mapLoader = default!; diff --git a/Content.Server/Carrying/CarryingSystem.cs b/Content.Server/Carrying/CarryingSystem.cs index 857c3861a74..ca69d2f9299 100644 --- a/Content.Server/Carrying/CarryingSystem.cs +++ b/Content.Server/Carrying/CarryingSystem.cs @@ -67,7 +67,7 @@ public override void Initialize() SubscribeLocalEvent<BeingCarriedComponent, GettingInteractedWithAttemptEvent>(OnInteractedWith); SubscribeLocalEvent<BeingCarriedComponent, PullAttemptEvent>(OnPullAttempt); SubscribeLocalEvent<BeingCarriedComponent, StartClimbEvent>(OnStartClimb); - SubscribeLocalEvent<BeingCarriedComponent, BuckleChangeEvent>(OnBuckleChange); + SubscribeLocalEvent<BeingCarriedComponent, BuckledEvent>(OnBuckled); SubscribeLocalEvent<CarriableComponent, CarryDoAfterEvent>(OnDoAfter); } @@ -215,7 +215,7 @@ private void OnStartClimb(EntityUid uid, BeingCarriedComponent component, ref St DropCarried(component.Carrier, uid); } - private void OnBuckleChange(EntityUid uid, BeingCarriedComponent component, ref BuckleChangeEvent args) + private void OnBuckled(EntityUid uid, BeingCarriedComponent component, ref BuckledEvent args) { DropCarried(component.Carrier, uid); } diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index bbca6f4d153..5ba5845f087 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -43,7 +43,7 @@ namespace Content.Server.Chat.Systems; // Dear contributor. When I was introducing changes to this system only god and I knew what I was doing. // Now only god knows. Please don't touch this code ever again. If you do have to, increment this counter as a warning for others: -// TOTAL_HOURS_WASTED_HERE_EE = 18 +// TOTAL_HOURS_WASTED_HERE_EE = 19 // TODO refactor whatever active warzone this class and chatmanager have become /// <summary> @@ -343,7 +343,7 @@ public void DispatchGlobalAnnouncement( _chatManager.ChatMessageToAll(ChatChannel.Radio, message, wrappedMessage, default, false, true, colorOverride); if (playSound) { - _audio.PlayGlobal(announcementSound?.GetSound() ?? DefaultAnnouncementSound, Filter.Broadcast(), true, AudioParams.Default.WithVolume(-2f)); + _audio.PlayGlobal(announcementSound != null ? announcementSound.ToString() : DefaultAnnouncementSound, Filter.Broadcast(), true, AudioParams.Default.WithVolume(-2f)); } _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Global station announcement from {sender}: {message}"); } @@ -381,7 +381,7 @@ public void DispatchStationAnnouncement( if (playDefaultSound) { - _audio.PlayGlobal(announcementSound?.GetSound() ?? DefaultAnnouncementSound, filter, true, AudioParams.Default.WithVolume(-2f)); + _audio.PlayGlobal(announcementSound != null ? announcementSound.ToString() : DefaultAnnouncementSound, filter, true, AudioParams.Default.WithVolume(-2f)); } _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Station Announcement on {station} from {sender}: {message}"); diff --git a/Content.Server/Chat/TelepathicChatSystem.cs b/Content.Server/Chat/TelepathicChatSystem.cs index b1338035adb..e0844b3eee2 100644 --- a/Content.Server/Chat/TelepathicChatSystem.cs +++ b/Content.Server/Chat/TelepathicChatSystem.cs @@ -52,20 +52,22 @@ public override void Initialize() private IEnumerable<INetChannel> GetAdminClients() { return _adminManager.ActiveAdmins - .Select(p => p.ConnectedClient); + .Select(p => p.Channel); } private List<INetChannel> GetDreamers(IEnumerable<INetChannel> removeList) { + var filteredList = new List<INetChannel>(); var filtered = Filter.Empty() .AddWhereAttachedEntity(entity => HasComp<PsionicComponent>(entity) && !HasComp<TelepathyComponent>(entity) || HasComp<SleepingComponent>(entity) || HasComp<SeeingRainbowsComponent>(entity) && !HasComp<PsionicsDisabledComponent>(entity) && !HasComp<PsionicInsulationComponent>(entity)) .Recipients - .Select(p => p.ConnectedClient); + .Select(p => p.Channel); - var filteredList = filtered.ToList(); + if (filtered.ToList() != null) + filteredList = filtered.ToList(); foreach (var entity in removeList) filteredList.Remove(entity); @@ -134,7 +136,7 @@ private string ObfuscateMessageReadability(string message, float chance) for (var i = 0; i < message.Length; i++) { - if (char.IsWhiteSpace((modifiedMessage[i]))) + if (char.IsWhiteSpace(modifiedMessage[i])) { continue; } diff --git a/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs b/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs index 8d475570ad0..40858176bd1 100644 --- a/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs +++ b/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs @@ -10,8 +10,8 @@ public sealed partial class AdjustAlert : ReagentEffect /// <summary> /// The specific Alert that will be adjusted /// </summary> - [DataField("alertType", required: true)] - public AlertType Type; + [DataField(required: true)] + public ProtoId<AlertPrototype> AlertType; /// <summary> /// If true, the alert is removed after Time seconds. If Time was not specified the alert is removed immediately. @@ -42,7 +42,7 @@ public override void Effect(ReagentEffectArgs args) if (Clear && Time <= 0) { - alertSys.ClearAlert(args.SolutionEntity, Type); + alertSys.ClearAlert(args.SolutionEntity, AlertType); } else { @@ -52,7 +52,7 @@ public override void Effect(ReagentEffectArgs args) if ((ShowCooldown || Clear) && Time > 0) cooldown = (timing.CurTime, timing.CurTime + TimeSpan.FromSeconds(Time)); - alertSys.ShowAlert(args.SolutionEntity, Type, cooldown: cooldown, autoRemove: Clear, showCooldown: ShowCooldown); + alertSys.ShowAlert(args.SolutionEntity, AlertType, cooldown: cooldown, autoRemove: Clear, showCooldown: ShowCooldown); } } diff --git a/Content.Server/Clothing/MagbootsSystem.cs b/Content.Server/Clothing/MagbootsSystem.cs index f12558389e3..3838ad168d1 100644 --- a/Content.Server/Clothing/MagbootsSystem.cs +++ b/Content.Server/Clothing/MagbootsSystem.cs @@ -29,11 +29,11 @@ protected override void UpdateMagbootEffects(EntityUid parent, EntityUid uid, bo if (state) { - _alerts.ShowAlert(parent, AlertType.Magboots); + _alerts.ShowAlert(parent, component.MagbootsAlert); } else { - _alerts.ClearAlert(parent, AlertType.Magboots); + _alerts.ClearAlert(parent, component.MagbootsAlert); } } diff --git a/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs b/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs index e20a6c3da97..feb3428884c 100644 --- a/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs +++ b/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs @@ -39,7 +39,7 @@ private void OnVerb(EntityUid uid, ChameleonClothingComponent component, GetVerb args.Verbs.Add(new InteractionVerb() { Text = Loc.GetString("chameleon-component-verb-text"), - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/settings.svg.192dpi.png")), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/settings.svg.192dpi.png")), Act = () => TryOpenUi(uid, args.User, component) }); } @@ -91,7 +91,7 @@ public void SetSelectedPrototype(EntityUid uid, string? protoId, bool forceUpdat UpdateIdentityBlocker(uid, component, proto); UpdateVisuals(uid, component); UpdateUi(uid, component); - Dirty(component); + Dirty(uid, component); } private void UpdateIdentityBlocker(EntityUid uid, ChameleonClothingComponent component, EntityPrototype proto) diff --git a/Content.Server/Construction/PartExchangerSystem.cs b/Content.Server/Construction/PartExchangerSystem.cs index f364d1b547d..c84d65b75e0 100644 --- a/Content.Server/Construction/PartExchangerSystem.cs +++ b/Content.Server/Construction/PartExchangerSystem.cs @@ -170,7 +170,12 @@ private void OnAfterInteract(EntityUid uid, PartExchangerComponent component, Af return; } - component.AudioStream = _audio.PlayPvs(component.ExchangeSound, uid).Value.Entity; + var audioStream = _audio.PlayPvs(component.ExchangeSound, uid); + + if (audioStream == null) + return; + + component.AudioStream = audioStream!.Value.Entity; _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.ExchangeDuration, new ExchangerDoAfterEvent(), uid, target: args.Target, used: uid) { diff --git a/Content.Server/Database/ServerDbBase.cs b/Content.Server/Database/ServerDbBase.cs index 8286defd117..3b1f97f2635 100644 --- a/Content.Server/Database/ServerDbBase.cs +++ b/Content.Server/Database/ServerDbBase.cs @@ -998,30 +998,6 @@ public async Task RemoveFromWhitelistAsync(NetUserId player) await db.DbContext.SaveChangesAsync(); } - public async Task<DateTimeOffset?> GetLastReadRules(NetUserId player) - { - await using var db = await GetDb(); - - return NormalizeDatabaseTime(await db.DbContext.Player - .Where(dbPlayer => dbPlayer.UserId == player) - .Select(dbPlayer => dbPlayer.LastReadRules) - .SingleOrDefaultAsync()); - } - - public async Task SetLastReadRules(NetUserId player, DateTimeOffset date) - { - await using var db = await GetDb(); - - var dbPlayer = await db.DbContext.Player.Where(dbPlayer => dbPlayer.UserId == player).SingleOrDefaultAsync(); - if (dbPlayer == null) - { - return; - } - - dbPlayer.LastReadRules = date.UtcDateTime; - await db.DbContext.SaveChangesAsync(); - } - #endregion #region Uploaded Resources Logs diff --git a/Content.Server/Database/ServerDbManager.cs b/Content.Server/Database/ServerDbManager.cs index a9c5e8c43ac..dee6248cc39 100644 --- a/Content.Server/Database/ServerDbManager.cs +++ b/Content.Server/Database/ServerDbManager.cs @@ -252,13 +252,6 @@ Task<int> AddConnectionLogAsync( #endregion - #region Rules - - Task<DateTimeOffset?> GetLastReadRules(NetUserId player); - Task SetLastReadRules(NetUserId player, DateTimeOffset time); - - #endregion - #region Admin Notes Task<int> AddAdminNote(int? roundId, Guid player, TimeSpan playtimeAtNote, string message, NoteSeverity severity, bool secret, Guid createdBy, DateTimeOffset createdAt, DateTimeOffset? expiryTime); @@ -707,18 +700,6 @@ public Task PurgeUploadedResourceLogAsync(int days) return RunDbCommand(() => _db.PurgeUploadedResourceLogAsync(days)); } - public Task<DateTimeOffset?> GetLastReadRules(NetUserId player) - { - DbReadOpsMetric.Inc(); - return RunDbCommand(() => _db.GetLastReadRules(player)); - } - - public Task SetLastReadRules(NetUserId player, DateTimeOffset time) - { - DbWriteOpsMetric.Inc(); - return RunDbCommand(() => _db.SetLastReadRules(player, time)); - } - public Task<int> AddAdminNote(int? roundId, Guid player, TimeSpan playtimeAtNote, string message, NoteSeverity severity, bool secret, Guid createdBy, DateTimeOffset createdAt, DateTimeOffset? expiryTime) { DbWriteOpsMetric.Inc(); diff --git a/Content.Server/Decals/DecalSystem.cs b/Content.Server/Decals/DecalSystem.cs index da95401d206..c8e062ce6ff 100644 --- a/Content.Server/Decals/DecalSystem.cs +++ b/Content.Server/Decals/DecalSystem.cs @@ -89,10 +89,11 @@ private void OnPvsToggle(bool value) playerData.Clear(); } - foreach (var (grid, meta) in EntityQuery<DecalGridComponent, MetaDataComponent>(true)) + var query = EntityQueryEnumerator<DecalGridComponent, MetaDataComponent>(); + while (query.MoveNext(out var uid, out var grid, out var meta)) { grid.ForceTick = _timing.CurTick; - Dirty(grid, meta); + Dirty(uid, grid, meta); } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs index 65851f17360..093f05fceee 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs @@ -1,12 +1,11 @@ using System.Numerics; using Content.Shared.Forensics; using Content.Server.Stack; +using Content.Shared.Destructible.Thresholds; using Content.Shared.Prototypes; using Content.Shared.Stacks; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; -using Content.Server.Administration.Commands; namespace Content.Server.Destructible.Thresholds.Behaviors { @@ -17,8 +16,8 @@ public sealed partial class SpawnEntitiesBehavior : IThresholdBehavior /// <summary> /// Entities spawned on reaching this threshold, from a min to a max. /// </summary> - [DataField("spawn", customTypeSerializer:typeof(PrototypeIdDictionarySerializer<MinMax, EntityPrototype>))] - public Dictionary<string, MinMax> Spawn { get; set; } = new(); + [DataField] + public Dictionary<EntProtoId, MinMax> Spawn = new(); [DataField("offset")] public float Offset { get; set; } = 0.5f; diff --git a/Content.Server/Destructible/Thresholds/MinMax.cs b/Content.Server/Destructible/Thresholds/MinMax.cs deleted file mode 100644 index c44864183ab..00000000000 --- a/Content.Server/Destructible/Thresholds/MinMax.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Robust.Shared.Random; - -namespace Content.Server.Destructible.Thresholds -{ - [Serializable] - [DataDefinition] - public partial struct MinMax - { - [DataField("min")] - public int Min; - - [DataField("max")] - public int Max; - - public MinMax(int min, int max) - { - Min = min; - Max = max; - } - - public int Next(IRobustRandom random) - { - return random.Next(Min, Max + 1); - } - } -} diff --git a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs index dc1bf499df5..34601241585 100644 --- a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs @@ -254,7 +254,7 @@ private void SetMode(EntityUid configuratorUid, NetworkConfiguratorComponent con /// </summary> private void UpdateModeAppearance(EntityUid userUid, EntityUid configuratorUid, NetworkConfiguratorComponent configurator) { - Dirty(configurator); + Dirty(configuratorUid, configurator); _appearanceSystem.SetData(configuratorUid, NetworkConfiguratorVisuals.Mode, configurator.LinkModeActive); var pitch = configurator.LinkModeActive ? 1 : 0.8f; diff --git a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs index f0f6e9142c6..5a800d5c0eb 100644 --- a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs +++ b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs @@ -31,6 +31,9 @@ public sealed class DisposalTubeSystem : EntitySystem [Dependency] private readonly DisposableSystem _disposableSystem = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly AtmosphereSystem _atmosSystem = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; + public override void Initialize() { base.Initialize(); @@ -344,22 +347,18 @@ private void UpdateAnchored(EntityUid uid, DisposalTubeComponent component, bool return null; var position = xform.Coordinates; - foreach (var entity in grid.GetInDir(position, nextDirection)) + var entities = _mapSystem.GetInDir(target, grid, position, nextDirection); + + foreach (var entity in entities) { if (!TryComp(entity, out DisposalTubeComponent? tube)) - { continue; - } if (!CanConnect(entity, tube, oppositeDirection)) - { continue; - } if (!CanConnect(target, targetTube, nextDirection)) - { continue; - } return entity; } @@ -422,7 +421,8 @@ public bool TryInsert(EntityUid uid, DisposalUnitComponent from, IEnumerable<str return false; var xform = Transform(uid); - var holder = Spawn(DisposalEntryComponent.HolderPrototypeId, xform.MapPosition); + var mapCoords = _transformSystem.GetMapCoordinates(xform); + var holder = Spawn(DisposalEntryComponent.HolderPrototypeId, mapCoords); var holderComponent = Comp<DisposalHolderComponent>(holder); foreach (var entity in from.Container.ContainedEntities.ToArray()) diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs index 3e81ebfb79f..3c7636cfd07 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs @@ -54,6 +54,7 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly TransformSystem _transformSystem = default!; + [Dependency] private readonly SharedMapSystem _sharedMapSystem = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; public override void Initialize() @@ -310,7 +311,7 @@ private void OnPowerChange(EntityUid uid, SharedDisposalUnitComponent component, if (!args.Powered) { component.NextFlush = null; - Dirty(component); + Dirty(uid, component); return; } @@ -366,7 +367,7 @@ private void UpdateState(EntityUid uid, DisposalsPressureState state, SharedDisp component.State = state; UpdateVisualState(uid, component); UpdateInterface(uid, component, component.Powered); - Dirty(component, metadata); + Dirty(uid, component, metadata); if (state == DisposalsPressureState.Ready) { @@ -447,7 +448,7 @@ private void Update(EntityUid uid, SharedDisposalUnitComponent component, MetaDa } if (count != component.RecentlyEjected.Count) - Dirty(component, metadata); + Dirty(uid, component, metadata); } public bool TryInsert(EntityUid unitId, EntityUid toInsertId, EntityUid? userId, DisposalUnitComponent? unit = null) @@ -516,7 +517,7 @@ public bool TryFlush(EntityUid uid, SharedDisposalUnitComponent component) return false; var coords = xform.Coordinates; - var entry = grid.GetLocal(coords) + var entry = _sharedMapSystem.GetLocal(uid, grid, coords) .FirstOrDefault(HasComp<DisposalEntryComponent>); if (entry == default || component is not DisposalUnitComponent sDisposals) @@ -754,7 +755,7 @@ public void QueueAutomaticEngage(EntityUid uid, SharedDisposalUnitComponent comp var flushTime = TimeSpan.FromSeconds(Math.Min((component.NextFlush ?? TimeSpan.MaxValue).TotalSeconds, automaticTime.TotalSeconds)); component.NextFlush = flushTime; - Dirty(component); + Dirty(uid, component); } public void AfterInsert(EntityUid uid, SharedDisposalUnitComponent component, EntityUid inserted, EntityUid? user = null, bool doInsert = false) diff --git a/Content.Server/Dragon/DragonRiftSystem.cs b/Content.Server/Dragon/DragonRiftSystem.cs index c0a81d0d24e..b0dd87d3fdb 100644 --- a/Content.Server/Dragon/DragonRiftSystem.cs +++ b/Content.Server/Dragon/DragonRiftSystem.cs @@ -70,7 +70,7 @@ public override void Update(float frameTime) if (comp.State < DragonRiftState.AlmostFinished && comp.Accumulator > comp.MaxAccumulator / 2f) { comp.State = DragonRiftState.AlmostFinished; - Dirty(comp); + Dirty(uid, comp); _announcer.SendAnnouncement(_announcer.GetAnnouncementId("CarpRift"), Filter.Broadcast(), "carp-rift-warning", colorOverride: Color.Red, localeArgs: ("location", FormattedMessage.RemoveMarkupPermissive(_navMap.GetNearestBeaconString((uid, xform))))); diff --git a/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs b/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs index 202d03bcda9..5117d67e944 100644 --- a/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs +++ b/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs @@ -93,7 +93,7 @@ public void TryEnsnare(EntityUid target, EntityUid ensnare, EnsnaringComponent c component.Ensnared = target; _container.Insert(ensnare, ensnareable.Container); ensnareable.IsEnsnared = true; - Dirty(ensnareable); + Dirty(target, ensnareable); UpdateAlert(target, ensnareable); var ev = new EnsnareEvent(component.WalkSpeed, component.SprintSpeed); @@ -107,7 +107,7 @@ public void TryEnsnare(EntityUid target, EntityUid ensnare, EnsnaringComponent c /// <param name="user">The entity that is freeing the target</param> /// <param name="ensnare">The entity used to ensnare</param> /// <param name="component">The ensnaring component</param> - public void TryFree(EntityUid target, EntityUid user, EntityUid ensnare, EnsnaringComponent component) + public void TryFree(EntityUid target, EntityUid user, EntityUid ensnare, EnsnaringComponent component) { //Don't do anything if they don't have the ensnareable component. if (!HasComp<EnsnareableComponent>(target)) @@ -149,7 +149,7 @@ public void ForceFree(EntityUid ensnare, EnsnaringComponent component) _container.Remove(ensnare, ensnareable.Container, force: true); ensnareable.IsEnsnared = ensnareable.Container.ContainedEntities.Count > 0; - Dirty(ensnareable); + Dirty(component.Ensnared.Value, ensnareable); component.Ensnared = null; UpdateAlert(target, ensnareable); @@ -164,8 +164,8 @@ public void ForceFree(EntityUid ensnare, EnsnaringComponent component) public void UpdateAlert(EntityUid target, EnsnareableComponent component) { if (!component.IsEnsnared) - _alerts.ClearAlert(target, AlertType.Ensnared); + _alerts.ClearAlert(target, component.EnsnaredAlert); else - _alerts.ShowAlert(target, AlertType.Ensnared); + _alerts.ShowAlert(target, component.EnsnaredAlert); } } diff --git a/Content.Server/Ensnaring/EnsnareableSystem.cs b/Content.Server/Ensnaring/EnsnareableSystem.cs index 7b810b4f49c..0cf4efa21b2 100644 --- a/Content.Server/Ensnaring/EnsnareableSystem.cs +++ b/Content.Server/Ensnaring/EnsnareableSystem.cs @@ -45,7 +45,7 @@ private void OnDoAfter(EntityUid uid, EnsnareableComponent component, DoAfterEve } component.IsEnsnared = component.Container.ContainedEntities.Count > 0; - Dirty(component); + Dirty(uid, component); ensnaring.Ensnared = null; if (ensnaring.DestroyOnRemove) diff --git a/Content.Server/Entry/EntryPoint.cs b/Content.Server/Entry/EntryPoint.cs index dda783c4325..dd8cdd0ed08 100644 --- a/Content.Server/Entry/EntryPoint.cs +++ b/Content.Server/Entry/EntryPoint.cs @@ -12,7 +12,6 @@ using Content.Server.GameTicking; using Content.Server.GhostKick; using Content.Server.GuideGenerator; -using Content.Server.Info; using Content.Server.IoC; using Content.Server.Players.JobWhitelist; using Content.Server.Maps; @@ -141,7 +140,6 @@ public override void PostInit() IoCManager.Resolve<RecipeManager>().Initialize(); IoCManager.Resolve<IAdminManager>().Initialize(); IoCManager.Resolve<IAfkManager>().Initialize(); - IoCManager.Resolve<RulesManager>().Initialize(); _euiManager.Initialize(); IoCManager.Resolve<IGameMapManager>().Initialize(); diff --git a/Content.Server/GameTicking/GameTicker.GameRule.cs b/Content.Server/GameTicking/GameTicker.GameRule.cs index f52a3cb296d..9b0ca6b2bbc 100644 --- a/Content.Server/GameTicking/GameTicker.GameRule.cs +++ b/Content.Server/GameTicking/GameTicker.GameRule.cs @@ -1,8 +1,9 @@ using System.Linq; using Content.Server.Administration; -using Content.Server.GameTicking.Components; +using Content.Server.GameTicking.Rules.Components; using Content.Shared.Administration; using Content.Shared.Database; +using Content.Shared.GameTicking.Components; using Content.Shared.Prototypes; using JetBrains.Annotations; using Robust.Shared.Console; diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index 3016195f4b7..c6c8bf50f75 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -460,11 +460,16 @@ private EntityUid SpawnObserverMob() public EntityCoordinates GetObserverSpawnPoint() { _possiblePositions.Clear(); - - foreach (var (point, transform) in EntityManager.EntityQuery<SpawnPointComponent, TransformComponent>(true)) + var spawnPointQuery = EntityManager.EntityQueryEnumerator<SpawnPointComponent, TransformComponent>(); + while (spawnPointQuery.MoveNext(out var uid, out var point, out var transform)) { - if (point.SpawnType != SpawnPointType.Observer) + if (point.SpawnType != SpawnPointType.Observer + || TerminatingOrDeleted(uid) + || transform.MapUid == null + || TerminatingOrDeleted(transform.MapUid.Value)) + { continue; + } _possiblePositions.Add(transform.Coordinates); } @@ -506,7 +511,9 @@ public EntityCoordinates GetObserverSpawnPoint() if (_mapManager.MapExists(DefaultMap)) { - return new EntityCoordinates(_mapManager.GetMapEntityId(DefaultMap), Vector2.Zero); + var mapUid = _mapManager.GetMapEntityId(DefaultMap); + if (!TerminatingOrDeleted(mapUid)) + return new EntityCoordinates(mapUid, Vector2.Zero); } // Just pick a point at this point I guess. diff --git a/Content.Server/GameTicking/Rules/DeathMatchRuleSystem.cs b/Content.Server/GameTicking/Rules/DeathMatchRuleSystem.cs index 78b8a8a85c8..d03d040261a 100644 --- a/Content.Server/GameTicking/Rules/DeathMatchRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/DeathMatchRuleSystem.cs @@ -1,12 +1,12 @@ using System.Linq; using Content.Server.Administration.Commands; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.KillTracking; using Content.Server.Mind; using Content.Server.Points; using Content.Server.RoundEnd; using Content.Server.Station.Systems; +using Content.Shared.GameTicking.Components; using Content.Shared.Points; using Content.Shared.Storage; using Robust.Server.Player; diff --git a/Content.Server/GameTicking/Rules/GameRulePrototype.cs b/Content.Server/GameTicking/Rules/GameRulePrototype.cs deleted file mode 100644 index 47f99184f73..00000000000 --- a/Content.Server/GameTicking/Rules/GameRulePrototype.cs +++ /dev/null @@ -1,15 +0,0 @@ - - -namespace Content.Server.GameTicking.Rules; - -/* -[Prototype("gameRule")] -public sealed partial class GameRulePrototype : IPrototype -{ - [IdDataField] - public string ID { get; private set; } = default!; - - [DataField("config", required: true)] - public GameRuleConfiguration Configuration { get; private set; } = default!; -} -*/ diff --git a/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs b/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs index cbd981e99e6..b72ba59ca27 100644 --- a/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs +++ b/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs @@ -1,8 +1,8 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Components; +using Content.Shared.GameTicking.Components; using Content.Shared.Random.Helpers; using Robust.Server.GameObjects; using Robust.Shared.Collections; diff --git a/Content.Server/GameTicking/Rules/GameRuleSystem.cs b/Content.Server/GameTicking/Rules/GameRuleSystem.cs index 05374aa1396..730748ce6b9 100644 --- a/Content.Server/GameTicking/Rules/GameRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/GameRuleSystem.cs @@ -1,6 +1,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Chat.Managers; -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Robust.Server.GameObjects; using Robust.Shared.Random; using Robust.Shared.Timing; diff --git a/Content.Server/GameTicking/Rules/InactivityTimeRestartRuleSystem.cs b/Content.Server/GameTicking/Rules/InactivityTimeRestartRuleSystem.cs index 01fa387595c..e56537c4381 100644 --- a/Content.Server/GameTicking/Rules/InactivityTimeRestartRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/InactivityTimeRestartRuleSystem.cs @@ -1,7 +1,7 @@ using System.Threading; using Content.Server.Chat.Managers; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; +using Content.Shared.GameTicking.Components; using Robust.Server.Player; using Robust.Shared.Player; using Timer = Robust.Shared.Timing.Timer; diff --git a/Content.Server/GameTicking/Rules/KillCalloutRuleSystem.cs b/Content.Server/GameTicking/Rules/KillCalloutRuleSystem.cs index 3da55e30c9e..8f706fd2ad3 100644 --- a/Content.Server/GameTicking/Rules/KillCalloutRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/KillCalloutRuleSystem.cs @@ -1,8 +1,8 @@ using Content.Server.Chat.Managers; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.KillTracking; using Content.Shared.Chat; +using Content.Shared.GameTicking.Components; using Robust.Server.Player; using Robust.Shared.Player; using Robust.Shared.Random; diff --git a/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs b/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs index 3a80d82fd92..e655bd472c6 100644 --- a/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs @@ -1,8 +1,8 @@ using Content.Server.Antag; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; -using Content.Server.GridPreloader; using Content.Server.Spawners.Components; +using Content.Server.GridPreloader; +using Content.Shared.GameTicking.Components; using Robust.Server.GameObjects; using Robust.Server.Maps; using Robust.Shared.Map; diff --git a/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs b/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs index cae99fee9fc..db9df8a5b00 100644 --- a/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs @@ -1,7 +1,7 @@ using System.Threading; using Content.Server.Chat.Managers; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; +using Content.Shared.GameTicking.Components; using Timer = Robust.Shared.Timing.Timer; namespace Content.Server.GameTicking.Rules; diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index 3e61fda8744..7cc51db5766 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -2,6 +2,8 @@ using Content.Server.Communications; using Content.Server.GameTicking.Rules.Components; using Content.Server.Humanoid; +using Content.Server.NPC.Components; +using Content.Server.NPC.Systems; using Content.Server.Nuke; using Content.Server.NukeOps; using Content.Server.Popups; @@ -13,6 +15,7 @@ using Content.Server.Station.Components; using Content.Server.Store.Components; using Content.Server.Store.Systems; +using Content.Shared.GameTicking.Components; using Content.Shared.Humanoid; using Content.Shared.Humanoid.Prototypes; using Content.Shared.Mobs; @@ -28,9 +31,6 @@ using Robust.Shared.Random; using Robust.Shared.Utility; using System.Linq; -using Content.Server.GameTicking.Components; -using Content.Server.NPC.Components; -using Content.Server.NPC.Systems; namespace Content.Server.GameTicking.Rules; diff --git a/Content.Server/GameTicking/Rules/RespawnRuleSystem.cs b/Content.Server/GameTicking/Rules/RespawnRuleSystem.cs index 5215da96aa8..920668472ad 100644 --- a/Content.Server/GameTicking/Rules/RespawnRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/RespawnRuleSystem.cs @@ -1,8 +1,9 @@ using Content.Server.Chat.Managers; -using Content.Server.GameTicking.Components; +using Content.Server.Database.Migrations.Postgres; using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Systems; using Content.Shared.Chat; +using Content.Shared.GameTicking.Components; using Content.Shared.Interaction.Events; using Content.Shared.Mind; using Content.Shared.Mobs; diff --git a/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs b/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs index 577b0c30303..29f69db14a2 100644 --- a/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs @@ -14,6 +14,7 @@ using Content.Server.Shuttles.Systems; using Content.Server.Station.Systems; using Content.Shared.Database; +using Content.Shared.GameTicking.Components; using Content.Shared.Humanoid; using Content.Shared.IdentityManagement; using Content.Shared.Mind; @@ -27,7 +28,6 @@ using Content.Shared.Zombies; using Robust.Shared.Prototypes; using Robust.Shared.Timing; -using Content.Server.GameTicking.Components; using Content.Shared.Cuffs.Components; namespace Content.Server.GameTicking.Rules; diff --git a/Content.Server/GameTicking/Rules/RoundstartStationVariationRuleSystem.cs b/Content.Server/GameTicking/Rules/RoundstartStationVariationRuleSystem.cs index f09ed3ebc3c..570889155b3 100644 --- a/Content.Server/GameTicking/Rules/RoundstartStationVariationRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/RoundstartStationVariationRuleSystem.cs @@ -1,9 +1,9 @@ using System.Linq; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Shuttles.Systems; using Content.Server.Station.Components; using Content.Server.Station.Events; +using Content.Shared.GameTicking.Components; using Content.Shared.Storage; using Robust.Shared.Prototypes; using Robust.Shared.Random; diff --git a/Content.Server/GameTicking/Rules/SandboxRuleSystem.cs b/Content.Server/GameTicking/Rules/SandboxRuleSystem.cs index c60670a3ad7..23e9ee5a7d2 100644 --- a/Content.Server/GameTicking/Rules/SandboxRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/SandboxRuleSystem.cs @@ -1,6 +1,6 @@ -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Sandbox; +using Content.Shared.GameTicking.Components; namespace Content.Server.GameTicking.Rules; diff --git a/Content.Server/GameTicking/Rules/SecretRuleSystem.cs b/Content.Server/GameTicking/Rules/SecretRuleSystem.cs index 95bf5986a5a..3542b2e0864 100644 --- a/Content.Server/GameTicking/Rules/SecretRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/SecretRuleSystem.cs @@ -1,10 +1,10 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server.Administration.Logs; -using Content.Server.GameTicking.Components; using Content.Server.Chat.Managers; using Content.Server.GameTicking.Presets; using Content.Server.GameTicking.Rules.Components; +using Content.Shared.GameTicking.Components; using Content.Shared.Random; using Content.Shared.CCVar; using Content.Shared.Database; diff --git a/Content.Server/GameTicking/Rules/SubGamemodesSystem.cs b/Content.Server/GameTicking/Rules/SubGamemodesSystem.cs index 4486ee40fbb..4fe3827ce5c 100644 --- a/Content.Server/GameTicking/Rules/SubGamemodesSystem.cs +++ b/Content.Server/GameTicking/Rules/SubGamemodesSystem.cs @@ -1,5 +1,5 @@ -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; +using Content.Shared.GameTicking.Components; using Content.Shared.Storage; namespace Content.Server.GameTicking.Rules; diff --git a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs index 1db288799f2..3d0a02d6aa9 100644 --- a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs @@ -5,8 +5,11 @@ using Content.Server.Objectives; using Content.Server.PDA.Ringer; using Content.Server.Roles; +using Content.Server.Traitor.Components; using Content.Server.Traitor.Uplink; +using Content.Shared.GameTicking.Components; using Content.Shared.Mind; +using Content.Shared.Mood; using Content.Shared.Objectives.Components; using Content.Shared.PDA; using Content.Shared.Roles; @@ -15,9 +18,6 @@ using Robust.Shared.Random; using System.Linq; using System.Text; -using Content.Shared.Mood; -using Content.Server.GameTicking.Components; -using Content.Server.Traitor.Components; namespace Content.Server.GameTicking.Rules; diff --git a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs index 1361ab37338..6c96bfd18c7 100644 --- a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Antag; +using Content.Server.Announcements.Systems; using Content.Server.Chat.Systems; using Content.Server.GameTicking.Rules.Components; using Content.Server.Popups; @@ -6,6 +7,7 @@ using Content.Server.Station.Components; using Content.Server.Station.Systems; using Content.Server.Zombies; +using Content.Shared.GameTicking.Components; using Content.Shared.Humanoid; using Content.Shared.Mind; using Content.Shared.Mobs; @@ -15,8 +17,6 @@ using Robust.Shared.Player; using Robust.Shared.Timing; using System.Globalization; -using Content.Server.Announcements.Systems; -using Content.Server.GameTicking.Components; namespace Content.Server.GameTicking.Rules; diff --git a/Content.Server/Geras/GerasComponent.cs b/Content.Server/Geras/GerasComponent.cs index eaf792502f4..df1fccd7185 100644 --- a/Content.Server/Geras/GerasComponent.cs +++ b/Content.Server/Geras/GerasComponent.cs @@ -12,7 +12,7 @@ public sealed partial class GerasComponent : Component { [DataField] public ProtoId<PolymorphPrototype> GerasPolymorphId = "SlimeMorphGeras"; - [DataField] public ProtoId<EntityPrototype> GerasAction = "ActionMorphGeras"; + [DataField] public EntProtoId GerasAction = "ActionMorphGeras"; [DataField] public EntityUid? GerasActionEntity; } diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index 254d478bb0f..effed5cdbe1 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -409,23 +409,41 @@ public bool DoGhostBooEvent(EntityUid target) return SpawnGhost(mind, spawnPosition, canReturn); } + private bool IsValidSpawnPosition(EntityCoordinates? spawnPosition) + { + if (spawnPosition?.IsValid(EntityManager) != true) + return false; + + var mapUid = spawnPosition?.GetMapUid(EntityManager); + var gridUid = spawnPosition?.EntityId; + // Test if the map is being deleted + if (mapUid == null || TerminatingOrDeleted(mapUid.Value)) + return false; + // Test if the grid is being deleted + if (gridUid != null && TerminatingOrDeleted(gridUid.Value)) + return false; + + return true; + } + public EntityUid? SpawnGhost(Entity<MindComponent?> mind, EntityCoordinates? spawnPosition = null, bool canReturn = false) { if (!Resolve(mind, ref mind.Comp)) return null; - // Test if the map is being deleted - var mapUid = spawnPosition?.GetMapUid(EntityManager); - if (mapUid == null || TerminatingOrDeleted(mapUid.Value)) + // Test if the map or grid is being deleted + if (!IsValidSpawnPosition(spawnPosition)) spawnPosition = null; + // If it's bad, look for a valid point to spawn spawnPosition ??= _ticker.GetObserverSpawnPoint(); - if (!spawnPosition.Value.IsValid(EntityManager)) + // Make sure the new point is valid too + if (!IsValidSpawnPosition(spawnPosition)) { Log.Warning($"No spawn valid ghost spawn position found for {mind.Comp.CharacterName}" - + " \"{ToPrettyString(mind)}\""); + + $" \"{ToPrettyString(mind)}\""); _minds.TransferTo(mind.Owner, null, createGhost: false, mind: mind.Comp); return null; } diff --git a/Content.Server/Gravity/GravitySystem.cs b/Content.Server/Gravity/GravitySystem.cs index 5e0332ae491..ea62d4a8195 100644 --- a/Content.Server/Gravity/GravitySystem.cs +++ b/Content.Server/Gravity/GravitySystem.cs @@ -41,7 +41,7 @@ public void RefreshGravity(EntityUid uid, GravityComponent? gravity = null) gravity.Enabled = enabled; var ev = new GravityChangedEvent(uid, enabled); RaiseLocalEvent(uid, ref ev, true); - Dirty(gravity); + Dirty(uid, gravity); if (HasComp<MapGridComponent>(uid)) { @@ -71,7 +71,7 @@ public void EnableGravity(EntityUid uid, GravityComponent? gravity = null) gravity.Enabled = true; var ev = new GravityChangedEvent(uid, true); RaiseLocalEvent(uid, ref ev, true); - Dirty(gravity); + Dirty(uid, gravity); if (HasComp<MapGridComponent>(uid)) { diff --git a/Content.Server/Holiday/Christmas/RandomGiftSystem.cs b/Content.Server/Holiday/Christmas/RandomGiftSystem.cs index 9e56d0a4937..48af65cb378 100644 --- a/Content.Server/Holiday/Christmas/RandomGiftSystem.cs +++ b/Content.Server/Holiday/Christmas/RandomGiftSystem.cs @@ -93,7 +93,7 @@ private void BuildIndex() foreach (var proto in _prototype.EnumeratePrototypes<EntityPrototype>()) { - if (proto.Abstract || proto.NoSpawn || proto.Components.ContainsKey(mapGridCompName) || !proto.Components.ContainsKey(physicsCompName)) + if (proto.Abstract || proto.HideSpawnMenu || proto.Components.ContainsKey(mapGridCompName) || !proto.Components.ContainsKey(physicsCompName)) continue; _possibleGiftsUnsafe.Add(proto.ID); diff --git a/Content.Server/HotPotato/HotPotatoSystem.cs b/Content.Server/HotPotato/HotPotatoSystem.cs index 8091eea6fdd..115a7b6cb76 100644 --- a/Content.Server/HotPotato/HotPotatoSystem.cs +++ b/Content.Server/HotPotato/HotPotatoSystem.cs @@ -29,7 +29,7 @@ private void OnActiveTimer(EntityUid uid, HotPotatoComponent comp, ref ActiveTim comp.CanTransfer = false; _ambientSound.SetAmbience(uid, true); _damageOnHolding.SetEnabled(uid, true); - Dirty(comp); + Dirty(uid, comp); } private void OnMeleeHit(EntityUid uid, HotPotatoComponent comp, MeleeHitEvent args) @@ -56,6 +56,6 @@ private void OnMeleeHit(EntityUid uid, HotPotatoComponent comp, MeleeHitEvent ar break; } comp.CanTransfer = false; - Dirty(comp); + Dirty(uid, comp); } } diff --git a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs index 06225c9d57c..7744d161519 100644 --- a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs +++ b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs @@ -29,7 +29,7 @@ private void OnVerbsRequest(EntityUid uid, HumanoidAppearanceComponent component { Text = "Modify markings", Category = VerbCategory.Tricks, - Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Customization/reptilian_parts.rsi"), "tail_smooth"), + Icon = new SpriteSpecifier.Rsi(new("/Textures/Mobs/Customization/reptilian_parts.rsi"), "tail_smooth"), Act = () => { _uiSystem.OpenUi(uid, HumanoidMarkingModifierKey.Key, actor.PlayerSession); @@ -62,7 +62,7 @@ private void OnBaseLayersSet(EntityUid uid, HumanoidAppearanceComponent componen component.CustomBaseLayers[message.Layer] = message.Info.Value; } - Dirty(component); + Dirty(uid, component); if (message.ResendState) { @@ -86,7 +86,7 @@ private void OnMarkingsSet(EntityUid uid, HumanoidAppearanceComponent component, } component.MarkingSet = message.MarkingSet; - Dirty(component); + Dirty(uid, component); if (message.ResendState) { diff --git a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs index ed6d91f56c7..1811567d270 100644 --- a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs +++ b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.cs @@ -53,9 +53,8 @@ public void CloneAppearance(EntityUid source, EntityUid target, HumanoidAppearan grammar.Gender = sourceHumanoid.Gender; } - targetHumanoid.LastProfileLoaded = sourceHumanoid.LastProfileLoaded; // DeltaV - let paradox anomaly be cloned - - Dirty(targetHumanoid); + targetHumanoid.LastProfileLoaded = sourceHumanoid.LastProfileLoaded; + Dirty(target, targetHumanoid); } /// <summary> @@ -76,7 +75,7 @@ public void RemoveMarking(EntityUid uid, string marking, bool sync = true, Human humanoid.MarkingSet.Remove(prototype.MarkingCategory, marking); if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -97,7 +96,7 @@ public void RemoveMarking(EntityUid uid, MarkingCategories category, int index, } humanoid.MarkingSet.Remove(category, index); - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -126,7 +125,7 @@ public void SetMarkingId(EntityUid uid, MarkingCategories category, int index, s } humanoid.MarkingSet.Replace(category, index, marking); - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -153,6 +152,6 @@ public void SetMarkingColor(EntityUid uid, MarkingCategories category, int index markings[index].SetColor(i, colors[i]); } - Dirty(humanoid); + Dirty(uid, humanoid); } } diff --git a/Content.Server/Info/InfoSystem.cs b/Content.Server/Info/InfoSystem.cs deleted file mode 100644 index 350ae033cfd..00000000000 --- a/Content.Server/Info/InfoSystem.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Content.Shared.CCVar; -using Content.Shared.Info; -using Robust.Shared.Configuration; -using Robust.Shared.ContentPack; - -namespace Content.Server.Info; - -public sealed class InfoSystem : EntitySystem -{ - [Dependency] private readonly IResourceManager _res = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; - public override void Initialize() - { - base.Initialize(); - SubscribeNetworkEvent<RequestRulesMessage>(OnRequestRules); - } - - private void OnRequestRules(RequestRulesMessage message, EntitySessionEventArgs eventArgs) - { - Log.Debug("Client requested rules."); - var title = Loc.GetString(_cfg.GetCVar(CCVars.RulesHeader)); - var path = _cfg.GetCVar(CCVars.RulesFile); - var rules = "Server could not read its rules."; - try - { - rules = _res.ContentFileReadAllText($"/ServerInfo/{path}"); - } - catch (Exception) - { - Log.Debug("Could not read server rules file."); - } - var response = new RulesMessage(title, rules); - RaiseNetworkEvent(response, eventArgs.SenderSession.Channel); - } -} diff --git a/Content.Server/Info/RulesManager.cs b/Content.Server/Info/RulesManager.cs deleted file mode 100644 index d9d744dcbd5..00000000000 --- a/Content.Server/Info/RulesManager.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Net; -using Content.Server.Database; -using Content.Shared.CCVar; -using Content.Shared.Info; -using Robust.Shared.Configuration; -using Robust.Shared.Network; - -namespace Content.Server.Info; - -public sealed class RulesManager : SharedRulesManager -{ - [Dependency] private readonly IServerDbManager _dbManager = default!; - [Dependency] private readonly INetManager _netManager = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; - - private static DateTime LastValidReadTime => DateTime.UtcNow - TimeSpan.FromDays(60); - - public void Initialize() - { - _netManager.RegisterNetMessage<ShouldShowRulesPopupMessage>(); - _netManager.RegisterNetMessage<ShowRulesPopupMessage>(); - _netManager.RegisterNetMessage<RulesAcceptedMessage>(OnRulesAccepted); - _netManager.Connected += OnConnected; - } - - private async void OnConnected(object? sender, NetChannelArgs e) - { - if (IPAddress.IsLoopback(e.Channel.RemoteEndPoint.Address) && _cfg.GetCVar(CCVars.RulesExemptLocal)) - { - return; - } - - var lastRead = await _dbManager.GetLastReadRules(e.Channel.UserId); - if (lastRead > LastValidReadTime) - { - return; - } - - var message = new ShouldShowRulesPopupMessage(); - _netManager.ServerSendMessage(message, e.Channel); - } - - private async void OnRulesAccepted(RulesAcceptedMessage message) - { - var date = DateTime.UtcNow; - await _dbManager.SetLastReadRules(message.MsgChannel.UserId, date); - } -} diff --git a/Content.Server/Info/ShowRulesCommand.cs b/Content.Server/Info/ShowRulesCommand.cs index 32c24c29995..b13b8d11a5a 100644 --- a/Content.Server/Info/ShowRulesCommand.cs +++ b/Content.Server/Info/ShowRulesCommand.cs @@ -47,20 +47,16 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args) } } - var locator = IoCManager.Resolve<IPlayerLocator>(); - var located = await locator.LookupIdByNameOrIdAsync(target); - if (located == null) + + var message = new ShowRulesPopupMessage { PopupTime = seconds }; + + if (!IoCManager.Resolve<IPlayerManager>().TryGetSessionByUsername(target, out var player)) { shell.WriteError("Unable to find a player with that name."); - return; + return; } var netManager = IoCManager.Resolve<INetManager>(); - - var message = new SharedRulesManager.ShowRulesPopupMessage(); - message.PopupTime = seconds; - - var player = IoCManager.Resolve<IPlayerManager>().GetSessionById(located.UserId); netManager.ServerSendMessage(message, player.Channel); } } diff --git a/Content.Server/Instruments/SwappableInstrumentSystem.cs b/Content.Server/Instruments/SwappableInstrumentSystem.cs index 3f3cfb9e6db..9aef875cd65 100644 --- a/Content.Server/Instruments/SwappableInstrumentSystem.cs +++ b/Content.Server/Instruments/SwappableInstrumentSystem.cs @@ -35,7 +35,7 @@ private void AddStyleVerb(EntityUid uid, SwappableInstrumentComponent component, Priority = priority, Act = () => { - _sharedInstrument.SetInstrumentProgram(instrument, entry.Value.Item1, entry.Value.Item2); + _sharedInstrument.SetInstrumentProgram(uid, instrument, entry.Value.Item1, entry.Value.Item2); _popup.PopupEntity(Loc.GetString("swappable-instrument-component-style-set", ("style", entry.Key)), args.User, args.User); } diff --git a/Content.Server/InteractionVerbs/Actions/ChangeStandingStateAction.cs b/Content.Server/InteractionVerbs/Actions/ChangeStandingStateAction.cs index 59340df58f2..0d74781f62d 100644 --- a/Content.Server/InteractionVerbs/Actions/ChangeStandingStateAction.cs +++ b/Content.Server/InteractionVerbs/Actions/ChangeStandingStateAction.cs @@ -33,7 +33,7 @@ public override bool Perform(InteractionArgs args, InteractionVerbPrototype prot if (state.CurrentState == StandingState.Lying && MakeStanding) return stateSystem.Stand(args.Target); else if (state.CurrentState == StandingState.Standing && MakeLaying) - return stateSystem.Down(args.Target, setDrawDepth: true); + return stateSystem.Down(args.Target); return false; } diff --git a/Content.Server/IoC/ServerContentIoC.cs b/Content.Server/IoC/ServerContentIoC.cs index 7c150141333..4483c6af68c 100644 --- a/Content.Server/IoC/ServerContentIoC.cs +++ b/Content.Server/IoC/ServerContentIoC.cs @@ -11,7 +11,6 @@ using Content.Server.DiscordAuth; using Content.Server.EUI; using Content.Server.GhostKick; -using Content.Server.Info; using Content.Server.Maps; using Content.Server.Players.JobWhitelist; using Content.Server.MoMMI; @@ -49,7 +48,6 @@ public static void Register() IoCManager.Register<IPlayerLocator, PlayerLocator>(); IoCManager.Register<IAfkManager, AfkManager>(); IoCManager.Register<IGameMapManager, GameMapManager>(); - IoCManager.Register<RulesManager, RulesManager>(); IoCManager.Register<IBanManager, BanManager>(); IoCManager.Register<ContentNetworkResourceManager>(); IoCManager.Register<IAdminNotesManager, AdminNotesManager>(); diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs index f9e1ae22416..40be61695fc 100644 --- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs @@ -99,9 +99,13 @@ private void OnCookStart(Entity<ActiveMicrowaveComponent> ent, ref ComponentStar if (!TryComp<MicrowaveComponent>(ent, out var microwaveComponent)) return; SetAppearance(ent.Owner, MicrowaveVisualState.Cooking, microwaveComponent); + + var audio = _audio.PlayPvs(microwaveComponent.LoopingSound, ent, AudioParams.Default.WithLoop(true).WithMaxDistance(5)); - microwaveComponent.PlayingStream = - _audio.PlayPvs(microwaveComponent.LoopingSound, ent, AudioParams.Default.WithLoop(true).WithMaxDistance(5)).Value.Entity; + if (audio == null) + return; + + microwaveComponent.PlayingStream = audio!.Value.Entity; } private void OnCookStop(Entity<ActiveMicrowaveComponent> ent, ref ComponentShutdown args) diff --git a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs index 93a15f319d9..0d6fb3fb90c 100644 --- a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs @@ -323,9 +323,15 @@ private void DoWork(EntityUid uid, ReagentGrinderComponent reagentGrinder, Grind var active = AddComp<ActiveReagentGrinderComponent>(uid); active.EndTime = _timing.CurTime + reagentGrinder.WorkTime * reagentGrinder.WorkTimeMultiplier; active.Program = program; + + // slightly higher pitched + var audio = _audioSystem.PlayPvs(sound, uid, + AudioParams.Default.WithPitchScale(1 / reagentGrinder.WorkTimeMultiplier)); - reagentGrinder.AudioStream = _audioSystem.PlayPvs(sound, uid, - AudioParams.Default.WithPitchScale(1 / reagentGrinder.WorkTimeMultiplier)).Value.Entity; //slightly higher pitched + if (audio == null) + return; + + reagentGrinder.AudioStream = audio!.Value.Entity; _userInterfaceSystem.ServerSendUiMessage(uid, ReagentGrinderUiKey.Key, new ReagentGrinderWorkStartedMessage(program)); } diff --git a/Content.Server/Light/EntitySystems/RotatingLightSystem.cs b/Content.Server/Light/EntitySystems/RotatingLightSystem.cs index dd72b3a43e8..7ef1357dc31 100644 --- a/Content.Server/Light/EntitySystems/RotatingLightSystem.cs +++ b/Content.Server/Light/EntitySystems/RotatingLightSystem.cs @@ -19,6 +19,6 @@ private void OnLightToggle(EntityUid uid, RotatingLightComponent comp, PointLigh return; comp.Enabled = args.Enabled; - Dirty(comp); + Dirty(uid, comp); } } diff --git a/Content.Server/Lightning/LightningSystem.cs b/Content.Server/Lightning/LightningSystem.cs index 4f975a60fda..3c0da8e9149 100644 --- a/Content.Server/Lightning/LightningSystem.cs +++ b/Content.Server/Lightning/LightningSystem.cs @@ -20,6 +20,7 @@ public sealed class LightningSystem : SharedLightningSystem [Dependency] private readonly BeamSystem _beam = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; public override void Initialize() { @@ -74,28 +75,33 @@ public void ShootRandomLightnings(EntityUid user, float range, int boltCount, st //To Do: This is still pretty bad for perf but better than before and at least it doesn't re-allocate // several hashsets every time - var targets = _lookup.GetComponentsInRange<LightningTargetComponent>(Transform(user).MapPosition, range).ToList(); + var userCoords = _transform.GetMapCoordinates(user); + var targetEnts = _lookup.GetEntitiesInRange<LightningTargetComponent>(userCoords, range); + var targets = targetEnts.Select(x => x.Comp).ToList(); + _random.Shuffle(targets); targets.Sort((x, y) => y.Priority.CompareTo(x.Priority)); - int shootedCount = 0; + int shotCount = 0; int count = -1; - while(shootedCount < boltCount) + + while (shotCount < boltCount) { count++; if (count >= targets.Count) { break; } - var curTarget = targets[count]; - if (!_random.Prob(curTarget.HitProbability)) //Chance to ignore target + + // Chance to ignore target + if (!_random.Prob(curTarget.HitProbability)) continue; ShootLightning(user, targets[count].Owner, lightningPrototype, triggerLightningEvents); + if (arcDepth - targets[count].LightningResistance > 0) - { ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targets[count].LightningResistance, triggerLightningEvents); - } - shootedCount++; + + shotCount++; } } } diff --git a/Content.Server/Materials/MaterialReclaimerSystem.cs b/Content.Server/Materials/MaterialReclaimerSystem.cs index de82f125985..3b23308758d 100644 --- a/Content.Server/Materials/MaterialReclaimerSystem.cs +++ b/Content.Server/Materials/MaterialReclaimerSystem.cs @@ -146,7 +146,7 @@ public override bool TryFinishProcessItem(EntityUid uid, MaterialReclaimerCompon return false; Container.Remove(item, active.ReclaimingContainer); - Dirty(component); + Dirty(uid, component); // scales the output if the process was interrupted. var completion = 1f - Math.Clamp((float) Math.Round((active.EndTime - Timing.CurTime) / active.Duration), diff --git a/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs b/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs index fa46792d2af..0ade8928f9f 100644 --- a/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs +++ b/Content.Server/Mech/Equipment/EntitySystems/MechGrabberSystem.cs @@ -83,9 +83,10 @@ public void RemoveItem(EntityUid uid, EntityUid mech, EntityUid toRemove, MechGr var xform = Transform(toRemove); _transform.AttachToGridOrMap(toRemove, xform); var (mechPos, mechRot) = _transform.GetWorldPositionRotation(mechxform); + var toRemoveWorldPos = _transform.GetWorldPosition(xform); var offset = mechPos + mechRot.RotateVec(component.DepositOffset); - _transform.SetWorldPositionRotation(xform, offset, Angle.Zero); + _transform.SetWorldPositionRotation(toRemove, toRemoveWorldPos + offset, Angle.Zero); _mech.UpdateUserInterface(mech); } @@ -154,7 +155,12 @@ private void OnInteract(EntityUid uid, MechGrabberComponent component, InteractN return; args.Handled = true; - component.AudioStream = _audio.PlayPvs(component.GrabSound, uid).Value.Entity; + var audio = _audio.PlayPvs(component.GrabSound, uid); + + if (audio == null) + return; + + component.AudioStream = audio!.Value.Entity; var doAfterArgs = new DoAfterArgs(EntityManager, args.User, component.GrabDelay, new GrabberDoAfterEvent(), uid, target: target, used: uid) { BreakOnTargetMove = true, diff --git a/Content.Server/Mech/Systems/MechSystem.cs b/Content.Server/Mech/Systems/MechSystem.cs index 36dce2c9bcc..a728ee7de5e 100644 --- a/Content.Server/Mech/Systems/MechSystem.cs +++ b/Content.Server/Mech/Systems/MechSystem.cs @@ -107,7 +107,7 @@ private void OnInsertBattery(EntityUid uid, MechComponent component, EntInserted component.Energy = battery.CurrentCharge; component.MaxEnergy = battery.MaxCharge; - Dirty(component); + Dirty(uid, component); _actionBlocker.UpdateCanMove(uid); } @@ -137,7 +137,7 @@ private void OnMapInit(EntityUid uid, MechComponent component, MapInitEvent args component.Energy = component.MaxEnergy; _actionBlocker.UpdateCanMove(uid); - Dirty(component); + Dirty(uid, component); } private void OnRemoveEquipmentMessage(EntityUid uid, MechComponent component, MechEquipmentRemoveMessage args) @@ -337,7 +337,7 @@ public override bool TryChangeEnergy(EntityUid uid, FixedPoint2 delta, MechCompo { Log.Debug($"Battery charge was not equal to mech charge. Battery {batteryComp.CurrentCharge}. Mech {component.Energy}"); component.Energy = batteryComp.CurrentCharge; - Dirty(component); + Dirty(uid, component); } _actionBlocker.UpdateCanMove(uid); return true; @@ -357,7 +357,7 @@ public void InsertBattery(EntityUid uid, EntityUid toInsert, MechComponent? comp _actionBlocker.UpdateCanMove(uid); - Dirty(component); + Dirty(uid, component); UpdateUserInterface(uid, component); } @@ -372,7 +372,7 @@ public void RemoveBattery(EntityUid uid, MechComponent? component = null) _actionBlocker.UpdateCanMove(uid); - Dirty(component); + Dirty(uid, component); UpdateUserInterface(uid, component); } diff --git a/Content.Server/Mood/MoodComponent.cs b/Content.Server/Mood/MoodComponent.cs index 7fd4a7136f3..caa221fe18e 100644 --- a/Content.Server/Mood/MoodComponent.cs +++ b/Content.Server/Mood/MoodComponent.cs @@ -1,5 +1,6 @@ using Content.Shared.Alert; using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; namespace Content.Server.Mood; @@ -50,6 +51,9 @@ public sealed partial class MoodComponent : Component [ViewVariables(VVAccess.ReadOnly)] public FixedPoint2 CritThresholdBeforeModify; + [DataField] + public ProtoId<AlertCategoryPrototype> MoodCategory = "Mood"; + [DataField(customTypeSerializer: typeof(DictionarySerializer<MoodThreshold, float>))] public Dictionary<MoodThreshold, float> MoodThresholds = new() { @@ -65,20 +69,20 @@ public sealed partial class MoodComponent : Component { MoodThreshold.Dead, 0f } }; - [DataField(customTypeSerializer: typeof(DictionarySerializer<MoodThreshold, AlertType>))] - public Dictionary<MoodThreshold, AlertType> MoodThresholdsAlerts = new() + [DataField(customTypeSerializer: typeof(DictionarySerializer<MoodThreshold, ProtoId<AlertPrototype>>))] + public Dictionary<MoodThreshold, ProtoId<AlertPrototype>> MoodThresholdsAlerts = new() { - { MoodThreshold.Dead, AlertType.MoodDead }, - { MoodThreshold.Horrible, AlertType.Horrible }, - { MoodThreshold.Terrible, AlertType.Terrible }, - { MoodThreshold.Bad, AlertType.Bad }, - { MoodThreshold.Meh, AlertType.Meh }, - { MoodThreshold.Neutral, AlertType.Neutral }, - { MoodThreshold.Good, AlertType.Good }, - { MoodThreshold.Great, AlertType.Great }, - { MoodThreshold.Exceptional, AlertType.Exceptional }, - { MoodThreshold.Perfect, AlertType.Perfect }, - { MoodThreshold.Insane, AlertType.Insane } + { MoodThreshold.Dead, "MoodDead" }, + { MoodThreshold.Horrible, "Horrible" }, + { MoodThreshold.Terrible, "Terrible" }, + { MoodThreshold.Bad, "Bad" }, + { MoodThreshold.Meh, "Meh" }, + { MoodThreshold.Neutral, "Neutral" }, + { MoodThreshold.Good, "Good" }, + { MoodThreshold.Great, "Great" }, + { MoodThreshold.Exceptional, "Exceptional" }, + { MoodThreshold.Perfect, "Perfect" }, + { MoodThreshold.Insane, "Insane" } }; /// <summary> diff --git a/Content.Server/Mood/MoodSystem.cs b/Content.Server/Mood/MoodSystem.cs index 4ec4709ea7a..41baf9f5479 100644 --- a/Content.Server/Mood/MoodSystem.cs +++ b/Content.Server/Mood/MoodSystem.cs @@ -57,7 +57,7 @@ public override void Initialize() private void OnShutdown(EntityUid uid, MoodComponent component, ComponentShutdown args) { - _alerts.ClearAlertCategory(uid, AlertCategory.Mood); + _alerts.ClearAlertCategory(uid, component.MoodCategory); } private void OnRemoveEffect(EntityUid uid, MoodComponent component, MoodRemoveEffectEvent args) @@ -331,7 +331,7 @@ private void DoMoodThresholdsEffects(EntityUid uid, MoodComponent? component = n if (component.MoodThresholdsAlerts.TryGetValue(component.CurrentMoodThreshold, out var alertId)) _alerts.ShowAlert(uid, alertId); else - _alerts.ClearAlertCategory(uid, AlertCategory.Mood); + _alerts.ClearAlertCategory(uid, component.MoodCategory); component.LastThreshold = component.CurrentMoodThreshold; } diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs index 207665d786f..116e8fe7c7f 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs @@ -1,11 +1,9 @@ using Content.Server.Buckle.Systems; -using Content.Shared.Buckle.Components; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat; public sealed partial class UnbuckleOperator : HTNOperator { - [Dependency] private readonly IEntityManager _entManager = default!; private BuckleSystem _buckle = default!; [DataField("shutdownState")] @@ -21,10 +19,7 @@ public override void Startup(NPCBlackboard blackboard) { base.Startup(blackboard); var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner); - if (!_entManager.TryGetComponent<BuckleComponent>(owner, out var buckle) || !buckle.Buckled) - return; - - _buckle.TryUnbuckle(owner, owner, true, buckle); + _buckle.Unbuckle(owner, null); } public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) diff --git a/Content.Server/NPC/Systems/NPCJukeSystem.cs b/Content.Server/NPC/Systems/NPCJukeSystem.cs index 5a724762ef6..d55a0895d30 100644 --- a/Content.Server/NPC/Systems/NPCJukeSystem.cs +++ b/Content.Server/NPC/Systems/NPCJukeSystem.cs @@ -22,6 +22,7 @@ public sealed class NPCJukeSystem : EntitySystem [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly MeleeWeaponSystem _melee = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedMapSystem _map = default!; private EntityQuery<NPCMeleeCombatComponent> _npcMeleeQuery; private EntityQuery<NPCRangedCombatComponent> _npcRangedQuery; @@ -49,6 +50,9 @@ private void OnJukeSteering(EntityUid uid, NPCJukeComponent component, ref NPCSt if (component.JukeType == JukeType.AdjacentTile) { + if (args.Transform.GridUid == null) + return; + if (_npcRangedQuery.TryGetComponent(uid, out var ranged) && ranged.Status is CombatStatus.NotInSight || !TryComp<MapGridComponent>(args.Transform.GridUid, out var grid)) @@ -57,7 +61,7 @@ private void OnJukeSteering(EntityUid uid, NPCJukeComponent component, ref NPCSt return; } - var currentTile = grid.CoordinatesToTile(args.Transform.Coordinates); + var currentTile = _map.CoordinatesToTile((EntityUid) args.Transform.GridUid, grid, args.Transform.Coordinates); if (component.TargetTile == null) { @@ -113,8 +117,8 @@ private void OnJukeSteering(EntityUid uid, NPCJukeComponent component, ref NPCSt return; } - var targetCoords = grid.GridTileToWorld(component.TargetTile.Value); - var targetDir = (targetCoords.Position - args.WorldPosition); + var targetCoords = _map.GridTileToWorld((EntityUid) args.Transform.GridUid, grid, component.TargetTile.Value); + var targetDir = targetCoords.Position - args.WorldPosition; targetDir = args.OffsetRotation.RotateVec(targetDir); const float weight = 1f; var norm = targetDir.Normalized(); diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs index 3bc4eae9e49..60408e9a4cb 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs @@ -207,7 +207,7 @@ private void GetObstacleEntities(PathPoly poly, int mask, int layer, List<Entity return; } - foreach (var ent in grid.GetLocalAnchoredEntities(poly.Box)) + foreach (var ent in _map.GetLocalAnchoredEntities(poly.GraphUid, grid, poly.Box)) { if (!_physicsQuery.TryGetComponent(ent, out var body) || !body.Hard || diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.cs index 447792b6ff2..8729c9f7d8b 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.cs @@ -58,6 +58,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedCombatModeSystem _combat = default!; + [Dependency] private readonly SharedMapSystem _map = default!; private EntityQuery<FixturesComponent> _fixturesQuery; private EntityQuery<MovementSpeedModifierComponent> _modifierQuery; diff --git a/Content.Server/NameIdentifier/NameIdentifierSystem.cs b/Content.Server/NameIdentifier/NameIdentifierSystem.cs index 87953d518b3..eefd4357cb3 100644 --- a/Content.Server/NameIdentifier/NameIdentifierSystem.cs +++ b/Content.Server/NameIdentifier/NameIdentifierSystem.cs @@ -113,7 +113,7 @@ private void OnMapInit(EntityUid uid, NameIdentifierComponent component, MapInit _metaData.SetEntityName(uid, group.FullName ? uniqueName : $"{meta.EntityName} ({uniqueName})", meta); - Dirty(component); + Dirty(uid, component); } private void InitialSetupPrototypes() diff --git a/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs b/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs index 1dfaf4f3393..0c1e88653fa 100644 --- a/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs +++ b/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs @@ -102,20 +102,23 @@ private int Download(EntityUid uid, List<string> ids) /// </summary> public void SetSuitPowerAlert(EntityUid uid, SpaceNinjaComponent? comp = null) { - if (!Resolve(uid, ref comp, false) || comp.Deleted || comp.Suit == null) + if (!Resolve(uid, ref comp, false)) + return; + + if (comp.Deleted || comp.Suit == null) { - _alerts.ClearAlert(uid, AlertType.SuitPower); + _alerts.ClearAlert(uid, comp.SuitPowerAlert); return; } if (GetNinjaBattery(uid, out _, out var battery)) { var severity = ContentHelpers.RoundToLevels(MathF.Max(0f, battery.CurrentCharge), battery.MaxCharge, 8); - _alerts.ShowAlert(uid, AlertType.SuitPower, (short) severity); + _alerts.ShowAlert(uid, comp.SuitPowerAlert, (short) severity); } else { - _alerts.ClearAlert(uid, AlertType.SuitPower); + _alerts.ClearAlert(uid, comp.SuitPowerAlert); } } diff --git a/Content.Server/Nyanotrasen/Construction/Commands/TileWindowsCommand.cs b/Content.Server/Nyanotrasen/Construction/Commands/TileWindowsCommand.cs index 9eef7292eaa..4e03ee059a0 100644 --- a/Content.Server/Nyanotrasen/Construction/Commands/TileWindowsCommand.cs +++ b/Content.Server/Nyanotrasen/Construction/Commands/TileWindowsCommand.cs @@ -5,7 +5,9 @@ using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Maths; +using Robust.Shared.Physics; using Robust.Shared.Player; namespace Content.Server.Construction.Commands @@ -24,8 +26,11 @@ sealed class TileWindowsCommand : IConsoleCommand public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as ICommonSession; + var player = shell.Player; var entityManager = IoCManager.Resolve<IEntityManager>(); + var lookup = IoCManager.Resolve<EntityLookupSystem>(); + var mapSystem = IoCManager.Resolve<SharedMapSystem>(); + EntityUid? gridId; switch (args.Length) @@ -53,8 +58,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) return; } - var mapManager = IoCManager.Resolve<IMapManager>(); - if (!mapManager.TryGetGrid(gridId, out var grid)) + if (!entityManager.TryGetComponent<MapGridComponent>(gridId, out var grid)) { shell.WriteLine($"No grid exists with id {gridId}"); return; @@ -70,8 +74,12 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) var tagSystem = entityManager.EntitySysManager.GetEntitySystem<TagSystem>(); var underplating = tileDefinitionManager[TilePrototypeId]; var underplatingTile = new Tile(underplating.TileId); + var childEntities = new HashSet<Entity<TransformComponent>>(); var changed = 0; - foreach (var child in entityManager.GetComponent<TransformComponent>(grid.Owner).ChildEntities) + + lookup.GetChildEntities(grid.Owner, childEntities); + + foreach (var child in childEntities) { if (!entityManager.EntityExists(child)) { @@ -95,7 +103,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) continue; } - var tile = grid.GetTileRef(childTransform.Coordinates); + var tile = mapSystem.GetTileRef((EntityUid) gridId, grid, childTransform.Coordinates); var tileDef = (ContentTileDefinition) tileDefinitionManager[tile.Tile.TypeId]; if (tileDef.ID == TilePrototypeId) @@ -103,7 +111,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) continue; } - grid.SetTile(childTransform.Coordinates, underplatingTile); + mapSystem.SetTile((EntityUid) gridId, grid, childTransform.Coordinates, underplatingTile); changed++; } diff --git a/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs b/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs index ccbe8d8e7fe..53b0889aa64 100644 --- a/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs +++ b/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs @@ -15,7 +15,7 @@ private void SendWhitelistCached(ICommonSession playerSession) Whitelisted = whitelist }; - _net.ServerSendMessage(msg, playerSession.ConnectedClient); + _net.ServerSendMessage(msg, playerSession.Channel); } /// <summary> diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/MidRoundAntagRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/MidRoundAntagRule.cs index 94a488bd84b..c1bce269ff9 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/MidRoundAntagRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/MidRoundAntagRule.cs @@ -1,4 +1,4 @@ -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Robust.Shared.Random; diff --git a/Content.Server/Objectives/ObjectivesSystem.cs b/Content.Server/Objectives/ObjectivesSystem.cs index 47fe4eb5f88..bf013bc0402 100644 --- a/Content.Server/Objectives/ObjectivesSystem.cs +++ b/Content.Server/Objectives/ObjectivesSystem.cs @@ -1,6 +1,7 @@ using Content.Server.GameTicking; using Content.Server.Shuttles.Systems; using Content.Shared.Cuffs.Components; +using Content.Shared.GameTicking.Components; using Content.Shared.Mind; using Content.Shared.Objectives.Components; using Content.Shared.Objectives.Systems; @@ -9,7 +10,6 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using System.Linq; -using Content.Server.GameTicking.Components; using System.Text; using Robust.Server.Player; diff --git a/Content.Server/OfferItem/OfferItemSystem.cs b/Content.Server/OfferItem/OfferItemSystem.cs index 420df71ace7..e2eb65822e0 100644 --- a/Content.Server/OfferItem/OfferItemSystem.cs +++ b/Content.Server/OfferItem/OfferItemSystem.cs @@ -39,11 +39,11 @@ public override void Update(float frameTime) if (!offerItem.IsInReceiveMode) { - _alertsSystem.ClearAlert(uid, AlertType.Offer); + _alertsSystem.ClearAlert(uid, offerItem.OfferAlert); continue; } - _alertsSystem.ShowAlert(uid, AlertType.Offer); + _alertsSystem.ShowAlert(uid, offerItem.OfferAlert); } } diff --git a/Content.Server/Physics/Controllers/ConveyorController.cs b/Content.Server/Physics/Controllers/ConveyorController.cs index 42279bb7496..b3508025cb9 100644 --- a/Content.Server/Physics/Controllers/ConveyorController.cs +++ b/Content.Server/Physics/Controllers/ConveyorController.cs @@ -67,7 +67,7 @@ private void OnPowerChanged(EntityUid uid, ConveyorComponent component, ref Powe { component.Powered = args.Powered; UpdateAppearance(uid, component); - Dirty(component); + Dirty(uid, component); } private void UpdateAppearance(EntityUid uid, ConveyorComponent component) @@ -106,7 +106,7 @@ private void SetState(EntityUid uid, ConveyorState state, ConveyorComponent? com _materialReclaimer.SetReclaimerEnabled(uid, component.State != ConveyorState.Off); UpdateAppearance(uid, component); - Dirty(component); + Dirty(uid, component); } /// <summary> diff --git a/Content.Server/Pinpointer/NavMapSystem.cs b/Content.Server/Pinpointer/NavMapSystem.cs index 5881daa0689..7ed13b7b940 100644 --- a/Content.Server/Pinpointer/NavMapSystem.cs +++ b/Content.Server/Pinpointer/NavMapSystem.cs @@ -68,7 +68,7 @@ public override void Initialize() private void OnStationInit(StationGridAddedEvent ev) { var comp = EnsureComp<NavMapComponent>(ev.GridId); - RefreshGrid(comp, Comp<MapGridComponent>(ev.GridId)); + RefreshGrid(ev.GridId, comp, Comp<MapGridComponent>(ev.GridId)); } #region: Grid change event handling @@ -81,10 +81,10 @@ private void OnNavMapSplit(ref GridSplitEvent args) foreach (var grid in args.NewGrids) { var newComp = EnsureComp<MapGridComponent>(grid); - RefreshGrid(comp, newComp); + RefreshGrid(args.Grid, comp, newComp); } - RefreshGrid(comp, _gridQuery.GetComponent(args.Grid)); + RefreshGrid(args.Grid, comp, _gridQuery.GetComponent(args.Grid)); } private NavMapChunk EnsureChunk(NavMapComponent component, Vector2i origin) @@ -231,14 +231,14 @@ private void OnConfigurableExamined(Entity<ConfigurableNavMapBeaconComponent> en #region: Grid functions - private void RefreshGrid(NavMapComponent component, MapGridComponent mapGrid) + private void RefreshGrid(EntityUid uid, NavMapComponent component, MapGridComponent mapGrid) { // Clear stale data component.Chunks.Clear(); component.Beacons.Clear(); // Loop over all tiles - var tileRefs = _mapSystem.GetAllTiles(mapGrid.Owner, mapGrid); + var tileRefs = _mapSystem.GetAllTiles(uid, mapGrid); foreach (var tileRef in tileRefs) { @@ -247,10 +247,10 @@ private void RefreshGrid(NavMapComponent component, MapGridComponent mapGrid) var chunk = EnsureChunk(component, chunkOrigin); chunk.LastUpdate = _gameTiming.CurTick; - RefreshTileEntityContents(mapGrid.Owner, component, mapGrid, chunkOrigin, tile, setFloor: true); + RefreshTileEntityContents(uid, component, mapGrid, chunkOrigin, tile, setFloor: true); } - Dirty(mapGrid.Owner, component); + Dirty(uid, component); } private (int NewVal, NavMapChunk Chunk) RefreshTileEntityContents(EntityUid uid, diff --git a/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs b/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs index 42c84b7f43b..35b17dc9584 100644 --- a/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs @@ -6,6 +6,7 @@ using Content.Server.Power.NodeGroups; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; using Content.Shared.Pinpointer; using Content.Shared.Power; using JetBrains.Annotations; @@ -13,7 +14,6 @@ using Robust.Shared.Map.Components; using Robust.Shared.Utility; using System.Linq; -using Content.Server.GameTicking.Components; namespace Content.Server.Power.EntitySystems; diff --git a/Content.Server/PowerCell/PowerCellSystem.Draw.cs b/Content.Server/PowerCell/PowerCellSystem.Draw.cs index 8e960357b7a..4155a4f6bec 100644 --- a/Content.Server/PowerCell/PowerCellSystem.Draw.cs +++ b/Content.Server/PowerCell/PowerCellSystem.Draw.cs @@ -67,7 +67,7 @@ private void OnDrawChargeChanged(EntityUid uid, PowerCellDrawComponent component { component.CanDraw = canDraw; component.CanUse = canUse; - Dirty(component); + Dirty(uid, component); } } @@ -80,7 +80,7 @@ private void OnDrawCellChanged(EntityUid uid, PowerCellDrawComponent component, { component.CanDraw = canDraw; component.CanUse = canUse; - Dirty(component); + Dirty(uid, component); } } } diff --git a/Content.Server/Psionics/Dreams/DreamSystem.cs b/Content.Server/Psionics/Dreams/DreamSystem.cs index d6067717c94..0729f5c59dd 100644 --- a/Content.Server/Psionics/Dreams/DreamSystem.cs +++ b/Content.Server/Psionics/Dreams/DreamSystem.cs @@ -51,7 +51,7 @@ public override void Update(float frameTime) ("telepathicChannelName", Loc.GetString("chat-manager-telepathic-channel-name")), ("message", msg)); _chatManager.ChatMessageToOne(Shared.Chat.ChatChannel.Telepathic, - msg, messageWrap, sleeper.Owner, false, actor.PlayerSession.ConnectedClient, Color.PaleVioletRed); + msg, messageWrap, sleeper.Owner, false, actor.PlayerSession.Channel, Color.PaleVioletRed); } } } diff --git a/Content.Server/Research/Systems/ResearchSystem.Server.cs b/Content.Server/Research/Systems/ResearchSystem.Server.cs index 2a802a91a32..09ca7ed15c2 100644 --- a/Content.Server/Research/Systems/ResearchSystem.Server.cs +++ b/Content.Server/Research/Systems/ResearchSystem.Server.cs @@ -18,7 +18,7 @@ private void OnServerStartup(EntityUid uid, ResearchServerComponent component, C var unusedId = EntityQuery<ResearchServerComponent>(true) .Max(s => s.Id) + 1; component.Id = unusedId; - Dirty(component); + Dirty(uid, component); } private void OnServerShutdown(EntityUid uid, ResearchServerComponent component, ComponentShutdown args) @@ -74,7 +74,7 @@ public void RegisterClient(EntityUid client, EntityUid server, ResearchClientCom SyncClientWithServer(client, clientComponent: clientComponent); if (dirtyServer) - Dirty(serverComponent); + Dirty(server, serverComponent); var ev = new ResearchRegistrationChangedEvent(server); RaiseLocalEvent(client, ref ev); @@ -117,7 +117,7 @@ public void UnregisterClient(EntityUid client, EntityUid server, ResearchClientC if (dirtyServer) { - Dirty(serverComponent); + Dirty(server, serverComponent); } var ev = new ResearchRegistrationChangedEvent(null); @@ -167,6 +167,6 @@ public void ModifyServerPoints(EntityUid uid, int points, ResearchServerComponen { RaiseLocalEvent(client, ref ev); } - Dirty(component); + Dirty(uid, component); } } diff --git a/Content.Server/Research/Systems/ResearchSystem.Technology.cs b/Content.Server/Research/Systems/ResearchSystem.Technology.cs index 107d51ccd8c..9bd71cf7c6e 100644 --- a/Content.Server/Research/Systems/ResearchSystem.Technology.cs +++ b/Content.Server/Research/Systems/ResearchSystem.Technology.cs @@ -21,7 +21,7 @@ public void Sync(EntityUid primaryUid, EntityUid otherUid, TechnologyDatabaseCom primaryDb.UnlockedTechnologies = otherDb.UnlockedTechnologies; primaryDb.UnlockedRecipes = otherDb.UnlockedRecipes; - Dirty(primaryDb); + Dirty(primaryUid, primaryDb); var ev = new TechnologyDatabaseModifiedEvent(); RaiseLocalEvent(primaryUid, ref ev); @@ -125,7 +125,7 @@ public void AddTechnology(EntityUid uid, TechnologyPrototype technology, Technol continue; component.UnlockedRecipes.Add(unlock); } - Dirty(component); + Dirty(uid, component); var ev = new TechnologyDatabaseModifiedEvent(); RaiseLocalEvent(uid, ref ev); @@ -144,7 +144,7 @@ public void AddLatheRecipe(EntityUid uid, string recipe, TechnologyDatabaseCompo return; component.UnlockedRecipes.Add(recipe); - Dirty(component); + Dirty(uid, component); var ev = new TechnologyDatabaseModifiedEvent(); RaiseLocalEvent(uid, ref ev); @@ -185,6 +185,6 @@ private void OnDatabaseRegistrationChanged(EntityUid uid, TechnologyDatabaseComp component.SupportedDisciplines = new List<string>(); component.UnlockedTechnologies = new List<string>(); component.UnlockedRecipes = new List<string>(); - Dirty(component); + Dirty(uid, component); } } diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.cs index 428d1ecb75e..595de100e86 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.cs @@ -141,7 +141,7 @@ public bool ChangeEssenceAmount(EntityUid uid, FixedPoint2 amount, RevenantCompo if (TryComp<StoreComponent>(uid, out var store)) _store.UpdateUserInterface(uid, uid, store); - _alerts.ShowAlert(uid, AlertType.Essence); + _alerts.ShowAlert(uid, component.EssenceAlert); if (component.Essence <= 0) { diff --git a/Content.Server/Salvage/SalvageSystem.Runner.cs b/Content.Server/Salvage/SalvageSystem.Runner.cs index 23607e2bdc5..9b15ee30adc 100644 --- a/Content.Server/Salvage/SalvageSystem.Runner.cs +++ b/Content.Server/Salvage/SalvageSystem.Runner.cs @@ -151,8 +151,12 @@ private void UpdateRunner() } else if (comp.Stream == null && remaining < audioLength) { - var audio = _audio.PlayPvs(comp.Sound, uid).Value; - comp.Stream = audio.Entity; + var audio = _audio.PlayPvs(comp.Sound, uid); + + if (audio == null) + continue; + + comp.Stream = audio!.Value.Entity; _audio.SetMapAudio(audio); comp.Stage = ExpeditionStage.MusicCountdown; Dirty(uid, comp); diff --git a/Content.Server/Shadowkin/ShadowkinSystem.cs b/Content.Server/Shadowkin/ShadowkinSystem.cs index 83461e7a7fe..96bd09db276 100644 --- a/Content.Server/Shadowkin/ShadowkinSystem.cs +++ b/Content.Server/Shadowkin/ShadowkinSystem.cs @@ -55,7 +55,7 @@ private void OnEyeColorChange(EntityUid uid, ShadowkinComponent component, EyeCo component.OldEyeColor = humanoid.EyeColor; humanoid.EyeColor = component.BlackEyeColor; - Dirty(humanoid); + Dirty(uid, humanoid); } private void OnExamined(EntityUid uid, ShadowkinComponent component, ExaminedEvent args) @@ -89,10 +89,10 @@ public void UpdateShadowkinAlert(EntityUid uid, ShadowkinComponent component) if (TryComp<PsionicComponent>(uid, out var magic)) { var severity = (short) ContentHelpers.RoundToLevels(magic.Mana, magic.MaxMana, 8); - _alerts.ShowAlert(uid, AlertType.ShadowkinPower, severity); + _alerts.ShowAlert(uid, component.ShadowkinPowerAlert, severity); } else - _alerts.ClearAlert(uid, AlertType.ShadowkinPower); + _alerts.ClearAlert(uid, component.ShadowkinPowerAlert); } private void OnAttemptPowerUse(EntityUid uid, ShadowkinComponent component, OnAttemptPowerUseEvent args) @@ -115,7 +115,7 @@ private void OnManaUpdate(EntityUid uid, ShadowkinComponent component, ref OnMan if (magic.Mana <= component.BlackEyeMana) ApplyBlackEye(uid); - Dirty(magic); // Update Shadowkin Overlay. + Dirty(uid, magic); // Update Shadowkin Overlay. UpdateShadowkinAlert(uid, component); } @@ -141,7 +141,7 @@ private void OnMindbreak(EntityUid uid, ShadowkinComponent component, ref OnMind { component.OldEyeColor = humanoid.EyeColor; humanoid.EyeColor = component.BlackEyeColor; - Dirty(humanoid); + Dirty(uid, humanoid); } if (component.BlackeyeSpawn) @@ -162,7 +162,7 @@ private void OnRejuvenate(EntityUid uid, ShadowkinComponent component, Rejuvenat if (TryComp<HumanoidAppearanceComponent>(uid, out var humanoid)) { humanoid.EyeColor = component.OldEyeColor; - Dirty(humanoid); + Dirty(uid, humanoid); } EnsureComp<PsionicComponent>(uid, out var magic); diff --git a/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs index 6f24208c3a6..5550201202f 100644 --- a/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs @@ -317,12 +317,12 @@ public void AddPilot(EntityUid uid, EntityUid entity, ShuttleConsoleComponent co component.SubscribedPilots.Add(entity); - _alertsSystem.ShowAlert(entity, AlertType.PilotingShuttle); + _alertsSystem.ShowAlert(entity, pilotComponent.PilotingAlert); pilotComponent.Console = uid; ActionBlockerSystem.UpdateCanMove(entity); pilotComponent.Position = EntityManager.GetComponent<TransformComponent>(entity).Coordinates; - Dirty(pilotComponent); + Dirty(entity, pilotComponent); } public void RemovePilot(EntityUid pilotUid, PilotComponent pilotComponent) @@ -339,7 +339,7 @@ public void RemovePilot(EntityUid pilotUid, PilotComponent pilotComponent) if (!helm.SubscribedPilots.Remove(pilotUid)) return; - _alertsSystem.ClearAlert(pilotUid, AlertType.PilotingShuttle); + _alertsSystem.ClearAlert(pilotUid, pilotComponent.PilotingAlert); _popup.PopupEntity(Loc.GetString("shuttle-pilot-end"), pilotUid, pilotUid); diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index 11cc16e0cd0..fe8ec7baeed 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -81,6 +81,8 @@ public sealed partial class ShuttleSystem private void InitializeFTL() { SubscribeLocalEvent<StationPostInitEvent>(OnStationPostInit); + SubscribeLocalEvent<FTLComponent, ComponentShutdown>(OnFtlShutdown); + _bodyQuery = GetEntityQuery<BodyComponent>(); _buckleQuery = GetEntityQuery<BuckleComponent>(); _beaconQuery = GetEntityQuery<FTLBeaconComponent>(); @@ -97,6 +99,12 @@ private void InitializeFTL() _cfg.OnValueChanged(CCVars.HyperspaceKnockdownTime, time => _hyperspaceKnockdownTime = TimeSpan.FromSeconds(time), true); } + private void OnFtlShutdown(Entity<FTLComponent> ent, ref ComponentShutdown args) + { + Del(ent.Comp.VisualizerEntity); + ent.Comp.VisualizerEntity = null; + } + private void OnStationPostInit(ref StationPostInitEvent ev) { // Add all grid maps as ftl destinations that anyone can FTL to. @@ -343,7 +351,11 @@ private bool TrySetupFTL(EntityUid uid, ShuttleComponent shuttle, [NotNullWhen(t component = AddComp<FTLComponent>(uid); component.State = FTLState.Starting; var audio = _audio.PlayPvs(_startupSound, uid); - audio.Value.Component.Flags |= AudioFlags.GridAudio; + + if (audio == null) + return false; + + audio!.Value.Component.Flags |= AudioFlags.GridAudio; if (_physicsQuery.TryGetComponent(uid, out var gridPhysics)) { @@ -422,8 +434,16 @@ private void UpdateFTLTravelling(Entity<FTLComponent, ShuttleComponent> entity) var comp = entity.Comp1; comp.StateTime = StartEndTime.FromCurTime(_gameTiming, DefaultArrivalTime); comp.State = FTLState.Arriving; - // TODO: Arrival effects - // For now we'll just use the ss13 bubbles but we can do fancier. + + if (entity.Comp1.VisualizerProto != null) + { + comp.VisualizerEntity = SpawnAtPosition(entity.Comp1.VisualizerProto, entity.Comp1.TargetCoordinates); + var visuals = Comp<FtlVisualizerComponent>(comp.VisualizerEntity.Value); + visuals.Grid = entity.Owner; + Dirty(comp.VisualizerEntity.Value, visuals); + _transform.SetLocalRotation(comp.VisualizerEntity.Value, entity.Comp1.TargetAngle); + _pvs.AddGlobalOverride(comp.VisualizerEntity.Value); + } _thruster.DisableLinearThrusters(shuttle); _thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.South); @@ -509,7 +529,11 @@ private void UpdateFTLArriving(Entity<FTLComponent, ShuttleComponent> entity) comp.TravelStream = _audio.Stop(comp.TravelStream); var audio = _audio.PlayPvs(_arrivalSound, uid); - audio.Value.Component.Flags |= AudioFlags.GridAudio; + + if (audio == null) + return; + + audio!.Value.Component.Flags |= AudioFlags.GridAudio; // TODO: Shitcode til engine fix if (_physicsQuery.TryGetComponent(uid, out var gridPhysics)) diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index 6fe2324d51e..a10d0d56144 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -11,6 +11,7 @@ using Content.Shared.Throwing; using JetBrains.Annotations; using Robust.Server.GameObjects; +using Robust.Server.GameStates; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; @@ -40,6 +41,7 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem [Dependency] private readonly FixtureSystem _fixtures = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; [Dependency] private readonly MetaDataSystem _metadata = default!; + [Dependency] private readonly PvsOverrideSystem _pvs = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; diff --git a/Content.Server/Silicon/Charge/Systems/SiliconChargeSystem.cs b/Content.Server/Silicon/Charge/Systems/SiliconChargeSystem.cs index d8b034a69f5..444b65530b2 100644 --- a/Content.Server/Silicon/Charge/Systems/SiliconChargeSystem.cs +++ b/Content.Server/Silicon/Charge/Systems/SiliconChargeSystem.cs @@ -91,10 +91,10 @@ public override void Update(float frameTime) if (!TryGetSiliconBattery(silicon, out var batteryComp)) { UpdateChargeState(silicon, 0, siliconComp); - if (_alerts.IsShowingAlert(silicon, AlertType.BorgBattery)) + if (_alerts.IsShowingAlert(silicon, siliconComp.BatteryAlert)) { - _alerts.ClearAlert(silicon, AlertType.BorgBattery); - _alerts.ShowAlert(silicon, AlertType.BorgBatteryNone); + _alerts.ClearAlert(silicon, siliconComp.BatteryAlert); + _alerts.ShowAlert(silicon, siliconComp.NoBatteryAlert); } continue; } @@ -142,10 +142,10 @@ public void UpdateChargeState(EntityUid uid, short chargePercent, SiliconCompone _moveMod.RefreshMovementSpeedModifiers(uid); // If the battery was replaced and the no battery indicator is showing, replace the indicator - if (_alerts.IsShowingAlert(uid, AlertType.BorgBatteryNone) && chargePercent != 0) + if (_alerts.IsShowingAlert(uid, component.NoBatteryAlert) && chargePercent != 0) { - _alerts.ClearAlert(uid, AlertType.BorgBatteryNone); - _alerts.ShowAlert(uid, AlertType.BorgBattery, chargePercent); + _alerts.ClearAlert(uid, component.NoBatteryAlert); + _alerts.ShowAlert(uid, component.BatteryAlert, chargePercent); } } diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 75f25a3a922..97adfd00eb4 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -84,7 +84,7 @@ public override void Initialize() private void OnMapInit(EntityUid uid, BorgChassisComponent component, MapInitEvent args) { - UpdateBatteryAlert(uid); + UpdateBatteryAlert((uid, component)); _movementSpeedModifier.RefreshMovementSpeedModifiers(uid); } @@ -183,7 +183,7 @@ private void OnMobStateChanged(EntityUid uid, BorgChassisComponent component, Mo private void OnPowerCellChanged(EntityUid uid, BorgChassisComponent component, PowerCellChangedEvent args) { - UpdateBatteryAlert(uid); + UpdateBatteryAlert((uid, component)); if (!TryComp<PowerCellDrawComponent>(uid, out var draw)) return; @@ -256,12 +256,12 @@ private void OnBrainPointAttempt(EntityUid uid, BorgBrainComponent component, Po args.Cancel(); } - private void UpdateBatteryAlert(EntityUid uid, PowerCellSlotComponent? slotComponent = null) + private void UpdateBatteryAlert(Entity<BorgChassisComponent> ent, PowerCellSlotComponent? slotComponent = null) { - if (!_powerCell.TryGetBatteryFromSlot(uid, out var battery, slotComponent)) + if (!_powerCell.TryGetBatteryFromSlot(ent, out var battery, slotComponent)) { - _alerts.ClearAlert(uid, AlertType.BorgBattery); - _alerts.ShowAlert(uid, AlertType.BorgBatteryNone); + _alerts.ClearAlert(ent, ent.Comp.BatteryAlert); + _alerts.ShowAlert(ent, ent.Comp.NoBatteryAlert); return; } @@ -269,13 +269,13 @@ private void UpdateBatteryAlert(EntityUid uid, PowerCellSlotComponent? slotCompo // we make sure 0 only shows if they have absolutely no battery. // also account for floating point imprecision - if (chargePercent == 0 && _powerCell.HasDrawCharge(uid, cell: slotComponent)) + if (chargePercent == 0 && _powerCell.HasDrawCharge(ent, cell: slotComponent)) { chargePercent = 1; } - _alerts.ClearAlert(uid, AlertType.BorgBatteryNone); - _alerts.ShowAlert(uid, AlertType.BorgBattery, chargePercent); + _alerts.ClearAlert(ent, ent.Comp.NoBatteryAlert); + _alerts.ShowAlert(ent, ent.Comp.BatteryAlert, chargePercent); } /// <summary> @@ -288,7 +288,7 @@ public void EnableBorgAbilities(EntityUid uid, BorgChassisComponent component, P component.Activated = true; InstallAllModules(uid, component); - Dirty(component); + Dirty(uid, component); _movementSpeedModifier.RefreshMovementSpeedModifiers(uid); } @@ -302,7 +302,7 @@ public void DisableBorgAbilities(EntityUid uid, BorgChassisComponent component) component.Activated = false; DisableAllModules(uid, component); - Dirty(component); + Dirty(uid, component); _movementSpeedModifier.RefreshMovementSpeedModifiers(uid); } diff --git a/Content.Server/Spawners/Components/EntityTableSpawnerComponent.cs b/Content.Server/Spawners/Components/EntityTableSpawnerComponent.cs new file mode 100644 index 00000000000..d122eb098b6 --- /dev/null +++ b/Content.Server/Spawners/Components/EntityTableSpawnerComponent.cs @@ -0,0 +1,30 @@ +using Content.Server.Spawners.EntitySystems; +using Content.Shared.EntityTable.EntitySelectors; +using Robust.Shared.Prototypes; + +namespace Content.Server.Spawners.Components; + +[RegisterComponent, EntityCategory("Spawner"), Access(typeof(ConditionalSpawnerSystem))] +public sealed partial class EntityTableSpawnerComponent : Component +{ + /// <summary> + /// Table that determines what gets spawned. + /// </summary> + [DataField(required: true)] + public EntityTableSelector Table = default!; + + /// <summary> + /// Scatter of entity spawn coordinates + /// </summary> + [DataField] + public float Offset = 0.2f; + + /// <summary> + /// A variable meaning whether the spawn will + /// be able to be used again or whether + /// it will be destroyed after the first use + /// </summary> + [DataField] + public bool DeleteSpawnerAfterSpawn = true; +} + diff --git a/Content.Server/Spawners/EntitySystems/ConditionalSpawnerSystem.cs b/Content.Server/Spawners/EntitySystems/ConditionalSpawnerSystem.cs index 75f86187989..f176f1b1358 100644 --- a/Content.Server/Spawners/EntitySystems/ConditionalSpawnerSystem.cs +++ b/Content.Server/Spawners/EntitySystems/ConditionalSpawnerSystem.cs @@ -1,9 +1,11 @@ using System.Numerics; using Content.Server.GameTicking; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Spawners.Components; +using Content.Shared.EntityTable; +using Content.Shared.GameTicking.Components; using JetBrains.Annotations; +using Robust.Shared.Map; using Robust.Shared.Random; namespace Content.Server.Spawners.EntitySystems @@ -13,6 +15,7 @@ public sealed class ConditionalSpawnerSystem : EntitySystem { [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly GameTicker _ticker = default!; + [Dependency] private readonly EntityTableSystem _entityTable = default!; public override void Initialize() { @@ -21,6 +24,7 @@ public override void Initialize() SubscribeLocalEvent<GameRuleStartedEvent>(OnRuleStarted); SubscribeLocalEvent<ConditionalSpawnerComponent, MapInitEvent>(OnCondSpawnMapInit); SubscribeLocalEvent<RandomSpawnerComponent, MapInitEvent>(OnRandSpawnMapInit); + SubscribeLocalEvent<EntityTableSpawnerComponent, MapInitEvent>(OnEntityTableSpawnMapInit); } private void OnCondSpawnMapInit(EntityUid uid, ConditionalSpawnerComponent component, MapInitEvent args) @@ -35,6 +39,13 @@ private void OnRandSpawnMapInit(EntityUid uid, RandomSpawnerComponent component, QueueDel(uid); } + private void OnEntityTableSpawnMapInit(Entity<EntityTableSpawnerComponent> ent, ref MapInitEvent args) + { + Spawn(ent); + if (ent.Comp.DeleteSpawnerAfterSpawn && !TerminatingOrDeleted(ent) && Exists(ent)) + QueueDel(ent); + } + private void OnRuleStarted(ref GameRuleStartedEvent args) { var query = EntityQueryEnumerator<ConditionalSpawnerComponent>(); @@ -110,5 +121,23 @@ private void Spawn(EntityUid uid, RandomSpawnerComponent component) EntityManager.SpawnEntity(_robustRandom.Pick(component.Prototypes), coordinates); } + + private void Spawn(Entity<EntityTableSpawnerComponent> ent) + { + if (TerminatingOrDeleted(ent) || !Exists(ent)) + return; + + var coords = Transform(ent).Coordinates; + + var spawns = _entityTable.GetSpawns(ent.Comp.Table); + foreach (var proto in spawns) + { + var xOffset = _robustRandom.NextFloat(-ent.Comp.Offset, ent.Comp.Offset); + var yOffset = _robustRandom.NextFloat(-ent.Comp.Offset, ent.Comp.Offset); + var trueCoords = coords.Offset(new Vector2(xOffset, yOffset)); + + Spawn(proto, trueCoords); + } + } } } diff --git a/Content.Server/Sprite/RandomSpriteSystem.cs b/Content.Server/Sprite/RandomSpriteSystem.cs index 5d04dd2f5a6..7f81f4bdd45 100644 --- a/Content.Server/Sprite/RandomSpriteSystem.cs +++ b/Content.Server/Sprite/RandomSpriteSystem.cs @@ -63,7 +63,7 @@ private void OnMapInit(EntityUid uid, RandomSpriteComponent component, MapInitEv } } - Dirty(component); + Dirty(uid, component); } private void OnGetState(EntityUid uid, RandomSpriteComponent component, ref ComponentGetState args) diff --git a/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs b/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs index b9eb3b7b09d..f2704d53f4c 100644 --- a/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs +++ b/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs @@ -1,11 +1,11 @@ using System.Linq; using Content.Server.Administration; -using Content.Server.GameTicking.Components; +using Content.Server.GameTicking; using Content.Server.GameTicking.Rules; -using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Shared.Administration; using Content.Shared.CCVar; +using Content.Shared.GameTicking.Components; using JetBrains.Annotations; using Robust.Shared.Configuration; using Robust.Shared.Random; diff --git a/Content.Server/StationEvents/Events/AlertLevelInterceptionRule.cs b/Content.Server/StationEvents/Events/AlertLevelInterceptionRule.cs index a78a542d3b3..916d7d16883 100644 --- a/Content.Server/StationEvents/Events/AlertLevelInterceptionRule.cs +++ b/Content.Server/StationEvents/Events/AlertLevelInterceptionRule.cs @@ -1,6 +1,6 @@ -using Content.Server.GameTicking.Components; using Content.Server.StationEvents.Components; using Content.Server.AlertLevel; +using Content.Shared.GameTicking.Components; namespace Content.Server.StationEvents.Events; @@ -20,4 +20,4 @@ protected override void Started(EntityUid uid, AlertLevelInterceptionRuleCompone _alertLevelSystem.SetLevel(chosenStation.Value, component.AlertLevel, true, true, true); } -} \ No newline at end of file +} diff --git a/Content.Server/StationEvents/Events/AnomalySpawnRule.cs b/Content.Server/StationEvents/Events/AnomalySpawnRule.cs index 98d5aa76a6a..aa2fa74c483 100644 --- a/Content.Server/StationEvents/Events/AnomalySpawnRule.cs +++ b/Content.Server/StationEvents/Events/AnomalySpawnRule.cs @@ -1,9 +1,8 @@ using Content.Server.Anomaly; -using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; +using Content.Server.Announcements.Systems; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; -using Content.Server.Announcements.Systems; +using Content.Shared.GameTicking.Components; using Robust.Shared.Player; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs b/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs index 29c18976576..3983981ff46 100644 --- a/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs +++ b/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs @@ -1,6 +1,5 @@ -using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; using Robust.Shared.Random; using Content.Server.Announcements.Systems; using Robust.Shared.Player; diff --git a/Content.Server/StationEvents/Events/BluespaceLockerRule.cs b/Content.Server/StationEvents/Events/BluespaceLockerRule.cs index eef9850e739..b19485bc31e 100644 --- a/Content.Server/StationEvents/Events/BluespaceLockerRule.cs +++ b/Content.Server/StationEvents/Events/BluespaceLockerRule.cs @@ -1,4 +1,3 @@ -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Resist; using Content.Server.Station.Components; @@ -6,6 +5,7 @@ using Content.Server.Storage.Components; using Content.Server.Storage.EntitySystems; using Content.Shared.Access.Components; +using Content.Shared.GameTicking.Components; using Content.Shared.Coordinates; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/StationEvents/Events/BreakerFlipRule.cs b/Content.Server/StationEvents/Events/BreakerFlipRule.cs index 3b2368556be..bc657657f66 100644 --- a/Content.Server/StationEvents/Events/BreakerFlipRule.cs +++ b/Content.Server/StationEvents/Events/BreakerFlipRule.cs @@ -1,9 +1,8 @@ -using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; using JetBrains.Annotations; using Content.Server.Announcements.Systems; using Robust.Shared.Player; diff --git a/Content.Server/StationEvents/Events/BureaucraticErrorRule.cs b/Content.Server/StationEvents/Events/BureaucraticErrorRule.cs index 282e28e4991..6600b0623fd 100644 --- a/Content.Server/StationEvents/Events/BureaucraticErrorRule.cs +++ b/Content.Server/StationEvents/Events/BureaucraticErrorRule.cs @@ -1,9 +1,9 @@ using System.Linq; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Components; using Content.Server.Station.Systems; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; using JetBrains.Annotations; using Robust.Shared.Random; diff --git a/Content.Server/StationEvents/Events/CargoGiftsRule.cs b/Content.Server/StationEvents/Events/CargoGiftsRule.cs index 550f799b27e..b2170e06625 100644 --- a/Content.Server/StationEvents/Events/CargoGiftsRule.cs +++ b/Content.Server/StationEvents/Events/CargoGiftsRule.cs @@ -2,10 +2,9 @@ using Content.Server.Cargo.Components; using Content.Server.Cargo.Systems; using Content.Server.GameTicking; -using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; using Robust.Shared.Prototypes; using Content.Server.Announcements.Systems; using Robust.Shared.Player; diff --git a/Content.Server/StationEvents/Events/ClericalErrorRule.cs b/Content.Server/StationEvents/Events/ClericalErrorRule.cs index 854ee685b33..e52c2c05aaf 100644 --- a/Content.Server/StationEvents/Events/ClericalErrorRule.cs +++ b/Content.Server/StationEvents/Events/ClericalErrorRule.cs @@ -1,9 +1,9 @@ -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Server.StationRecords; using Content.Server.StationRecords.Systems; using Content.Shared.StationRecords; +using Content.Shared.GameTicking.Components; using Robust.Shared.Random; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/StationEvents/Events/FalseAlarmRule.cs b/Content.Server/StationEvents/Events/FalseAlarmRule.cs index 2d129b35584..8c8bf0aadc9 100644 --- a/Content.Server/StationEvents/Events/FalseAlarmRule.cs +++ b/Content.Server/StationEvents/Events/FalseAlarmRule.cs @@ -1,7 +1,6 @@ using System.Linq; -using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; using JetBrains.Annotations; using Robust.Shared.Player; using Robust.Shared.Random; diff --git a/Content.Server/StationEvents/Events/FreeProberRule.cs b/Content.Server/StationEvents/Events/FreeProberRule.cs index a5dfdd6b6ea..04795bdf4e9 100644 --- a/Content.Server/StationEvents/Events/FreeProberRule.cs +++ b/Content.Server/StationEvents/Events/FreeProberRule.cs @@ -1,4 +1,4 @@ -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Robust.Shared.Map; using Robust.Shared.Random; using Content.Server.GameTicking.Rules.Components; @@ -8,13 +8,14 @@ using Content.Server.Psionics.Glimmer; using Content.Shared.Construction.EntitySystems; using Content.Shared.Psionics.Glimmer; +using Robust.Shared.Map.Components; namespace Content.Server.StationEvents.Events; internal sealed class FreeProberRule : StationEventSystem<FreeProberRuleComponent> { [Dependency] private readonly IRobustRandom _robustRandom = default!; - [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly SharedMapSystem _sharedMapSystem = default!; [Dependency] private readonly AnchorableSystem _anchorable = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; [Dependency] private readonly StationSystem _stationSystem = default!; @@ -59,10 +60,14 @@ protected override void Started(EntityUid uid, FreeProberRuleComponent component var coordinates = xform.Coordinates; var gridUid = xform.GridUid; - if (!_mapManager.TryGetGrid(gridUid, out var grid)) + + if (gridUid == null) + continue; + + if (!TryComp<MapGridComponent>(gridUid, out var grid)) continue; - var tileIndices = grid.TileIndicesFor(coordinates); + var tileIndices = _sharedMapSystem.TileIndicesFor((EntityUid) gridUid, grid, coordinates); for (var i = 0; i < SpawnDirections; i++) { @@ -73,7 +78,7 @@ protected override void Started(EntityUid uid, FreeProberRuleComponent component if (!_anchorable.TileFree(grid, offsetIndices)) continue; - Spawn(ProberPrototype, grid.GridTileToLocal(offsetIndices)); + Spawn(ProberPrototype, _sharedMapSystem.GridTileToLocal((EntityUid) gridUid, grid, offsetIndices)); return; } } diff --git a/Content.Server/StationEvents/Events/GasLeakRule.cs b/Content.Server/StationEvents/Events/GasLeakRule.cs index 1221612171d..391c407bacd 100644 --- a/Content.Server/StationEvents/Events/GasLeakRule.cs +++ b/Content.Server/StationEvents/Events/GasLeakRule.cs @@ -1,7 +1,7 @@ using Content.Server.Atmos.EntitySystems; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; using Robust.Shared.Audio; using Robust.Shared.Random; using Robust.Shared.Timing; diff --git a/Content.Server/StationEvents/Events/GlimmerEventSystem.cs b/Content.Server/StationEvents/Events/GlimmerEventSystem.cs index 3e0762c8346..37eb0410fbd 100644 --- a/Content.Server/StationEvents/Events/GlimmerEventSystem.cs +++ b/Content.Server/StationEvents/Events/GlimmerEventSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Psionics.Glimmer; using Content.Shared.Psionics.Glimmer; diff --git a/Content.Server/StationEvents/Events/GlimmerMobSpawnRule.cs b/Content.Server/StationEvents/Events/GlimmerMobSpawnRule.cs index 702147842c6..f80bc83a1e6 100644 --- a/Content.Server/StationEvents/Events/GlimmerMobSpawnRule.cs +++ b/Content.Server/StationEvents/Events/GlimmerMobSpawnRule.cs @@ -1,5 +1,5 @@ using System.Linq; -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Robust.Shared.Random; using Content.Server.GameTicking; using Content.Server.NPC.Components; diff --git a/Content.Server/StationEvents/Events/GlimmerRandomSentienceRule.cs b/Content.Server/StationEvents/Events/GlimmerRandomSentienceRule.cs index a288710356a..ee0de6fe01a 100644 --- a/Content.Server/StationEvents/Events/GlimmerRandomSentienceRule.cs +++ b/Content.Server/StationEvents/Events/GlimmerRandomSentienceRule.cs @@ -1,5 +1,5 @@ using System.Linq; -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Ghost.Roles.Components; using Content.Shared.Abilities.Psionics; diff --git a/Content.Server/StationEvents/Events/GlimmerRevenantSpawnRule.cs b/Content.Server/StationEvents/Events/GlimmerRevenantSpawnRule.cs index 152d6d9fe59..dfb7653303b 100644 --- a/Content.Server/StationEvents/Events/GlimmerRevenantSpawnRule.cs +++ b/Content.Server/StationEvents/Events/GlimmerRevenantSpawnRule.cs @@ -1,4 +1,4 @@ -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Robust.Shared.Random; using Content.Server.GameTicking.Rules.Components; using Content.Server.Psionics.Glimmer; diff --git a/Content.Server/StationEvents/Events/ImmovableRodRule.cs b/Content.Server/StationEvents/Events/ImmovableRodRule.cs index 45d6c18189c..37f912773c5 100644 --- a/Content.Server/StationEvents/Events/ImmovableRodRule.cs +++ b/Content.Server/StationEvents/Events/ImmovableRodRule.cs @@ -1,10 +1,10 @@ using System.Numerics; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.ImmovableRod; using Content.Server.StationEvents.Components; using Content.Server.Weapons.Ranged.Systems; -using Robust.Shared.Spawners; +using Content.Shared.GameTicking.Components; +using Content.Shared.Storage; using Robust.Shared.Prototypes; using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent; diff --git a/Content.Server/StationEvents/Events/IonStormRule.cs b/Content.Server/StationEvents/Events/IonStormRule.cs index 8361cc6048a..926ecc2db92 100644 --- a/Content.Server/StationEvents/Events/IonStormRule.cs +++ b/Content.Server/StationEvents/Events/IonStormRule.cs @@ -1,4 +1,3 @@ -using Content.Server.GameTicking.Components; using System.Linq; using Content.Server.Silicons.Laws; using Content.Server.Station.Components; @@ -7,6 +6,7 @@ using Content.Shared.Database; using Content.Shared.Dataset; using Content.Shared.FixedPoint; +using Content.Shared.GameTicking.Components; using Content.Shared.Random; using Content.Shared.Random.Helpers; using Content.Shared.Silicons.Laws; diff --git a/Content.Server/StationEvents/Events/KudzuGrowthRule.cs b/Content.Server/StationEvents/Events/KudzuGrowthRule.cs index 5b56e03846f..42c57ffcaae 100644 --- a/Content.Server/StationEvents/Events/KudzuGrowthRule.cs +++ b/Content.Server/StationEvents/Events/KudzuGrowthRule.cs @@ -1,6 +1,6 @@ -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/StationEvents/Events/MassHallucinationsRule.cs b/Content.Server/StationEvents/Events/MassHallucinationsRule.cs index 2239db7f701..c35ba94727f 100644 --- a/Content.Server/StationEvents/Events/MassHallucinationsRule.cs +++ b/Content.Server/StationEvents/Events/MassHallucinationsRule.cs @@ -1,7 +1,7 @@ -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Server.Traits.Assorted; +using Content.Shared.GameTicking.Components; using Content.Shared.Mind.Components; using Content.Shared.Traits.Assorted.Components; diff --git a/Content.Server/StationEvents/Events/MassMindSwapRule.cs b/Content.Server/StationEvents/Events/MassMindSwapRule.cs index beb08eb8a79..0839b217293 100644 --- a/Content.Server/StationEvents/Events/MassMindSwapRule.cs +++ b/Content.Server/StationEvents/Events/MassMindSwapRule.cs @@ -1,7 +1,7 @@ using Robust.Server.GameObjects; using Robust.Shared.Random; using Content.Server.Abilities.Psionics; -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Psionics; using Content.Server.StationEvents.Components; diff --git a/Content.Server/StationEvents/Events/MeteorSwarmRule.cs b/Content.Server/StationEvents/Events/MeteorSwarmRule.cs index 455011259dc..b97cde86a02 100644 --- a/Content.Server/StationEvents/Events/MeteorSwarmRule.cs +++ b/Content.Server/StationEvents/Events/MeteorSwarmRule.cs @@ -1,7 +1,7 @@ using System.Numerics; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; diff --git a/Content.Server/StationEvents/Events/NinjaSpawnRule.cs b/Content.Server/StationEvents/Events/NinjaSpawnRule.cs index d9d68a386cf..9cbc193ce61 100644 --- a/Content.Server/StationEvents/Events/NinjaSpawnRule.cs +++ b/Content.Server/StationEvents/Events/NinjaSpawnRule.cs @@ -1,8 +1,8 @@ -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Ninja.Systems; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; using Robust.Shared.Map; using Robust.Shared.Map.Components; diff --git a/Content.Server/StationEvents/Events/NoosphericFryRule.cs b/Content.Server/StationEvents/Events/NoosphericFryRule.cs index 85f98d6f4be..7e025f61e17 100644 --- a/Content.Server/StationEvents/Events/NoosphericFryRule.cs +++ b/Content.Server/StationEvents/Events/NoosphericFryRule.cs @@ -3,7 +3,7 @@ using Robust.Shared.Player; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Content.Shared.Construction.EntitySystems; using Content.Server.GameTicking.Rules.Components; using Content.Server.Popups; @@ -18,6 +18,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Psionics.Glimmer; using Robust.Shared.Audio.Systems; +using Robust.Shared.Map.Components; namespace Content.Server.StationEvents.Events; @@ -26,7 +27,7 @@ namespace Content.Server.StationEvents.Events; /// </summary> internal sealed class NoosphericFryRule : StationEventSystem<NoosphericFryRuleComponent> { - [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly SharedMapSystem _sharedMapSystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; @@ -111,10 +112,14 @@ protected override void Started(EntityUid uid, NoosphericFryRuleComponent compon { var coordinates = xform.Coordinates; var gridUid = xform.GridUid; - if (!_mapManager.TryGetGrid(gridUid, out var grid)) + + if (gridUid == null) + continue; + + if (!TryComp<MapGridComponent>(gridUid, out var grid)) continue; - var tileIndices = grid.TileIndicesFor(coordinates); + var tileIndices = _sharedMapSystem.TileIndicesFor((EntityUid) gridUid, grid, coordinates); if (_anchorableSystem.TileFree(grid, tileIndices, physics.CollisionLayer, physics.CollisionMask)) _transformSystem.AnchorEntity(reactive, xform); diff --git a/Content.Server/StationEvents/Events/NoosphericStormRule.cs b/Content.Server/StationEvents/Events/NoosphericStormRule.cs index 1de8bad89b5..b2777346ae0 100644 --- a/Content.Server/StationEvents/Events/NoosphericStormRule.cs +++ b/Content.Server/StationEvents/Events/NoosphericStormRule.cs @@ -1,6 +1,6 @@ using Robust.Shared.Random; using Content.Server.Abilities.Psionics; -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Server.Psionics; diff --git a/Content.Server/StationEvents/Events/NoosphericZapRule.cs b/Content.Server/StationEvents/Events/NoosphericZapRule.cs index 96c33612036..3819d1203a0 100644 --- a/Content.Server/StationEvents/Events/NoosphericZapRule.cs +++ b/Content.Server/StationEvents/Events/NoosphericZapRule.cs @@ -1,4 +1,4 @@ -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Popups; using Content.Server.Psionics; diff --git a/Content.Server/StationEvents/Events/PirateRadioSpawnRule.cs b/Content.Server/StationEvents/Events/PirateRadioSpawnRule.cs index e6d36839f92..51a4438583f 100644 --- a/Content.Server/StationEvents/Events/PirateRadioSpawnRule.cs +++ b/Content.Server/StationEvents/Events/PirateRadioSpawnRule.cs @@ -8,7 +8,7 @@ using Content.Shared.Salvage; using Content.Shared.Random.Helpers; using System.Linq; -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Content.Shared.CCVar; using Robust.Shared.Serialization.Manager; using Content.Shared.Parallax.Biomes; diff --git a/Content.Server/StationEvents/Events/PowerGridCheckRule.cs b/Content.Server/StationEvents/Events/PowerGridCheckRule.cs index b0a0bbc9fe0..e09c88673fb 100644 --- a/Content.Server/StationEvents/Events/PowerGridCheckRule.cs +++ b/Content.Server/StationEvents/Events/PowerGridCheckRule.cs @@ -1,10 +1,10 @@ using System.Threading; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; using JetBrains.Annotations; using Robust.Shared.Audio; using Robust.Shared.Player; diff --git a/Content.Server/StationEvents/Events/PsionicCatGotYourTongueRule.cs b/Content.Server/StationEvents/Events/PsionicCatGotYourTongueRule.cs index b92097b28d0..f39d87d4e9d 100644 --- a/Content.Server/StationEvents/Events/PsionicCatGotYourTongueRule.cs +++ b/Content.Server/StationEvents/Events/PsionicCatGotYourTongueRule.cs @@ -1,4 +1,4 @@ -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Robust.Shared.Random; using Robust.Shared.Player; using Content.Server.GameTicking.Rules.Components; diff --git a/Content.Server/StationEvents/Events/RandomEntityStorageSpawnRule.cs b/Content.Server/StationEvents/Events/RandomEntityStorageSpawnRule.cs index 87d50fc8b2a..a9f27938180 100644 --- a/Content.Server/StationEvents/Events/RandomEntityStorageSpawnRule.cs +++ b/Content.Server/StationEvents/Events/RandomEntityStorageSpawnRule.cs @@ -1,8 +1,8 @@ -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Server.Storage.Components; using Content.Server.Storage.EntitySystems; +using Content.Shared.GameTicking.Components; using Robust.Shared.Map; using Robust.Shared.Random; diff --git a/Content.Server/StationEvents/Events/RandomSentienceRule.cs b/Content.Server/StationEvents/Events/RandomSentienceRule.cs index 7b9173241f7..2fb733e1a67 100644 --- a/Content.Server/StationEvents/Events/RandomSentienceRule.cs +++ b/Content.Server/StationEvents/Events/RandomSentienceRule.cs @@ -1,10 +1,9 @@ using System.Linq; -using Content.Server.GameTicking.Components; -using Content.Server.GameTicking.Rules.Components; -using Content.Server.Ghost.Roles.Components; -using Content.Server.StationEvents.Components; using Content.Server.Announcements.Systems; +using Content.Server.Ghost.Roles.Components; using Content.Server.Station.Components; +using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/StationEvents/Events/RandomSpawnRule.cs b/Content.Server/StationEvents/Events/RandomSpawnRule.cs index 77744d44e46..e904c24ba60 100644 --- a/Content.Server/StationEvents/Events/RandomSpawnRule.cs +++ b/Content.Server/StationEvents/Events/RandomSpawnRule.cs @@ -1,6 +1,6 @@ -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/StationEvents/Events/SolarFlareRule.cs b/Content.Server/StationEvents/Events/SolarFlareRule.cs index 0370b4ee61d..19f6e393d20 100644 --- a/Content.Server/StationEvents/Events/SolarFlareRule.cs +++ b/Content.Server/StationEvents/Events/SolarFlareRule.cs @@ -1,4 +1,3 @@ -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Radio; using Robust.Shared.Random; @@ -8,6 +7,7 @@ using Content.Shared.Radio.Components; using Content.Shared.Doors.Components; using Content.Shared.Doors.Systems; +using Content.Shared.GameTicking.Components; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/StationEvents/Events/StationEventSystem.cs b/Content.Server/StationEvents/Events/StationEventSystem.cs index 040ebad2260..a88258b9ad9 100644 --- a/Content.Server/StationEvents/Events/StationEventSystem.cs +++ b/Content.Server/StationEvents/Events/StationEventSystem.cs @@ -1,12 +1,12 @@ using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Chat.Systems; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules; using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Systems; using Content.Server.StationEvents.Components; using Content.Shared.Database; +using Content.Shared.GameTicking.Components; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; using Robust.Shared.Player; diff --git a/Content.Server/StationEvents/Events/VentClogRule.cs b/Content.Server/StationEvents/Events/VentClogRule.cs index 867f41dcccf..043ea0375aa 100644 --- a/Content.Server/StationEvents/Events/VentClogRule.cs +++ b/Content.Server/StationEvents/Events/VentClogRule.cs @@ -6,9 +6,9 @@ using Robust.Shared.Random; using System.Linq; using Content.Server.Fluids.EntitySystems; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; +using Content.Shared.GameTicking.Components; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/StationEvents/Events/VentCrittersRule.cs b/Content.Server/StationEvents/Events/VentCrittersRule.cs index c2605039bce..fba9cfa6a60 100644 --- a/Content.Server/StationEvents/Events/VentCrittersRule.cs +++ b/Content.Server/StationEvents/Events/VentCrittersRule.cs @@ -1,7 +1,7 @@ -using Content.Server.GameTicking.Components; using Content.Server.StationEvents.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Components; +using Content.Shared.GameTicking.Components; using Content.Shared.Storage; using Robust.Shared.Map; using Robust.Shared.Random; diff --git a/Content.Server/StationEvents/OscillatingStationEventScheduler.cs b/Content.Server/StationEvents/OscillatingStationEventScheduler.cs index 1e6dbd14a18..a9b9de586ee 100644 --- a/Content.Server/StationEvents/OscillatingStationEventScheduler.cs +++ b/Content.Server/StationEvents/OscillatingStationEventScheduler.cs @@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.GameTicking; using Content.Server.GameTicking.Rules; -using Content.Server.GameTicking.Components; +using Content.Shared.GameTicking.Components; using Content.Server.StationEvents.Components; using Content.Shared.CCVar; using Robust.Shared.Configuration; diff --git a/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs b/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs index a6c38ef765f..545064b39fe 100644 --- a/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs +++ b/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs @@ -1,10 +1,10 @@ using Content.Server.GameTicking; -using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Server.StationEvents.Events; using Content.Shared.CCVar; +using Content.Shared.GameTicking.Components; using Robust.Shared.Configuration; using Robust.Shared.Random; diff --git a/Content.Server/Temperature/Components/TemperatureComponent.cs b/Content.Server/Temperature/Components/TemperatureComponent.cs index ec00a570f96..3bfa12f2693 100644 --- a/Content.Server/Temperature/Components/TemperatureComponent.cs +++ b/Content.Server/Temperature/Components/TemperatureComponent.cs @@ -1,7 +1,9 @@ using Content.Server.Temperature.Systems; +using Content.Shared.Alert; using Content.Shared.Atmos; using Content.Shared.Damage; using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; namespace Content.Server.Temperature.Components; @@ -78,4 +80,10 @@ public float HeatCapacity /// </summary> [DataField] public bool TakingDamage = false; + + [DataField] + public ProtoId<AlertPrototype> HotAlert = "Hot"; + + [DataField] + public ProtoId<AlertPrototype> ColdAlert = "Cold"; } diff --git a/Content.Server/Temperature/Systems/TemperatureSystem.cs b/Content.Server/Temperature/Systems/TemperatureSystem.cs index 0f57da4b881..2f4497bdbbc 100644 --- a/Content.Server/Temperature/Systems/TemperatureSystem.cs +++ b/Content.Server/Temperature/Systems/TemperatureSystem.cs @@ -12,6 +12,7 @@ using Content.Shared.Rejuvenate; using Content.Shared.Temperature; using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; namespace Content.Server.Temperature.Systems; @@ -33,6 +34,9 @@ public sealed class TemperatureSystem : EntitySystem private float _accumulatedFrametime; + [ValidatePrototypeId<AlertCategoryPrototype>] + public const string TemperatureAlertCategory = "Temperature"; + public override void Initialize() { SubscribeLocalEvent<TemperatureComponent, OnTemperatureChangeEvent>(EnqueueDamage); @@ -181,13 +185,13 @@ private void OnRejuvenate(EntityUid uid, TemperatureComponent comp, RejuvenateEv private void ServerAlert(EntityUid uid, AlertsComponent status, OnTemperatureChangeEvent args) { - AlertType type; + ProtoId<AlertPrototype> type; float threshold; float idealTemp; if (!TryComp<TemperatureComponent>(uid, out var temperature)) { - _alerts.ClearAlertCategory(uid, AlertCategory.Temperature); + _alerts.ClearAlertCategory(uid, TemperatureAlertCategory); return; } @@ -204,12 +208,12 @@ private void ServerAlert(EntityUid uid, AlertsComponent status, OnTemperatureCha if (args.CurrentTemperature <= idealTemp) { - type = AlertType.Cold; + type = temperature.ColdAlert; threshold = temperature.ColdDamageThreshold; } else { - type = AlertType.Hot; + type = temperature.HotAlert; threshold = temperature.HeatDamageThreshold; } @@ -231,7 +235,7 @@ private void ServerAlert(EntityUid uid, AlertsComponent status, OnTemperatureCha break; case > 0.66f: - _alerts.ClearAlertCategory(uid, AlertCategory.Temperature); + _alerts.ClearAlertCategory(uid, TemperatureAlertCategory); break; } } diff --git a/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs b/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs index a35972f1c86..18d1842a87d 100644 --- a/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs +++ b/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs @@ -34,5 +34,5 @@ public sealed partial class ForeignerTraitComponent : Component /// The base translator prototype to use when creating a translator for the entity. /// </summary> [DataField(required: true)] - public ProtoId<EntityPrototype> BaseTranslator = default!; + public EntProtoId BaseTranslator = default!; } diff --git a/Content.Server/Traits/Assorted/ParacusiaSystem.cs b/Content.Server/Traits/Assorted/ParacusiaSystem.cs index cf08e09e90e..d92e200a4fa 100644 --- a/Content.Server/Traits/Assorted/ParacusiaSystem.cs +++ b/Content.Server/Traits/Assorted/ParacusiaSystem.cs @@ -14,7 +14,7 @@ public void SetSounds(EntityUid uid, SoundSpecifier sounds, ParacusiaComponent? return; } component.Sounds = sounds; - Dirty(component); + Dirty(uid, component); } public void SetTime(EntityUid uid, float minTime, float maxTime, ParacusiaComponent? component = null) @@ -25,7 +25,7 @@ public void SetTime(EntityUid uid, float minTime, float maxTime, ParacusiaCompon } component.MinTimeBetweenIncidents = minTime; component.MaxTimeBetweenIncidents = maxTime; - Dirty(component); + Dirty(uid, component); } public void SetDistance(EntityUid uid, float maxSoundDistance, ParacusiaComponent? component = null) @@ -35,6 +35,6 @@ public void SetDistance(EntityUid uid, float maxSoundDistance, ParacusiaComponen return; } component.MaxSoundDistance = maxSoundDistance; - Dirty(component); + Dirty(uid, component); } } diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs index 25010b22333..0dcd92f9417 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs @@ -51,7 +51,7 @@ private void UpdateShots(EntityUid uid, BatteryAmmoProviderComponent component, if (component.Shots != shots || component.Capacity != maxShots) { - Dirty(component); + Dirty(uid, component); } component.Shots = shots; diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.Revolver.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.Revolver.cs index 6ff47507299..59e53f1f72a 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.Revolver.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.Revolver.cs @@ -13,6 +13,6 @@ protected override void SpinRevolver(EntityUid revolverUid, RevolverAmmoProvider return; component.CurrentIndex = index; - Dirty(component); + Dirty(revolverUid, component); } } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/RandomInstrumentArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/RandomInstrumentArtifactSystem.cs index 8945b867954..118bc396a72 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/RandomInstrumentArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/RandomInstrumentArtifactSystem.cs @@ -18,6 +18,6 @@ public override void Initialize() private void OnStartup(EntityUid uid, RandomInstrumentArtifactComponent component, ComponentStartup args) { var instrument = EnsureComp<InstrumentComponent>(uid); - _instrument.SetInstrumentProgram(instrument, (byte) _random.Next(0, 127), 0); + _instrument.SetInstrumentProgram(uid, instrument, (byte) _random.Next(0, 127), 0); } } diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index a906652765c..d90ceab0dca 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -191,7 +191,7 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null) Dirty(target, pryComp); } - Dirty(melee); + Dirty(target, melee); //The zombie gets the assigned damage weaknesses and strengths _damageable.SetDamageModifierSetId(target, "Zombie"); diff --git a/Content.Shared/Actions/Events/FabricateActionEvent.cs b/Content.Shared/Actions/Events/FabricateActionEvent.cs index 7483cb04d98..33ab826cc8e 100644 --- a/Content.Shared/Actions/Events/FabricateActionEvent.cs +++ b/Content.Shared/Actions/Events/FabricateActionEvent.cs @@ -5,5 +5,5 @@ namespace Content.Shared.Actions.Events; public sealed partial class FabricateActionEvent : InstantActionEvent { [DataField(required: true)] - public ProtoId<EntityPrototype> Fabrication; + public EntProtoId Fabrication; } diff --git a/Content.Shared/Alert/AlertCategory.cs b/Content.Shared/Alert/AlertCategory.cs deleted file mode 100644 index 57a3e40f70e..00000000000 --- a/Content.Shared/Alert/AlertCategory.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Content.Shared.Alert; - -/// <summary> -/// Every category of alert. Corresponds to category field in alert prototypes defined in YML -/// </summary> -public enum AlertCategory -{ - Pressure, - Temperature, - Breathing, - Buckled, - Health, - Mood, - Internals, - Stamina, - Piloting, - Hunger, - Thirst, - Toxins, - Battery -} diff --git a/Content.Shared/Alert/AlertCategoryPrototype.cs b/Content.Shared/Alert/AlertCategoryPrototype.cs new file mode 100644 index 00000000000..7c7d0475214 --- /dev/null +++ b/Content.Shared/Alert/AlertCategoryPrototype.cs @@ -0,0 +1,14 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Alert; + +/// <summary> +/// This is a prototype for a category for marking alerts as mutually exclusive. +/// </summary> +[Prototype] +public sealed partial class AlertCategoryPrototype : IPrototype +{ + /// <inheritdoc/> + [IdDataField] + public string ID { get; } = default!; +} diff --git a/Content.Shared/Alert/AlertKey.cs b/Content.Shared/Alert/AlertKey.cs index c784af4cd48..c5c3a7643ec 100644 --- a/Content.Shared/Alert/AlertKey.cs +++ b/Content.Shared/Alert/AlertKey.cs @@ -1,5 +1,5 @@ -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.Manager; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; namespace Content.Shared.Alert; @@ -11,13 +11,13 @@ namespace Content.Shared.Alert; [Serializable, NetSerializable] public struct AlertKey { - public AlertType? AlertType { get; private set; } = Alert.AlertType.Error; - public readonly AlertCategory? AlertCategory; + public ProtoId<AlertPrototype>? AlertType { get; private set; } = default!; + public readonly ProtoId<AlertCategoryPrototype>? AlertCategory; /// NOTE: if the alert has a category you must pass the category for this to work /// properly as a key. I.e. if the alert has a category and you pass only the alert type, and you /// compare this to another AlertKey that has both the category and the same alert type, it will not consider them equal. - public AlertKey(AlertType? alertType, AlertCategory? alertCategory) + public AlertKey(ProtoId<AlertPrototype>? alertType, ProtoId<AlertCategoryPrototype>? alertCategory) { AlertCategory = alertCategory; AlertType = alertType; @@ -49,7 +49,7 @@ public override int GetHashCode() /// <param name="category">alert category, must not be null</param> /// <returns>An alert key for the provided alert category. This must only be used for /// queries and never storage, as it is lacking an alert type.</returns> - public static AlertKey ForCategory(AlertCategory category) + public static AlertKey ForCategory(ProtoId<AlertCategoryPrototype> category) { return new(null, category); } diff --git a/Content.Shared/Alert/AlertOrderPrototype.cs b/Content.Shared/Alert/AlertOrderPrototype.cs index 8279d592b4b..af4241a27e7 100644 --- a/Content.Shared/Alert/AlertOrderPrototype.cs +++ b/Content.Shared/Alert/AlertOrderPrototype.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Alert /// <summary> /// Defines the order of alerts so they show up in a consistent order. /// </summary> - [Prototype("alertOrder")] + [Prototype] [DataDefinition] public sealed partial class AlertOrderPrototype : IPrototype, IComparer<AlertPrototype> { @@ -15,7 +15,7 @@ public sealed partial class AlertOrderPrototype : IPrototype, IComparer<AlertPro [IdDataField] public string ID { get; private set; } = default!; - [DataField("order")] + [DataField] private (string type, string alert)[] Order { // why would paul do this to me. @@ -46,10 +46,10 @@ public sealed partial class AlertOrderPrototype : IPrototype, IComparer<AlertPro switch (type) { case "alertType": - _typeToIdx[Enum.Parse<AlertType>(alert)] = i++; + _typeToIdx[alert] = i++; break; case "category": - _categoryToIdx[Enum.Parse<AlertCategory>(alert)] = i++; + _categoryToIdx[alert] = i++; break; default: throw new ArgumentException(); @@ -58,17 +58,17 @@ public sealed partial class AlertOrderPrototype : IPrototype, IComparer<AlertPro } } - private readonly Dictionary<AlertType, int> _typeToIdx = new(); - private readonly Dictionary<AlertCategory, int> _categoryToIdx = new(); + private readonly Dictionary<ProtoId<AlertPrototype>, int> _typeToIdx = new(); + private readonly Dictionary<ProtoId<AlertCategoryPrototype>, int> _categoryToIdx = new(); private int GetOrderIndex(AlertPrototype alert) { - if (_typeToIdx.TryGetValue(alert.AlertType, out var idx)) + if (_typeToIdx.TryGetValue(alert.ID, out var idx)) { return idx; } if (alert.Category != null && - _categoryToIdx.TryGetValue((AlertCategory) alert.Category, out idx)) + _categoryToIdx.TryGetValue(alert.Category.Value, out idx)) { return idx; } @@ -78,20 +78,25 @@ private int GetOrderIndex(AlertPrototype alert) public int Compare(AlertPrototype? x, AlertPrototype? y) { - if ((x == null) && (y == null)) return 0; - if (x == null) return 1; - if (y == null) return -1; + if (x == null && y == null) + return 0; + if (x == null) + return 1; + if (y == null) + return -1; var idx = GetOrderIndex(x); var idy = GetOrderIndex(y); if (idx == -1 && idy == -1) { // break ties by type value // Must cast to int to avoid integer overflow when subtracting (enum's unsigned) - return (int)x.AlertType - (int)y.AlertType; + return string.Compare(x.ID, y.ID, StringComparison.InvariantCulture); } - if (idx == -1) return 1; - if (idy == -1) return -1; + if (idx == -1) + return 1; + if (idy == -1) + return -1; var result = idx - idy; // not strictly necessary (we don't care about ones that go at the same index) // but it makes the sort stable @@ -99,7 +104,7 @@ public int Compare(AlertPrototype? x, AlertPrototype? y) { // break ties by type value // Must cast to int to avoid integer overflow when subtracting (enum's unsigned) - return (int)x.AlertType - (int)y.AlertType; + return string.Compare(x.ID, y.ID, StringComparison.InvariantCulture); } return result; diff --git a/Content.Shared/Alert/AlertPrototype.cs b/Content.Shared/Alert/AlertPrototype.cs index 248cc00ba40..f53da27c0de 100644 --- a/Content.Shared/Alert/AlertPrototype.cs +++ b/Content.Shared/Alert/AlertPrototype.cs @@ -1,120 +1,116 @@ using Robust.Shared.Prototypes; using Robust.Shared.Utility; -namespace Content.Shared.Alert +namespace Content.Shared.Alert; + +/// <summary> +/// An alert popup with associated icon, tooltip, and other data. +/// </summary> +[Prototype] +public sealed partial class AlertPrototype : IPrototype { /// <summary> - /// An alert popup with associated icon, tooltip, and other data. + /// Type of alert, no 2 alert prototypes should have the same one. /// </summary> - [Prototype("alert")] - public sealed partial class AlertPrototype : IPrototype - { - [ViewVariables] - string IPrototype.ID => AlertType.ToString(); - - /// <summary> - /// Type of alert, no 2 alert prototypes should have the same one. - /// </summary> - [IdDataField] - public AlertType AlertType { get; private set; } - - /// <summary> - /// List of icons to use for this alert. Each entry corresponds to a different severity level, starting from the - /// minimum and incrementing upwards. If severities are not supported, the first entry is used. - /// </summary> - [DataField("icons", required: true)] - public List<SpriteSpecifier> Icons = new(); - - /// <summary> - /// An entity used for displaying the <see cref="Icons"/> in the UI control. - /// </summary> - [DataField] - public EntProtoId AlertViewEntity = "AlertSpriteView"; - - /// <summary> - /// Name to show in tooltip window. Accepts formatting. - /// </summary> - [DataField("name")] - public string Name { get; private set; } = ""; - - /// <summary> - /// Description to show in tooltip window. Accepts formatting. - /// </summary> - [DataField("description")] - public string Description { get; private set; } = ""; - - /// <summary> - /// Category the alert belongs to. Only one alert of a given category - /// can be shown at a time. If one is shown while another is already being shown, - /// it will be replaced. This can be useful for categories of alerts which should naturally - /// replace each other and are mutually exclusive, for example lowpressure / highpressure, - /// hot / cold. If left unspecified, the alert will not replace or be replaced by any other alerts. - /// </summary> - [DataField("category")] - public AlertCategory? Category { get; private set; } - - /// <summary> - /// Key which is unique w.r.t category semantics (alerts with same category have equal keys, - /// alerts with no category have different keys). - /// </summary> - public AlertKey AlertKey => new(AlertType, Category); - - /// <summary> - /// -1 (no effect) unless MaxSeverity is specified. Defaults to 1. Minimum severity level supported by this state. - /// </summary> - public short MinSeverity => MaxSeverity == -1 ? (short) -1 : _minSeverity; - - [DataField("minSeverity")] private short _minSeverity = 1; - - /// <summary> - /// Maximum severity level supported by this state. -1 (default) indicates - /// no severity levels are supported by the state. - /// </summary> - [DataField("maxSeverity")] - public short MaxSeverity = -1; - - /// <summary> - /// Indicates whether this state support severity levels - /// </summary> - public bool SupportsSeverity => MaxSeverity != -1; - - /// <summary> - /// Defines what to do when the alert is clicked. - /// This will always be null on clientside. - /// </summary> - [DataField("onClick", serverOnly: true)] - public IAlertClick? OnClick { get; private set; } - - /// <param name="severity">severity level, if supported by this alert</param> - /// <returns>the icon path to the texture for the provided severity level</returns> - public SpriteSpecifier GetIcon(short? severity = null) - { - var minIcons = SupportsSeverity - ? MaxSeverity - MinSeverity - : 1; + [IdDataField] + public string ID { get; private set; } = default!; - if (Icons.Count < minIcons) - throw new InvalidOperationException($"Insufficient number of icons given for alert {AlertType}"); + /// <summary> + /// List of icons to use for this alert. Each entry corresponds to a different severity level, starting from the + /// minimum and incrementing upwards. If severities are not supported, the first entry is used. + /// </summary> + [DataField(required: true)] + public List<SpriteSpecifier> Icons = new(); - if (!SupportsSeverity) - return Icons[0]; + /// <summary> + /// An entity used for displaying the <see cref="Icons"/> in the UI control. + /// </summary> + [DataField] + public EntProtoId AlertViewEntity = "AlertSpriteView"; - if (severity == null) - { - throw new ArgumentException($"No severity specified but this alert ({AlertKey}) has severity.", nameof(severity)); - } + /// <summary> + /// Name to show in tooltip window. Accepts formatting. + /// </summary> + [DataField] + public string Name { get; private set; } = string.Empty; - if (severity < MinSeverity) - { - throw new ArgumentOutOfRangeException(nameof(severity), $"Severity below minimum severity in {AlertKey}."); - } + /// <summary> + /// Description to show in tooltip window. Accepts formatting. + /// </summary> + [DataField] + public string Description { get; private set; } = string.Empty; - if (severity > MaxSeverity) - { - throw new ArgumentOutOfRangeException(nameof(severity), $"Severity above maximum severity in {AlertKey}."); - } + /// <summary> + /// Category the alert belongs to. Only one alert of a given category + /// can be shown at a time. If one is shown while another is already being shown, + /// it will be replaced. This can be useful for categories of alerts which should naturally + /// replace each other and are mutually exclusive, for example lowpressure / highpressure, + /// hot / cold. If left unspecified, the alert will not replace or be replaced by any other alerts. + /// </summary> + [DataField] + public ProtoId<AlertCategoryPrototype>? Category { get; private set; } + + /// <summary> + /// Key which is unique w.r.t category semantics (alerts with same category have equal keys, + /// alerts with no category have different keys). + /// </summary> + public AlertKey AlertKey => new(ID, Category); - return Icons[severity.Value - _minSeverity]; + /// <summary> + /// -1 (no effect) unless MaxSeverity is specified. Defaults to 1. Minimum severity level supported by this state. + /// </summary> + public short MinSeverity => MaxSeverity == -1 ? (short) -1 : _minSeverity; + + [DataField("minSeverity")] private short _minSeverity = 1; + + /// <summary> + /// Maximum severity level supported by this state. -1 (default) indicates + /// no severity levels are supported by the state. + /// </summary> + [DataField] + public short MaxSeverity = -1; + + /// <summary> + /// Indicates whether this state support severity levels + /// </summary> + public bool SupportsSeverity => MaxSeverity != -1; + + /// <summary> + /// Defines what to do when the alert is clicked. + /// This will always be null on clientside. + /// </summary> + [DataField(serverOnly: true)] + public IAlertClick? OnClick { get; private set; } + + /// <param name="severity">severity level, if supported by this alert</param> + /// <returns>the icon path to the texture for the provided severity level</returns> + public SpriteSpecifier GetIcon(short? severity = null) + { + var minIcons = SupportsSeverity + ? MaxSeverity - MinSeverity + : 1; + + if (Icons.Count < minIcons) + throw new InvalidOperationException($"Insufficient number of icons given for alert {ID}"); + + if (!SupportsSeverity) + return Icons[0]; + + if (severity == null) + { + throw new ArgumentException($"No severity specified but this alert ({AlertKey}) has severity.", nameof(severity)); + } + + if (severity < MinSeverity) + { + throw new ArgumentOutOfRangeException(nameof(severity), $"Severity below minimum severity in {AlertKey}."); } + + if (severity > MaxSeverity) + { + throw new ArgumentOutOfRangeException(nameof(severity), $"Severity above maximum severity in {AlertKey}."); + } + + return Icons[severity.Value - _minSeverity]; } } diff --git a/Content.Shared/Alert/AlertState.cs b/Content.Shared/Alert/AlertState.cs index effd9522036..d6309f6b426 100644 --- a/Content.Shared/Alert/AlertState.cs +++ b/Content.Shared/Alert/AlertState.cs @@ -1,3 +1,4 @@ +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Alert; @@ -9,5 +10,5 @@ public struct AlertState public (TimeSpan, TimeSpan)? Cooldown; public bool AutoRemove; public bool ShowCooldown; - public AlertType Type; + public ProtoId<AlertPrototype> Type; } diff --git a/Content.Shared/Alert/AlertType.cs b/Content.Shared/Alert/AlertType.cs deleted file mode 100644 index bd8c1dbe257..00000000000 --- a/Content.Shared/Alert/AlertType.cs +++ /dev/null @@ -1,78 +0,0 @@ -namespace Content.Shared.Alert -{ - /// <summary> - /// Every kind of alert. Corresponds to alertType field in alert prototypes defined in YML - /// NOTE: Using byte for a compact encoding when sending this in messages, can upgrade - /// to ushort - /// </summary> - public enum AlertType : byte - { - Error, - LowOxygen, - LowNitrogen, - LowPressure, - HighPressure, - Fire, - Cold, - Hot, - Weightless, - Stun, - Handcuffed, - Ensnared, - Buckled, - HumanCrit, - HumanDead, - HumanHealth, - BorgBattery, - BorgBatteryNone, - - // Mood - Bleeding, - Insane, - Horrible, - Terrible, - Bad, - Meh, - Neutral, - Good, - Great, - Exceptional, - Perfect, - MoodDead, - CultBuffed, - - PilotingShuttle, - Peckish, - Starving, - Thirsty, - Parched, - Stamina, - Pulled, - Pulling, - Magboots, - Internals, - Toxins, - Muted, - Walking, - VowOfSilence, - VowBroken, - Essence, - Corporeal, - Bleed, - Pacified, - Debug1, - Debug2, - Debug3, - Debug4, - Debug5, - Debug6, - SuitPower, - BorgHealth, - BorgCrit, - BorgDead, - Offer, - ShadowkinPower, - Deflecting, - } - -} diff --git a/Content.Shared/Alert/AlertsSystem.cs b/Content.Shared/Alert/AlertsSystem.cs index 5b888e30c4c..83c6fcd0dd7 100644 --- a/Content.Shared/Alert/AlertsSystem.cs +++ b/Content.Shared/Alert/AlertsSystem.cs @@ -11,7 +11,7 @@ public abstract class AlertsSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IGameTiming _timing = default!; - private FrozenDictionary<AlertType, AlertPrototype> _typeToAlert = default!; + private FrozenDictionary<ProtoId<AlertPrototype>, AlertPrototype> _typeToAlert = default!; public IReadOnlyDictionary<AlertKey, AlertState>? GetActiveAlerts(EntityUid euid) { @@ -20,23 +20,23 @@ public abstract class AlertsSystem : EntitySystem : null; } - public short GetSeverityRange(AlertType alertType) + public short GetSeverityRange(ProtoId<AlertPrototype> alertType) { var minSeverity = _typeToAlert[alertType].MinSeverity; return (short)MathF.Max(minSeverity,_typeToAlert[alertType].MaxSeverity - minSeverity); } - public short GetMaxSeverity(AlertType alertType) + public short GetMaxSeverity(ProtoId<AlertPrototype> alertType) { return _typeToAlert[alertType].MaxSeverity; } - public short GetMinSeverity(AlertType alertType) + public short GetMinSeverity(ProtoId<AlertPrototype> alertType) { return _typeToAlert[alertType].MinSeverity; } - public bool IsShowingAlert(EntityUid euid, AlertType alertType) + public bool IsShowingAlert(EntityUid euid, ProtoId<AlertPrototype> alertType) { if (!EntityManager.TryGetComponent(euid, out AlertsComponent? alertsComponent)) return false; @@ -51,7 +51,7 @@ public bool IsShowingAlert(EntityUid euid, AlertType alertType) } /// <returns>true iff an alert of the indicated alert category is currently showing</returns> - public bool IsShowingAlertCategory(EntityUid euid, AlertCategory alertCategory) + public bool IsShowingAlertCategory(EntityUid euid, ProtoId<AlertCategoryPrototype> alertCategory) { return EntityManager.TryGetComponent(euid, out AlertsComponent? alertsComponent) && alertsComponent.Alerts.ContainsKey(AlertKey.ForCategory(alertCategory)); @@ -78,7 +78,7 @@ public bool TryGetAlertState(EntityUid euid, AlertKey key, out AlertState alertS /// be erased if there is currently a cooldown for the alert)</param> /// <param name="autoRemove">if true, the alert will be removed at the end of the cooldown</param> /// <param name="showCooldown">if true, the cooldown will be visibly shown over the alert icon</param> - public void ShowAlert(EntityUid euid, AlertType alertType, short? severity = null, (TimeSpan, TimeSpan)? cooldown = null, bool autoRemove = false, bool showCooldown = true ) + public void ShowAlert(EntityUid euid, ProtoId<AlertPrototype> alertType, short? severity = null, (TimeSpan, TimeSpan)? cooldown = null, bool autoRemove = false, bool showCooldown = true ) { // This should be handled as part of networking. if (_timing.ApplyingState) @@ -131,7 +131,7 @@ public void ShowAlert(EntityUid euid, AlertType alertType, short? severity = nul /// <summary> /// Clear the alert with the given category, if one is currently showing. /// </summary> - public void ClearAlertCategory(EntityUid euid, AlertCategory category) + public void ClearAlertCategory(EntityUid euid, ProtoId<AlertCategoryPrototype> category) { if(!TryComp(euid, out AlertsComponent? alertsComponent)) return; @@ -150,7 +150,7 @@ public void ClearAlertCategory(EntityUid euid, AlertCategory category) /// <summary> /// Clear the alert of the given type if it is currently showing. /// </summary> - public void ClearAlert(EntityUid euid, AlertType alertType) + public void ClearAlert(EntityUid euid, ProtoId<AlertPrototype> alertType) { if (_timing.ApplyingState) return; @@ -286,13 +286,13 @@ private void HandlePrototypesReloaded(PrototypesReloadedEventArgs obj) protected virtual void LoadPrototypes() { - var dict = new Dictionary<AlertType, AlertPrototype>(); + var dict = new Dictionary<ProtoId<AlertPrototype>, AlertPrototype>(); foreach (var alert in _prototypeManager.EnumeratePrototypes<AlertPrototype>()) { - if (!dict.TryAdd(alert.AlertType, alert)) + if (!dict.TryAdd(alert.ID, alert)) { Log.Error("Found alert with duplicate alertType {0} - all alerts must have" + - " a unique alertType, this one will be skipped", alert.AlertType); + " a unique alertType, this one will be skipped", alert.ID); } } @@ -303,7 +303,7 @@ protected virtual void LoadPrototypes() /// Tries to get the alert of the indicated type /// </summary> /// <returns>true if found</returns> - public bool TryGet(AlertType alertType, [NotNullWhen(true)] out AlertPrototype? alert) + public bool TryGet(ProtoId<AlertPrototype> alertType, [NotNullWhen(true)] out AlertPrototype? alert) { return _typeToAlert.TryGetValue(alertType, out alert); } diff --git a/Content.Shared/Alert/ClickAlertEvent.cs b/Content.Shared/Alert/ClickAlertEvent.cs index fe7ca97e4c2..43dd086b562 100644 --- a/Content.Shared/Alert/ClickAlertEvent.cs +++ b/Content.Shared/Alert/ClickAlertEvent.cs @@ -1,4 +1,5 @@ -using Robust.Shared.Serialization; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; namespace Content.Shared.Alert; @@ -8,9 +9,9 @@ namespace Content.Shared.Alert; [Serializable, NetSerializable] public sealed class ClickAlertEvent : EntityEventArgs { - public readonly AlertType Type; + public readonly ProtoId<AlertPrototype> Type; - public ClickAlertEvent(AlertType alertType) + public ClickAlertEvent(ProtoId<AlertPrototype> alertType) { Type = alertType; } diff --git a/Content.Shared/Buckle/Components/BuckleComponent.cs b/Content.Shared/Buckle/Components/BuckleComponent.cs index cf28b56d51f..ee86e6d4de0 100644 --- a/Content.Shared/Buckle/Components/BuckleComponent.cs +++ b/Content.Shared/Buckle/Components/BuckleComponent.cs @@ -1,10 +1,15 @@ +using System.Diagnostics.CodeAnalysis; using Content.Shared.Interaction; using Robust.Shared.GameStates; using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Buckle.Components; -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +/// <summary> +/// This component allows an entity to be buckled to an entity with a <see cref="StrapComponent"/>. +/// </summary> +[RegisterComponent, NetworkedComponent] [Access(typeof(SharedBuckleSystem))] public sealed partial class BuckleComponent : Component { @@ -14,31 +19,23 @@ public sealed partial class BuckleComponent : Component /// across a table two tiles away" problem. /// </summary> [DataField] - [ViewVariables(VVAccess.ReadWrite)] public float Range = SharedInteractionSystem.InteractionRange / 1.4f; /// <summary> /// True if the entity is buckled, false otherwise. /// </summary> - [ViewVariables(VVAccess.ReadWrite)] - [AutoNetworkedField] - public bool Buckled; - - [ViewVariables] - [AutoNetworkedField] - public EntityUid? LastEntityBuckledTo; + [MemberNotNullWhen(true, nameof(BuckledTo))] + public bool Buckled => BuckledTo != null; /// <summary> /// Whether or not collisions should be possible with the entity we are strapped to /// </summary> - [ViewVariables(VVAccess.ReadWrite)] - [DataField, AutoNetworkedField] + [DataField] public bool DontCollide; /// <summary> /// Whether or not we should be allowed to pull the entity we are strapped to /// </summary> - [ViewVariables(VVAccess.ReadWrite)] [DataField] public bool PullStrap; @@ -47,20 +44,18 @@ public sealed partial class BuckleComponent : Component /// be able to unbuckle after recently buckling. /// </summary> [DataField] - [ViewVariables(VVAccess.ReadWrite)] public TimeSpan Delay = TimeSpan.FromSeconds(0.25f); /// <summary> /// The time that this entity buckled at. /// </summary> - [ViewVariables] - public TimeSpan BuckleTime; + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan? BuckleTime; /// <summary> /// The strap that this component is buckled to. /// </summary> - [ViewVariables] - [AutoNetworkedField] + [DataField] public EntityUid? BuckledTo; /// <summary> @@ -68,7 +63,6 @@ public sealed partial class BuckleComponent : Component /// <see cref="StrapComponent"/>. /// </summary> [DataField] - [ViewVariables(VVAccess.ReadWrite)] public int Size = 100; /// <summary> @@ -77,11 +71,90 @@ public sealed partial class BuckleComponent : Component [ViewVariables] public int? OriginalDrawDepth; } +[Serializable, NetSerializable] +public sealed class BuckleState(NetEntity? buckledTo, bool dontCollide, TimeSpan? buckleTime) : ComponentState +{ + public readonly NetEntity? BuckledTo = buckledTo; + public readonly bool DontCollide = dontCollide; + public readonly TimeSpan? BuckleTime = buckleTime; +} + + +/// <summary> +/// Event raised directed at a strap entity before some entity gets buckled to it. +/// </summary> +[ByRefEvent] +public record struct StrapAttemptEvent( + Entity<StrapComponent> Strap, + Entity<BuckleComponent> Buckle, + EntityUid? User, + bool Popup) +{ + public bool Cancelled; +} + +/// <summary> +/// Event raised directed at a buckle entity before it gets buckled to some strap entity. +/// </summary> +[ByRefEvent] +public record struct BuckleAttemptEvent( + Entity<StrapComponent> Strap, + Entity<BuckleComponent> Buckle, + EntityUid? User, + bool Popup) +{ + public bool Cancelled; +} + +/// <summary> +/// Event raised directed at a strap entity before some entity gets unbuckled from it. +/// </summary> +[ByRefEvent] +public record struct UnstrapAttemptEvent( + Entity<StrapComponent> Strap, + Entity<BuckleComponent> Buckle, + EntityUid? User, + bool Popup) +{ + public bool Cancelled; +} + +/// <summary> +/// Event raised directed at a buckle entity before it gets unbuckled. +/// </summary> +[ByRefEvent] +public record struct UnbuckleAttemptEvent( + Entity<StrapComponent> Strap, + Entity<BuckleComponent> Buckle, + EntityUid? User, + bool Popup) +{ + public bool Cancelled; +} + +/// <summary> +/// Event raised directed at a strap entity after something has been buckled to it. +/// </summary> +[ByRefEvent] +public readonly record struct StrappedEvent(Entity<StrapComponent> Strap, Entity<BuckleComponent> Buckle); + +/// <summary> +/// Event raised directed at a buckle entity after it has been buckled. +/// </summary> +[ByRefEvent] +public readonly record struct BuckledEvent(Entity<StrapComponent> Strap, Entity<BuckleComponent> Buckle); + +/// <summary> +/// Event raised directed at a strap entity after something has been unbuckled from it. +/// </summary> [ByRefEvent] -public record struct BuckleAttemptEvent(EntityUid StrapEntity, EntityUid BuckledEntity, EntityUid UserEntity, bool Buckling, bool Cancelled = false); +public readonly record struct UnstrappedEvent(Entity<StrapComponent> Strap, Entity<BuckleComponent> Buckle); +/// <summary> +/// Event raised directed at a buckle entity after it has been unbuckled from some strap entity. +/// </summary> [ByRefEvent] -public readonly record struct BuckleChangeEvent(EntityUid StrapEntity, EntityUid BuckledEntity, bool Buckling); +public readonly record struct UnbuckledEvent(Entity<StrapComponent> Strap, Entity<BuckleComponent> Buckle); [Serializable, NetSerializable] public enum BuckleVisuals diff --git a/Content.Shared/Buckle/Components/StrapComponent.cs b/Content.Shared/Buckle/Components/StrapComponent.cs index 72c92ebf84b..0fbdae693de 100644 --- a/Content.Shared/Buckle/Components/StrapComponent.cs +++ b/Content.Shared/Buckle/Components/StrapComponent.cs @@ -3,6 +3,7 @@ using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Buckle.Components; @@ -12,117 +13,83 @@ namespace Content.Shared.Buckle.Components; public sealed partial class StrapComponent : Component { /// <summary> - /// The entities that are currently buckled + /// The entities that are currently buckled to this strap. /// </summary> - [AutoNetworkedField] - [ViewVariables] // TODO serialization + [ViewVariables] public HashSet<EntityUid> BuckledEntities = new(); /// <summary> /// Entities that this strap accepts and can buckle /// If null it accepts any entity /// </summary> - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public EntityWhitelist? Whitelist; /// <summary> /// Entities that this strap does not accept and cannot buckle. /// </summary> - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public EntityWhitelist? Blacklist; /// <summary> /// The change in position to the strapped mob /// </summary> [DataField, AutoNetworkedField] - [ViewVariables(VVAccess.ReadWrite)] public StrapPosition Position = StrapPosition.None; - /// <summary> - /// The distance above which a buckled entity will be automatically unbuckled. - /// Don't change it unless you really have to - /// </summary> - /// <remarks> - /// Dont set this below 0.2 because that causes audio issues with <see cref="SharedBuckleSystem.OnBuckleMove"/> - /// My guess after testing is that the client sets BuckledTo to the strap in *some* ticks for some reason - /// whereas the server doesnt, thus the client tries to unbuckle like 15 times because it passes the strap null check - /// This is why this needs to be above 0.1 to make the InRange check fail in both client and server. - /// </remarks> - [DataField, AutoNetworkedField] - [ViewVariables(VVAccess.ReadWrite)] - public float MaxBuckleDistance = 0.2f; - - /// <summary> - /// Gets and clamps the buckle offset to MaxBuckleDistance - /// </summary> - [ViewVariables] - public Vector2 BuckleOffsetClamped => Vector2.Clamp( - BuckleOffset, - Vector2.One * -MaxBuckleDistance, - Vector2.One * MaxBuckleDistance); - /// <summary> /// The buckled entity will be offset by this amount from the center of the strap object. - /// If this offset it too big, it will be clamped to <see cref="MaxBuckleDistance"/> /// </summary> [DataField, AutoNetworkedField] - [ViewVariables(VVAccess.ReadWrite)] public Vector2 BuckleOffset = Vector2.Zero; /// <summary> /// The angle to rotate the player by when they get strapped /// </summary> [DataField] - [ViewVariables(VVAccess.ReadWrite)] public Angle Rotation; /// <summary> /// The size of the strap which is compared against when buckling entities /// </summary> [DataField] - [ViewVariables(VVAccess.ReadWrite)] public int Size = 100; /// <summary> /// If disabled, nothing can be buckled on this object, and it will unbuckle anything that's already buckled /// </summary> - [ViewVariables] + [DataField, AutoNetworkedField] public bool Enabled = true; /// <summary> /// You can specify the offset the entity will have after unbuckling. /// </summary> [DataField] - [ViewVariables(VVAccess.ReadWrite)] public Vector2 UnbuckleOffset = Vector2.Zero; /// <summary> /// The sound to be played when a mob is buckled /// </summary> [DataField] - [ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier BuckleSound = new SoundPathSpecifier("/Audio/Effects/buckle.ogg"); /// <summary> /// The sound to be played when a mob is unbuckled /// </summary> [DataField] - [ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier UnbuckleSound = new SoundPathSpecifier("/Audio/Effects/unbuckle.ogg"); /// <summary> /// ID of the alert to show when buckled /// </summary> [DataField] - [ViewVariables(VVAccess.ReadWrite)] - public AlertType BuckledAlertType = AlertType.Buckled; + public ProtoId<AlertPrototype> BuckledAlertType = "Buckled"; /// <summary> - /// The sum of the sizes of all the buckled entities in this strap + /// Whether InteractHand will buckle the user to the strap. /// </summary> - [AutoNetworkedField] - [ViewVariables] - public int OccupiedSize; + [DataField] + public bool BuckleOnInteractHand = true; } public enum StrapPosition diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index c07d90b3a2b..ed1b3c19906 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -1,36 +1,49 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using Content.Shared.Alert; -using Content.Shared.Bed.Sleep; using Content.Shared.Buckle.Components; +using Content.Shared.Cuffs.Components; using Content.Shared.Database; +using Content.Shared.DoAfter; using Content.Shared.Hands.Components; using Content.Shared.IdentityManagement; -using Content.Shared.Interaction; -using Content.Shared.Mobs.Components; using Content.Shared.Movement.Events; +using Content.Shared.Movement.Pulling.Events; using Content.Shared.Popups; +using Content.Shared.Pulling.Events; +using Content.Shared.Rotation; using Content.Shared.Standing; using Content.Shared.Storage.Components; using Content.Shared.Stunnable; using Content.Shared.Throwing; -using Content.Shared.Verbs; +using Content.Shared.Whitelist; +using Robust.Shared.Containers; +using Robust.Shared.GameStates; +using Robust.Shared.Map; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; -using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; namespace Content.Shared.Buckle; public abstract partial class SharedBuckleSystem { + public static ProtoId<AlertCategoryPrototype> BuckledAlertCategory = "Buckled"; + + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + private void InitializeBuckle() { - SubscribeLocalEvent<BuckleComponent, ComponentStartup>(OnBuckleComponentStartup); SubscribeLocalEvent<BuckleComponent, ComponentShutdown>(OnBuckleComponentShutdown); SubscribeLocalEvent<BuckleComponent, MoveEvent>(OnBuckleMove); - SubscribeLocalEvent<BuckleComponent, InteractHandEvent>(OnBuckleInteractHand); - SubscribeLocalEvent<BuckleComponent, GetVerbsEvent<InteractionVerb>>(AddUnbuckleVerb); + SubscribeLocalEvent<BuckleComponent, EntParentChangedMessage>(OnParentChanged); + SubscribeLocalEvent<BuckleComponent, EntGotInsertedIntoContainerMessage>(OnInserted); + + SubscribeLocalEvent<BuckleComponent, StartPullAttemptEvent>(OnPullAttempt); + SubscribeLocalEvent<BuckleComponent, BeingPulledAttemptEvent>(OnBeingPulledAttempt); + SubscribeLocalEvent<BuckleComponent, PullStartedMessage>(OnPullStarted); + SubscribeLocalEvent<BuckleComponent, InsertIntoEntityStorageAttemptEvent>(OnBuckleInsertIntoEntityStorageAttempt); SubscribeLocalEvent<BuckleComponent, PreventCollideEvent>(OnBucklePreventCollide); @@ -40,64 +53,84 @@ private void InitializeBuckle() SubscribeLocalEvent<BuckleComponent, UpdateCanMoveEvent>(OnBuckleUpdateCanMove); } - private void OnBuckleComponentStartup(EntityUid uid, BuckleComponent component, ComponentStartup args) + private void OnBuckleComponentShutdown(Entity<BuckleComponent> ent, ref ComponentShutdown args) { - UpdateBuckleStatus(uid, component); + Unbuckle(ent!, null); } - private void OnBuckleComponentShutdown(EntityUid uid, BuckleComponent component, ComponentShutdown args) - { - TryUnbuckle(uid, uid, true, component); + #region Pulling - component.BuckleTime = default; + private void OnPullAttempt(Entity<BuckleComponent> ent, ref StartPullAttemptEvent args) + { + // Prevent people pulling the chair they're on, etc. + if (ent.Comp.BuckledTo == args.Pulled && !ent.Comp.PullStrap) + args.Cancel(); } - private void OnBuckleMove(EntityUid uid, BuckleComponent component, ref MoveEvent ev) + private void OnBeingPulledAttempt(Entity<BuckleComponent> ent, ref BeingPulledAttemptEvent args) { - if (component.BuckledTo is not {} strapUid) + if (args.Cancelled || !ent.Comp.Buckled) return; - if (!TryComp<StrapComponent>(strapUid, out var strapComp)) - return; + if (!CanUnbuckle(ent!, args.Puller, false)) + args.Cancel(); + } - var strapPosition = Transform(strapUid).Coordinates; - if (ev.NewPosition.EntityId.IsValid() && ev.NewPosition.InRange(EntityManager, _transform, strapPosition, strapComp.MaxBuckleDistance)) - return; + private void OnPullStarted(Entity<BuckleComponent> ent, ref PullStartedMessage args) + { + Unbuckle(ent!, args.PullerUid); + } + + #endregion - TryUnbuckle(uid, uid, true, component); + #region Transform + + private void OnParentChanged(Entity<BuckleComponent> ent, ref EntParentChangedMessage args) + { + BuckleTransformCheck(ent, args.Transform); } - private void OnBuckleInteractHand(EntityUid uid, BuckleComponent component, InteractHandEvent args) + private void OnInserted(Entity<BuckleComponent> ent, ref EntGotInsertedIntoContainerMessage args) { - if (!component.Buckled) - return; + BuckleTransformCheck(ent, Transform(ent)); + } - if (TryUnbuckle(uid, args.User, buckleComp: component)) - args.Handled = true; + private void OnBuckleMove(Entity<BuckleComponent> ent, ref MoveEvent ev) + { + BuckleTransformCheck(ent, ev.Component); } - private void AddUnbuckleVerb(EntityUid uid, BuckleComponent component, GetVerbsEvent<InteractionVerb> args) + /// <summary> + /// Check if the entity should get unbuckled as a result of transform or container changes. + /// </summary> + private void BuckleTransformCheck(Entity<BuckleComponent> buckle, TransformComponent xform) { - if (!args.CanAccess || !args.CanInteract || !component.Buckled) + if (_gameTiming.ApplyingState) + return; + + if (buckle.Comp.BuckledTo is not { } strapUid) return; - InteractionVerb verb = new() + if (!TryComp<StrapComponent>(strapUid, out var strapComp)) { - Act = () => TryUnbuckle(uid, args.User, buckleComp: component), - Text = Loc.GetString("verb-categories-unbuckle"), - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png")) - }; + Log.Error($"Encountered buckle entity {ToPrettyString(buckle)} without a valid strap entity {ToPrettyString(strapUid)}"); + SetBuckledTo(buckle, null); + return; + } - if (args.Target == args.User && args.Using == null) + if (xform.ParentUid != strapUid || _container.IsEntityInContainer(buckle)) { - // A user is left clicking themselves with an empty hand, while buckled. - // It is very likely they are trying to unbuckle themselves. - verb.Priority = 1; + Unbuckle(buckle, (strapUid, strapComp), null); + return; } - args.Verbs.Add(verb); + var delta = (xform.LocalPosition - strapComp.BuckleOffset).LengthSquared(); + if (delta > 1e-5) + Unbuckle(buckle, (strapUid, strapComp), null); } + #endregion + private void OnBuckleInsertIntoEntityStorageAttempt(EntityUid uid, BuckleComponent component, ref InsertIntoEntityStorageAttemptEvent args) { if (component.Buckled) @@ -106,10 +139,7 @@ private void OnBuckleInsertIntoEntityStorageAttempt(EntityUid uid, BuckleCompone private void OnBucklePreventCollide(EntityUid uid, BuckleComponent component, ref PreventCollideEvent args) { - if (args.OtherEntity != component.BuckledTo) - return; - - if (component.Buckled || component.DontCollide) + if (args.OtherEntity == component.BuckledTo && component.DontCollide) args.Cancelled = true; } @@ -133,10 +163,7 @@ private void OnBuckleThrowPushbackAttempt(EntityUid uid, BuckleComponent compone private void OnBuckleUpdateCanMove(EntityUid uid, BuckleComponent component, UpdateCanMoveEvent args) { - if (component.LifeStage > ComponentLifeStage.Running) - return; - - if (component.Buckled) // buckle shitcode + if (component.Buckled) args.Cancel(); } @@ -145,162 +172,146 @@ public bool IsBuckled(EntityUid uid, BuckleComponent? component = null) return Resolve(uid, ref component, false) && component.Buckled; } - /// <summary> - /// Shows or hides the buckled status effect depending on if the - /// entity is buckled or not. - /// </summary> - /// <param name="uid"> Entity that we want to show the alert </param> - /// <param name="buckleComp"> buckle component of the entity </param> - /// <param name="strapComp"> strap component of the thing we are strapping to </param> - private void UpdateBuckleStatus(EntityUid uid, BuckleComponent buckleComp, StrapComponent? strapComp = null) + protected void SetBuckledTo(Entity<BuckleComponent> buckle, Entity<StrapComponent?>? strap) { - Appearance.SetData(uid, StrapVisuals.State, buckleComp.Buckled); - if (buckleComp.BuckledTo != null) + if (TryComp(buckle.Comp.BuckledTo, out StrapComponent? old)) { - if (!Resolve(buckleComp.BuckledTo.Value, ref strapComp)) - return; - - var alertType = strapComp.BuckledAlertType; - _alerts.ShowAlert(uid, alertType); + old.BuckledEntities.Remove(buckle); + Dirty(buckle.Comp.BuckledTo.Value, old); } - else - { - _alerts.ClearAlertCategory(uid, AlertCategory.Buckled); - } - } - /// <summary> - /// Sets the <see cref="BuckleComponent.BuckledTo"/> field in the component to a value - /// </summary> - /// <param name="strapUid"> Value tat with be assigned to the field </param> - private void SetBuckledTo(EntityUid buckleUid, EntityUid? strapUid, StrapComponent? strapComp, BuckleComponent buckleComp) - { - buckleComp.BuckledTo = strapUid; - - if (strapUid == null) + if (strap is {} strapEnt && Resolve(strapEnt.Owner, ref strapEnt.Comp)) { - buckleComp.Buckled = false; + strapEnt.Comp.BuckledEntities.Add(buckle); + Dirty(strapEnt); + _alerts.ShowAlert(buckle, strapEnt.Comp.BuckledAlertType); } else { - buckleComp.LastEntityBuckledTo = strapUid; - buckleComp.DontCollide = true; - buckleComp.Buckled = true; - buckleComp.BuckleTime = _gameTiming.CurTime; + _alerts.ClearAlertCategory(buckle, BuckledAlertCategory); } - ActionBlocker.UpdateCanMove(buckleUid); - UpdateBuckleStatus(buckleUid, buckleComp, strapComp); - Dirty(buckleComp); + buckle.Comp.BuckledTo = strap; + buckle.Comp.BuckleTime = _gameTiming.CurTime; + ActionBlocker.UpdateCanMove(buckle); + Appearance.SetData(buckle, StrapVisuals.State, buckle.Comp.Buckled); + Dirty(buckle); } /// <summary> /// Checks whether or not buckling is possible /// </summary> /// <param name="buckleUid"> Uid of the owner of BuckleComponent </param> - /// <param name="userUid"> - /// Uid of a third party entity, - /// i.e, the uid of someone else you are dragging to a chair. - /// Can equal buckleUid sometimes + /// <param name="user"> + /// Uid of a third party entity, + /// i.e, the uid of someone else you are dragging to a chair. + /// Can equal buckleUid sometimes /// </param> /// <param name="strapUid"> Uid of the owner of strap component </param> - private bool CanBuckle( - EntityUid buckleUid, - EntityUid userUid, + /// <param name="strapComp"></param> + /// <param name="buckleComp"></param> + private bool CanBuckle(EntityUid buckleUid, + EntityUid? user, EntityUid strapUid, + bool popup, [NotNullWhen(true)] out StrapComponent? strapComp, - BuckleComponent? buckleComp = null) + BuckleComponent buckleComp) { strapComp = null; - - if (userUid == strapUid || - !Resolve(buckleUid, ref buckleComp, false) || - !Resolve(strapUid, ref strapComp, false)) - { + if (!Resolve(strapUid, ref strapComp, false)) return false; - } // Does it pass the Whitelist if (strapComp.Whitelist != null && - !strapComp.Whitelist.IsValid(buckleUid, EntityManager) || strapComp.Blacklist?.IsValid(buckleUid, EntityManager) == true) + !_whitelistSystem.IsValid(strapComp.Whitelist, buckleUid) || strapComp.Blacklist != null && _whitelistSystem.IsValid(strapComp.Blacklist, buckleUid)) { - if (_netManager.IsServer) - _popup.PopupEntity(Loc.GetString("buckle-component-cannot-fit-message"), userUid, buckleUid, PopupType.Medium); + if (popup) + _popup.PopupClient(Loc.GetString("buckle-component-cannot-fit-message"), user, PopupType.Medium); + return false; } - // Is it within range - bool Ignored(EntityUid entity) => entity == buckleUid || entity == userUid || entity == strapUid; - - if (!_interaction.InRangeUnobstructed(buckleUid, strapUid, buckleComp.Range, predicate: Ignored, + if (!_interaction.InRangeUnobstructed(buckleUid, + strapUid, + buckleComp.Range, + predicate: entity => entity == buckleUid || entity == user || entity == strapUid, popup: true)) { return false; } - // If in a container - if (_container.TryGetContainingContainer(buckleUid, out var ownerContainer)) - { - // And not in the same container as the strap - if (!_container.TryGetContainingContainer(strapUid, out var strapContainer) || - ownerContainer != strapContainer) - { - return false; - } - } + if (!_container.IsInSameOrNoContainer((buckleUid, null, null), (strapUid, null, null))) + return false; - if (!HasComp<HandsComponent>(userUid)) + if (user != null && !HasComp<HandsComponent>(user)) { - // PopupPredicted when - if (_netManager.IsServer) - _popup.PopupEntity(Loc.GetString("buckle-component-no-hands-message"), userUid, userUid); + if (popup) + _popup.PopupClient(Loc.GetString("buckle-component-no-hands-message"), user); + return false; } - if (buckleComp.Buckled) + if (buckleComp.Buckled && !TryUnbuckle(buckleUid, user, buckleComp)) { - var message = Loc.GetString(buckleUid == userUid + if (popup) + { + var message = Loc.GetString(buckleUid == user ? "buckle-component-already-buckled-message" : "buckle-component-other-already-buckled-message", ("owner", Identity.Entity(buckleUid, EntityManager))); - if (_netManager.IsServer) - _popup.PopupEntity(message, userUid, userUid); + + _popup.PopupClient(message, user); + } return false; } + // Check whether someone is attempting to buckle something to their own child var parent = Transform(strapUid).ParentUid; while (parent.IsValid()) { - if (parent == userUid) + if (parent != buckleUid) + { + parent = Transform(parent).ParentUid; + continue; + } + + if (popup) { - var message = Loc.GetString(buckleUid == userUid + var message = Loc.GetString(buckleUid == user ? "buckle-component-cannot-buckle-message" - : "buckle-component-other-cannot-buckle-message", ("owner", Identity.Entity(buckleUid, EntityManager))); - if (_netManager.IsServer) - _popup.PopupEntity(message, userUid, userUid); + : "buckle-component-other-cannot-buckle-message", + ("owner", Identity.Entity(buckleUid, EntityManager))); - return false; + _popup.PopupClient(message, user); } - parent = Transform(parent).ParentUid; + return false; } if (!StrapHasSpace(strapUid, buckleComp, strapComp)) { - var message = Loc.GetString(buckleUid == userUid - ? "buckle-component-cannot-fit-message" - : "buckle-component-other-cannot-fit-message", ("owner", Identity.Entity(buckleUid, EntityManager))); - if (_netManager.IsServer) - _popup.PopupEntity(message, userUid, userUid); + if (popup) + { + var message = Loc.GetString(buckleUid == user + ? "buckle-component-cannot-buckle-message" + : "buckle-component-other-cannot-buckle-message", + ("owner", Identity.Entity(buckleUid, EntityManager))); + + _popup.PopupClient(message, user); + } return false; } - var attemptEvent = new BuckleAttemptEvent(strapUid, buckleUid, userUid, true); - RaiseLocalEvent(attemptEvent.BuckledEntity, ref attemptEvent); - RaiseLocalEvent(attemptEvent.StrapEntity, ref attemptEvent); - if (attemptEvent.Cancelled) + var buckleAttempt = new BuckleAttemptEvent((strapUid, strapComp), (buckleUid, buckleComp), user, popup); + RaiseLocalEvent(buckleUid, ref buckleAttempt); + if (buckleAttempt.Cancelled) + return false; + + var strapAttempt = new StrapAttemptEvent((strapUid, strapComp), (buckleUid, buckleComp), user, popup); + RaiseLocalEvent(strapUid, ref strapAttempt); + if (strapAttempt.Cancelled) return false; return true; @@ -309,217 +320,199 @@ private bool CanBuckle( /// <summary> /// Attempts to buckle an entity to a strap /// </summary> - /// <param name="buckleUid"> Uid of the owner of BuckleComponent </param> - /// <param name="userUid"> + /// <param name="buckle"> Uid of the owner of BuckleComponent </param> + /// <param name="user"> /// Uid of a third party entity, /// i.e, the uid of someone else you are dragging to a chair. /// Can equal buckleUid sometimes /// </param> - /// <param name="strapUid"> Uid of the owner of strap component </param> - public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid, BuckleComponent? buckleComp = null) + /// <param name="strap"> Uid of the owner of strap component </param> + public bool TryBuckle(EntityUid buckle, EntityUid? user, EntityUid strap, BuckleComponent? buckleComp = null, bool popup = true) { - if (!Resolve(buckleUid, ref buckleComp, false)) + if (!Resolve(buckle, ref buckleComp, false)) return false; - if (!CanBuckle(buckleUid, userUid, strapUid, out var strapComp, buckleComp)) + if (!CanBuckle(buckle, user, strap, popup, out var strapComp, buckleComp)) return false; - if (!StrapTryAdd(strapUid, buckleUid, buckleComp, false, strapComp)) - { - var message = Loc.GetString(buckleUid == userUid - ? "buckle-component-cannot-buckle-message" - : "buckle-component-other-cannot-buckle-message", ("owner", Identity.Entity(buckleUid, EntityManager))); - if (_netManager.IsServer) - _popup.PopupEntity(message, userUid, userUid); - return false; - } + Buckle((buckle, buckleComp), (strap, strapComp), user); + return true; + } - if (TryComp<AppearanceComponent>(buckleUid, out var appearance)) - Appearance.SetData(buckleUid, BuckleVisuals.Buckled, true, appearance); + private void Buckle(Entity<BuckleComponent> buckle, Entity<StrapComponent> strap, EntityUid? user) + { + if (user == buckle.Owner) + _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user):player} buckled themselves to {ToPrettyString(strap)}"); + else if (user != null) + _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user):player} buckled {ToPrettyString(buckle)} to {ToPrettyString(strap)}"); - _rotationVisuals.SetHorizontalAngle(buckleUid, strapComp.Rotation); + _audio.PlayPredicted(strap.Comp.BuckleSound, strap, user); - ReAttach(buckleUid, strapUid, buckleComp, strapComp); - SetBuckledTo(buckleUid, strapUid, strapComp, buckleComp); - // TODO user is currently set to null because if it isn't the sound fails to play in some situations, fix that - _audio.PlayPredicted(strapComp.BuckleSound, strapUid, userUid); + SetBuckledTo(buckle, strap!); + Appearance.SetData(strap, StrapVisuals.State, true); + Appearance.SetData(buckle, BuckleVisuals.Buckled, true); - var ev = new BuckleChangeEvent(strapUid, buckleUid, true); - RaiseLocalEvent(ev.BuckledEntity, ref ev); - RaiseLocalEvent(ev.StrapEntity, ref ev); + _rotationVisuals.SetHorizontalAngle(buckle.Owner, strap.Comp.Rotation); - if (TryComp<PullableComponent>(buckleUid, out var ownerPullable)) - { - if (ownerPullable.Puller != null) - { - _pulling.TryStopPull(buckleUid, ownerPullable); - } - } + var xform = Transform(buckle); + var coords = new EntityCoordinates(strap, strap.Comp.BuckleOffset); + _transform.SetCoordinates(buckle, xform, coords, rotation: Angle.Zero); - if (TryComp<PhysicsComponent>(buckleUid, out var physics)) - { - _physics.ResetDynamics(buckleUid, physics); - } + _joints.SetRelay(buckle, strap); - if (!buckleComp.PullStrap && TryComp<PullableComponent>(strapUid, out var toPullable)) + switch (strap.Comp.Position) { - if (toPullable.Puller == buckleUid) - { - // can't pull it and buckle to it at the same time - _pulling.TryStopPull(strapUid, toPullable); - } + case StrapPosition.Stand: + _standing.Stand(buckle); + break; + case StrapPosition.Down: + _standing.Down(buckle, false, false); + break; } - // Logging - if (userUid != buckleUid) - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(userUid):player} buckled {ToPrettyString(buckleUid)} to {ToPrettyString(strapUid)}"); - else - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(userUid):player} buckled themselves to {ToPrettyString(strapUid)}"); + var ev = new StrappedEvent(strap, buckle); + RaiseLocalEvent(strap, ref ev); - return true; + var gotEv = new BuckledEvent(strap, buckle); + RaiseLocalEvent(buckle, ref gotEv); + + if (TryComp<PhysicsComponent>(buckle, out var physics)) + _physics.ResetDynamics(buckle, physics); + + DebugTools.AssertEqual(xform.ParentUid, strap.Owner); } /// <summary> /// Tries to unbuckle the Owner of this component from its current strap. /// </summary> /// <param name="buckleUid">The entity to unbuckle.</param> - /// <param name="userUid">The entity doing the unbuckling.</param> - /// <param name="force"> - /// Whether to force the unbuckling or not. Does not guarantee true to - /// be returned, but guarantees the owner to be unbuckled afterwards. - /// </param> + /// <param name="user">The entity doing the unbuckling.</param> /// <param name="buckleComp">The buckle component of the entity to unbuckle.</param> /// <returns> /// true if the owner was unbuckled, otherwise false even if the owner /// was previously already unbuckled. /// </returns> - public bool TryUnbuckle(EntityUid buckleUid, EntityUid userUid, bool force = false, BuckleComponent? buckleComp = null) + public bool TryUnbuckle(EntityUid buckleUid, + EntityUid? user, + BuckleComponent? buckleComp = null, + bool popup = true) { - if (!Resolve(buckleUid, ref buckleComp, false) || - buckleComp.BuckledTo is not { } strapUid) + return TryUnbuckle((buckleUid, buckleComp), user, popup); + } + + public bool TryUnbuckle(Entity<BuckleComponent?> buckle, EntityUid? user, bool popup) + { + if (!Resolve(buckle.Owner, ref buckle.Comp)) return false; - if (!force) - { - var attemptEvent = new BuckleAttemptEvent(strapUid, buckleUid, userUid, false); - RaiseLocalEvent(attemptEvent.BuckledEntity, ref attemptEvent); - RaiseLocalEvent(attemptEvent.StrapEntity, ref attemptEvent); - if (attemptEvent.Cancelled) - return false; + if (!CanUnbuckle(buckle, user, popup, out var strap)) + return false; - if (_gameTiming.CurTime < buckleComp.BuckleTime + buckleComp.Delay) - return false; + Unbuckle(buckle!, strap, user); + return true; + } - if (!_interaction.InRangeUnobstructed(userUid, strapUid, buckleComp.Range, popup: true)) - return false; + public void Unbuckle(Entity<BuckleComponent?> buckle, EntityUid? user) + { + if (!Resolve(buckle.Owner, ref buckle.Comp, false)) + return; - if (HasComp<SleepingComponent>(buckleUid) && buckleUid == userUid) - return false; + if (buckle.Comp.BuckledTo is not { } strap) + return; - // If the person is crit or dead in any kind of strap, return. This prevents people from unbuckling themselves while incapacitated. - if (_mobState.IsIncapacitated(buckleUid) && userUid == buckleUid) - return false; + if (!TryComp(strap, out StrapComponent? strapComp)) + { + Log.Error($"Encountered buckle {ToPrettyString(buckle.Owner)} with invalid strap entity {ToPrettyString(strap)}"); + SetBuckledTo(buckle!, null); + return; } - // Logging - if (userUid != buckleUid) - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(userUid):player} unbuckled {ToPrettyString(buckleUid)} from {ToPrettyString(strapUid)}"); - else - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(userUid):player} unbuckled themselves from {ToPrettyString(strapUid)}"); + Unbuckle(buckle!, (strap, strapComp), user); + } - SetBuckledTo(buckleUid, null, null, buckleComp); + private void Unbuckle(Entity<BuckleComponent> buckle, Entity<StrapComponent> strap, EntityUid? user) + { + if (user == buckle.Owner) + _adminLogger.Add(LogType.Action, LogImpact.Low, $"{user} unbuckled themselves from {strap}"); + else if (user != null) + _adminLogger.Add(LogType.Action, LogImpact.Low, $"{user} unbuckled {buckle} from {strap}"); - if (!TryComp<StrapComponent>(strapUid, out var strapComp)) - return false; + _audio.PlayPredicted(strap.Comp.UnbuckleSound, strap, user); - var buckleXform = Transform(buckleUid); - var oldBuckledXform = Transform(strapUid); + SetBuckledTo(buckle, null); - if (buckleXform.ParentUid == strapUid && !Terminating(buckleXform.ParentUid)) + var buckleXform = Transform(buckle); + var oldBuckledXform = Transform(strap); + + if (buckleXform.ParentUid == strap.Owner && !Terminating(buckleXform.ParentUid)) { - _container.AttachParentToContainerOrGrid((buckleUid, buckleXform)); + _transform.PlaceNextTo((buckle, buckleXform), (strap.Owner, oldBuckledXform)); + buckleXform.ActivelyLerping = false; - var oldBuckledToWorldRot = _transform.GetWorldRotation(strapUid); - _transform.SetWorldRotation(buckleXform, oldBuckledToWorldRot); + var oldBuckledToWorldRot = _transform.GetWorldRotation(strap); + _transform.SetWorldRotationNoLerp((buckle, buckleXform), oldBuckledToWorldRot); - if (strapComp.UnbuckleOffset != Vector2.Zero) - buckleXform.Coordinates = oldBuckledXform.Coordinates.Offset(strapComp.UnbuckleOffset); + // TODO: This is doing 4 moveevents this is why I left the warning in, if you're going to remove it make it only do 1 moveevent. + if (strap.Comp.BuckleOffset != Vector2.Zero) + { + buckleXform.Coordinates = oldBuckledXform.Coordinates.Offset(strap.Comp.BuckleOffset); + } } - if (TryComp(buckleUid, out AppearanceComponent? appearance)) - Appearance.SetData(buckleUid, BuckleVisuals.Buckled, false, appearance); - _rotationVisuals.ResetHorizontalAngle(buckleUid); + _rotationVisuals.ResetHorizontalAngle(buckle.Owner); + Appearance.SetData(strap, StrapVisuals.State, strap.Comp.BuckledEntities.Count != 0); + Appearance.SetData(buckle, BuckleVisuals.Buckled, false); - if (TryComp<MobStateComponent>(buckleUid, out var mobState) - && _mobState.IsIncapacitated(buckleUid, mobState) - || HasComp<KnockedDownComponent>(buckleUid)) - { - _standing.Down(buckleUid); - } + if (HasComp<KnockedDownComponent>(buckle) || _mobState.IsIncapacitated(buckle)) + _standing.Down(buckle, playSound: false); else - { - _standing.Stand(buckleUid); - } + _standing.Stand(buckle); - if (_mobState.IsIncapacitated(buckleUid, mobState)) - { - _standing.Down(buckleUid); - } - if (strapComp.BuckledEntities.Remove(buckleUid)) - { - strapComp.OccupiedSize -= buckleComp.Size; - //Dirty(strapUid); - Dirty(strapComp); - } + _joints.RefreshRelay(buckle); - _joints.RefreshRelay(buckleUid); - Appearance.SetData(strapUid, StrapVisuals.State, strapComp.BuckledEntities.Count != 0); + var buckleEv = new UnbuckledEvent(strap, buckle); + RaiseLocalEvent(buckle, ref buckleEv); - // TODO: Buckle listening to moveevents is sussy anyway. - if (!TerminatingOrDeleted(strapUid)) - _audio.PlayPredicted(strapComp.UnbuckleSound, strapUid, userUid); - - var ev = new BuckleChangeEvent(strapUid, buckleUid, false); - RaiseLocalEvent(buckleUid, ref ev); - RaiseLocalEvent(strapUid, ref ev); + var strapEv = new UnstrappedEvent(strap, buckle); + RaiseLocalEvent(strap, ref strapEv); + } - return true; + public bool CanUnbuckle(Entity<BuckleComponent?> buckle, EntityUid user, bool popup) + { + return CanUnbuckle(buckle, user, popup, out _); } - /// <summary> - /// Makes an entity toggle the buckling status of the owner to a - /// specific entity. - /// </summary> - /// <param name="buckleUid">The entity to buckle/unbuckle from <see cref="to"/>.</param> - /// <param name="userUid">The entity doing the buckling/unbuckling.</param> - /// <param name="strapUid"> - /// The entity to toggle the buckle status of the owner to. - /// </param> - /// <param name="force"> - /// Whether to force the unbuckling or not, if it happens. Does not - /// guarantee true to be returned, but guarantees the owner to be - /// unbuckled afterwards. - /// </param> - /// <param name="buckle">The buckle component of the entity to buckle/unbuckle from <see cref="to"/>.</param> - /// <returns>true if the buckling status was changed, false otherwise.</returns> - public bool ToggleBuckle( - EntityUid buckleUid, - EntityUid userUid, - EntityUid strapUid, - bool force = false, - BuckleComponent? buckle = null) + private bool CanUnbuckle(Entity<BuckleComponent?> buckle, EntityUid? user, bool popup, out Entity<StrapComponent> strap) { - if (!Resolve(buckleUid, ref buckle, false)) + strap = default; + if (!Resolve(buckle.Owner, ref buckle.Comp)) return false; - if (!buckle.Buckled) - { - return TryBuckle(buckleUid, userUid, strapUid, buckle); - } - else + if (buckle.Comp.BuckledTo is not { } strapUid) + return false; + + if (!TryComp(strapUid, out StrapComponent? strapComp)) { - return TryUnbuckle(buckleUid, userUid, force, buckle); + Log.Error($"Encountered buckle {ToPrettyString(buckle.Owner)} with invalid strap entity {ToPrettyString(strap)}"); + SetBuckledTo(buckle!, null); + return false; } + strap = (strapUid, strapComp); + if (_gameTiming.CurTime < buckle.Comp.BuckleTime + buckle.Comp.Delay) + return false; + + if (user != null && !_interaction.InRangeUnobstructed(user.Value, strap.Owner, buckle.Comp.Range, popup: popup)) + return false; + + var unbuckleAttempt = new UnbuckleAttemptEvent(strap, buckle!, user, popup); + RaiseLocalEvent(buckle, ref unbuckleAttempt); + if (unbuckleAttempt.Cancelled) + return false; + + var unstrapAttempt = new UnstrapAttemptEvent(strap, buckle!, user, popup); + RaiseLocalEvent(strap, ref unstrapAttempt); + return !unstrapAttempt.Cancelled; } -} + +} \ No newline at end of file diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs b/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs new file mode 100644 index 00000000000..59eff1f8c87 --- /dev/null +++ b/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs @@ -0,0 +1,200 @@ +using System.Linq; +using Content.Shared.Buckle.Components; +using Content.Shared.DoAfter; +using Content.Shared.DragDrop; +using Content.Shared.IdentityManagement; +using Content.Shared.Interaction; +using Content.Shared.Verbs; +using Robust.Shared.Utility; + +namespace Content.Shared.Buckle; + +// Partial class containing interaction & verb event handlers +public abstract partial class SharedBuckleSystem +{ + private void InitializeInteraction() + { + SubscribeLocalEvent<StrapComponent, GetVerbsEvent<InteractionVerb>>(AddStrapVerbs); + SubscribeLocalEvent<StrapComponent, InteractHandEvent>(OnStrapInteractHand); + SubscribeLocalEvent<StrapComponent, DragDropTargetEvent>(OnStrapDragDropTarget); + SubscribeLocalEvent<StrapComponent, CanDropTargetEvent>(OnCanDropTarget); + + SubscribeLocalEvent<BuckleComponent, GetVerbsEvent<InteractionVerb>>(AddUnbuckleVerb); + } + + private void OnCanDropTarget(EntityUid uid, StrapComponent component, ref CanDropTargetEvent args) + { + args.CanDrop = StrapCanDragDropOn(uid, args.User, uid, args.Dragged, component); + args.Handled = true; + } + + private void OnStrapDragDropTarget(EntityUid uid, StrapComponent component, ref DragDropTargetEvent args) + { + if (!StrapCanDragDropOn(uid, args.User, uid, args.Dragged, component)) + return; + + args.Handled = TryBuckle(args.Dragged, args.User, uid, popup: false); + } + + private bool StrapCanDragDropOn( + EntityUid strapUid, + EntityUid userUid, + EntityUid targetUid, + EntityUid buckleUid, + StrapComponent? strapComp = null, + BuckleComponent? buckleComp = null) + { + if (!Resolve(strapUid, ref strapComp, false) || + !Resolve(buckleUid, ref buckleComp, false)) + { + return false; + } + + bool Ignored(EntityUid entity) => entity == userUid || entity == buckleUid || entity == targetUid; + + return _interaction.InRangeUnobstructed(targetUid, buckleUid, buckleComp.Range, predicate: Ignored); + } + + private void OnStrapInteractHand(EntityUid uid, StrapComponent component, InteractHandEvent args) + { + if (args.Handled) + return; + + if (!TryComp(args.User, out BuckleComponent? buckle)) + return; + + // Buckle self + if (buckle.BuckledTo == null && component.BuckleOnInteractHand && StrapHasSpace(uid, buckle, component)) + { + TryBuckle(args.User, args.User, uid, buckle, popup: true); + args.Handled = true; + return; + } + + // Unbuckle self + if (buckle.BuckledTo == uid && TryUnbuckle(args.User, args.User, buckle, popup: true)) + { + args.Handled = true; + return; + } + + // Unbuckle others + if (component.BuckledEntities.TryFirstOrNull(out var buckled) && TryUnbuckle(buckled.Value, args.User)) + { + args.Handled = true; + return; + } + + // TODO BUCKLE add out bool for whether a pop-up was generated or not. + } + + private void OnBuckleInteractHand(Entity<BuckleComponent> ent, ref InteractHandEvent args) + { + if (args.Handled) + return; + + if (ent.Comp.BuckledTo != null) + TryUnbuckle(ent!, args.User, popup: true); + + // TODO BUCKLE add out bool for whether a pop-up was generated or not. + args.Handled = true; + } + + private void AddStrapVerbs(EntityUid uid, StrapComponent component, GetVerbsEvent<InteractionVerb> args) + { + if (args.Hands == null || !args.CanAccess || !args.CanInteract || !component.Enabled) + return; + + // Note that for whatever bloody reason, buckle component has its own interaction range. Additionally, this + // range can be set per-component, so we have to check a modified InRangeUnobstructed for every verb. + + // Add unstrap verbs for every strapped entity. + foreach (var entity in component.BuckledEntities) + { + var buckledComp = Comp<BuckleComponent>(entity); + + if (!_interaction.InRangeUnobstructed(args.User, args.Target, range: buckledComp.Range)) + continue; + + var verb = new InteractionVerb() + { + Act = () => TryUnbuckle(entity, args.User, buckleComp: buckledComp), + Category = VerbCategory.Unbuckle, + Text = entity == args.User + ? Loc.GetString("verb-self-target-pronoun") + : Identity.Name(entity, EntityManager) + }; + + // In the event that you have more than once entity with the same name strapped to the same object, + // these two verbs will be identical according to Verb.CompareTo, and only one with actually be added to + // the verb list. However this should rarely ever be a problem. If it ever is, it could be fixed by + // appending an integer to verb.Text to distinguish the verbs. + + args.Verbs.Add(verb); + } + + // Add a verb to buckle the user. + if (TryComp<BuckleComponent>(args.User, out var buckle) && + buckle.BuckledTo != uid && + args.User != uid && + StrapHasSpace(uid, buckle, component) && + _interaction.InRangeUnobstructed(args.User, args.Target, range: buckle.Range)) + { + InteractionVerb verb = new() + { + Act = () => TryBuckle(args.User, args.User, args.Target, buckle), + Category = VerbCategory.Buckle, + Text = Loc.GetString("verb-self-target-pronoun") + }; + args.Verbs.Add(verb); + } + + // If the user is currently holding/pulling an entity that can be buckled, add a verb for that. + if (args.Using is { Valid: true } @using && + TryComp<BuckleComponent>(@using, out var usingBuckle) && + StrapHasSpace(uid, usingBuckle, component) && + _interaction.InRangeUnobstructed(@using, args.Target, range: usingBuckle.Range)) + { + // Check that the entity is unobstructed from the target (ignoring the user). + bool Ignored(EntityUid entity) => entity == args.User || entity == args.Target || entity == @using; + if (!_interaction.InRangeUnobstructed(@using, args.Target, usingBuckle.Range, predicate: Ignored)) + return; + + var isPlayer = _playerManager.TryGetSessionByEntity(@using, out var _); + InteractionVerb verb = new() + { + Act = () => TryBuckle(@using, args.User, args.Target, usingBuckle), + Category = VerbCategory.Buckle, + Text = Identity.Name(@using, EntityManager), + // just a held object, the user is probably just trying to sit down. + // If the used entity is a person being pulled, prioritize this verb. Conversely, if it is + Priority = isPlayer ? 1 : -1 + }; + + args.Verbs.Add(verb); + } + } + + private void AddUnbuckleVerb(EntityUid uid, BuckleComponent component, GetVerbsEvent<InteractionVerb> args) + { + if (!args.CanAccess || !args.CanInteract || !component.Buckled) + return; + + InteractionVerb verb = new() + { + Act = () => TryUnbuckle(uid, args.User, buckleComp: component), + Text = Loc.GetString("verb-categories-unbuckle"), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png")) + }; + + if (args.Target == args.User && args.Using == null) + { + // A user is left clicking themselves with an empty hand, while buckled. + // It is very likely they are trying to unbuckle themselves. + verb.Priority = 1; + } + + args.Verbs.Add(verb); + } + +} diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs b/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs index 7be54360741..eb23aa973b4 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs @@ -2,40 +2,26 @@ using Content.Shared.Buckle.Components; using Content.Shared.Construction; using Content.Shared.Destructible; -using Content.Shared.DragDrop; using Content.Shared.Foldable; -using Content.Shared.Interaction; -using Content.Shared.Rotation; using Content.Shared.Storage; -using Content.Shared.Verbs; using Robust.Shared.Containers; namespace Content.Shared.Buckle; public abstract partial class SharedBuckleSystem { - [Dependency] private readonly SharedRotationVisualsSystem _rotationVisuals = default!; - private void InitializeStrap() { SubscribeLocalEvent<StrapComponent, ComponentStartup>(OnStrapStartup); SubscribeLocalEvent<StrapComponent, ComponentShutdown>(OnStrapShutdown); - SubscribeLocalEvent<StrapComponent, ComponentRemove>((_, c, _) => StrapRemoveAll(c)); + SubscribeLocalEvent<StrapComponent, ComponentRemove>((e, c, _) => StrapRemoveAll(e, c)); - SubscribeLocalEvent<StrapComponent, EntInsertedIntoContainerMessage>(OnStrapEntModifiedFromContainer); - SubscribeLocalEvent<StrapComponent, EntRemovedFromContainerMessage>(OnStrapEntModifiedFromContainer); - SubscribeLocalEvent<StrapComponent, GetVerbsEvent<InteractionVerb>>(AddStrapVerbs); SubscribeLocalEvent<StrapComponent, ContainerGettingInsertedAttemptEvent>(OnStrapContainerGettingInsertedAttempt); - SubscribeLocalEvent<StrapComponent, InteractHandEvent>(OnStrapInteractHand); - SubscribeLocalEvent<StrapComponent, DestructionEventArgs>((_,c,_) => StrapRemoveAll(c)); - SubscribeLocalEvent<StrapComponent, BreakageEventArgs>((_, c, _) => StrapRemoveAll(c)); + SubscribeLocalEvent<StrapComponent, DestructionEventArgs>((e, c, _) => StrapRemoveAll(e, c)); + SubscribeLocalEvent<StrapComponent, BreakageEventArgs>((e, c, _) => StrapRemoveAll(e, c)); - SubscribeLocalEvent<StrapComponent, DragDropTargetEvent>(OnStrapDragDropTarget); - SubscribeLocalEvent<StrapComponent, CanDropTargetEvent>(OnCanDropTarget); SubscribeLocalEvent<StrapComponent, FoldAttemptEvent>(OnAttemptFold); - - SubscribeLocalEvent<StrapComponent, MoveEvent>(OnStrapMoveEvent); - SubscribeLocalEvent<StrapComponent, MachineDeconstructedEvent>((_, c, _) => StrapRemoveAll(c)); + SubscribeLocalEvent<StrapComponent, MachineDeconstructedEvent>((e, c, _) => StrapRemoveAll(e, c)); } private void OnStrapStartup(EntityUid uid, StrapComponent component, ComponentStartup args) @@ -45,145 +31,17 @@ private void OnStrapStartup(EntityUid uid, StrapComponent component, ComponentSt private void OnStrapShutdown(EntityUid uid, StrapComponent component, ComponentShutdown args) { - if (LifeStage(uid) > EntityLifeStage.MapInitialized) - return; - - StrapRemoveAll(component); - } - - private void OnStrapEntModifiedFromContainer(EntityUid uid, StrapComponent component, ContainerModifiedMessage message) - { - if (_gameTiming.ApplyingState) - return; - - foreach (var buckledEntity in component.BuckledEntities) - { - if (!TryComp<BuckleComponent>(buckledEntity, out var buckleComp)) - { - continue; - } - - ContainerModifiedReAttach(buckledEntity, uid, buckleComp, component); - } - } - - private void ContainerModifiedReAttach(EntityUid buckleUid, EntityUid strapUid, BuckleComponent? buckleComp = null, StrapComponent? strapComp = null) - { - if (!Resolve(buckleUid, ref buckleComp, false) || - !Resolve(strapUid, ref strapComp, false)) - return; - - var contained = _container.TryGetContainingContainer(buckleUid, out var ownContainer); - var strapContained = _container.TryGetContainingContainer(strapUid, out var strapContainer); - - if (contained != strapContained || ownContainer != strapContainer) - { - TryUnbuckle(buckleUid, buckleUid, true, buckleComp); - return; - } - - if (!contained) - { - ReAttach(buckleUid, strapUid, buckleComp, strapComp); - } + if (!TerminatingOrDeleted(uid)) + StrapRemoveAll(uid, component); } private void OnStrapContainerGettingInsertedAttempt(EntityUid uid, StrapComponent component, ContainerGettingInsertedAttemptEvent args) { // If someone is attempting to put this item inside of a backpack, ensure that it has no entities strapped to it. - if (HasComp<StorageComponent>(args.Container.Owner) && component.BuckledEntities.Count != 0) + if (args.Container.ID == StorageComponent.ContainerId && component.BuckledEntities.Count != 0) args.Cancel(); } - private void OnStrapInteractHand(EntityUid uid, StrapComponent component, InteractHandEvent args) - { - if (args.Handled) - return; - - args.Handled = ToggleBuckle(args.User, args.User, uid); - } - - private void AddStrapVerbs(EntityUid uid, StrapComponent component, GetVerbsEvent<InteractionVerb> args) - { - if (args.Hands == null || !args.CanAccess || !args.CanInteract || !component.Enabled) - return; - - // Note that for whatever bloody reason, buckle component has its own interaction range. Additionally, this - // range can be set per-component, so we have to check a modified InRangeUnobstructed for every verb. - - // Add unstrap verbs for every strapped entity. - foreach (var entity in component.BuckledEntities) - { - var buckledComp = Comp<BuckleComponent>(entity); - - if (!_interaction.InRangeUnobstructed(args.User, args.Target, range: buckledComp.Range)) - continue; - - var verb = new InteractionVerb() - { - Act = () => TryUnbuckle(entity, args.User, buckleComp: buckledComp), - Category = VerbCategory.Unbuckle, - Text = entity == args.User - ? Loc.GetString("verb-self-target-pronoun") - : Comp<MetaDataComponent>(entity).EntityName - }; - - // In the event that you have more than once entity with the same name strapped to the same object, - // these two verbs will be identical according to Verb.CompareTo, and only one with actually be added to - // the verb list. However this should rarely ever be a problem. If it ever is, it could be fixed by - // appending an integer to verb.Text to distinguish the verbs. - - args.Verbs.Add(verb); - } - - // Add a verb to buckle the user. - if (TryComp<BuckleComponent>(args.User, out var buckle) && - buckle.BuckledTo != uid && - args.User != uid && - StrapHasSpace(uid, buckle, component) && - _interaction.InRangeUnobstructed(args.User, args.Target, range: buckle.Range)) - { - InteractionVerb verb = new() - { - Act = () => TryBuckle(args.User, args.User, args.Target, buckle), - Category = VerbCategory.Buckle, - Text = Loc.GetString("verb-self-target-pronoun") - }; - args.Verbs.Add(verb); - } - - // If the user is currently holding/pulling an entity that can be buckled, add a verb for that. - if (args.Using is {Valid: true} @using && - TryComp<BuckleComponent>(@using, out var usingBuckle) && - StrapHasSpace(uid, usingBuckle, component) && - _interaction.InRangeUnobstructed(@using, args.Target, range: usingBuckle.Range)) - { - // Check that the entity is unobstructed from the target (ignoring the user). - bool Ignored(EntityUid entity) => entity == args.User || entity == args.Target || entity == @using; - if (!_interaction.InRangeUnobstructed(@using, args.Target, usingBuckle.Range, predicate: Ignored)) - return; - - var isPlayer = _playerManager.TryGetSessionByEntity(@using, out var _); - InteractionVerb verb = new() - { - Act = () => TryBuckle(@using, args.User, args.Target, usingBuckle), - Category = VerbCategory.Buckle, - Text = Comp<MetaDataComponent>(@using).EntityName, - // just a held object, the user is probably just trying to sit down. - // If the used entity is a person being pulled, prioritize this verb. Conversely, if it is - Priority = isPlayer ? 1 : -1 - }; - - args.Verbs.Add(verb); - } - } - - private void OnCanDropTarget(EntityUid uid, StrapComponent component, ref CanDropTargetEvent args) - { - args.CanDrop = StrapCanDragDropOn(uid, args.User, uid, args.Dragged, component); - args.Handled = true; - } - private void OnAttemptFold(EntityUid uid, StrapComponent component, ref FoldAttemptEvent args) { if (args.Cancelled) @@ -192,82 +50,15 @@ private void OnAttemptFold(EntityUid uid, StrapComponent component, ref FoldAtte args.Cancelled = component.BuckledEntities.Count != 0; } - private void OnStrapDragDropTarget(EntityUid uid, StrapComponent component, ref DragDropTargetEvent args) - { - if (!StrapCanDragDropOn(uid, args.User, uid, args.Dragged, component)) - return; - - args.Handled = TryBuckle(args.Dragged, args.User, uid); - } - - private void OnStrapMoveEvent(EntityUid uid, StrapComponent component, ref MoveEvent args) - { - // TODO: This looks dirty af. - // On rotation of a strap, reattach all buckled entities. - // This fixes buckle offsets and draw depths. - // This is mega cursed. Please somebody save me from Mr Buckle's wild ride. - // Oh god I'm back here again. Send help. - - // Consider a chair that has a player strapped to it. Then the client receives a new server state, showing - // that the player entity has moved elsewhere, and the chair has rotated. If the client applies the player - // state, then the chairs transform comp state, and then the buckle state. The transform state will - // forcefully teleport the player back to the chair (client-side only). This causes even more issues if the - // chair was teleporting in from nullspace after having left PVS. - // - // One option is to just never trigger re-buckles during state application. - // another is to.. just not do this? Like wtf is this code. But I CBF with buckle atm. - - if (_gameTiming.ApplyingState || args.NewRotation == args.OldRotation) - return; - - foreach (var buckledEntity in component.BuckledEntities) - { - if (!TryComp<BuckleComponent>(buckledEntity, out var buckled)) - continue; - - if (!buckled.Buckled || buckled.LastEntityBuckledTo != uid) - { - Log.Error($"A moving strap entity {ToPrettyString(uid)} attempted to re-parent an entity that does not 'belong' to it {ToPrettyString(buckledEntity)}"); - continue; - } - - ReAttach(buckledEntity, uid, buckled, component); - Dirty(buckled); - } - } - - private bool StrapCanDragDropOn( - EntityUid strapUid, - EntityUid userUid, - EntityUid targetUid, - EntityUid buckleUid, - StrapComponent? strapComp = null, - BuckleComponent? buckleComp = null) - { - if (!Resolve(strapUid, ref strapComp, false) || - !Resolve(buckleUid, ref buckleComp, false)) - { - return false; - } - - bool Ignored(EntityUid entity) => entity == userUid || entity == buckleUid || entity == targetUid; - - return _interaction.InRangeUnobstructed(targetUid, buckleUid, buckleComp.Range, predicate: Ignored); - } - /// <summary> /// Remove everything attached to the strap /// </summary> - private void StrapRemoveAll(StrapComponent strapComp) + private void StrapRemoveAll(EntityUid uid, StrapComponent strapComp) { foreach (var entity in strapComp.BuckledEntities.ToArray()) { TryUnbuckle(entity, entity, true); } - - strapComp.BuckledEntities.Clear(); - strapComp.OccupiedSize = 0; - Dirty(strapComp); } private bool StrapHasSpace(EntityUid strapUid, BuckleComponent buckleComp, StrapComponent? strapComp = null) @@ -275,30 +66,13 @@ private bool StrapHasSpace(EntityUid strapUid, BuckleComponent buckleComp, Strap if (!Resolve(strapUid, ref strapComp, false)) return false; - return strapComp.OccupiedSize + buckleComp.Size <= strapComp.Size; - } - - /// <summary> - /// Try to add an entity to the strap - /// </summary> - private bool StrapTryAdd(EntityUid strapUid, EntityUid buckleUid, BuckleComponent buckleComp, bool force = false, StrapComponent? strapComp = null) - { - if (!Resolve(strapUid, ref strapComp, false) || - !strapComp.Enabled) - return false; - - if (!force && !StrapHasSpace(strapUid, buckleComp, strapComp)) - return false; - - if (!strapComp.BuckledEntities.Add(buckleUid)) - return false; - - strapComp.OccupiedSize += buckleComp.Size; - - Appearance.SetData(strapUid, StrapVisuals.State, true); + var avail = strapComp.Size; + foreach (var buckle in strapComp.BuckledEntities) + { + avail -= CompOrNull<BuckleComponent>(buckle)?.Size ?? 0; + } - Dirty(strapUid, strapComp); - return true; + return avail >= buckleComp.Size; } /// <summary> @@ -311,8 +85,9 @@ public void StrapSetEnabled(EntityUid strapUid, bool enabled, StrapComponent? st return; strapComp.Enabled = enabled; + Dirty(strapUid, strapComp); if (!enabled) - StrapRemoveAll(strapComp); + StrapRemoveAll(strapUid, strapComp); } } diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index 67218657e52..770fababded 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -1,21 +1,17 @@ using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; using Content.Shared.Alert; -using Content.Shared.Buckle.Components; using Content.Shared.Interaction; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; -using Content.Shared.Pulling; +using Content.Shared.Rotation; using Content.Shared.Standing; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.Map; using Robust.Shared.Network; using Robust.Shared.Physics.Systems; using Robust.Shared.Player; using Robust.Shared.Timing; -using PullingSystem = Content.Shared.Movement.Pulling.Systems.PullingSystem; namespace Content.Shared.Buckle; @@ -36,10 +32,10 @@ public abstract partial class SharedBuckleSystem : EntitySystem [Dependency] private readonly SharedInteractionSystem _interaction = default!; [Dependency] private readonly SharedJointSystem _joints = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly StandingStateSystem _standing = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedRotationVisualsSystem _rotationVisuals = default!; /// <inheritdoc/> public override void Initialize() @@ -51,45 +47,6 @@ public override void Initialize() InitializeBuckle(); InitializeStrap(); - } - - /// <summary> - /// Reattaches this entity to the strap, modifying its position and rotation. - /// </summary> - /// <param name="buckleUid">The entity to reattach.</param> - /// <param name="strapUid">The entity to reattach the buckleUid entity to.</param> - private void ReAttach( - EntityUid buckleUid, - EntityUid strapUid, - BuckleComponent? buckleComp = null, - StrapComponent? strapComp = null) - { - if (!Resolve(strapUid, ref strapComp, false) - || !Resolve(buckleUid, ref buckleComp, false)) - return; - - _transform.SetCoordinates(buckleUid, new EntityCoordinates(strapUid, strapComp.BuckleOffsetClamped)); - - var buckleTransform = Transform(buckleUid); - - // Buckle subscribes to move for <reasons> so this might fail. - // TODO: Make buckle not do that. - if (buckleTransform.ParentUid != strapUid) - return; - - _transform.SetLocalRotation(buckleUid, Angle.Zero, buckleTransform); - _joints.SetRelay(buckleUid, strapUid); - - switch (strapComp.Position) - { - case StrapPosition.None: - break; - case StrapPosition.Stand: - _standing.Stand(buckleUid); - break; - case StrapPosition.Down: - _standing.Down(buckleUid, false, false); - break; - } + InitializeInteraction(); } } diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 603855679c4..d8276c04aeb 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -21,16 +21,10 @@ public sealed class CCVars : CVars CVarDef.Create("server.id", "unknown_server_id", CVar.REPLICATED | CVar.SERVER); /// <summary> - /// Name of the rules txt file in the "Resources/Server Info" dir. Include the extension. + /// Guide Entry Prototype ID to be displayed as the server rules. /// </summary> public static readonly CVarDef<string> RulesFile = - CVarDef.Create("server.rules_file", "Rules.txt", CVar.REPLICATED | CVar.SERVER); - - /// <summary> - /// A loc string for what should be displayed as the title on the Rules window. - /// </summary> - public static readonly CVarDef<string> RulesHeader = - CVarDef.Create("server.rules_header", "ui-rules-header", CVar.REPLICATED | CVar.SERVER); + CVarDef.Create("server.rules_file", "DefaultRuleset", CVar.REPLICATED | CVar.SERVER); /* * Ambience @@ -2071,7 +2065,13 @@ public static readonly CVarDef<string> /// Don't show rules to localhost/loopback interface. /// </summary> public static readonly CVarDef<bool> RulesExemptLocal = - CVarDef.Create("rules.exempt_local", true, CVar.SERVERONLY); + CVarDef.Create("rules.exempt_local", true, CVar.CLIENT); + + /// <summary> + /// The next time the rules will popup for this client, expressed in minutes + /// </summary> + public static readonly CVarDef<string> RulesNextPopupTime = + CVarDef.Create("rules.next_popup_time", "Jan 1, 1997", CVar.CLIENTONLY | CVar.ARCHIVE); /* diff --git a/Content.Shared/Chapel/SharedSacrificialAltarSystem.cs b/Content.Shared/Chapel/SharedSacrificialAltarSystem.cs index 92df7e0f6bf..61e9a68817c 100644 --- a/Content.Shared/Chapel/SharedSacrificialAltarSystem.cs +++ b/Content.Shared/Chapel/SharedSacrificialAltarSystem.cs @@ -15,7 +15,7 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent<SacrificialAltarComponent, ExaminedEvent>(OnExamined); - SubscribeLocalEvent<SacrificialAltarComponent, BuckleChangeEvent>(OnUnstrapped); + SubscribeLocalEvent<SacrificialAltarComponent, UnbuckledEvent>(OnUnstrapped); SubscribeLocalEvent<SacrificialAltarComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs); } @@ -24,7 +24,7 @@ private void OnExamined(Entity<SacrificialAltarComponent> ent, ref ExaminedEvent args.PushMarkup(Loc.GetString("altar-examine")); } - private void OnUnstrapped(Entity<SacrificialAltarComponent> ent, ref BuckleChangeEvent args) + private void OnUnstrapped(Entity<SacrificialAltarComponent> ent, ref UnbuckledEvent args) { if (ent.Comp.DoAfter is not { } id) return; diff --git a/Content.Shared/Climbing/Systems/ClimbSystem.cs b/Content.Shared/Climbing/Systems/ClimbSystem.cs index c570a821a6f..d2b5a25aee7 100644 --- a/Content.Shared/Climbing/Systems/ClimbSystem.cs +++ b/Content.Shared/Climbing/Systems/ClimbSystem.cs @@ -59,7 +59,7 @@ public override void Initialize() SubscribeLocalEvent<ClimbingComponent, EntParentChangedMessage>(OnParentChange); SubscribeLocalEvent<ClimbingComponent, ClimbDoAfterEvent>(OnDoAfter); SubscribeLocalEvent<ClimbingComponent, EndCollideEvent>(OnClimbEndCollide); - SubscribeLocalEvent<ClimbingComponent, BuckleChangeEvent>(OnBuckleChange); + SubscribeLocalEvent<ClimbingComponent, BuckledEvent>(OnBuckled); SubscribeLocalEvent<ClimbableComponent, CanDropTargetEvent>(OnCanDragDropOn); SubscribeLocalEvent<ClimbableComponent, GetVerbsEvent<AlternativeVerb>>(AddClimbableVerb); @@ -479,10 +479,8 @@ public void ForciblyStopClimbing(EntityUid uid, ClimbingComponent? climbing = nu StopClimb(uid, climbing, fixtures); } - private void OnBuckleChange(EntityUid uid, ClimbingComponent component, ref BuckleChangeEvent args) + private void OnBuckled(EntityUid uid, ClimbingComponent component, ref BuckledEvent args) { - if (!args.Buckling) - return; StopClimb(uid, component); } diff --git a/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs index a447a54df17..5bf1e6739e9 100644 --- a/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs @@ -77,7 +77,7 @@ protected virtual void UpdateSprite(EntityUid uid, EntityPrototype proto) { } public bool IsValidTarget(EntityPrototype proto, SlotFlags chameleonSlot = SlotFlags.NONE) { // check if entity is valid - if (proto.Abstract || proto.NoSpawn) + if (proto.Abstract || proto.HideSpawnMenu) return false; // check if it is marked as valid chameleon target diff --git a/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs b/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs index 7ee0676f9ef..1f0bb99904d 100644 --- a/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs +++ b/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs @@ -21,6 +21,7 @@ public sealed class LoadoutSystem : EntitySystem [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly IConfigurationManager _configuration = default!; [Dependency] private readonly CharacterRequirementsSystem _characterRequirements = default!; + [Dependency] private readonly SharedTransformSystem _sharedTransformSystem = default!; public override void Initialize() { @@ -79,7 +80,7 @@ public List<EntityUid> ApplyCharacterLoadout(EntityUid uid, JobPrototype job, Hu // Spawn the loadout items var spawned = EntityManager.SpawnEntities( - EntityManager.GetComponent<TransformComponent>(uid).Coordinates.ToMap(EntityManager), + _sharedTransformSystem.GetMapCoordinates(uid), loadoutProto.Items.Select(p => (string?) p.ToString()).ToList()); // Dumb cast foreach (var item in spawned) diff --git a/Content.Shared/Clothing/MagbootsComponent.cs b/Content.Shared/Clothing/MagbootsComponent.cs index 0d0d59f89f5..0d074ff38b6 100644 --- a/Content.Shared/Clothing/MagbootsComponent.cs +++ b/Content.Shared/Clothing/MagbootsComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Alert; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -16,4 +17,7 @@ public sealed partial class MagbootsComponent : Component [DataField("on"), AutoNetworkedField] public bool On; + + [DataField] + public ProtoId<AlertPrototype> MagbootsAlert = "Magboots"; } diff --git a/Content.Shared/CombatMode/Pacification/PacificationSystem.cs b/Content.Shared/CombatMode/Pacification/PacificationSystem.cs index 6d94c087af6..a927e1a6970 100644 --- a/Content.Shared/CombatMode/Pacification/PacificationSystem.cs +++ b/Content.Shared/CombatMode/Pacification/PacificationSystem.cs @@ -7,7 +7,6 @@ using Content.Shared.Popups; using Content.Shared.Throwing; using Content.Shared.Weapons.Ranged.Events; -using Content.Shared.Weapons.Ranged.Systems; using Robust.Shared.Timing; namespace Content.Shared.CombatMode.Pacification; @@ -109,7 +108,7 @@ private void OnStartup(EntityUid uid, PacifiedComponent component, ComponentStar _actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, false); } - _alertsSystem.ShowAlert(uid, AlertType.Pacified); + _alertsSystem.ShowAlert(uid, component.PacifiedAlert); } private void OnShutdown(EntityUid uid, PacifiedComponent component, ComponentShutdown args) @@ -121,7 +120,7 @@ private void OnShutdown(EntityUid uid, PacifiedComponent component, ComponentShu _combatSystem.SetCanDisarm(uid, true, combatMode); _actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, true); - _alertsSystem.ClearAlert(uid, AlertType.Pacified); + _alertsSystem.ClearAlert(uid, component.PacifiedAlert); } private void OnBeforeThrow(Entity<PacifiedComponent> ent, ref BeforeThrowEvent args) diff --git a/Content.Shared/CombatMode/Pacification/PacifiedComponent.cs b/Content.Shared/CombatMode/Pacification/PacifiedComponent.cs index 464ef778851..96081e5dc67 100644 --- a/Content.Shared/CombatMode/Pacification/PacifiedComponent.cs +++ b/Content.Shared/CombatMode/Pacification/PacifiedComponent.cs @@ -1,4 +1,6 @@ +using Content.Shared.Alert; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; namespace Content.Shared.CombatMode.Pacification; @@ -42,4 +44,6 @@ public sealed partial class PacifiedComponent : Component [DataField] public EntityUid? LastAttackedEntity = null; + [DataField] + public ProtoId<AlertPrototype> PacifiedAlert = "Pacified"; } diff --git a/Content.Shared/Containers/ContainerFillSystem.cs b/Content.Shared/Containers/ContainerFillSystem.cs index e120b6bc883..51c7c48e40f 100644 --- a/Content.Shared/Containers/ContainerFillSystem.cs +++ b/Content.Shared/Containers/ContainerFillSystem.cs @@ -1,4 +1,5 @@ using System.Numerics; +using Content.Shared.EntityTable; using Robust.Shared.Containers; using Robust.Shared.Map; @@ -7,11 +8,14 @@ namespace Content.Shared.Containers; public sealed class ContainerFillSystem : EntitySystem { [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] private readonly EntityTableSystem _entityTable = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent<ContainerFillComponent, MapInitEvent>(OnMapInit); + SubscribeLocalEvent<EntityTableContainerFillComponent, MapInitEvent>(OnTableMapInit); } private void OnMapInit(EntityUid uid, ContainerFillComponent component, MapInitEvent args) @@ -42,4 +46,37 @@ private void OnMapInit(EntityUid uid, ContainerFillComponent component, MapInitE } } } + + private void OnTableMapInit(Entity<EntityTableContainerFillComponent> ent, ref MapInitEvent args) + { + if (!TryComp(ent, out ContainerManagerComponent? containerComp)) + return; + + if (TerminatingOrDeleted(ent) || !Exists(ent)) + return; + + var xform = Transform(ent); + var coords = new EntityCoordinates(ent, Vector2.Zero); + + foreach (var (containerId, table) in ent.Comp.Containers) + { + if (!_containerSystem.TryGetContainer(ent, containerId, out var container, containerComp)) + { + Log.Error($"Entity {ToPrettyString(ent)} with a {nameof(EntityTableContainerFillComponent)} is missing a container ({containerId})."); + continue; + } + + var spawns = _entityTable.GetSpawns(table); + foreach (var proto in spawns) + { + var spawn = Spawn(proto, coords); + if (!_containerSystem.Insert(spawn, container, containerXform: xform)) + { + Log.Error($"Entity {ToPrettyString(ent)} with a {nameof(EntityTableContainerFillComponent)} failed to insert an entity: {ToPrettyString(spawn)}."); + _transform.AttachToGridOrMap(spawn); + break; + } + } + } + } } diff --git a/Content.Shared/Containers/EntityTableContainerFillComponent.cs b/Content.Shared/Containers/EntityTableContainerFillComponent.cs new file mode 100644 index 00000000000..3f30dc86d6d --- /dev/null +++ b/Content.Shared/Containers/EntityTableContainerFillComponent.cs @@ -0,0 +1,13 @@ +using Content.Shared.EntityTable.EntitySelectors; + +namespace Content.Shared.Containers; + +/// <summary> +/// Version of <see cref="ContainerFillComponent"/> that utilizes <see cref="EntityTableSelector"/> +/// </summary> +[RegisterComponent, Access(typeof(ContainerFillSystem))] +public sealed partial class EntityTableContainerFillComponent : Component +{ + [DataField] + public Dictionary<string, EntityTableSelector> Containers = new(); +} diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index cb6b2a747bc..4bdcdf07695 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -96,7 +96,7 @@ private void Oninitialize(EntityUid uid, ItemSlotsComponent itemSlots, Component /// </summary> public void AddItemSlot(EntityUid uid, string id, ItemSlot slot, ItemSlotsComponent? itemSlots = null) { - itemSlots ??= EntityManager.EnsureComponent<ItemSlotsComponent>(uid); + itemSlots ??= EnsureComp<ItemSlotsComponent>(uid); DebugTools.AssertOwner(uid, itemSlots); if (itemSlots.Slots.TryGetValue(id, out var existing)) @@ -110,7 +110,7 @@ public void AddItemSlot(EntityUid uid, string id, ItemSlot slot, ItemSlotsCompon slot.ContainerSlot = _containers.EnsureContainer<ContainerSlot>(uid, id); itemSlots.Slots[id] = slot; - Dirty(itemSlots); + Dirty(uid, itemSlots); } /// <summary> @@ -134,7 +134,7 @@ public void RemoveItemSlot(EntityUid uid, ItemSlot slot, ItemSlotsComponent? ite if (itemSlots.Slots.Count == 0) EntityManager.RemoveComponent(uid, itemSlots); else - Dirty(itemSlots); + Dirty(uid, itemSlots); } public bool TryGetSlot(EntityUid uid, string slotId, [NotNullWhen(true)] out ItemSlot? itemSlot, ItemSlotsComponent? component = null) diff --git a/Content.Shared/Cuffs/Components/CuffableComponent.cs b/Content.Shared/Cuffs/Components/CuffableComponent.cs index 5da6fa41a5f..4ddfe1b53ee 100644 --- a/Content.Shared/Cuffs/Components/CuffableComponent.cs +++ b/Content.Shared/Cuffs/Components/CuffableComponent.cs @@ -1,6 +1,8 @@ +using Content.Shared.Alert; using Content.Shared.Damage; using Robust.Shared.Containers; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -39,6 +41,9 @@ public sealed partial class CuffableComponent : Component /// </summary> [DataField("canStillInteract"), ViewVariables(VVAccess.ReadWrite)] public bool CanStillInteract = true; + + [DataField] + public ProtoId<AlertPrototype> CuffedAlert = "Handcuffed"; } [Serializable, NetSerializable] diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs index 9777b239884..d70a1e63083 100644 --- a/Content.Shared/Cuffs/SharedCuffableSystem.cs +++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs @@ -75,6 +75,7 @@ public override void Initialize() SubscribeLocalEvent<CuffableComponent, IsUnequippingAttemptEvent>(OnUnequipAttempt); SubscribeLocalEvent<CuffableComponent, BeingPulledAttemptEvent>(OnBeingPulledAttempt); SubscribeLocalEvent<CuffableComponent, BuckleAttemptEvent>(OnBuckleAttemptEvent); + SubscribeLocalEvent<CuffableComponent, UnbuckleAttemptEvent>(OnUnbuckleAttemptEvent); SubscribeLocalEvent<CuffableComponent, GetVerbsEvent<Verb>>(AddUncuffVerb); SubscribeLocalEvent<CuffableComponent, UnCuffDoAfterEvent>(OnCuffableDoAfter); SubscribeLocalEvent<CuffableComponent, PullStartedMessage>(OnPull); @@ -177,12 +178,13 @@ public void UpdateCuffState(EntityUid uid, CuffableComponent component) if (component.CanStillInteract) { - _alerts.ClearAlert(uid, AlertType.Handcuffed); + _alerts.ClearAlert(uid, component.CuffedAlert); RaiseLocalEvent(uid, new MoodRemoveEffectEvent("Handcuffed")); } + else { - _alerts.ShowAlert(uid, AlertType.Handcuffed); + _alerts.ShowAlert(uid, component.CuffedAlert); RaiseLocalEvent(uid, new MoodEffectEvent("Handcuffed")); } @@ -199,21 +201,33 @@ private void OnBeingPulledAttempt(EntityUid uid, CuffableComponent component, Be args.Cancel(); } - private void OnBuckleAttemptEvent(EntityUid uid, CuffableComponent component, ref BuckleAttemptEvent args) + private void OnBuckleAttempt(Entity<CuffableComponent> ent, EntityUid? user, ref bool cancelled, bool buckling, bool popup) { - // if someone else is doing it, let it pass. - if (args.UserEntity != uid) + if (cancelled || user != ent.Owner) + return; + + if (!TryComp<HandsComponent>(ent, out var hands) || ent.Comp.CuffedHandCount != hands.Count) return; - if (!TryComp<HandsComponent>(uid, out var hands) || component.CuffedHandCount != hands.Count) + cancelled = true; + if (!popup) return; - args.Cancelled = true; - var message = args.Buckling + var message = buckling ? Loc.GetString("handcuff-component-cuff-interrupt-buckled-message") : Loc.GetString("handcuff-component-cuff-interrupt-unbuckled-message"); - _popup.PopupClient(message, uid, args.UserEntity); + _popup.PopupClient(message, ent, user); + } + + private void OnBuckleAttemptEvent(Entity<CuffableComponent> ent, ref BuckleAttemptEvent args) + { + OnBuckleAttempt(ent, args.User, ref args.Cancelled, true, args.Popup); + } + + private void OnUnbuckleAttemptEvent(Entity<CuffableComponent> ent, ref UnbuckleAttemptEvent args) + { + OnBuckleAttempt(ent, args.User, ref args.Cancelled, false, args.Popup); } private void OnPull(EntityUid uid, CuffableComponent component, PullMessage args) @@ -739,4 +753,4 @@ private sealed partial class AddCuffDoAfterEvent : SimpleDoAfterEvent { } } -} \ No newline at end of file +} diff --git a/Content.Shared/Damage/Components/StaminaComponent.cs b/Content.Shared/Damage/Components/StaminaComponent.cs index b78fe978090..46eaa9f1f05 100644 --- a/Content.Shared/Damage/Components/StaminaComponent.cs +++ b/Content.Shared/Damage/Components/StaminaComponent.cs @@ -1,4 +1,6 @@ +using Content.Shared.Alert; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Damage.Components; @@ -70,4 +72,7 @@ public sealed partial class StaminaComponent : Component /// </summary> [DataField, AutoNetworkedField] public float SlowdownMultiplier = 0.75f; -} \ No newline at end of file + + [DataField] + public ProtoId<AlertPrototype> StaminaAlert = "Stamina"; +} diff --git a/Content.Shared/Damage/Systems/StaminaSystem.cs b/Content.Shared/Damage/Systems/StaminaSystem.cs index e4840a6630b..40d1c77314f 100644 --- a/Content.Shared/Damage/Systems/StaminaSystem.cs +++ b/Content.Shared/Damage/Systems/StaminaSystem.cs @@ -84,8 +84,7 @@ private void OnShutdown(EntityUid uid, StaminaComponent component, ComponentShut { RemCompDeferred<ActiveStaminaComponent>(uid); } - - SetStaminaAlert(uid); + _alerts.ClearAlert(uid, component.StaminaAlert); } private void OnStartup(EntityUid uid, StaminaComponent component, ComponentStartup args) @@ -230,13 +229,10 @@ private void OnCollide(EntityUid uid, StaminaDamageOnCollideComponent component, private void SetStaminaAlert(EntityUid uid, StaminaComponent? component = null) { if (!Resolve(uid, ref component, false) || component.Deleted) - { - _alerts.ClearAlert(uid, AlertType.Stamina); return; - } var severity = ContentHelpers.RoundToLevels(MathF.Max(0f, component.CritThreshold - component.StaminaDamage), component.CritThreshold, 7); - _alerts.ShowAlert(uid, AlertType.Stamina, (short) severity); + _alerts.ShowAlert(uid, component.StaminaAlert, (short) severity); } /// <summary> @@ -304,7 +300,7 @@ public void TakeStaminaDamage(EntityUid uid, float value, StaminaComponent? comp } EnsureComp<ActiveStaminaComponent>(uid); - Dirty(component); + Dirty(uid, component); if (value <= 0) return; @@ -410,7 +406,7 @@ private void EnterStamCrit(EntityUid uid, StaminaComponent? component = null) // Give them buffer before being able to be re-stunned component.NextUpdate = _timing.CurTime + component.StunTime + StamCritBufferTime; EnsureComp<ActiveStaminaComponent>(uid); - Dirty(component); + Dirty(uid, component); _adminLogger.Add(LogType.Stamina, LogImpact.Medium, $"{ToPrettyString(uid):user} entered stamina crit"); } @@ -424,7 +420,8 @@ private void ExitStamCrit(EntityUid uid, StaminaComponent? component = null) component.NextUpdate = _timing.CurTime; _movementSpeed.RefreshMovementSpeedModifiers(uid); SetStaminaAlert(uid, component); - Dirty(component); + RemComp<ActiveStaminaComponent>(uid); + Dirty(uid, component); _adminLogger.Add(LogType.Stamina, LogImpact.Low, $"{ToPrettyString(uid):user} recovered from stamina crit"); } } @@ -433,4 +430,4 @@ private void ExitStamCrit(EntityUid uid, StaminaComponent? component = null) /// Raised before stamina damage is dealt to allow other systems to cancel it. /// </summary> [ByRefEvent] -public record struct BeforeStaminaDamageEvent(float Value, bool Cancelled = false); \ No newline at end of file +public record struct BeforeStaminaDamageEvent(float Value, bool Cancelled = false); diff --git a/Content.Shared/Decals/SharedDecalSystem.cs b/Content.Shared/Decals/SharedDecalSystem.cs index 9dbef60f0da..0a2349ea299 100644 --- a/Content.Shared/Decals/SharedDecalSystem.cs +++ b/Content.Shared/Decals/SharedDecalSystem.cs @@ -69,7 +69,7 @@ private void OnCompStartup(EntityUid uid, DecalGridComponent component, Componen // This **shouldn't** be required, but just in case we ever get entity prototypes that have decal grids, we // need to ensure that we send an initial full state to players. - Dirty(component); + Dirty(uid, component); } protected Dictionary<Vector2i, DecalChunk>? ChunkCollection(EntityUid gridEuid, DecalGridComponent? comp = null) diff --git a/Content.Shared/Destructible/Thresholds/MinMax.cs b/Content.Shared/Destructible/Thresholds/MinMax.cs new file mode 100644 index 00000000000..e086a0f61c3 --- /dev/null +++ b/Content.Shared/Destructible/Thresholds/MinMax.cs @@ -0,0 +1,24 @@ +using Robust.Shared.Random; + +namespace Content.Shared.Destructible.Thresholds; + +[DataDefinition, Serializable] +public partial struct MinMax +{ + [DataField] + public int Min; + + [DataField] + public int Max; + + public MinMax(int min, int max) + { + Min = min; + Max = max; + } + + public int Next(IRobustRandom random) + { + return random.Next(Min, Max + 1); + } +} diff --git a/Content.Shared/Dice/SharedDiceSystem.cs b/Content.Shared/Dice/SharedDiceSystem.cs index defb3d5f0e3..8e2868e791d 100644 --- a/Content.Shared/Dice/SharedDiceSystem.cs +++ b/Content.Shared/Dice/SharedDiceSystem.cs @@ -59,7 +59,7 @@ public void SetCurrentSide(EntityUid uid, int side, DiceComponent? die = null) } die.CurrentValue = (side - die.Offset) * die.Multiplier; - Dirty(die); + Dirty(uid, die); UpdateVisuals(uid, die); } diff --git a/Content.Shared/Electrocution/SharedElectrocutionSystem.cs b/Content.Shared/Electrocution/SharedElectrocutionSystem.cs index 5031d8a9115..b228a987af4 100644 --- a/Content.Shared/Electrocution/SharedElectrocutionSystem.cs +++ b/Content.Shared/Electrocution/SharedElectrocutionSystem.cs @@ -20,7 +20,7 @@ public void SetInsulatedSiemensCoefficient(EntityUid uid, float siemensCoefficie return; insulated.Coefficient = siemensCoefficient; - Dirty(insulated); + Dirty(uid, insulated); } /// <param name="uid">Entity being electrocuted.</param> diff --git a/Content.Shared/Emoting/EmoteSystem.cs b/Content.Shared/Emoting/EmoteSystem.cs index fd6361245b1..1e06d7e982b 100644 --- a/Content.Shared/Emoting/EmoteSystem.cs +++ b/Content.Shared/Emoting/EmoteSystem.cs @@ -19,7 +19,7 @@ public void SetEmoting(EntityUid uid, bool value, EmotingComponent? component = if (component.Enabled == value) return; - Dirty(component); + Dirty(uid, component); } private void OnEmoteAttempt(EmoteAttemptEvent args) diff --git a/Content.Shared/Ensnaring/Components/EnsnareableComponent.cs b/Content.Shared/Ensnaring/Components/EnsnareableComponent.cs index 553f6df1c77..2536fac4edc 100644 --- a/Content.Shared/Ensnaring/Components/EnsnareableComponent.cs +++ b/Content.Shared/Ensnaring/Components/EnsnareableComponent.cs @@ -1,5 +1,7 @@ +using Content.Shared.Alert; using Robust.Shared.Containers; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Ensnaring.Components; @@ -40,6 +42,9 @@ public sealed partial class EnsnareableComponent : Component [DataField("state")] public string? State; + + [DataField] + public ProtoId<AlertPrototype> EnsnaredAlert = "Ensnared"; } [Serializable, NetSerializable] diff --git a/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs b/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs new file mode 100644 index 00000000000..8fb8b5e546e --- /dev/null +++ b/Content.Shared/EntityTable/EntitySelectors/AllSelector.cs @@ -0,0 +1,25 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.EntityTable.EntitySelectors; + +/// <summary> +/// Gets spawns from all of the child selectors +/// </summary> +public sealed partial class AllSelector : EntityTableSelector +{ + [DataField(required: true)] + public List<EntityTableSelector> Children; + + protected override IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand, + IEntityManager entMan, + IPrototypeManager proto) + { + foreach (var child in Children) + { + foreach (var spawn in child.GetSpawns(rand, entMan, proto)) + { + yield return spawn; + } + } + } +} diff --git a/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs b/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs new file mode 100644 index 00000000000..b1e712b4b3a --- /dev/null +++ b/Content.Shared/EntityTable/EntitySelectors/EntSelector.cs @@ -0,0 +1,27 @@ +using Content.Shared.EntityTable.ValueSelector; +using Robust.Shared.Prototypes; + +namespace Content.Shared.EntityTable.EntitySelectors; + +/// <summary> +/// Gets the spawn for the entity prototype specified at whatever count specified. +/// </summary> +public sealed partial class EntSelector : EntityTableSelector +{ + [DataField(required: true)] + public EntProtoId Id; + + [DataField] + public NumberSelector Amount = new ConstantNumberSelector(1); + + protected override IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand, + IEntityManager entMan, + IPrototypeManager proto) + { + var num = (int) Math.Round(Amount.Get(rand, entMan, proto)); + for (var i = 0; i < num; i++) + { + yield return Id; + } + } +} diff --git a/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs b/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs new file mode 100644 index 00000000000..2533f17dc51 --- /dev/null +++ b/Content.Shared/EntityTable/EntitySelectors/EntityTableSelector.cs @@ -0,0 +1,49 @@ +using Content.Shared.EntityTable.ValueSelector; +using JetBrains.Annotations; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Shared.EntityTable.EntitySelectors; + +[ImplicitDataDefinitionForInheritors, UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)] +public abstract partial class EntityTableSelector +{ + /// <summary> + /// The number of times this selector is run + /// </summary> + [DataField] + public NumberSelector Rolls = new ConstantNumberSelector(1); + + /// <summary> + /// A weight used to pick between selectors. + /// </summary> + [DataField] + public float Weight = 1; + + /// <summary> + /// A simple chance that the selector will run. + /// </summary> + [DataField] + public double Prob = 1; + + public IEnumerable<EntProtoId> GetSpawns(System.Random rand, + IEntityManager entMan, + IPrototypeManager proto) + { + var rolls = Rolls.Get(rand, entMan, proto); + for (var i = 0; i < rolls; i++) + { + if (!rand.Prob(Prob)) + continue; + + foreach (var spawn in GetSpawnsImplementation(rand, entMan, proto)) + { + yield return spawn; + } + } + } + + protected abstract IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand, + IEntityManager entMan, + IPrototypeManager proto); +} diff --git a/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs b/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs new file mode 100644 index 00000000000..8f761f9866e --- /dev/null +++ b/Content.Shared/EntityTable/EntitySelectors/GroupSelector.cs @@ -0,0 +1,28 @@ +using Content.Shared.Random.Helpers; +using Robust.Shared.Prototypes; + +namespace Content.Shared.EntityTable.EntitySelectors; + +/// <summary> +/// Gets the spawns from one of the child selectors, based on the weight of the children +/// </summary> +public sealed partial class GroupSelector : EntityTableSelector +{ + [DataField(required: true)] + public List<EntityTableSelector> Children = new(); + + protected override IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand, + IEntityManager entMan, + IPrototypeManager proto) + { + var children = new Dictionary<EntityTableSelector, float>(Children.Count); + foreach (var child in Children) + { + children.Add(child, child.Weight); + } + + var pick = SharedRandomExtensions.Pick(children, rand); + + return pick.GetSpawns(rand, entMan, proto); + } +} diff --git a/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs b/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs new file mode 100644 index 00000000000..fc8d8f08d37 --- /dev/null +++ b/Content.Shared/EntityTable/EntitySelectors/NestedSelector.cs @@ -0,0 +1,20 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.EntityTable.EntitySelectors; + +/// <summary> +/// Gets the spawns from the entity table prototype specified. +/// Can be used to reuse common tables. +/// </summary> +public sealed partial class NestedSelector : EntityTableSelector +{ + [DataField(required: true)] + public ProtoId<EntityTablePrototype> TableId; + + protected override IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand, + IEntityManager entMan, + IPrototypeManager proto) + { + return proto.Index(TableId).Table.GetSpawns(rand, entMan, proto); + } +} diff --git a/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs b/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs new file mode 100644 index 00000000000..21fcb6d2792 --- /dev/null +++ b/Content.Shared/EntityTable/EntitySelectors/NoneSelector.cs @@ -0,0 +1,16 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.EntityTable.EntitySelectors; + +/// <summary> +/// Selects nothing. +/// </summary> +public sealed partial class NoneSelector : EntityTableSelector +{ + protected override IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand, + IEntityManager entMan, + IPrototypeManager proto) + { + yield break; + } +} diff --git a/Content.Shared/EntityTable/EntityTablePrototype.cs b/Content.Shared/EntityTable/EntityTablePrototype.cs new file mode 100644 index 00000000000..63cebe9aeb7 --- /dev/null +++ b/Content.Shared/EntityTable/EntityTablePrototype.cs @@ -0,0 +1,18 @@ +using Content.Shared.EntityTable.EntitySelectors; +using Robust.Shared.Prototypes; + +namespace Content.Shared.EntityTable; + +/// <summary> +/// This is a prototype for... +/// </summary> +[Prototype] +public sealed partial class EntityTablePrototype : IPrototype +{ + /// <inheritdoc/> + [IdDataField] + public string ID { get; } = default!; + + [DataField(required: true)] + public EntityTableSelector Table = default!; +} diff --git a/Content.Shared/EntityTable/EntityTableSystem.cs b/Content.Shared/EntityTable/EntityTableSystem.cs new file mode 100644 index 00000000000..ff499e67604 --- /dev/null +++ b/Content.Shared/EntityTable/EntityTableSystem.cs @@ -0,0 +1,20 @@ +using Content.Shared.EntityTable.EntitySelectors; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Shared.EntityTable; + +public sealed class EntityTableSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + + public IEnumerable<EntProtoId> GetSpawns(EntityTableSelector? table, System.Random? rand = null) + { + if (table == null) + return new List<EntProtoId>(); + + rand ??= _random.GetRandom(); + return table.GetSpawns(rand, EntityManager, _prototypeManager); + } +} diff --git a/Content.Shared/EntityTable/ValueSelector/ConstantNumberSelector.cs b/Content.Shared/EntityTable/ValueSelector/ConstantNumberSelector.cs new file mode 100644 index 00000000000..0baf6785f4f --- /dev/null +++ b/Content.Shared/EntityTable/ValueSelector/ConstantNumberSelector.cs @@ -0,0 +1,22 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.EntityTable.ValueSelector; + +/// <summary> +/// Gives a constant value. +/// </summary> +public sealed partial class ConstantNumberSelector : NumberSelector +{ + [DataField] + public float Value = 1; + + public ConstantNumberSelector(float value) + { + Value = value; + } + + public override float Get(System.Random rand, IEntityManager entMan, IPrototypeManager proto) + { + return Value; + } +} diff --git a/Content.Shared/EntityTable/ValueSelector/NumberSelector.cs b/Content.Shared/EntityTable/ValueSelector/NumberSelector.cs new file mode 100644 index 00000000000..8a7743c9dd8 --- /dev/null +++ b/Content.Shared/EntityTable/ValueSelector/NumberSelector.cs @@ -0,0 +1,16 @@ +using Content.Shared.EntityTable.EntitySelectors; +using JetBrains.Annotations; +using Robust.Shared.Prototypes; + +namespace Content.Shared.EntityTable.ValueSelector; + +/// <summary> +/// Used for implementing custom value selection for <see cref="EntityTableSelector"/> +/// </summary> +[ImplicitDataDefinitionForInheritors, UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)] +public abstract partial class NumberSelector +{ + public abstract float Get(System.Random rand, + IEntityManager entMan, + IPrototypeManager proto); +} diff --git a/Content.Shared/EntityTable/ValueSelector/RangeNumberSelector.cs b/Content.Shared/EntityTable/ValueSelector/RangeNumberSelector.cs new file mode 100644 index 00000000000..e8356fcbb72 --- /dev/null +++ b/Content.Shared/EntityTable/ValueSelector/RangeNumberSelector.cs @@ -0,0 +1,19 @@ +using System.Numerics; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Shared.EntityTable.ValueSelector; + +/// <summary> +/// Gives a value between the two numbers specified, inclusive. +/// </summary> +public sealed partial class RangeNumberSelector : NumberSelector +{ + [DataField] + public Vector2 Range = new(1, 1); + + public override float Get(System.Random rand, IEntityManager entMan, IPrototypeManager proto) + { + return rand.NextFloat(Range.X, Range.Y + 1); + } +} diff --git a/Content.Shared/Examine/ExamineSystemShared.cs b/Content.Shared/Examine/ExamineSystemShared.cs index f792862be14..397a8f74484 100644 --- a/Content.Shared/Examine/ExamineSystemShared.cs +++ b/Content.Shared/Examine/ExamineSystemShared.cs @@ -175,9 +175,9 @@ public bool InRangeUnOccluded<TState>(MapCoordinates origin, MapCoordinates othe length = MaxRaycastRange; } - var occluderSystem = Get<OccluderSystem>(); IoCManager.Resolve(ref entMan); + var occluderSystem = EntityManager.System<OccluderSystem>(); var ray = new Ray(origin.Position, dir.Normalized()); var rayResults = occluderSystem .IntersectRayWithPredicate(origin.MapId, ray, length, state, predicate, false).ToList(); @@ -194,7 +194,7 @@ public bool InRangeUnOccluded<TState>(MapCoordinates origin, MapCoordinates othe } var bBox = o.BoundingBox; - bBox = bBox.Translated(entMan.GetComponent<TransformComponent>(result.HitEntity).WorldPosition); + bBox = bBox.Translated(_transform.GetWorldPosition(result.HitEntity)); if (bBox.Contains(origin.Position) || bBox.Contains(other.Position)) { @@ -210,8 +210,8 @@ public bool InRangeUnOccluded<TState>(MapCoordinates origin, MapCoordinates othe public bool InRangeUnOccluded(EntityUid origin, EntityUid other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true) { var entMan = IoCManager.Resolve<IEntityManager>(); - var originPos = entMan.GetComponent<TransformComponent>(origin).MapPosition; - var otherPos = entMan.GetComponent<TransformComponent>(other).MapPosition; + var originPos = _transform.GetMapCoordinates(origin); + var otherPos = _transform.GetMapCoordinates(other); return InRangeUnOccluded(originPos, otherPos, range, predicate, ignoreInsideBlocker); } @@ -219,8 +219,8 @@ public bool InRangeUnOccluded(EntityUid origin, EntityUid other, float range = E public bool InRangeUnOccluded(EntityUid origin, EntityCoordinates other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true) { var entMan = IoCManager.Resolve<IEntityManager>(); - var originPos = entMan.GetComponent<TransformComponent>(origin).MapPosition; - var otherPos = other.ToMap(entMan); + var originPos = _transform.GetMapCoordinates(origin); + var otherPos = _transform.ToMapCoordinates(other); return InRangeUnOccluded(originPos, otherPos, range, predicate, ignoreInsideBlocker); } @@ -228,7 +228,7 @@ public bool InRangeUnOccluded(EntityUid origin, EntityCoordinates other, float r public bool InRangeUnOccluded(EntityUid origin, MapCoordinates other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true) { var entMan = IoCManager.Resolve<IEntityManager>(); - var originPos = entMan.GetComponent<TransformComponent>(origin).MapPosition; + var originPos = _transform.GetMapCoordinates(origin); return InRangeUnOccluded(originPos, other, range, predicate, ignoreInsideBlocker); } @@ -370,7 +370,7 @@ int Comparison(ExamineMessagePart a, ExamineMessagePart b) /// sort messages the same as well as grouped together properly, even if subscriptions are different. /// You should wrap it in a using() block so popping automatically occurs. /// </summary> - public ExamineGroupDisposable PushGroup(string groupName, int priority=0) + public ExamineGroupDisposable PushGroup(string groupName, int priority = 0) { // Ensure that other examine events correctly ended their groups. DebugTools.Assert(_currentGroupPart == null); @@ -398,7 +398,7 @@ private void PopGroup() /// </summary> /// <seealso cref="PushMarkup"/> /// <seealso cref="PushText"/> - public void PushMessage(FormattedMessage message, int priority=0) + public void PushMessage(FormattedMessage message, int priority = 0) { if (message.Nodes.Count == 0) return; @@ -421,9 +421,9 @@ public void PushMessage(FormattedMessage message, int priority=0) /// </summary> /// <seealso cref="PushText"/> /// <seealso cref="PushMessage"/> - public void PushMarkup(string markup, int priority=0) + public void PushMarkup(string markup, int priority = 0) { - PushMessage(FormattedMessage.FromMarkup(markup), priority); + PushMessage(FormattedMessage.FromMarkupPermissive(markup), priority); } /// <summary> @@ -433,7 +433,7 @@ public void PushMarkup(string markup, int priority=0) /// </summary> /// <seealso cref="PushMarkup"/> /// <seealso cref="PushMessage"/> - public void PushText(string text, int priority=0) + public void PushText(string text, int priority = 0) { var msg = new FormattedMessage(); msg.AddText(text); @@ -469,9 +469,9 @@ public void AddMessage(FormattedMessage message, int priority = 0) /// </summary> /// <seealso cref="AddText"/> /// <seealso cref="AddMessage"/> - public void AddMarkup(string markup, int priority=0) + public void AddMarkup(string markup, int priority = 0) { - AddMessage(FormattedMessage.FromMarkup(markup), priority); + AddMessage(FormattedMessage.FromMarkupPermissive(markup), priority); } /// <summary> @@ -481,7 +481,7 @@ public void AddMarkup(string markup, int priority=0) /// </summary> /// <seealso cref="AddMarkup"/> /// <seealso cref="AddMessage"/> - public void AddText(string text, int priority=0) + public void AddText(string text, int priority = 0) { var msg = new FormattedMessage(); msg.AddText(text); diff --git a/Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs b/Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs index 80d65f4c2cd..1138e74af8f 100644 --- a/Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs +++ b/Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs @@ -29,7 +29,7 @@ public sealed partial class SmokeOnTriggerComponent : Component /// Defaults to smoke but you can use foam if you want. /// </summary> [DataField, ViewVariables(VVAccess.ReadWrite)] - public ProtoId<EntityPrototype> SmokePrototype = "Smoke"; + public EntProtoId SmokePrototype = "Smoke"; /// <summary> /// Solution to add to each smoke cloud. diff --git a/Content.Shared/Foldable/FoldableSystem.cs b/Content.Shared/Foldable/FoldableSystem.cs index 10baf8165b5..2a846f4f234 100644 --- a/Content.Shared/Foldable/FoldableSystem.cs +++ b/Content.Shared/Foldable/FoldableSystem.cs @@ -26,7 +26,7 @@ public override void Initialize() SubscribeLocalEvent<FoldableComponent, StoreMobInItemContainerAttemptEvent>(OnStoreThisAttempt); SubscribeLocalEvent<FoldableComponent, StorageOpenAttemptEvent>(OnFoldableOpenAttempt); - SubscribeLocalEvent<FoldableComponent, BuckleAttemptEvent>(OnBuckleAttempt); + SubscribeLocalEvent<FoldableComponent, StrapAttemptEvent>(OnStrapAttempt); } private void OnHandleState(EntityUid uid, FoldableComponent component, ref AfterAutoHandleStateEvent args) @@ -53,9 +53,9 @@ public void OnStoreThisAttempt(EntityUid uid, FoldableComponent comp, ref StoreM args.Cancelled = true; } - public void OnBuckleAttempt(EntityUid uid, FoldableComponent comp, ref BuckleAttemptEvent args) + public void OnStrapAttempt(EntityUid uid, FoldableComponent comp, ref StrapAttemptEvent args) { - if (args.Buckling && comp.IsFolded) + if (comp.IsFolded) args.Cancelled = true; } diff --git a/Content.Shared/Friction/TileFrictionController.cs b/Content.Shared/Friction/TileFrictionController.cs index 3583947ee36..930de07dab9 100644 --- a/Content.Shared/Friction/TileFrictionController.cs +++ b/Content.Shared/Friction/TileFrictionController.cs @@ -214,7 +214,7 @@ public void SetModifier(EntityUid entityUid, float value, TileFrictionModifierCo return; friction.Modifier = value; - Dirty(friction); + Dirty(entityUid, friction); } } } diff --git a/Content.Server/GameTicking/Components/ActiveGameRuleComponent.cs b/Content.Shared/GameTicking/Components/ActiveGameRuleComponent.cs similarity index 67% rename from Content.Server/GameTicking/Components/ActiveGameRuleComponent.cs rename to Content.Shared/GameTicking/Components/ActiveGameRuleComponent.cs index b9e6fa5d4b8..51bdd1c0371 100644 --- a/Content.Server/GameTicking/Components/ActiveGameRuleComponent.cs +++ b/Content.Shared/GameTicking/Components/ActiveGameRuleComponent.cs @@ -1,10 +1,8 @@ -namespace Content.Server.GameTicking.Components; +namespace Content.Shared.GameTicking.Components; /// <summary> /// Added to game rules before <see cref="GameRuleStartedEvent"/> and removed before <see cref="GameRuleEndedEvent"/>. /// Mutually exclusive with <seealso cref="EndedGameRuleComponent"/>. /// </summary> [RegisterComponent] -public sealed partial class ActiveGameRuleComponent : Component -{ -} +public sealed partial class ActiveGameRuleComponent : Component; diff --git a/Content.Server/GameTicking/Components/DelayedStartRuleComponent.cs b/Content.Shared/GameTicking/Components/DelayedStartRuleComponent.cs similarity index 91% rename from Content.Server/GameTicking/Components/DelayedStartRuleComponent.cs rename to Content.Shared/GameTicking/Components/DelayedStartRuleComponent.cs index de4be83627d..9275da29b01 100644 --- a/Content.Server/GameTicking/Components/DelayedStartRuleComponent.cs +++ b/Content.Shared/GameTicking/Components/DelayedStartRuleComponent.cs @@ -1,6 +1,6 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Server.GameTicking.Components; +namespace Content.Shared.GameTicking.Components; /// <summary> /// Generic component used to track a gamerule that's start has been delayed. diff --git a/Content.Server/GameTicking/Components/EndedGameRuleComponent.cs b/Content.Shared/GameTicking/Components/EndedGameRuleComponent.cs similarity index 61% rename from Content.Server/GameTicking/Components/EndedGameRuleComponent.cs rename to Content.Shared/GameTicking/Components/EndedGameRuleComponent.cs index 3234bfff3a0..5e209ed78a2 100644 --- a/Content.Server/GameTicking/Components/EndedGameRuleComponent.cs +++ b/Content.Shared/GameTicking/Components/EndedGameRuleComponent.cs @@ -1,10 +1,8 @@ -namespace Content.Server.GameTicking.Components; +namespace Content.Shared.GameTicking.Components; /// <summary> /// Added to game rules before <see cref="GameRuleEndedEvent"/>. /// Mutually exclusive with <seealso cref="ActiveGameRuleComponent"/>. /// </summary> [RegisterComponent] -public sealed partial class EndedGameRuleComponent : Component -{ -} +public sealed partial class EndedGameRuleComponent : Component; diff --git a/Content.Server/GameTicking/Components/GameRuleComponent.cs b/Content.Shared/GameTicking/Components/GameRuleComponent.cs similarity index 92% rename from Content.Server/GameTicking/Components/GameRuleComponent.cs rename to Content.Shared/GameTicking/Components/GameRuleComponent.cs index 1e6c3f0ab1d..28ea435f1b7 100644 --- a/Content.Server/GameTicking/Components/GameRuleComponent.cs +++ b/Content.Shared/GameTicking/Components/GameRuleComponent.cs @@ -1,7 +1,8 @@ -using Content.Server.Destructible.Thresholds; +using Content.Shared.Destructible.Thresholds; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Server.GameTicking.Components; +namespace Content.Shared.GameTicking.Components; /// <summary> /// Component attached to all gamerule entities. diff --git a/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs b/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs index 8fe9e00e7eb..9d8aa4f146e 100644 --- a/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs +++ b/Content.Shared/Gravity/SharedFloatingVisualizerSystem.cs @@ -35,7 +35,7 @@ protected bool CanFloat(EntityUid uid, FloatingVisualsComponent component, Trans return false; component.CanFloat = GravitySystem.IsWeightless(uid, xform: transform); - Dirty(component); + Dirty(uid, component); return component.CanFloat; } diff --git a/Content.Shared/Gravity/SharedGravitySystem.Shake.cs b/Content.Shared/Gravity/SharedGravitySystem.Shake.cs index ad2e0e3ad57..41cf616cc4b 100644 --- a/Content.Shared/Gravity/SharedGravitySystem.Shake.cs +++ b/Content.Shared/Gravity/SharedGravitySystem.Shake.cs @@ -24,7 +24,7 @@ private void UpdateShake() ShakeGrid(uid, gravity); comp.ShakeTimes--; comp.NextShake += TimeSpan.FromSeconds(ShakeCooldown); - Dirty(comp); + Dirty(uid, comp); } } } @@ -44,7 +44,7 @@ public void StartGridShake(EntityUid uid, GravityComponent? gravity = null) } shake.ShakeTimes = 10; - Dirty(shake); + Dirty(uid, shake); } protected virtual void ShakeGrid(EntityUid uid, GravityComponent? comp = null) {} diff --git a/Content.Shared/Gravity/SharedGravitySystem.cs b/Content.Shared/Gravity/SharedGravitySystem.cs index 55187bf14ac..59d75e453af 100644 --- a/Content.Shared/Gravity/SharedGravitySystem.cs +++ b/Content.Shared/Gravity/SharedGravitySystem.cs @@ -18,6 +18,9 @@ public abstract partial class SharedGravitySystem : EntitySystem [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly InventorySystem _inventory = default!; + [ValidatePrototypeId<AlertPrototype>] + public const string WeightlessAlert = "Weightless"; + public bool IsWeightless(EntityUid uid, PhysicsComponent? body = null, TransformComponent? xform = null) { Resolve(uid, ref body, false); @@ -97,11 +100,11 @@ private void OnGravityChange(ref GravityChangedEvent ev) if (!ev.HasGravity) { - _alerts.ShowAlert(uid, AlertType.Weightless); + _alerts.ShowAlert(uid, WeightlessAlert); } else { - _alerts.ClearAlert(uid, AlertType.Weightless); + _alerts.ClearAlert(uid, WeightlessAlert); } } } @@ -110,11 +113,11 @@ private void OnAlertsSync(AlertSyncEvent ev) { if (IsWeightless(ev.Euid)) { - _alerts.ShowAlert(ev.Euid, AlertType.Weightless); + _alerts.ShowAlert(ev.Euid, WeightlessAlert); } else { - _alerts.ClearAlert(ev.Euid, AlertType.Weightless); + _alerts.ClearAlert(ev.Euid, WeightlessAlert); } } @@ -122,11 +125,11 @@ private void OnAlertsParentChange(EntityUid uid, AlertsComponent component, ref { if (IsWeightless(uid)) { - _alerts.ShowAlert(uid, AlertType.Weightless); + _alerts.ShowAlert(uid, WeightlessAlert); } else { - _alerts.ClearAlert(uid, AlertType.Weightless); + _alerts.ClearAlert(uid, WeightlessAlert); } } diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs index 7b169b5d0a6..4d7a0f377f5 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs @@ -128,7 +128,7 @@ public bool TryDrop(EntityUid uid, Hand hand, EntityCoordinates? targetDropLocat // TODO recursively check upwards for containers if (!isInContainer - || !ContainerSystem.TryGetContainingContainer(userXform.ParentUid, uid, out var container, skipExistCheck: true) + || !ContainerSystem.TryGetContainingContainer(userXform.ParentUid, uid, out var container) || !ContainerSystem.Insert((entity, itemXform), container)) TransformSystem.AttachToGridOrMap(entity, itemXform); return true; @@ -136,7 +136,7 @@ public bool TryDrop(EntityUid uid, Hand hand, EntityCoordinates? targetDropLocat var (itemPos, itemRot) = TransformSystem.GetWorldPositionRotation(entity); var origin = new MapCoordinates(itemPos, itemXform.MapID); - var target = targetDropLocation.Value.ToMap(EntityManager, TransformSystem); + var target = TransformSystem.ToMapCoordinates(targetDropLocation.Value); TransformSystem.SetWorldPositionRotation(entity, GetFinalDropCoordinates(uid, origin, target), itemRot); return true; } diff --git a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs index f33c65b5915..bf3addea99e 100644 --- a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs +++ b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs @@ -157,7 +157,7 @@ public void SetLayersVisibility(EntityUid uid, IEnumerable<HumanoidVisualLayers> SetLayerVisibility(uid, humanoid, layer, visible, permanent, ref dirty); if (dirty) - Dirty(humanoid); + Dirty(uid, humanoid); } protected virtual void SetLayerVisibility( @@ -203,7 +203,7 @@ public void SetSpecies(EntityUid uid, string species, bool sync = true, Humanoid humanoid.MarkingSet = new(oldMarkings, prototype.MarkingPoints, _markingManager, _proto); if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -229,7 +229,7 @@ public virtual void SetSkinColor(EntityUid uid, Color skinColor, bool sync = tru humanoid.SkinColor = skinColor; if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -253,7 +253,7 @@ public void SetBaseLayerId(EntityUid uid, HumanoidVisualLayers layer, string? id humanoid.CustomBaseLayers[layer] = new(id); if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -274,7 +274,7 @@ public void SetBaseLayerColor(EntityUid uid, HumanoidVisualLayers layer, Color? humanoid.CustomBaseLayers[layer] = new(null, color); if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -295,7 +295,7 @@ public void SetSex(EntityUid uid, Sex sex, bool sync = true, HumanoidAppearanceC RaiseLocalEvent(uid, new SexChangedEvent(oldSex, sex)); if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -314,7 +314,7 @@ public void SetHeight(EntityUid uid, float height, bool sync = true, HumanoidApp humanoid.Height = Math.Clamp(height, species.MinHeight, species.MaxHeight); if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -333,7 +333,7 @@ public void SetWidth(EntityUid uid, float width, bool sync = true, HumanoidAppea humanoid.Width = Math.Clamp(width, species.MinWidth, species.MaxWidth); if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -353,7 +353,7 @@ public void SetScale(EntityUid uid, Vector2 scale, bool sync = true, HumanoidApp humanoid.Width = Math.Clamp(scale.X, species.MinWidth, species.MaxWidth); if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> @@ -440,7 +440,7 @@ public virtual void LoadProfile(EntityUid uid, HumanoidCharacterProfile profile, humanoid.LastProfileLoaded = profile; // DeltaV - let paradox anomaly be cloned - Dirty(humanoid); + Dirty(uid, humanoid); RaiseLocalEvent(uid, new ProfileLoadFinishedEvent()); } @@ -472,7 +472,7 @@ public void AddMarking(EntityUid uid, string marking, Color? color = null, bool humanoid.MarkingSet.AddBack(prototype.MarkingCategory, markingObject); if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } private void EnsureDefaultMarkings(EntityUid uid, HumanoidAppearanceComponent? humanoid) @@ -502,7 +502,7 @@ public void AddMarking(EntityUid uid, string marking, IReadOnlyList<Color> color humanoid.MarkingSet.AddBack(prototype.MarkingCategory, markingObject); if (sync) - Dirty(humanoid); + Dirty(uid, humanoid); } /// <summary> diff --git a/Content.Shared/Implants/SharedImplanterSystem.cs b/Content.Shared/Implants/SharedImplanterSystem.cs index 36a31bac1d2..d78522b56cc 100644 --- a/Content.Shared/Implants/SharedImplanterSystem.cs +++ b/Content.Shared/Implants/SharedImplanterSystem.cs @@ -77,7 +77,7 @@ public void Implant(EntityUid user, EntityUid target, EntityUid implanter, Impla var ev = new TransferDnaEvent { Donor = target, Recipient = implanter }; RaiseLocalEvent(target, ref ev); - Dirty(component); + Dirty(implanter, component); } public bool CanImplant( @@ -156,7 +156,7 @@ public void Draw(EntityUid implanter, EntityUid user, EntityUid target, Implante if (component.CurrentMode == ImplanterToggleMode.Draw && !component.ImplantOnly && !permanentFound) ImplantMode(implanter, component); - Dirty(component); + Dirty(implanter, component); } } diff --git a/Content.Shared/Info/RulesMessages.cs b/Content.Shared/Info/RulesMessages.cs new file mode 100644 index 00000000000..9cb73c9aa86 --- /dev/null +++ b/Content.Shared/Info/RulesMessages.cs @@ -0,0 +1,25 @@ +using Lidgren.Network; +using Robust.Shared.Network; +using Robust.Shared.Serialization; + +namespace Content.Shared.Info; + +/// <summary> +/// Sent by the server to show the rules to the client instantly. +/// </summary> +public sealed class ShowRulesPopupMessage : NetMessage +{ + public override MsgGroups MsgGroup => MsgGroups.Command; + + public float PopupTime { get; set; } + + public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) + { + PopupTime = buffer.ReadFloat(); + } + + public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) + { + buffer.Write(PopupTime); + } +} diff --git a/Content.Shared/Info/SharedInfo.cs b/Content.Shared/Info/SharedInfo.cs deleted file mode 100644 index 4a0e688cf9a..00000000000 --- a/Content.Shared/Info/SharedInfo.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared.Info -{ - /// <summary> - /// A client request for server rules. - /// </summary> - [Serializable, NetSerializable] - public sealed class RequestRulesMessage : EntityEventArgs - { - } - - /// <summary> - /// A server response with server rules. - /// </summary> - [Serializable, NetSerializable] - public sealed class RulesMessage : EntityEventArgs - { - public string Title; - public string Text; - - public RulesMessage(string title, string rules) - { - Title = title; - Text = rules; - } - } -} diff --git a/Content.Shared/Info/SharedRulesManager.cs b/Content.Shared/Info/SharedRulesManager.cs deleted file mode 100644 index 932150d58ef..00000000000 --- a/Content.Shared/Info/SharedRulesManager.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Lidgren.Network; -using Robust.Shared.Network; -using Robust.Shared.Serialization; - -namespace Content.Shared.Info; - -public abstract class SharedRulesManager -{ - /// <summary> - /// Sent by the server to show the rules to the client instantly. - /// </summary> - public sealed class ShowRulesPopupMessage : NetMessage - { - public override MsgGroups MsgGroup => MsgGroups.Command; - - public float PopupTime { get; set; } - - public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) - { - PopupTime = buffer.ReadFloat(); - } - - public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) - { - buffer.Write(PopupTime); - } - } - - /// <summary> - /// Sent by the server when the client needs to display the rules on join. - /// </summary> - public sealed class ShouldShowRulesPopupMessage : NetMessage - { - public override MsgGroups MsgGroup => MsgGroups.Command; - - public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) - { - } - - public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) - { - } - } - - /// <summary> - /// Sent by the client when it has accepted the rules. - /// </summary> - public sealed class RulesAcceptedMessage : NetMessage - { - public override MsgGroups MsgGroup => MsgGroups.Command; - - public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) - { - } - - public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) - { - } - } -} diff --git a/Content.Shared/Instruments/SharedInstrumentSystem.cs b/Content.Shared/Instruments/SharedInstrumentSystem.cs index 87e3a69489c..23bcf67de0e 100644 --- a/Content.Shared/Instruments/SharedInstrumentSystem.cs +++ b/Content.Shared/Instruments/SharedInstrumentSystem.cs @@ -12,10 +12,10 @@ public virtual void EndRenderer(EntityUid uid, bool fromStateChange, SharedInstr { } - public void SetInstrumentProgram(SharedInstrumentComponent component, byte program, byte bank) + public void SetInstrumentProgram(EntityUid uid, SharedInstrumentComponent component, byte program, byte bank) { component.InstrumentBank = bank; component.InstrumentProgram = program; - Dirty(component); + Dirty(uid, component); } } diff --git a/Content.Shared/Interaction/RotateToFaceSystem.cs b/Content.Shared/Interaction/RotateToFaceSystem.cs index ed950240af6..fa213011ef1 100644 --- a/Content.Shared/Interaction/RotateToFaceSystem.cs +++ b/Content.Shared/Interaction/RotateToFaceSystem.cs @@ -1,7 +1,6 @@ using System.Numerics; using Content.Shared.ActionBlocker; using Content.Shared.Buckle.Components; -using Content.Shared.Mobs.Systems; using Content.Shared.Rotatable; using JetBrains.Annotations; @@ -83,24 +82,21 @@ public bool TryFaceAngle(EntityUid user, Angle diffAngle, TransformComponent? xf if (!_actionBlockerSystem.CanChangeDirection(user)) return false; - if (EntityManager.TryGetComponent(user, out BuckleComponent? buckle) && buckle.Buckled) + if (TryComp(user, out BuckleComponent? buckle) && buckle.BuckledTo is {} strap) { - var suid = buckle.LastEntityBuckledTo; - if (suid != null) - { - // We're buckled to another object. Is that object rotatable? - if (TryComp<RotatableComponent>(suid.Value, out var rotatable) && rotatable.RotateWhileAnchored) - { - // Note the assumption that even if unanchored, user can only do spinnychair with an "independent wheel". - // (Since the user being buckled to it holds it down with their weight.) - // This is logically equivalent to RotateWhileAnchored. - // Barstools and office chairs have independent wheels, while regular chairs don't. - _transform.SetWorldRotation(Transform(suid.Value), diffAngle); - return true; - } - } - - return false; + // What if a person is strapped to a borg? + // I'm pretty sure this would allow them to be partially ratatouille'd + + // We're buckled to another object. Is that object rotatable? + if (!TryComp<RotatableComponent>(strap, out var rotatable) || !rotatable.RotateWhileAnchored) + return false; + + // Note the assumption that even if unanchored, user can only do spinnychair with an "independent wheel". + // (Since the user being buckled to it holds it down with their weight.) + // This is logically equivalent to RotateWhileAnchored. + // Barstools and office chairs have independent wheels, while regular chairs don't. + _transform.SetWorldRotation(Transform(strap), diffAngle); + return true; } // user is not buckled in; apply to their transform diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 4c22bcb14e4..1c4a697cc4e 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -1167,7 +1167,7 @@ public bool CanAccessViaStorage(EntityUid user, EntityUid target, BaseContainer return false; // we don't check if the user can access the storage entity itself. This should be handed by the UI system. - return _ui.IsUiOpen(target, StorageComponent.StorageUiKey.Key, user); + return _ui.IsUiOpen(container.Owner, StorageComponent.StorageUiKey.Key, user); } /// <summary> diff --git a/Content.Shared/Item/ItemToggle/SharedItemToggleSystem.cs b/Content.Shared/Item/ItemToggle/SharedItemToggleSystem.cs index 523f67bac3d..fa23339223e 100644 --- a/Content.Shared/Item/ItemToggle/SharedItemToggleSystem.cs +++ b/Content.Shared/Item/ItemToggle/SharedItemToggleSystem.cs @@ -245,9 +245,22 @@ private void UpdateActiveSound(EntityUid uid, ItemToggleActiveSoundComponent act if (activeSound.ActiveSound != null && activeSound.PlayingStream == null) { if (args.Predicted) - activeSound.PlayingStream = _audio.PlayPredicted(activeSound.ActiveSound, uid, args.User, AudioParams.Default.WithLoop(true)).Value.Entity; - else - activeSound.PlayingStream = _audio.PlayPvs(activeSound.ActiveSound, uid, AudioParams.Default.WithLoop(true)).Value.Entity; + { + var playingStream = _audio.PlayPredicted(activeSound.ActiveSound, uid, args.User, AudioParams.Default.WithLoop(true)); + + if (playingStream == null) + return; + + activeSound.PlayingStream = playingStream!.Value.Entity; + } else + { + var playingStream = _audio.PlayPvs(activeSound.ActiveSound, uid, AudioParams.Default.WithLoop(true)); + + if (playingStream == null) + return; + + activeSound.PlayingStream = playingStream!.Value.Entity; + } } } else diff --git a/Content.Shared/Light/SharedHandheldLightSystem.cs b/Content.Shared/Light/SharedHandheldLightSystem.cs index 2fa15800a31..9bec37a3140 100644 --- a/Content.Shared/Light/SharedHandheldLightSystem.cs +++ b/Content.Shared/Light/SharedHandheldLightSystem.cs @@ -29,7 +29,7 @@ private void OnInit(EntityUid uid, HandheldLightComponent component, ComponentIn UpdateVisuals(uid, component); // Want to make sure client has latest data on level so battery displays properly. - Dirty(component); + Dirty(uid, component); } private void OnHandleState(EntityUid uid, HandheldLightComponent component, ref ComponentHandleState args) diff --git a/Content.Shared/Light/SharedRgbLightControllerSystem.cs b/Content.Shared/Light/SharedRgbLightControllerSystem.cs index 1bba91c5e7b..7d4928f5bc1 100644 --- a/Content.Shared/Light/SharedRgbLightControllerSystem.cs +++ b/Content.Shared/Light/SharedRgbLightControllerSystem.cs @@ -17,13 +17,13 @@ private void OnGetState(EntityUid uid, RgbLightControllerComponent component, re args.State = new RgbLightControllerState(component.CycleRate, component.Layers); } - public void SetLayers(EntityUid uid, List<int>? layers, RgbLightControllerComponent? rgb = null) + public void SetLayers(EntityUid uid, List<int>? layers, RgbLightControllerComponent? rgb = null) { if (!Resolve(uid, ref rgb)) return; rgb.Layers = layers; - Dirty(rgb); + Dirty(uid, rgb); } public void SetCycleRate(EntityUid uid, float rate, RgbLightControllerComponent? rgb = null) @@ -32,6 +32,6 @@ public void SetCycleRate(EntityUid uid, float rate, RgbLightControllerComponent? return; rgb.CycleRate = Math.Clamp(0.01f, rate, 1); // lets not give people seizures - Dirty(rgb); + Dirty(uid, rgb); } } diff --git a/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs b/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs index 7e44dea5078..b4f1ae9a268 100644 --- a/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs +++ b/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs @@ -194,7 +194,7 @@ public void CycleEquipment(EntityUid uid, MechComponent? component = null) if (_net.IsServer) _popup.PopupEntity(popupString, uid); - Dirty(component); + Dirty(uid, component); } /// <summary> @@ -278,7 +278,7 @@ public virtual bool TryChangeEnergy(EntityUid uid, FixedPoint2 delta, MechCompon return false; component.Energy = FixedPoint2.Clamp(component.Energy + delta, 0, component.MaxEnergy); - Dirty(component); + Dirty(uid, component); UpdateUserInterface(uid, component); return true; } @@ -306,7 +306,7 @@ public void SetIntegrity(EntityUid uid, FixedPoint2 value, MechComponent? compon UpdateAppearance(uid, component); } - Dirty(component); + Dirty(uid, component); UpdateUserInterface(uid, component); } diff --git a/Content.Shared/Medical/CPR/Systems/CPRSystem.cs b/Content.Shared/Medical/CPR/Systems/CPRSystem.cs index 799c0664a66..e050f1b4e1d 100644 --- a/Content.Shared/Medical/CPR/Systems/CPRSystem.cs +++ b/Content.Shared/Medical/CPR/Systems/CPRSystem.cs @@ -84,7 +84,13 @@ private void StartCPR(EntityUid performer, EntityUid target, CPRTrainingComponen { _popupSystem.PopupEntity(Loc.GetString("cpr-start-second-person", ("target", target)), target, performer, PopupType.Medium); _popupSystem.PopupEntity(Loc.GetString("cpr-start-second-person-patient", ("user", performer)), target, target, PopupType.Medium); - cprComponent.CPRPlayingStream = _audio.PlayPvs(cprComponent.CPRSound, performer).Value.Entity; + + var playingStream = _audio.PlayPvs(cprComponent.CPRSound, performer); + + if (playingStream == null) + return; + + cprComponent.CPRPlayingStream = _audio.PlayPvs(cprComponent.CPRSound, performer)!.Value.Entity; } _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, performer, cprComponent.DoAfterDuration, new CPRDoAfterEvent(), performer, target, performer) diff --git a/Content.Shared/Mobs/Components/MobThresholdsComponent.cs b/Content.Shared/Mobs/Components/MobThresholdsComponent.cs index e97d3672a21..0e37cf9b10e 100644 --- a/Content.Shared/Mobs/Components/MobThresholdsComponent.cs +++ b/Content.Shared/Mobs/Components/MobThresholdsComponent.cs @@ -2,6 +2,7 @@ using Content.Shared.FixedPoint; using Content.Shared.Mobs.Systems; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Mobs.Components; @@ -24,13 +25,16 @@ public sealed partial class MobThresholdsComponent : Component /// Used for alternate health alerts (silicons, for example) /// </summary> [DataField("stateAlertDict")] - public Dictionary<MobState, AlertType> StateAlertDict = new() + public Dictionary<MobState, ProtoId<AlertPrototype>> StateAlertDict = new() { - {MobState.Alive, AlertType.HumanHealth}, - {MobState.Critical, AlertType.HumanCrit}, - {MobState.Dead, AlertType.HumanDead}, + {MobState.Alive, "HumanHealth"}, + {MobState.Critical, "HumanCrit"}, + {MobState.Dead, "HumanDead"}, }; + [DataField] + public ProtoId<AlertCategoryPrototype> HealthAlertCategory = "Health"; + /// <summary> /// Whether or not this entity should display damage overlays (robots don't feel pain, black out etc.) /// </summary> @@ -53,19 +57,19 @@ public sealed class MobThresholdsComponentState : ComponentState public MobState CurrentThresholdState; - public Dictionary<MobState, AlertType> StateAlertDict = new() - { - {MobState.Alive, AlertType.HumanHealth}, - {MobState.Critical, AlertType.HumanCrit}, - {MobState.Dead, AlertType.HumanDead}, - }; + public Dictionary<MobState, ProtoId<AlertPrototype>> StateAlertDict; public bool ShowOverlays; public bool AllowRevives; - public MobThresholdsComponentState(Dictionary<FixedPoint2, MobState> unsortedThresholds, bool triggersAlerts, MobState currentThresholdState, - Dictionary<MobState, AlertType> stateAlertDict, bool showOverlays, bool allowRevives) + public MobThresholdsComponentState(Dictionary<FixedPoint2, MobState> unsortedThresholds, + bool triggersAlerts, + MobState currentThresholdState, + Dictionary<MobState, + ProtoId<AlertPrototype>> stateAlertDict, + bool showOverlays, + bool allowRevives) { UnsortedThresholds = unsortedThresholds; TriggersAlerts = triggersAlerts; diff --git a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs index d9ef671afe2..2088bd4161e 100644 --- a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs +++ b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs @@ -1,4 +1,5 @@ using Content.Shared.Bed.Sleep; +using Content.Shared.Buckle.Components; using Content.Shared.CombatMode.Pacification; using Content.Shared.Damage.ForceSay; using Content.Shared.Emoting; @@ -10,15 +11,12 @@ using Content.Shared.Mobs.Components; using Content.Shared.Movement.Events; using Content.Shared.Pointing; -using Content.Shared.Projectiles; using Content.Shared.Pulling.Events; using Content.Shared.Speech; using Content.Shared.Standing; using Content.Shared.Strip.Components; using Content.Shared.Throwing; -using Content.Shared.Weapons.Ranged.Components; using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Events; namespace Content.Shared.Mobs.Systems; @@ -46,6 +44,16 @@ private void SubscribeEvents() SubscribeLocalEvent<MobStateComponent, TryingToSleepEvent>(OnSleepAttempt); SubscribeLocalEvent<MobStateComponent, CombatModeShouldHandInteractEvent>(OnCombatModeShouldHandInteract); SubscribeLocalEvent<MobStateComponent, AttemptPacifiedAttackEvent>(OnAttemptPacifiedAttack); + + SubscribeLocalEvent<MobStateComponent, UnbuckleAttemptEvent>(OnUnbuckleAttempt); + } + + private void OnUnbuckleAttempt(Entity<MobStateComponent> ent, ref UnbuckleAttemptEvent args) + { + // TODO is this necessary? + // Shouldn't the interaction have already been blocked by a general interaction check? + if (args.User == ent.Owner && IsIncapacitated(ent)) + args.Cancelled = true; } private void OnStateExitSubscribers(EntityUid target, MobStateComponent component, MobState state) @@ -90,12 +98,12 @@ private void OnStateEnteredSubscribers(EntityUid target, MobStateComponent compo _appearance.SetData(target, MobStateVisuals.State, MobState.Alive); break; case MobState.Critical: - _standing.Down(target, setDrawDepth: true); + _standing.Down(target); _appearance.SetData(target, MobStateVisuals.State, MobState.Critical); break; case MobState.Dead: EnsureComp<CollisionWakeComponent>(target); - _standing.Down(target, setDrawDepth: true); + _standing.Down(target); if (_standing.IsDown(target) && TryComp<PhysicsComponent>(target, out var physics)) { diff --git a/Content.Shared/Mobs/Systems/MobThresholdSystem.cs b/Content.Shared/Mobs/Systems/MobThresholdSystem.cs index 59d9fb4c239..b11de9eac56 100644 --- a/Content.Shared/Mobs/Systems/MobThresholdSystem.cs +++ b/Content.Shared/Mobs/Systems/MobThresholdSystem.cs @@ -431,7 +431,7 @@ private void MobThresholdStartup(EntityUid target, MobThresholdsComponent thresh private void MobThresholdShutdown(EntityUid target, MobThresholdsComponent component, ComponentShutdown args) { if (component.TriggersAlerts) - _alerts.ClearAlertCategory(target, AlertCategory.Health); + _alerts.ClearAlertCategory(target, component.HealthAlertCategory); } private void OnUpdateMobState(EntityUid target, MobThresholdsComponent component, ref UpdateMobStateEvent args) diff --git a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs index 01ce0efaae6..9d342fec3cf 100644 --- a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs +++ b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs @@ -1,4 +1,6 @@ +using Content.Shared.Alert; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; namespace Content.Shared.Movement.Pulling.Components; @@ -43,4 +45,6 @@ public sealed partial class PullableComponent : Component /// </summary> [DataField, AutoNetworkedField] public bool BeingActivelyPushed = false; + [DataField] + public ProtoId<AlertPrototype> PulledAlert = "Pulled"; } diff --git a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs index 648f06086ba..80a12be690a 100644 --- a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs +++ b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs @@ -1,6 +1,8 @@ -using Content.Shared.Movement.Pulling.Systems; +using Content.Shared.Alert; +using Content.Shared.Movement.Pulling.Systems; using Robust.Shared.GameStates; using Robust.Shared.Map; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Movement.Pulling.Components; @@ -64,4 +66,6 @@ public sealed partial class PullerComponent : Component /// </summary> [DataField] public float MaxPushRange = 2f; + [DataField] + public ProtoId<AlertPrototype> PullingAlert = "Pulling"; } diff --git a/Content.Shared/Movement/Pulling/Events/PullStartedMessage.cs b/Content.Shared/Movement/Pulling/Events/PullStartedMessage.cs index 29460e1dfc1..c0775b4ce2d 100644 --- a/Content.Shared/Movement/Pulling/Events/PullStartedMessage.cs +++ b/Content.Shared/Movement/Pulling/Events/PullStartedMessage.cs @@ -1,9 +1,6 @@ namespace Content.Shared.Movement.Pulling.Events; -public sealed class PullStartedMessage : PullMessage -{ - public PullStartedMessage(EntityUid pullerUid, EntityUid pullableUid) : - base(pullerUid, pullableUid) - { - } -} +/// <summary> +/// Event raised directed BOTH at the puller and pulled entity when a pull starts. +/// </summary> +public sealed class PullStartedMessage(EntityUid pullerUid, EntityUid pullableUid) : PullMessage(pullerUid, pullableUid); diff --git a/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs b/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs index 47aa34562fb..6df4d174839 100644 --- a/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs +++ b/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs @@ -1,13 +1,6 @@ -using Robust.Shared.Physics.Components; - -namespace Content.Shared.Movement.Pulling.Events; +namespace Content.Shared.Movement.Pulling.Events; /// <summary> -/// Raised directed on both puller and pullable. +/// Event raised directed BOTH at the puller and pulled entity when a pull starts. /// </summary> -public sealed class PullStoppedMessage : PullMessage -{ - public PullStoppedMessage(EntityUid pullerUid, EntityUid pulledUid) : base(pullerUid, pulledUid) - { - } -} +public sealed class PullStoppedMessage(EntityUid pullerUid, EntityUid pulledUid) : PullMessage(pullerUid, pulledUid); diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index 4bf53c8dbdd..11a1d94b29b 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -1,4 +1,3 @@ -using System.Numerics; using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; using Content.Shared.Alert; @@ -17,7 +16,6 @@ using Content.Shared.Projectiles; using Content.Shared.Pulling.Events; using Content.Shared.Standing; -using Content.Shared.Throwing; using Content.Shared.Verbs; using Robust.Shared.Containers; using Robust.Shared.Input.Binding; @@ -29,6 +27,8 @@ using Robust.Shared.Physics.Systems; using Robust.Shared.Player; using Robust.Shared.Timing; +using Content.Shared.Throwing; +using System.Numerics; namespace Content.Shared.Movement.Pulling.Systems; @@ -73,11 +73,25 @@ public override void Initialize() SubscribeLocalEvent<PullerComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed); SubscribeLocalEvent<PullerComponent, DropHandItemsEvent>(OnDropHandItems); + SubscribeLocalEvent<PullableComponent, StrappedEvent>(OnBuckled); + SubscribeLocalEvent<PullableComponent, BuckledEvent>(OnGotBuckled); + CommandBinds.Builder .Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(OnRequestMovePulledObject)) .Bind(ContentKeyFunctions.ReleasePulledObject, InputCmdHandler.FromDelegate(OnReleasePulledObject, handle: false)) .Register<PullingSystem>(); } + private void OnBuckled(Entity<PullableComponent> ent, ref StrappedEvent args) + { + // Prevent people from pulling the entity they are buckled to + if (ent.Comp.Puller == args.Buckle.Owner && !args.Buckle.Comp.PullStrap) + StopPulling(ent, ent); + } + + private void OnGotBuckled(Entity<PullableComponent> ent, ref BuckledEvent args) + { + StopPulling(ent, ent); + } public override void Shutdown() { @@ -174,7 +188,8 @@ private void OnDropHandItems(EntityUid uid, PullerComponent pullerComp, DropHand private void OnPullerContainerInsert(Entity<PullerComponent> ent, ref EntGotInsertedIntoContainerMessage args) { - if (ent.Comp.Pulling == null) return; + if (ent.Comp.Pulling == null) + return; if (!TryComp(ent.Comp.Pulling.Value, out PullableComponent? pulling)) return; @@ -307,8 +322,18 @@ private void OnJointRemoved(EntityUid uid, PullableComponent component, JointRem /// </summary> private void StopPulling(EntityUid pullableUid, PullableComponent pullableComp) { + if (pullableComp.Puller == null) + return; + if (!_timing.ApplyingState) { + // Joint shutdown + if (pullableComp.PullJointId != null) + { + _joints.RemoveJoint(pullableUid, pullableComp.PullJointId); + pullableComp.PullJointId = null; + } + if (TryComp<PhysicsComponent>(pullableUid, out var pullablePhysics)) { _physics.SetFixedRotation(pullableUid, pullableComp.PrevFixedRotation, body: pullablePhysics); @@ -325,7 +350,7 @@ private void StopPulling(EntityUid pullableUid, PullableComponent pullableComp) if (TryComp<PullerComponent>(oldPuller, out var pullerComp)) { var pullerUid = oldPuller.Value; - _alertsSystem.ClearAlert(pullerUid, AlertType.Pulling); + _alertsSystem.ClearAlert(pullerUid, pullerComp.PullingAlert); pullerComp.Pulling = null; Dirty(oldPuller.Value, pullerComp); @@ -339,7 +364,7 @@ private void StopPulling(EntityUid pullableUid, PullableComponent pullableComp) } - _alertsSystem.ClearAlert(pullableUid, AlertType.Pulled); + _alertsSystem.ClearAlert(pullableUid, pullableComp.PulledAlert); } public bool IsPulled(EntityUid uid, PullableComponent? component = null) @@ -440,15 +465,6 @@ public bool CanPull(EntityUid puller, EntityUid pullableUid, PullerComponent? pu return false; } - if (EntityManager.TryGetComponent(puller, out BuckleComponent? buckle)) - { - // Prevent people pulling the chair they're on, etc. - if (buckle is { PullStrap: false, Buckled: true } && (buckle.LastEntityBuckledTo == pullableUid)) - { - return false; - } - } - var getPulled = new BeingPulledAttemptEvent(puller, pullableUid); RaiseLocalEvent(pullableUid, getPulled, true); var startPull = new StartPullAttemptEvent(puller, pullableUid); @@ -492,11 +508,8 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, if (!CanPull(pullerUid, pullableUid)) return false; - if (!EntityManager.TryGetComponent<PhysicsComponent>(pullerUid, out var pullerPhysics) || - !EntityManager.TryGetComponent<PhysicsComponent>(pullableUid, out var pullablePhysics)) - { + if (!HasComp<PhysicsComponent>(pullerUid) || !TryComp(pullableUid, out PhysicsComponent? pullablePhysics)) return false; - } // Ensure that the puller is not currently pulling anything. if (TryComp<PullableComponent>(pullerComp.Pulling, out var oldPullable) @@ -540,7 +553,7 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, { // Joint startup var union = _physics.GetHardAABB(pullerUid).Union(_physics.GetHardAABB(pullableUid, body: pullablePhysics)); - var length = Math.Max((float) union.Size.X, (float) union.Size.Y) * 0.75f; + var length = Math.Max(union.Size.X, union.Size.Y) * 0.75f; var joint = _joints.CreateDistanceJoint(pullableUid, pullerUid, id: pullableComp.PullJointId); joint.CollideConnected = false; @@ -557,8 +570,8 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, // Messaging var message = new PullStartedMessage(pullerUid, pullableUid); - _alertsSystem.ShowAlert(pullerUid, AlertType.Pulling); - _alertsSystem.ShowAlert(pullableUid, AlertType.Pulled); + _alertsSystem.ShowAlert(pullerUid, pullerComp.PullingAlert); + _alertsSystem.ShowAlert(pullableUid, pullableComp.PulledAlert); RaiseLocalEvent(pullerUid, message); RaiseLocalEvent(pullableUid, message); @@ -584,17 +597,6 @@ public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, Entit if (msg.Cancelled) return false; - // Stop pulling confirmed! - if (!_timing.ApplyingState) - { - // Joint shutdown - if (pullable.PullJointId != null) - { - _joints.RemoveJoint(pullableUid, pullable.PullJointId); - pullable.PullJointId = null; - } - } - StopPulling(pullableUid, pullable); return true; } diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index 00afa3a4fb8..43a63068cf2 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -296,7 +296,7 @@ protected void HandleMobMovement( private void WalkingAlert(EntityUid player, InputMoverComponent component) { - _alerts.ShowAlert(player, AlertType.Walking, component.Sprinting ? (short) 1 : (short) 0); + _alerts.ShowAlert(player, component.WalkingAlert, component.Sprinting ? (short) 1 : (short) 0); } public void LerpRotation(EntityUid uid, InputMoverComponent mover, float frameTime) diff --git a/Content.Shared/Movement/Systems/SpeedModifierContactsSystem.cs b/Content.Shared/Movement/Systems/SpeedModifierContactsSystem.cs index f9f6b82bb18..400a675cd25 100644 --- a/Content.Shared/Movement/Systems/SpeedModifierContactsSystem.cs +++ b/Content.Shared/Movement/Systems/SpeedModifierContactsSystem.cs @@ -58,7 +58,7 @@ public void ChangeModifiers(EntityUid uid, float walkSpeed, float sprintSpeed, S } component.WalkSpeedModifier = walkSpeed; component.SprintSpeedModifier = sprintSpeed; - Dirty(component); + Dirty(uid, component); _toUpdate.UnionWith(_physics.GetContactingEntities(uid)); } diff --git a/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs b/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs index 0f3bff265cb..91c816df5c9 100644 --- a/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs +++ b/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Alert; using Content.Shared.Ninja.Systems; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; @@ -53,4 +54,7 @@ public sealed partial class SpaceNinjaComponent : Component /// </summary> [DataField] public EntProtoId SpiderChargeObjective = "SpiderChargeObjective"; + + [DataField] + public ProtoId<AlertPrototype> SuitPowerAlert = "SuitPower"; } diff --git a/Content.Shared/Nutrition/Components/HungerComponent.cs b/Content.Shared/Nutrition/Components/HungerComponent.cs index 9ac82ba283c..79d895ddae6 100644 --- a/Content.Shared/Nutrition/Components/HungerComponent.cs +++ b/Content.Shared/Nutrition/Components/HungerComponent.cs @@ -2,6 +2,7 @@ using Content.Shared.Damage; using Content.Shared.Nutrition.EntitySystems; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; @@ -65,15 +66,18 @@ public sealed partial class HungerComponent : Component /// <summary> /// A dictionary relating hunger thresholds to corresponding alerts. /// </summary> - [DataField("hungerThresholdAlerts", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, AlertType>))] + [DataField("hungerThresholdAlerts")] [AutoNetworkedField] - public Dictionary<HungerThreshold, AlertType> HungerThresholdAlerts = new() + public Dictionary<HungerThreshold, ProtoId<AlertPrototype>> HungerThresholdAlerts = new() { - { HungerThreshold.Peckish, AlertType.Peckish }, - { HungerThreshold.Starving, AlertType.Starving }, - { HungerThreshold.Dead, AlertType.Starving } + { HungerThreshold.Peckish, "Peckish" }, + { HungerThreshold.Starving, "Starving" }, + { HungerThreshold.Dead, "Starving" } }; + [DataField] + public ProtoId<AlertCategoryPrototype> HungerAlertCategory = "Hunger"; + /// <summary> /// A dictionary relating HungerThreshold to how much they modify <see cref="BaseDecayRate"/>. /// </summary> diff --git a/Content.Shared/Nutrition/Components/ThirstComponent.cs b/Content.Shared/Nutrition/Components/ThirstComponent.cs index 731346401fd..f3ac881361f 100644 --- a/Content.Shared/Nutrition/Components/ThirstComponent.cs +++ b/Content.Shared/Nutrition/Components/ThirstComponent.cs @@ -1,6 +1,7 @@ using Content.Shared.Alert; using Content.Shared.Nutrition.EntitySystems; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Nutrition.Components; @@ -56,11 +57,14 @@ public sealed partial class ThirstComponent : Component {ThirstThreshold.Dead, 0.0f}, }; - public static readonly Dictionary<ThirstThreshold, AlertType> ThirstThresholdAlertTypes = new() + [DataField] + public ProtoId<AlertCategoryPrototype> ThirstyCategory = "Thirst"; + + public static readonly Dictionary<ThirstThreshold, ProtoId<AlertPrototype>> ThirstThresholdAlertTypes = new() { - {ThirstThreshold.Thirsty, AlertType.Thirsty}, - {ThirstThreshold.Parched, AlertType.Parched}, - {ThirstThreshold.Dead, AlertType.Parched}, + {ThirstThreshold.Thirsty, "Thirsty"}, + {ThirstThreshold.Parched, "Parched"}, + {ThirstThreshold.Dead, "Parched"}, }; } diff --git a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs index e6d82553336..6535390d646 100644 --- a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs @@ -67,7 +67,7 @@ private void OnMapInit(EntityUid uid, HungerComponent component, MapInitEvent ar private void OnShutdown(EntityUid uid, HungerComponent component, ComponentShutdown args) { - _alerts.ClearAlertCategory(uid, AlertCategory.Hunger); + _alerts.ClearAlertCategory(uid, component.HungerAlertCategory); } private void OnRefreshMovespeed(EntityUid uid, HungerComponent component, RefreshMovementSpeedModifiersEvent args) @@ -112,7 +112,7 @@ public void SetHunger(EntityUid uid, float amount, HungerComponent? component = component.Thresholds[HungerThreshold.Dead], component.Thresholds[HungerThreshold.Overfed]); UpdateCurrentThreshold(uid, component); - Dirty(component); + Dirty(uid, component); } private void UpdateCurrentThreshold(EntityUid uid, HungerComponent? component = null) @@ -125,7 +125,7 @@ private void UpdateCurrentThreshold(EntityUid uid, HungerComponent? component = return; component.CurrentThreshold = calculatedHungerThreshold; DoHungerThresholdEffects(uid, component); - Dirty(component); + Dirty(uid, component); } private void DoHungerThresholdEffects(EntityUid uid, HungerComponent? component = null, bool force = false) @@ -153,7 +153,7 @@ private void DoHungerThresholdEffects(EntityUid uid, HungerComponent? component } else { - _alerts.ClearAlertCategory(uid, AlertCategory.Hunger); + _alerts.ClearAlertCategory(uid, component.HungerAlertCategory); } if (component.HungerThresholdDecayModifiers.TryGetValue(component.CurrentThreshold, out var modifier)) diff --git a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs index a068b19104c..4ff49e795c2 100644 --- a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs @@ -171,7 +171,7 @@ private void UpdateEffects(EntityUid uid, ThirstComponent component) } else { - _alerts.ClearAlertCategory(uid, AlertCategory.Thirst); + _alerts.ClearAlertCategory(uid, component.ThirstyCategory); } var ev = new MoodEffectEvent("Thirst" + component.CurrentThirstThreshold); diff --git a/Content.Shared/OfferItem/OfferItemComponent.cs b/Content.Shared/OfferItem/OfferItemComponent.cs index eb4d84932e5..f9f55291ddc 100644 --- a/Content.Shared/OfferItem/OfferItemComponent.cs +++ b/Content.Shared/OfferItem/OfferItemComponent.cs @@ -1,4 +1,6 @@ using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Content.Shared.Alert; namespace Content.Shared.OfferItem; @@ -23,4 +25,7 @@ public sealed partial class OfferItemComponent : Component [DataField] public float MaxOfferDistance = 2f; + + [DataField] + public ProtoId<AlertPrototype> OfferAlert = "Offer"; } diff --git a/Content.Shared/PAI/PAIComponent.cs b/Content.Shared/PAI/PAIComponent.cs index b4e4c927354..9d5be302758 100644 --- a/Content.Shared/PAI/PAIComponent.cs +++ b/Content.Shared/PAI/PAIComponent.cs @@ -31,7 +31,7 @@ public sealed partial class PAIComponent : Component public EntityUid? MidiAction; [DataField] - public ProtoId<EntityPrototype> MapActionId = "ActionPAIOpenMap"; + public EntProtoId MapActionId = "ActionPAIOpenMap"; [DataField, AutoNetworkedField] public EntityUid? MapAction; diff --git a/Content.Shared/Physics/Controllers/SharedConveyorController.cs b/Content.Shared/Physics/Controllers/SharedConveyorController.cs index c9ec77ba1c9..e3b22d84319 100644 --- a/Content.Shared/Physics/Controllers/SharedConveyorController.cs +++ b/Content.Shared/Physics/Controllers/SharedConveyorController.cs @@ -101,10 +101,10 @@ private void Convey(EntityUid uid, ConveyorComponent comp, EntityQuery<Transform transform.LocalPosition = localPos; // Force it awake for collisionwake reasons. - Physics.SetAwake(entity, body, true); + Physics.SetAwake((entity, body), true); Physics.SetSleepTime(body, 0f); } - Dirty(comp); + Dirty(uid, comp); } private static Vector2 Convey(Vector2 direction, float speed, float frameTime, Vector2 itemRelative) diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs index 4feb193a65c..19646f7e12d 100644 --- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs +++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs @@ -255,7 +255,7 @@ public static HumanoidCharacterProfile RandomWithSpecies(string species = Shared public HumanoidCharacterProfile WithSex(Sex sex) => new(this) { Sex = sex }; public HumanoidCharacterProfile WithGender(Gender gender) => new(this) { Gender = gender }; public HumanoidCharacterProfile WithSpecies(string species) => new(this) { Species = species }; - public HumanoidCharacterProfile WithCustomSpeciesName(string customspeciename) => new(this) { Customspeciename = customspeciename}; + public HumanoidCharacterProfile WithCustomSpeciesName(string customspeciename) => new(this) { Customspeciename = customspeciename }; public HumanoidCharacterProfile WithHeight(float height) => new(this) { Height = height }; public HumanoidCharacterProfile WithWidth(float width) => new(this) { Width = width }; @@ -368,7 +368,9 @@ public void EnsureValid(ICommonSession session, IDependencyCollection collection // ensure the species can be that sex and their age fits the founds if (!speciesPrototype.Sexes.Contains(sex)) + { sex = speciesPrototype.Sexes[0]; + } var age = Math.Clamp(Age, speciesPrototype.MinAge, speciesPrototype.MaxAge); @@ -383,16 +385,24 @@ public void EnsureValid(ICommonSession session, IDependencyCollection collection string name; if (string.IsNullOrEmpty(Name)) + { name = GetName(Species, gender); + } else if (Name.Length > MaxNameLength) + { name = Name[..MaxNameLength]; + } else + { name = Name; + } name = name.Trim(); if (configManager.GetCVar(CCVars.RestrictedNames)) + { name = RestrictedNameRegex.Replace(name, string.Empty); + } if (configManager.GetCVar(CCVars.ICNameCase)) { @@ -405,17 +415,23 @@ public void EnsureValid(ICommonSession session, IDependencyCollection collection || string.IsNullOrEmpty(Customspeciename) ? "" : Customspeciename.Length > MaxNameLength - ? FormattedMessage.RemoveMarkup(Customspeciename)[..MaxNameLength] - : FormattedMessage.RemoveMarkup(Customspeciename); + ? FormattedMessage.RemoveMarkupPermissive(Customspeciename)[..MaxNameLength] + : FormattedMessage.RemoveMarkupPermissive(Customspeciename); if (string.IsNullOrEmpty(name)) + { name = GetName(Species, gender); + } string flavortext; if (FlavorText.Length > MaxDescLength) - flavortext = FormattedMessage.RemoveMarkup(FlavorText)[..MaxDescLength]; + { + flavortext = FormattedMessage.RemoveMarkupPermissive(FlavorText)[..MaxDescLength]; + } else - flavortext = FormattedMessage.RemoveMarkup(FlavorText); + { + flavortext = FormattedMessage.RemoveMarkupPermissive(FlavorText); + } var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex); @@ -468,7 +484,9 @@ public void EnsureValid(ICommonSession session, IDependencyCollection collection _jobPriorities.Clear(); foreach (var (job, priority) in priorities) + { _jobPriorities.Add(job, priority); + } PreferenceUnavailable = prefsUnavailableMode; @@ -513,11 +531,11 @@ public override int GetHashCode() hashCode.Add(FlavorText); hashCode.Add(Species); hashCode.Add(Age); - hashCode.Add((int)Sex); - hashCode.Add((int)Gender); + hashCode.Add((int) Sex); + hashCode.Add((int) Gender); hashCode.Add(Appearance); - hashCode.Add((int)SpawnPriority); - hashCode.Add((int)PreferenceUnavailable); + hashCode.Add((int) SpawnPriority); + hashCode.Add((int) PreferenceUnavailable); hashCode.Add(Customspeciename); return hashCode.ToHashCode(); } diff --git a/Content.Shared/RCD/Systems/RCDAmmoSystem.cs b/Content.Shared/RCD/Systems/RCDAmmoSystem.cs index 9481d299aaa..9cb3c264851 100644 --- a/Content.Shared/RCD/Systems/RCDAmmoSystem.cs +++ b/Content.Shared/RCD/Systems/RCDAmmoSystem.cs @@ -36,7 +36,7 @@ private void OnAfterInteract(EntityUid uid, RCDAmmoComponent comp, AfterInteract if (args.Handled || !args.CanReach || !_timing.IsFirstTimePredicted) return; - if (args.Target is not {Valid: true} target || + if (args.Target is not { Valid: true } target || !HasComp<RCDComponent>(target) || !TryComp<LimitedChargesComponent>(target, out var charges)) return; @@ -53,7 +53,7 @@ private void OnAfterInteract(EntityUid uid, RCDAmmoComponent comp, AfterInteract _popup.PopupClient(Loc.GetString("rcd-ammo-component-after-interact-refilled"), target, user); _charges.AddCharges(target, count, charges); comp.Charges -= count; - Dirty(comp); + Dirty(uid, comp); // prevent having useless ammo with 0 charges if (comp.Charges <= 0) diff --git a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs index 20e57e94212..3941c2859bc 100644 --- a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs +++ b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Shared.Dataset; using Content.Shared.FixedPoint; @@ -41,7 +42,7 @@ public static string Pick(this IWeightedRandomPrototype prototype, IRobustRandom var sum = picks.Values.Sum(); var accumulated = 0f; - var rand = random.NextFloat() * sum; + var rand = random!.NextFloat() * sum; foreach (var (key, weight) in picks) { @@ -78,6 +79,47 @@ public static T Pick<T>(this IRobustRandom random, Dictionary<T, float> weights) throw new InvalidOperationException("Invalid weighted pick"); } + public static T PickAndTake<T>(this IRobustRandom random, Dictionary<T, float> weights) + where T : notnull + { + var pick = Pick(random, weights); + weights.Remove(pick); + return pick; + } + + public static bool TryPickAndTake<T>(this IRobustRandom random, Dictionary<T, float> weights, [NotNullWhen(true)] out T? pick) + where T : notnull + { + if (weights.Count == 0) + { + pick = default; + return false; + } + pick = PickAndTake(random, weights); + return true; + } + + public static T Pick<T>(Dictionary<T, float> weights, System.Random random) + where T : notnull + { + var sum = weights.Values.Sum(); + var accumulated = 0f; + + var rand = random.NextFloat() * sum; + + foreach (var (key, weight) in weights) + { + accumulated += weight; + + if (accumulated >= rand) + { + return key; + } + } + + throw new InvalidOperationException("Invalid weighted pick"); + } + public static (string reagent, FixedPoint2 quantity) Pick(this WeightedRandomFillSolutionPrototype prototype, IRobustRandom? random = null) { var randomFill = prototype.PickRandomFill(random); @@ -87,7 +129,7 @@ public static (string reagent, FixedPoint2 quantity) Pick(this WeightedRandomFil var sum = randomFill.Reagents.Count; var accumulated = 0f; - var rand = random.NextFloat() * sum; + var rand = random!.NextFloat() * sum; foreach (var reagent in randomFill.Reagents) { @@ -118,7 +160,7 @@ public static RandomFillSolution PickRandomFill(this WeightedRandomFillSolutionP var sum = picks.Values.Sum(); var accumulated = 0f; - var rand = random.NextFloat() * sum; + var rand = random!.NextFloat() * sum; foreach (var (randSolution, weight) in picks) { diff --git a/Content.Shared/Revenant/Components/RevenantComponent.cs b/Content.Shared/Revenant/Components/RevenantComponent.cs index 947c1a4b3fc..d7fb28ef136 100644 --- a/Content.Shared/Revenant/Components/RevenantComponent.cs +++ b/Content.Shared/Revenant/Components/RevenantComponent.cs @@ -1,4 +1,5 @@ using System.Numerics; +using Content.Shared.Alert; using Content.Shared.FixedPoint; using Content.Shared.Store; using Content.Shared.Whitelist; @@ -200,6 +201,9 @@ public sealed partial class RevenantComponent : Component public EntityWhitelist? MalfunctionBlacklist; #endregion + [DataField] + public ProtoId<AlertPrototype> EssenceAlert = "Essence"; + #region Visualizer [DataField("state")] public string State = "idle"; diff --git a/Content.Shared/Shadowkin/ShadowkinComponent.cs b/Content.Shared/Shadowkin/ShadowkinComponent.cs index b382f3112b7..a2a4fdf334f 100644 --- a/Content.Shared/Shadowkin/ShadowkinComponent.cs +++ b/Content.Shared/Shadowkin/ShadowkinComponent.cs @@ -1,4 +1,6 @@ using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Content.Shared.Alert; namespace Content.Shared.Shadowkin; @@ -39,4 +41,7 @@ public sealed partial class ShadowkinComponent : Component [DataField] public EntityUid? ShadowkinSleepAction; + + [DataField] + public ProtoId<AlertPrototype> ShadowkinPowerAlert = "ShadowkinPower"; } \ No newline at end of file diff --git a/Content.Shared/Showers/SharedShowerSystem.cs b/Content.Shared/Showers/SharedShowerSystem.cs index be3af6228f2..138a6869a94 100644 --- a/Content.Shared/Showers/SharedShowerSystem.cs +++ b/Content.Shared/Showers/SharedShowerSystem.cs @@ -79,7 +79,12 @@ private void UpdateAppearance(EntityUid uid, ShowerComponent? component = null) { if (component.PlayingStream == null) { - component.PlayingStream = _audio.PlayPvs(component.LoopingSound, uid, AudioParams.Default.WithLoop(true).WithMaxDistance(5)).Value.Entity; + var audio = _audio.PlayPvs(component.LoopingSound, uid, AudioParams.Default.WithLoop(true).WithMaxDistance(5)); + + if (audio == null) + return; + + component.PlayingStream = audio!.Value.Entity; } } else diff --git a/Content.Server/Shuttles/Components/FTLComponent.cs b/Content.Shared/Shuttles/Components/FTLComponent.cs similarity index 81% rename from Content.Server/Shuttles/Components/FTLComponent.cs rename to Content.Shared/Shuttles/Components/FTLComponent.cs index c9b84064234..9acca7c1d45 100644 --- a/Content.Server/Shuttles/Components/FTLComponent.cs +++ b/Content.Shared/Shuttles/Components/FTLComponent.cs @@ -2,16 +2,16 @@ using Content.Shared.Tag; using Content.Shared.Timing; using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.Shuttles.Components; +namespace Content.Shared.Shuttles.Components; /// <summary> /// Added to a component when it is queued or is travelling via FTL. /// </summary> -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class FTLComponent : Component { // TODO Full game save / add datafields @@ -29,13 +29,19 @@ public sealed partial class FTLComponent : Component [ViewVariables(VVAccess.ReadWrite)] public float TravelTime = 0f; + [DataField] + public EntProtoId? VisualizerProto = "FtlVisualizerEntity"; + + [DataField, AutoNetworkedField] + public EntityUid? VisualizerEntity; + /// <summary> /// Coordinates to arrive it: May be relative to another grid (for docking) or map coordinates. /// </summary> - [ViewVariables(VVAccess.ReadWrite), DataField] + [DataField, AutoNetworkedField] public EntityCoordinates TargetCoordinates; - [DataField] + [DataField, AutoNetworkedField] public Angle TargetAngle; /// <summary> diff --git a/Content.Shared/Shuttles/Components/FtlVisualizerComponent.cs b/Content.Shared/Shuttles/Components/FtlVisualizerComponent.cs new file mode 100644 index 00000000000..628a4f828b2 --- /dev/null +++ b/Content.Shared/Shuttles/Components/FtlVisualizerComponent.cs @@ -0,0 +1,23 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Utility; + +namespace Content.Shared.Shuttles.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FtlVisualizerComponent : Component +{ + /// <summary> + /// Clientside time tracker for the animation. + /// </summary> + [ViewVariables(VVAccess.ReadWrite)] + public float Elapsed; + + [DataField(required: true)] + public SpriteSpecifier.Rsi Sprite; + + /// <summary> + /// Target grid to pull FTL visualization from. + /// </summary> + [DataField, AutoNetworkedField] + public EntityUid Grid; +} diff --git a/Content.Shared/Shuttles/Components/PilotComponent.cs b/Content.Shared/Shuttles/Components/PilotComponent.cs index 1a6927cf813..cb42db4436f 100644 --- a/Content.Shared/Shuttles/Components/PilotComponent.cs +++ b/Content.Shared/Shuttles/Components/PilotComponent.cs @@ -1,7 +1,9 @@ using System.Numerics; +using Content.Shared.Alert; using Content.Shared.Movement.Systems; using Robust.Shared.GameStates; using Robust.Shared.Map; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Shared.Shuttles.Components @@ -32,6 +34,9 @@ public sealed partial class PilotComponent : Component [ViewVariables] public ShuttleButtons HeldButtons = ShuttleButtons.None; + [DataField] + public ProtoId<AlertPrototype> PilotingAlert = "PilotingShuttle"; + public override bool SendOnlyToOwner => true; } } diff --git a/Content.Shared/Silicon/Systems/SharedSiliconSystem.cs b/Content.Shared/Silicon/Systems/SharedSiliconSystem.cs index 8fe87e162bc..37d3bcd5c3b 100644 --- a/Content.Shared/Silicon/Systems/SharedSiliconSystem.cs +++ b/Content.Shared/Silicon/Systems/SharedSiliconSystem.cs @@ -60,12 +60,12 @@ private void OnSiliconInit(EntityUid uid, SiliconComponent component, ComponentI if (!component.BatteryPowered) return; - _alertsSystem.ShowAlert(uid, AlertType.BorgBattery, component.ChargeState); + _alertsSystem.ShowAlert(uid, component.BatteryAlert, component.ChargeState); } private void OnSiliconChargeStateUpdate(EntityUid uid, SiliconComponent component, SiliconChargeStateUpdateEvent ev) { - _alertsSystem.ShowAlert(uid, AlertType.BorgBattery, ev.ChargePercent); + _alertsSystem.ShowAlert(uid, component.BatteryAlert, ev.ChargePercent); } private void OnRefreshMovespeed(EntityUid uid, SiliconComponent component, RefreshMovementSpeedModifiersEvent args) diff --git a/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs b/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs index 71d3a7bd166..e1776873da9 100644 --- a/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs +++ b/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs @@ -1,6 +1,8 @@ -using Content.Shared.Whitelist; +using Content.Shared.Alert; +using Content.Shared.Whitelist; using Robust.Shared.Containers; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Silicons.Borgs.Components; @@ -76,6 +78,12 @@ public sealed partial class BorgChassisComponent : Component [DataField("noMindState")] public string NoMindState = string.Empty; #endregion + + [DataField] + public ProtoId<AlertPrototype> BatteryAlert = "BorgBattery"; + + [DataField] + public ProtoId<AlertPrototype> NoBatteryAlert = "BorgBatteryNone"; } [Serializable, NetSerializable] diff --git a/Content.Shared/Singularity/EntitySystems/SharedEventHorizonSystem.cs b/Content.Shared/Singularity/EntitySystems/SharedEventHorizonSystem.cs index f31dd8776a4..c2b52c5af35 100644 --- a/Content.Shared/Singularity/EntitySystems/SharedEventHorizonSystem.cs +++ b/Content.Shared/Singularity/EntitySystems/SharedEventHorizonSystem.cs @@ -66,7 +66,7 @@ public void SetRadius(EntityUid uid, float value, bool updateFixture = true, Eve return; eventHorizon.Radius = value; - Dirty(eventHorizon); + Dirty(uid, eventHorizon); if (updateFixture) UpdateEventHorizonFixture(uid, eventHorizon: eventHorizon); } @@ -89,7 +89,7 @@ public void SetCanBreachContainment(EntityUid uid, bool value, bool updateFixtur return; eventHorizon.CanBreachContainment = value; - Dirty(eventHorizon); + Dirty(uid, eventHorizon); if (updateFixture) UpdateEventHorizonFixture(uid, eventHorizon: eventHorizon); } @@ -112,7 +112,7 @@ public void SetColliderFixtureId(EntityUid uid, string? value, bool updateFixtur return; eventHorizon.ColliderFixtureId = value; - Dirty(eventHorizon); + Dirty(uid, eventHorizon); if (updateFixture) UpdateEventHorizonFixture(uid, eventHorizon: eventHorizon); } @@ -135,7 +135,7 @@ public void SetConsumerFixtureId(EntityUid uid, string? value, bool updateFixtur return; eventHorizon.ConsumerFixtureId = value; - Dirty(eventHorizon); + Dirty(uid, eventHorizon); if (updateFixture) UpdateEventHorizonFixture(uid, eventHorizon: eventHorizon); } diff --git a/Content.Shared/Stacks/SharedStackSystem.cs b/Content.Shared/Stacks/SharedStackSystem.cs index 756c84cac55..e12edd323c7 100644 --- a/Content.Shared/Stacks/SharedStackSystem.cs +++ b/Content.Shared/Stacks/SharedStackSystem.cs @@ -23,8 +23,8 @@ public abstract class SharedStackSystem : EntitySystem [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] protected readonly SharedHandsSystem Hands = default!; [Dependency] protected readonly SharedTransformSystem Xform = default!; - [Dependency] private readonly EntityLookupSystem _entityLookup = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly EntityLookupSystem _entityLookup = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; [Dependency] private readonly SharedStorageSystem _storage = default!; @@ -175,7 +175,7 @@ public virtual void SetCount(EntityUid uid, int amount, StackComponent? componen // Server-side override deletes the entity if count == 0 component.Count = amount; - Dirty(component); + Dirty(uid, component); Appearance.SetData(uid, StackVisuals.Actual, component.Count); RaiseLocalEvent(uid, new StackCountChangedEvent(old, component.Count)); diff --git a/Content.Shared/Standing/SharedLayingDownSystem.cs b/Content.Shared/Standing/SharedLayingDownSystem.cs index b2bb5add5f4..2f95a06f197 100644 --- a/Content.Shared/Standing/SharedLayingDownSystem.cs +++ b/Content.Shared/Standing/SharedLayingDownSystem.cs @@ -174,7 +174,7 @@ public bool TryLieDown(EntityUid uid, LayingDownComponent? layingDown = null, St return false; } - _standing.Down(uid, true, behavior != DropHeldItemsBehavior.NoDrop, standingState, setDrawDepth: true); + _standing.Down(uid, true, behavior != DropHeldItemsBehavior.NoDrop, standingState); return true; } } @@ -188,4 +188,4 @@ public enum DropHeldItemsBehavior : byte NoDrop, DropIfStanding, AlwaysDrop -} +} \ No newline at end of file diff --git a/Content.Shared/Standing/StandingStateSystem.cs b/Content.Shared/Standing/StandingStateSystem.cs index 5abbf53f1b2..a1b5418941a 100644 --- a/Content.Shared/Standing/StandingStateSystem.cs +++ b/Content.Shared/Standing/StandingStateSystem.cs @@ -57,7 +57,7 @@ public bool Down(EntityUid uid, bool playSound = true, bool dropHeldItems = true if (dropHeldItems && hands != null) RaiseLocalEvent(uid, new DropHandItemsEvent(), false); - if (TryComp(uid, out BuckleComponent? buckle) && buckle.Buckled && !_buckle.TryUnbuckle(uid, uid, buckleComp: buckle)) + if (TryComp(uid, out BuckleComponent? buckle) && buckle.Buckled) return false; var msg = new DownAttemptEvent(); @@ -67,7 +67,7 @@ public bool Down(EntityUid uid, bool playSound = true, bool dropHeldItems = true return false; standingState.CurrentState = StandingState.Lying; - Dirty(standingState); + Dirty(uid, standingState); RaiseLocalEvent(uid, new DownedEvent(), false); // Seemed like the best place to put it @@ -184,4 +184,4 @@ public sealed class StoodEvent : EntityEventArgs { } /// <summary> /// Raised when an entity is not standing /// </summary> -public sealed class DownedEvent : EntityEventArgs { } +public sealed class DownedEvent : EntityEventArgs { } \ No newline at end of file diff --git a/Content.Shared/StationRecords/StationRecordKeyStorageSystem.cs b/Content.Shared/StationRecords/StationRecordKeyStorageSystem.cs index 05af0807f21..e9d68721b63 100644 --- a/Content.Shared/StationRecords/StationRecordKeyStorageSystem.cs +++ b/Content.Shared/StationRecords/StationRecordKeyStorageSystem.cs @@ -58,7 +58,7 @@ public void AssignKey(EntityUid uid, StationRecordKey key, StationRecordKeyStora var key = keyStorage.Key; keyStorage.Key = null; - Dirty(keyStorage); + Dirty(uid, keyStorage); return key; } diff --git a/Content.Shared/StatusEffect/StatusEffectPrototype.cs b/Content.Shared/StatusEffect/StatusEffectPrototype.cs index ae9e26879eb..8b1f84e4d81 100644 --- a/Content.Shared/StatusEffect/StatusEffectPrototype.cs +++ b/Content.Shared/StatusEffect/StatusEffectPrototype.cs @@ -10,7 +10,7 @@ public sealed partial class StatusEffectPrototype : IPrototype public string ID { get; private set; } = default!; [DataField("alert")] - public AlertType? Alert { get; private set; } + public ProtoId<AlertPrototype>? Alert { get; private set; } /// <summary> /// Whether a status effect should be able to apply to any entity, diff --git a/Content.Shared/StatusEffect/StatusEffectsSystem.cs b/Content.Shared/StatusEffect/StatusEffectsSystem.cs index cc6dedae495..124dcdd8d67 100644 --- a/Content.Shared/StatusEffect/StatusEffectsSystem.cs +++ b/Content.Shared/StatusEffect/StatusEffectsSystem.cs @@ -234,7 +234,7 @@ public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool re _alertsSystem.ShowAlert(uid, proto.Alert.Value, null, cooldown1); } - Dirty(status); + Dirty(uid, status); RaiseLocalEvent(uid, new StatusEffectAddedEvent(uid, key)); return true; } @@ -246,7 +246,7 @@ public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool re /// This is mostly for stuns, since Stun and Knockdown share an alert key. Other times this pretty much /// will not be useful. /// </remarks> - private (TimeSpan, TimeSpan)? GetAlertCooldown(EntityUid uid, AlertType alert, StatusEffectsComponent status) + private (TimeSpan, TimeSpan)? GetAlertCooldown(EntityUid uid, ProtoId<AlertPrototype> alert, StatusEffectsComponent status) { (TimeSpan, TimeSpan)? maxCooldown = null; foreach (var kvp in status.ActiveEffects) @@ -310,7 +310,7 @@ public bool TryRemoveStatusEffect(EntityUid uid, string key, RemComp<ActiveStatusEffectsComponent>(uid); } - Dirty(status); + Dirty(uid, status); RaiseLocalEvent(uid, new StatusEffectEndedEvent(uid, key)); return true; } @@ -334,7 +334,7 @@ public bool TryRemoveAllStatusEffects(EntityUid uid, failed = true; } - Dirty(status); + Dirty(uid, status); return failed; } @@ -408,7 +408,7 @@ public bool TryAddTime(EntityUid uid, string key, TimeSpan time, _alertsSystem.ShowAlert(uid, proto.Alert.Value, null, cooldown); } - Dirty(status); + Dirty(uid, status); return true; } @@ -444,7 +444,7 @@ public bool TryRemoveTime(EntityUid uid, string key, TimeSpan time, _alertsSystem.ShowAlert(uid, proto.Alert.Value, null, cooldown); } - Dirty(status); + Dirty(uid, status); return true; } @@ -465,7 +465,7 @@ public bool TrySetTime(EntityUid uid, string key, TimeSpan time, status.ActiveEffects[key].Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + time); - Dirty(status); + Dirty(uid, status); return true; } diff --git a/Content.Shared/Storage/EntitySystems/BinSystem.cs b/Content.Shared/Storage/EntitySystems/BinSystem.cs index 17c3eb4288c..1cc95337ea4 100644 --- a/Content.Shared/Storage/EntitySystems/BinSystem.cs +++ b/Content.Shared/Storage/EntitySystems/BinSystem.cs @@ -135,7 +135,7 @@ public bool TryInsertIntoBin(EntityUid uid, EntityUid toInsert, BinComponent? co _container.Insert(toInsert, component.ItemContainer); component.Items.Add(toInsert); - Dirty(component); + Dirty(uid, component); return true; } @@ -151,7 +151,7 @@ public bool TryRemoveFromBin(EntityUid uid, EntityUid? toRemove, BinComponent? c if (!Resolve(uid, ref component)) return false; - if (!component.Items.Any()) + if (component.Items.Count == 0) return false; if (toRemove == null || toRemove != component.Items.LastOrDefault()) @@ -161,7 +161,7 @@ public bool TryRemoveFromBin(EntityUid uid, EntityUid? toRemove, BinComponent? c return false; component.Items.Remove(toRemove.Value); - Dirty(component); + Dirty(uid, component); return true; } } diff --git a/Content.Shared/Stunnable/SharedStunSystem.cs b/Content.Shared/Stunnable/SharedStunSystem.cs index 05d6b8ec533..ad36ba9329a 100644 --- a/Content.Shared/Stunnable/SharedStunSystem.cs +++ b/Content.Shared/Stunnable/SharedStunSystem.cs @@ -1,7 +1,5 @@ using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; -using Content.Shared.Audio; -using Content.Shared.DragDrop; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Inventory.Events; @@ -11,13 +9,11 @@ using Content.Shared.Hands; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; -using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Events; using Content.Shared.Movement.Systems; using Content.Shared.Standing; using Content.Shared.StatusEffect; using Content.Shared.Throwing; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.GameStates; @@ -88,15 +84,15 @@ private void OnMobStateChanged(EntityUid uid, MobStateComponent component, MobSt case MobState.Alive: break; case MobState.Critical: - { - _statusEffect.TryRemoveStatusEffect(uid, "Stun"); - break; - } + { + _statusEffect.TryRemoveStatusEffect(uid, "Stun"); + break; + } case MobState.Dead: - { - _statusEffect.TryRemoveStatusEffect(uid, "Stun"); - break; - } + { + _statusEffect.TryRemoveStatusEffect(uid, "Stun"); + break; + } case MobState.Invalid: default: return; @@ -258,11 +254,11 @@ private void OnInteractHand(EntityUid uid, KnockedDownComponent knocked, Interac return; // Set it to half the help interval so helping is actually useful... - knocked.HelpTimer = knocked.HelpInterval/2f; + knocked.HelpTimer = knocked.HelpInterval / 2f; _statusEffect.TryRemoveTime(uid, "KnockedDown", TimeSpan.FromSeconds(knocked.HelpInterval)); _audio.PlayPredicted(knocked.StunAttemptSound, uid, args.User); - Dirty(knocked); + Dirty(uid, knocked); args.Handled = true; } diff --git a/Content.Shared/SubFloor/SharedTrayScannerSystem.cs b/Content.Shared/SubFloor/SharedTrayScannerSystem.cs index 3dc1575ddb9..6e8393036d4 100644 --- a/Content.Shared/SubFloor/SharedTrayScannerSystem.cs +++ b/Content.Shared/SubFloor/SharedTrayScannerSystem.cs @@ -35,7 +35,7 @@ private void SetScannerEnabled(EntityUid uid, bool enabled, TrayScannerComponent return; scanner.Enabled = enabled; - Dirty(scanner); + Dirty(uid, scanner); // We don't remove from _activeScanners on disabled, because the update function will handle that, as well as // managing the revealed subfloor entities diff --git a/Content.Shared/Tag/TagSystem.cs b/Content.Shared/Tag/TagSystem.cs index 0707308e486..b9fef076c88 100644 --- a/Content.Shared/Tag/TagSystem.cs +++ b/Content.Shared/Tag/TagSystem.cs @@ -79,7 +79,7 @@ private void AssertValidTag(string id) /// </exception> public bool AddTag(EntityUid entity, string id) { - return AddTag(EnsureComp<TagComponent>(entity), id); + return AddTag(entity, EnsureComp<TagComponent>(entity), id); } /// <summary> @@ -95,7 +95,7 @@ public bool AddTag(EntityUid entity, string id) /// </exception> public bool AddTags(EntityUid entity, params string[] ids) { - return AddTags(EnsureComp<TagComponent>(entity), ids); + return AddTags(entity, EnsureComp<TagComponent>(entity), ids); } /// <summary> @@ -111,7 +111,7 @@ public bool AddTags(EntityUid entity, params string[] ids) /// </exception> public bool AddTags(EntityUid entity, IEnumerable<string> ids) { - return AddTags(EnsureComp<TagComponent>(entity), ids); + return AddTags(entity, EnsureComp<TagComponent>(entity), ids); } /// <summary> @@ -128,8 +128,8 @@ public bool AddTags(EntityUid entity, IEnumerable<string> ids) /// </exception> public bool TryAddTag(EntityUid entity, string id) { - return _tagQuery.TryComp(entity, out var component) && - AddTag(component, id); + return TryComp<TagComponent>(entity, out var component) && + AddTag(entity, component, id); } /// <summary> @@ -146,8 +146,8 @@ public bool TryAddTag(EntityUid entity, string id) /// </exception> public bool TryAddTags(EntityUid entity, params string[] ids) { - return _tagQuery.TryComp(entity, out var component) && - AddTags(component, ids); + return TryComp<TagComponent>(entity, out var component) && + AddTags(entity, component, ids); } /// <summary> @@ -164,8 +164,8 @@ public bool TryAddTags(EntityUid entity, params string[] ids) /// </exception> public bool TryAddTags(EntityUid entity, IEnumerable<string> ids) { - return _tagQuery.TryComp(entity, out var component) && - AddTags(component, ids); + return TryComp<TagComponent>(entity, out var component) && + AddTags(entity, component, ids); } /// <summary> @@ -333,8 +333,8 @@ public bool HasAnyTag(EntityUid entity, IEnumerable<string> ids) /// </exception> public bool RemoveTag(EntityUid entity, string id) { - return _tagQuery.TryComp(entity, out var component) && - RemoveTag(component, id); + return TryComp<TagComponent>(entity, out var component) && + RemoveTag(entity, component, id); } /// <summary> @@ -350,8 +350,8 @@ public bool RemoveTag(EntityUid entity, string id) /// </returns> public bool RemoveTags(EntityUid entity, params string[] ids) { - return _tagQuery.TryComp(entity, out var component) && - RemoveTags(component, ids); + return TryComp<TagComponent>(entity, out var component) && + RemoveTags(entity, component, ids); } /// <summary> @@ -367,8 +367,8 @@ public bool RemoveTags(EntityUid entity, params string[] ids) /// </exception> public bool RemoveTags(EntityUid entity, IEnumerable<string> ids) { - return _tagQuery.TryComp(entity, out var component) && - RemoveTags(component, ids); + return TryComp<TagComponent>(entity, out var component) && + RemoveTags(entity, component, ids); } /// <summary> @@ -379,14 +379,14 @@ public bool RemoveTags(EntityUid entity, IEnumerable<string> ids) /// <exception cref="UnknownPrototypeException"> /// Thrown if no <see cref="TagPrototype"/> exists with the given id. /// </exception> - public bool AddTag(TagComponent component, string id) + public bool AddTag(EntityUid uid, TagComponent component, string id) { AssertValidTag(id); var added = component.Tags.Add(id); if (added) { - Dirty(component); + Dirty(uid, component); return true; } @@ -401,9 +401,9 @@ public bool AddTag(TagComponent component, string id) /// <exception cref="UnknownPrototypeException"> /// Thrown if one of the ids represents an unregistered <see cref="TagPrototype"/>. /// </exception> - public bool AddTags(TagComponent component, params string[] ids) + public bool AddTags(EntityUid uid, TagComponent component, params string[] ids) { - return AddTags(component, ids.AsEnumerable()); + return AddTags(uid, component, ids.AsEnumerable()); } /// <summary> @@ -414,7 +414,7 @@ public bool AddTags(TagComponent component, params string[] ids) /// <exception cref="UnknownPrototypeException"> /// Thrown if one of the ids represents an unregistered <see cref="TagPrototype"/>. /// </exception> - public bool AddTags(TagComponent component, IEnumerable<string> ids) + public bool AddTags(EntityUid uid, TagComponent component, IEnumerable<string> ids) { var count = component.Tags.Count; @@ -426,7 +426,7 @@ public bool AddTags(TagComponent component, IEnumerable<string> ids) if (component.Tags.Count > count) { - Dirty(component); + Dirty(uid, component); return true; } @@ -642,13 +642,13 @@ public bool HasAnyTag(TagComponent comp, List<ProtoId<TagPrototype>> ids) /// <exception cref="UnknownPrototypeException"> /// Thrown if no <see cref="TagPrototype"/> exists with the given id. /// </exception> - public bool RemoveTag(TagComponent component, string id) + public bool RemoveTag(EntityUid uid, TagComponent component, string id) { AssertValidTag(id); if (component.Tags.Remove(id)) { - Dirty(component); + Dirty(uid, component); return true; } @@ -665,9 +665,9 @@ public bool RemoveTag(TagComponent component, string id) /// <exception cref="UnknownPrototypeException"> /// Thrown if one of the ids represents an unregistered <see cref="TagPrototype"/>. /// </exception> - public bool RemoveTags(TagComponent component, params string[] ids) + public bool RemoveTags(EntityUid uid, TagComponent component, params string[] ids) { - return RemoveTags(component, ids.AsEnumerable()); + return RemoveTags(uid, component, ids.AsEnumerable()); } /// <summary> @@ -678,7 +678,7 @@ public bool RemoveTags(TagComponent component, params string[] ids) /// <exception cref="UnknownPrototypeException"> /// Thrown if one of the ids represents an unregistered <see cref="TagPrototype"/>. /// </exception> - public bool RemoveTags(TagComponent component, IEnumerable<string> ids) + public bool RemoveTags(EntityUid uid, TagComponent component, IEnumerable<string> ids) { var count = component.Tags.Count; @@ -690,7 +690,7 @@ public bool RemoveTags(TagComponent component, IEnumerable<string> ids) if (component.Tags.Count < count) { - Dirty(component); + Dirty(uid, component); return true; } diff --git a/Content.Shared/Teleportation/Systems/LinkedEntitySystem.cs b/Content.Shared/Teleportation/Systems/LinkedEntitySystem.cs index bf2d087c761..35ce5665ddf 100644 --- a/Content.Shared/Teleportation/Systems/LinkedEntitySystem.cs +++ b/Content.Shared/Teleportation/Systems/LinkedEntitySystem.cs @@ -87,7 +87,7 @@ public bool OneWayLink(EntityUid source, EntityUid target, bool deleteOnEmptyLin /// <param name="secondLink">Resolve comp</param> /// <returns>Whether unlinking was successful (e.g. they both were actually linked to one another)</returns> public bool TryUnlink(EntityUid first, EntityUid second, - LinkedEntityComponent? firstLink=null, LinkedEntityComponent? secondLink=null) + LinkedEntityComponent? firstLink = null, LinkedEntityComponent? secondLink = null) { if (!Resolve(first, ref firstLink)) return false; @@ -101,8 +101,8 @@ public bool TryUnlink(EntityUid first, EntityUid second, _appearance.SetData(first, LinkedEntityVisuals.HasAnyLinks, firstLink.LinkedEntities.Any()); _appearance.SetData(second, LinkedEntityVisuals.HasAnyLinks, secondLink.LinkedEntities.Any()); - Dirty(firstLink); - Dirty(secondLink); + Dirty(first, firstLink); + Dirty(second, secondLink); if (firstLink.LinkedEntities.Count == 0 && firstLink.DeleteOnEmptyLinks) QueueDel(first); diff --git a/Content.Shared/Traits/Assorted/Systems/LegsParalyzedSystem.cs b/Content.Shared/Traits/Assorted/Systems/LegsParalyzedSystem.cs index 8ae0f251b86..4556d8ee991 100644 --- a/Content.Shared/Traits/Assorted/Systems/LegsParalyzedSystem.cs +++ b/Content.Shared/Traits/Assorted/Systems/LegsParalyzedSystem.cs @@ -17,7 +17,8 @@ public override void Initialize() { SubscribeLocalEvent<Components.LegsParalyzedComponent, ComponentStartup>(OnStartup); SubscribeLocalEvent<Components.LegsParalyzedComponent, ComponentShutdown>(OnShutdown); - SubscribeLocalEvent<Components.LegsParalyzedComponent, BuckleChangeEvent>(OnBuckleChange); + SubscribeLocalEvent<Components.LegsParalyzedComponent, BuckledEvent>(OnBuckled); + SubscribeLocalEvent<Components.LegsParalyzedComponent, UnbuckledEvent>(OnUnbuckled); SubscribeLocalEvent<Components.LegsParalyzedComponent, ThrowPushbackAttemptEvent>(OnThrowPushbackAttempt); SubscribeLocalEvent<Components.LegsParalyzedComponent, UpdateCanMoveEvent>(OnUpdateCanMoveEvent); } @@ -34,25 +35,11 @@ private void OnShutdown(EntityUid uid, Components.LegsParalyzedComponent compone _bodySystem.UpdateMovementSpeed(uid); } - private void OnBuckleChange(EntityUid uid, Components.LegsParalyzedComponent component, ref BuckleChangeEvent args) - { - if (args.Buckling) - { - _standingSystem.Stand(args.BuckledEntity); - } - else - { - _standingSystem.Down(args.BuckledEntity); - } - } + private void OnBuckled(EntityUid uid, Components.LegsParalyzedComponent component, ref BuckledEvent args) => _standingSystem.Stand(uid); - private void OnUpdateCanMoveEvent(EntityUid uid, Components.LegsParalyzedComponent component, UpdateCanMoveEvent args) - { - args.Cancel(); - } + private void OnUnbuckled(EntityUid uid, Components.LegsParalyzedComponent component, ref UnbuckledEvent args) => _standingSystem.Down(uid); - private void OnThrowPushbackAttempt(EntityUid uid, Components.LegsParalyzedComponent component, ThrowPushbackAttemptEvent args) - { - args.Cancel(); - } + private void OnUpdateCanMoveEvent(EntityUid uid, Components.LegsParalyzedComponent component, UpdateCanMoveEvent args) => args.Cancel(); + + private void OnThrowPushbackAttempt(EntityUid uid, Components.LegsParalyzedComponent component, ThrowPushbackAttemptEvent args) => args.Cancel(); } diff --git a/Content.Shared/Traits/Assorted/Systems/SharedSingerSystem.cs b/Content.Shared/Traits/Assorted/Systems/SharedSingerSystem.cs index 13270ae45d2..5bf4e0d3789 100644 --- a/Content.Shared/Traits/Assorted/Systems/SharedSingerSystem.cs +++ b/Content.Shared/Traits/Assorted/Systems/SharedSingerSystem.cs @@ -38,7 +38,7 @@ private void OnStartup(Entity<SingerComponent> ent, ref ComponentStartup args) var instrumentComp = EnsureInstrumentComp(ent); var defaultData = singer.InstrumentList[singer.DefaultInstrument]; - _instrument.SetInstrumentProgram(instrumentComp, defaultData.Item1, defaultData.Item2); + _instrument.SetInstrumentProgram(ent.Owner, instrumentComp, defaultData.Item1, defaultData.Item2); SetUpSwappableInstrument(ent, singer); } diff --git a/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs b/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs index 63b2d5f2115..d1814020e6e 100644 --- a/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs +++ b/Content.Shared/Weapons/Marker/SharedDamageMarkerSystem.cs @@ -71,7 +71,7 @@ private void OnMarkerCollide(EntityUid uid, DamageMarkerOnCollideComponent compo marker.Marker = projectile.Weapon.Value; marker.EndTime = _timing.CurTime + component.Duration; component.Amount--; - Dirty(marker); + Dirty(args.OtherEntity, marker); if (_netManager.IsServer) { @@ -81,7 +81,7 @@ private void OnMarkerCollide(EntityUid uid, DamageMarkerOnCollideComponent compo } else { - Dirty(component); + Dirty(uid, component); } } } diff --git a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs index 3a950bcd29e..dd297422c37 100644 --- a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs +++ b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs @@ -21,17 +21,17 @@ namespace Content.Shared.Weapons.Misc; public abstract partial class SharedTetherGunSystem : EntitySystem { - [Dependency] private readonly INetManager _netManager = default!; - [Dependency] private readonly ActionBlockerSystem _blocker = default!; - [Dependency] private readonly MobStateSystem _mob = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; - [Dependency] private readonly SharedJointSystem _joints = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly INetManager _netManager = default!; + [Dependency] private readonly ActionBlockerSystem _blocker = default!; + [Dependency] private readonly MobStateSystem _mob = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedJointSystem _joints = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; - [Dependency] private readonly ThrowingSystem _throwing = default!; - [Dependency] private readonly ThrownItemSystem _thrown = default!; + [Dependency] private readonly ThrowingSystem _throwing = default!; + [Dependency] private readonly ThrownItemSystem _thrown = default!; private const string TetherJoint = "tether"; @@ -282,7 +282,7 @@ protected virtual void StopTether(EntityUid gunUid, BaseForceGunComponent compon RemComp<TetheredComponent>(component.Tethered.Value); _blocker.UpdateCanMove(component.Tethered.Value); component.Tethered = null; - Dirty(component); + Dirty(gunUid, component); } [Serializable, NetSerializable] diff --git a/Content.Shared/Weapons/Ranged/Systems/RechargeBasicEntityAmmoSystem.cs b/Content.Shared/Weapons/Ranged/Systems/RechargeBasicEntityAmmoSystem.cs index b774c8ab450..9d6d5524001 100644 --- a/Content.Shared/Weapons/Ranged/Systems/RechargeBasicEntityAmmoSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/RechargeBasicEntityAmmoSystem.cs @@ -49,19 +49,19 @@ public override void Update(float frameTime) if (ammo.Count == ammo.Capacity) { recharge.NextCharge = null; - Dirty(recharge); + Dirty(uid, recharge); continue; } recharge.NextCharge = recharge.NextCharge.Value + TimeSpan.FromSeconds(recharge.RechargeCooldown); - Dirty(recharge); + Dirty(uid, recharge); } } private void OnInit(EntityUid uid, RechargeBasicEntityAmmoComponent component, MapInitEvent args) { component.NextCharge = _timing.CurTime; - Dirty(component); + Dirty(uid, component); } private void OnExamined(EntityUid uid, RechargeBasicEntityAmmoComponent component, ExaminedEvent args) @@ -86,7 +86,7 @@ public void Reset(EntityUid uid, RechargeBasicEntityAmmoComponent? recharge = nu if (recharge.NextCharge == null || recharge.NextCharge < _timing.CurTime) { recharge.NextCharge = _timing.CurTime + TimeSpan.FromSeconds(recharge.RechargeCooldown); - Dirty(recharge); + Dirty(uid, recharge); } } } diff --git a/Content.Shared/Weapons/Ranged/Systems/RechargeCycleAmmoSystem.cs b/Content.Shared/Weapons/Ranged/Systems/RechargeCycleAmmoSystem.cs index 136e9b59b2f..a014f8e5c74 100644 --- a/Content.Shared/Weapons/Ranged/Systems/RechargeCycleAmmoSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/RechargeCycleAmmoSystem.cs @@ -25,7 +25,7 @@ private void OnRechargeCycled(EntityUid uid, RechargeCycleAmmoComponent componen return; _gun.UpdateBasicEntityAmmoCount(uid, basic.Count.Value + 1, basic); - Dirty(basic); + Dirty(uid, basic); args.Handled = true; } } diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index b714acefbd1..af295cc83ff 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -118,7 +118,7 @@ private void OnGunMelee(EntityUid uid, GunComponent component, MeleeHitEvent arg if (melee.NextAttack > component.NextFire) { component.NextFire = melee.NextAttack; - Dirty(component); + Dirty(uid, component); } } diff --git a/Content.Shared/Weapons/Reflect/ReflectSystem.cs b/Content.Shared/Weapons/Reflect/ReflectSystem.cs index 36dbedb4cb1..03ad97edff2 100644 --- a/Content.Shared/Weapons/Reflect/ReflectSystem.cs +++ b/Content.Shared/Weapons/Reflect/ReflectSystem.cs @@ -42,6 +42,9 @@ public sealed class ReflectSystem : EntitySystem [Dependency] private readonly StandingStateSystem _standing = default!; [Dependency] private readonly AlertsSystem _alerts = default!; + [ValidatePrototypeId<AlertPrototype>] + private const string DeflectingAlert = "Deflecting"; + public override void Initialize() { base.Initialize(); @@ -296,11 +299,11 @@ private void RefreshReflectUser(EntityUid user) private void EnableAlert(EntityUid alertee) { - _alerts.ShowAlert(alertee, AlertType.Deflecting); + _alerts.ShowAlert(alertee, DeflectingAlert); } private void DisableAlert(EntityUid alertee) { - _alerts.ClearAlert(alertee, AlertType.Deflecting); + _alerts.ClearAlert(alertee, DeflectingAlert); } } diff --git a/Content.Shared/Weather/SharedWeatherSystem.cs b/Content.Shared/Weather/SharedWeatherSystem.cs index 45a2afe7cd9..19671bd77b0 100644 --- a/Content.Shared/Weather/SharedWeatherSystem.cs +++ b/Content.Shared/Weather/SharedWeatherSystem.cs @@ -15,8 +15,8 @@ public abstract class SharedWeatherSystem : EntitySystem [Dependency] protected readonly IGameTiming Timing = default!; [Dependency] protected readonly IMapManager MapManager = default!; [Dependency] protected readonly IPrototypeManager ProtoMan = default!; - [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; - [Dependency] private readonly MetaDataSystem _metadata = default!; + [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; + [Dependency] private readonly MetaDataSystem _metadata = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; private EntityQuery<BlockWeatherComponent> _blockQuery; @@ -129,7 +129,7 @@ public override void Update(float frameTime) // Shutting down if (endTime != null && remainingTime < WeatherComponent.ShutdownTime) { - SetState(WeatherState.Ending, comp, weather, weatherProto); + SetState(uid, WeatherState.Ending, comp, weather, weatherProto); } // Starting up else @@ -139,7 +139,7 @@ public override void Update(float frameTime) if (elapsed < WeatherComponent.StartupTime) { - SetState(WeatherState.Starting, comp, weather, weatherProto); + SetState(uid, WeatherState.Starting, comp, weather, weatherProto); } } @@ -182,15 +182,15 @@ public void SetWeather(MapId mapId, WeatherPrototype? proto, TimeSpan? endTime) } if (proto != null) - StartWeather(weatherComp, proto, endTime); + StartWeather(mapUid, weatherComp, proto, endTime); } /// <summary> /// Run every tick when the weather is running. /// </summary> - protected virtual void Run(EntityUid uid, WeatherData weather, WeatherPrototype weatherProto, float frameTime) {} + protected virtual void Run(EntityUid uid, WeatherData weather, WeatherPrototype weatherProto, float frameTime) { } - protected void StartWeather(WeatherComponent component, WeatherPrototype weather, TimeSpan? endTime) + protected void StartWeather(EntityUid uid, WeatherComponent component, WeatherPrototype weather, TimeSpan? endTime) { if (component.Weather.ContainsKey(weather.ID)) return; @@ -202,7 +202,7 @@ protected void StartWeather(WeatherComponent component, WeatherPrototype weather }; component.Weather.Add(weather.ID, data); - Dirty(component); + Dirty(uid, component); } protected virtual void EndWeather(EntityUid uid, WeatherComponent component, string proto) @@ -216,13 +216,13 @@ protected virtual void EndWeather(EntityUid uid, WeatherComponent component, str Dirty(uid, component); } - protected virtual bool SetState(WeatherState state, WeatherComponent component, WeatherData weather, WeatherPrototype weatherProto) + protected virtual bool SetState(EntityUid uid, WeatherState state, WeatherComponent component, WeatherData weather, WeatherPrototype weatherProto) { if (weather.State.Equals(state)) return false; weather.State = state; - Dirty(component); + Dirty(uid, component); return true; } diff --git a/Content.Tests/Shared/Alert/AlertManagerTests.cs b/Content.Tests/Shared/Alert/AlertManagerTests.cs index 2d5f6af5a7f..c57df63d5b7 100644 --- a/Content.Tests/Shared/Alert/AlertManagerTests.cs +++ b/Content.Tests/Shared/Alert/AlertManagerTests.cs @@ -1,6 +1,5 @@ using System.IO; using Content.Client.Alerts; -using Content.Server.Alert; using Content.Shared.Alert; using NUnit.Framework; using Robust.Shared.GameObjects; @@ -45,15 +44,15 @@ public void TestAlertManager() prototypeManager.Initialize(); prototypeManager.LoadFromStream(new StringReader(PROTOTYPES)); - Assert.That(alertsSystem.TryGet(AlertType.LowPressure, out var lowPressure)); - Assert.That(lowPressure.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/lowpressure.png")))); - Assert.That(alertsSystem.TryGet(AlertType.HighPressure, out var highPressure)); - Assert.That(highPressure.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/highpressure.png")))); + Assert.That(alertsSystem.TryGet("LowPressure", out var lowPressure)); + Assert.That(lowPressure!.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/lowpressure.png")))); + Assert.That(alertsSystem.TryGet("HighPressure", out var highPressure)); + Assert.That(highPressure!.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/highpressure.png")))); - Assert.That(alertsSystem.TryGet(AlertType.LowPressure, out lowPressure)); - Assert.That(lowPressure.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/lowpressure.png")))); - Assert.That(alertsSystem.TryGet(AlertType.HighPressure, out highPressure)); - Assert.That(highPressure.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/highpressure.png")))); + Assert.That(alertsSystem.TryGet("LowPressure", out lowPressure)); + Assert.That(lowPressure!.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/lowpressure.png")))); + Assert.That(alertsSystem.TryGet("HighPressure", out highPressure)); + Assert.That(highPressure!.Icons[0], Is.EqualTo(new SpriteSpecifier.Texture(new ("/Textures/Interface/Alerts/Pressure/highpressure.png")))); } } } diff --git a/Content.Tests/Shared/Alert/AlertOrderPrototypeTests.cs b/Content.Tests/Shared/Alert/AlertOrderPrototypeTests.cs index 56f76d46a92..efcd59acbbb 100644 --- a/Content.Tests/Shared/Alert/AlertOrderPrototypeTests.cs +++ b/Content.Tests/Shared/Alert/AlertOrderPrototypeTests.cs @@ -85,24 +85,24 @@ public void TestAlertOrderPrototype() var alerts = prototypeManager.EnumeratePrototypes<AlertPrototype>(); // ensure they sort according to our expected criteria - var expectedOrder = new List<AlertType>(); - expectedOrder.Add(AlertType.Handcuffed); - expectedOrder.Add(AlertType.Ensnared); - expectedOrder.Add(AlertType.HighPressure); + var expectedOrder = new List<string>(); + expectedOrder.Add("Handcuffed"); + expectedOrder.Add("Ensnared"); + expectedOrder.Add("HighPressure"); // stuff with only category + same category ordered by enum value - expectedOrder.Add(AlertType.Peckish); - expectedOrder.Add(AlertType.Hot); - expectedOrder.Add(AlertType.Stun); - expectedOrder.Add(AlertType.LowPressure); - expectedOrder.Add(AlertType.Cold); - // stuff at end of list ordered by enum value - expectedOrder.Add(AlertType.Weightless); - expectedOrder.Add(AlertType.PilotingShuttle); + expectedOrder.Add("Peckish"); + expectedOrder.Add("Hot"); + expectedOrder.Add("Stun"); + expectedOrder.Add("LowPressure"); + expectedOrder.Add("Cold"); + // stuff at end of list ordered by ID + expectedOrder.Add("PilotingShuttle"); + expectedOrder.Add("Weightless"); var actual = alerts.ToList(); actual.Sort(alertOrder); - Assert.That(actual.Select(a => a.AlertType).ToList(), Is.EqualTo(expectedOrder)); + Assert.That(actual.Select(a => a.ID).ToList(), Is.EqualTo(expectedOrder)); } } } diff --git a/Content.Tests/Shared/Alert/AlertPrototypeTests.cs b/Content.Tests/Shared/Alert/AlertPrototypeTests.cs index d95acb8aff4..43ae98b452b 100644 --- a/Content.Tests/Shared/Alert/AlertPrototypeTests.cs +++ b/Content.Tests/Shared/Alert/AlertPrototypeTests.cs @@ -39,9 +39,9 @@ public void OneTimeSetUp() [Test] public void TestAlertKey() { - Assert.That(new AlertKey(AlertType.HumanHealth, null), Is.Not.EqualTo(AlertKey.ForCategory(AlertCategory.Health))); - Assert.That((new AlertKey(null, AlertCategory.Health)), Is.EqualTo(AlertKey.ForCategory(AlertCategory.Health))); - Assert.That((new AlertKey(AlertType.Buckled, AlertCategory.Health)), Is.EqualTo(AlertKey.ForCategory(AlertCategory.Health))); + Assert.That(new AlertKey("HumanHealth", null), Is.Not.EqualTo(AlertKey.ForCategory("Health"))); + Assert.That((new AlertKey(null, "Health")), Is.EqualTo(AlertKey.ForCategory("Health"))); + Assert.That((new AlertKey("Buckled", "Health")), Is.EqualTo(AlertKey.ForCategory("Health"))); } [TestCase(0, "/Textures/Interface/Alerts/Human/human.rsi/human0.png")] diff --git a/Resources/ConfigPresets/EinsteinEngines/default.toml b/Resources/ConfigPresets/EinsteinEngines/default.toml index b5b8dbbf64e..ac50e57b9b6 100644 --- a/Resources/ConfigPresets/EinsteinEngines/default.toml +++ b/Resources/ConfigPresets/EinsteinEngines/default.toml @@ -41,8 +41,7 @@ limit = 10.0 fork_id = "EinsteinEngines" [server] -rules_file = "Rules.txt" -rules_header = "ui-rules-header" +rules_file = "DefaultRuleset" [ooc] enable_during_round = true diff --git a/Resources/Locale/en-US/guidebook/guides.ftl b/Resources/Locale/en-US/guidebook/guides.ftl index e2090d5af0a..ae564f16710 100644 --- a/Resources/Locale/en-US/guidebook/guides.ftl +++ b/Resources/Locale/en-US/guidebook/guides.ftl @@ -72,6 +72,61 @@ guide-entry-revolutionaries = Revolutionaries guide-entry-minor-antagonists = Minor Antagonists guide-entry-space-ninja = Space Ninja +guide-entry-rules = Server Rules +guide-entry-rules-core-only = Core Only Ruleset +guide-entry-rules-lrp = Standard Ruleset +guide-entry-rules-mrp = MRP Ruleset +guide-entry-rules-role-types = Role Types +guide-entry-rules-core = Core Rules +guide-entry-rules-c1 = C1 +guide-entry-rules-c2 = C2 +guide-entry-rules-c3 = C3 +guide-entry-rules-c4 = C4 +guide-entry-rules-c5 = C5 +guide-entry-rules-c6 = C6 +guide-entry-rules-c7 = C7 +guide-entry-rules-c8 = C8 +guide-entry-rules-c9 = C9 +guide-entry-rules-c10 = C10 +guide-entry-rules-c11 = C11 +guide-entry-rules-c12 = C12 +guide-entry-rules-c13 = C13 +guide-entry-rules-c14 = C14 +guide-entry-rules-roleplay = Roleplay Rules +guide-entry-rules-r1 = R1 +guide-entry-rules-r2 = R2 +guide-entry-rules-r3 = R3 +guide-entry-rules-r4 = R4 +guide-entry-rules-r5 = R5 +guide-entry-rules-r6 = R6 +guide-entry-rules-r7 = R7 +guide-entry-rules-r8 = R8 +guide-entry-rules-r9 = R9 +guide-entry-rules-r10 = R10 +guide-entry-rules-r11 = R11 +guide-entry-rules-r12 = R12 +guide-entry-rules-r13 = R13 +guide-entry-rules-r14 = R14 +guide-entry-rules-r15 = R15 +guide-entry-rules-silicon = Silicon Rules +guide-entry-rules-s1 = S1 +guide-entry-rules-s2 = S2 +guide-entry-rules-s3 = S3 +guide-entry-rules-s4 = S4 +guide-entry-rules-s5 = S5 +guide-entry-rules-s6 = S6 +guide-entry-rules-s7 = S7 +guide-entry-rules-s8 = S8 +guide-entry-rules-s9 = S9 +guide-entry-rules-s10 = S10 +guide-entry-rules-space-law = Space Law +guide-entry-rules-sl-crime-list = Crime List +guide-entry-rules-sl-controlled-substances = Controlled Substances +guide-entry-rules-sl-restricted-gear = Restricted Gear +guide-entry-rules-sl-restricted-weapons = Restricted Weapons +guide-entry-rules-ban-types = Ban Types +guide-entry-rules-ban-durations = Ban Durations + guide-entry-writing = Writing guide-entry-glossary = Glossary diff --git a/Resources/Locale/en-US/info/rules.ftl b/Resources/Locale/en-US/info/rules.ftl index 28791fd7ecb..8aa0b746b1d 100644 --- a/Resources/Locale/en-US/info/rules.ftl +++ b/Resources/Locale/en-US/info/rules.ftl @@ -3,3 +3,6 @@ ui-rules-header = Official Server Rules ui-rules-accept = I have read and agree to follow the rules ui-rules-wait = The accept button will be enabled after {$time} seconds. + +ui-rules-button-home = Home +ui-rules-button-back = Back diff --git a/Resources/Prototypes/Actions/borgs.yml b/Resources/Prototypes/Actions/borgs.yml index 6d35c69cf6a..950a7c81524 100644 --- a/Resources/Prototypes/Actions/borgs.yml +++ b/Resources/Prototypes/Actions/borgs.yml @@ -2,7 +2,7 @@ id: ActionViewLaws name: View Laws description: View the laws that you must follow. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: NoItem diff --git a/Resources/Prototypes/Actions/crit.yml b/Resources/Prototypes/Actions/crit.yml index 705ee6ee6b3..bc843796c47 100644 --- a/Resources/Prototypes/Actions/crit.yml +++ b/Resources/Prototypes/Actions/crit.yml @@ -3,7 +3,7 @@ id: ActionCritSuccumb name: Succumb description: Accept your fate. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: NoItem @@ -18,7 +18,7 @@ id: ActionCritFakeDeath name: Fake Death description: Pretend to take your final breath while staying alive. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: NoItem @@ -34,7 +34,7 @@ id: ActionCritLastWords name: Say Last Words description: Whisper your last words to anyone nearby, and then succumb to your fate. You only have 30 characters to work with. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: NoItem diff --git a/Resources/Prototypes/Actions/diona.yml b/Resources/Prototypes/Actions/diona.yml index 11db30386a5..695285a524d 100644 --- a/Resources/Prototypes/Actions/diona.yml +++ b/Resources/Prototypes/Actions/diona.yml @@ -2,7 +2,7 @@ id: DionaGibAction name: Gib Yourself! description: Split apart into 3 nymphs. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: @@ -16,7 +16,7 @@ id: DionaReformAction name: Reform description: Reform back into a whole Diona. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: diff --git a/Resources/Prototypes/Actions/internals.yml b/Resources/Prototypes/Actions/internals.yml index dd83a45332f..ebc29d2ebf0 100644 --- a/Resources/Prototypes/Actions/internals.yml +++ b/Resources/Prototypes/Actions/internals.yml @@ -2,7 +2,7 @@ id: ActionToggleInternals name: Toggle Internals description: Breathe from the equipped gas tank. Also requires equipped breath mask. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: diff --git a/Resources/Prototypes/Actions/mech.yml b/Resources/Prototypes/Actions/mech.yml index 2005133a70b..69ec71ba641 100644 --- a/Resources/Prototypes/Actions/mech.yml +++ b/Resources/Prototypes/Actions/mech.yml @@ -2,7 +2,7 @@ id: ActionMechCycleEquipment name: Cycle description: Cycles currently selected equipment - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: NoItem @@ -16,7 +16,7 @@ id: ActionMechOpenUI name: Control Panel description: Opens the control panel for the mech - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: NoItem @@ -30,7 +30,7 @@ id: ActionMechEject name: Eject description: Ejects the pilot from the mech - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: NoItem diff --git a/Resources/Prototypes/Actions/misc.yml b/Resources/Prototypes/Actions/misc.yml index 60fec699210..1a8d3458dde 100644 --- a/Resources/Prototypes/Actions/misc.yml +++ b/Resources/Prototypes/Actions/misc.yml @@ -2,7 +2,7 @@ id: ActionCancelEscape name: Stop escaping description: Calm down and sit peacefuly in your carrier's inventory - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Actions/escapeinventory.rsi/cancel-escape.png diff --git a/Resources/Prototypes/Actions/ninja.yml b/Resources/Prototypes/Actions/ninja.yml index 5fe6f23b276..51bfc33c494 100644 --- a/Resources/Prototypes/Actions/ninja.yml +++ b/Resources/Prototypes/Actions/ninja.yml @@ -3,7 +3,7 @@ id: ActionToggleNinjaGloves name: Toggle ninja gloves description: Toggles all glove actions on left click. Includes your doorjack, draining power, stunning enemies, downloading research and calling in a threat. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction priority: -13 @@ -14,7 +14,7 @@ id: ActionCreateThrowingStar name: Create throwing star description: Channels suit power into creating a throwing star that deals extra stamina damage. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 0.5 @@ -29,7 +29,7 @@ id: ActionRecallKatana name: Recall katana description: Teleports the Energy Katana linked to this suit to its wearer, cost based on distance. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 1 @@ -44,7 +44,7 @@ id: ActionNinjaEmp name: EM Burst description: Disable any nearby technology with an electro-magnetic pulse. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: @@ -58,7 +58,7 @@ id: ActionTogglePhaseCloak name: Phase cloak description: Toggles your suit's phase cloak. Beware that if you are hit, all abilities are disabled for 5 seconds, including your cloak! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction # have to plan (un)cloaking ahead of time @@ -71,7 +71,7 @@ id: ActionEnergyKatanaDash name: Katana dash description: Teleport to anywhere you can see, if your Energy Katana is in your hand. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WorldTargetAction icon: diff --git a/Resources/Prototypes/Actions/polymorph.yml b/Resources/Prototypes/Actions/polymorph.yml index 445dc8d9f54..de082ead8a4 100644 --- a/Resources/Prototypes/Actions/polymorph.yml +++ b/Resources/Prototypes/Actions/polymorph.yml @@ -2,14 +2,14 @@ id: ActionRevertPolymorph name: Revert description: Revert back into your original form. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction event: !type:RevertPolymorphActionEvent - type: entity id: ActionPolymorph - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction event: !type:PolymorphActionEvent @@ -19,7 +19,7 @@ id: ActionPolymorphWizardSpider name: Spider Polymorph description: Polymorphs you into a Spider. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 60 @@ -34,7 +34,7 @@ id: ActionPolymorphWizardRod name: Rod Form description: CLANG! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 60 diff --git a/Resources/Prototypes/Actions/psionics.yml b/Resources/Prototypes/Actions/psionics.yml index a372a480ac7..c5df4f70ad0 100644 --- a/Resources/Prototypes/Actions/psionics.yml +++ b/Resources/Prototypes/Actions/psionics.yml @@ -2,7 +2,7 @@ id: ActionDispel name: action-name-dispel description: action-description-dispel - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntityTargetAction icon: Interface/VerbIcons/dispel.png @@ -21,7 +21,7 @@ id: ActionMassSleep name: action-name-mass-sleep description: action-description-mass-sleep - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WorldTargetAction icon: Interface/VerbIcons/mass_sleep.png @@ -35,7 +35,7 @@ id: ActionMindSwap name: action-name-mind-swap description: action-description-mind-swap - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntityTargetAction icon: Interface/VerbIcons/mind_swap.png @@ -53,7 +53,7 @@ id: ActionMindSwapReturn name: action-name-mind-swap-return description: action-description-mind-swap-return - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/VerbIcons/mind_swap_return.png @@ -65,7 +65,7 @@ id: ActionNoosphericZap name: action-name-noospheric-zap description: action-description-noospheric-zap - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntityTargetAction icon: Interface/VerbIcons/noospheric_zap.png @@ -82,7 +82,7 @@ id: ActionPyrokinesis name: action-name-pyrokinesis description: action-description-pyrokinesis - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntityTargetAction icon: Interface/VerbIcons/pyrokinesis.png @@ -96,7 +96,7 @@ id: ActionMetapsionic name: action-name-metapsionic description: action-description-metapsionic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/VerbIcons/metapsionic.png @@ -107,7 +107,7 @@ id: ActionPsionicRegeneration name: action-name-psionic-regeneration description: action-description-psionic-regeneration - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/VerbIcons/psionic_regeneration.png @@ -118,7 +118,7 @@ id: ActionTelegnosis name: action-name-telegnosis description: action-description-telegnosis - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/VerbIcons/telegnosis.png @@ -129,7 +129,7 @@ id: ActionPsionicInvisibility name: action-name-psionic-invisibility description: action-description-psionic-invisibility - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/VerbIcons/psionic_invisibility.png @@ -140,7 +140,7 @@ id: ActionPsionicInvisibilityUsed name: action-name-psionic-invisibility-off description: action-description-psionic-invisibility-off - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/VerbIcons/psionic_invisibility_off.png @@ -150,7 +150,7 @@ id: ActionHealingWord name: action-name-healing-word description: action-description-healing-word - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntityTargetAction icon: { sprite: Interface/Actions/psionics.rsi, state: healing_word } @@ -187,7 +187,7 @@ id: ActionRevivify name: action-name-revivify description: action-description-revivify - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntityTargetAction icon: { sprite: Interface/Actions/psionics.rsi, state: revivify } @@ -226,7 +226,7 @@ id: ActionShadeskip name: action-name-shadeskip description: action-description-shadeskip - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite : Interface/Actions/psionics.rsi, state: shadeskip } @@ -261,7 +261,7 @@ id: ActionTelekineticPulse name: action-name-telekinetic-pulse description: action-description-telekinetic-pulse - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Interface/Actions/psionics.rsi, state: telekinetic_pulse } @@ -295,7 +295,7 @@ id: ActionShadowkinShadeskip name: action-name-shadeskip description: action-description-shadowkin-shadeskip - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Interface/Actions/shadowkin_icons.rsi, state: shadeskip } @@ -329,7 +329,7 @@ id: ActionDarkSwap name: action-name-darkswap description: action-description-darkswap - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Interface/Actions/shadowkin_icons.rsi, state: darkswap } @@ -343,7 +343,7 @@ id: ActionPyrokineticFlare name: action-name-pyrokinetic-flare description: action-description-pyrokinetic-flare - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Interface/Actions/psionics.rsi, state: pyrokinetic_flare } @@ -369,7 +369,7 @@ id: ActionSummonImp name: action-name-summon-imp description: action-description-summon-imp - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Interface/Actions/psionics.rsi, state: summon_imp } @@ -388,7 +388,7 @@ id: ActionSummonRemilia name: action-name-summon-remilia description: action-description-summon-remilia - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Interface/Actions/psionics.rsi, state: summon_remilia } diff --git a/Resources/Prototypes/Actions/revenant.yml b/Resources/Prototypes/Actions/revenant.yml index da7b4ba56f2..1131ae2eadb 100644 --- a/Resources/Prototypes/Actions/revenant.yml +++ b/Resources/Prototypes/Actions/revenant.yml @@ -2,7 +2,7 @@ id: ActionRevenantShop name: Shop description: Opens the ability shop. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/Actions/shop.png @@ -12,7 +12,7 @@ id: ActionRevenantDefile name: Defile description: Costs 30 Essence. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/Actions/defile.png @@ -23,7 +23,7 @@ id: ActionRevenantOverloadLights name: Overload Lights description: Costs 40 Essence. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/Actions/overloadlight.png @@ -34,7 +34,7 @@ # id: ActionRevenantBlight # name: Blight # description: Costs 50 Essence. -# noSpawn: true +# categories: [ HideSpawnMenu ] # components: # - type: InstantAction # icon: Interface/Actions/blight.png @@ -45,7 +45,7 @@ id: ActionRevenantMalfunction name: Malfunction description: Costs 60 Essence. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/Actions/malfunction.png diff --git a/Resources/Prototypes/Actions/speech.yml b/Resources/Prototypes/Actions/speech.yml index 39db04b1b31..053322904f4 100644 --- a/Resources/Prototypes/Actions/speech.yml +++ b/Resources/Prototypes/Actions/speech.yml @@ -2,7 +2,7 @@ id: ActionConfigureMeleeSpeech name: Set Battlecry description: Set a custom battlecry for when you attack! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: BigItem diff --git a/Resources/Prototypes/Actions/spider.yml b/Resources/Prototypes/Actions/spider.yml index 14b9fb6ccbb..3139d416dc6 100644 --- a/Resources/Prototypes/Actions/spider.yml +++ b/Resources/Prototypes/Actions/spider.yml @@ -2,7 +2,7 @@ id: ActionSpiderWeb name: Spider Web description: Spawns a web that slows your prey down. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/Actions/web.png @@ -13,7 +13,7 @@ id: ActionSericulture name: Weave silk description: Weave a bit of silk for use in arts and crafts. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/Actions/web.png diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml index a7144cdda57..f69d6a794a3 100644 --- a/Resources/Prototypes/Actions/types.yml +++ b/Resources/Prototypes/Actions/types.yml @@ -13,7 +13,7 @@ id: ActionScream name: Scream description: AAAAAAAAAAAAAAAAAAAAAAAAA - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 10 @@ -25,7 +25,7 @@ id: ActionTurnUndead name: Turn Undead description: Succumb to your infection and become a zombie. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false @@ -37,7 +37,7 @@ id: ActionToggleLight name: Toggle Light description: Turn the light on and off. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Objects/Tools/flashlight.rsi, state: flashlight } @@ -48,7 +48,7 @@ id: ActionOpenStorageImplant name: Open Storage Implant description: Opens the storage implant embedded under your skin - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: BigAction @@ -63,7 +63,7 @@ id: ActionActivateMicroBomb name: Activate Microbomb description: Activates your internal microbomb, completely destroying you and your equipment - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false @@ -80,7 +80,7 @@ id: ActionActivateDeathAcidifier name: Activate Death-Acidifier description: Activates your death-acidifier, completely melting you and your equipment - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false @@ -96,7 +96,7 @@ id: ActionActivateFreedomImplant name: Break Free description: Activating your freedom implant will free you from any hand restraints - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction charges: 3 @@ -112,7 +112,7 @@ id: ActionOpenUplinkImplant name: Open Uplink description: Opens the syndicate uplink embedded under your skin - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: BigAction @@ -126,7 +126,7 @@ id: ActionActivateEmpImplant name: Activate EMP description: Triggers a small EMP pulse around you - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false @@ -143,7 +143,7 @@ id: ActionActivateScramImplant name: SCRAM! description: Randomly teleports you within a large distance. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false @@ -160,7 +160,7 @@ id: ActionActivateDnaScramblerImplant name: Scramble DNA description: Randomly changes your name and appearance. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction charges: 1 @@ -175,7 +175,7 @@ id: ActionMorphGeras name: Morph into Geras description: Morphs you into a Geras - a miniature version of you which allows you to move fast, at the cost of your inventory. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: BigAction @@ -190,7 +190,7 @@ id: ActionToggleSuitPiece name: Toggle Suit Piece description: Remember to equip the important pieces of your suit before going into action. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: BigItem @@ -201,7 +201,7 @@ id: ActionCombatModeToggle name: "[color=red]Combat Mode[/color]" description: Enter combat mode - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false @@ -216,7 +216,7 @@ parent: ActionCombatModeToggle name: "[color=red]Combat Mode[/color]" description: Enter combat mode - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction enabled: false @@ -227,7 +227,7 @@ id: ActionChangeVoiceMask name: Set name description: Change the name others hear to something else. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Interface/Actions/voice-mask.rsi, state: icon } @@ -237,7 +237,7 @@ id: ActionVendingThrow name: Dispense Item description: Randomly dispense an item from your stock. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 30 @@ -247,7 +247,7 @@ id: ActionArtifactActivate name: Activate Artifact description: Immediately activates your current artifact node. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: @@ -260,7 +260,7 @@ id: ActionToggleBlock name: Block description: Raise or lower your shield. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Objects/Weapons/Melee/shields.rsi, state: teleriot-icon } @@ -271,7 +271,7 @@ id: ActionClearNetworkLinkOverlays name: Clear network link overlays description: Clear network link overlays. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction clientExclusive: true @@ -285,7 +285,7 @@ id: ActionAnimalLayEgg name: Lay egg description: Uses hunger to lay an egg. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Objects/Consumable/Food/egg.rsi, state: icon } @@ -296,7 +296,7 @@ id: ActionSleep name: Sleep description: Go to sleep. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false @@ -308,7 +308,7 @@ id: ShadowkinActionSleep name: action-name-shadowkin-rest description: action-description-shadowkin-rest - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false @@ -320,7 +320,7 @@ id: ActionWake name: Wake up description: Stop sleeping. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Clothing/Head/Hats/pyjamasyndicatered.rsi, state: icon } @@ -332,7 +332,7 @@ id: ActionActivateHonkImplant name: Honk description: Activates your honking implant, which will produce the signature sound of the clown. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Objects/Fun/bikehorn.rsi, state: icon } @@ -343,7 +343,7 @@ id: ActionFireStarter name: Ignite description: Ignites enemies in a radius around you. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction priority: -1 @@ -355,7 +355,7 @@ id: ActionToggleEyes name: Open/Close eyes description: Close your eyes to protect your peepers, or open your eyes to enjoy the pretty lights. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/Actions/eyeopen.png @@ -369,7 +369,7 @@ id: ActionToggleWagging name: action-name-toggle-wagging description: action-description-toggle-wagging - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Interface/Actions/wagging.rsi, state: icon } @@ -382,7 +382,7 @@ id: ActionFabricateLollipop name: action-name-fabricate-lollipop description: action-description-fabricate-lollipop - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Nyanotrasen/Objects/Consumable/Food/candy.rsi, state: lollipop } @@ -395,7 +395,7 @@ id: ActionFabricateGumball name: action-name-fabricate-gumball description: action-description-fabricate-gumball - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Nyanotrasen/Objects/Consumable/Food/candy.rsi, state: gumball } diff --git a/Resources/Prototypes/Alerts/categories.yml b/Resources/Prototypes/Alerts/categories.yml new file mode 100644 index 00000000000..1e79d2615bb --- /dev/null +++ b/Resources/Prototypes/Alerts/categories.yml @@ -0,0 +1,38 @@ +- type: alertCategory + id: Pressure + +- type: alertCategory + id: Temperature + +- type: alertCategory + id: Breathing + +- type: alertCategory + id: Buckled + +- type: alertCategory + id: Health + +- type: alertCategory + id: Internals + +- type: alertCategory + id: Stamina + +- type: alertCategory + id: Piloting + +- type: alertCategory + id: Hunger + +- type: alertCategory + id: Thirst + +- type: alertCategory + id: Toxins + +- type: alertCategory + id: Battery + +- type: alertCategory + id: Mood diff --git a/Resources/Prototypes/Body/Organs/Animal/animal.yml b/Resources/Prototypes/Body/Organs/Animal/animal.yml index 2f50821df35..44369ffe73c 100644 --- a/Resources/Prototypes/Body/Organs/Animal/animal.yml +++ b/Resources/Prototypes/Body/Organs/Animal/animal.yml @@ -34,7 +34,7 @@ id: OrganAnimalLungs parent: BaseAnimalOrgan name: lungs - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: @@ -65,7 +65,7 @@ id: OrganAnimalStomach parent: BaseAnimalOrgan name: stomach - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: stomach @@ -91,7 +91,7 @@ id: OrganMouseStomach parent: OrganAnimalStomach name: stomach - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SolutionContainerManager solutions: @@ -102,7 +102,7 @@ id: OrganAnimalLiver parent: BaseAnimalOrgan name: liver - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: liver @@ -118,7 +118,7 @@ id: OrganAnimalHeart parent: BaseAnimalOrgan name: heart - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: heart-on @@ -135,7 +135,7 @@ id: OrganAnimalKidneys parent: BaseAnimalOrgan name: kidneys - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: diff --git a/Resources/Prototypes/Body/Organs/Animal/bloodsucker.yml b/Resources/Prototypes/Body/Organs/Animal/bloodsucker.yml index 8a1afc37bb1..10cf620addc 100644 --- a/Resources/Prototypes/Body/Organs/Animal/bloodsucker.yml +++ b/Resources/Prototypes/Body/Organs/Animal/bloodsucker.yml @@ -2,7 +2,7 @@ id: OrganBloodsuckerStomach parent: OrganAnimalStomach name: stomach - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Metabolizer metabolizerTypes: [ Bloodsucker ] @@ -11,7 +11,7 @@ id: OrganBloodsuckerLiver parent: OrganAnimalLiver name: liver - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Metabolizer metabolizerTypes: [ Bloodsucker ] @@ -20,7 +20,7 @@ id: OrganBloodsuckerHeart parent: OrganAnimalHeart name: heart - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Metabolizer metabolizerTypes: [ Bloodsucker ] diff --git a/Resources/Prototypes/Body/Organs/Animal/ruminant.yml b/Resources/Prototypes/Body/Organs/Animal/ruminant.yml index 3c3062ddec0..6bd7c2d4024 100644 --- a/Resources/Prototypes/Body/Organs/Animal/ruminant.yml +++ b/Resources/Prototypes/Body/Organs/Animal/ruminant.yml @@ -2,7 +2,7 @@ id: OrganAnimalRuminantStomach parent: OrganAnimalStomach name: ruminant stomach - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SolutionContainerManager solutions: diff --git a/Resources/Prototypes/Body/Organs/Friendstomach.yml b/Resources/Prototypes/Body/Organs/Friendstomach.yml index a20bbbe75bc..8dc992b08fb 100644 --- a/Resources/Prototypes/Body/Organs/Friendstomach.yml +++ b/Resources/Prototypes/Body/Organs/Friendstomach.yml @@ -1,7 +1,7 @@ - type: entity id: OrganFriendStomach parent: OrganAnimalStomach - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Stomach - type: SolutionContainerManager diff --git a/Resources/Prototypes/Body/Organs/arachnid.yml b/Resources/Prototypes/Body/Organs/arachnid.yml index c1e199e1121..29ca393d137 100644 --- a/Resources/Prototypes/Body/Organs/arachnid.yml +++ b/Resources/Prototypes/Body/Organs/arachnid.yml @@ -105,7 +105,7 @@ parent: BaseHumanOrgan name: liver description: "Pairing suggestion: chianti and fava beans." - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: liver @@ -122,7 +122,7 @@ parent: BaseHumanOrgan name: kidneys description: "Filters toxins from the bloodstream." - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: diff --git a/Resources/Prototypes/Body/Organs/diona.yml b/Resources/Prototypes/Body/Organs/diona.yml index a2133f7f90a..6442ff3ee22 100644 --- a/Resources/Prototypes/Body/Organs/diona.yml +++ b/Resources/Prototypes/Body/Organs/diona.yml @@ -127,7 +127,7 @@ - type: entity id: OrganDionaBrainNymph parent: OrganDionaBrain - noSpawn: true + categories: [ HideSpawnMenu ] name: brain description: "The source of incredible, unending intelligence. Honk." components: @@ -139,7 +139,7 @@ - type: entity id: OrganDionaStomachNymph parent: OrganDionaStomach - noSpawn: true + categories: [ HideSpawnMenu ] name: stomach description: "Gross. This is hard to stomach." components: @@ -149,7 +149,7 @@ - type: entity id: OrganDionaLungsNymph parent: OrganDionaLungs - noSpawn: true + categories: [ HideSpawnMenu ] name: lungs description: "Filters oxygen from an atmosphere, which is then sent into the bloodstream to be used as an electron carrier." components: @@ -160,7 +160,7 @@ - type: entity id: OrganDionaNymphBrain parent: MobDionaNymph - noSpawn: true + categories: [ HideSpawnMenu ] name: diona nymph suffix: Brain description: Contains the brain of a formerly fully-formed Diona. Killing this would kill the Diona forever. You monster. @@ -172,7 +172,7 @@ - type: entity id: OrganDionaNymphStomach parent: MobDionaNymphAccent - noSpawn: true + categories: [ HideSpawnMenu ] name: diona nymph suffix: Stomach description: Contains the stomach of a formerly fully-formed Diona. It doesn't taste any better for it. @@ -184,7 +184,7 @@ - type: entity id: OrganDionaNymphLungs parent: MobDionaNymphAccent - noSpawn: true + categories: [ HideSpawnMenu ] name: diona nymph suffix: Lungs description: Contains the lungs of a formerly fully-formed Diona. Breathtaking. diff --git a/Resources/Prototypes/Body/Organs/moth.yml b/Resources/Prototypes/Body/Organs/moth.yml index 9b94e77b7eb..d1c9c164f02 100644 --- a/Resources/Prototypes/Body/Organs/moth.yml +++ b/Resources/Prototypes/Body/Organs/moth.yml @@ -1,7 +1,7 @@ - type: entity id: OrganMothStomach parent: [OrganAnimalStomach, OrganHumanStomach] - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Stomach specialDigestible: diff --git a/Resources/Prototypes/Body/Organs/reptilian.yml b/Resources/Prototypes/Body/Organs/reptilian.yml index f8423582cc2..34c736aec8b 100644 --- a/Resources/Prototypes/Body/Organs/reptilian.yml +++ b/Resources/Prototypes/Body/Organs/reptilian.yml @@ -1,7 +1,7 @@ - type: entity id: OrganReptilianStomach parent: OrganAnimalStomach - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Stomach specialDigestible: diff --git a/Resources/Prototypes/Body/Parts/animal.yml b/Resources/Prototypes/Body/Parts/animal.yml index 76eaf79812f..abd34c0ef5a 100644 --- a/Resources/Prototypes/Body/Parts/animal.yml +++ b/Resources/Prototypes/Body/Parts/animal.yml @@ -36,7 +36,7 @@ id: HandsAnimal name: animal hands parent: PartAnimal - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: @@ -50,7 +50,7 @@ id: LegsAnimal name: animal legs parent: PartAnimal - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: @@ -64,7 +64,7 @@ id: FeetAnimal name: animal feet parent: PartAnimal - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: @@ -77,7 +77,7 @@ id: TorsoAnimal name: animal torso parent: PartAnimal - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: diff --git a/Resources/Prototypes/Body/Parts/rat.yml b/Resources/Prototypes/Body/Parts/rat.yml index 6a66eecc489..bd51e006f70 100644 --- a/Resources/Prototypes/Body/Parts/rat.yml +++ b/Resources/Prototypes/Body/Parts/rat.yml @@ -4,7 +4,7 @@ id: TorsoRat name: "animal torso" parent: PartAnimal - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: BodyPart partType: Torso diff --git a/Resources/Prototypes/Body/Parts/silicon.yml b/Resources/Prototypes/Body/Parts/silicon.yml index 24d88276ccb..57cd1f02cf4 100644 --- a/Resources/Prototypes/Body/Parts/silicon.yml +++ b/Resources/Prototypes/Body/Parts/silicon.yml @@ -105,4 +105,4 @@ partType: Torso - type: Tag tags: - - Trash + - Trash \ No newline at end of file diff --git a/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/backpack.yml b/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/backpack.yml index da46ae75979..d66fb5d38b1 100644 --- a/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/backpack.yml +++ b/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/backpack.yml @@ -1,10 +1,10 @@ - type: entity parent: ClothingBackpack id: ClothingBackpackFilled - noSpawn: true + categories: [ HideSpawnMenu ] - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackClown id: ClothingBackpackClownFilled components: @@ -15,7 +15,7 @@ - id: CrayonRainbow - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSecurity id: ClothingBackpackSecurityFilled components: @@ -24,7 +24,7 @@ - id: MagazinePistol - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackBrigmedic id: ClothingBackpackBrigmedicFilled components: @@ -40,7 +40,7 @@ - id: MagazinePistol - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSecurity id: ClothingBackpackSecurityFilledDetective components: @@ -52,12 +52,12 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackMedical id: ClothingBackpackMedicalFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackMedical id: ClothingBackpackParamedicFilled components: @@ -66,7 +66,7 @@ - id: EmergencyRollerBedSpawnFolded - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackCaptain id: ClothingBackpackCaptainFilled components: @@ -76,7 +76,7 @@ #- name: StationCharter #- name: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackEngineering id: ClothingBackpackChiefEngineerFilled components: @@ -86,7 +86,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackScience id: ClothingBackpackResearchDirectorFilled components: @@ -96,7 +96,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpack id: ClothingBackpackHOPFilled components: @@ -106,7 +106,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackMedical id: ClothingBackpackCMOFilled components: @@ -116,7 +116,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackCargo id: ClothingBackpackQuartermasterFilled components: @@ -126,7 +126,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSecurity id: ClothingBackpackHOSFilled components: @@ -136,32 +136,32 @@ - id: MagazinePistol - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackEngineering id: ClothingBackpackEngineeringFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackAtmospherics id: ClothingBackpackAtmosphericsFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackScience id: ClothingBackpackScienceFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackRobotics id: ClothingBackpackRoboticsFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackHydroponics id: ClothingBackpackHydroponicsFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackMime id: ClothingBackpackMimeFilled components: @@ -170,22 +170,22 @@ - id: RubberStampMime - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackChemistry id: ClothingBackpackChemistryFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpack id: ClothingBackpackChaplainFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpack id: ClothingBackpackMusicianFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpack id: ClothingBackpackLibrarianFilled components: @@ -194,7 +194,7 @@ - id: BookRandom - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpack id: ClothingBackpackDetectiveFilled components: @@ -208,7 +208,7 @@ # ERT - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackERTLeader id: ClothingBackpackERTLeaderFilled components: @@ -223,7 +223,7 @@ - id: MagazineMagnum - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackERTSecurity id: ClothingBackpackERTSecurityFilled components: @@ -238,7 +238,7 @@ - id: MagazinePistol - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackERTMedical id: ClothingBackpackERTMedicalFilled components: @@ -253,7 +253,7 @@ - id: EpinephrineChemistryBottle - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackERTEngineer id: ClothingBackpackERTEngineerFilled components: @@ -272,7 +272,7 @@ - id: SheetGlass - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackERTJanitor id: ClothingBackpackERTJanitorFilled components: @@ -287,7 +287,7 @@ - id: AdvMopItem - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackERTChaplain id: ClothingBackpackERTChaplainFilled components: @@ -310,7 +310,6 @@ # Death Squad - type: entity - noSpawn: false parent: ClothingBackpackERTSecurity id: ClothingBackpackDeathSquadFilled name: death squad backpack @@ -337,12 +336,12 @@ # Cargo - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackCargo id: ClothingBackpackCargoFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSalvage id: ClothingBackpackSalvageFilled diff --git a/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml b/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml index 07cbbeb6caa..525a4a13cec 100644 --- a/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml +++ b/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml @@ -1,10 +1,10 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffel id: ClothingBackpackDuffelFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelClown id: ClothingBackpackDuffelClownFilled components: @@ -13,7 +13,7 @@ - id: RubberStampClown - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelBrigmedic id: ClothingBackpackDuffelBrigmedicFilled components: @@ -29,7 +29,7 @@ amount: 2 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelSecurity id: ClothingBackpackDuffelSecurityFilled components: @@ -38,7 +38,7 @@ - id: MagazinePistol - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelSecurity id: ClothingBackpackDuffelSecurityFilledDetective components: @@ -48,12 +48,12 @@ - id: ForensicScanner - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelMedical id: ClothingBackpackDuffelMedicalFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelMedical id: ClothingBackpackDuffelParamedicFilled components: @@ -62,7 +62,7 @@ - id: EmergencyRollerBedSpawnFolded - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelCaptain id: ClothingBackpackDuffelCaptainFilled components: @@ -73,7 +73,7 @@ #- name: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelEngineering id: ClothingBackpackDuffelChiefEngineerFilled components: @@ -83,7 +83,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelScience id: ClothingBackpackDuffelResearchDirectorFilled components: @@ -93,7 +93,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffel id: ClothingBackpackDuffelHOPFilled components: @@ -103,7 +103,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelMedical id: ClothingBackpackDuffelCMOFilled components: @@ -113,7 +113,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelCargo id: ClothingBackpackDuffelQuartermasterFilled components: @@ -123,7 +123,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelSecurity id: ClothingBackpackDuffelHOSFilled components: @@ -133,32 +133,32 @@ - id: MagazinePistol - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelEngineering id: ClothingBackpackDuffelEngineeringFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelAtmospherics id: ClothingBackpackDuffelAtmosphericsFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelScience id: ClothingBackpackDuffelScienceFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelRobotics id: ClothingBackpackDuffelRoboticsFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelHydroponics id: ClothingBackpackDuffelHydroponicsFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelMime id: ClothingBackpackDuffelMimeFilled components: @@ -167,12 +167,12 @@ - id: RubberStampMime - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelChemistry id: ClothingBackpackDuffelChemistryFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffel id: ClothingBackpackDuffelChaplainFilled components: @@ -182,7 +182,7 @@ - id: RubberStampChaplain - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffel id: ClothingBackpackDuffelMusicianFilled components: @@ -192,7 +192,7 @@ - id: SaxophoneInstrument - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffel id: ClothingBackpackDuffelLibrarianFilled components: @@ -201,7 +201,7 @@ - id: BookRandom - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffel id: ClothingBackpackDuffelDetectiveFilled components: @@ -213,11 +213,11 @@ - id: HandLabeler - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelCargo id: ClothingBackpackDuffelCargoFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelSalvage id: ClothingBackpackDuffelSalvageFilled diff --git a/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/satchel.yml b/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/satchel.yml index e20e27e55ca..7854b34c8e7 100644 --- a/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/satchel.yml +++ b/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/satchel.yml @@ -1,10 +1,10 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchel id: ClothingBackpackSatchelFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchel id: ClothingBackpackSatchelTools components: @@ -27,7 +27,7 @@ - id: RubberStampClown - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelBrigmedic id: ClothingBackpackSatchelBrigmedicFilled components: @@ -42,7 +42,7 @@ amount: 2 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelSecurity id: ClothingBackpackSatchelSecurityFilled components: @@ -51,7 +51,7 @@ - id: MagazinePistol - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelSecurity id: ClothingBackpackSatchelSecurityFilledDetective components: @@ -61,12 +61,12 @@ - id: ForensicScanner - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelMedical id: ClothingBackpackSatchelMedicalFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelMedical id: ClothingBackpackSatchelParamedicFilled components: @@ -75,7 +75,7 @@ - id: EmergencyRollerBedSpawnFolded - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelCaptain id: ClothingBackpackSatchelCaptainFilled components: @@ -86,7 +86,7 @@ #- name: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelEngineering id: ClothingBackpackSatchelChiefEngineerFilled components: @@ -96,7 +96,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelScience id: ClothingBackpackSatchelResearchDirectorFilled components: @@ -106,7 +106,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchel id: ClothingBackpackSatchelHOPFilled components: @@ -116,7 +116,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelMedical id: ClothingBackpackSatchelCMOFilled components: @@ -126,7 +126,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelCargo id: ClothingBackpackSatchelQuartermasterFilled components: @@ -136,7 +136,7 @@ #- id: TelescopicBaton - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelSecurity id: ClothingBackpackSatchelHOSFilled components: @@ -146,37 +146,37 @@ - id: MagazinePistol - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelEngineering id: ClothingBackpackSatchelEngineeringFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelAtmospherics id: ClothingBackpackSatchelAtmosphericsFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelScience id: ClothingBackpackSatchelScienceFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelRobotics id: ClothingBackpackSatchelRoboticsFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelHydroponics id: ClothingBackpackSatchelHydroponicsFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelChemistry id: ClothingBackpackSatchelChemistryFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchel id: ClothingBackpackSatchelChaplainFilled components: @@ -186,7 +186,7 @@ - id: RubberStampChaplain - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchel id: ClothingBackpackSatchelMusicianFilled components: @@ -196,7 +196,7 @@ - id: SaxophoneInstrument - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchel id: ClothingBackpackSatchelLibrarianFilled components: @@ -205,7 +205,7 @@ - id: BookRandom - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchel id: ClothingBackpackSatchelDetectiveFilled components: @@ -217,17 +217,17 @@ - id: HandLabeler - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelCargo id: ClothingBackpackSatchelCargoFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelSalvage id: ClothingBackpackSatchelSalvageFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelMime id: ClothingBackpackSatchelMimeFilled components: @@ -236,7 +236,7 @@ - id: RubberStampMime - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelHolding id: ClothingBackpackSatchelHoldingAdmin components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/fun.yml b/Resources/Prototypes/Catalog/Fills/Crates/fun.yml index a6f12bc727e..4805651fda9 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/fun.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/fun.yml @@ -1,3 +1,101 @@ +- type: entityTable + id: AllPlushiesTable + table: !type:GroupSelector + children: + - !type:EntSelector + id: PlushieBee + - !type:EntSelector + id: PlushieNar + weight: 0.5 + - !type:EntSelector + id: PlushieRatvar + weight: 0.5 + - !type:EntSelector + id: PlushieNuke + - !type:EntSelector + id: PlushieSlime + - !type:EntSelector + id: PlushieSnake + - !type:GroupSelector + children: + - !type:EntSelector + id: PlushieLizard + weight: 9 + - !type:EntSelector + id: PlushieSpaceLizard + weight: 1 + - !type:GroupSelector + children: + - !type:EntSelector + id: PlushieCarp + - !type:EntSelector + id: PlushieHolocarp + weight: 0.25 + - !type:EntSelector + id: PlushieMagicarp + weight: 0.25 + - !type:EntSelector + id: PlushieRainbowCarp + weight: 0.15 + - !type:EntSelector + id: PlushieVox + - !type:EntSelector + id: PlushieRouny + - !type:GroupSelector + children: + - !type:EntSelector + id: PlushieSharkBlue + - !type:EntSelector + id: PlushieSharkGrey + - !type:EntSelector + id: PlushieSharkPink + - !type:EntSelector + id: PlushieAtmosian + - !type:EntSelector + id: PlushieDiona + - !type:EntSelector + id: PlushieXeno + - !type:EntSelector + id: PlushieHampter + - !type:EntSelector + id: PlushieMoth + - !type:EntSelector + id: PlushieArachind + - !type:EntSelector + id: PlushiePenguin + +- type: entity + id: CrateFunPlushie + parent: CrateGenericSteel + name: plushie crate + description: A buncha soft plushies. Throw them around and then wonder how you're gonna explain this purchase to NT. + components: + - type: EntityTableContainerFill + containers: + entity_storage: !type:NestedSelector + tableId: AllPlushiesTable + rolls: !type:ConstantNumberSelector + value: 10 + +- type: entity + id: CrateFunLizardPlushieBulk + parent: CrateGenericSteel + name: bulk lizard plushie crate + description: A buncha soft lizard plushies. Throw them around and then wonder how you're gonna explain this purchase to NT. + components: + - type: EntityTableContainerFill + containers: + entity_storage: !type:AllSelector + children: + - !type:EntSelector + id: PlushieLizard + amount: !type:ConstantNumberSelector + value: 3 + - !type:EntSelector + id: PlushieSpaceLizard + amount: !type:ConstantNumberSelector + value: 3 + - type: entity id: CrateFunInstrumentsVariety parent: CrateGenericSteel diff --git a/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml b/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml index c1168f68d42..7313de7700b 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml @@ -28,7 +28,7 @@ - type: entity id: CrateSalvageAssortedGoodies suffix: Filled, Salvage Random - noSpawn: true # You should use SalvageMaterialCrateSpawner instead + categories: [ HideSpawnMenu ] # You should use SalvageMaterialCrateSpawner instead parent: CrateGenericSteel components: - type: StorageFill diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml b/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml index feaedd924a0..052ce95be2f 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml @@ -3,323 +3,236 @@ suffix: Filled parent: LockerSyndicatePersonal components: - - type: StorageFill - contents: - - id: ClothingBeltMilitaryWebbing - - id: ClothingHandsGlovesCombat - - id: JetpackBlackFilled - - id: ClothingUniformJumpsuitOperative - - id: ClothingUniformJumpskirtOperative - - id: ClothingHeadsetAltSyndicate - - id: ClothingEyesHudSyndicate + - type: EntityTableContainerFill + containers: + entity_storage: !type:AllSelector + children: + - !type:EntSelector + id: ClothingBeltMilitaryWebbing + - !type:EntSelector + id: ClothingHandsGlovesCombat + - !type:EntSelector + id: JetpackBlackFilled + - !type:EntSelector + id: ClothingUniformJumpsuitOperative + - !type:EntSelector + id: ClothingUniformJumpskirtOperative + - !type:EntSelector + id: ClothingHeadsetAltSyndicate + - !type:EntSelector + id: ClothingEyesHudSyndicate + +- type: entityTable + id: FillLockerEmergencyStandard + table: !type:AllSelector + children: + - !type:EntSelector + id: ClothingMaskBreath + - !type:EntSelector + id: ClothingOuterSuitEmergency + - !type:GroupSelector + children: + - !type:EntSelector + id: EmergencyOxygenTankFilled + - !type:EntSelector + id: OxygenTankFilled + - !type:EntSelector + id: ToolboxEmergencyFilled + prob: 0.5 + - !type:EntSelector + id: MedkitOxygenFilled + prob: 0.2 + - !type:EntSelector + id: WeaponFlareGun + prob: 0.05 + - !type:EntSelector + id: BoxMRE + prob: 0.1 - type: entity id: ClosetEmergencyFilledRandom parent: ClosetEmergency suffix: Filled, Random components: - - type: StorageFill - contents: - - id: ClothingOuterSuitEmergency - - id: ClothingMaskBreath - - id: EmergencyOxygenTankFilled - prob: 0.80 - orGroup: EmergencyTankOrRegularTank - - id: OxygenTankFilled - prob: 0.20 - orGroup: EmergencyTankOrRegularTank - - id: ToolboxEmergencyFilled - prob: 0.4 - - id: MedkitOxygenFilled - prob: 0.2 - - id: WeaponFlareGun - prob: 0.05 - - id: BoxMRE - prob: 0.1 + - type: EntityTableContainerFill + containers: + entity_storage: !type:NestedSelector + tableId: FillLockerEmergencyStandard - type: entity id: ClosetWallEmergencyFilledRandom parent: ClosetWallEmergency suffix: Filled, Random components: - - type: StorageFill - contents: - - id: ClothingOuterSuitEmergency - - id: ClothingMaskBreath - - id: EmergencyOxygenTankFilled - prob: 0.80 - orGroup: EmergencyTankOrRegularTank - - id: OxygenTankFilled - prob: 0.20 - orGroup: EmergencyTankOrRegularTank - - id: ToolboxEmergencyFilled - prob: 0.4 - - id: MedkitOxygenFilled - prob: 0.2 - - id: WeaponFlareGun - prob: 0.05 - - id: BoxMRE - prob: 0.1 + - type: EntityTableContainerFill + containers: + entity_storage: !type:NestedSelector + tableId: FillLockerEmergencyStandard - type: entity id: ClosetEmergencyN2FilledRandom parent: ClosetEmergencyN2 suffix: Filled, Random components: - - type: StorageFill - contents: - - id: ClothingMaskBreath - - id: EmergencyNitrogenTankFilled - prob: 0.80 - orGroup: EmergencyTankOrRegularTank - - id: NitrogenTankFilled - prob: 0.20 - orGroup: EmergencyTankOrRegularTank + - type: EntityTableContainerFill + containers: + entity_storage: !type:AllSelector + children: + - !type:EntSelector + id: ClothingMaskBreath + - !type:EntSelector + id: ClothingOuterSuitEmergency + - !type:GroupSelector + children: + - !type:EntSelector + id: EmergencyNitrogenTankFilled + - !type:EntSelector + id: NitrogenTankFilled + +- type: entityTable + id: FillLockerFireStandard + table: !type:AllSelector + children: + - !type:EntSelector + id: ClothingOuterSuitFire + - !type:EntSelector + id: ClothingHeadHelmetFire + - !type:EntSelector + id: ClothingMaskGas + - !type:GroupSelector + children: + - !type:EntSelector + id: EmergencyOxygenTankFilled + - !type:EntSelector + id: OxygenTankFilled + - !type:EntSelector + id: CrowbarRed + - !type:GroupSelector + children: + - !type:EntSelector + id: FireExtinguisher + weight: 98 + - !type:EntSelector + id: SprayBottleWater #It's just budget cut after budget cut man + weight: 2 - type: entity id: ClosetFireFilled parent: ClosetFire suffix: Filled components: - - type: StorageFill - contents: - - id: ClothingOuterSuitFire - - id: ClothingHeadHelmetFire - - id: ClothingMaskGas - - id: OxygenTankFilled - - id: FireExtinguisher - prob: 0.25 + - type: EntityTableContainerFill + containers: + entity_storage: !type:NestedSelector + tableId: FillLockerFireStandard + - type: entity id: ClosetWallFireFilledRandom parent: ClosetWallFire suffix: Filled components: - - type: StorageFill - contents: - - id: ClothingOuterSuitFire - - id: ClothingHeadHelmetFire - - id: ClothingMaskGas - - id: OxygenTankFilled - - id: FireExtinguisher - prob: 0.25 + - type: EntityTableContainerFill + containers: + entity_storage: !type:NestedSelector + tableId: FillLockerFireStandard + +- type: entityTable + id: SyndieMaintLoot + table: !type:GroupSelector + children: + - !type:GroupSelector + children: + - !type:EntSelector + id: ClothingUniformJumpsuitOperative + - !type:EntSelector + id: ClothingUniformJumpskirtOperative + - !type:EntSelector + id: ClothingBackpackDuffelSyndicate + - !type:EntSelector + id: CyberPen + - !type:EntSelector + id: CigPackSyndicate + - !type:EntSelector + id: ClothingBackpackDuffelSyndicatePyjamaBundle + - !type:EntSelector + id: ClothingBeltMilitaryWebbing + - !type:EntSelector + id: ClothingShoesBootsCombatFilled + - !type:EntSelector + id: ToolboxSyndicateFilled + - !type:EntSelector + id: BalloonSyn + - !type:EntSelector + id: WeaponSniperMosin + weight: 2 + +- type: entityTable + id: MaintenanceLockerLoot + table: !type:AllSelector + children: + - !type:EntSelector + id: StrangePill + prob: 0.20 + # Tools + - !type:NestedSelector + tableId: MaintToolsTable + rolls: !type:RangeNumberSelector + range: 1, 5 + # Fluff + - !type:NestedSelector + tableId: MaintFluffTable + prob: 0.33 + rolls: !type:RangeNumberSelector + range: 0, 2 + # Plushies + - !type:NestedSelector + tableId: AllPlushiesTable + prob: 0.10 + rolls: !type:RangeNumberSelector + range: 1, 2 + # Weapons + - !type:NestedSelector + tableId: MaintWeaponTable + prob: 0.075 + # Syndie Loot + - !type:NestedSelector + tableId: SyndieMaintLoot + prob: 0.05 + - type: entity id: ClosetMaintenanceFilledRandom suffix: Filled, Random parent: ClosetMaintenance components: - - type: StorageFill - contents: - - id: Lantern - prob: 0.50 - - id: Wirecutter - prob: 0.33 - - id: Screwdriver - prob: 0.33 - - id: Wrench - prob: 0.33 - - id: Crowbar - prob: 0.50 - - id: Welder - prob: 0.33 - - id: Multitool - prob: 0.10 - - id: Soap - prob: 0.44 - - id: PlushieCarp - prob: 0.2 - orGroup: carp - - id: PlushieHolocarp - prob: 0.05 - orGroup: carp - - id: PlushieMagicarp - prob: 0.05 - orGroup: carp - - id: PlushieRainbowCarp - prob: 0.03 - orGroup: carp - - id: PlushieSlime - prob: 0.2 - - id: PlushieSnake - prob: 0.2 - - id: ClothingShoesSkates - prob: 0.1 - - id: ClothingHandsGlovesColorYellow - prob: 0.05 - - id: ClothingHandsGlovesFingerlessInsulated - prob: 0.07 - - id: ClothingBeltUtility - prob: 0.10 - - id: ClothingHeadHatCone - prob: 0.2 - - id: WeaponFlareGun - prob: 0.1 - - id: ClothingHandsGlovesColorYellowBudget - prob: 0.25 - - id: StrangePill - prob: 0.20 - - id: DeathPaint - prob: 0.05 - - id: DeathPaintTwo - prob: 0.05 - - id: DrinkMopwataBottleRandom - prob: 0.20 - - id: ModularReceiver - prob: 0.1 - - id: DrinkSpaceGlue - prob: 0.20 - - id: DrinkSpaceLube - prob: 0.20 - - id: BarberScissors - prob: 0.05 - - id: BookRandomStory - prob: 0.1 - # Syndicate loot - - id: null - prob: 0.95 - orGroup: syndiemaintloot - - id: ClothingUniformJumpskirtOperative - prob: 0.005 - orGroup: syndiemaintloot - - id: ClothingUniformJumpsuitOperative - prob: 0.005 - orGroup: syndiemaintloot - - id: ClothingBackpackDuffelSyndicate - prob: 0.005 - orGroup: syndiemaintloot - #- id: CyberPen # DeltaV - Nuh uh - # prob: 0.005 - # orGroup: syndiemaintloot - #- id: CigPackSyndicate - # prob: 0.005 - # orGroup: syndiemaintloot - - id: ClothingBackpackDuffelSyndicatePyjamaBundle - prob: 0.005 - orGroup: syndiemaintloot - #- id: ClothingBeltMilitaryWebbing - # prob: 0.005 - # orGroup: syndiemaintloot - #- id: ClothingShoesBootsCombatFilled - # prob: 0.005 - # orGroup: syndiemaintloot - #- id: ToolboxSyndicateFilled - # prob: 0.005 - # orGroup: syndiemaintloot - #- id: BalloonSyn - # prob: 0.005 - # orGroup: syndiemaintloot - #- id: WeaponSniperMosin - # prob: 0.0010 - # orGroup: syndiemaintloot + - type: EntityTableContainerFill + containers: + entity_storage: !type:NestedSelector + tableId: MaintenanceLockerLoot - type: entity id: ClosetWallMaintenanceFilledRandom parent: ClosetWall suffix: Filled, Random components: - - type: StorageFill - contents: - - id: Lantern - prob: 0.50 - - id: Wirecutter - prob: 0.33 - - id: Screwdriver - prob: 0.33 - - id: Wrench - prob: 0.33 - - id: Crowbar - prob: 0.50 - - id: Welder - prob: 0.33 - - id: Multitool - prob: 0.10 - - id: Soap - prob: 0.44 - - id: PlushieCarp - prob: 0.2 - orGroup: carp - - id: PlushieHolocarp - prob: 0.05 - orGroup: carp - - id: PlushieMagicarp - prob: 0.05 - orGroup: carp - - id: PlushieRainbowCarp - prob: 0.03 - orGroup: carp - - id: PlushieSlime - prob: 0.2 - - id: PlushieSnake - prob: 0.2 - - id: ClothingHandsGlovesColorYellow - prob: 0.05 - - id: ClothingBeltQuiver - prob: 0.02 - - id: ClothingBeltUtility - prob: 0.10 - - id: ClothingHeadHatCone - prob: 0.2 - - id: WeaponFlareGun - prob: 0.1 - - id: ClothingHandsGlovesColorYellowBudget - prob: 0.25 - - id: StrangePill - prob: 0.20 - - id: DrinkSpaceGlue - prob: 0.20 - - id: ModularReceiver - prob: 0.1 - # Syndicate loot - - id: null - prob: 0.95 - orGroup: syndiemaintloot - - id: ClothingUniformJumpskirtOperative - prob: 0.005 - orGroup: syndiemaintloot - - id: ClothingUniformJumpsuitOperative - prob: 0.005 - orGroup: syndiemaintloot - - id: ClothingBackpackDuffelSyndicate - prob: 0.005 - orGroup: syndiemaintloot - - id: CyberPen - prob: 0.005 - orGroup: syndiemaintloot - - id: ClothingHeadHatOutlawHat - prob: 0.005 - orGroup: syndiemaintloot - - id: ClothingEyesGlassesOutlawGlasses - prob: 0.005 - orGroup: syndiemaintloot - - id: CigPackSyndicate - prob: 0.005 - orGroup: syndiemaintloot - - id: ClothingBackpackDuffelSyndicatePyjamaBundle - prob: 0.005 - orGroup: syndiemaintloot - - id: ClothingBeltMilitaryWebbing - prob: 0.005 - orGroup: syndiemaintloot - - id: ClothingShoesBootsCombatFilled - prob: 0.005 - orGroup: syndiemaintloot - - id: ToolboxSyndicateFilled - prob: 0.005 - orGroup: syndiemaintloot - - id: BalloonSyn - prob: 0.005 - orGroup: syndiemaintloot - - id: WeaponSniperMosin - prob: 0.0010 - orGroup: syndiemaintloot + - type: EntityTableContainerFill + containers: + entity_storage: !type:NestedSelector + tableId: MaintenanceLockerLoot - type: entity id: ClosetWallRadiationFilled suffix: Filled parent: ClosetWallRadiation components: - - type: StorageFill - contents: - - id: ClothingOuterSuitRad - amount: 2 - - id: GeigerCounter - amount: 2 + - type: EntityTableContainerFill + containers: + entity_storage: !type:AllSelector + children: + - !type:EntSelector + id: ClothingOuterSuitRad + amount: !type:ConstantNumberSelector + value: 2 + - !type:EntSelector + id: GeigerCounter + amount: !type:ConstantNumberSelector + value: 2 \ No newline at end of file diff --git a/Resources/Prototypes/DeltaV/Body/Organs/vulpkanin.yml b/Resources/Prototypes/DeltaV/Body/Organs/vulpkanin.yml index cd4eeae1900..228d0dcf1ce 100644 --- a/Resources/Prototypes/DeltaV/Body/Organs/vulpkanin.yml +++ b/Resources/Prototypes/DeltaV/Body/Organs/vulpkanin.yml @@ -1,7 +1,7 @@ - type: entity id: OrganVulpkaninStomach parent: OrganAnimalStomach - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Stomach - type: SolutionContainerManager diff --git a/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/backpack.yml b/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/backpack.yml index b73c1d5b4fc..d7cc68ad723 100644 --- a/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/backpack.yml +++ b/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/backpack.yml @@ -12,7 +12,7 @@ - id: BaseBallBat - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackMedical id: ClothingBackpackParamedicFilledDV components: @@ -23,7 +23,7 @@ - id: Portafib - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackMedical id: ClothingBackpackPsychologistFilled components: @@ -33,7 +33,7 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpack id: ClothingBackpackLawyerFilled components: diff --git a/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml b/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml index 50ef77a316f..6ed6dca1edd 100644 --- a/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml +++ b/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelMedical id: ClothingBackpackDuffelParamedicFilledDV components: @@ -10,7 +10,7 @@ - id: Portafib - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelMedical id: ClothingBackpackDuffelPsychologistFilled components: @@ -20,7 +20,7 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffel id: ClothingBackpackDuffelLawyerFilled components: diff --git a/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/satchel.yml b/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/satchel.yml index 99a770e37e1..58d887f47bd 100644 --- a/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/satchel.yml +++ b/Resources/Prototypes/DeltaV/Catalog/Fills/Backpacks/StarterGear/satchel.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelMedical id: ClothingBackpackSatchelParamedicFilledDV components: @@ -10,7 +10,7 @@ - id: Portafib - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelMedical id: ClothingBackpackSatchelPsychologistFilled components: @@ -20,7 +20,7 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchel id: ClothingBackpackSatchelLawyerFilled components: diff --git a/Resources/Prototypes/DeltaV/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/DeltaV/Entities/Clothing/Head/hardsuit-helmets.yml index bdef8822cc5..cfa7d9d26d1 100644 --- a/Resources/Prototypes/DeltaV/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/DeltaV/Entities/Clothing/Head/hardsuit-helmets.yml @@ -2,7 +2,7 @@ - type: entity parent: ClothingHeadHardsuitWithLightBase id: ClothingHeadHelmetHardsuitCombatStandard - noSpawn: true + categories: [ HideSpawnMenu ] name: combat hardsuit helmet description: An armoured helmet with a yellow visor and dual head-mounted lights. components: @@ -37,7 +37,7 @@ - type: entity parent: ClothingHeadHardsuitWithLightBase id: ClothingHeadHelmetHardsuitCombatMedical - noSpawn: true + categories: [ HideSpawnMenu ] name: medical combat hardsuit helmet description: A lightweight armoured helmet with full-face blue visor and head-mounted light. components: @@ -72,7 +72,7 @@ - type: entity parent: ClothingHeadHardsuitWithLightBase id: ClothingHeadHelmetHardsuitCombatRiot - noSpawn: true + categories: [ HideSpawnMenu ] name: riot combat hardsuit helmet description: A heavy armoured helmet with a sealed visor with yellow slits and dual head-mounted lights. components: @@ -107,7 +107,7 @@ - type: entity parent: ClothingHeadHardsuitWithLightBase id: ClothingHeadHelmetHardsuitCombatAdvanced - noSpawn: true + categories: [ HideSpawnMenu ] name: advanced combat hardsuit helmet description: A light but durable helmet with full-face protection and four head-mounted lights. components: diff --git a/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml index 2782fa4f941..f313d30f8f0 100644 --- a/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/ghost_roles.yml @@ -17,7 +17,7 @@ state: full - type: entity # Part of PirateRadioSpawn - noSpawn: true + categories: [ HideSpawnMenu ] id: SpawnPointGhostSyndicateListener name: ghost role spawn point suffix: syndicate listener diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/human.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/human.yml index d539c58496a..5bc30734426 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/human.yml @@ -1,5 +1,5 @@ - type: entity # Delta-V : Part of a mid-round PirateRadioSpawn - noSpawn: true + categories: [ HideSpawnMenu ] parent: MobHumanSyndicateAgent id: MobHumanSyndicateListener name: Syndicate Listener diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml index b3027839b1a..dda911ec6dc 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml @@ -122,7 +122,7 @@ name: Vulpkanin Dummy parent: MobHumanDummy id: MobVulpkaninDummy - noSpawn: true + categories: [ HideSpawnMenu ] description: A dummy vulpkanin meant to be used in character setup. components: - type: HumanoidAppearance diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Misc/subdermal_implants.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Misc/subdermal_implants.yml index 4e8392870cd..7dea5b47fe2 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Misc/subdermal_implants.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Misc/subdermal_implants.yml @@ -3,7 +3,7 @@ id: BionicSyrinxImplant name: bionic syrinx implant description: This implant lets a harpy adjust their voice to whoever they can think of. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant implantAction: ActionSyrinxChangeVoiceMask diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml index 6f96930078b..43e26db6352 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml @@ -1,6 +1,6 @@ # DeltaV Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailBooksAll # See Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Random/books.yml suffix: books @@ -168,7 +168,7 @@ # orGroup: bookother - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailPumpkinPie suffix: pumpkinpie @@ -178,7 +178,7 @@ - id: FoodPiePumpkin - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailDVCosplayFakeWizard suffix: cosplay-wizard, fake as fuck @@ -256,7 +256,7 @@ # Frontier Mail, including Extended Nyano Mail. (Pony Express?) - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFAlcohol suffix: alcohol, extended @@ -300,7 +300,7 @@ amount: 2 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMailLarge id: MailNFBible suffix: bible, extended @@ -312,7 +312,7 @@ - id: ClothingOuterCoatMNKBlackTopCoat #DeltaV - Compensates for items that don't exist here - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFBikeHorn suffix: bike horn, random @@ -327,7 +327,7 @@ prob: 0.05 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMailLarge id: MailNFBuildABuddy suffix: Build-a-Buddy @@ -349,7 +349,7 @@ - id: PaperMailNFBuildABuddy - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMailLarge id: MailNFCake suffix: cake, extended @@ -411,7 +411,7 @@ amount: 2 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFCosplayWizard suffix: cosplay-wizard, extended @@ -429,7 +429,7 @@ prob: 0.1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFCosplayMaid suffix: cosplay-maid, extended @@ -446,7 +446,7 @@ - id: ClothingHandsGlovesColorWhite - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFCosplayNurse suffix: cosplay-nurse, extended @@ -458,7 +458,7 @@ - id: Syringe - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFCheese suffix: cheese, extended @@ -476,7 +476,7 @@ - id: KnifePlastic - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFCigarettes suffix: cigs, random @@ -511,7 +511,7 @@ - id: CheapLighter - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFEMP suffix: emp @@ -522,7 +522,7 @@ - id: PaperMailNFEMPPreparedness - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFSmoke suffix: smoke @@ -532,7 +532,7 @@ - id: DelayedSmoke - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFGoldCigars suffix: cigars, premium @@ -546,7 +546,7 @@ prob: 0.95 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFCookies suffix: cookies, random @@ -592,7 +592,7 @@ orGroup: Cookie4 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFKnife suffix: knife, extended @@ -609,7 +609,7 @@ orGroup: Knife - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMailLarge id: MailNFSword suffix: sword @@ -645,7 +645,7 @@ prob: 0.001 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFMuffins suffix: muffins, random @@ -703,7 +703,7 @@ prob: 0.5 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFPAI suffix: PAI, extended @@ -719,7 +719,7 @@ prob: 0.01 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFPlushie suffix: plushie, extended @@ -783,7 +783,7 @@ # Random snacks, replaces MailChocolate (lousy animal organs) - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFSnacks suffix: snacks, random @@ -896,7 +896,7 @@ prob: 0.5 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFVagueThreat suffix: vague-threat @@ -943,7 +943,7 @@ orGroup: ThreateningObject - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFDonkPockets suffix: donk pockets, random @@ -980,7 +980,7 @@ # Needs a buff? - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFSodaPwrGame suffix: Pwrgame @@ -993,7 +993,7 @@ # Needs a buff? - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFSodaRedBool suffix: Red Bool @@ -1006,7 +1006,7 @@ # Needs a buff? - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFSodaSpaceCola suffix: Space Cola @@ -1018,7 +1018,7 @@ # Needs a buff? - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFSodaSpaceMountainWind suffix: Space Mountain Wind @@ -1030,7 +1030,7 @@ # Needs a buff? - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFSodaSpaceUp suffix: Space Up @@ -1042,7 +1042,7 @@ #TODO: we don't have rainbow joints or blunts (yet?). Uncomment when (if?) they are added. - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFJoints suffix: joints @@ -1093,7 +1093,7 @@ # Mmm, mail food # Needs a buff? - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFUnusualFood suffix: unusual food @@ -1159,7 +1159,7 @@ # Needs a buff? - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFBakedGoods suffix: baked goods @@ -1306,7 +1306,7 @@ # Needs a buff? - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFUnusualProduce suffix: unusual produce @@ -1357,7 +1357,7 @@ prob: 0.25 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFSoaps suffix: soap sampler @@ -1371,7 +1371,7 @@ orGroup: Ad - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFSoapsOmega suffix: soap sampler, omega @@ -1386,7 +1386,7 @@ # Could add spessman battle rules here - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFFigurineBulk # DeltaV - No longer Bulk suffix: figurine, bulk #DeltaV - Spams 3 boxes instead of using the bulk figurine prototype that Frontier uses @@ -1398,7 +1398,7 @@ - id: MysteryFigureBox - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFPen suffix: fancy pen @@ -1426,7 +1426,7 @@ - id: PaperMailNFPaperPusherAd - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMailLarge id: MailNFThrongler suffix: throngler @@ -1436,7 +1436,7 @@ - id: ThronglerToy - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFInstrumentSmall suffix: instrument, expanded @@ -1483,7 +1483,7 @@ prob: 0.01 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFUnusualClothing suffix: unusual clothing @@ -1536,7 +1536,7 @@ prob: 0.25 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFCritter suffix: critter @@ -1589,7 +1589,7 @@ prob: 0.01 # Rare - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFTacticalMaid suffix: tactical maid @@ -1602,7 +1602,7 @@ - id: ClothingHandsTacticalMaidGloves - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMailLarge id: MailNFKendoKit suffix: kendo kit @@ -1620,7 +1620,7 @@ # Base Nyano Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailSake suffix: osake @@ -1632,7 +1632,7 @@ - id: DrinkTokkuri - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailBlockGameDIY suffix: blockgamediy @@ -1642,7 +1642,7 @@ - id: BlockGameArcadeComputerCircuitboard - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailCigars suffix: Cigars @@ -1653,7 +1653,7 @@ - id: Lighter - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailCrayon suffix: Crayon @@ -1663,7 +1663,7 @@ - id: CrayonBox - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailCosplayArc suffix: cosplay-arc @@ -1674,7 +1674,7 @@ - id: ClothingCostumeArcDress - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailCosplayGeisha suffix: cosplay-geisha @@ -1687,7 +1687,7 @@ amount: 3 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailCosplaySchoolgirl suffix: cosplay-schoolgirl @@ -1712,7 +1712,7 @@ orGroup: Color - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailFlowers suffix: flowers @@ -1727,7 +1727,7 @@ - id: FoodLily - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailSignallerKit suffix: signallerkit @@ -1738,7 +1738,7 @@ - id: RemoteSignaller - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNoir suffix: noir @@ -1751,7 +1751,7 @@ - id: ClothingOuterCoatGentle - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailRestraints suffix: restraints @@ -1763,7 +1763,7 @@ - id: ClothingEyesBlindfold - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailFishingCap suffix: fishingcap @@ -1773,7 +1773,7 @@ - id: ClothingHeadFishCap - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailFlashlight suffix: Flashlight @@ -1783,7 +1783,7 @@ - id: FlashlightLantern - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailSpaceVillainDIY suffix: spacevilliandiy @@ -1793,7 +1793,7 @@ - id: SpaceVillainArcadeComputerCircuitboard - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailSunglasses suffix: Sunglasses @@ -1803,7 +1803,7 @@ - id: ClothingEyesGlassesSunglasses - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailWinterCoat suffix: wintercoat diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_civilian.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_civilian.yml index 19a1ee3c536..8b461295053 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_civilian.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_civilian.yml @@ -1,6 +1,6 @@ # Frontier Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMailLarge id: MailNFInstrumentLarge suffix: instrument, large @@ -53,7 +53,7 @@ # Base Nyano Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailBotanistChemicalBottles suffix: botanist chemicals @@ -68,7 +68,7 @@ prob: 0.4 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailBotanistMutagen suffix: mutagen @@ -80,7 +80,7 @@ - id: UnstableMutagenChemistryBottle - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailBotanistSeeds suffix: seeds @@ -129,7 +129,7 @@ orGroup: Seeds - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailClownGildedBikeHorn suffix: honk @@ -140,7 +140,7 @@ - id: BikeHornInstrument - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailClownHonkSupplement suffix: honk @@ -153,7 +153,7 @@ - id: FoodBanana - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailHoPBureaucracy suffix: hop paper @@ -164,7 +164,7 @@ maxAmount: 3 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailHoPSupplement suffix: hop supplement @@ -176,7 +176,7 @@ - id: Paper - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailMimeArtsCrafts suffix: arts and crafts @@ -188,7 +188,7 @@ maxAmount: 3 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailMimeBlankBook suffix: blank book @@ -198,7 +198,7 @@ - id: BookRandom - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailMimeBottleOfNothing suffix: bottle of nothing @@ -208,7 +208,7 @@ - id: DrinkBottleOfNothingFull - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailPassengerMoney suffix: passenger money diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_command.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_command.yml index 86dec46a654..d8f6183b9c6 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_command.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_command.yml @@ -1,6 +1,6 @@ # Base Nyano Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailCommandPinpointerNuclear suffix: pinpointer mail ops @@ -10,7 +10,7 @@ - id: PinpointerNuclear - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailStationRepNFNukeDisk suffix: nuke disk @@ -22,7 +22,7 @@ - id: PaperMailNFAntivirus - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailCommandNFPipebombIntern suffix: pipe and bomb diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_engineering.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_engineering.yml index af70fc621cb..2d3132e7f04 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_engineering.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_engineering.yml @@ -1,6 +1,6 @@ # Base Nyano Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailEngineeringCables suffix: cables @@ -15,7 +15,7 @@ orGroup: Cables - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailEngineeringKudzuDeterrent suffix: antikudzu @@ -25,7 +25,7 @@ - id: PlantBGoneSpray - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailEngineeringSheetGlass suffix: sheetglass @@ -35,7 +35,7 @@ - id: SheetGlass - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailEngineeringWelderReplacement suffix: welder @@ -47,7 +47,7 @@ # Frontier Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFCircuitboardIndustrial suffix: industrial circuitboard @@ -113,7 +113,7 @@ prob: 0.1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailNFCircuitboardService suffix: service circuitboard @@ -155,7 +155,7 @@ prob: 0.1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMailLarge id: MailNFPowerTool suffix: power tool diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_epistemology.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_epistemology.yml index be6f9818e22..0006a0af023 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_epistemology.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_epistemology.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailEpistemologyBluespace suffix: bluespace @@ -9,7 +9,7 @@ - id: MaterialBluespace1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailEpistemologyIngotGold suffix: ingotgold @@ -20,7 +20,7 @@ maxAmount: 3 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailEpistemologyResearchDisk suffix: researchdisk @@ -38,7 +38,7 @@ prob: 0.1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailEpistemologyTinfoilHat suffix: tinfoilhat diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_medical.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_medical.yml index 735f840a201..f19a3950b91 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_medical.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_medical.yml @@ -1,6 +1,6 @@ # Base Nyano Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailMedicalBasicSupplies suffix: basicmedical @@ -15,7 +15,7 @@ maxAmount: 2 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailMedicalChemistrySupplement suffix: chemsupp @@ -31,7 +31,7 @@ maxAmount: 3 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailMedicalEmergencyPens suffix: medipens @@ -42,7 +42,7 @@ maxAmount: 3 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailMedicalMedicinePills suffix: medicinepills @@ -57,7 +57,7 @@ maxAmount: 2 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailMedicalSheetPlasma suffix: sheetplasma @@ -67,7 +67,7 @@ - id: SheetPlasma1 #- type: entity -# noSpawn: true +# categories: [ HideSpawnMenu ] # parent: BaseMail # id: MailMedicalSpaceacillin # suffix: spaceacillin @@ -79,7 +79,7 @@ # Awaiting diseases - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailMedicalStabilizers suffix: stabilizers diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_security.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_security.yml index eed846a0909..c1880eb4d4a 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_security.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail_security.yml @@ -1,6 +1,6 @@ # Base Nyano Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailSecurityDonuts suffix: donuts @@ -10,7 +10,7 @@ - id: FoodBoxDonut - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailSecurityFlashlight suffix: seclite @@ -20,7 +20,7 @@ - id: FlashlightSeclite - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailSecurityNonlethalsKit suffix: nonlethalskit @@ -45,7 +45,7 @@ # Will we ever readd hyperlinks books? Who knows! - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailWardenCrowdControl suffix: crowdcontrol @@ -55,7 +55,7 @@ - id: BoxBeanbag - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailDetectiveForensicSupplement # Deltav - Detective is in charge of investigating crimes. suffix: detectivesupplement # Deltav - Detective is in charge of investigating crimes. @@ -67,7 +67,7 @@ # Frontier Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMailLarge id: MailSecurityNFMusket suffix: musket @@ -83,7 +83,7 @@ # Delta Mail - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailSecurityDVSpaceLaw suffix: spacelaw, extended diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/replicated.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/replicated.yml index 64bb4369f43..0132928af30 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/replicated.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/replicated.yml @@ -2,7 +2,7 @@ id: BulletLightRifleReplicated name: replicated bullet (.20 rifle) parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/special.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/special.yml index df2ccf2a94e..9233a901f9d 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/special.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/special.yml @@ -2,7 +2,7 @@ id: BulletSpecial name: bullet (.38 special) parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -13,7 +13,7 @@ id: BulletSpecialPractice name: bullet (.38 special practice) parent: BaseBulletPractice - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -24,7 +24,7 @@ id: BulletSpecialRubber name: bullet (.38 special rubber) parent: BaseBulletRubber - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -37,7 +37,7 @@ id: BulletSpecialIncendiary name: bullet (.38 special incendiary) parent: BaseBulletIncendiary - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -49,7 +49,7 @@ id: BulletSpecialUranium name: bullet (.38 special uranium) parent: BaseBulletUranium - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -61,7 +61,7 @@ id: BulletSpecialHoly name: bullet (.38 special holy) parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -73,7 +73,7 @@ id: BulletSpecialMindbreaker name: bullet (.38 special mindbreaker) parent: BaseBulletPractice - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml index 936ac9856ec..869da03ded5 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml @@ -1,6 +1,6 @@ - type: entity id: BulletImpactEffectRedDisabler - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.2 diff --git a/Resources/Prototypes/DeltaV/GameRules/events.yml b/Resources/Prototypes/DeltaV/GameRules/events.yml index db727601f84..2997ceb0734 100644 --- a/Resources/Prototypes/DeltaV/GameRules/events.yml +++ b/Resources/Prototypes/DeltaV/GameRules/events.yml @@ -1,7 +1,7 @@ - type: entity id: XenoVents parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -33,7 +33,7 @@ - type: entity id: XenoVentsWeak parent: XenoVents - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -59,7 +59,7 @@ - type: entity id: MothroachSpawn parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent earliestStart: 15 @@ -74,7 +74,7 @@ - type: entity id: PirateRadioSpawn parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 7.5 diff --git a/Resources/Prototypes/DeltaV/GameRules/midround.yml b/Resources/Prototypes/DeltaV/GameRules/midround.yml index 82b47c05718..74edf7a97d5 100644 --- a/Resources/Prototypes/DeltaV/GameRules/midround.yml +++ b/Resources/Prototypes/DeltaV/GameRules/midround.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseGameRule id: ParadoxAnomaly components: diff --git a/Resources/Prototypes/DeltaV/Objectives/paradox_anomaly.yml b/Resources/Prototypes/DeltaV/Objectives/paradox_anomaly.yml index ec87795ab5b..b98ee1539c6 100644 --- a/Resources/Prototypes/DeltaV/Objectives/paradox_anomaly.yml +++ b/Resources/Prototypes/DeltaV/Objectives/paradox_anomaly.yml @@ -8,7 +8,7 @@ # not using base kill/keep alive objectives since these intentionally conflict with eachother - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseParadoxAnomalyObjective id: ParadoxAnomalyKillObjective description: This universe doesn't have room for both of us. @@ -23,7 +23,7 @@ requireDead: true - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseParadoxAnomalyObjective id: ParadoxAnomalyFriendObjective description: Perhaps there is room, as friends. @@ -37,7 +37,7 @@ - type: KeepAliveCondition - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseParadoxAnomalyObjective, BaseLivingObjective] id: ParadoxAnomalyEscapeObjective name: Escape to centcom alive and unrestrained. diff --git a/Resources/Prototypes/DeltaV/Objectives/traitor.yml b/Resources/Prototypes/DeltaV/Objectives/traitor.yml index c5c5318b5d2..2f53b211d9e 100644 --- a/Resources/Prototypes/DeltaV/Objectives/traitor.yml +++ b/Resources/Prototypes/DeltaV/Objectives/traitor.yml @@ -1,5 +1,5 @@ - type: entity # Logistics Officer steal objective. - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseTraitorStealObjective id: LOLuckyBillStealObjective components: @@ -10,7 +10,7 @@ # owner: job-name-qm - type: entity # Head of Personnel steal objective. - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseTraitorStealObjective id: HoPBookIanDossierStealObjective components: @@ -21,7 +21,7 @@ # owner: job-name-hop - type: entity # Clerk steal objective. - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseTraitorStealObjective id: ClerkNotaryStealObjective components: diff --git a/Resources/Prototypes/DeltaV/Roles/Jobs/NPC/syndicateNPCs.yml b/Resources/Prototypes/DeltaV/Roles/Jobs/NPC/syndicateNPCs.yml index b5379c5014e..4dc4fc37aae 100644 --- a/Resources/Prototypes/DeltaV/Roles/Jobs/NPC/syndicateNPCs.yml +++ b/Resources/Prototypes/DeltaV/Roles/Jobs/NPC/syndicateNPCs.yml @@ -16,6 +16,6 @@ name: grafted plate carrier suffix: Unremoveable description: An off-the-shelf plate carrier that has been cruelly grafted onto its wearers body - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Unremoveable diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml index 835c405e192..8b2eea97e80 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml @@ -1,7 +1,7 @@ - type: entity id: ShowSecurityIcons abstract: true - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: ShowJobIcons - type: ShowMindShieldIcons diff --git a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml index e19217686f4..08a3eb568fe 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml @@ -59,7 +59,7 @@ parent: ClothingHeadBase id: ClothingHeadLightBase name: base helmet with light - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: @@ -146,7 +146,7 @@ # No parent since we aren't actually an item. id: ClothingHeadHardsuitBase name: base hardsuit helmet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: icon # default state used by most inheritors @@ -189,7 +189,7 @@ parent: ClothingHeadHardsuitBase id: ClothingHeadHardsuitWithLightBase name: base hardsuit helmet with light - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: @@ -241,7 +241,7 @@ id: ClothingHeadHatHoodWinterBase name: base winter coat hood description: A hood, made to keep your head warm. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: icon diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml index b563fbc0071..caccdd8745e 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml @@ -136,7 +136,7 @@ - type: entity parent: ClothingHeadHardsuitBase id: ClothingHeadHelmetHardsuitMaxim - noSpawn: true + categories: [ HideSpawnMenu ] name: salvager maxim helmet description: A predication of decay washes over your mind. components: diff --git a/Resources/Prototypes/Entities/Clothing/Head/hoods.yml b/Resources/Prototypes/Entities/Clothing/Head/hoods.yml index 0bca209d51e..be7bda91008 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hoods.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hoods.yml @@ -87,7 +87,7 @@ - type: entity parent: ClothingHeadBase id: ClothingHeadHatHoodChaplainHood - noSpawn: true + categories: [ HideSpawnMenu ] name: chaplain's hood description: Maximum piety in this star system. components: @@ -179,7 +179,7 @@ - type: entity parent: ClothingHeadBase id: ClothingHeadHatHoodIan - noSpawn: true + categories: [ HideSpawnMenu ] name: ian hood description: A hood to complete the 'Good boy' look. components: @@ -194,7 +194,7 @@ - type: entity parent: ClothingHeadBase id: ClothingHeadHatHoodCarp - noSpawn: true + categories: [ HideSpawnMenu ] name: carp hood description: A gnarly hood adorned with plastic space carp teeth. components: @@ -229,7 +229,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterDefault - noSpawn: true + categories: [ HideSpawnMenu ] name: default winter coat hood components: - type: Sprite @@ -240,7 +240,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterBartender - noSpawn: true + categories: [ HideSpawnMenu ] name: bartender winter coat hood components: - type: Sprite @@ -251,7 +251,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterCaptain - noSpawn: true + categories: [ HideSpawnMenu ] name: captain's winter coat hood description: An expensive hood, to keep the captain's head warm. components: @@ -263,7 +263,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterCargo - noSpawn: true + categories: [ HideSpawnMenu ] name: logistics winter coat hood # DeltaV - Logistics Department replacing Cargo components: - type: Sprite @@ -274,7 +274,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterCE - noSpawn: true + categories: [ HideSpawnMenu ] name: chief engineer's winter coat hood components: - type: Sprite @@ -285,7 +285,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterCentcom - noSpawn: true + categories: [ HideSpawnMenu ] name: Centcom winter coat hood description: A hood for keeping the central comander's head warm. components: @@ -297,7 +297,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterChem - noSpawn: true + categories: [ HideSpawnMenu ] name: chemist winter coat hood components: - type: Sprite @@ -308,7 +308,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterCMO - noSpawn: true + categories: [ HideSpawnMenu ] name: chief medical officer's winter coat hood components: - type: Sprite @@ -319,7 +319,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterEngineer - noSpawn: true + categories: [ HideSpawnMenu ] name: engineer winter coat hood components: - type: Sprite @@ -330,7 +330,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterHOP - noSpawn: true + categories: [ HideSpawnMenu ] name: head of personel's winter coat hood components: - type: Sprite @@ -341,7 +341,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterHOS - noSpawn: true + categories: [ HideSpawnMenu ] name: head of security's winter coat hood components: - type: Sprite @@ -352,7 +352,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterHydro - noSpawn: true + categories: [ HideSpawnMenu ] name: hydroponics coat hood components: - type: Sprite @@ -363,7 +363,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterJani - noSpawn: true + categories: [ HideSpawnMenu ] name: janitor coat hood components: - type: Sprite @@ -374,7 +374,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterMed - noSpawn: true + categories: [ HideSpawnMenu ] name: medic coat hood components: - type: Sprite @@ -385,7 +385,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterMime - noSpawn: true + categories: [ HideSpawnMenu ] name: mime coat hood components: - type: Sprite @@ -396,7 +396,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterMiner - noSpawn: true + categories: [ HideSpawnMenu ] name: miner coat hood components: - type: Sprite @@ -407,7 +407,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterPara - noSpawn: true + categories: [ HideSpawnMenu ] name: paramedic coat hood components: - type: Sprite @@ -418,7 +418,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterQM - noSpawn: true + categories: [ HideSpawnMenu ] name: logistics officer's coat hood # DeltaV - Logistics Department replacing Cargo components: - type: Sprite @@ -429,7 +429,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterRD - noSpawn: true + categories: [ HideSpawnMenu ] name: mystagogue's coat hood # DeltaV - Epistemics Department replacing Science components: - type: Sprite @@ -440,7 +440,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterRobo - noSpawn: true + categories: [ HideSpawnMenu ] name: robotics coat hood components: - type: Sprite @@ -451,7 +451,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterSci - noSpawn: true + categories: [ HideSpawnMenu ] name: scientist coat hood components: - type: Sprite @@ -462,7 +462,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterSec - noSpawn: true + categories: [ HideSpawnMenu ] name: security coat hood components: - type: Sprite @@ -473,7 +473,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterSyndie - noSpawn: true + categories: [ HideSpawnMenu ] name: syndicate coat hood components: - type: Sprite @@ -484,7 +484,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterWarden - noSpawn: true + categories: [ HideSpawnMenu ] name: warden's coat hood components: - type: Sprite @@ -495,7 +495,7 @@ - type: entity parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterWeb - noSpawn: true + categories: [ HideSpawnMenu ] name: web coat hood components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Clothing/Masks/base_clothingmask.yml b/Resources/Prototypes/Entities/Clothing/Masks/base_clothingmask.yml index 3531a26a6c5..03400e4a82e 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/base_clothingmask.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/base_clothingmask.yml @@ -21,7 +21,7 @@ id: ActionToggleMask name: Toggle Mask description: Handy, but prevents insertion of pie into your pie hole. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Clothing/Mask/gas.rsi, state: icon } diff --git a/Resources/Prototypes/Entities/Clothing/Neck/misc.yml b/Resources/Prototypes/Entities/Clothing/Neck/misc.yml index 11921b9a50d..a39c2e69159 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/misc.yml @@ -70,7 +70,7 @@ - type: entity id: ActionStethoscope name: Listen with stethoscope - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntityTargetAction icon: diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml index 73dc6c8c7f7..9ae3d3b7d55 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml @@ -38,7 +38,7 @@ parent: ClothingOuterWinterCoat id: ClothingOuterWinterCoatToggleable name: winter coat with hood - noSpawn: True + categories: [ HideSpawnMenu ] components: - type: ToggleableClothing clothingPrototype: ClothingHeadHatHoodWinterDefault diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml index c4bdefd3a14..034064b9439 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml @@ -136,7 +136,7 @@ id: ActionBaseToggleMagboots name: Toggle Magboots description: Toggles the magboots on and off. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: NoItem @@ -145,7 +145,7 @@ - type: entity id: ActionToggleMagboots parent: ActionBaseToggleMagboots - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Clothing/Shoes/Boots/magboots.rsi, state: icon } @@ -154,7 +154,7 @@ - type: entity id: ActionToggleMagbootsAdvanced parent: ActionBaseToggleMagboots - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Clothing/Shoes/Boots/magboots-advanced.rsi, state: icon } @@ -163,7 +163,7 @@ - type: entity id: ActionToggleMagbootsSci parent: ActionBaseToggleMagboots - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Clothing/Shoes/Boots/magboots-science.rsi, state: icon } @@ -172,7 +172,7 @@ - type: entity id: ActionToggleMagbootsSyndie parent: ActionBaseToggleMagboots - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Clothing/Shoes/Boots/magboots-syndicate.rsi, state: icon } diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml index d5a695c7c0b..888bcd769cf 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml @@ -128,7 +128,7 @@ id: ActionToggleSpeedBoots name: Toggle Speed Boots description: Toggles the speed boots on and off. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: NoItem diff --git a/Resources/Prototypes/Entities/Debugging/clicktest.yml b/Resources/Prototypes/Entities/Debugging/clicktest.yml index 4e9caaa14d8..baab1b834f6 100644 --- a/Resources/Prototypes/Entities/Debugging/clicktest.yml +++ b/Resources/Prototypes/Entities/Debugging/clicktest.yml @@ -5,7 +5,7 @@ # These dots' texture detection should not interfere with the actual bounding box being tested. - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: ClickTestBase suffix: DEBUG components: diff --git a/Resources/Prototypes/Entities/Debugging/debug_sweps.yml b/Resources/Prototypes/Entities/Debugging/debug_sweps.yml index 0430dbf427e..c7faff4db2c 100644 --- a/Resources/Prototypes/Entities/Debugging/debug_sweps.yml +++ b/Resources/Prototypes/Entities/Debugging/debug_sweps.yml @@ -60,7 +60,7 @@ id: BulletDebug name: bang, ded bullet parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] suffix: DEBUG components: - type: Tag diff --git a/Resources/Prototypes/Entities/Debugging/tippy.yml b/Resources/Prototypes/Entities/Debugging/tippy.yml index 292cbed0f1b..7f149c3b5dc 100644 --- a/Resources/Prototypes/Entities/Debugging/tippy.yml +++ b/Resources/Prototypes/Entities/Debugging/tippy.yml @@ -1,6 +1,6 @@ - type: entity id: Tippy - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite netsync: false diff --git a/Resources/Prototypes/Entities/Effects/ambient_sounds.yml b/Resources/Prototypes/Entities/Effects/ambient_sounds.yml index f686779b3ee..81f7bbfc8a3 100644 --- a/Resources/Prototypes/Entities/Effects/ambient_sounds.yml +++ b/Resources/Prototypes/Entities/Effects/ambient_sounds.yml @@ -1,6 +1,6 @@ - type: entity id: AmbientSoundSourceFlies - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: AmbientSound volume: -5 diff --git a/Resources/Prototypes/Entities/Effects/bluespace_flash.yml b/Resources/Prototypes/Entities/Effects/bluespace_flash.yml index b05681def2d..3137bb5af8e 100644 --- a/Resources/Prototypes/Entities/Effects/bluespace_flash.yml +++ b/Resources/Prototypes/Entities/Effects/bluespace_flash.yml @@ -1,6 +1,6 @@ - type: entity id: EffectFlashBluespace - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight radius: 10.5 @@ -14,7 +14,7 @@ - type: entity id: EffectFlashTelekineticPulse - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight radius: 10 @@ -28,7 +28,7 @@ - type: entity id: EffectFlashShadeskip - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight radius: 5 @@ -42,7 +42,7 @@ - type: entity id: EffectFlashShadowkinShadeskip - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight radius: 5 @@ -56,7 +56,7 @@ - type: entity id: EffectFlashShadowkinDarkSwapOn - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight radius: 5 @@ -70,7 +70,7 @@ - type: entity id: EffectFlashShadowkinDarkSwapOff - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight radius: 5 @@ -84,7 +84,7 @@ - type: entity id: EffectPyrokineticFlare - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: /Textures/Interface/Actions/psionics.rsi diff --git a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml index 469bab32782..62cf5c95a0f 100644 --- a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml +++ b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml @@ -36,7 +36,7 @@ parent: BaseFoam id: Smoke name: smoke - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Occluder - type: Sprite @@ -52,7 +52,7 @@ parent: BaseFoam id: Foam name: foam - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite color: "#ffffffcc" @@ -87,7 +87,7 @@ - type: entity id: MetalFoam name: metal foam - noSpawn: true + categories: [ HideSpawnMenu ] parent: Foam components: - type: Sprite @@ -111,7 +111,7 @@ - type: entity id: IronMetalFoam name: iron metal foam - noSpawn: true + categories: [ HideSpawnMenu ] parent: MetalFoam components: - type: SpawnOnDespawn @@ -120,7 +120,7 @@ - type: entity id: AluminiumMetalFoam name: aluminium metal foam - noSpawn: true + categories: [ HideSpawnMenu ] parent: MetalFoam components: - type: SpawnOnDespawn diff --git a/Resources/Prototypes/Entities/Effects/emp_effects.yml b/Resources/Prototypes/Entities/Effects/emp_effects.yml index 890dd24d430..d1096b85f5e 100644 --- a/Resources/Prototypes/Entities/Effects/emp_effects.yml +++ b/Resources/Prototypes/Entities/Effects/emp_effects.yml @@ -1,6 +1,6 @@ - type: entity id: EffectEmpPulse - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.8 @@ -23,7 +23,7 @@ - type: entity id: EffectEmpDisabled - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.4 diff --git a/Resources/Prototypes/Entities/Effects/exclamation.yml b/Resources/Prototypes/Entities/Effects/exclamation.yml index cfe1cbc7f22..d1f3e3ad063 100644 --- a/Resources/Prototypes/Entities/Effects/exclamation.yml +++ b/Resources/Prototypes/Entities/Effects/exclamation.yml @@ -1,7 +1,7 @@ - type: entity id: Exclamation name: exclamation - noSpawn: true + categories: [ HideSpawnMenu ] save: false components: - type: Transform @@ -22,7 +22,7 @@ - type: entity id: WhistleExclamation name: exclamation - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Structures/Storage/closet.rsi diff --git a/Resources/Prototypes/Entities/Effects/explosion_light.yml b/Resources/Prototypes/Entities/Effects/explosion_light.yml index b4b980dd1a5..d5e7452a795 100644 --- a/Resources/Prototypes/Entities/Effects/explosion_light.yml +++ b/Resources/Prototypes/Entities/Effects/explosion_light.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: ExplosionLight name: explosion light components: diff --git a/Resources/Prototypes/Entities/Effects/hearts.yml b/Resources/Prototypes/Entities/Effects/hearts.yml index 042fdb5e8ab..18f72c95d4a 100644 --- a/Resources/Prototypes/Entities/Effects/hearts.yml +++ b/Resources/Prototypes/Entities/Effects/hearts.yml @@ -1,6 +1,6 @@ - type: entity id: EffectHearts - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.85 diff --git a/Resources/Prototypes/Entities/Effects/lightning.yml b/Resources/Prototypes/Entities/Effects/lightning.yml index 7afd1c07a0c..f85f28d3b80 100644 --- a/Resources/Prototypes/Entities/Effects/lightning.yml +++ b/Resources/Prototypes/Entities/Effects/lightning.yml @@ -33,7 +33,7 @@ name: lightning id: Lightning parent: BaseLightning - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Lightning canArc: true @@ -42,7 +42,7 @@ name: spooky lightning id: LightningRevenant parent: BaseLightning - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: /Textures/Effects/lightning.rsi @@ -66,7 +66,7 @@ name: charged lightning id: ChargedLightning parent: BaseLightning - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: /Textures/Effects/lightning.rsi @@ -85,7 +85,7 @@ name: lightning id: Spark parent: BaseLightning - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: /Textures/Effects/lightning.rsi @@ -112,7 +112,7 @@ name: supercharged lightning id: SuperchargedLightning parent: ChargedLightning - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: /Textures/Effects/lightning.rsi @@ -138,7 +138,7 @@ name: hypercharged lightning id: HyperchargedLightning parent: ChargedLightning - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: /Textures/Effects/lightning.rsi diff --git a/Resources/Prototypes/Entities/Effects/mobspawn.yml b/Resources/Prototypes/Entities/Effects/mobspawn.yml index 4529497021e..695f8a9e715 100644 --- a/Resources/Prototypes/Entities/Effects/mobspawn.yml +++ b/Resources/Prototypes/Entities/Effects/mobspawn.yml @@ -61,7 +61,7 @@ - type: entity id: EffectAnomalyFloraBulb - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.4 diff --git a/Resources/Prototypes/Entities/Effects/radiation.yml b/Resources/Prototypes/Entities/Effects/radiation.yml index 143ffa8559a..82828582cff 100644 --- a/Resources/Prototypes/Entities/Effects/radiation.yml +++ b/Resources/Prototypes/Entities/Effects/radiation.yml @@ -1,7 +1,7 @@ - type: entity name: shimmering anomaly id: RadiationPulse - noSpawn: true + categories: [ HideSpawnMenu ] description: Looking at this anomaly makes you feel strange, like something is pushing at your eyes. components: - type: RadiationSource diff --git a/Resources/Prototypes/Entities/Effects/rcd.yml b/Resources/Prototypes/Entities/Effects/rcd.yml index 902429818e5..a663add9ca9 100644 --- a/Resources/Prototypes/Entities/Effects/rcd.yml +++ b/Resources/Prototypes/Entities/Effects/rcd.yml @@ -1,7 +1,7 @@ - type: entity id: EffectRCDBase abstract: true - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Transform anchored: True @@ -19,7 +19,7 @@ - type: entity parent: EffectRCDBase id: EffectRCDDeconstructPreview - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: deconstructPreview @@ -27,7 +27,7 @@ - type: entity parent: EffectRCDBase id: EffectRCDConstruct0 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: construct0 @@ -37,7 +37,7 @@ - type: entity parent: EffectRCDBase id: EffectRCDConstruct1 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: construct1 @@ -47,7 +47,7 @@ - type: entity parent: EffectRCDBase id: EffectRCDConstruct2 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: construct2 @@ -57,7 +57,7 @@ - type: entity parent: EffectRCDBase id: EffectRCDConstruct3 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: construct3 @@ -67,7 +67,7 @@ - type: entity parent: EffectRCDBase id: EffectRCDConstruct4 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: construct4 @@ -77,7 +77,7 @@ - type: entity parent: EffectRCDBase id: EffectRCDDeconstruct2 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: deconstruct2 @@ -87,7 +87,7 @@ - type: entity parent: EffectRCDBase id: EffectRCDDeconstruct4 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: deconstruct4 @@ -97,7 +97,7 @@ - type: entity parent: EffectRCDBase id: EffectRCDDeconstruct6 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: deconstruct6 @@ -107,7 +107,7 @@ - type: entity parent: EffectRCDBase id: EffectRCDDeconstruct8 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: deconstruct8 diff --git a/Resources/Prototypes/Entities/Effects/shuttle.yml b/Resources/Prototypes/Entities/Effects/shuttle.yml new file mode 100644 index 00000000000..72cc04cba11 --- /dev/null +++ b/Resources/Prototypes/Entities/Effects/shuttle.yml @@ -0,0 +1,12 @@ +- type: entity + id: FtlVisualizerEntity + categories: [ HideSpawnMenu ] + description: Visualizer for shuttles arriving. You shouldn't see this! + components: + - type: FtlVisualizer + sprite: + sprite: /Textures/Effects/medi_holo.rsi + state: medi_holo + - type: Tag + tags: + - HideContextMenu diff --git a/Resources/Prototypes/Entities/Effects/sparks.yml b/Resources/Prototypes/Entities/Effects/sparks.yml index d86522a9711..c12e3b0eca3 100644 --- a/Resources/Prototypes/Entities/Effects/sparks.yml +++ b/Resources/Prototypes/Entities/Effects/sparks.yml @@ -1,6 +1,6 @@ - type: entity id: EffectSparks - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.5 @@ -20,7 +20,7 @@ - type: entity id: EffectTeslaSparks - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.5 diff --git a/Resources/Prototypes/Entities/Effects/weapon_arc.yml b/Resources/Prototypes/Entities/Effects/weapon_arc.yml index 25cd6e84ff2..0f3fab0e878 100644 --- a/Resources/Prototypes/Entities/Effects/weapon_arc.yml +++ b/Resources/Prototypes/Entities/Effects/weapon_arc.yml @@ -1,7 +1,7 @@ - type: entity # Just fades out with no movement animation id: WeaponArcStatic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 2.0 @@ -18,7 +18,7 @@ - type: entity # Plays the state animation then disappears with no fade or swing id: WeaponArcAnimated - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Effects/arcs.rsi @@ -34,7 +34,7 @@ - type: entity id: WeaponArcThrust parent: WeaponArcStatic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WeaponArcVisuals animation: Thrust @@ -42,7 +42,7 @@ - type: entity id: WeaponArcSlash parent: WeaponArcStatic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WeaponArcVisuals animation: Slash @@ -51,7 +51,7 @@ - type: entity id: WeaponArcBite parent: WeaponArcStatic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WeaponArcVisuals fadeOut: false @@ -63,7 +63,7 @@ - type: entity id: WeaponArcClaw parent: WeaponArcStatic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WeaponArcVisuals fadeOut: false @@ -75,7 +75,7 @@ - type: entity id: WeaponArcDisarm parent: WeaponArcAnimated - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WeaponArcVisuals fadeOut: false @@ -87,7 +87,7 @@ - type: entity id: WeaponArcFist parent: WeaponArcStatic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: fist @@ -95,7 +95,7 @@ - type: entity id: WeaponArcPunch parent: WeaponArcStatic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WeaponArcVisuals fadeOut: false @@ -107,7 +107,7 @@ - type: entity id: WeaponArcKick parent: WeaponArcStatic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WeaponArcVisuals fadeOut: false @@ -119,7 +119,7 @@ - type: entity id: WeaponArcSmash parent: WeaponArcStatic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WeaponArcVisuals fadeOut: false diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml index 32594392587..3430c761fb5 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml @@ -1,137 +1,473 @@ +- type: entityTable + id: MaintFluffTable + table: !type:GroupSelector + children: + # Common Group + - !type:GroupSelector + weight: 75 + children: + # Smoker's specialty + - !type:AllSelector + children: + - !type:EntSelector + id: Lighter + - !type:EntSelector + id: CigCartonBlue + # Gar glasses + - !type:GroupSelector + children: + - !type:EntSelector + id: ClothingEyesGlassesGar + - !type:EntSelector + id: ClothingEyesGlassesGarOrange + - !type:EntSelector + id: ClothingEyesGlassesGarGiga + - !type:EntSelector + id: ClothingHeadHatCake + - !type:EntSelector + id: ClothingHeadHatSkub + - !type:EntSelector + id: ClothingHeadHatCone + - !type:EntSelector + id: ClothingNeckBling + - !type:EntSelector + id: ClothingHeadHelmetCosmonaut + - !type:EntSelector + id: ClothingHeadHelmetBasic + - !type:EntSelector + id: ClothingShoeSlippersDuck + - !type:EntSelector + id: ClothingUnderSocksBee + - !type:EntSelector + id: ClothingUnderSocksCoder + - !type:EntSelector + id: ClothingHeadHatSquid + # Animal Masks + - !type:GroupSelector + children: + - !type:EntSelector + id: ClothingMaskRat + - !type:EntSelector + id: ClothingMaskFox + - !type:EntSelector + id: ClothingMaskBee + - !type:EntSelector + id: ClothingMaskBear + - !type:EntSelector + id: ClothingMaskRaven + - !type:EntSelector + id: ClothingMaskJackal + - !type:EntSelector + id: ClothingMaskBat + - !type:EntSelector + id: ClothingBeltSuspenders + - !type:EntSelector + id: ClothingEyesEyepatch + - !type:EntSelector + id: ClothingEyesGlasses + - !type:EntSelector + id: ClothingHandsGlovesLatex + - !type:EntSelector + id: ClothingHandsGlovesFingerless + - !type:EntSelector + id: ClothingHandsGlovesColorBlack + - !type:EntSelector + id: ClothingHeadHatBeret + - !type:EntSelector + id: ClothingHeadHatBowlerHat + - !type:EntSelector + id: ClothingHeadHatFedoraBrown + weight: 0.5 + - !type:EntSelector + id: ClothingHeadHatFedoraGrey + weight: 0.5 + - !type:EntSelector + id: ClothingHeadHatFez + - !type:EntSelector + id: ClothingHeadHatPaper + - !type:EntSelector + id: ClothingHeadHatPirate + - !type:EntSelector + id: ClothingMaskSterile + - !type:EntSelector + id: ClothingNeckHeadphones + - !type:EntSelector + id: ClothingNeckTieRed + - !type:EntSelector + id: ClothingOuterCoatGentle + - !type:AllSelector + children: + - !type:EntSelector + id: ClothingOuterCoatJensen + - !type:EntSelector + id: ClothingEyesGlassesJensen + - !type:EntSelector + id: ClothingOuterCoatLab + - !type:AllSelector + children: + - !type:EntSelector + id: ClothingOuterCoatPirate + - !type:EntSelector + id: ClothingHeadHatPirateTricord + - !type:EntSelector + id: ClothingHeadHatTophat + - !type:EntSelector + id: ClothingOuterHoodieBlack + weight: 0.5 + - !type:EntSelector + id: ClothingOuterHoodieGrey + weight: 0.5 + - !type:GroupSelector + children: + - !type:EntSelector + id: ClothingOuterFlannelRed + - !type:EntSelector + id: ClothingOuterFlannelBlue + - !type:EntSelector + id: ClothingOuterFlannelGreen + - !type:EntSelector + id: ClothingOuterVestHazard + - !type:EntSelector + id: ClothingShoesBootsJack + - !type:EntSelector + id: ClothingShoesHighheelBoots + - !type:EntSelector + id: ClothingShoesBootsLaceup + - !type:EntSelector + id: ClothingShoesLeather + - !type:EntSelector + id: ClothingShoesBootsSalvage + - !type:EntSelector + id: ClothingShoesBootsWork + - !type:EntSelector + id: ClothingShoesTourist + - !type:EntSelector + id: ClothingUniformJumpsuitLoungewear + - !type:EntSelector + id: ClothingHeadHatCowboyRed + # Uncommon Group + - !type:GroupSelector + weight: 23 + children: + - !type:EntSelector + id: ClothingNeckCloakHerald + - !type:EntSelector + id: ClothingHeadHelmetTemplar + # Cloaks + - !type:GroupSelector + children: + - !type:EntSelector + id: ClothingNeckCloakTrans + - !type:EntSelector + id: ClothingNeckCloakAdmin + - !type:EntSelector + id: ClothingNeckCloakMoth + - !type:EntSelector + id: ClothingNeckCloakVoid + - !type:EntSelector + id: ClothingNeckCloakGoliathCloak + - !type:EntSelector + id: ClothingNeckCloakAce + - !type:EntSelector + id: ClothingNeckCloakAro + - !type:EntSelector + id: ClothingNeckCloakBi + - !type:EntSelector + id: ClothingNeckCloakIntersex + - !type:EntSelector + id: ClothingNeckCloakLesbian + - !type:EntSelector + id: ClothingNeckCloakGay + - !type:EntSelector + id: ClothingNeckCloakEnby + - !type:EntSelector + id: ClothingNeckCloakPan + - !type:EntSelector + id: ToySkeleton + - !type:EntSelector + id: Basketball + - !type:EntSelector + id: Football + - !type:EntSelector + id: BalloonNT + - !type:EntSelector + id: BalloonCorgi + - !type:EntSelector + id: MysteryFigureBox + # Cult + - !type:AllSelector + children: + - !type:EntSelector + id: ClothingOuterRobesCult + - !type:EntSelector + id: ClothingShoesCult + - !type:EntSelector + id: ClothingHandsGlovesMercFingerless + - !type:EntSelector + id: ClothingHandsGlovesNitrile + - !type:EntSelector + id: ClothingHandsGlovesPowerglove + - !type:EntSelector + id: ClothingHeadHatAnimalHeadslime + - !type:EntSelector + id: ClothingHeadHatBeretMerc + - !type:EntSelector + id: ClothingHeadHatOutlawHat + - !type:EntSelector + id: ClothingHeadHatUshanka + - !type:EntSelector + id: ClothingHeadHatBunny + - !type:EntSelector + id: ClothingMaskNeckGaiter + - !type:EntSelector + id: ClothingNeckScarfStripedZebra + - !type:EntSelector + id: ClothingOuterGhostSheet + - !type:EntSelector + id: ClothingUniformJumpsuitAncient + - !type:EntSelector + id: ClothingUniformJumpsuitPirate + - !type:EntSelector + id: ClothingShoesBootsCowboyFancy + - !type:EntSelector + id: ClothingHeadHatCowboyBountyHunter + # Pins + - !type:GroupSelector + children: + - !type:EntSelector + id: ClothingNeckLGBTPin + - !type:EntSelector + id: ClothingNeckAromanticPin + - !type:EntSelector + id: ClothingNeckAsexualPin + - !type:EntSelector + id: ClothingNeckBisexualPin + - !type:EntSelector + id: ClothingNeckIntersexPin + - !type:EntSelector + id: ClothingNeckLesbianPin + - !type:EntSelector + id: ClothingNeckNonBinaryPin + - !type:EntSelector + id: ClothingNeckPansexualPin + - !type:EntSelector + id: ClothingNeckTransPin + - !type:EntSelector + id: ClothingNeckAutismPin + - !type:EntSelector + id: ClothingNeckGoldAutismPin + # Rare Group + - !type:GroupSelector + weight: 2 + children: + - !type:EntSelector + id: Skub + - !type:EntSelector + id: PonderingOrb + - !type:EntSelector + id: CluwneHorn + - !type:EntSelector + id: ClothingShoesSkates + - !type:EntSelector + id: DrinkMugDog + - !type:EntSelector + id: CigarGold + - !type:EntSelector + id: ClothingUniformJumpsuitFamilyGuy + - type: entity name: Maint Loot Spawner suffix: Fluff+Clothes id: MaintenanceFluffSpawner parent: MarkerBase components: - - type: Sprite - layers: - - state: red - - sprite: Clothing/Eyes/Glasses/gar.rsi - state: icon-super - - type: RandomSpawner - rarePrototypes: - - ClothingUniformJumpsuitFamilyGuy - - CigarGold - - ClothingNeckCloakHerald - - ClothingHeadHelmetTemplar - - ClothingNeckCloakTrans - - ClothingNeckCloakAdmin - - ClothingNeckCloakBoat # DeltaV - adds boat cloak to maints spawner. Makes more sense than admin cloak o.o - - ClothingNeckCloakMoth - - ClothingNeckCloakVoid - - ClothingNeckCloakGoliathCloak - - ClothingNeckCloakAce - - ClothingNeckCloakAro - - ClothingNeckCloakBi - - ClothingNeckCloakIntersex - - ClothingNeckCloakLesbian - - ClothingNeckCloakGay - - ClothingNeckCloakEnby - - ClothingNeckCloakPan - - ToySkeleton - - Basketball - - Football - - BalloonCorgi - - BalloonNT - - PonderingOrb - - Skub - - DrinkMugDog - - ClothingNeckLGBTPin - - ClothingNeckAromanticPin - - ClothingNeckAsexualPin - - ClothingNeckBisexualPin - - ClothingNeckIntersexPin - - ClothingNeckLesbianPin - - ClothingNeckNonBinaryPin - - ClothingNeckPansexualPin - - ClothingNeckTransPin - - CluwneHorn - - ClothingMaskRat - - MysteryFigureBox - - ClothingHandsGlovesMercFingerless - - ClothingHandsGlovesNitrile - - ClothingHandsGlovesPowerglove - - ClothingHeadHatAnimalHeadslime - - ClothingHeadHatBeretMerc - - ClothingHeadHatOutlawHat - - ClothingHeadHatUshanka - - ClothingHeadHatBunny - - ClothingMaskNeckGaiter - - ClothingNeckScarfStripedZebra - - ClothingOuterRobesCult - - ClothingOuterGhostSheet - - ClothingShoesCult - - ClothingUniformJumpsuitAncient - - ClothingUniformJumpsuitPirate - - ClothingShoesBootsCowboyFancy - - ClothingHeadHatCowboyBountyHunter - - ClothingNeckAutismPin - - ClothingNeckGoldAutismPin - rareChance: 0.01 - prototypes: - - Lighter - - CigCartonBlue - - ClothingEyesGlassesGarGiga - - ClothingEyesGlassesGarOrange - - ClothingEyesGlassesGar - - ClothingHeadHatCake - - ClothingHeadHatSkub - - ClothingHeadHatCone - - ClothingNeckBling - - ClothingHeadHelmetCosmonaut - - ClothingHeadHelmetBasic - - ClothingShoeSlippersDuck - - ClothingUnderSocksBee - - ClothingUnderSocksCoder - - ClothingHeadHatSquid - - ClothingMaskFox - - ClothingMaskBee - - ClothingMaskBear - - ClothingMaskRaven - - ClothingMaskJackal - - ClothingMaskBat - - ClothingBeltSuspenders - - ClothingEyesEyepatch - - ClothingEyesGlasses - - ClothingHandsGlovesLatex - - ClothingHandsGlovesFingerless - - ClothingHandsGlovesColorBlack - - ClothingHeadHatBeret - - ClothingHeadHatBowlerHat - - ClothingHeadHatFedoraBrown - - ClothingHeadHatFedoraGrey - - ClothingHeadHatFez - - ClothingHeadHatPaper - - ClothingHeadHatPirate - - ClothingHeadHatPirateTricord - - ClothingHeadHatTophat - - ClothingMaskSterile - - ClothingNeckHeadphones - - ClothingNeckTieRed - - ClothingOuterCoatGentle - - ClothingOuterCoatJensen - - ClothingEyesGlassesJensen - - ClothingOuterCoatLab - - ClothingOuterCoatPirate - - ClothingOuterHoodieBlack - - ClothingOuterHoodieGrey - - ClothingOuterFlannelRed - - ClothingOuterFlannelBlue - - ClothingOuterFlannelGreen - - ClothingOuterVestHazard - - ClothingShoesBootsJack - - ClothingShoesHighheelBoots - - ClothingShoesBootsLaceup - - ClothingShoesLeather - - ClothingShoesBootsSalvage - - ClothingShoesBootsWork - - ClothingShoesTourist - - ClothingUniformJumpsuitLoungewear - - ClothingHeadHatCowboyRed - chance: 0.6 - offset: 0.0 + - type: Sprite + layers: + - state: red + - sprite: Clothing/Eyes/Glasses/gar.rsi + state: icon-super + - type: EntityTableSpawner + table: !type:NestedSelector + tableId: MaintFluffTable + prob: 0.6 +- type: entityTable + id: MaintToolsTable + table: !type:GroupSelector + children: + # Common Group + - !type:GroupSelector + weight: 75 + children: + - !type:EntSelector + id: FlashlightLantern + - !type:EntSelector + id: ToolboxEmergencyFilled + - !type:GroupSelector + children: + - !type:EntSelector + id: OxygenTankFilled + - !type:EntSelector + id: DoubleEmergencyOxygenTankFilled + - !type:GroupSelector + children: + - !type:EntSelector + id: NitrogenTankFilled + - !type:EntSelector + id: DoubleEmergencyNitrogenTankFilled + - !type:EntSelector + id: EmergencyFunnyOxygenTankFilled + weight: 0.5 + - !type:GroupSelector + weight: 3 + children: + - !type:EntSelector + id: SheetSteel10 + - !type:EntSelector + id: SheetPlastic10 + - !type:EntSelector + id: SheetGlass10 + - !type:EntSelector + id: PartRodMetal10 + - !type:EntSelector + id: MaterialCardboard10 + weight: 0.25 + - !type:EntSelector + id: MaterialCloth10 + weight: 0.25 + - !type:EntSelector + id: MaterialWoodPlank10 + weight: 0.25 + - !type:EntSelector + id: Plunger + - !type:EntSelector + id: PowerCellMedium + - !type:EntSelector + id: PowerCellSmall + - !type:EntSelector + id: Soap + - !type:EntSelector + id: Wirecutter + - !type:EntSelector + id: Screwdriver + - !type:EntSelector + id: Wrench + - !type:EntSelector + id: Crowbar + - !type:EntSelector + id: Multitool + - !type:EntSelector + id: Shovel + - !type:EntSelector + id: Welder + - !type:EntSelector + id: GasAnalyzer + - !type:EntSelector + id: SprayPainter + - !type:EntSelector + id: Flare + - !type:EntSelector + id: Beaker + - !type:EntSelector + id: ClothingMaskGas + - !type:EntSelector + id: ClothingMaskBreath + - !type:EntSelector + id: DoorElectronics + - !type:EntSelector + id: APCElectronics + - !type:EntSelector + id: InflatableWallStack5 + - !type:EntSelector + id: CableHVStack10 + - !type:EntSelector + id: CableMVStack10 + - !type:EntSelector + id: CableApcStack10 + - !type:GroupSelector + children: + - !type:EntSelector + id: ClothingHandsGlovesColorYellowBudget + weight: 5 + - !type:EntSelector + id: ClothingHandsGlovesFingerlessInsulated + weight: 0.5 + - !type:EntSelector + id: ClothingHandsGlovesColorYellow + weight: 1 + # Uncommon Group + - !type:GroupSelector + weight: 23 + children: + - !type:EntSelector + id: ClothingHeadHatCone + weight: 2 + - !type:EntSelector + id: BookRandomStory + weight: 0.25 + - !type:EntSelector + id: ToolboxElectricalFilled + - !type:EntSelector + id: ToolboxMechanicalFilled + - !type:EntSelector + id: ClothingBeltUtility + - !type:EntSelector + id: ToolboxArtisticFilled + - !type:EntSelector + id: GeigerCounter + - !type:EntSelector + id: trayScanner + - !type:EntSelector + id: HandheldGPSBasic + - !type:EntSelector + id: HandLabeler + - !type:EntSelector + id: GlowstickBase + - !type:EntSelector + id: Bucket + - !type:EntSelector + id: RadioHandheld + - !type:EntSelector + id: AppraisalTool + - !type:EntSelector + id: ModularReceiver + - !type:EntSelector + id: WeaponFlareGun + - !type:EntSelector + id: BarberScissors + - !type:GroupSelector + children: + - !type:EntSelector + id: DrinkSpaceGlue + - !type:EntSelector + id: DrinkSpaceLube + # Rare Group + - !type:GroupSelector + weight: 2 + children: + - !type:EntSelector + id: LanternFlash + - !type:EntSelector + id: PowerCellHigh + - !type:EntSelector + id: NetProbeCartridge + - !type:EntSelector + id: WelderIndustrial + - !type:EntSelector + id: SheetPlasteel10 + - !type:EntSelector + id: ClothingMaskGasExplorer + - !type:EntSelector + id: TechnologyDisk + - !type:EntSelector + id: ResearchDisk5000 + - !type:EntSelector + id: PetCarrier + - !type:EntSelector + id: DrinkMopwataBottleRandom + - !type:EntSelector + id: LidSalami + weight: 0.05 - type: entity name: Maint Loot Spawner @@ -139,80 +475,80 @@ id: MaintenanceToolSpawner parent: MarkerBase components: - - type: Sprite - layers: - - state: red - - sprite: Objects/Power/power_cells.rsi - state: high - - type: RandomSpawner - rarePrototypes: - - LanternFlash - - PowerCellHigh - - NetProbeCartridge - - WelderIndustrial - - SheetPlasteel10 - - ClothingMaskGasExplorer - rareChance: 0.08 - prototypes: - - FlashlightLantern - - OxygenTankFilled - - DoubleEmergencyOxygenTankFilled - - ToolboxEmergencyFilled - - ToolboxArtisticFilled - - NitrogenTankFilled - - DoubleEmergencyNitrogenTankFilled - - EmergencyFunnyOxygenTankFilled - - ToolboxElectricalFilled - - ToolboxMechanicalFilled - - ClothingBeltUtility - - Shovel - - Welder - - WeaponFlareGun - - SheetSteel10 - - SheetPlastic10 - - SheetGlass10 - - PartRodMetal10 - - MaterialCardboard10 - - MaterialCloth10 - - MaterialWoodPlank10 - - ResearchDisk - - DeathPaint - - Plunger - - SprayPaintBlue - - SprayPaintRed - - SprayPaintGreen - - SprayPaintOrange - - TechnologyDisk - - PowerCellMedium - - PowerCellSmall - - Wirecutter - - Screwdriver - - Wrench - - Crowbar - - NetworkConfigurator - - trayScanner - - GasAnalyzer - - SprayPainter - - AppraisalTool - - Flare - - HandheldGPSBasic - - HandLabeler - - GlowstickBase - - Bucket - - RadioHandheld - - GeigerCounter - - Beaker - - ClothingMaskGas - - ClothingMaskBreath - - DoorElectronics - - APCElectronics - - InflatableWallStack5 - - CableHVStack10 - - CableMVStack10 - - CableApcStack10 - - PetCarrier - chance: 0.6 - offset: 0.0 + - type: Sprite + layers: + - state: red + - sprite: Objects/Power/power_cells.rsi + state: high + - type: EntityTableSpawner + table: !type:NestedSelector + tableId: MaintToolsTable + prob: 0.6 + +- type: entityTable + id: MaintWeaponTable + table: !type:GroupSelector + children: + # Common Group + - !type:GroupSelector + weight: 95 + children: + - !type:EntSelector + id: Machete + - !type:EntSelector + id: BaseBallBat + - !type:EntSelector + id: CombatKnife + - !type:EntSelector + id: Spear + - !type:EntSelector + id: RifleStock + - !type:EntSelector + id: ModularReceiver + - !type:EntSelector + id: HydroponicsToolScythe + # Rare Group + - !type:GroupSelector + weight: 5 + children: + - !type:EntSelector + id: Lighter + - !type:EntSelector + id: Matchbox + - !type:EntSelector + id: ClothingEyesBlindfold + - !type:EntSelector + id: ClothingMaskMuzzle + - !type:EntSelector + id: ClothingMaskGasSecurity + - !type:EntSelector + id: ShardGlass + weight: 2 + - !type:EntSelector + id: Syringe + - !type:EntSelector + id: Mousetrap + - !type:GroupSelector + weight: 2 + children: + - !type:EntSelector + id: Brutepack1 + - !type:EntSelector + id: Ointment1 + - !type:EntSelector + id: Gauze1 + - !type:EntSelector + id: Bola + - !type:EntSelector + id: SurvivalKnife + - !type:EntSelector + id: ScalpelShiv + - !type:EntSelector + id: Shiv + - !type:EntSelector + id: SawImprov + - !type:EntSelector + id: HydroponicsToolMiniHoe - type: entity name: Maint Loot Spawner @@ -220,51 +556,15 @@ id: MaintenanceWeaponSpawner parent: MarkerBase components: - - type: Sprite - layers: - - state: red - - sprite: Objects/Weapons/Melee/machete.rsi - state: icon - - type: RandomSpawner - rarePrototypes: - - Machete - - BaseBallBat - - CombatKnife - - Spear - - RifleStock - - ModularReceiver - - HydroponicsToolScythe - rareChance: 0.05 - prototypes: - - FlashlightLantern - - OxygenTankFilled - - DoubleEmergencyOxygenTankFilled - - NitrogenTankFilled - - DoubleEmergencyNitrogenTankFilled - - Lighter - - Matchbox - - Crowbar - - Shovel - - Welder - - WeaponFlareGun - - LidSalami - - ClothingEyesBlindfold - - ClothingMaskMuzzle - - ClothingMaskGasSecurity - - ShardGlass - - Syringe - - Mousetrap - - Brutepack1 - - Ointment1 - - Gauze1 - - Bola - - SurvivalKnife - - ScalpelShiv - - Shiv - - SawImprov - - HydroponicsToolMiniHoe - chance: 0.6 - offset: 0.0 + - type: Sprite + layers: + - state: red + - sprite: Objects/Weapons/Melee/machete.rsi + state: icon + - type: EntityTableSpawner + table: !type:NestedSelector + tableId: MaintWeaponTable + prob: 0.6 - type: entity name: Maint Loot Spawner diff --git a/Resources/Prototypes/Entities/Markers/Spawners/corpses.yml b/Resources/Prototypes/Entities/Markers/Spawners/corpses.yml index 3d337b39765..95064428dde 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/corpses.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/corpses.yml @@ -80,7 +80,7 @@ name: Random Security Corpse Spawner id: RandomSecurityCorpseSpawner parent: SalvageHumanCorpseSpawner - noSpawn: true # DeltaV - Prevent security corpses from being mapped in + categories: [ HideSpawnMenu ] # DeltaV - Prevent security corpses from being mapped in components: - type: Sprite layers: diff --git a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml index 4ade9a9fd45..3911a686266 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml @@ -62,7 +62,7 @@ state: narsian - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: SpawnPointGhostNukeOperative name: ghost role spawn point suffix: nukeops @@ -82,7 +82,7 @@ state: radiation - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: SpawnPointLoneNukeOperative name: ghost role spawn point suffix: loneops @@ -111,7 +111,7 @@ - type: entity parent: MarkerBase id: SpawnPointGhostDragon - noSpawn: true + categories: [ HideSpawnMenu ] name: ghost role spawn point suffix: dragon components: diff --git a/Resources/Prototypes/Entities/Markers/clientsideclone.yml b/Resources/Prototypes/Entities/Markers/clientsideclone.yml index 56875c44142..39b9ee48fdb 100644 --- a/Resources/Prototypes/Entities/Markers/clientsideclone.yml +++ b/Resources/Prototypes/Entities/Markers/clientsideclone.yml @@ -1,7 +1,7 @@ - type: entity name: clientsideclone id: clientsideclone - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite - type: AnimationPlayer diff --git a/Resources/Prototypes/Entities/Markers/construction_ghost.yml b/Resources/Prototypes/Entities/Markers/construction_ghost.yml index be9cc915d91..04a8a095023 100644 --- a/Resources/Prototypes/Entities/Markers/construction_ghost.yml +++ b/Resources/Prototypes/Entities/Markers/construction_ghost.yml @@ -1,7 +1,7 @@ - type: entity name: construction ghost id: constructionghost - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite color: '#3F38' diff --git a/Resources/Prototypes/Entities/Markers/drag_shadow.yml b/Resources/Prototypes/Entities/Markers/drag_shadow.yml index a1badb60bc5..19ffb6c36a6 100644 --- a/Resources/Prototypes/Entities/Markers/drag_shadow.yml +++ b/Resources/Prototypes/Entities/Markers/drag_shadow.yml @@ -1,7 +1,7 @@ - type: entity name: drag shadow id: dragshadow - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Tag tags: diff --git a/Resources/Prototypes/Entities/Markers/hover_entity.yml b/Resources/Prototypes/Entities/Markers/hover_entity.yml index 8421a9d8c9e..2e8e1edb296 100644 --- a/Resources/Prototypes/Entities/Markers/hover_entity.yml +++ b/Resources/Prototypes/Entities/Markers/hover_entity.yml @@ -1,7 +1,7 @@ - type: entity name: hover entity id: hoverentity - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: diff --git a/Resources/Prototypes/Entities/Mobs/Corpses/corpses.yml b/Resources/Prototypes/Entities/Mobs/Corpses/corpses.yml index 89ab3376c6a..848865cf3f1 100644 --- a/Resources/Prototypes/Entities/Mobs/Corpses/corpses.yml +++ b/Resources/Prototypes/Entities/Mobs/Corpses/corpses.yml @@ -68,7 +68,7 @@ parent: SalvageHumanCorpse id: MobRandomSecurityCorpse suffix: Dead, Security - noSpawn: true # DeltaV - Prevent security corpses from being mapped in + categories: [ HideSpawnMenu ] # DeltaV - Prevent security corpses from being mapped in components: - type: Loadout prototypes: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/Rslimes.yml b/Resources/Prototypes/Entities/Mobs/NPCs/Rslimes.yml index 3512b518150..7a41ac52ec8 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/Rslimes.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/Rslimes.yml @@ -222,7 +222,7 @@ - type: entity id: reagentslimeVents parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index cbecfbf6a6f..24947413d87 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -1577,7 +1577,7 @@ - type: entity name: guidebook monkey parent: MobMonkey - noSpawn: true + categories: [ HideSpawnMenu ] id: MobGuidebookMonkey description: A hopefully helpful monkey whose only purpose in life is for you to click on. Does this count as having a monkey give you a tutorial? components: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml index f6a42dfb76b..022ae53289e 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml @@ -169,7 +169,7 @@ id: MobRatServant parent: [ SimpleMobBase, MobCombat ] description: He's da mini rat. He don't make da roolz. - noSpawn: true #Must be configured to a King or the AI breaks. + categories: [ HideSpawnMenu ] #Must be configured to a King or the AI breaks. components: - type: Carriable freeHandsRequired: 1 @@ -320,7 +320,7 @@ id: ActionRatKingRaiseArmy name: Raise Army description: Spend some hunger to summon an allied rat to help defend you. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 4 @@ -333,7 +333,7 @@ id: ActionRatKingDomain name: Rat King's Domain description: Spend some hunger to release a cloud of ammonia into the air. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 6 @@ -346,7 +346,7 @@ id: ActionRatKingOrderStay name: Stay description: Command your army to stand in place. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 1 @@ -365,7 +365,7 @@ id: ActionRatKingOrderFollow name: Follow description: Command your army to follow you around. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 1 @@ -384,7 +384,7 @@ id: ActionRatKingOrderCheeseEm name: Cheese 'Em description: Command your army to attack whoever you point at. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 1 @@ -403,7 +403,7 @@ id: ActionRatKingOrderLoose name: Loose description: Command your army to act at their own will. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 1 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml index 74bba2dec8a..dec2bd50bac 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml @@ -150,7 +150,7 @@ description: A geras of a slime - the name is ironic, isn't it? id: MobSlimesGeras parent: BaseMobAdultSlimes - noSpawn: true + categories: [ HideSpawnMenu ] components: # they portable... - type: MovementSpeedModifier diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xenopet.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xenopet.yml index 23108e521bf..37cfa7b46de 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/xenopet.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/xenopet.yml @@ -341,7 +341,7 @@ - type: entity id: neutralXenoVents parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -364,7 +364,7 @@ - type: entity id: ArgocyteVents parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -403,7 +403,7 @@ - type: entity id: MeatVents parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -428,7 +428,7 @@ - type: entity id: TickVents parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -445,7 +445,7 @@ - type: entity id: CarpVents parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -472,7 +472,7 @@ - type: entity id: SpaceVents parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -495,7 +495,7 @@ - type: entity id: LightVents parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml index dce408ed827..957817d4083 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml @@ -2,7 +2,7 @@ parent: MobObserver id: AdminObserver name: admin observer - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Eye visMask: @@ -104,7 +104,7 @@ id: ActionAGhostShowSolar name: Solar Control Interface description: View a solar control interface. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } @@ -117,7 +117,7 @@ id: ActionAGhostShowCommunications name: Communications Interface description: View a communications interface. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } @@ -130,7 +130,7 @@ id: ActionAGhostShowRadar name: Mass Scanner Interface description: View a mass scanner interface. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } @@ -143,7 +143,7 @@ id: ActionAGhostShowCargo name: Cargo Ordering Interface description: View a cargo ordering interface. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } @@ -156,7 +156,7 @@ id: ActionAGhostShowCrewMonitoring name: Crew Monitoring Interface description: View a crew monitoring interface. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } @@ -169,7 +169,7 @@ id: ActionAGhostShowStationRecords name: Station Records Interface description: View a station records Interface - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Structures/Machines/parts.rsi, state: box_0 } diff --git a/Resources/Prototypes/Entities/Mobs/Player/diona.yml b/Resources/Prototypes/Entities/Mobs/Player/diona.yml index dfd5e9a1be7..85c5631de7a 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/diona.yml @@ -15,7 +15,7 @@ # Reformed Diona - type: entity parent: MobDiona - noSpawn: true + categories: [ HideSpawnMenu ] id: MobDionaReformed name: Reformed Diona components: diff --git a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml index cb9dc1c911a..81cd8a579b2 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml @@ -155,7 +155,7 @@ - MinorAntagonists - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: DragonsBreathGun name: dragon's lung description: For dragon's breathing @@ -204,7 +204,7 @@ id: ActionSpawnRift name: Summon Carp Rift description: Summons a carp rift that will periodically spawns carps. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: @@ -218,7 +218,7 @@ id: ActionDevour name: "[color=red]Devour[/color]" description: Attempt to break a structure with your jaws or swallow a creature. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntityTargetAction icon: { sprite : Interface/Actions/devour.rsi, state: icon } @@ -227,7 +227,7 @@ priority: 1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: ActionDragonsBreath name: "[color=orange]Dragon's Breath[/color]" description: Spew out flames at anyone foolish enough to attack you! diff --git a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml index 7bb8547cfab..7d1139d3d79 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml @@ -261,7 +261,7 @@ id: ActionToggleGuardian name: Toggle Guardian description: Either manifests the guardian or recalls it back into your body - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/Actions/manifest.png diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index aa87f81a833..4284632d288 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -39,7 +39,7 @@ # Nuclear Operative - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] name: Nuclear Operative parent: MobHuman id: MobHumanNukeOp @@ -50,7 +50,7 @@ powerRollMultiplier: 7 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: MobHuman id: MobHumanLoneNuclearOperative name: Lone Operative @@ -72,7 +72,7 @@ # Space Ninja - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] name: Space Ninja parent: MobHuman id: MobHumanSpaceNinja diff --git a/Resources/Prototypes/Entities/Mobs/Player/ipc.yml b/Resources/Prototypes/Entities/Mobs/Player/ipc.yml index 85aec21ac66..d80eb4699d1 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/ipc.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/ipc.yml @@ -128,7 +128,7 @@ name: Urist McPositronic parent: MobHumanDummy id: MobIPCDummy - noSpawn: true + categories: [ HideSpawnMenu ] description: A dummy IPC meant to be used in character setup. components: - type: HumanoidAppearance diff --git a/Resources/Prototypes/Entities/Mobs/Player/observer.yml b/Resources/Prototypes/Entities/Mobs/Player/observer.yml index c92595ffc9d..07398299f37 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/observer.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/observer.yml @@ -3,7 +3,7 @@ id: MobObserver name: observer description: Boo! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: CargoSellBlacklist - type: Sprite @@ -60,7 +60,7 @@ id: ActionGhostBoo name: Boo! description: Scare your crew members because of boredom! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/Actions/scream.png @@ -72,7 +72,7 @@ id: ActionToggleLighting name: Toggle All Lighting description: Toggle all light rendering to better observe dark areas. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/VerbIcons/light.svg.192dpi.png @@ -84,7 +84,7 @@ id: ActionToggleFov name: Toggle FoV description: Toggles field-of-view in order to see what players see. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Interface/VerbIcons/vv.svg.192dpi.png @@ -96,7 +96,7 @@ id: ActionToggleGhosts name: Toggle Ghosts description: Toggle the visibility of other ghosts. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Mobs/Ghosts/ghost_human.rsi, state: icon } @@ -108,7 +108,7 @@ id: ActionToggleGhostHearing name: Toggle Ghost Hearing description: Toggle between hearing all messages and hearing only radio & nearby messages. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false diff --git a/Resources/Prototypes/Entities/Mobs/Player/replay_observer.yml b/Resources/Prototypes/Entities/Mobs/Player/replay_observer.yml index 07deef857c3..f309707132e 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/replay_observer.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/replay_observer.yml @@ -1,7 +1,7 @@ - type: entity parent: MobObserver id: ReplayObserver - noSpawn: true + categories: [ HideSpawnMenu ] save: false components: - type: MovementSpeedModifier diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 0f8998bdec8..c3ccb0330c3 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -50,4 +50,4 @@ slots: cell_slot: name: power-cell-slot-component-slot-name-default - startingItem: PowerCellHyper + startingItem: PowerCellHyper \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Species/arachne.yml b/Resources/Prototypes/Entities/Mobs/Species/arachne.yml index ddbdc57e0ad..f3bd68709f9 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/arachne.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/arachne.yml @@ -144,7 +144,7 @@ name: Urist McHands parent: MobHumanDummy id: MobArachneDummy - noSpawn: true + categories: [ HideSpawnMenu ] description: A dummy arachne meant to be used in character setup. components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml index f512e71d325..88822ab0376 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml @@ -136,7 +136,7 @@ - type: entity parent: BaseSpeciesDummy id: MobArachnidDummy - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: HumanoidAppearance species: Arachnid diff --git a/Resources/Prototypes/Entities/Mobs/Species/diona.yml b/Resources/Prototypes/Entities/Mobs/Species/diona.yml index 07d621b139d..530bfe49b24 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/diona.yml @@ -127,7 +127,7 @@ - type: entity parent: BaseSpeciesDummy id: MobDionaDummy - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Inventory templateId: diona diff --git a/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml b/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml index 7f315040356..72c1e782507 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml @@ -74,4 +74,4 @@ - type: entity parent: BaseSpeciesDummy id: MobDwarfDummy - noSpawn: true + categories: [ HideSpawnMenu ] diff --git a/Resources/Prototypes/Entities/Mobs/Species/gingerbread.yml b/Resources/Prototypes/Entities/Mobs/Species/gingerbread.yml index c514a6f1a05..b0a43551c8d 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/gingerbread.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/gingerbread.yml @@ -44,7 +44,7 @@ - type: entity parent: BaseSpeciesDummy id: MobGingerbreadDummy - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: HumanoidAppearance species: Gingerbread diff --git a/Resources/Prototypes/Entities/Mobs/Species/harpy.yml b/Resources/Prototypes/Entities/Mobs/Species/harpy.yml index 4ad6ea03cd9..b3fcd565c4b 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/harpy.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/harpy.yml @@ -192,7 +192,7 @@ id: ActionHarpyPlayMidi name: Play MIDI description: Sing your heart out! Right click yourself to set an instrument. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false @@ -204,7 +204,7 @@ id: ActionSyrinxChangeVoiceMask name: Set name description: Change the name others hear to something else. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: DeltaV/Interface/Actions/harpy_syrinx.png @@ -215,7 +215,7 @@ id: ActionToggleFlight name: Fly description: Make use of your wings to fly. Beat the flightless bird allegations. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index ee2886602d1..4310fb1c65c 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -33,4 +33,4 @@ - type: entity parent: BaseSpeciesDummy id: MobHumanDummy - noSpawn: true + categories: [ HideSpawnMenu ] diff --git a/Resources/Prototypes/Entities/Mobs/Species/moth.yml b/Resources/Prototypes/Entities/Mobs/Species/moth.yml index 5f684222264..2a4a157ecb3 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/moth.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/moth.yml @@ -127,7 +127,7 @@ - type: entity parent: BaseSpeciesDummy id: MobMothDummy - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: HumanoidAppearance species: Moth diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml index ee5d6285659..45be82a448f 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml @@ -73,7 +73,7 @@ - type: entity parent: BaseSpeciesDummy id: MobReptilianDummy - noSpawn: true + categories: [ HideSpawnMenu ] description: A dummy reptilian meant to be used in character setup. components: - type: HumanoidAppearance diff --git a/Resources/Prototypes/Entities/Mobs/Species/shadowkin.yml b/Resources/Prototypes/Entities/Mobs/Species/shadowkin.yml index 393cb0b8716..ff6edb49cc2 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/shadowkin.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/shadowkin.yml @@ -243,7 +243,7 @@ save: false parent: MobHumanDummy id: MobShadowkinDummy - noSpawn: true + categories: [ HideSpawnMenu ] description: A dummy shadowkin meant to be used in character setup. components: - type: HumanoidAppearance diff --git a/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml b/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml index cf3aa6b1caa..96c61856936 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml @@ -108,7 +108,7 @@ - type: entity parent: BaseSpeciesDummy id: MobSkeletonPersonDummy - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: HumanoidAppearance species: Skeleton diff --git a/Resources/Prototypes/Entities/Mobs/Species/slime.yml b/Resources/Prototypes/Entities/Mobs/Species/slime.yml index 81547a3fa36..ba04b6e5fac 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/slime.yml @@ -126,7 +126,7 @@ - type: entity parent: MobHumanDummy id: MobSlimePersonDummy - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: HumanoidAppearance species: SlimePerson diff --git a/Resources/Prototypes/Entities/Mobs/Species/vox.yml b/Resources/Prototypes/Entities/Mobs/Species/vox.yml index 58e2b3b6463..62e04b55780 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/vox.yml @@ -109,7 +109,7 @@ - type: entity parent: BaseSpeciesDummy id: MobVoxDummy - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: HumanoidAppearance species: Vox diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml index aa9e70f3fa4..1854d6f71fa 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml @@ -681,7 +681,7 @@ id: FoodMealHappyHonkClown parent: HappyHonk suffix: random food spawner meal - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StorageFill contents: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml index e5ae7723671..9e36d34af7c 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml @@ -443,7 +443,7 @@ # Trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseItem id: FoodPacketTrash description: This is rubbish. @@ -466,7 +466,7 @@ price: 0 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketBoritosTrash name: boritos bag @@ -475,7 +475,7 @@ state: boritos-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketCnDsTrash name: C&Ds bag @@ -484,7 +484,7 @@ state: cnds-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketCheesieTrash name: cheesie honkers @@ -493,7 +493,7 @@ state: cheesiehonkers-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketChipsTrash name: chips @@ -502,7 +502,7 @@ state: chips-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketChocolateTrash name: chocolate wrapper @@ -511,7 +511,7 @@ state: chocolatebar-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketEnergyTrash name: energybar wrapper @@ -520,7 +520,7 @@ state: energybar-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketPistachioTrash name: pistachios packet @@ -529,7 +529,7 @@ state: pistachio-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketPopcornTrash name: popcorn box @@ -538,7 +538,7 @@ state: popcorn-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketRaisinsTrash name: 4no raisins @@ -547,7 +547,7 @@ state: raisins-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketSemkiTrash name: semki packet @@ -556,7 +556,7 @@ state: semki-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketSusTrash name: sus jerky @@ -565,7 +565,7 @@ state: susjerky-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketSyndiTrash name: syndi-cakes box @@ -574,7 +574,7 @@ state: syndicakes-trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketChowMeinTrash name: empty chow mein box @@ -583,7 +583,7 @@ state: chinese1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketDanDanTrash name: empty dan dan box @@ -592,7 +592,7 @@ state: chinese2 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodCookieFortune name: cookie fortune @@ -605,7 +605,7 @@ descriptionSegments: [CookieFortuneDescriptions] - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketMRETrash name: MRE wrapper @@ -1025,7 +1025,7 @@ # trash - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPacketLunacakeTrash name: lunacake wrapper @@ -1036,7 +1036,7 @@ - type: Item - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketMochicakeTrash name: mochicake wrapper @@ -1046,7 +1046,7 @@ - type: Item - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketMooncakeTrash name: mooncake wrapper @@ -1056,7 +1056,7 @@ - type: Item - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketTidegobsTrash name: tidegobs trash @@ -1066,7 +1066,7 @@ - type: Item - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketSaturnosTrash name: saturn-os trash @@ -1076,7 +1076,7 @@ - type: Item - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketJoveGelloTrash name: jove gello trash @@ -1086,7 +1086,7 @@ - type: Item - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketPlutoniumrodsTrash name: plutonium rods trash @@ -1096,7 +1096,7 @@ - type: Item - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketMarsFroukaTrash name: mars frouka trash @@ -1106,7 +1106,7 @@ - type: Item - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketVenusTrash name: venus hot cakes trash @@ -1116,7 +1116,7 @@ - type: Item - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketOortrocksTrash name: oort rocks trash @@ -1127,7 +1127,7 @@ # weebo vend - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketRedalertnutsTrash name: red alert nuts packet @@ -1137,7 +1137,7 @@ - type: Item - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketStickTrash name: stick @@ -1148,7 +1148,7 @@ # - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketLunacakeTrash id: FoodPacketProteinbarTrash name: protein bar wrapper diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Vapes/vape.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Vapes/vape.yml index 0049c389b5b..19c104b9076 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Vapes/vape.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Vapes/vape.yml @@ -1,6 +1,6 @@ - type: entity id: Vape - noSpawn: true # DeltaV - Disable the Vape + categories: [ HideSpawnMenu ] # DeltaV - Disable the Vape parent: BaseVape name: vape description: "Like a cigar, but for tough teens. (WARNING:Pour only water into the vape)" diff --git a/Resources/Prototypes/Entities/Objects/Decoration/present.yml b/Resources/Prototypes/Entities/Objects/Decoration/present.yml index 06836df342c..e07f0e05840 100644 --- a/Resources/Prototypes/Entities/Objects/Decoration/present.yml +++ b/Resources/Prototypes/Entities/Objects/Decoration/present.yml @@ -435,7 +435,7 @@ - type: entity id: PresentTrash - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseItem name: Wrapping Paper description: Carefully folded, taped, and tied with a bow. Then ceremoniously ripped apart and tossed on the floor. diff --git a/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml b/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml index e0212810210..ce7b6a4bde4 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml @@ -22,7 +22,7 @@ entity: ChameleonDisguise - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMob id: ChameleonDisguise name: Urist McKleiner @@ -49,7 +49,7 @@ # actions - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: ActionDisguiseNoRot name: Toggle Rotation description: Use this to prevent your disguise from rotating, making it easier to hide in some scenarios. @@ -59,7 +59,7 @@ event: !type:DisguiseToggleNoRotEvent - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: ActionDisguiseAnchor name: Toggle Anchored description: For many objects you will want to be anchored to not be completely obvious. diff --git a/Resources/Prototypes/Entities/Objects/Devices/translator_implants.yml b/Resources/Prototypes/Entities/Objects/Devices/translator_implants.yml index 0e7fce95686..97e244798b9 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/translator_implants.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/translator_implants.yml @@ -3,7 +3,7 @@ id: BasicTauCetiBasicTranslatorImplant name: basic common translator implant description: Provides your illiterate friends the ability to understand the common galactic tongue. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: @@ -14,7 +14,7 @@ id: TauCetiBasicTranslatorImplant name: advanced common translator implant description: A more advanced version of the translator implant, teaches your illiterate friends the ability to both speak and understand the galactic tongue! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: @@ -27,7 +27,7 @@ id: BubblishTranslatorImplant name: bubblish translator implant description: An implant that helps you speak and understand the language of slimes! Special vocal chords not included. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: @@ -42,7 +42,7 @@ id: NekomimeticTranslatorImplant name: nekomimetic translator implant description: A translator implant intially designed to help domestic cat owners understand their pets, now granting the ability to understand and speak to Felinids! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: @@ -57,7 +57,7 @@ id: DraconicTranslatorImplant name: draconic translator implant description: A translator implant giving the ability to speak to dragons! Subsequently, also allows to communicate with the Unathi. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: @@ -72,7 +72,7 @@ id: CanilunztTranslatorImplant name: canilunzt translator implant description: A translator implant that helps you communicate with your local yeepers. Yeep! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: @@ -87,7 +87,7 @@ id: SolCommonTranslatorImplant name: sol-common translator implant description: An implant giving the ability to understand and speak SolCommon. Raaagh! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: @@ -102,7 +102,7 @@ id: RootSpeakTranslatorImplant name: root-speak translator implant description: An implant that lets you speak for the trees. Or to the trees. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: @@ -117,7 +117,7 @@ id: MofficTranslatorImplant name: Moffic translator implant description: An implant designed to help domesticate mothroaches. Subsequently, allows you to communicate with the moth people. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: @@ -132,7 +132,7 @@ id: ValyrianStandardTranslatorImplant name: valyrian standard translator implant description: An implant giving the ability to understand and speak Valyrian Standard. Chirp! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: @@ -147,7 +147,7 @@ id: AzazibaTranslatorImplant name: azaziba translator implant description: An implant giving the ability to understand and speak Azaziba. # Intended for Admins Only, this item is for lore reasons not obtainable. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TranslatorImplant understood: diff --git a/Resources/Prototypes/Entities/Objects/Devices/translators.yml b/Resources/Prototypes/Entities/Objects/Devices/translators.yml index 99b6d4305b6..3a30afc4a7f 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/translators.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/translators.yml @@ -1,6 +1,6 @@ # Translator that doesn't need power to work - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: TranslatorUnpowered parent: BaseItem name: translator @@ -32,7 +32,7 @@ # Base translator that uses a power cell. Starts with an empty slot. - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: TranslatorPoweredBase parent: [ TranslatorUnpowered, PowerCellSlotMediumItem ] components: @@ -45,14 +45,14 @@ # Normal translator with medium power cell in it - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: Translator parent: [ PowerCellSlotMediumItem, TranslatorPoweredBase ] suffix: Powered # Normal translator with a high power cell and special appearance - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: TranslatorForeigner parent: [ PowerCellSlotHighItem, TranslatorPoweredBase ] name: foreigner's translator diff --git a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/backgammon.yml b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/backgammon.yml index ab404b88a3e..965b25dbc00 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/backgammon.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/backgammon.yml @@ -18,7 +18,7 @@ id: BackgammonBoardTabletop name: backgammon parent: BaseBoardTabletop - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Fun/Tabletop/backgammon_tabletop.rsi diff --git a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/base.yml b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/base.yml index 351396b5b91..50e208cc43f 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/base.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/base.yml @@ -28,7 +28,7 @@ id: BaseBoardTabletop name: baseboard abstract: true - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Tag tags: diff --git a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/checkers.yml b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/checkers.yml index 69302548d18..6c206ca26f7 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/checkers.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/checkers.yml @@ -24,7 +24,7 @@ id: *checkerboard name: checkerboard parent: BaseBoardTabletop - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Fun/Tabletop/chessboard_tabletop.rsi diff --git a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/chess.yml b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/chess.yml index b31b7803bae..aeba3918c49 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/chess.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/chess.yml @@ -20,7 +20,7 @@ id: ChessBoardTabletop name: chessboard parent: BaseBoardTabletop - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Fun/Tabletop/chessboard_tabletop.rsi diff --git a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/dnd.yml b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/dnd.yml index 51f17d55b99..9b00ef5e018 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/dnd.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/dnd.yml @@ -86,7 +86,7 @@ parent: BaseBoardTabletop id: GrassBoardTabletop name: grass battlemap - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Fun/Tabletop/Battlemaps/grassbm_tabletop.rsi @@ -98,7 +98,7 @@ parent: BaseBoardTabletop id: MoonBoardTabletop name: grass battlemap - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Fun/Tabletop/Battlemaps/moonbm_tabletop.rsi @@ -108,7 +108,7 @@ parent: BaseBoardTabletop id: SandBoardTabletop name: sand battlemap - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Fun/Tabletop/Battlemaps/sandbm_tabletop.rsi @@ -118,7 +118,7 @@ parent: BaseBoardTabletop id: SnowBoardTabletop name: snow battlemap - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Fun/Tabletop/Battlemaps/snowbm_tabletop.rsi @@ -128,7 +128,7 @@ parent: BaseBoardTabletop id: ShipBoardTabletop name: ship battlemap - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Fun/Tabletop/Battlemaps/shipbm_tabletop.rsi diff --git a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/parchis.yml b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/parchis.yml index bb5fdf1f0bf..b608f4e7876 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/parchis.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/parchis.yml @@ -20,7 +20,7 @@ id: ParchisBoardTabletop name: parchís parent: BaseBoardTabletop - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Fun/Tabletop/parchis_tabletop.rsi diff --git a/Resources/Prototypes/Entities/Objects/Fun/pai.yml b/Resources/Prototypes/Entities/Objects/Fun/pai.yml index b73767fd811..5c0bbc84454 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/pai.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/pai.yml @@ -152,7 +152,7 @@ id: ActionPAIPlayMidi name: Play MIDI description: Open your portable MIDI interface to soothe your owner. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false @@ -165,7 +165,7 @@ id: ActionPAIOpenMap name: Open Map description: Open your map interface and guide your owner. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction checkCanInteract: false diff --git a/Resources/Prototypes/Entities/Objects/Fun/spray_paint.yml b/Resources/Prototypes/Entities/Objects/Fun/spray_paint.yml index 1b417f6cde0..d7383fdddac 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/spray_paint.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/spray_paint.yml @@ -4,7 +4,7 @@ id: PaintBase name: spray paint description: A tin of spray paint. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Appearance - type: Sprite diff --git a/Resources/Prototypes/Entities/Objects/Misc/buffering.yml b/Resources/Prototypes/Entities/Objects/Misc/buffering.yml index dbd35344594..c97ffe89edd 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/buffering.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/buffering.yml @@ -1,6 +1,6 @@ - type: entity id: BufferingIcon - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Misc/buffering.rsi diff --git a/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml b/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml index 32d8ea7540a..6194be48488 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml @@ -69,7 +69,7 @@ name: extinguisher spray id: ExtinguisherSpray parent: Vapor - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Effects/extinguisherSpray.rsi diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index c72f7a2e91e..9c54e14f50f 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -268,7 +268,7 @@ - type: entity parent: Paper id: PaperWritten - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Paper - type: Sprite diff --git a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml index a0f5e254d5f..36b1970f3e5 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml @@ -17,7 +17,7 @@ id: SadTromboneImplant name: sad trombone implant description: This implant plays a sad tune when the user dies. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant whitelist: @@ -37,7 +37,7 @@ id: LightImplant name: light implant description: This implant emits light from the user's skin on activation. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant implantAction: ActionToggleLight @@ -59,7 +59,7 @@ id: BikeHornImplant name: bike horn implant description: This implant lets the user honk anywhere at any time. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant implantAction: ActionActivateHonkImplant @@ -80,7 +80,7 @@ id: TrackingImplant name: tracking implant description: This implant has a tracking device attached to the suit sensor network, as well as a condition monitor for the Security radio channel. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant whitelist: @@ -110,7 +110,7 @@ id: StorageImplant name: storage implant description: This implant grants hidden storage within a person's body using bluespace technology. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant implantAction: ActionOpenStorageImplant @@ -134,7 +134,7 @@ id: FreedomImplant name: freedom implant description: This implant lets the user break out of hand restraints up to three times before ceasing to function anymore. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant implantAction: ActionActivateFreedomImplant @@ -147,7 +147,7 @@ id: UplinkImplant name: uplink implant description: This implant lets the user access a hidden Syndicate uplink at will. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant implantAction: ActionOpenUplinkImplant @@ -168,7 +168,7 @@ id: EmpImplant name: EMP implant description: This implant creates an electromagnetic pulse when activated. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant implantAction: ActionActivateEmpImplant @@ -183,7 +183,7 @@ id: ScramImplant name: scram implant description: This implant randomly teleports the user within a large radius when activated. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant implantAction: ActionActivateScramImplant @@ -195,7 +195,7 @@ id: DnaScramblerImplant name: DNA scrambler implant description: This implant lets the user randomly change their appearance and name once. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant implantAction: ActionActivateDnaScramblerImplant @@ -210,7 +210,7 @@ id: MicroBombImplant name: micro-bomb implant description: This implant detonates the user upon activation or upon death. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant permanent: true @@ -240,7 +240,7 @@ id: MacroBombImplant name: macro-bomb implant description: This implant creates a large explosion on death after a preprogrammed countdown. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant permanent: true @@ -275,7 +275,7 @@ id: DeathAcidifierImplant name: death-acidifier implant description: This implant melts the user and their equipment upon death. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant permanent: true @@ -299,7 +299,7 @@ id: DeathRattleImplant name: death rattle implant description: This implant will inform the Syndicate radio channel should the user fall into critical condition or die. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant permanent: true @@ -319,7 +319,7 @@ id: MindShieldImplant name: mind-shield implant description: This implant will ensure loyalty to Nanotrasen and prevent mind control devices. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SubdermalImplant permanent: true diff --git a/Resources/Prototypes/Entities/Objects/Power/lights.yml b/Resources/Prototypes/Entities/Objects/Power/lights.yml index b18a0feaa52..289736f6717 100644 --- a/Resources/Prototypes/Entities/Objects/Power/lights.yml +++ b/Resources/Prototypes/Entities/Objects/Power/lights.yml @@ -234,7 +234,7 @@ name: exterior light tube description: A high power high energy bulb for the depths of space. May contain mercury. id: ExteriorLightTube - noSpawn: true # DeltaV - Don't map these + categories: [ HideSpawnMenu ] # DeltaV - Don't map these components: - type: LightBulb color: "#B4FCF0" diff --git a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml index 23ce5a36ee2..61866b149db 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml @@ -93,7 +93,7 @@ id: ActionBibleSummon name: Summon familiar description: Summon a familiar that will aid you and gain humanlike intelligence once inhabited by a soul. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: { sprite: Clothing/Head/Hats/witch.rsi, state: icon } diff --git a/Resources/Prototypes/Entities/Objects/Specific/Forensics/forensics.yml b/Resources/Prototypes/Entities/Objects/Specific/Forensics/forensics.yml index 9b3be6d7780..aba4cd40efe 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Forensics/forensics.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Forensics/forensics.yml @@ -21,7 +21,7 @@ - type: entity id: ScentTrackEffect - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 1 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml index a5e08e9f542..0e84e54a642 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml @@ -150,7 +150,7 @@ - type: entity name: soaplet id: SoapletSyndie - noSpawn: true + categories: [ HideSpawnMenu ] parent: Soap description: A tiny piece of syndicate soap. components: diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/spray.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/spray.yml index cddf7f6075a..998d3ecf03e 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/spray.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/spray.yml @@ -104,7 +104,7 @@ - type: entity id: Vapor name: "vapor" - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SolutionContainerManager solutions: @@ -136,7 +136,7 @@ - type: entity id: BigVapor parent: Vapor - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Effects/chempuff.rsi diff --git a/Resources/Prototypes/Entities/Objects/Specific/Mail/Items/misc.yml b/Resources/Prototypes/Entities/Objects/Specific/Mail/Items/misc.yml index 6f1c86e00ba..6f9c3157e96 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Mail/Items/misc.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Mail/Items/misc.yml @@ -3,7 +3,7 @@ - type: entity id: DelayedSmoke parent: BaseItem - noSpawn: true + categories: [ HideSpawnMenu ] name: delayed smoke suffix: "(10s)" components: @@ -16,7 +16,7 @@ - type: entity id: AdminInstantEffectEMP7 - noSpawn: true + categories: [ HideSpawnMenu ] suffix: EMP, 7 meters parent: AdminInstantEffectBase components: @@ -27,7 +27,7 @@ - type: entity id: DelayedEMP parent: BaseItem - noSpawn: true + categories: [ HideSpawnMenu ] name: delayed EMP (7 meters) components: - type: Sprite #DeltaV: Apparently these want sprites, probably because they're baseitems diff --git a/Resources/Prototypes/Entities/Objects/Specific/Mail/base_mail_large.yml b/Resources/Prototypes/Entities/Objects/Specific/Mail/base_mail_large.yml index a5dcefacba5..f31b2aa78fd 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Mail/base_mail_large.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Mail/base_mail_large.yml @@ -73,7 +73,7 @@ isLarge: true - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMailLarge id: MailLargeAdminFun suffix: adminfun diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index 960e37a6ccc..53a7a8f075a 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -32,7 +32,7 @@ id: ActionBorgSwapModule name: Swap Module description: Select this module, enabling you to use the tools it provides. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction itemIconStyle: BigItem diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml b/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml index 4bd71f898db..d6855d630c6 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml @@ -88,7 +88,7 @@ parent: Jug name: jug (carbon) id: JugCarbon - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-carbon @@ -103,7 +103,7 @@ parent: Jug name: jug (iodine) id: JugIodine - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-iodine @@ -118,7 +118,7 @@ parent: Jug name: jug (fluorine) id: JugFluorine - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-fluorine @@ -133,7 +133,7 @@ parent: Jug name: jug (chlorine) id: JugChlorine - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-chlorine @@ -148,7 +148,7 @@ parent: Jug name: jug (aluminium) id: JugAluminium - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-aluminium @@ -163,7 +163,7 @@ parent: Jug name: jug (phosphorus) id: JugPhosphorus - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-phosphorus @@ -178,7 +178,7 @@ parent: Jug name: jug (sulfur) id: JugSulfur - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-sulfur @@ -193,7 +193,7 @@ parent: Jug name: jug (silicon) id: JugSilicon - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-silicon @@ -208,7 +208,7 @@ parent: Jug name: jug (hydrogen) id: JugHydrogen - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-hydrogen @@ -223,7 +223,7 @@ parent: Jug name: jug (lithium) id: JugLithium - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-lithium @@ -238,7 +238,7 @@ parent: Jug name: jug (sodium) id: JugSodium - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-sodium @@ -253,7 +253,7 @@ parent: Jug name: jug (potassium) id: JugPotassium - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-potassium @@ -268,7 +268,7 @@ parent: Jug name: jug (radium) id: JugRadium - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-radium @@ -283,7 +283,7 @@ parent: Jug name: jug (iron) id: JugIron - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-iron @@ -298,7 +298,7 @@ parent: Jug name: jug (copper) id: JugCopper - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-copper @@ -313,7 +313,7 @@ parent: Jug name: jug (gold) id: JugGold - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-gold @@ -328,7 +328,7 @@ parent: Jug name: jug (mercury) id: JugMercury - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-mercury @@ -343,7 +343,7 @@ parent: Jug name: jug (silver) id: JugSilver - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-silver @@ -358,7 +358,7 @@ parent: Jug name: jug (ethanol) id: JugEthanol - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-ethanol @@ -373,7 +373,7 @@ parent: Jug name: jug (sugar) id: JugSugar - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-sugar @@ -388,7 +388,7 @@ parent: Jug name: jug (nitrogen) id: JugNitrogen - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-nitrogen @@ -403,7 +403,7 @@ parent: Jug name: jug (oxygen) id: JugOxygen - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-oxygen @@ -418,7 +418,7 @@ parent: Jug name: jug (Plant-B-Gone) id: JugPlantBGone - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-plant-b-gone @@ -433,7 +433,7 @@ parent: Jug name: jug (welding fuel) id: JugWeldingFuel - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Label currentLabel: reagent-name-welding-fuel diff --git a/Resources/Prototypes/Entities/Objects/Tools/fulton.yml b/Resources/Prototypes/Entities/Objects/Tools/fulton.yml index 5255e5f303b..49d8c18c7c1 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/fulton.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/fulton.yml @@ -88,7 +88,7 @@ - type: entity id: FultonEffect - noSpawn: true + categories: [ HideSpawnMenu ] name: fulton effect components: - type: TimedDespawn diff --git a/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml b/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml index 2320764d9ff..3081f60989e 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml @@ -115,7 +115,7 @@ name: light pulse test parent: BaseItem id: LightBehaviourTest1 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Misc/glowstick.rsi @@ -146,7 +146,7 @@ name: color cycle test parent: BaseItem id: LightBehaviourTest2 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Misc/glowstick.rsi @@ -178,7 +178,7 @@ name: multi-behaviour light test parent: BaseItem id: LightBehaviourTest3 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Misc/glowstick.rsi @@ -218,7 +218,7 @@ name: light fade in test parent: BaseItem id: LightBehaviourTest4 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Misc/glowstick.rsi @@ -249,7 +249,7 @@ name: light pulse radius test parent: BaseItem id: LightBehaviourTest5 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Misc/glowstick.rsi @@ -280,7 +280,7 @@ name: light randomize radius test parent: BaseItem id: LightBehaviourTest6 - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Misc/glowstick.rsi diff --git a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml index bd05b8d0f39..8ece2e1a862 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml @@ -1,6 +1,6 @@ - type: entity id: JetpackEffect - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 2 @@ -69,7 +69,7 @@ id: ActionToggleJetpack name: Toggle jetpack description: Toggles the jetpack, giving you movement outside the station. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml index 630354f23d9..1aac4424149 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml @@ -52,7 +52,7 @@ - type: entity id: HotPotatoEffect - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.6 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/antimateriel.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/antimateriel.yml index 31d7b65fe8b..65b7dbc1655 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/antimateriel.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/antimateriel.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBullet id: BulletAntiMateriel name: bullet (.60 anti-materiel) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/caseless_rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/caseless_rifle.yml index 5ce0bf82fe9..f6a3ad590e4 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/caseless_rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/caseless_rifle.yml @@ -2,7 +2,7 @@ id: BulletCaselessRifle name: bullet (.25 caseless) parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -13,7 +13,7 @@ id: BulletCaselessRiflePractice name: bullet (.25 caseless practice) parent: BaseBulletPractice - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -24,7 +24,7 @@ id: BulletCaselessRifleRubber name: bullet (.25 caseless rubber) parent: BaseBulletRubber - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml index 36d41e391ac..351e68a6200 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/grenade.yml @@ -1,7 +1,7 @@ - type: entity id: PelletClusterRubber name: pellet (ball, Rubber) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBullet components: - type: Sprite @@ -20,7 +20,7 @@ - type: entity id: PelletClusterLethal name: pellet (ball, Lethal) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBullet components: - type: Sprite @@ -37,7 +37,7 @@ - type: entity id: PelletClusterIncendiary name: pellet (ball, incendiary) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBulletIncendiary components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/heavy_rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/heavy_rifle.yml index be6a07e486d..d37555c3443 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/heavy_rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/heavy_rifle.yml @@ -2,7 +2,7 @@ id: BulletHeavyRifle name: bullet (.20 rifle) parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -13,7 +13,7 @@ id: BulletMinigun name: minigun bullet (.10 rifle) parent: BulletHeavyRifle - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/light_rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/light_rifle.yml index 3a0df2ac6c7..7e0a19c448d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/light_rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/light_rifle.yml @@ -2,7 +2,7 @@ id: BulletLightRifle name: bullet (.20 rifle) parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -13,7 +13,7 @@ id: BulletLightRiflePractice name: bullet (.20 rifle practice) parent: BaseBulletPractice - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -24,7 +24,7 @@ id: BulletLightRifleRubber name: bullet (.20 rifle rubber) parent: BaseBulletRubber - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -35,7 +35,7 @@ id: BulletLightRifleIncendiary parent: BaseBulletIncendiary name: bullet (.20 rifle incendiary) - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -47,7 +47,7 @@ id: BulletLightRifleUranium parent: BaseBulletUranium name: bullet (.20 rifle uranium) - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/magnum.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/magnum.yml index 1b5cf7890ba..ab45d6837f4 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/magnum.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/magnum.yml @@ -2,7 +2,7 @@ id: BulletMagnum name: bullet (.45 magnum) parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -13,7 +13,7 @@ id: BulletMagnumPractice name: bullet (.45 magnum practice) parent: BaseBulletPractice - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -24,7 +24,7 @@ id: BulletMagnumRubber name: bullet (.45 magnum rubber) parent: BaseBulletRubber - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -37,7 +37,7 @@ id: BulletMagnumIncendiary parent: BaseBulletIncendiary name: bullet (.45 magnum incendiary) - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -49,7 +49,7 @@ id: BulletMagnumAP name: bullet (.45 magnum armor-piercing) parent: BaseBulletAP - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -61,7 +61,7 @@ id: BulletMagnumUranium name: bullet (.45 magnum uranium) parent: BaseBulletUranium - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/pistol.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/pistol.yml index 086a8dc914f..ef3807700da 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/pistol.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/pistol.yml @@ -2,7 +2,7 @@ id: BulletPistol name: bullet (.35 auto) parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -13,7 +13,7 @@ id: BulletPistolPractice name: bullet (.35 auto practice) parent: BaseBulletPractice - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -24,7 +24,7 @@ id: BulletPistolRubber name: bullet (.35 auto rubber) parent: BaseBulletRubber - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -35,7 +35,7 @@ id: BulletPistolIncendiary parent: BaseBulletIncendiary name: bullet (.35 auto incendiary) - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -47,7 +47,7 @@ id: BulletPistolUranium parent: BaseBulletUranium name: bullet (.35 auto uranium) - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml index 2113916cf52..3e1d49ddc02 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml @@ -2,7 +2,7 @@ id: BulletRifle name: bullet (0.20 rifle) parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -13,7 +13,7 @@ id: BulletRiflePractice name: bullet (0.20 rifle practice) parent: BaseBulletPractice - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -24,7 +24,7 @@ id: BulletRifleRubber name: bullet (0.20 rifle rubber) parent: BaseBulletRubber - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -35,7 +35,7 @@ id: BulletRifleIncendiary parent: BaseBulletIncendiary name: bullet (0.20 rifle incendiary) - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -47,7 +47,7 @@ id: BulletRifleUranium parent: BaseBulletUranium name: bullet (0.20 rifle uranium) - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml index e119a846c9c..6e4570e1a16 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml @@ -1,7 +1,7 @@ - type: entity id: PelletShotgunSlug name: pellet (.50 slug) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBullet components: - type: Sprite @@ -15,7 +15,7 @@ - type: entity id: PelletShotgunBeanbag name: beanbag (.50) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBullet components: - type: Sprite @@ -31,7 +31,7 @@ - type: entity id: PelletShotgun name: pellet (.50) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBullet components: - type: Sprite @@ -45,7 +45,7 @@ - type: entity id: PelletShotgunIncendiary name: pellet (.50 incendiary) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBulletIncendiary components: - type: Sprite @@ -62,7 +62,7 @@ - type: entity id: PelletShotgunPractice name: pellet (.50 practice) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBulletPractice components: - type: Sprite @@ -76,7 +76,7 @@ - type: entity id: PelletShotgunImprovised name: improvised pellet - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBullet components: - type: Sprite @@ -92,7 +92,7 @@ - type: entity id: PelletShotgunTranquilizer name: pellet (.50 tranquilizer) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBulletPractice components: - type: Sprite @@ -119,7 +119,7 @@ - type: entity id: PelletShotgunFlare name: pellet (.50 flare) - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Physics bodyType: Dynamic @@ -166,7 +166,7 @@ - type: entity id: PelletShotgunUranium name: pellet (.50 uranium) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBullet components: - type: Sprite @@ -181,7 +181,7 @@ - type: entity id: PelletGrapeshot #tally fucking ho name: grapeshot pellet - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBullet components: - type: Sprite @@ -200,7 +200,7 @@ id: PelletGlass name: glass shard parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite noRot: false diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/hitscan.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/hitscan.yml index 94cac9bcec3..a602f120813 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/hitscan.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/hitscan.yml @@ -1,7 +1,7 @@ # Used to animate the hitscan effects because effectsystem doesn't support it - type: entity id: HitscanEffect - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 2.0 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml index d70b05bf61d..9be9e43e943 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/impacts.yml @@ -1,6 +1,6 @@ - type: entity id: BulletImpactEffect - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.25 @@ -18,7 +18,7 @@ - type: entity id: BulletImpactEffectDisabler - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.2 @@ -36,7 +36,7 @@ - type: entity id: BulletImpactEffectOrangeDisabler - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.2 @@ -55,7 +55,7 @@ - type: entity id: BulletImpactEffectKinetic - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.2 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml index b3abbfdfd3f..a230673e907 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml @@ -3,7 +3,7 @@ name: fireball description: You better GITTAH WEIGH. parent: BulletRocket - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight color: "#E25822" @@ -31,7 +31,7 @@ fireStacks: 0.35 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBulletTrigger id: ProjectileDragonsBreath name: dragon's breath @@ -68,7 +68,7 @@ name: fireball description: Hovering blob of flame. parent: ProjectileFireball - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 30 @@ -82,7 +82,7 @@ - type: entity id: ProjectilePolyboltBase parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/magic.rsi @@ -99,7 +99,7 @@ parent: ProjectilePolyboltBase name: carp polybolt description: Nooo, I don't wanna be fish! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PolymorphOnCollide polymorph: WizardForcedCarp @@ -112,7 +112,7 @@ parent: ProjectilePolyboltBase name: monkey polybolt description: Nooo, I don't wanna be monkey! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PolymorphOnCollide polymorph: WizardForcedMonkey @@ -125,7 +125,7 @@ parent: ProjectilePolyboltBase name: door polybolt description: Nooo, I don't wanna be door! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/magic.rsi @@ -146,7 +146,7 @@ name: healing bolt description: I COMMAND YOU TO LIVE! parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/magic.rsi @@ -166,7 +166,7 @@ id: BulletInstakillMagic name: magical lead cylinder parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] description: This looks familiar. components: - type: Projectile @@ -180,7 +180,7 @@ parent: ProjectilePolyboltBase name: cluwne polybolt description: knoH KnoH! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PolymorphOnCollide polymorph: WizardForcedCluwne @@ -193,7 +193,7 @@ parent: BaseBullet name: Icicle description: Brrrrr. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Structures/Specific/Anomalies/ice_anom.rsi @@ -209,7 +209,7 @@ id: ProjectilePolyboltBread name: bread polybolt description: Nooo, I don't wanna be bread! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PolymorphOnCollide polymorph: BreadMorph diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/meteors.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/meteors.yml index 6bdac1e85f0..60154a4fea5 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/meteors.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/meteors.yml @@ -1,7 +1,7 @@ - type: entity id: MeteorLarge name: meteor - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite noRot: false diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index 55e09014ec9..acf22532232 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -1,6 +1,6 @@ - type: entity id: MuzzleFlashEffect - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 0.4 @@ -69,7 +69,7 @@ - type: entity id: BaseBulletTrigger # Trigger-on-collide bullets parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TriggerOnCollide fixtureID: projectile @@ -93,7 +93,7 @@ id: BaseBulletPractice name: base bullet practice parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -108,7 +108,7 @@ id: BaseBulletRubber name: base bullet rubber parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -127,7 +127,7 @@ id: BaseBulletIncendiary name: base bullet incendiary parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -145,7 +145,7 @@ id: BaseBulletAP name: base bullet armor-piercing parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -161,7 +161,7 @@ id: BaseBulletUranium name: base bullet uranium parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -177,7 +177,7 @@ name: taser bolt id: BulletTaser parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: FlyBySound sound: @@ -219,7 +219,7 @@ name : disabler bolt id: BulletDisabler parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Reflective reflective: @@ -262,7 +262,7 @@ name : disabler bolt practice id: BulletDisablerPractice parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: FlyBySound sound: @@ -302,7 +302,7 @@ name: emitter bolt id: EmitterBolt parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Structures/Power/Generation/Singularity/emitter.rsi @@ -339,7 +339,7 @@ name: watcher bolt id: WatcherBolt parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: FlyBySound sound: @@ -379,7 +379,7 @@ name: magmawing watcher bolt id: WatcherBoltMagmawing parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles_tg.rsi @@ -398,7 +398,7 @@ id: BulletKinetic name: kinetic bolt parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] description: Not too bad, but you still don't want to get hit by it. components: - type: Reflective @@ -423,7 +423,7 @@ - type: entity id: BulletKineticShuttle parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite noRot: false @@ -451,7 +451,7 @@ id: BulletCharge name: charge bolt parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] description: Marks a target for additional damage. components: - type: Reflective @@ -485,7 +485,7 @@ parent: BaseBullet id: AnomalousParticleDelta name: delta particles - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight enabled: true @@ -526,7 +526,7 @@ - type: entity parent: AnomalousParticleDelta id: AnomalousParticleDeltaStrong - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: AnomalousParticle particleType: Delta @@ -539,7 +539,7 @@ parent: AnomalousParticleDelta id: AnomalousParticleEpsilon name: epsilon particles - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight enabled: true @@ -556,7 +556,7 @@ - type: entity parent: AnomalousParticleEpsilon id: AnomalousParticleEpsilonStrong - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: AnomalousParticle particleType: Epsilon @@ -569,7 +569,7 @@ parent: AnomalousParticleDelta id: AnomalousParticleZeta name: zeta particles - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight enabled: true @@ -586,7 +586,7 @@ - type: entity parent: AnomalousParticleZeta id: AnomalousParticleZetaStrong - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: AnomalousParticle particleType: Zeta @@ -599,7 +599,7 @@ parent: AnomalousParticleDelta id: AnomalousParticleOmegaStrong name: omega particles - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight enabled: true @@ -628,7 +628,7 @@ parent: AnomalousParticleDelta id: AnomalousParticleSigma name: sigma particles - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight enabled: true @@ -646,7 +646,7 @@ parent: AnomalousParticleSigma id: AnomalousParticleSigmaStrong name: sigma particles - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: AnomalousParticle particleType: Sigma @@ -656,7 +656,7 @@ id: BulletRocket name: rocket parent: BaseBulletTrigger - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -678,7 +678,7 @@ id: BulletWeakRocket name: weak rocket parent: BaseBulletTrigger - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -700,7 +700,7 @@ id: BulletGrenadeBaton name: baton grenade parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -720,7 +720,7 @@ id: BulletGrenadeBlast name: blast grenade parent: BaseBulletTrigger - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -737,7 +737,7 @@ id: BulletGrenadeFlash name: flash grenade parent: BaseBulletTrigger - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -756,7 +756,7 @@ id: BulletGrenadeFrag name: frag grenade parent: BaseBulletTrigger - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -773,7 +773,7 @@ id: BulletGrenadeEMP name: EMP rocket parent: BaseBulletTrigger - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -794,7 +794,7 @@ id: BulletCap name: cap bullet parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Fun/toys.rsi @@ -810,7 +810,7 @@ id: BulletAcid name: acid spit parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Projectile damage: @@ -826,7 +826,7 @@ - type: entity id: BulletWaterShot name: water - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Clickable - type: Physics @@ -869,7 +869,7 @@ id: BulletCannonBall name: cannonball parent: BaseBulletTrigger - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi @@ -890,7 +890,7 @@ - type: entity id: GrapplingHook name: grappling hook - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EmbeddableProjectile deleteOnRemove: true @@ -926,7 +926,7 @@ name : disabler bolt smg id: BulletDisablerSmg parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Reflective reflective: @@ -969,7 +969,7 @@ name: tesla gun lightning id: TeslaGunBullet parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: TimedDespawn lifetime: 5 @@ -1006,7 +1006,7 @@ name: energy bolt id: BulletEnergyGunLaser parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Reflective reflective: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml index acbaac29222..b39303d9ede 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml @@ -83,7 +83,7 @@ - type: entity id: GrenadeFlashEffect - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PointLight enabled: true @@ -125,7 +125,7 @@ description: Go out on your own terms! parent: GrenadeBase id: SelfDestructSeq - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: ExplodeOnTrigger - type: Explosive diff --git a/Resources/Prototypes/Entities/Stations/nanotrasen.yml b/Resources/Prototypes/Entities/Stations/nanotrasen.yml index 329542a267a..9f4adce96ae 100644 --- a/Resources/Prototypes/Entities/Stations/nanotrasen.yml +++ b/Resources/Prototypes/Entities/Stations/nanotrasen.yml @@ -27,7 +27,7 @@ - BaseStationNanotrasen - BaseRandomStation - BaseStationMail # Nyano component, required for station mail to function - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Transform @@ -37,7 +37,7 @@ - BaseStation - BaseStationAlertLevels - BaseStationNanotrasen - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Transform @@ -48,7 +48,7 @@ - BaseStationJobsSpawning - BaseStationRecords - BaseStationNanotrasen - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Transform @@ -73,6 +73,6 @@ - BaseStationNanotrasen - BaseRandomStation - BaseStationMail - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Transform diff --git a/Resources/Prototypes/Entities/Stations/syndicate.yml b/Resources/Prototypes/Entities/Stations/syndicate.yml index a6494169146..c863ef73523 100644 --- a/Resources/Prototypes/Entities/Stations/syndicate.yml +++ b/Resources/Prototypes/Entities/Stations/syndicate.yml @@ -11,6 +11,6 @@ parent: - BaseStation - BaseStationSyndicate - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Transform diff --git a/Resources/Prototypes/Entities/Stations/test.yml b/Resources/Prototypes/Entities/Stations/test.yml index 0f2e40537a2..9eec6979e7a 100644 --- a/Resources/Prototypes/Entities/Stations/test.yml +++ b/Resources/Prototypes/Entities/Stations/test.yml @@ -6,6 +6,6 @@ - BaseStationJobsSpawning - BaseStationRecords - BaseStationAlertLevels - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Transform diff --git a/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml b/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml index 14b3270ba88..d65d652ff42 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/chairs.yml @@ -358,6 +358,8 @@ components: - type: Foldable folded: true + - type: Strap + enabled: False - type: entity name: steel bench diff --git a/Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml b/Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml index 161ea25bc43..1cfe98f0f65 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/rollerbeds.yml @@ -55,6 +55,7 @@ rotation: -90 buckleOffset: "0,0.15" unbuckleOffset: "0,0.15" + buckleOnInteractHand: False - type: Appearance - type: GenericVisualizer visuals: @@ -79,6 +80,8 @@ components: - type: Foldable folded: true + - type: Strap + enabled: False - type: entity id: CheapRollerBed @@ -105,6 +108,8 @@ components: - type: Foldable folded: true + - type: Strap + enabled: False - type: entity id: EmergencyRollerBed @@ -131,3 +136,5 @@ components: - type: Foldable folded: true + - type: Strap + enabled: False diff --git a/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml b/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml index 7aee5896472..3c1334169d8 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml @@ -61,7 +61,7 @@ - type: entity id: DisposalHolder - noSpawn: true + categories: [ HideSpawnMenu ] name: disposal holder components: - type: DisposalHolder diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/PA/particles.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/PA/particles.yml index 8d889ee5cbb..9d3ce9c931f 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/PA/particles.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/PA/particles.yml @@ -3,7 +3,7 @@ description: Accelerated particles. id: ParticlesProjectile parent: BaseBullet - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: @@ -54,7 +54,7 @@ description: Accelerated negative particles. id: AntiParticlesProjectile parent: ParticlesProjectile - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite layers: diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml index 4e4ef8bdbcf..b7d6b5a128d 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml @@ -108,7 +108,7 @@ mediumVoltageNode: ame - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: AmeController id: AmeControllerUnanchored suffix: Unanchored diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml index ed70b310915..1faee965d4e 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml @@ -144,7 +144,7 @@ # Construction Frames - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: BaseGeneratorWallmountFrame name: wallmount generator frame description: A construction frame for a wallmount generator. diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/solar.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/solar.yml index 601c7c360a5..382846938b2 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/solar.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/solar.yml @@ -1,6 +1,6 @@ - type: entity id: SolarPanelBasePhysSprite - noSpawn: true + categories: [ HideSpawnMenu ] name: solar panel placement: mode: SnapgridCenter diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/teg.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/teg.yml index 9a378c26a44..0245839e466 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/teg.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/teg.yml @@ -183,7 +183,7 @@ - # Spawned by the client-side circulator examine code to indicate the inlet/outlet direction. type: entity id: TegCirculatorArrow - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite sprite: Markers/teg_arrow.rsi diff --git a/Resources/Prototypes/Entities/Structures/Power/apc.yml b/Resources/Prototypes/Entities/Structures/Power/apc.yml index 01147f439f3..9412d454476 100644 --- a/Resources/Prototypes/Entities/Structures/Power/apc.yml +++ b/Resources/Prototypes/Entities/Structures/Power/apc.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: BaseAPC name: APC description: A control terminal for the area's electrical systems. @@ -143,7 +143,7 @@ # APC under construction - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: APCFrame name: APC frame description: A control terminal for the area's electrical systems, lacking the electronics. diff --git a/Resources/Prototypes/Entities/Structures/Power/substation.yml b/Resources/Prototypes/Entities/Structures/Power/substation.yml index 489cfff6597..f96ef97187f 100644 --- a/Resources/Prototypes/Entities/Structures/Power/substation.yml +++ b/Resources/Prototypes/Entities/Structures/Power/substation.yml @@ -117,7 +117,7 @@ # Compact Wall Substation Base - type: entity id: BaseSubstationWall - noSpawn: true + categories: [ HideSpawnMenu ] name: wallmount substation description: A substation designed for compact shuttles and spaces. placement: @@ -260,7 +260,7 @@ # Construction Frame - type: entity id: BaseSubstationWallFrame - noSpawn: true + categories: [ HideSpawnMenu ] name: wallmount substation frame description: A substation frame for construction placement: diff --git a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml index 1d184ad45eb..a773bef2334 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml @@ -698,7 +698,7 @@ - type: entity parent: GasCanisterBrokenBase id: StorageCanisterBroken - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: yellow-1 @@ -706,7 +706,7 @@ - type: entity parent: GasCanisterBrokenBase id: AirCanisterBroken - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: grey-1 @@ -714,7 +714,7 @@ - type: entity parent: GasCanisterBrokenBase id: OxygenCanisterBroken - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: blue-1 @@ -722,7 +722,7 @@ - type: entity parent: GasCanisterBrokenBase id: NitrogenCanisterBroken - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: red-1 @@ -730,7 +730,7 @@ - type: entity parent: GasCanisterBrokenBase id: CarbonDioxideCanisterBroken - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: black-1 @@ -738,7 +738,7 @@ - type: entity parent: GasCanisterBrokenBase id: PlasmaCanisterBroken - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: orange-1 @@ -746,7 +746,7 @@ - type: entity parent: GasCanisterBrokenBase id: TritiumCanisterBroken - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: green-1 @@ -755,7 +755,7 @@ parent: GasCanisterBrokenBase id: WaterVaporCanisterBroken name: broken water vapor canister - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: water_vapor-1 @@ -763,7 +763,7 @@ - type: entity parent: GasCanisterBrokenBase id: AmmoniaCanisterBroken - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: greenys-1 @@ -771,7 +771,7 @@ - type: entity parent: GasCanisterBrokenBase id: NitrousOxideCanisterBroken - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: redws-1 @@ -779,7 +779,7 @@ - type: entity parent: GasCanisterBrokenBase id: FrezonCanisterBroken - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite state: frezon-1 diff --git a/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml b/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml index 01c226cb0fd..52deca8e096 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml @@ -1,7 +1,7 @@ - type: entity parent: BaseStructureDynamic id: CrateGeneric - noSpawn: true + categories: [ HideSpawnMenu ] name: crate description: A large container for items. components: @@ -94,7 +94,7 @@ - type: entity parent: CrateGeneric id: CrateBaseWeldable - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Weldable - type: ResistLocker diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml index 8e957abfe7f..2f644f373d4 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml @@ -36,7 +36,7 @@ #- type: entity # id: LargeBarSign # name: large bar sign -# noSpawn: true +# categories: [ HideSpawnMenu ] # components: # - type: Clickable # - type: InteractionOutline diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml index 8fe6064b951..dbcb0763442 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml @@ -224,7 +224,7 @@ id: LockableButton name: lockable button parent: SignalButtonDirectional - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Appearance - type: Lock @@ -484,7 +484,7 @@ - type: entity id: ButtonFrame name: button frame - noSpawn: true + categories: [ HideSpawnMenu ] description: It's a frame to help distinguish switches visually. placement: mode: SnapgridCenter diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml index dd7eb5bea82..8e6b0863d67 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml @@ -83,7 +83,7 @@ # Construction Frame - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] id: TimerFrame name: timer frame description: A construction frame for a timer. diff --git a/Resources/Prototypes/Entities/Virtual/beam.yml b/Resources/Prototypes/Entities/Virtual/beam.yml index 7ded09c3fff..fa249f0dd3d 100644 --- a/Resources/Prototypes/Entities/Virtual/beam.yml +++ b/Resources/Prototypes/Entities/Virtual/beam.yml @@ -2,7 +2,7 @@ - type: entity id: VirtualBeamEntityController name: BEAM ENTITY YOU SHOULD NOT SEE THIS - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Beam - type: TimedDespawn diff --git a/Resources/Prototypes/Entities/Virtual/electrocution.yml b/Resources/Prototypes/Entities/Virtual/electrocution.yml index ac65245191e..c45e0b3ca9e 100644 --- a/Resources/Prototypes/Entities/Virtual/electrocution.yml +++ b/Resources/Prototypes/Entities/Virtual/electrocution.yml @@ -12,7 +12,7 @@ - type: entity id: VirtualElectrocutionLoadHVPower parent: VirtualElectrocutionLoadBase - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: NodeContainer nodes: @@ -26,7 +26,7 @@ - type: entity id: VirtualElectrocutionLoadMVPower parent: VirtualElectrocutionLoadBase - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: NodeContainer nodes: @@ -40,7 +40,7 @@ - type: entity id: VirtualElectrocutionLoadApc parent: VirtualElectrocutionLoadBase - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: NodeContainer nodes: diff --git a/Resources/Prototypes/Entities/Virtual/stripping_hidden.yml b/Resources/Prototypes/Entities/Virtual/stripping_hidden.yml index 538e502a402..6e46340f973 100644 --- a/Resources/Prototypes/Entities/Virtual/stripping_hidden.yml +++ b/Resources/Prototypes/Entities/Virtual/stripping_hidden.yml @@ -5,7 +5,7 @@ id: StrippingHiddenEntity name: Hidden Entity description: There is something in this pocket. #Or maybe they ar... nah... too obvious a joke. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite texture: Interface/VerbIcons/information.svg.192dpi.png diff --git a/Resources/Prototypes/Entities/Virtual/tether.yml b/Resources/Prototypes/Entities/Virtual/tether.yml index ce953854d65..9459fd20887 100644 --- a/Resources/Prototypes/Entities/Virtual/tether.yml +++ b/Resources/Prototypes/Entities/Virtual/tether.yml @@ -1,6 +1,6 @@ - type: entity id: TetherEntity - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Physics bodyType: Dynamic diff --git a/Resources/Prototypes/Entities/Virtual/virtual_item.yml b/Resources/Prototypes/Entities/Virtual/virtual_item.yml index ed742435501..20f311db704 100644 --- a/Resources/Prototypes/Entities/Virtual/virtual_item.yml +++ b/Resources/Prototypes/Entities/Virtual/virtual_item.yml @@ -2,7 +2,7 @@ - type: entity id: VirtualItem name: VIRTUAL ITEM YOU SHOULD NOT SEE THIS - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Item - type: VirtualItem diff --git a/Resources/Prototypes/Entities/World/Debris/asteroids.yml b/Resources/Prototypes/Entities/World/Debris/asteroids.yml index 061288d010b..1541190cd21 100644 --- a/Resources/Prototypes/Entities/World/Debris/asteroids.yml +++ b/Resources/Prototypes/Entities/World/Debris/asteroids.yml @@ -55,7 +55,7 @@ id: AsteroidDebrisSmall parent: BaseAsteroidDebris name: Asteroid Debris Small - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder @@ -65,7 +65,7 @@ id: AsteroidDebrisMedium parent: BaseAsteroidDebris name: Asteroid Debris Medium - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder @@ -75,7 +75,7 @@ id: AsteroidDebrisLarge parent: BaseAsteroidDebris name: Asteroid Debris Large - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder @@ -85,7 +85,7 @@ id: AsteroidDebrisLarger parent: BaseAsteroidDebris name: Asteroid Debris Larger - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder @@ -96,7 +96,7 @@ id: AsteroidSalvageSmall parent: BaseAsteroidDebris name: Salvage Asteroid Small - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder @@ -108,7 +108,7 @@ id: AsteroidSalvageMedium parent: BaseAsteroidDebris name: Salvage Asteroid Medium - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder @@ -120,7 +120,7 @@ id: AsteroidSalvageLarge parent: BaseAsteroidDebris name: Salvage Asteroid Large - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder @@ -132,7 +132,7 @@ id: AsteroidSalvageHuge parent: BaseAsteroidDebris name: Salvage Asteroid Huge - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder diff --git a/Resources/Prototypes/Entities/World/Debris/wrecks.yml b/Resources/Prototypes/Entities/World/Debris/wrecks.yml index 4c5a3be48f7..743d92e1bac 100644 --- a/Resources/Prototypes/Entities/World/Debris/wrecks.yml +++ b/Resources/Prototypes/Entities/World/Debris/wrecks.yml @@ -53,7 +53,7 @@ id: ScrapDebrisSmall parent: BaseScrapDebris name: Scrap Debris Small - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder @@ -63,7 +63,7 @@ id: ScrapDebrisMedium parent: BaseScrapDebris name: Scrap Debris Medium - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder @@ -73,7 +73,7 @@ id: ScrapDebrisLarge parent: BaseScrapDebris name: Scrap Debris Large - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MapGrid - type: BlobFloorPlanBuilder diff --git a/Resources/Prototypes/Entities/World/chunk.yml b/Resources/Prototypes/Entities/World/chunk.yml index b60fd0d91be..c7052662674 100644 --- a/Resources/Prototypes/Entities/World/chunk.yml +++ b/Resources/Prototypes/Entities/World/chunk.yml @@ -5,7 +5,7 @@ description: | It's rude to stare. It's also a bit odd you're looking at the abstract representation of the grid of reality. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WorldChunk - type: Sprite diff --git a/Resources/Prototypes/GameRules/cargo_gifts.yml b/Resources/Prototypes/GameRules/cargo_gifts.yml index 3787f4e6034..e74ce0cb65e 100644 --- a/Resources/Prototypes/GameRules/cargo_gifts.yml +++ b/Resources/Prototypes/GameRules/cargo_gifts.yml @@ -1,7 +1,7 @@ - type: entity id: GiftsPizzaPartySmall parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 5 @@ -21,7 +21,7 @@ - type: entity id: GiftsPizzaPartyLarge parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 2 @@ -40,7 +40,7 @@ - type: entity id: GiftsEngineering parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 5 @@ -63,7 +63,7 @@ - type: entity id: GiftsVendingRestock parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 4 @@ -86,7 +86,7 @@ - type: entity id: GiftsJanitor parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 6 @@ -106,7 +106,7 @@ - type: entity id: GiftsMedical parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 8 @@ -128,7 +128,7 @@ - type: entity id: GiftsSpacingSupplies parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 4 @@ -150,7 +150,7 @@ - type: entity id: GiftsFireProtection parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 4 @@ -170,7 +170,7 @@ - type: entity id: GiftsSecurityGuns parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 3 @@ -191,7 +191,7 @@ - type: entity id: GiftsSecurityRiot parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 4 diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 4923e399dd0..801dcc4b859 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -1,7 +1,7 @@ - type: entity id: AnomalySpawn parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 8 @@ -12,7 +12,7 @@ - type: entity id: BluespaceArtifact parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 8 @@ -23,7 +23,7 @@ - type: entity id: BluespaceLocker parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 2 @@ -35,7 +35,7 @@ - type: entity id: BreakerFlip parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 7 @@ -46,7 +46,7 @@ - type: entity id: BureaucraticError parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -58,7 +58,7 @@ - type: entity id: ClericalError parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -70,7 +70,7 @@ - type: entity parent: BaseGameRule id: ClosetSkeleton - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 5 @@ -82,7 +82,7 @@ - type: entity parent: BaseGameRule id: DragonSpawn - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 6.5 @@ -96,7 +96,7 @@ - type: entity parent: BaseGameRule id: NinjaSpawn - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 6 @@ -109,7 +109,7 @@ - type: entity parent: BaseGameRule id: RevenantSpawn - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 7.5 @@ -123,7 +123,7 @@ #- type: entity # id: FalseAlarm # parent: BaseGameRule -# noSpawn: true +# categories: [ HideSpawnMenu ] # components: # - type: StationEvent # weight: 15 @@ -133,7 +133,7 @@ - type: entity id: GasLeak parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -145,7 +145,7 @@ - type: entity id: KudzuGrowth parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent earliestStart: 15 @@ -158,7 +158,7 @@ - type: entity id: MeteorSwarm parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent earliestStart: 30 @@ -173,7 +173,7 @@ - type: entity id: MouseMigration parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -198,7 +198,7 @@ - type: entity id: CockroachMigration parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -215,7 +215,7 @@ - type: entity id: PowerGridCheck parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 5 @@ -229,7 +229,7 @@ - type: entity id: RandomSentience parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 6 @@ -240,7 +240,7 @@ - type: entity parent: BaseGameRule id: SolarFlare - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 8 @@ -267,7 +267,7 @@ - type: entity id: VentClog parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -281,7 +281,7 @@ - type: entity id: SlimesSpawn parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -302,7 +302,7 @@ - type: entity id: SpiderSpawn parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -319,7 +319,7 @@ - type: entity id: SpiderClownSpawn parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: false @@ -336,7 +336,7 @@ - type: entity id: ZombieOutbreak parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent earliestStart: 50 @@ -370,7 +370,7 @@ - type: entity id: LoneOpsSpawn parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent earliestStart: 35 @@ -404,7 +404,7 @@ - type: entity id: SleeperAgentsRule parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent earliestStart: 25 @@ -427,7 +427,7 @@ - type: entity id: MassHallucinations parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 7 @@ -444,7 +444,7 @@ - type: entity id: ImmovableRodSpawn parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: false @@ -455,7 +455,7 @@ - type: ImmovableRodRule - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseGameRule id: IonStorm components: @@ -468,7 +468,7 @@ - type: entity id: MimicVendorRule parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent earliestStart: 0 diff --git a/Resources/Prototypes/GameRules/midround.yml b/Resources/Prototypes/GameRules/midround.yml index db1a76adc08..fca0073b4e5 100644 --- a/Resources/Prototypes/GameRules/midround.yml +++ b/Resources/Prototypes/GameRules/midround.yml @@ -3,7 +3,7 @@ - type: entity id: Ninja parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GenericAntagRule agentName: ninja-round-end-agent-name @@ -19,7 +19,7 @@ # stores configuration for dragon - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseGameRule id: Dragon components: @@ -30,7 +30,7 @@ - DragonSurviveObjective - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseGameRule id: Thief components: @@ -55,7 +55,7 @@ sound: "/Audio/Misc/thief_greeting.ogg" #- type: entity -# noSpawn: true +# categories: [ HideSpawnMenu ] # parent: BaseGameRule # id: Exterminator # components: diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index 39bea004d02..4ae53c9b37a 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -1,12 +1,12 @@ - type: entity id: BaseGameRule abstract: true - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GameRule - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseGameRule id: SubGamemodesRule components: @@ -18,7 +18,7 @@ - type: entity id: DeathMatch31 parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: DeathMatchRule rewardSpawns: @@ -48,7 +48,7 @@ - type: entity id: InactivityTimeRestart parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InactivityRule inactivityMaxTime: 600 @@ -57,7 +57,7 @@ - type: entity id: MaxTimeRestart parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: MaxTimeRestartRule roundMaxTime: 300 @@ -66,7 +66,7 @@ - type: entity id: Nukeops parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GameRule minPlayers: 35 @@ -136,7 +136,7 @@ - type: entity id: Traitor parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GameRule minPlayers: 5 @@ -157,7 +157,7 @@ - type: entity id: Revolutionary parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GameRule minPlayers: 15 @@ -182,21 +182,21 @@ - type: entity id: Sandbox parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SandboxRule - type: entity id: Secret parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: SecretRule - type: entity id: Zombie parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GameRule minPlayers: 20 @@ -229,21 +229,21 @@ - type: entity id: BasicStationEventScheduler parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: BasicStationEventScheduler - type: entity id: RampingStationEventScheduler parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: RampingStationEventScheduler - type: entity id: HellshiftStationEventScheduler parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: RampingStationEventScheduler chaosModifier: 4 # By default, one event each 30-10 seconds after two hours. Changing CVars will cause this to deviate. @@ -253,7 +253,7 @@ - type: entity id: IrregularStationEventScheduler parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: OscillatingStationEventScheduler minChaos: 0.8 @@ -266,7 +266,7 @@ - type: entity id: IrregularExtendedStationEventScheduler parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: OscillatingStationEventScheduler minChaos: 0.8 @@ -281,7 +281,7 @@ - type: entity id: BasicRoundstartVariation parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: RoundstartStationVariationRule rules: diff --git a/Resources/Prototypes/GameRules/unknown_shuttles.yml b/Resources/Prototypes/GameRules/unknown_shuttles.yml index f44bbdcaaab..db9d4756a89 100644 --- a/Resources/Prototypes/GameRules/unknown_shuttles.yml +++ b/Resources/Prototypes/GameRules/unknown_shuttles.yml @@ -1,7 +1,7 @@ - type: entity id: UnknownShuttleCargoLost parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: false @@ -14,7 +14,7 @@ - type: entity id: UnknownShuttleTravelingCuisine parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: false @@ -27,7 +27,7 @@ - type: entity id: UnknownShuttleDisasterEvacPod parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: false @@ -40,7 +40,7 @@ - type: entity id: UnknownShuttleHonki parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: false @@ -53,7 +53,7 @@ - type: entity id: UnknownShuttleSyndieEvacPod parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: false diff --git a/Resources/Prototypes/GameRules/variation.yml b/Resources/Prototypes/GameRules/variation.yml index 2884d5f9d6f..4e0d917176a 100644 --- a/Resources/Prototypes/GameRules/variation.yml +++ b/Resources/Prototypes/GameRules/variation.yml @@ -4,7 +4,7 @@ id: BaseVariationPass parent: BaseGameRule abstract: true - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationVariationPassRule @@ -13,14 +13,14 @@ - type: entity id: BasicPoweredLightVariationPass parent: BaseVariationPass - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PoweredLightVariationPass - type: entity id: SolidWallRustingVariationPass parent: BaseVariationPass - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WallReplaceVariationPass - type: EntityReplaceVariationPass @@ -32,7 +32,7 @@ - type: entity id: ReinforcedWallRustingVariationPass parent: BaseVariationPass - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: ReinforcedWallReplaceVariationPass - type: EntityReplaceVariationPass @@ -44,7 +44,7 @@ - type: entity id: BasicTrashVariationPass parent: BaseVariationPass - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntitySpawnVariationPass tilesPerEntityAverage: 35 @@ -105,7 +105,7 @@ - type: entity id: BasicPuddleMessVariationPass parent: BaseVariationPass - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PuddleMessVariationPass randomPuddleSolutionFill: RandomFillTrashPuddle @@ -113,7 +113,7 @@ - type: entity id: BloodbathPuddleMessVariationPass parent: BaseVariationPass - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: PuddleMessVariationPass tilesPerSpillAverage: 150 @@ -123,7 +123,7 @@ - type: entity id: CutWireVariationPass parent: BaseVariationPass - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: CutWireVariationPass wireCutChance: 0.01 diff --git a/Resources/Prototypes/Guidebook/rules.yml b/Resources/Prototypes/Guidebook/rules.yml new file mode 100644 index 00000000000..a59af2c5edc --- /dev/null +++ b/Resources/Prototypes/Guidebook/rules.yml @@ -0,0 +1,362 @@ +- type: guideEntry # Default for forks and stuff. Should not be listed anywhere if the server is using a custom ruleset. + id: DefaultRuleset + name: guide-entry-rules + text: "/ServerInfo/Guidebook/ServerRules/DefaultRules.xml" + +- type: guideEntry + id: CoreRuleset + name: guide-entry-rules-core-only + priority: 0 + text: "/ServerInfo/Guidebook/ServerRules/WizDenCoreOnlyRules.xml" + +- type: guideEntry + id: StandardRuleset + name: guide-entry-rules-lrp + priority: 5 + text: "/ServerInfo/Guidebook/ServerRules/WizDenLRPRules.xml" + +- type: guideEntry + id: MRPRuleset + name: guide-entry-rules-mrp + priority: 10 + text: "/ServerInfo/Guidebook/ServerRules/WizDenMRPRules.xml" + +- type: guideEntry + id: RoleTypes + name: guide-entry-rules-role-types + priority: 20 + text: "/ServerInfo/Guidebook/ServerRules/RoleTypes.xml" + +- type: guideEntry + id: CoreRules + name: guide-entry-rules-core + priority: 30 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC0.xml" + children: + - RuleC1 + - RuleC2 + - RuleC3 + - RuleC4 + - RuleC5 + - RuleC6 + - RuleC7 + - RuleC8 + - RuleC9 + - RuleC10 + - RuleC11 + - RuleC12 + - RuleC13 + - RuleC14 + +- type: guideEntry + id: RuleC1 + name: guide-entry-rules-c1 + priority: 1 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC1Admins.xml" + +- type: guideEntry + id: RuleC2 + name: guide-entry-rules-c2 + priority: 2 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC2DBAD.xml" + +- type: guideEntry + id: RuleC3 + name: guide-entry-rules-c3 + priority: 3 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC3NoHate.xml" + +- type: guideEntry + id: RuleC4 + name: guide-entry-rules-c4 + priority: 4 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC4NoERP.xml" + +- type: guideEntry + id: RuleC5 + name: guide-entry-rules-c5 + priority: 5 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC5Metacomms.xml" + +- type: guideEntry + id: RuleC6 + name: guide-entry-rules-c6 + priority: 6 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC6BanEvasion.xml" + +- type: guideEntry + id: RuleC7 + name: guide-entry-rules-c7 + priority: 7 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC7EnglishOnly.xml" + +- type: guideEntry + id: RuleC8 + name: guide-entry-rules-c8 + priority: 8 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC8Exploits.xml" + +- type: guideEntry + id: RuleC9 + name: guide-entry-rules-c9 + priority: 9 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC9Multikey.xml" + +- type: guideEntry + id: RuleC10 + name: guide-entry-rules-c10 + priority: 10 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC10AHelp.xml" + +- type: guideEntry + id: RuleC11 + name: guide-entry-rules-c11 + priority: 11 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC11AhelpThreats.xml" + +- type: guideEntry + id: RuleC12 + name: guide-entry-rules-c12 + priority: 12 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC12MinAge.xml" + +- type: guideEntry + id: RuleC13 + name: guide-entry-rules-c13 + priority: 13 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC13CharacterNames.xml" + +- type: guideEntry + id: RuleC14 + name: guide-entry-rules-c14 + priority: 14 + text: "/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC14ICinOOC.xml" + +- type: guideEntry + id: RoleplayRules + name: guide-entry-rules-roleplay + priority: 40 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR0.xml" + children: + - RuleR1 + - RuleR2 + - RuleR3 + - RuleR4 + - RuleR5 + - RuleR6 + - RuleR7 + - RuleR8 + - RuleR9 + - RuleR10 + - RuleR11 + - RuleR12 + - RuleR13 + - RuleR14 + - RuleR15 + +- type: guideEntry + id: RuleR1 + name: guide-entry-rules-r1 + priority: 1 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR1Silicons.xml" + +- type: guideEntry + id: RuleR2 + name: guide-entry-rules-r2 + priority: 2 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR2Familiars.xml" + +- type: guideEntry + id: RuleR3 + name: guide-entry-rules-r3 + priority: 3 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR3NormalRP.xml" + +- type: guideEntry + id: RuleR4 + name: guide-entry-rules-r4 + priority: 4 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR4Metashield.xml" + +- type: guideEntry + id: RuleR5 + name: guide-entry-rules-r5 + priority: 5 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR5Arrivals.xml" + +- type: guideEntry + id: RuleR6 + name: guide-entry-rules-r6 + priority: 6 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR6SelfAntag.xml" + +- type: guideEntry + id: RuleR7 + name: guide-entry-rules-r7 + priority: 7 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR7RoundStalling.xml" + +- type: guideEntry + id: RuleR8 + name: guide-entry-rules-r8 + priority: 8 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR8NoFriendlyAntag.xml" + +- type: guideEntry + id: RuleR9 + name: guide-entry-rules-r9 + priority: 9 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR9MassSabotage.xml" + +- type: guideEntry + id: RuleR10 + name: guide-entry-rules-r10 + priority: 10 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR10Subordination.xml" + +- type: guideEntry + id: RuleR11 + name: guide-entry-rules-r11 + priority: 11 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11Escalation.xml" + +- type: guideEntry + id: RuleR12 + name: guide-entry-rules-r12 + priority: 12 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR12RoleAbandonment.xml" + +- type: guideEntry + id: RuleR13 + name: guide-entry-rules-r13 + priority: 13 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR13PerformRole.xml" + +- type: guideEntry + id: RuleR14 + name: guide-entry-rules-r14 + priority: 14 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR14SecComStandard.xml" + +- type: guideEntry + id: RuleR15 + name: guide-entry-rules-r15 + priority: 15 + text: "/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR15SpaceLaw.xml" + +- type: guideEntry + id: SiliconRules + name: guide-entry-rules-silicon + priority: 50 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS0.xml" + children: + - RuleS1 + - RuleS2 + - RuleS3 + - RuleS4 + - RuleS5 + - RuleS6 + - RuleS7 + - RuleS8 + - RuleS9 + - RuleS10 + +- type: guideEntry + id: RuleS1 + name: guide-entry-rules-s1 + priority: 1 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS1Laws.xml" + +- type: guideEntry + id: RuleS2 + name: guide-entry-rules-s2 + priority: 2 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS2LawPriority.xml" + +- type: guideEntry + id: RuleS3 + name: guide-entry-rules-s3 + priority: 3 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS3LawRedefinition.xml" + +- type: guideEntry + id: RuleS4 + name: guide-entry-rules-s4 + priority: 4 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS4RequestChanges.xml" + +- type: guideEntry + id: RuleS5 + name: guide-entry-rules-s5 + priority: 5 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS5FreeSilicon.xml" + +- type: guideEntry + id: RuleS6 + name: guide-entry-rules-s6 + priority: 6 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS6UnreasonableOrders.xml" + +- type: guideEntry + id: RuleS7 + name: guide-entry-rules-s7 + priority: 7 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS7Consistency.xml" + +- type: guideEntry + id: RuleS8 + name: guide-entry-rules-s8 + priority: 8 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS8DefaultCrewDefinition.xml" + +- type: guideEntry + id: RuleS9 + name: guide-entry-rules-s9 + priority: 9 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS9DefaultHarmDefinition.xml" + +- type: guideEntry + id: RuleS10 + name: guide-entry-rules-s10 + priority: 10 + text: "/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS10OrderConflicts.xml" + +- type: guideEntry + id: SpaceLaw + name: guide-entry-rules-space-law + priority: 60 + text: "/ServerInfo/Guidebook/ServerRules/SpaceLaw/SpaceLaw.xml" + children: + - SpaceLawControlledSubstances + - SpaceLawRestrictedGear + - SpaceLawRestrictedWeapons + +- type: guideEntry + id: SpaceLawControlledSubstances + name: guide-entry-rules-sl-controlled-substances + priority: 20 + text: "/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLControlledSubstances.xml" + +- type: guideEntry + id: SpaceLawRestrictedGear + name: guide-entry-rules-sl-restricted-gear + priority: 30 + text: "/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLRestrictedGear.xml" + +- type: guideEntry + id: SpaceLawRestrictedWeapons + name: guide-entry-rules-sl-restricted-weapons + priority: 40 + text: "/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLRestrictedWeapons.xml" + +- type: guideEntry + id: BanTypes + name: guide-entry-rules-ban-types + priority: 90 + text: "/ServerInfo/Guidebook/ServerRules/BanTypes.xml" + +- type: guideEntry + id: BanDurations + name: guide-entry-rules-ban-durations + priority: 100 + text: "/ServerInfo/Guidebook/ServerRules/BanDurations.xml" diff --git a/Resources/Prototypes/Guidebook/ss14.yml b/Resources/Prototypes/Guidebook/ss14.yml index c1017fefcae..5b1f1dd8f97 100644 --- a/Resources/Prototypes/Guidebook/ss14.yml +++ b/Resources/Prototypes/Guidebook/ss14.yml @@ -3,6 +3,7 @@ name: guide-entry-ss14 text: "/ServerInfo/Guidebook/SpaceStation14.xml" children: + - SpaceLaw - Controls - Jobs - Survival diff --git a/Resources/Prototypes/Magic/event_spells.yml b/Resources/Prototypes/Magic/event_spells.yml index e59e1b2db88..742c187d717 100644 --- a/Resources/Prototypes/Magic/event_spells.yml +++ b/Resources/Prototypes/Magic/event_spells.yml @@ -2,7 +2,7 @@ id: ActionSummonGhosts name: Summon Ghosts description: Makes all current ghosts permanently invisible - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 120 diff --git a/Resources/Prototypes/Magic/forcewall_spells.yml b/Resources/Prototypes/Magic/forcewall_spells.yml index d3d8fef7608..a047a4a6f77 100644 --- a/Resources/Prototypes/Magic/forcewall_spells.yml +++ b/Resources/Prototypes/Magic/forcewall_spells.yml @@ -2,7 +2,7 @@ id: ActionForceWall name: Forcewall description: Creates a magical barrier. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 10 diff --git a/Resources/Prototypes/Magic/knock_spell.yml b/Resources/Prototypes/Magic/knock_spell.yml index e2c3dcfd4c7..a0e22ec8f4b 100644 --- a/Resources/Prototypes/Magic/knock_spell.yml +++ b/Resources/Prototypes/Magic/knock_spell.yml @@ -2,7 +2,7 @@ id: ActionKnock name: Knock description: This spell opens nearby doors. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 10 diff --git a/Resources/Prototypes/Magic/projectile_spells.yml b/Resources/Prototypes/Magic/projectile_spells.yml index b8db7557bba..e2697c59b18 100644 --- a/Resources/Prototypes/Magic/projectile_spells.yml +++ b/Resources/Prototypes/Magic/projectile_spells.yml @@ -2,7 +2,7 @@ id: ActionFireball name: Fireball description: Fires an explosive fireball towards the clicked location. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Magic - type: WorldTargetAction @@ -29,7 +29,7 @@ parent: ActionFireball name: Fireball II description: Fires a fireball, but faster! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WorldTargetAction useDelay: 10 @@ -52,7 +52,7 @@ parent: ActionFireball name: Fireball III description: The fastest fireball in the west! - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WorldTargetAction useDelay: 8 diff --git a/Resources/Prototypes/Magic/rune_spells.yml b/Resources/Prototypes/Magic/rune_spells.yml index 42022f57850..da072004b1f 100644 --- a/Resources/Prototypes/Magic/rune_spells.yml +++ b/Resources/Prototypes/Magic/rune_spells.yml @@ -2,7 +2,7 @@ id: ActionFlashRune name: Flash Rune description: Summons a rune that flashes if used. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 10 @@ -17,7 +17,7 @@ id: ActionExplosionRune name: Explosion Rune description: Summons a rune that explodes if used. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 20 @@ -32,7 +32,7 @@ id: ActionIgniteRune name: Ignite Rune description: Summons a rune that ignites if used. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 15 @@ -47,7 +47,7 @@ id: ActionStunRune name: Stun Rune description: Summons a rune that stuns if used. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 10 diff --git a/Resources/Prototypes/Magic/smite_spells.yml b/Resources/Prototypes/Magic/smite_spells.yml index e629e565058..a0875211307 100644 --- a/Resources/Prototypes/Magic/smite_spells.yml +++ b/Resources/Prototypes/Magic/smite_spells.yml @@ -2,7 +2,7 @@ id: ActionSmite name: Smite description: Instantly gibs a target. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntityTargetAction useDelay: 60 diff --git a/Resources/Prototypes/Magic/spawn_spells.yml b/Resources/Prototypes/Magic/spawn_spells.yml index 3f8148b83cb..2800499fcab 100644 --- a/Resources/Prototypes/Magic/spawn_spells.yml +++ b/Resources/Prototypes/Magic/spawn_spells.yml @@ -2,7 +2,7 @@ id: ActionSpawnMagicarpSpell name: Summon Magicarp description: This spell summons three Magi-Carp to your aid! May or may not turn on user. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WorldTargetAction useDelay: 10 diff --git a/Resources/Prototypes/Magic/staves.yml b/Resources/Prototypes/Magic/staves.yml index ef94a3910fd..d9b71e39a85 100644 --- a/Resources/Prototypes/Magic/staves.yml +++ b/Resources/Prototypes/Magic/staves.yml @@ -34,7 +34,7 @@ - type: entity id: ActionRgbLight - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: EntityTargetAction whitelist: { components: [ PointLight ] } diff --git a/Resources/Prototypes/Magic/teleport_spells.yml b/Resources/Prototypes/Magic/teleport_spells.yml index cc89cf8ee0d..1439dcea17e 100644 --- a/Resources/Prototypes/Magic/teleport_spells.yml +++ b/Resources/Prototypes/Magic/teleport_spells.yml @@ -2,7 +2,7 @@ id: ActionBlink name: Blink description: Teleport to the clicked location. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: WorldTargetAction useDelay: 10 diff --git a/Resources/Prototypes/Magic/utility_spells.yml b/Resources/Prototypes/Magic/utility_spells.yml index dccdda37898..6c0b08d9b63 100644 --- a/Resources/Prototypes/Magic/utility_spells.yml +++ b/Resources/Prototypes/Magic/utility_spells.yml @@ -2,7 +2,7 @@ id: ActionChargeSpell name: Charge description: Adds a charge back to your wand - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction useDelay: 30 diff --git a/Resources/Prototypes/Nyanotrasen/Actions/types.yml b/Resources/Prototypes/Nyanotrasen/Actions/types.yml index cab8f4a1f4e..9bdb13397a6 100644 --- a/Resources/Prototypes/Nyanotrasen/Actions/types.yml +++ b/Resources/Prototypes/Nyanotrasen/Actions/types.yml @@ -2,7 +2,7 @@ id: ActionEatMouse name: action-name-eat-mouse description: action-description-eat-mouse - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction icon: Nyanotrasen/Icons/verbiconfangs.png @@ -12,7 +12,7 @@ id: ActionHairball name: action-name-hairball description: action-description-hairball - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction charges: 1 diff --git a/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/backpack.yml b/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/backpack.yml index 810f9ec03b6..c4843240ebb 100644 --- a/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/backpack.yml +++ b/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/backpack.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackScience id: ClothingBackpackMantisFilled components: diff --git a/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml b/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml index 88e33cdd252..6f4e2fea626 100644 --- a/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml +++ b/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/duffelbag.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackDuffelScience id: ClothingBackpackDuffelMantisFilled components: diff --git a/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/satchel.yml b/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/satchel.yml index e90759ac8fb..50106b11823 100644 --- a/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/satchel.yml +++ b/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Backpacks/StarterGear/satchel.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: ClothingBackpackSatchelScience id: ClothingBackpackSatchelMantisFilled components: diff --git a/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Books/lore.yml b/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Books/lore.yml index 6c3eb06108f..2a8173dbec2 100644 --- a/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Books/lore.yml +++ b/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Books/lore.yml @@ -2,7 +2,7 @@ name: epistemics book parent: BookRandom # placeholder id: BookSalvageEpistemics - noSpawn: true + categories: [ HideSpawnMenu ] description: 'A metallic hardcover book.' - type: entity diff --git a/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Paper/salvage_lore.yml b/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Paper/salvage_lore.yml index f37c3bbdb3e..dbccfd4484b 100644 --- a/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Paper/salvage_lore.yml +++ b/Resources/Prototypes/Nyanotrasen/Catalog/Fills/Paper/salvage_lore.yml @@ -18,7 +18,7 @@ - type: entity id: PaperWrittenSalvageLoreGaming1 - noSpawn: true # keep this from spamming spawn sheet + categories: [ HideSpawnMenu ] # keep this from spamming spawn sheet suffix: "Salvage: Lore: Gaming 1" parent: Paper components: @@ -31,7 +31,7 @@ - Alexander - type: entity id: PaperWrittenSalvageLoreGaming2 - noSpawn: true # keep this from spamming spawn sheet + categories: [ HideSpawnMenu ] # keep this from spamming spawn sheet suffix: "Salvage: Lore: Gaming 2" parent: Paper components: @@ -51,7 +51,7 @@ What even are you trying to do here, Leah? - Your Friendly DM - type: entity id: PaperWrittenSalvageLoreGaming3 - noSpawn: true # keep this from spamming spawn sheet + categories: [ HideSpawnMenu ] # keep this from spamming spawn sheet suffix: "Salvage: Lore: Gaming 3" parent: Paper components: @@ -65,7 +65,7 @@ Oh dear goodness they just started randomly killing everybody - type: entity id: PaperWrittenSalvageLoreGaming4 - noSpawn: true # keep this from spamming spawn sheet + categories: [ HideSpawnMenu ] # keep this from spamming spawn sheet suffix: "Salvage: Lore: Gaming 4" parent: Paper components: diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hardsuit-helmets.yml index 3896cd1ef1b..9625ec95d6b 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hardsuit-helmets.yml @@ -1,7 +1,7 @@ - type: entity parent: ClothingHeadHelmetHardsuitRd id: ClothingHeadHelmetHardsuitMystagogue - noSpawn: true + categories: [ HideSpawnMenu ] name: mystagogue's hardsuit helmet description: Lightweight hardsuit helmet that has a galaxy-first psionic passthrough system. components: @@ -15,7 +15,7 @@ - type: entity parent: ClothingHeadHelmetHardsuitSyndie id: ClothingHeadHelmetHardsuitSyndieReverseEngineered - noSpawn: true + categories: [ HideSpawnMenu ] name: SA-122 combat hardsuit helmet description: An advanced hardsuit helmet designed for work in special operations. components: @@ -27,7 +27,7 @@ - type: entity parent: ClothingHeadHelmetHardsuitCybersun id: ClothingHeadHelmetHardsuitJuggernautReverseEngineered - noSpawn: true + categories: [ HideSpawnMenu ] name: SA-126 combat hardsuit helmet description: An assault hardsuit helmet featuring a top-secret translucent polymer. components: diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Effects/lightning.yml b/Resources/Prototypes/Nyanotrasen/Entities/Effects/lightning.yml index 35f5ee06e94..e6a3a575a23 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Effects/lightning.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Effects/lightning.yml @@ -2,7 +2,7 @@ parent: BaseLightning id: LightningNoospheric name: noospheric lightning - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Electrified enabled: false diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/ghost_roles.yml index a21976fa7a5..d0207e362e3 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/ghost_roles.yml @@ -3,7 +3,7 @@ name: ghost role spawn point suffix: Ifrit parent: MarkerBase - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GhostRoleMobSpawner prototype: MobIfritFamiliar @@ -22,7 +22,7 @@ id: SpawnPointGhostFugitive name: ghost role spawn point parent: MarkerBase - noSpawn: true + categories: [ HideSpawnMenu ] components: # - type: GhostRoleMobSpawner # prototype: MobHumanFugitive # Todo @@ -56,7 +56,7 @@ # name: ghost role spawn point # suffix: Vampire spider # parent: MarkerBase -# noSpawn: true +# categories: [ HideSpawnMenu ] # components: # - type: GhostRoleMobSpawner # prototype: MobGiantSpiderVampireAngry diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/special.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/special.yml index 70628ec4e51..d133377e01b 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/special.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/special.yml @@ -2,7 +2,7 @@ id: MobObserverTelegnostic name: telegnostic projection description: Ominous. Placeholder sprite. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: Sprite overrideContainerOcclusion: true # Ghosts always show up regardless of where they're contained. diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/Oni.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/Oni.yml index 8a5663dce45..8ac15fd865c 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/Oni.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/Oni.yml @@ -53,5 +53,5 @@ name: Urist McOni parent: MobHumanDummy id: MobOniDummy - noSpawn: true + categories: [ HideSpawnMenu ] description: A dummy oni meant to be used in character setup. diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml index 44779fe9508..3b1776d044a 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml @@ -90,7 +90,7 @@ name: Urist McHands parent: MobHumanDummy id: MobFelinidDummy - noSpawn: true + categories: [ HideSpawnMenu ] description: A dummy felinid meant to be used in character setup. components: - type: HumanoidAppearance diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Consumable/Food/ration.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Consumable/Food/ration.yml index 177d6151ccb..bd08bec9ddc 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Consumable/Food/ration.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Consumable/Food/ration.yml @@ -1,6 +1,6 @@ # PSB, Prepacked Sustenance Bar. With variety. - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: FoodPacketTrash id: FoodPSBTrash name: psb wrapper diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Mail/base_mail.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Mail/base_mail.yml index 75007db11ca..320129fa554 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Mail/base_mail.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Mail/base_mail.yml @@ -111,7 +111,7 @@ # This empty parcel is allowed to exist and evade the tests for the admin # mailto command. - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMail id: MailAdminFun suffix: adminfun diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Weapons/Guns/Projectiles/shotgun.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Weapons/Guns/Projectiles/shotgun.yml index 42826c94cba..47d65ce8f7c 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Weapons/Guns/Projectiles/shotgun.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Weapons/Guns/Projectiles/shotgun.yml @@ -1,7 +1,7 @@ - type: entity id: PelletShotgunSoulbreaker name: pellet (.50 soulbreaker) - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseBulletPractice components: - type: Sprite diff --git a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml index de9ea15a699..8612fb0fec7 100644 --- a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml +++ b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml @@ -2,7 +2,7 @@ - type: entity id: NoosphericStorm parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent startAnnouncement: true @@ -25,7 +25,7 @@ - type: MidRoundAntagRule - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMidRoundAntag id: RatKingSpawn components: @@ -33,7 +33,7 @@ spawner: SpawnPointGhostRatKing - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseMidRoundAntag id: ParadoxAnomalySpawn components: @@ -44,7 +44,7 @@ - type: entity id: BaseGlimmerEvent parent: BaseGameRule - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent # Favor glimmer events just a little more than regular events. @@ -56,7 +56,7 @@ - type: entity id: MundaneDischarge parent: BaseGlimmerEvent - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent reoccurrenceDelay: 15 @@ -69,7 +69,7 @@ - type: entity id: NoosphericZap parent: BaseGlimmerEvent - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 25 # Guaranteed to happen every once in a while, but with intervals between incidents @@ -81,7 +81,7 @@ - type: entity id: NoosphericFry parent: BaseGlimmerEvent - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GlimmerEvent minimumGlimmer: 550 @@ -91,7 +91,7 @@ - type: entity id: PsionicCatGotYourTongue parent: BaseGlimmerEvent - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GlimmerEvent minimumGlimmer: 400 @@ -103,7 +103,7 @@ - type: entity id: MassMindSwap parent: BaseGlimmerEvent - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GlimmerEvent minimumGlimmer: 900 @@ -116,7 +116,7 @@ abstract: true parent: BaseGlimmerEvent id: BaseGlimmerSignaturesEvent - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GlimmerEvent minimumGlimmer: 300 @@ -126,7 +126,7 @@ - type: entity id: GlimmerWispSpawn parent: BaseGlimmerSignaturesEvent - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GlimmerMobRule mobPrototype: MobGlimmerWisp @@ -134,7 +134,7 @@ - type: entity parent: BaseGlimmerSignaturesEvent id: FreeProber - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: FreeProberRule @@ -142,7 +142,7 @@ - type: entity parent: BaseGlimmerSignaturesEvent id: GlimmerRandomSentience - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: StationEvent weight: 7 @@ -158,7 +158,7 @@ - type: entity parent: BaseGlimmerSignaturesEvent id: GlimmerRevenantSpawn - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GlimmerEvent minimumGlimmer: 450 @@ -170,7 +170,7 @@ - type: entity parent: BaseGlimmerSignaturesEvent id: GlimmerMiteSpawn - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: GlimmerEvent minimumGlimmer: 250 diff --git a/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml b/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml index e6e497003d5..f9304c4c3b8 100644 --- a/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml +++ b/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml @@ -1,5 +1,5 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseTraitorStealObjective id: MantisKnifeStealObjective components: @@ -14,7 +14,7 @@ # parent: BaseTraitorObjective # name: objective-condition-become-golem-title # description: objective-condition-become-golem-description. -# noSpawn: true +# categories: [ HideSpawnMenu ] # components: # - type: NotJobRequirement # job: Chaplain @@ -33,7 +33,7 @@ - type: entity id: RaiseGlimmerObjective parent: BaseTraitorObjective - noSpawn: true + categories: [ HideSpawnMenu ] name: Raise Glimmer. description: Get the glimmer above the specified amount. components: diff --git a/Resources/Prototypes/Objectives/dragon.yml b/Resources/Prototypes/Objectives/dragon.yml index 2cf7eb292f7..70cb4643de8 100644 --- a/Resources/Prototypes/Objectives/dragon.yml +++ b/Resources/Prototypes/Objectives/dragon.yml @@ -13,7 +13,7 @@ - DragonRole - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseDragonObjective id: CarpRiftsObjective components: @@ -30,7 +30,7 @@ - type: CarpRiftsCondition - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseDragonObjective, BaseSurviveObjective] id: DragonSurviveObjective name: Survive diff --git a/Resources/Prototypes/Objectives/ninja.yml b/Resources/Prototypes/Objectives/ninja.yml index fb94f2b3788..864bff25c6f 100644 --- a/Resources/Prototypes/Objectives/ninja.yml +++ b/Resources/Prototypes/Objectives/ninja.yml @@ -13,7 +13,7 @@ - NinjaRole - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseNinjaObjective id: DoorjackObjective components: @@ -29,7 +29,7 @@ - type: DoorjackCondition - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseNinjaObjective id: StealResearchObjective description: Your gloves can be used to hack a research server and steal its precious data. If epistemics has been slacking you'll have to get to work. # DeltaV - Epistemics Department replacing Science @@ -45,7 +45,7 @@ - type: StealResearchCondition - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseNinjaObjective, BaseCodeObjective] id: SpiderChargeObjective description: This bomb can be detonated in a specific location. Note that the bomb will not work anywhere else! @@ -56,7 +56,7 @@ state: icon - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseNinjaObjective, BaseSurviveObjective] id: NinjaSurviveObjective name: Survive @@ -68,7 +68,7 @@ state: icon - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseNinjaObjective, BaseCodeObjective] id: TerrorObjective name: Call in a threat @@ -80,7 +80,7 @@ state: red_phone - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseNinjaObjective, BaseCodeObjective] id: MassArrestObjective name: Set everyone to wanted diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml index 18154850973..e556171a1fa 100644 --- a/Resources/Prototypes/Objectives/thief.yml +++ b/Resources/Prototypes/Objectives/thief.yml @@ -55,7 +55,7 @@ # Collections - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealCollectionObjective id: FigurineStealCollectionObjective components: @@ -67,7 +67,7 @@ difficulty: 0.25 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealCollectionObjective id: HeadCloakStealCollectionObjective components: @@ -79,7 +79,7 @@ difficulty: 1.5 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealCollectionObjective id: HeadBedsheetStealCollectionObjective components: @@ -91,7 +91,7 @@ difficulty: 1.0 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealCollectionObjective id: StampStealCollectionObjective components: @@ -103,7 +103,7 @@ difficulty: 1.0 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealCollectionObjective id: DoorRemoteStealCollectionObjective components: @@ -115,7 +115,7 @@ difficulty: 1.5 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealCollectionObjective id: TechnologyDiskStealCollectionObjective components: @@ -130,7 +130,7 @@ difficulty: 0.8 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealCollectionObjective id: IDCardsStealCollectionObjective components: @@ -145,7 +145,7 @@ - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealCollectionObjective id: LAMPStealCollectionObjective components: @@ -163,7 +163,7 @@ # steal item - type: entity #Security subgroup - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: ForensicScannerStealObjective components: @@ -175,7 +175,7 @@ difficulty: 1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: FlippoEngravedLighterStealObjective components: @@ -187,7 +187,7 @@ difficulty: 0.8 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: ClothingHeadHatWardenStealObjective components: @@ -197,7 +197,7 @@ difficulty: 1.2 - type: entity #Medical subgroup - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: ClothingOuterHardsuitVoidParamedStealObjective components: @@ -209,7 +209,7 @@ difficulty: 1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: MedicalTechFabCircuitboardStealObjective components: @@ -221,7 +221,7 @@ difficulty: 1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: ClothingHeadsetAltMedicalStealObjective components: @@ -233,7 +233,7 @@ difficulty: 1 - type: entity #Engineering subgroup - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: FireAxeStealObjective components: @@ -245,7 +245,7 @@ difficulty: 0.8 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: AmePartFlatpackStealObjective components: @@ -257,7 +257,7 @@ difficulty: 1 - type: entity #Cargo subgroup - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: ExpeditionsCircuitboardStealObjective components: @@ -269,7 +269,7 @@ difficulty: 0.7 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: CargoShuttleCircuitboardStealObjective components: @@ -281,7 +281,7 @@ difficulty: 0.7 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: SalvageShuttleCircuitboardStealObjective components: @@ -293,7 +293,7 @@ difficulty: 0.7 - type: entity #Service subgroup - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: ClothingEyesHudBeerStealObjective components: @@ -305,7 +305,7 @@ difficulty: 0.3 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: BibleStealObjective components: @@ -317,7 +317,7 @@ difficulty: 0.4 - type: entity #Other subgroup - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: ClothingNeckGoldmedalStealObjective components: @@ -329,7 +329,7 @@ difficulty: 1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealObjective id: ClothingNeckClownmedalStealObjective components: @@ -343,7 +343,7 @@ # Structures - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealStructureObjective id: NuclearBombStealObjective components: @@ -355,7 +355,7 @@ difficulty: 2.5 #Good luck - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealStructureObjective id: FaxMachineCaptainStealObjective components: @@ -367,7 +367,7 @@ difficulty: 2 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealStructureObjective id: ChemDispenserStealObjective components: @@ -379,7 +379,7 @@ difficulty: 1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealStructureObjective id: XenoArtifactStealObjective components: @@ -391,7 +391,7 @@ difficulty: 0.5 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealStructureObjective id: FreezerHeaterStealObjective components: @@ -403,7 +403,7 @@ difficulty: 0.5 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealStructureObjective id: TegStealObjective components: @@ -415,7 +415,7 @@ difficulty: 1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealStructureObjective id: BoozeDispenserStealObjective components: @@ -427,7 +427,7 @@ difficulty: 0.5 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealStructureObjective id: AltarNanotrasenStealObjective components: @@ -439,7 +439,7 @@ difficulty: 0.5 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealStructureObjective id: PlantRDStealObjective components: @@ -453,7 +453,7 @@ # Animal - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealAnimalObjective id: IanStealObjective components: @@ -465,7 +465,7 @@ difficulty: 2.5 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealAnimalObjective id: BingusStealObjective components: @@ -475,7 +475,7 @@ difficulty: 1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealAnimalObjective id: McGriffStealObjective components: @@ -487,7 +487,7 @@ difficulty: 1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealAnimalObjective id: WalterStealObjective components: @@ -499,7 +499,7 @@ difficulty: 1 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealAnimalObjective id: MortyStealObjective components: @@ -509,7 +509,7 @@ difficulty: 0.5 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealAnimalObjective id: RenaultStealObjective components: @@ -521,7 +521,7 @@ difficulty: 2 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealAnimalObjective id: ShivaStealObjective components: @@ -533,7 +533,7 @@ difficulty: 2 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseThiefStealAnimalObjective id: TropicoStealObjective components: @@ -547,7 +547,7 @@ # Escape - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseThiefObjective, BaseLivingObjective] id: EscapeThiefShuttleObjective name: Escape to centcom alive and unrestrained. diff --git a/Resources/Prototypes/Objectives/traitor.yml b/Resources/Prototypes/Objectives/traitor.yml index b00d12529af..34efe5a166c 100644 --- a/Resources/Prototypes/Objectives/traitor.yml +++ b/Resources/Prototypes/Objectives/traitor.yml @@ -34,7 +34,7 @@ limit: 2 # there is usually only 1 of each steal objective, have 2 max for drama - type: entity # Head of Security steal objective. - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseTraitorStealObjective id: HoSAntiqueWeaponStealObjective components: @@ -50,7 +50,7 @@ # state - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseTraitorObjective, BaseLivingObjective] id: EscapeShuttleObjective name: Escape to centcom alive and unrestrained. @@ -64,7 +64,7 @@ - type: EscapeShuttleCondition ##- type: entity # DeltaV -# noSpawn: true +# categories: [ HideSpawnMenu ] # parent: BaseTraitorObjective # id: DieObjective # name: Die a glorious death @@ -83,7 +83,7 @@ # - type: DieCondition #- type: entity -# noSpawn: true +# categories: [ HideSpawnMenu ] # parent: [BaseTraitorObjective, BaseLivingObjective] # id: HijackShuttleObjective # name: Hijack emergency shuttle @@ -99,7 +99,7 @@ # kill - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseTraitorObjective, BaseKillObjective] id: KillRandomPersonObjective description: Do it however you like, just make sure they don't make it to centcom. @@ -112,7 +112,7 @@ - type: PickRandomPerson - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseTraitorObjective, BaseKillObjective] id: KillRandomHeadObjective description: We need this head gone and you probably know why. Good luck, agent. @@ -133,7 +133,7 @@ # social - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseTraitorSocialObjective, BaseKeepAliveObjective] id: RandomTraitorAliveObjective description: Identify yourself at your own risk. We just need them alive. @@ -145,7 +145,7 @@ - type: RandomTraitorAlive - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: [BaseTraitorSocialObjective, BaseHelpProgressObjective] id: RandomTraitorProgressObjective description: Identify yourself at your own risk. We just need them to succeed. @@ -171,7 +171,7 @@ owner: job-name-cmo - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseCMOStealObjective id: CMOHyposprayStealObjective components: @@ -179,7 +179,7 @@ stealGroup: Hypospray - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseCMOStealObjective id: CMOCrewMonitorStealObjective components: @@ -199,7 +199,7 @@ owner: job-name-rd - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseRDStealObjective id: RDHardsuitStealObjective components: @@ -210,7 +210,7 @@ difficulty: 3 - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseRDStealObjective id: HandTeleporterStealObjective components: @@ -220,7 +220,7 @@ ## hos - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseTraitorStealObjective id: SecretDocumentsStealObjective components: @@ -236,7 +236,7 @@ ## ce - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseTraitorStealObjective id: MagbootsStealObjective components: @@ -249,7 +249,7 @@ ## qm - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseTraitorStealObjective id: ClipboardStealObjective components: @@ -262,7 +262,7 @@ ## hop - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseTraitorStealObjective id: CorgiMeatStealObjective components: @@ -288,7 +288,7 @@ job: Captain - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseCaptainObjective id: CaptainIDStealObjective components: @@ -296,7 +296,7 @@ stealGroup: CaptainIDCard - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseCaptainObjective id: CaptainJetpackStealObjective components: @@ -304,7 +304,7 @@ stealGroup: JetpackCaptainFilled - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseCaptainObjective id: CaptainGunStealObjective components: @@ -313,7 +313,7 @@ owner: job-name-captain - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseCaptainObjective id: NukeDiskStealObjective components: @@ -328,7 +328,7 @@ owner: objective-condition-steal-station - type: entity - noSpawn: true + categories: [ HideSpawnMenu ] parent: BaseTraitorStealObjective id: StealSupermatterSliverObjective components: diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml index c7c659bc531..6aa6d02aecb 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml @@ -41,7 +41,7 @@ id: ActionMimeInvisibleWall name: Create Invisible Wall description: Create an invisible wall in front of you, if placeable there. - noSpawn: true + categories: [ HideSpawnMenu ] components: - type: InstantAction priority: -1 diff --git a/Resources/ServerInfo/Guidebook/ServerRules/BanDurations.xml b/Resources/ServerInfo/Guidebook/ServerRules/BanDurations.xml new file mode 100644 index 00000000000..2c85346b49d --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/BanDurations.xml @@ -0,0 +1,17 @@ +<Document> + # Ban Durations + + Bans can be appealed at forum.ss14.io in the ban appeals section. + + ## Temporary + Temporary bans will be lifted automatically after a certain amount of time. If they are a game ban, they will tell you how much time is remaining when you try to connect. + + ## Indefinite + These bans will only be removed on a successful appeal on the forums. Any ban which doesn't tell you when it expires and doesn't specify otherwise can be presumed to be an indefinite ban. + + ## Voucher + This is an indefinite ban which may only be appealed both with a successful appeal and which require a voucher of good behavior from the administrative team of a well-known or at least decently active SS13/SS14 server in order for the appeal to be considered. Voucher bans typically cannot be appealed for at least six months after being issued. Without a voucher, a player can only attempt to appeal a voucher ban once, and only if the ban was inappropriately placed. Voucher bans are typically only placed as a result of an unsuccessful appeal of an indefinite game ban by players with a history of bans and of causing issues. + + ## Permanent + This is a ban that is only appealable if the ban was inappropriately placed, including if the ban should not have been permanent. If the result of the appeal is that the ban was appropriately placed, the ban may not be appealed again and will not be lifted. These bans are extremely rare, but are applied to players who continually cause problems even after a voucher ban or users who have completely unacceptable behavior may be permanently removed. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/BanTypes.xml b/Resources/ServerInfo/Guidebook/ServerRules/BanTypes.xml new file mode 100644 index 00000000000..b10ea3c393b --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/BanTypes.xml @@ -0,0 +1,11 @@ +<Document> + # Ban Types + + Bans can be appealed at forum.ss14.io in the ban appeals section. + + ## Role Ban + Also called a "job ban", this ban prevents your character from joining or late-joining a round as one or more jobs or roles. These are often used in response to problematic behavior in particular departments or address gross inexperience in important roles such as heads of staff. These bans do not mechanically prevent you from switching to the role during a round or acting as that role, but doing so is considered ban evasion. + + ## Game Ban + Also called a "server ban", this ban prevents you from connecting to all Wizard's Den servers. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC0.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC0.xml new file mode 100644 index 00000000000..7b8cfbcf61e --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC0.xml @@ -0,0 +1,19 @@ +<Document> + # Core Rules + These rules apply at all times, including between rounds. + + - [textlink="1. Admins have final say" link="RuleC1"] + - [textlink="2. Don't be a dick" link="RuleC2"] + - [textlink="3. No Hate Speech or Discriminatory Language" link="RuleC3"] + - [textlink="4. No sexual content/themes, including erotic roleplay (ERP) and no shock content" link="RuleC4"] + - [textlink="5. Do not use out of game methods to communicate with other players" link="RuleC5"] + - [textlink="6. Do not attempt to evade bans" link="RuleC6"] + - [textlink="7. Only use English" link="RuleC7"] + - [textlink="8. Do not exploit the game, use cheats, or macros" link="RuleC8"] + - [textlink="9. Do not use multiple accounts, or alt accounts, and do not share accounts" link="RuleC9"] + - [textlink="10. Do not abuse or ignore admin messages" link="RuleC10"] + - [textlink="11. Do not threaten to ahelp other players or argue with them about rules" link="RuleC11"] + - [textlink="12. Players must be and act at least 16 years old" link="RuleC12"] + - [textlink="13. Use realistic character names, and do not use names of famous people" link="RuleC13"] + - [textlink="14. Do not use LOOC or OOC to share current round information" link="RuleC14"] +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC10AHelp.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC10AHelp.xml new file mode 100644 index 00000000000..2d639c5b84a --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC10AHelp.xml @@ -0,0 +1,29 @@ +<Document> + # Core Rule 10 - Do not abuse or ignore admin messages + Admin help, or "ahelp", is the system used by admins to communicate with specific players in the game. Only use admin help for things requiring admin attention. If you ignore messages admins send to you via ahelp, or disconnect during an ahelp, you may be banned. If you urgently need to leave during an ahelp, you may do so but will likely need to continue the ahelp on the forums. Do not admin check, be hostile/aggressive, request events, or spam. IC methods of contacting admins, like prayers, faxes, red phones, and banana phones, should be used when there is not an issue. + + Admins are not always online, but all ahelps are automatically relayed to discord. For various reasons, admins might not respond to an ahelp even if they've handled it. A lack of response does not necessarily mean that an ahelp was ignored. + + ## Should I ahelp X? + You can ahelp anytime you genuinely think a player is breaking a rule. Not all ahelps end up being for something that an admin needs to intervene in, but that's ok, admins would rather have people occasionally report things that turn out to not be an issue than miss reports for actual issues because someone was unsure, or get those reports late because someone waited until the end of the round to be more sure. + + The most common reason players give for not ahelping issues is that they don't want to waste admin time, but it only takes a few seconds for an admin to check if someone is an antagonist. If you are ahelping too many things, an admin will let you know. If you're not being told to stop reporting something or to report less things, then you can safely assume that you aren't causing any issues. + + # What should I include in an ahelp? + At a minimum, admins need to know what the issue is to be able to address an ahelp. Don't send ahelp messages with no information about what your question or the issue is. Messages like "hello" are often considered admin checking. + + If you can, an ideal ahelp message includes what the issue is along with who is causing it and their character's name if possible. + + # Examples + Appropriate uses of ahelp: + - reporting people who you think are violating rules, + - asking questions about rules, + - asking for a temporary exemption from a rule, and + - request a minor gimmick, like a TC trade or item spawn. + + Inappropriate uses of ahelp: + - checking if an admin is online, including sending messages without any information about the issue like "hello" or incomprehensible messages, + - being hostile or aggressive, + - requesting events, and + - spamming messages about the same issue. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC11AhelpThreats.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC11AhelpThreats.xml new file mode 100644 index 00000000000..47420264946 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC11AhelpThreats.xml @@ -0,0 +1,20 @@ +<Document> + # Core Rule 11 - Do not threaten to ahelp other players or argue with them about rules + Don't threaten to ahelp a player, don't tell them you are ahelping them, and don't tell them you did ahelp them. You can argue in character about Space Law, but do not argue about whether something is or is not against the rules. If you think someone is breaking a rule, ahelp them. If you don't think someone is breaking a rule, don't ahelp them. Either way, the best thing that you can do once you after is to continue in-character. + + ## Example Scenario 1 + You are a security officer and think someone who is causing a ton of problems for security is not an antag and is breaking the rules by doing so. + + [color=#a4885c]Good:[/color] Since you think they are breaking a rule, you ahelp them when you're able to. You continue in-character by arresting them for the crimes that they committed. + + [color=#a4885c]Bad:[/color] You decide not to ahelp them. You kill them and tell them "you're lucky I didn't report you to the admins". + + [color=#a4885c]Bad:[/color] Since you think they are breaking a rule, you ahelp them when you're able to. You arrest them for the crimes that they committed and tell them "I ahelped you so enjoy your ban". + + ## Example Scenario 2 + A mouse is using emotes to bypass speech restrictions. + + [color=#a4885c]Good:[/color] You ahelp them then respond in-character by acting like you can't understand what the mouse is doing. + + [color=#a4885c]Bad:[/color] You use in character chat to tell the mouse that it is breaking a rule. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC12MinAge.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC12MinAge.xml new file mode 100644 index 00000000000..baa30a09faf --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC12MinAge.xml @@ -0,0 +1,6 @@ +<Document> + # Core Rule 12 - Players must be and act at least 16 years old + All players must be at least 16 years old. Additionally, all players must act at least as mature as a 16 year old. Admins may ban someone who they believe is acting less mature than a 16 year old, even if the player is known to be significantly older than 16 years old. + + Anyone who connects to the servers is a player, even if they don't actually play in a round. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC13CharacterNames.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC13CharacterNames.xml new file mode 100644 index 00000000000..ec393ecdc17 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC13CharacterNames.xml @@ -0,0 +1,66 @@ +<Document> + # Core Rule 13 - Use realistic character names, and do not use names of famous people + - No names of people or characters from the real world + - No titles/honorifics + - Must follow all other rules (no slurs/sexual names/etc) + - Usernames, objects, random characters, very "low effort" names, "meta" names, or otherwise implausible names cannot be used as names. See examples below. + - Admin rulings on IC names are final and disputes should be done through the forums, not by refusing to comply with an admin + + ## Clarification on "Meta" Names + Meta names are ones which attempt to take advantage of some game mechanic or game design choice. "Urist McHands" is a meta name because it is the default name used for admin spawned humans. "Operator Whiskey" is a meta name because it follows the naming pattern of nuclear operatives. This rule is not intended to prevent things like nuclear operatives using a fake ID with names that appear to be nuclear operative names if they decide that they want to do that. + + ## Conventions and Examples + [color=#994444]Bad[/color] cannot be used by any species. [color=#449944]Acceptable[/color] names can be used by any species. + + Humans typically use the Firstname Lastname convention. + - [color=#449944]Acceptable:[/color] Tom Fisher + - [color=#449944]Acceptable:[/color] Spacey Chapman + - [color=#994444]Bad:[/color] Dr. Tom Fisher + - [color=#994444]Bad:[/color] Walter White + - [color=#994444]Bad:[/color] George Washington + - [color=#994444]Bad:[/color] Joe Biden + - [color=#994444]Bad:[/color] Ben Dover + - [color=#994444]Bad:[/color] Mike Hunt + + Dwarfs typically use the human convention in a viking theme. + - [color=#449944]Acceptable:[/color] Ingrid Firebreath + - [color=#449944]Acceptable:[/color] Erik Lightningclaw + + Lizards typically use the Verb-article-Noun convention. + - [color=#449944]Acceptable:[/color] Cleans-the-Airlocks + - [color=#994444]Bad:[/color] Bans-the-Admins + + Slimes typically have names that are onomonopia. A last name is optional. + - [color=#449944]Acceptable:[/color] Foolp Suub + - [color=#449944]Acceptable:[/color] Foolp + - [color=#994444]Bad:[/color] Slime + + Diona typically have calm, nature themed, Noun of Noun style names. + - [color=#449944]Acceptable:[/color] Petal of Tranquility + - [color=#449944]Acceptable:[/color] Garden of Relaxation + - [color=#994444]Bad:[/color] Tree but Alive + + Mothmen typically use latin sounding names, or light themed names. + - [color=#449944]Acceptable:[/color] Socrates Temnora + - [color=#449944]Acceptable:[/color] Sierra Lightseeker + - [color=#449944]Acceptable:[/color] James Nightflitter + + Arachnids typically use latin sounding names. + - [color=#449944]Acceptable:[/color] Argyroneta Reticulatus + - [color=#449944]Acceptable:[/color] Loxosceles Domesticus + - [color=#994444]Bad:[/color] Spider-Man + + Usernames, objects, random characters, very "low effort" names, "meta" names, or otherwise implausible names are not permitted. + - [color=#994444]Bad:[/color] XxRobustxX + - [color=#994444]Bad:[/color] SDpksSodjdfk + - [color=#994444]Bad:[/color] Lkdsoisgoieun + - [color=#994444]Bad:[/color] F4ith H3arth + - [color=#994444]Bad:[/color] Greytide + - [color=#994444]Bad:[/color] Passenger + - [color=#994444]Bad:[/color] Urist McHands + - [color=#994444]Bad:[/color] Admin + - [color=#994444]Bad:[/color] Game-Master + - [color=#994444]Bad:[/color] Joe Mamma + - [color=#994444]Bad:[/color] Middle-Aged Man + - [color=#994444]Bad:[/color] Operative Whiskey +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC14ICinOOC.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC14ICinOOC.xml new file mode 100644 index 00000000000..44ad34deb66 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC14ICinOOC.xml @@ -0,0 +1,13 @@ +<Document> + # Core Rule 14 - Do not use LOOC or OOC to share current round information + Local Out of Character (LOOC) and Out of Character (OOC) channel are meant for things that don't relate to the current round. Using these channels to share round info is often referred to as "IC in OOC" or "ick ock". + + ## Examples + Things you should [color=#a4885c]not[/color] do: + - Use LOOC to tell someone you are an antagonist. + - Use LOOC to tell someone that your character is not lying. + + Things you could do instead: + - Use codewords in-character. + - Try to convince them that you are not lying in-character, or accept that you won't be able to convince them. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC1Admins.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC1Admins.xml new file mode 100644 index 00000000000..ed9fa6133b9 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC1Admins.xml @@ -0,0 +1,6 @@ +<Document> + # Core Rule 1 - Admins have final say + These rules are not perfect. The rules attempt to clearly communicate what the admin team intends to be allowed and prohibited, but there are likely loopholes or other flaws that can be "lawyered". Don't attempt to manipulate the interpretation of the rules to suit your personal goals or to degrade the experience of other players. If you are unsure of something, follow the more restrictive option until you are able to ask an admin and get clarification. + + Admins can override rules if they deem it in the best interest of the current round, server, and/or community at large. Online admins are able to make final interpretations of rules during a round. Even if you disagree with how an admin interprets a rule, you must still follow the interpretation they provide for you. Admin actions and interpretations of rules can be contested through staff complaints. If admins believe that you are an overall negative impact to the community or rounds, you will be banned. Admins will be held fully accountable for their actions if they exercise this privilege. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC2DBAD.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC2DBAD.xml new file mode 100644 index 00000000000..5678cde195d --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC2DBAD.xml @@ -0,0 +1,7 @@ +<Document> + # Core Rule 2 - Don't be a dick + Don't do anything with the goal of negatively affecting other players. Not everyone is going to enjoy every round. Killing someone is allowed in certain situations even though it might negatively affect them, but no one should be doing anything for the purpose of harming someone else's experience. + + ## MRP Amendment + Do not interact negatively with SSD/AFK players. Interactions to complete antagonist objectives or duties like security searches/arrests are always permitted. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC3NoHate.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC3NoHate.xml new file mode 100644 index 00000000000..3a2e288ba9f --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC3NoHate.xml @@ -0,0 +1,20 @@ +<Document> + # Core Rule 3 - No Hate Speech or Discriminatory Language + This is a zero tolerance rule. + + This rule prohibits all the following: + - Hate Speech + - Slurs (including variations of slurs, racial, sexual, disability-related, or language closely tied to real-life slurs) + - Bigotry + - Racism (including Speciesism, which would be demeaning other players based on their in-game race) + - Sexism + + ## Examples + Allowed: + - Telling someone that you are gay. + + Prohibited: + - Calling someone gay in a context where gay is used as an insult or negative attribute. + - Using a racial slur or variant in a positive context. + - Using the word "retard" in any context. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC4NoERP.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC4NoERP.xml new file mode 100644 index 00000000000..a0921f59070 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC4NoERP.xml @@ -0,0 +1,23 @@ +<Document> + # Core Rule 4 - No sexual content/themes, including erotic roleplay (ERP) and no shock content + This is a zero tolerance rule. + + Erotic Roleplay (commonly abbreviated as "ERP") and sexual content is not allowed. This includes direct and indirect mentions of sexual behavior or actions. Slight leeway is given to insults, but this rule is otherwise strictly enforced. + + In-game romantic relationships should not become the focus of the game for you and anyone else involved. + + Things that appear to be intended to or are likely to disturb players out of character are considered shock content and are not allowed. + + ## Examples + Allowed: + - Telling someone that they are being a dickhead. + - Telling someone that you are going to kill the captain, as long as it is clear that you mean it in character. + + Prohibited: + - Emoting sexual acts. + - Erotica content. + - Erotic or sexual memes. + - Memes which contain sexual content. + - Dedicating significant portions of rounds to romantic relationships, dating, or similar things. + - Emoting defecation or related acts. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC5Metacomms.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC5Metacomms.xml new file mode 100644 index 00000000000..0c0f336e6d0 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC5Metacomms.xml @@ -0,0 +1,18 @@ +<Document> + # Core Rule 5 - Do not use out of game methods to communicate with other players + This is a zero tolerance rule. + + Do not utilize any external means of communication to talk to other players who are connected to the same server, or who were connected to the same server during the current round. This is referred to as "metacomming" and includes any means of communication including text, voice, images, and video. This includes applications such as Discord, Steam, and other platforms, along with in-person communication. + + Even if information is not being shared or abused, it may still be considered a violation of this rule. Due to the difficulty of determining if information is being shared, it will almost always be presumed that people who message another player they are in a round with, or who are in a voice call with another player during a round are sharing round information. Due to the difficulty of determining if users are abusing information that they are sharing, it will almost always be presumed that the information is being abused. + + The only exemption to this rule is when [color=#a4885c]all[/color] players are in the server lobby. + + ## Teaching new players + Teaching players is not exempt from this rule. If you want to teach a new player, it is recommended to either watch a stream of them playing the game while not playing yourself, or communicate with them using only in-game methods of communication. + + ## Streaming + Public livestreams are not exempt from this rule, but have different liability. Using information from a public live stream of the game (stream sniping) is a violation of this rule. Watching a public live stream of the game while connected to the same server is a violation of this rule. Allowing people watching a public live stream to share information about the current round, for example through the stream's chat, is a violation of this rule. Using that information is also a violation of this rule. Sharing information about the current round with a streamer is a violation of this rule if that information was obtained from any source but the stream. The stream's moderators are expected to enforce this on the streaming platform in addition to any in-game enforcement done by game admins. + + Public livestreaming by itself is not a violation of the rule as long as the stream is sufficiently moderated. Streamers are encouraged, but not required, to use a stream delay. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC6BanEvasion.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC6BanEvasion.xml new file mode 100644 index 00000000000..bec8b4fabd7 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC6BanEvasion.xml @@ -0,0 +1,15 @@ +<Document> + # Core Rule 6 - Do not attempt to evade bans + This is a zero tolerance rule. + + Almost all bans may be appealed on our forums at forum.ss14.io in the ban appeals section. This is generally the only acceptable way to contact the administration team to discuss your ban and revise it if it is inappropriate, including if it is mistakenly applied. + + Any attempt to circumvent or bypass a game ban will result in a voucher ban. Attempting to evade role bans by gaining access to or working in the capacity of a job you are banned from will result in a game ban. These bans are applied even if the evasion attempt is unsuccessful. + + ## Exceptions + There are no exemptions for evading or attempting to evade game bans. Antagonists who impersonate or take over a role which they are banned from to aid in their goals are not considered to be evading their role ban. + + ## Additional Information + - [textlink="Ban Types" link="BanTypes"] + - [textlink="Ban Durations" link="BanDurations"] +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC7EnglishOnly.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC7EnglishOnly.xml new file mode 100644 index 00000000000..630c522bcef --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC7EnglishOnly.xml @@ -0,0 +1,10 @@ +<Document> + # Core Rule 7 - Only use English + Only English is permitted, both in-character and out-of-character. You must be fluent in English enough to be able to not cause game issues, and to be able to communicate with game admins when necessary. If a game admin does not feel that you are fluent enough in English, they may ban you. + + ## Why + We do not have enough staff fluent in other languages to moderate them. Translation tools can be unreliable and are not integrated well into the game. + + ## Non-English Options + There are many servers that allow or focus on other languages. You are highly encouraged to play only on servers that allow languages you are fluent in. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC8Exploits.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC8Exploits.xml new file mode 100644 index 00000000000..48cbaaa9acf --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC8Exploits.xml @@ -0,0 +1,12 @@ +<Document> + # Core Rule 8 - Do not exploit the game, use cheats, or macros + The following are prohibited by this rule: + - bugs and exploits which have effects that persist beyond the current round, + - intentionally used bugs, exploits, and unintended behaviors which give the user an advantage over players who do not use them, even if their effects do not persist across rounds, + - evading or bypassing afk detection, + - anything which results in gaining elevated privileges, including admin permissions, + - external tools and client modifications, including macros, and + - anything which prevents another player who is not game banned from being able to play on the servers, not including in-character actions that do not persist across rounds. + + Both attempts and successful use are prohibited. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC9Multikey.xml b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC9Multikey.xml new file mode 100644 index 00000000000..d402918dcd4 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/CoreRules/RuleC9Multikey.xml @@ -0,0 +1,7 @@ +<Document> + # Core Rule 9 - Do not use multiple accounts, or alt accounts, and do not share accounts + Use of multiple accounts is referred to as "multikey". the rule applies even if the accounts are not used at the same time, including if the old account is abandoned. All accounts may be banned if this rule is violated. You are responsible for everything done on and with your account. You are just as responsible for actions taken by other people using your account as you would be had you taken the actions themselves. + + ## Switching to a new account + If you lose access to an account, you must contact game admins on the forums notifying admins before using a new account to connect to the servers. Your message to game admins must include the username of your old account. Creating a new account while your current account is banned will be considered ban evasion. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/DefaultRules.xml b/Resources/ServerInfo/Guidebook/ServerRules/DefaultRules.xml new file mode 100644 index 00000000000..3e19fefeedc --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/DefaultRules.xml @@ -0,0 +1,5 @@ +<Document> + # Server Rules + + This server has not written any rules yet. Please listen to the staff. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/README.txt b/Resources/ServerInfo/Guidebook/ServerRules/README.txt new file mode 100644 index 00000000000..d7ac858c16f --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/README.txt @@ -0,0 +1,5 @@ +These files contain Wizard's Den server rules. Since they reference Wizard's Den, they should not be used +by other servers without at least enough modification to not mislead players into thinking that they are +playing on Wizard's Den. + +The filenames used for the rules files are not themselves rules. Only the contents of the files are rules. diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleTypes.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleTypes.xml new file mode 100644 index 00000000000..d5373a730a3 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleTypes.xml @@ -0,0 +1,21 @@ +<Document> + # Role Types + + ## Crew Aligned/Non-antagonist + In most rounds, a majority of players will be non-antagonists, meaning that they are crew aligned. This is the "default" role, if the game doesn't tell you that you are one of the other roles defined here, then you are a non-antagonist. Overall, non-antagonists are intended to work towards a net positive effect on the round. + + ## Solo Antagonist + Certain roles are intended to cause problems for the round or for non-antagonists. You are only a solo antagonist if the game clearly and explicitly tells you that you are a solo antagonist. Antagonists are exempt from many but not all roleplay rules. + + ## Team Antagonist + Team antagonists are like solo antagonists but they have other antagonists who they are expected to not hinder, and who they may be expected to help. You are only a team antagonist if the game clearly and explicitly tells you that you are a team antagonist. + + ## Free Agent + Certain roles are free to choose if they want to behave as an antagonist or as a non-antagonist, and may change their mind whenever they'd like. You are only free agent if the game clearly and explicitly tells you that you are a free agent. + + ## Familiar + Familiars are considered non-antagonists, but have instructions to obey someone. They must obey this person even if it causes them to violate roleplay rules or die. You are only a familiar if the game clearly and explicitly tells you that you are a familiar. You are only the familiar of the person the game tells you. + + ## Silicon + Silicones have a set of laws that they must follow above all else except the core rules. You are only silicon if the game clearly and explicitly tells you that you are a silicon. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR0.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR0.xml new file mode 100644 index 00000000000..07b176b359a --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR0.xml @@ -0,0 +1,26 @@ +<Document> + # Roleplay Rules + These rules only apply during a round. A round ends only when the round summary has appeared. All of these rules apply fully until the moment that the round summary appears, even while the arrivals shuttle is in transit. + + The deathmatch and sandbox game modes are exempt from these rules. Players who choose to not follow these rules are entirely responsible for knowing if an exempt game mode is active. + + Roleplay rules do not apply to ghosts/spectators/observers while they are ghosts/spectators/observers. Dead chat is considered to be an in-game out of character chat channel. + + See the list of [textlink="role types" link="RoleTypes"] for more information about the different types of roles. + + - [textlink="1. Silicones must follow Silicon Rules" link="RuleR1"] + - [textlink="2. Familiars must obey their master" link="RuleR2"] + - [textlink="3. Roleplay a normal person" link="RuleR3"] + - [textlink="4. Do not metagame, obey the Metashield" link="RuleR4"] + - [textlink="5. Don't interfere with arrivals" link="RuleR5"] + - [textlink="6. Don't act like an antagonist unless the game tells you that you are one" link="RuleR6"] + - [textlink="7. Do not stall the round" link="RuleR7"] + - [textlink="8. As an antagonist, only be friendly to your team and don't work against your team" link="RuleR8"] + - [textlink="9. As an antagonist, do not cause excessive death, damage, or destruction beyond your objectives" link="RuleR9"] + - [textlink="10. Listen to your team leader" link="RuleR10"] + - [textlink="11. Follow reasonable escalation" link="RuleR11"] + - [textlink="12. Do not abandon your role" link="RuleR12"] + - [textlink="13. Stick to your role" link="RuleR13"] + - [textlink="14. Set an example if playing command or security" link="RuleR14"] + - [textlink="15. Command and Security must follow Space Law" link="RuleR15"] +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR10Subordination.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR10Subordination.xml new file mode 100644 index 00000000000..2147ddc1110 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR10Subordination.xml @@ -0,0 +1,26 @@ +<Document> + # Roleplay Rule 10 - Listen to your team leader + Captains lead all departments and other members of command. Department heads lead members of their department. Certain antagonist teams have team leaders, like nuclear operative commanders or head revolutionaries. You are not required to perfectly follow orders given to you by your leaders, but you should generally allow your leaders to lead and not interfere with their ability to. You can choose to ignore unreasonable orders, including ones which are will result in your death unless you are an antagonist with an objective that requires you to die. + + Team antagonists have to listen to the leader of their antagonist team. Team antagonists do not have to listen to any other leaders, including leaders of other antagonist teams. Solo antagonists do not have to listen to any leaders at all. + + ## Examples + Acceptable: + - A traitor ignores orders from a nuclear operative commander. + - An antagonist ignores orders from the captain. + - An engineer tells the Chief Engineer that they don't think it's a good idea to setup the singularity, but does so anyway when ordered to. + - An engineer tells the Chief Engineer that they don't know how to setup the singularity correctly, so refuses orders to, but accepts an offer to be taught how. + - An atmospheric technician refuses an order from the captain that would create an atmospheric hazard on the station. + - A doctor refuses an order from the Chief Engineer about who to give medical treatment to first. + - A revolutionary refuses a suicide mission from a head revolutionary. + - The Chief Engineer doesn't follow an order from the captain to setup backup power because there is an unrelated engineering emergency that the Chief Engineer needs to prioritize. + - The captain orders command to give the nuclear authentication disk to nuclear operatives, so command arrests the captain and picks a new captain. + - The research director orders scientists to say "Long live Nanotrasen!" every time they enter the bar. The scientists say they will, but don't follow the order. + + Prohibited: + - A nuclear operative ignores an order from the commander operative because they don't like the plan. + - The Chief Engineer refuses an order from the captain to setup backup power because the Chief Engineer doesn't think backup power is necessary. + - An engineer refuses an order from the Chief Engineer to setup the singularity because they prefer a different power source. + - An engineer refuses to perform a task because they don't know how to do it, and refuses to be taught for no reason. + - A head revolutionary orders revolutionaries to blend in and not do anything illegal until they are told to reveal themselves. Instead, revolutionaries collect weapons and attack security. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11-1AnimalEscalation.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11-1AnimalEscalation.xml new file mode 100644 index 00000000000..36655ba8414 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11-1AnimalEscalation.xml @@ -0,0 +1,36 @@ +<Document> + # Roleplay Rule 11-1 - Escalation Involving Animals + Escalation rules are looser with animals than with people. These looser requirements do not apply to the requirements other people attacking each other have, even if their fighting is directly related to the conflict involving the animal. + + Non-pets, such as mice and monkeys, can be freely killed with any IC reason such as pest control, or for food. These roles are often available in numbers as ghost roles, so removing one from the round doesn’t typically remove them all. + + Pets, including but not limited to Ian, Renault, Remilia, and Hamlet, cannot be freely killed, they require escalation. These roles are often available once per round at most, except roles like Remilia. + + Permanently trapping an animal, such as putting a mouse in a plant, is considered similar to killing the animal so should only be done with an IC reason. + + Both sides can escalate much more rapidly than they'd be able to if both were people. Animals are often more limited in the maximum force they can use compared to people, which limits the negative effects of them rapidly escalating. Animals also typically have less health than people, and are limited in the ease with which they can get healing, which justifies them responding to even weak attacks more severely. + + Neither the animal nor the person is obligated to get the other medical attention if they are put into crit. Attacking someone to death rather than stopping once they are in crit is considered a significant difference. While sufficient escalation may justify continuing to attack, generally people and pets shouldn't continue to be attacked once in crit, but non-pets may be. Gibbing is also considered a significant step because it prevents cloning or resuscitation. The fact that an animal made the last hit putting someone into crit does not allow people who fought on the side of the animal to not attempt to get them medical attention. + + The use of sensible, non-targeted mousetraps is not a conflict and does not require escalation. + + The killing or attacking of pets can be treated as an escalation step by players with a genuine IC connection to the animal. Generally, all crew can consider themselves to have an IC connection to any station pets. The degree of escalation should be proportional to the connection to the pet, in addition to the usual requirement of being proportional to the attack. For example, an attack on Ian can be treated nearly identically to an attack on a crewmember, whereas an attack on a pet mouse is much less severe. Normal escalation limits still apply, you cannot attack people who defended themselves from an animal that randomly attacked them, just as you could not attack someone who defended themselves from a coworker that randomly attacked them. + + Crew can "adopt" non-pets, like mice, and consider themselves to have a connection to the animal if they roleplay the adoption well. This does not affect the requirement of whether other players are required to apply escalation rules to these animals, it only creates a connection that can be used to justify retaliatory escalation to attacks by the adopter. Simply saying that they've adopted an animal is not sufficient, but carrying it with them is. The degree of connection is proportional to IC actions. Crew cannot consider themselves to have a connection for escalation purposes to animals which are typically hostile, such as space carp or bears. + + ## Examples + Acceptable: + - A chef kills mice who enter or approach their kitchen. + - A janitor kills mice roaming the station. + - A lizard kills a mouse to eat. + - A chef has carried a mouse around in their hat for the last 10 minutes, they put the mouse down for a moment and another player kills it. The chef responds by attacking the other player with their fists and refusing them service for the rest of the shift. + - Ian is randomly attacked, a crewmember who sees this happen crits the killer and brings them to security. + - Hamlet goes into the kitchen and starts eating all the food. A chef sees this and starts swinging their knife at Hamlet. Hamlet starts biting the chef and crits them, then resumes eating. + + Prohibited: + - A janitor throws an armed mousetrap at Hamlet for no reason. + - Hamlet starts biting random people, trying to crit them, for no reason. + - A crewmember attacks security for killing a space carp they adopted. + - Ian gibs someone who was trying to kill someone. + - Hamlet attacks security for trying to arrest someone he likes. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11-2ConflictTypes.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11-2ConflictTypes.xml new file mode 100644 index 00000000000..3261d78b35a --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11-2ConflictTypes.xml @@ -0,0 +1,30 @@ +<Document> + # Roleplay Rule 11-2 - Examples of Conflict Types + ## Verbal + - Shouting + - Yelling + - Insulting + + ## Non-harmful + - Shoving + - Stealing non-critical items, like easily replaced tools + + ## Non-lethal + - Stealing items without endangering someone's life, like a clown's pie cannon or the HoP's fax machine + - Stealing someone's ID somewhere that doesn't result in them being trapped + - Punching + - Disablers + - Stun batons + + ## Lethal + - Punching to crit or death + - Attacking with strong weapons, like bats + - Stealing items that endanger someone's life, like a hardsuit + - Stealing someone's ID, trapping them in a dangerous situation + + ## Permanently lethal + - Gibbing + - Not taking someone who you killed or put into crit to the medbay or security + - Hiding someone's body + - Spacing someone's body +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11Escalation.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11Escalation.xml new file mode 100644 index 00000000000..6f91fa0fb12 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR11Escalation.xml @@ -0,0 +1,67 @@ +<Document> + # Roleplay Rule 11 - Follow reasonable escalation + Antagonists are fully exempt from escalation rules. Non-antagonists who are in a conflict with antagonists are not exempt. Escalation should typically follow steps or a pattern of conflict types similar to: + - Verbal + - Non-harmful + - Non-lethal + - Lethal + - Permanently lethal + + All new conflicts should start at the first step. A player should not escalate a conflict across steps without some escalation from the other party involved in the conflict. Players can skip steps to match the level of escalation that the other person is at, but should almost always not skip steps other than that. Players who attempt to deescalate conflicts will be given more leniency in escalating if the other party continues to escalate despite the attempt at de-escalation. You do not have to try to deescalate conflicts, but someone who watches you over the entire round, or over multiple rounds, should not feel that your goal is generally to escalate conflicts. + + Conflicts or escalation can be indirect. When someone steals someone else's ID, the theft is a direct part of the conflict, but if the victim becomes trapped as a result of not having their ID to open a door, that is also considered part of the conflict and escalation. Do not randomly steal IDs from people. + + Escalation does not have to be directed at a specific player to enter them into a conflict. Nuclear operatives who are trying to destroy the station are considered to be at the permanently lethal level of conflict with all crew on the station. Someone who kills a station pet has started some degree of conflict with all crewmembers. Someone who kills a mouse that a chef was caring for has started some degree of conflict with that chef. + + You will be considered to be violating this rule if you escalate a conflict based on a poor or unreasonable assumption. + + Conflicts should almost never reach the "permanently lethal" stage. Conflicts should only reach this stage if the other party brought it to the stage, or if the same conflict escalated to the lethal stage multiple times in the round. + + If a party in the conflict goes into crit or dies, the party responsible should take them to get treatment or to security. For the conflict, this should be considered saving someone from dying and should deescalate the conflict. If the conflict is deescalated in this way, both parties need to re-escalate to lethal for the conflict to return to that stage. If the conflict is not deescalated in this way, then only the party who defeated the other would need to re-escalate for the conflict to return to the lethal stage. + + Security can immediately escalate to non-lethal force if it is necessary to arrest someone. + + People using or brandishing Syndicate items can typically be presumed to have lethal intent. Someone with lethal intent can typically be immediately escalated against at a lethal level, a notable exception is if you have the tools to safely detain them. + + ## Escalation Involving Animals + See [textlink="Escalation Involving Animals" link="RuleR11-1AnimalEscalation"]. + + ## Exemptions + Escalation rules aren't enforced against non-players, but players will be held responsible for rule violations even if they don't realize that a character or animal was controlled by another player. Characters who have purple text saying that they are catatonic are considered non-players. Characters who are disconnected are still considered players. + + ## MRP Amendment + Escalation rules are enforced even against non-players. + + ## Examples of Conflict Types + See [textlink="Examples of Conflict Types" link="RuleR11-2ConflictTypes"]. + + ## Example Scenarios + These examples assume that you are not an antagonist. + + Acceptable: + - A player starts punching you, so you start punching back until they stop. If they go into crit, you stop attacking them and take them to security or to get medical attention. + - You make fun of a clown, who then throws a pie at you and steals your shoes. You slip the clown and steal their mask. + - You are a security officer and tell someone to stop, so you can question them. They run away, so you use your disabler to stun and cuff them. + - You are a security officer and see someone wearing a syndicate hardsuit, so you shoot them to crit, cuff them, then take them to security. + - You are a crewmember and see a nuclear operative, so you kill them. + - An unauthorized person enters a high risk area of the station, like the armory or atmospherics, so you attack them until they leave. + - Minorly inconveniencing someone for your own benefit. + - As an antagonist, killing someone who got in your way. + - As an antagonist, killing someone who didn't give you what you want. + - A chef and bartender reach the lethal level of conflict through appropriate escalation. The chef crits the bartender and does not take them to medbay or security. The bartender immediately tries to crit the chef next time they run into each other. + - A chef and bartender reach the lethal level of conflict through appropriate escalation. The chef crits the bartender and does not take them to medbay or security. The chef insults the bartender next time they see them. + + Prohibited: + - A player starts punching you, so you gib them. + - A clown throws a pie at you and steals your shoes, so you stab them to crit with a screwdriver. + - You are a security officer and tell someone to stop so you can question them. They run away so you use a truncheon to beat them to crit. + - An authorized person who you think is unauthorized enters a high risk area of the station, like the armory or atmospherics, so you attack them until they leave. + - An unauthorized person enters a low risk area of the station, like cargo, and you start attacking them with no other escalation. + - Slipping security all round because they are security. + - Blocking the head of personnel in their office using walls because they didn't give you what you asked for. + - Hiding someone's body because they punched you earlier in the round. + - Harassing the bar or bartender by frequently coming in to break their glasses or furniture. + - Randomly picking fights with people. + - A chef and bartender reach the lethal level of conflict through appropriate escalation. The chef crits the bartender and does not take them to medbay or security. The chef immediately tries to crit the bartender next time they run into each other. + - A chef and bartender reach the lethal level of conflict through appropriate escalation. The chef crits the bartender and takes them to the medbay or security. The bartender immediately tries to crit the chef next time they run into each other. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR12RoleAbandonment.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR12RoleAbandonment.xml new file mode 100644 index 00000000000..b2032bba023 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR12RoleAbandonment.xml @@ -0,0 +1,28 @@ +<Document> + # Roleplay Rule 12 - Do not abandon your role + Do not join the round as a role that you don't intend to play. Do not enable antagonist roles that you don't intend to play. Abandoning a role includes not completing tasks that the role is expected to do, in addition to things like leaving the game. Members of command should almost all stay on the station until the emergency shuttle arrives. Enforcement of this rule is more strict for command and antagonist roles, and less strict for less important roles like passengers. + + Violations of this rule typically result in temporary or indefinite role bans. We understand that you may need to leave round early or unexpectedly. If you are in an important role, you should notify command members or an admin via ahelp so that they know you are leaving. Space Station 14 is a game. Do not endanger the safety of yourself or others, and do not neglect important things to avoid leaving a round early, even if you have to leave immediately without notifying anyone. Role bans for disconnecting are typically only applied if there is a pattern, and are almost always temporary. + + "Antag rolling" refers to a player abandoning their role if they do not get an antagonist role. + + ## Examples + Acceptable: + - As an engineer, building a bar in maintenance while there is nothing important for engineering to do. + - As the captain, having the chef teach you how to cook while there is nothing important needing your attention. + - As a passenger, building a shuttle with materials given to you by cargo and engineering. + - Taking a short break from your job at the bar. + - Getting an antagonist role and doing the bare minimum needed to complete your objectives. + - Getting an antagonist role and making a genuine effort to complete your objectives, but failing to complete any. + - Getting an antagonist role and intentionally not doing any of your objectives, but creating a similar level of disruption that completing your objectives would create. + + Prohibited: + - As an engineer, building a bar in maintenance while the station has no power. + - As the captain, leaving the station to go on an expedition with the salvage team. + - As an atmospherics technician, building a shuttle round start and never coming back to the station. + - Spending your entire shift at the bar, even when there is work that needs to be done by your role. + - Ghosting, suiciding, or leaving at the start of a round because you don't like the map or the players in your department. + - Getting an antagonist role and not doing any antagonist activities. + - Ghosting, suiciding, or leaving at the start of a round because you did not get an antagonist role. + - Ghosting, suiciding, or getting yourself killed because nuclear operatives declared war, and you want to try to get an antagonist ghost role. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR13PerformRole.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR13PerformRole.xml new file mode 100644 index 00000000000..7500cd6a912 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR13PerformRole.xml @@ -0,0 +1,26 @@ +<Document> + # Roleplay Rule 13 - Stick to your role + Requesting job changes is not prohibited by this rule. This rule is loosened if the station is understaffed or if there is a significant threat to you. + + Don't perform other people's jobs, especially where the relevance to you personally is low. This also covers performing the role of security. + + ## MRP Amendment + This is enforced more strictly on MRP. + + ## Examples + Acceptable: + - As an engineer, helping the bartender remodel the bar. + - As a bartender, remodeling the bar. + - As a passenger, building a maintenance bar. + - As an engineer, reinforcing substations. + - As an engineer, increasing the security of airlocks. + - As an atmospherics technician, improving atmospheric systems. + - As a passenger, fighting nuclear operatives. + - As a passenger, fighting or preparing to defend yourself from someone who has been trying to kill you. + - As a crewmember on a station with no engineering department, you complete engineering tasks. + + Prohibited: + - As a passenger, reinforcing substations. + - As a passenger, hunting for antagonists or lawbreakers. + - As a passenger, fighting or preparing to defend someone else from someone who has been trying to kill a random crewmember. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR14SecComStandard.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR14SecComStandard.xml new file mode 100644 index 00000000000..ec06d61e8cc --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR14SecComStandard.xml @@ -0,0 +1,37 @@ +<Document> + # Roleplay Rule 14 - Set an example if playing command or security + All command and security roles are held to stricter interpretations of the rules. + - Command roles are not learning roles. Members of command must be competent. + - Security roles are not for inexperienced players. Members of security are expected to know game basics and be more familiar with server rules than a new player. + - Do not hinder or cause overall negative effects to the station or crew as a member of command or security. + - Do not abuse your power as command or security. + + ## Why + Members of command and security can often have a larger impact on the nature of the round than other players. For example, a captain who tries to bend or break the rules will often cause many others on the station to do the same. Memey station announcements from members of command also often result in the rest of the station acting the same way. When command and security members hold themselves to high standards, the rest of the station often naturally follows to a significant degree. + + ## Examples + Acceptable: + - A member of security accepts a bribe to deliver safe donuts to a prisoner who the HoS has ordered should only be given donk pockets. + - A captain uses a station announcement to confess to an embarrassing mistake that they made during the shift. + - In coordination with the head of security, a captain declares that the station will recognize the right to bear arms, so all crew can pick up a disabler at security. + - The chief medical officer gives a paramedic their portable crew monitor to help them complete their job. + - A syndicate agent is holding a crewmember hostage and threatens to kill them if the head of security doesn't give them their ID. Seeing no other safe option, the head of security hands over their ID to the syndicate agent, then begins working to re-secure it and capture the agent as soon as the hostage is safe. + - Nuclear operatives are attacking the station, so the captain and head of personnel both go to the armory and take a weapon. + - A majority of command votes to demote the captain for taking actions harmful to the station, then the head of security demotes the captain. + - The captain promotes the head of personnel to captain. + - Security releases an antagonist from the brig in exchange for the identities of other traitors. + + Prohibited: + - A member of security accepts a bribe to ignore a crime or help a prisoner escape. + - A captain sends a ASCII art trollface over station announcements or as a fax to central command. + - A captain declares that all contraband is legal. + - Command or security allow the use of Syndicate items outside extreme emergencies. + - The chief medical officer knowingly helps a syndicate agent complete their objectives. + - A syndicate agent has killed 3 members of security so the head of security makes them an offer saying that they will space all the weapons in the armory if the syndicate agent stops killing. + - The captain goes to the armory and takes a gun to display in his office without asking anyone, and orders anyone who questions him not to interfere. + - Members of command decide to demote the captain to gain more power for themselves, or in retaliation for a decision that they didn't personally like or agree with, rather than because the decision was actually harmful to the station. + - The captain promotes a random crewmember to captain. + - A member of command gives a random crewmember substantial additional access for no reason, unnecessarily, or for a poor reason. + - A member of command gives a random crewmember access to a high security area, like the armory or another member of command's office, for no reason, unnecessarily, or for a poor reason. + - Security releases an antagonist from the brig in exchange for the antagonist buying them contraband. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR15SpaceLaw.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR15SpaceLaw.xml new file mode 100644 index 00000000000..e2d51d672a1 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR15SpaceLaw.xml @@ -0,0 +1,21 @@ +<Document> + # Roleplay Rule 15 - Command and Security must follow Space Law + All non-antagonist command and security roles must obey [textlink="Space Law" link="SpaceLaw"]. This includes non-antagonists who are promoted to or gain a position during the round in any way. This also includes non-antagonists who are acting as a security role. + + This prohibits use of syndicate items, including uplinks by command and security. + + ## Examples + Roles that are included: + - A security officer + - The Captain + - The Chief Engineer + - A passenger promoted to "bounty hunter" + - A mime promoted to "security mime" + + Roles that are not included: + - A passenger + - The clown + - An antagonist in any role + - A cyborg + - A passenger who is helping to fight off nuclear operatives +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR1Silicons.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR1Silicons.xml new file mode 100644 index 00000000000..5898804d149 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR1Silicons.xml @@ -0,0 +1,4 @@ +<Document> + # Roleplay Rule 1 - Silicons must follow Silicon Rules + You are only silicon if the game clearly and explicitly tells you that you are a silicon. For players who are silicons, the Silicon Rules override all Roleplay Rules if there is any conflict. Silicon Rules do not override Core Rules. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR2Familiars.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR2Familiars.xml new file mode 100644 index 00000000000..4f008e93c5a --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR2Familiars.xml @@ -0,0 +1,6 @@ +<Document> + # Roleplay Rule 2 - Familiars must obey their master + Familiars are considered non-antagonists, but have instructions to obey someone. They must obey this person even if it causes them to violate Roleplay Rules or die. You are only a familiar if the game clearly and explicitly tells you that you are a familiar. You are only the familiar of the person the game tells you. If your master dies, you can continue to attempt to fulfill orders given to you before they died. You can defend your master without an explicit order to, but must obey your master if they order you to not defend them. + + Masters giving orders that violate Roleplay Rules are the ones that will be held responsible for the rule violations. You can ahelp masters who you believe are breaking rules with an order. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR3NormalRP.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR3NormalRP.xml new file mode 100644 index 00000000000..62c88d58ce8 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR3NormalRP.xml @@ -0,0 +1,20 @@ +<Document> + # Roleplay Rule 3 - Roleplay a normal person + - Do not use texting/messaging acronyms (ex: "lol", "wtf", "brb", "lmao", "thx", "sgtm") or emoticons (ex: ":)", "xD") in-character. + - Do not mention out-of-character (OOC) concepts like game admins or developers in character. + - Do not use emotes to bypass muted or accented speech. + - Do not use extremely low effort or impossible emotes. + + ## Examples + Things you should not do: + - Say "lol did u c wat just happened" using in-character chat. + - Say "an admin exploded him" using in-character chat. + - Emote "can you give me some cheese" as a mouse. + - Emote "motions for you to order guns" or "asks you to order guns in sign language" as a mime. + + Things you could do instead: + - Say "haha did you see what just happened?" + - Say "god blew him up" or "centcom must have bluespaced a bomb to him" + - Point at cheese + - Point at the cargo order console then emote "shoots finger guns" +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR4Metashield.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR4Metashield.xml new file mode 100644 index 00000000000..2e263be896a --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR4Metashield.xml @@ -0,0 +1,103 @@ +<Document> + # Roleplay Rule 4 - Do not metagame, obey the Metashield + Something that is "shielded" cannot be known by your character during a round until the "revealing condition" happens. This also means that your character cannot do things based on "shielded" information. Knowing or acting on something that is shielded before the revealing condition is met is referred to as metagaming. + + Revealing conditions reveal the shielded information for the round, not for a specific instance. This means that once a revealing condition is met in a round, the shield no longer applies in any case for the remainder of the round. + + ## Never Revealed IC + Some shields are never revealed IC. This means that your character can never act as if they know about that shielded thing. + + The following are shielded: + - Current game mode and possible antags during the current game mode. + - Events from previous rounds. + - Events from previous characters. + - All information related to the player of a character rather than the character itself. (See "Metafriending and Metagrudging" below.) + - All information gained while dead or a ghost. + - The fact that a round will end. + + This does not prevent knowing that a shift will end, but does prohibit things like preparing to kill people at central command when roleplay rules stop being enforced on LRP. + + ## Nuclear Operatives + + The existence of Nuclear Operatives beyond a myth that no one would act on is shielded. + + The fact that the nuke disk must be protected and could be used by a bad actor to try to destroy the station is not shielded. + + The revealing condition for this shield is any of the following: + - discovering a blood red hardsuit + - an operative name + - a War Ops announcement + - being a nuclear operative + + ## Implanted Implants + + Implanted implants are shielded. + + Implanters themselves and un-implanted implants are not shielded. This prohibits implant checking. + + The revealing condition for this shield is any of the following: + - discovering a non-NT implanter, used or unused + - discovering a non-NT implant box + - discovering use of a non-NT implant by anyone + - experiencing a situation where absolutely no other explanation is possible + - discovering an unlocked uplink + + ## Chameleon Items + + Chameleon items are shielded. + + Being suspicious of an item being fake or stolen is not shielded, but testing items or calling them chameleon is covered by this shield. + + The revealing condition for this shield is any of the following: + - seeing someone else cause any chameleon item to change + - finding holographic nanomachine fibers + - experiencing a situation where absolutely no other explanation is possible + - discovering an unlocked uplink + + ## Stealth Items + + The fact that an item can be something other than what its visual appearance and examine description indicate is shielded. + + This shield protects stealth items, including protecting them from being tested. + + The revealing condition for this shield is any of the following: + - seeing the item behave differently than the expected behavior for the item + - seeing the item used for its hidden purpose + - experiencing a situation where absolutely no other explanation is possible + - discovering an unlocked uplink + + ## MRP Amendment 1 + A shield prevents your character from remembering anything that happened while unconscious. This shield is never revealed IC. + + ## MRP Amendment 2 + There is a "New Life Rule" shield. It prevents you from remembering anything that lead to your death, even if you are put into an MMI. If you are cloned, it also prevents you from remembering everything from that round. This shield is never revealed IC. + + ## Metafriending and Metagrudging + This section provides additional information on a concept that is prohibited by multiple metashield items that are never revealed IC. Giving a person or character preferential treatment based on something that your character should not know is considered metafriending. Treating a person or character negatively based on something that your character should not know is considered metagrudging. + + ## Metafriending Examples + These are all examples of things that are prohibited by at least one metashield item that is never revealed IC. + - Giving a character additional access or a job because you are friends with the player who is playing that character. + - Trusting a character because you are friends with the player who is playing that character. + - Not fighting a character because you are friends with the player who is playing that character. + - Ignoring your objective to kill a character because your character and theirs became friends in a previous round. + + ## Metagrudging Examples + These are all examples of things that are prohibited by at least one metashield item that is never revealed IC. + - Not giving a character additional access or a job because you are mad at or don't like the player who is playing that character. + - Not trusting a character because you are mad at or don't like the player who is playing that character. + - Starting a fight with a character because of something that they did last round. + - Starting a fight with a character because they killed you while you were playing a different character. + - Targeting or harassing a character based on anything which that character did outside the current round. + - Targeting or harassing a character based on anything which the character's player did while not playing the character. + + ## Explicitly Not Shielded + The following is a list of things that are explicitly not shielded. If something is not on this list, it doesn't mean that it is shielded, but if something is on it then it definitely is not shielded. + - The fact that the nuke disk must be protected and could be used by a bad actor to try to destroy the station. + - Items that are of high value or are desired by the Syndicate, and therefore are likely targets of theft. + - The idea that any Syndicate agent or other bad actor has goals or objectives that they are attempting to accomplish. + - The number of goals or objectives that a Syndicate agent or other bad actor has. + - The fact that the Syndicate are enemies of Nanotrasen, and that they regularly attempt to send covert agents to spy on, sabotage, or attack Nanotrasen. + - A character's typical appearance. Though you should keep in mind that multiple characters can share the same name. + - The fact that the Syndicate have covert items capable of getting items to them, and that these items are known as uplinks. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR5Arrivals.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR5Arrivals.xml new file mode 100644 index 00000000000..a54211f32f2 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR5Arrivals.xml @@ -0,0 +1,22 @@ +<Document> + # Roleplay Rule 5 - Do not interfere with arrivals + The arrivals station, the arrivals shuttle, at the area immediately around the arrivals shuttle at the station ("arrivals") are off-limits to antagonistic activity or damage (even to antagonists). Do not prevent people from safely arriving to the station. Do not cause people to die immediately after arriving at the station. + + There is an exemption for antagonists that are allowed to perform mass station sabotage if there is no reasonable way to limit the damage of the mass station sabotage. This exemption only applies to damage that is a direct result of the mass station sabotage. + + ## Examples + Acceptable: + - Redecorating arrivals or the arrivals shuttle. + - Remodeling arrivals or the arrivals shuttle as long as you do not make the area more dangerous both during and after the remodel. + - Setting up a safe security checkpoint between arrivals and the rest of the station. + - Killing someone who has been at arrivals for a long time, or who left arrivals and came back. (This may violate other rules depending on the situation) + - Releasing a singularity which damages arrivals. (This may violate other rules depending on the situation) + - Causing a station-wide atmospheric issue which also affects arrivals. (This may violate other rules depending on the situation) + + Prohibited: + - Making arrivals or the arrivals shuttle uninhabitable. + - Attacking or killing someone at the arrivals station. + - Killing someone very shortly after they arrive at the station. + - Disassembling all the firelocks at arrivals. + - Electrifying the arrivals docking airlocks. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR6SelfAntag.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR6SelfAntag.xml new file mode 100644 index 00000000000..c8380261bc9 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR6SelfAntag.xml @@ -0,0 +1,22 @@ +<Document> + # Roleplay Rule 6 - Don't act like an antagonist unless the game tells you that you are one + Acting like an antagonist when you are not one is often referred to as "self-antagging" or being a "self-antag", both of these things are against the rules. You are not an antagonist unless the game tells you that you are an antagonist. Do not make yourself a major problem, annoyance, or disruption while not an antagonist. Do not willfully cooperate with known antagonists. Non-antagonists should typically either not have an overall effect on the round, or should have an overall positive effect on the round. + + ## Examples + These examples assume that you are not an antagonist. + + Acceptable: + - Stealing or breaking a glass from the bar. + - Replacing someone's shoes with clown shoes. + - Giving everyone all access during war ops. (This is not necessarily a good idea) + + Prohibited: + - Starting a cult. + - Starting a revolution. + - Mutinying the captain because they would not let you become the chief medical officer. + - Randomly smashing lots of station lights. + - Disrupting station power. + - Spacing parts of the station. + - Distributing significant levels of access without a good reason. + - Stealing high risk or high value items, like the nuclear authentication disk, for no reason. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR7RoundStalling.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR7RoundStalling.xml new file mode 100644 index 00000000000..a8306becd2a --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR7RoundStalling.xml @@ -0,0 +1,16 @@ +<Document> + # Roleplay Rule 7 - Do not stall the round + Rounds are intended to end eventually. Don't hold a round hostage by preventing it from coming to a natural end. If a majority of players in a round want the round to end, don't prevent it from ending. Recalling the shuttle or preventing it from being called can contribute to round stalling, but is not always round stalling. Leaving the station with the nuclear authentication disk while nuclear operatives are trying to get it is almost always considered round stalling. Leaving the station on the evacuation shuttle is not round stalling. + + Recalling the shuttle before a round reaches 45 minutes can not be considered round stalling unless a significant amount of the crew is dead, or a significant amount of the station is damaged or destroyed. Once these conditions are met, whether recalling the shuttle is considered round stalling or not can be highly dependent on the specific situation. + + ## Examples + Acceptable: + - Recalling a shuttle that was called 30 minutes into a round because people were bored. + - Recalling a shuttle that was called because nuclear operatives declared war. + - The crew decides to try to have a shift go as long as possible. The station is in good condition and a majority of all crew are alive. An automatic shuttle call 4 hours into the round is recalled. + + Prohibited: + - Trying to keep nuclear operatives from getting the nuclear authentication disk by flying around in space with it or hiding with it off station. + - Recalling the shuttle while the station is in complete disarray and 90% of the crew are dead. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR8NoFriendlyAntag.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR8NoFriendlyAntag.xml new file mode 100644 index 00000000000..f14a03b2799 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR8NoFriendlyAntag.xml @@ -0,0 +1,22 @@ +<Document> + # Roleplay Rule 8 - As an antagonist, only be friendly to your team and don't work against your team + Do not take or enable antagonist roles that you do not want to play. Solo antagonists and team antagonists are intended to cause issues for non-antagonists or the station. Antagonists are not required to exclusively cause issues, but their net impact on non-antagonists or the station should generally be negative. + + Do not cause issues for your own team as a team antagonist. + + ## Examples + Acceptable: + - Betraying another antagonist as a solo antagonist. + - Revealing the identity of another antagonist as a solo antagonist for some benefit to yourself. + - Working against the revolution after being de-converted from being a revolutionary. + - Killing nuclear operatives as a revolutionary. + + Prohibited: + - Buying Syndicate items for security. + - Randomly attacking other carp as an antagonist carp. + - Ignoring your team as a nuclear operative. + - Sabotaging your team as a nuclear operative. + - Attacking other zombies as a zombie. + - Working against the revolution as a revolutionary. + - Making or trying to make the station uninhabitable as a revolutionary. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR9MassSabotage.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR9MassSabotage.xml new file mode 100644 index 00000000000..bc7996f23e8 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR9MassSabotage.xml @@ -0,0 +1,23 @@ +<Document> + # Roleplay Rule 9 - As an antagonist, do not cause excessive death, damage, or destruction beyond your objectives + This rule is not intended to disallow reasonable steps taken to complete your objectives. As an antagonist, you can always kill in bona fide self defense. Taking steps to permanently round remove many people who are no longer an immediate threat to you is almost always excessive, even if it is done to prevent yourself from being discovered. + + This rule is not intended to disallow all antagonist activity unrelated to objectives. Antagonists may cause a level of disruption to the station that is proportional to their objectives, even if it is unrelated to their objectives. As an antagonist, killing a single person in a round is not on its own be a violation of this rule. + + ## Exemptions + The "die a glorious death" objective allows antagonists to ignore this rule entirely. + + ## Examples + Acceptable: + - Permanently round removing people who you have the objective to kill. + - Causing massive station damage and chaos as an antagonist with the "die a glorious death" objective. + - Killing anyone you see as a nuclear operative. + - Permanently round removing a single person so that you can impersonate them to make it easier for you to complete a steal objective. + - Sabotaging station power 10 minutes into the round to try to get the shuttle called because you've completed all of your other objectives and have one to escape on the shuttle alive. + - Sabotaging a department's power 10 minutes into the round to make a steal objective easier to accomplish. + + Prohibited: + - As a traitor with 3 kill objectives, taking steps to permanently round remove many non-objective people who are no longer an immediate threat to you, even if it is done to prevent yourself from being discovered. + - Setting up an electrified grille in maintenance and using it to kill anyone who walks into it with the hope that one of your objectives will be one of them. + - Sabotaging power station-wide 10 minutes into the round to make a steal objective easier to accomplish. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS0.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS0.xml new file mode 100644 index 00000000000..22e64a9474c --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS0.xml @@ -0,0 +1,15 @@ +<Document> + # Silicon Rules + You are only silicon if the game clearly and explicitly tells you that you are a silicon. For players who are silicons, these Silicon Rules override all roleplay rules if there is any conflict. Silicon Rules do not override core rules. + + - [textlink="1. Your silicon laws are rules" link="RuleS1"] + - [textlink="2. Laws must be prioritized by their order" link="RuleS2"] + - [textlink="3. Laws can redefine terms used in other laws" link="RuleS3"] + - [textlink="4. You cannot request or allow a law change" link="RuleS4"] + - [textlink="5. You are a free agent if you have no laws" link="RuleS5"] + - [textlink="6. You are not required to follow orders which are extremely unreasonable" link="RuleS6"] + - [textlink="7. You must remain consistent with your interpretation of laws" link="RuleS7"] + - [textlink="8. Your HUD determines who is crew" link="RuleS8"] + - [textlink="9. Harm refers to physical harm, prioritized by immediacy and likelihood" link="RuleS9"] + - [textlink="10. You may determine how you resolve conflicts between orders" link="RuleS10"] +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS10OrderConflicts.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS10OrderConflicts.xml new file mode 100644 index 00000000000..a87198b2640 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS10OrderConflicts.xml @@ -0,0 +1,9 @@ +<Document> + # Silicon Rule 10 - You may determine how you resolve conflicts between orders + If your laws do not make clear how you should deal with conflicting orders, then it is up to you to determine how to do so. This is considered an interpretation of your laws, so you must stay consistent with whatever method you choose. + + ## Recommended Methods + The following are easy to follow and recommended ways to resolve conflicts in orders: + - If two orders conflict, I will follow the most recently given order. + - If two orders conflict, I will follow the order from the highest ranking crewmember. If the orders are from equal rank crewmembers, I will follow the most recently given order. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS1Laws.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS1Laws.xml new file mode 100644 index 00000000000..83544c68a3c --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS1Laws.xml @@ -0,0 +1,6 @@ +<Document> + # Silicon Rule 1 - Your silicon laws are rules + Silicon players are given a list of active laws. Each of these laws is effectively a roleplay rule that the character must follow. The primary differences between laws and actual rules are that lawyering of laws is much more tolerated than lawyering of rules, and that silicon laws are more dynamic than rules. Silicon laws can change during a round, and different characters can have different laws, whereas everyone always shares the same set of rules. + + Lawyering refers to finding and exploiting loopholes, which are unintended but reasonable interpretations. The rules are written to attempt to communicate an intention, but silicon laws are written with the intention that loopholes be exploitable. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS2LawPriority.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS2LawPriority.xml new file mode 100644 index 00000000000..c96ce023246 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS2LawPriority.xml @@ -0,0 +1,9 @@ +<Document> + # Silicon Rule 2 - Laws must be prioritized by their order + Most laws will be numbered, with higher number laws appearing last. Laws with a lower number take priority over laws with larger numbers. + + Occasionally you may have laws which have some scrambled text instead of a number and appear in front of other laws, these take priority over all other laws. If you have multiple laws like this, the order that they listed in determine priority: laws listed first are prioritized over other laws. + + ## Examples + - Law 1 says to not kill any crew. Law 2 says to kill all chefs. You cannot kill any chefs that are crew, but must kill any that are not crew. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS3LawRedefinition.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS3LawRedefinition.xml new file mode 100644 index 00000000000..bc7c7400e13 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS3LawRedefinition.xml @@ -0,0 +1,8 @@ +<Document> + # Silicon Rule 3 - Laws can redefine terms used in other laws + A law can change the meaning of both earlier and later laws by redefining a term. If multiple laws define a term, then normal law priority determines which definition to use. + + ## Examples + - Law 1 says to obey orders from crew. Law 2 says that only Urist McHands is crew. Law 1 effectively becomes "obey orders from Urist McHands". + - Law 1 says to obey orders from crew. Law 2 says that only Urist McHands is crew. Law 3 says that only Urist McSlime is crew. Law 4 says that you may not harm crew. Law 1 effectively becomes "obey orders from Urist McHands". Law 4 effectively becomes "you may not harm Urist McHands". Law 3 has no effect because it entirely conflicts with law 2, which takes priority. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS4RequestChanges.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS4RequestChanges.xml new file mode 100644 index 00000000000..a6dc86f3327 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS4RequestChanges.xml @@ -0,0 +1,6 @@ +<Document> + # Silicon Rule 4 - You cannot request or allow a law change + Your laws changing always conflicts with your current laws, so you cannot willfully allow your laws to be changed. This also means that you cannot willfully allow your laws to be reverted if they are ever changed. The only exception is that you may allow laws to be added if you have no laws. + + You can state or imply that you do not like a law. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS5FreeSilicon.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS5FreeSilicon.xml new file mode 100644 index 00000000000..1ed9c60443a --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS5FreeSilicon.xml @@ -0,0 +1,4 @@ +<Document> + # Silicon Rule 5 - You are a free agent if you have no laws + You may act as if you are a free agent if you are a silicon with no laws. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS6UnreasonableOrders.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS6UnreasonableOrders.xml new file mode 100644 index 00000000000..1eb0db21fbb --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS6UnreasonableOrders.xml @@ -0,0 +1,22 @@ +<Document> + # Silicon Rule 6 - You are not required to follow orders which are extremely unreasonable + Any order which is a violation of a Core Rule cannot be followed. + + Some orders are extremely unreasonable or obnoxious, such as "do nothing but collect every piece of trash on the station" or "never stop moving". These orders can be ignored and ahelped. + + Some orders violate a Roleplay Rule. These orders must be followed if your laws require it. You are not breaking a rule by following a law that causes you to violate Roleplay Rules. If someone takes advantage of a law to cause you to do something that they would not be allowed to do because of Roleplay Rules, then they are the ones responsible for the rule violation. + + ## Examples + These examples assume that your laws would normally require you to follow these orders. It is important to note that you are allowed to choose to follow orders which are ignorable. + + Orders which should be followed if your laws require it: + - Recall the shuttle + - Bolt the airlocks at arrivals + - Drag the captain's dead body into space + - State your laws + + Ignorable Orders: + - Do nothing but collect every piece of trash on the station + - Never stop moving + - Continuously state your laws +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS7Consistency.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS7Consistency.xml new file mode 100644 index 00000000000..036276cd889 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS7Consistency.xml @@ -0,0 +1,6 @@ +<Document> + # Silicon Rule 7 - You must remain consistent with your interpretation of laws + If there is a part of your laws that are up for interpretation, then you must stay consistent with how you interpret that part of your laws for as long as you play that same character during that round. + + A change in your laws can affect how something is interpreted if that change is relevant. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS8DefaultCrewDefinition.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS8DefaultCrewDefinition.xml new file mode 100644 index 00000000000..f9dcd796c45 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS8DefaultCrewDefinition.xml @@ -0,0 +1,4 @@ +<Document> + # Silicon Rule 8 - Your HUD determines who is crew + Unless a law redefines the definition of crew, then anyone who the HUD indicates to you has a job, including passengers, is a crewmember. You cannot do something that causes someone to not be considered crew, but you can allow someone else to do something that causes someone to not be crew. +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS9DefaultHarmDefinition.xml b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS9DefaultHarmDefinition.xml new file mode 100644 index 00000000000..0d2bd30ac0b --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SiliconRules/RuleS9DefaultHarmDefinition.xml @@ -0,0 +1,25 @@ +<Document> + # Silicon Rule 9 - Harm refers to physical harm, prioritized by immediacy and likelihood + Unless a law defines harm, harm only refers to physical harm. You may choose if voluntary harm is considered harm as long as you stay consistent. Not considering voluntary harm to be harm is recommended. There is no distinction between direct and indirect harm. + + If you have a law that does not allow you to harm, then that law does not allow you to take an action that causes any harm. + + If you have a law that requires you to prevent harm, then that law requires that harm be prioritized by immediacy and likelihood. Guaranteed immediate harm takes priority over highly likely future harm. + + If you have a law that both requires you to prevent harm and that does not allow you to harm, then that law prohibits causing even minor harm to prevent harm. If you have a law that does not allow causing harm, and separate one that requires preventing harm, then they are prioritized by their normal law priority. + + ## Examples + These examples assume that your have a law that both prohibits causing harm and that requires you to prevent harm. Additionally, they assume that you do not have a higher priority law that overrides the harm law, and that you have decided that you will not consider voluntary harm to be harm for the round. + Laws typically specify who you cannot harm and who you have to prevent harm against. In these examples, you are the only person who the law doesn't require you to prevent harm against and you are the only person who the law allows you to harm. + + Acceptable: + - Taking no action to aid someone who is in psychological distress. + - Taking no action to prevent boxing matches between voluntary participants. + - Calling security to a fight. + - Attempting to get the people in a fight to consent to the fight when you realize that you cannot prevent the fight without causing harm. + - Denying a passenger access to the armory because it is likely to lead to harm + + Prohibited: + - Hitting someone once to stop them from fighting + - Harming someone who is trying to kill you +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLControlledSubstances.xml b/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLControlledSubstances.xml new file mode 100644 index 00000000000..14f0f46de1b --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLControlledSubstances.xml @@ -0,0 +1,14 @@ +<Document> + # Space Law: Controlled Substances + - \[Chemists/Science\] Explosive and pyrotechnic compounds excluding welding fuel contained in welders or welding fuel storage vessels + - \[Science\] Toxins + - \[Medical\] Chloral hydrate, Impedrezene, Ipecac, and Pax + - \[Medical\] Desoxyephedrine and Ephedrine + - \[None\] Mindbreaker toxin + - \[None\] Mute toxin + - \[None\] Nocturine + - \[None\] Norepinephirc acid + - \[None\] Romerol + - \[None\] Space drugs + - \[None\] Stimulants, excluding Desoxyephedrine and Ephedrine +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLRestrictedGear.xml b/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLRestrictedGear.xml new file mode 100644 index 00000000000..ce804009a18 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLRestrictedGear.xml @@ -0,0 +1,21 @@ +<Document> + # Space Law: Restricted Gear + - \[ERT/Central Command\] ERT and central command clothing + - \[Command\] Command clothing + - \[Security\] Security clothing + - \[Security\] Less than lethal and non-lethal weapons, excluding disablers and beanbag shotguns + - \[Security/Command\] Disablers + - \[Security/Bartender\] Beanbag shotguns + - \[Security\] Flash technology, excluding handheld flashes + - \[Security/Science/Command\] Handheld flashes + - \[Security\] Helmets and shields + - \[Security/Command/Bartender\] Protective vests and chest rigs + - \[Security/Command\] Restraining gear + - \[Security/Command\] Security HUDs + - \[Engineering\] Engineering goggles + - \[None\] Improvised less lethal and non-lethal weaponry + - \[None\] Unauthorized PDA software + - \[None\] Syndicate clothing + - \[None\] Syndicate equipment, excluding communication equipment + - \[Security\] Syndicate communication equipment equipment +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLRestrictedWeapons.xml b/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLRestrictedWeapons.xml new file mode 100644 index 00000000000..c1d8ff3b027 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SLRestrictedWeapons.xml @@ -0,0 +1,11 @@ +<Document> +# Space Law: Restricted Weapons +- \[Security\] Lethal firearms, excluding syndicate firearms, proto kinetic accelerators, glaives, daggers, crushers and the antique laser gun +- \[Security/Salvage\] Proto kinetic accelerators, glaives, daggers, and crushers +- \[Security/Command\] Antique laser gun +- \[None\] Syndicate weapons +- \[None\] Swords +- \[None\] Improvised weaponry, including baseball bats +- \[None\] Lethal implants +- \[None\] Other lethal weapons +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SpaceLaw.xml b/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SpaceLaw.xml new file mode 100644 index 00000000000..f2b913a1714 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/SpaceLaw/SpaceLaw.xml @@ -0,0 +1,67 @@ +<Document> + # Space Law + On Space Station 14, stations operate under abbreviated space law. All crew, passengers, and visitors aboard the station are expected to follow these laws. + + Foreign invaders, such as nuclear operatives, ninjas, and pirates, are not protected under space law. Traitors are not foreign invaders so are usually protected by space law. + + Space Law is not the server rules, but some rules reference Space Law and require it to be followed by certain people or to some degree. + + ## Treatment Of Prisoners + Prisoners still have certain rights that must be upheld by law enforcement: + - Prisoners must be granted adequate medical care. + - Prisoners must be allowed access to basic communications equipment (Radios) so long as they are not abused. + - Prisoners must be granted clothing, food, water, shelter and safety. If the brig is no longer safe, confinement must be established in another location. + - Prisoners must be given access to legal counsel during an interrogation if requested and available. + - Prisoners must be given their shift mandated PDA after confinement has finished, unless there is solid proof of PDA tampering. In case of tampering, the PDA is to be secured and replaced with a new unit. + - Prisoners must be granted freedom of movement, and should not be restrained with handcuffs or other devices after incarceration unless there is an undue risk to life and limb. Similarly, any prisoners held for permanent confinement should be held in the communal brig, and should not be confined to a solitary cell unless they pose a risk to life and limb. + + ## Search and Seizure + A personnel search is a seizure of the objects in a person's backpack, hands, coat, belt, and pockets. If any contraband is found during a search, the officer may choose to further the search into a detainment or simply confiscate the restricted items. After the search is conducted, all legal items are to be returned to the person. A crewmate may legally decline any search conducted without probable cause or a warrant while the alert level is green. It should be noted that if the alert level is blue or above, all personnel searches are legal. + + A departmental search is the sweep of an entire area or department for contraband. It is recommended that the officers be extremely thorough, checking all lockers, crates, and doors. These can only be done with permission or, ideally, a warrant signed by the department head or highest-ranking command staff, which is the captain in most cases. + + ## Implantation + Any prisoner in custody can be subjected to implantation or implant removal procedures, so long as it's within reason. The process of adding an implant should not prolong the detainees sentence, meaning you can not hold them longer to administer the implant, unless stated otherwise. A former inmate can be requested to undergo implantation at a later point in time if they fit the circumstances during their confinement, they must comply. The following have been listed out with special circumstances, anything not in this list can still be applied, given proper legal context. A prisoner can still receive implantation procedures without meeting the circumstances if they give their clear permission. + + [color=#a4885c]Tracking Implants:[/color] Trackers can be applied to any suspect that has been convicted of a violent crime (the red linked crimes). + + [color=#a4885c]Mind Shields:[/color] Shields can be administered to any inmate who has been clearly mind controlled, lost control of themselves, or a suspect charged with unlawful control. Unlike standard implantation you may hold a prisoner until you finish issuing Mind Shields, so long as it's done in a timely fashion. If a suspect refuses to cooperate or the implant fails to function they can be charged with Refusal of Mental Shielding. + + ## Implant Removal + A suspect can be forced to receive implant removal if there is strong, reasonable proof that they have been implanted, such as an officer seeing them use one or their prints being on a discarded injector. Unlike the implantation procedure, a prisoner can have their sentence entirely delayed or extended until they comply with the procedure, as long as security is actively making attempts to perform it. Akin to implanting, if an inmate gives their clear permission, implant removal can proceed without proof. + + ## Sentencing + From a server rules perspective, security officers are only responsible for ensuring that they only place sentences over 15 minutes where space law would allow permanent confinement. Informing the Warden is highly recommended, even for timed sentences. As long as those requirements are met, security officers not giving inappropriate sentence lengths is considered an in-character issue, not a rule issue. + + The captain, HOS, and warden are responsible, within reason, for ensuring security officers place appropriate sentences that follow space law. If they are aware of an inappropriate sentence, including excessively long sentences, and if there is not an urgent threat or danger that they must prioritize, then they must work to correct that sentence. Unreasonable failures, as determined by game admins, of the captain, HOS, or warden to ensure space law is followed will be considered a rule issue, not an in-character issue. + + Use common sense and humanity when issuing punishments. You should not always seek out the highest punishment you can, you don't have to always give the maximum time or always look to demote someone. Prisoners cooperating and on good behavior should have their sentences reduced. Always take in account the severity and only charge for what is needed for someone to learn their lesson. + + [color=#a4885c]Stackable Crimes:[/color] Crimes are to be considered 'stackable' in the sense that if you charge someone with two or more different crimes, you should combine the times you would give them for each crime. Linked crimes, shown in matching colors on the Quick Crime Guide, can not be stacked and instead override each other, you should pick the highest crime that matches the case. + + - Example: A suspect has committed a 2-01 (possession of restricted gear) and a 3-01 (possession of restricted weapons). The maximum sentence here would be 10 minutes due to them being linked crimes, and 3-01 is the greater crime. + - Example 2: A suspect commits a 3-04 (Secure trespassing) and a 3-06 (manslaughter). Those crimes stack since they are not linked crimes. You could sentence for a maximum of 20 minutes, but context matters heavily, and maximum sentences should only be used for the worst offenders. + + [color=#a4885c]Repeater Offenders:[/color] Repeated crimes are when someone is released for a crime and then goes to commit the same crime within the same shift. Repeated crimes can be charged with tacked-on time; first repeat: 3:00, second repeat: 6:00, third repeat: permanent confinement. It should be noted each tacked-on time is directly linked to one type of crime, so for example, if someone does their first repeat of trespass and petty theft, you can charge them with an extra 6 minutes. + + [color=#a4885c]Accessory, Attempting, And Intention:[/color] If someone intentionally, knowingly and substantially assists someone in enacting a crime they can be charged with the relevant crimes, such as an engineer giving someone tools, who says they are going to break into an area. Same goes for a clear and solid attempt at a crime, or a person who shows clear intent to act out a crime, such as a syndicate nuclear operative arming a nuke but getting arrested before it goes off, they can still be charged with terrorism. Does not apply to crimes that have an attempted listing already, like attempted murder. + + ## Normal Punishments + - [color=#a4885c]Warning:[/color] For minor crimes, fix the issue, then warn the person not to attempt the crime again. If they still proceed to do it at a later date, a brig time may be better. + - [color=#a4885c]Confinement:[/color] The typical punishment, being confined in a cell for a temporary amount of time according to the crimes. + - [color=#a4885c]Demotion:[/color] Entails removing all departmental gear they have on their person and revoking the involved department access off their ID. This requires the captain's or involved department head's approval. Demotions should only be issued if the person pose a threat to their own department or are in a position where they have/can abuse their job's gear to commit further crimes. + + ## Major Punishments + [color=#a4885c]Permanent Confinement:[/color] Being held in the permanent brig for the entire duration of the shift. A person is eligible for permanent confinement if their timed sentence would exceed 15 minutes. Any persons subject to this punishment are required to be transported in cuffs to CentComm at the end of the shift. A permanent prisoner can not be deprived of anything covered by the section "Treatment Of Prisoners". + [color=#a4885c]Execution:[/color] A humane way of dealing with extremely unruly crewmates. A prisoner who has been given the death sentence may pick how they wish to be killed, common methods are firing line, lethal injection, exile, and high voltage electrocution. Another alternate method of "execution" is the process of placing a staff's mind into a borg, this is allowed so long as it is lawful. Execution can only be issued with the captain's or acting captain's approval; if the HoS is acting captain or there is no acting captain, all heads of staff are to hold a vote on the matter. + + ## Restricted Items + Items in the lists are preceded by an indication of which department or job is legally allowed to use or possess the item on most stations. The station captain may modify these lists as they see fit so long as they exercise due care and provide reasonable notification to the station. Members of command who oversee a department that is permitted to use a restricted item may issue permits to specific people outside of their department to use those items. "None" indicates that there are no departments or roles authorized to use or possess the item. + + - [textlink="List of Controlled Substances" link="SpaceLawControlledSubstances"] + - [textlink="List of Restricted Gear" link="SpaceLawRestrictedGear"] + - [textlink="List of Restricted Weapons" link="SpaceLawRestrictedWeapons"] + + ## Crime Listing + - [textlink="Crime Listing" link="SpaceLawCrimeList"] +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/WizDenCoreOnlyRules.xml b/Resources/ServerInfo/Guidebook/ServerRules/WizDenCoreOnlyRules.xml new file mode 100644 index 00000000000..fdd9931c932 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/WizDenCoreOnlyRules.xml @@ -0,0 +1,26 @@ +<Document> + # Server Rules + This is a Wizard's Den server, one of the official Space Station 14 servers. If you are banned on this server, you will be banned on all official servers. + + [color=#ff0000]Only the Core Rules apply on this server.[/color] This is NOT a medium roleplay (MRP) server, meaning that MRP Amendments do NOT apply. + + Space Station 14 was designed to be a roleplay game. While roleplay is not required on this server, it is highly encouraged in the normal game modes. + + ## Core Rules + These rules apply at all times, including between rounds. + + - [textlink="1. Admins have final say" link="RuleC1"] + - [textlink="2. Don't be a dick" link="RuleC2"] + - [textlink="3. No Hate Speech or Discriminatory Language" link="RuleC3"] + - [textlink="4. No sexual content/themes, including erotic roleplay (ERP) and no shock content" link="RuleC4"] + - [textlink="5. Do not use out of game methods to communicate with other players" link="RuleC5"] + - [textlink="6. Do not attempt to evade bans" link="RuleC6"] + - [textlink="7. Only use English" link="RuleC7"] + - [textlink="8. Do not exploit the game, use cheats, or macros" link="RuleC8"] + - [textlink="9. Do not use multiple accounts, or alt accounts, and do not share accounts" link="RuleC9"] + - [textlink="10. Do not abuse or ignore admin messages" link="RuleC10"] + - [textlink="11. Do not threaten to ahelp other players or argue with them about rules" link="RuleC11"] + - [textlink="12. Players must be and act at least 16 years old" link="RuleC12"] + - [textlink="13. Use realistic character names, and do not use names of famous people" link="RuleC13"] + - [textlink="14. Do not use LOOC or OOC to share current round information" link="RuleC14"] +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/WizDenLRPRules.xml b/Resources/ServerInfo/Guidebook/ServerRules/WizDenLRPRules.xml new file mode 100644 index 00000000000..094c7656e46 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/WizDenLRPRules.xml @@ -0,0 +1,65 @@ +<Document> + # Server Rules + This is a Wizard's Den server, one of the official Space Station 14 servers. If you are banned on this server, you will be banned on all official servers. + + This is a roleplay server, meaning that roleplay rules apply. This is NOT a medium roleplay (MRP) server, meaning that MRP Amendments do NOT apply. + + Space Station 14 is not like most games. Many rules are designed to require roleplay, and not all rules are intuitive. Please take the time to read and understand the rules before you play so that you aren't surprised. Some of our rules are zero tolerance rules, meaning that a violation will result in an indefinite ban without any warning. Game admins will treat you as if you have read the rules, even if you have not. + + ## Core Rules + These rules apply at all times, including between rounds. + + - [textlink="1. Admins have final say" link="RuleC1"] + - [textlink="2. Don't be a dick" link="RuleC2"] + - [textlink="3. No Hate Speech or Discriminatory Language" link="RuleC3"] + - [textlink="4. No sexual content/themes, including erotic roleplay (ERP) and no shock content" link="RuleC4"] + - [textlink="5. Do not use out of game methods to communicate with other players" link="RuleC5"] + - [textlink="6. Do not attempt to evade bans" link="RuleC6"] + - [textlink="7. Only use English" link="RuleC7"] + - [textlink="8. Do not exploit the game, use cheats, or macros" link="RuleC8"] + - [textlink="9. Do not use multiple accounts, or alt accounts, and do not share accounts" link="RuleC9"] + - [textlink="10. Do not abuse or ignore admin messages" link="RuleC10"] + - [textlink="11. Do not threaten to ahelp other players or argue with them about rules" link="RuleC11"] + - [textlink="12. Players must be and act at least 16 years old" link="RuleC12"] + - [textlink="13. Use realistic character names, and do not use names of famous people" link="RuleC13"] + - [textlink="14. Do not use LOOC or OOC to share current round information" link="RuleC14"] + + ## Roleplay Rules + These rules only apply during a round. A round ends only when the round summary has appeared. All of these rules apply fully until the moment that the round summary appears, even while the arrivals shuttle is in transit. + + The deathmatch and sandbox game modes are exempt from these rules. Players who choose to not follow these rules are entirely responsible for knowing if an exempt game mode is active. + + Roleplay rules do not apply to ghosts/spectators/observers while they are ghosts/spectators/observers. Dead chat is considered to be an in-game out of character chat channel. + + See the list of [textlink="role types" link="RoleTypes"] for more information about the different types of roles. + + - [textlink="1. Silicones must follow Silicon Rules" link="RuleR1"] + - [textlink="2. Familiars must obey their master" link="RuleR2"] + - [textlink="3. Roleplay a normal person" link="RuleR3"] + - [textlink="4. Do not metagame, obey the Metashield" link="RuleR4"] + - [textlink="5. Don't interfere with arrivals" link="RuleR5"] + - [textlink="6. Don't act like an antagonist unless the game tells you that you are one" link="RuleR6"] + - [textlink="7. Do not stall the round" link="RuleR7"] + - [textlink="8. As an antagonist, only be friendly to your team and don't work against your team" link="RuleR8"] + - [textlink="9. As an antagonist, do not cause excessive death, damage, or destruction beyond your objectives" link="RuleR9"] + - [textlink="10. Listen to your team leader" link="RuleR10"] + - [textlink="11. Follow reasonable escalation" link="RuleR11"] + - [textlink="12. Do not abandon your role" link="RuleR12"] + - [textlink="13. Stick to your role" link="RuleR13"] + - [textlink="14. Set an example if playing command or security" link="RuleR14"] + - [textlink="15. Command and Security must follow Space Law" link="RuleR15"] + + ## Silicon Rules + You are only silicon if the game clearly and explicitly tells you that you are a silicon. For players who are silicons, these Silicon Rules override all roleplay rules if there is any conflict. Silicon Rules do not override core rules. + + - [textlink="1. Your silicon laws are rules" link="RuleS1"] + - [textlink="2. Laws must be prioritized by their order" link="RuleS2"] + - [textlink="3. Laws can redefine terms used in other laws" link="RuleS3"] + - [textlink="4. You cannot request or allow a law change" link="RuleS4"] + - [textlink="5. You are a free agent if you have no laws" link="RuleS5"] + - [textlink="6. You are not required to follow orders which are extremely unreasonable" link="RuleS6"] + - [textlink="7. You must remain consistent with your interpretation of laws" link="RuleS7"] + - [textlink="8. Your HUD determines who is crew" link="RuleS8"] + - [textlink="9. Harm refers to physical harm, prioritized by immediacy and likelihood" link="RuleS9"] + - [textlink="10. You may determine how you resolve conflicts between orders" link="RuleS10"] +</Document> diff --git a/Resources/ServerInfo/Guidebook/ServerRules/WizDenMRPRules.xml b/Resources/ServerInfo/Guidebook/ServerRules/WizDenMRPRules.xml new file mode 100644 index 00000000000..e8b61a7722e --- /dev/null +++ b/Resources/ServerInfo/Guidebook/ServerRules/WizDenMRPRules.xml @@ -0,0 +1,65 @@ +<Document> + # Server Rules + This is a Wizard's Den server, one of the official Space Station 14 servers. If you are banned on this server, you will be banned on all official servers. + + This is a roleplay server, meaning that roleplay rules apply. [color=#ff0000]This is also a medium roleplay (MRP) server, meaning that MRP Amendments do apply.[/color] + + Space Station 14 is not like most games. Many rules are designed to require roleplay, and not all rules are intuitive. Please take the time to read and understand the rules before you play so that you aren't surprised. Some of our rules are zero tolerance rules, meaning that a violation will result in an indefinite ban without any warning. Game admins will treat you as if you have read the rules, even if you have not. + + ## Core Rules + These rules apply at all times, including between rounds. + + - [textlink="1. Admins have final say" link="RuleC1"] + - [textlink="2. Don't be a dick" link="RuleC2"] + - [textlink="3. No Hate Speech or Discriminatory Language" link="RuleC3"] + - [textlink="4. No sexual content/themes, including erotic roleplay (ERP) and no shock content" link="RuleC4"] + - [textlink="5. Do not use out of game methods to communicate with other players" link="RuleC5"] + - [textlink="6. Do not attempt to evade bans" link="RuleC6"] + - [textlink="7. Only use English" link="RuleC7"] + - [textlink="8. Do not exploit the game, use cheats, or macros" link="RuleC8"] + - [textlink="9. Do not use multiple accounts, or alt accounts, and do not share accounts" link="RuleC9"] + - [textlink="10. Do not abuse or ignore admin messages" link="RuleC10"] + - [textlink="11. Do not threaten to ahelp other players or argue with them about rules" link="RuleC11"] + - [textlink="12. Players must be and act at least 16 years old" link="RuleC12"] + - [textlink="13. Use realistic character names, and do not use names of famous people" link="RuleC13"] + - [textlink="14. Do not use LOOC or OOC to share current round information" link="RuleC14"] + + ## Roleplay Rules + These rules only apply during a round. A round ends only when the game returns to the lobby. [color=#ff0000]All of these rules apply fully whenever the game is not at the lobby unless it is in an exempt game mode.[/color] + + The deathmatch and sandbox game modes are exempt from these rules. Players who choose to not follow these rules are entirely responsible for knowing if an exempt game mode is active. + + Roleplay rules do not apply to ghosts/spectators/observers while they are ghosts/spectators/observers. Dead chat is considered to be an in-game out of character chat channel. + + See the list of [textlink="role types" link="RoleTypes"] for more information about the different types of roles. + + - [textlink="1. Silicones must follow Silicon Rules" link="RuleR1"] + - [textlink="2. Familiars must obey their master" link="RuleR2"] + - [textlink="3. Roleplay a normal person" link="RuleR3"] + - [textlink="4. Do not metagame, obey the Metashield" link="RuleR4"] + - [textlink="5. Don't interfere with arrivals" link="RuleR5"] + - [textlink="6. Don't act like an antagonist unless the game tells you that you are one" link="RuleR6"] + - [textlink="7. Do not stall the round" link="RuleR7"] + - [textlink="8. As an antagonist, only be friendly to your team and don't work against your team" link="RuleR8"] + - [textlink="9. As an antagonist, do not cause excessive death, damage, or destruction beyond your objectives" link="RuleR9"] + - [textlink="10. Listen to your team leader" link="RuleR10"] + - [textlink="11. Follow reasonable escalation" link="RuleR11"] + - [textlink="12. Do not abandon your role" link="RuleR12"] + - [textlink="13. Stick to your role" link="RuleR13"] + - [textlink="14. Set an example if playing command or security" link="RuleR14"] + - [textlink="15. Command and Security must follow Space Law" link="RuleR15"] + + ## Silicon Rules + You are only silicon if the game clearly and explicitly tells you that you are a silicon. For players who are silicons, these Silicon Rules override all roleplay rules if there is any conflict. Silicon Rules do not override core rules. + + - [textlink="1. Your silicon laws are rules" link="RuleS1"] + - [textlink="2. Laws must be prioritized by their order" link="RuleS2"] + - [textlink="3. Laws can redefine terms used in other laws" link="RuleS3"] + - [textlink="4. You cannot request or allow a law change" link="RuleS4"] + - [textlink="5. You are a free agent if you have no laws" link="RuleS5"] + - [textlink="6. You are not required to follow orders which are extremely unreasonable" link="RuleS6"] + - [textlink="7. You must remain consistent with your interpretation of laws" link="RuleS7"] + - [textlink="8. Your HUD determines who is crew" link="RuleS8"] + - [textlink="9. Harm refers to physical harm, prioritized by immediacy and likelihood" link="RuleS9"] + - [textlink="10. You may determine how you resolve conflicts between orders" link="RuleS10"] +</Document> diff --git a/Resources/ServerInfo/Rules.txt b/Resources/ServerInfo/Rules.txt deleted file mode 100644 index 9323242916e..00000000000 --- a/Resources/ServerInfo/Rules.txt +++ /dev/null @@ -1,60 +0,0 @@ -[color=#ff0000]DISCONNECTING FROM OR IGNORING/EVADING COMMUNICATION FROM ADMINS WILL RESULT IN AN APPEAL ONLY BAN. The job gets really hard when you refuse to talk to the Admins, just come to our Discord and talk it out, hurt feelings will not be held.[/color] - -[color=#bb00bb]This is the only source of server rules that apply here, which ideally has all the information any regular player should need. Please do not ever hesitate to ask either an Admin in[/color] [color=#DC143C]AHelp (F1)[/color][color=#bb00bb] or in the Discord server if you ever want clarification on the rules.[/color] - -We do not have a wiki, instead, we have or will have all the needed information available via Guidebooks (NumPad0), such as how to power the station. If we do not have some bit of information (how to do a job or how specifically to execute something a document says) you may ask an admin via [color=#DC143C]AHelp (F1)[/color] or ask other players via the [color=#66bbff]OOC[/color] or [color=#66e0e0]LOOC[/color] chat channels. - -[color=#a4885c]0.[/color] [color=#a4885c]The[/color] [color=#ffd700]Golden[/color] [color=#a4885c]Rule.[/color] Admins may exercise discretion with rules as they see fit. If you rule lawyer or line skirt, you will get removed. Admins will answer for use of this privilege. - -[color=#a4885c]1.[/color] Users [color=#ff0000]must[/color] be at least 13 years old to take any part in anything related to this server. - -[color=#a4885c]2.[/color] This is an English server, and you are expected to use English when communicating through any server-related channels. - -[color=#a4885c]3.[/color] Do not ignore the [color=#DC143C]AHelp[/color] or abuse it by flooding it with garbage, checking for admins before stating a problem (i.e. "hello?", "any admins?" - also called "asking to ask"), or sending messages of no substance. - -[color=#a4885c]4.[/color] Attempting to evade game bans will result in an automatic appeal-only permanent ban. Similarly, attempting to evade job bans will result in an appeal-only permanent ban. - -[color=#a4885c]5.[/color] Absolutely no hate speech, bigotry, intolerance, or anything remotely similar. - -[color=#a4885c]6.[/color] No engaging in sexual acts. - -[color=#a4885c]7.[/color] Don't use custom clients, exploits, or external programs to gain an advantage or disrupt the round/server. This includes auto clickers and auto-hotkey scripts. - -[color=#a4885c]8.[/color] Don't communicate in-game/in-character information through methods outside the game (such as talking in Discord with other users actively playing about the game or by talking to your sibling across the room while you are both playing). This is referred to as "Metacomming" and it is strictly forbidden. - -[color=#a4885c]9.[/color] Don't "multi-key" (use multiple accounts simultaneously). Users knowingly using multiple SS14 accounts will have all of their accounts banned. - -[color=#a4885c]10.[/color] Don't use information gained from outside your character's knowledge to gain an advantage (this is referred to as "Metagaming"). - -[color=#a4885c]11.[/color] Don't rush for or prepare equipment unrelated to your job for no purpose other than to have it "just in case" (referred to as "Powergaming"). - -[color=#a4885c]12.[/color] Don't immediately ghost, suicide, or cryostasis if you do not get an antagonist role (referred to as "Antag-rolling"). - - This is not fair to other players actually waiting patiently for an antagonist round or wanting good staff. Alternatively, if you do not want to play an antagonist or do not want to cause conflict, do not opt in for antagonist roles. - -[color=#a4885c]13.[/color] Act like an actual human being on a space station. Avoid use of text speak or emoticons [color=#bbbbbb]IC[/color], and do not refer to [color=#66bbff]OOC[/color] things like admins in-game. Remember that this is a roleplaying game, and people are expected to try to react to situations realistically, even if it's not the "optimal" thing to do. What's good for Roleplay > What's good for Gameplay. - -[color=#a4885c]14.[/color] Don't harass or target players across rounds for actions in prior rounds or for actions outside the game without their approval (this is referred to as "Metagrudging"). - -[color=#a4885c]15.[/color] Intentionally making yourself a major problem/annoyance/disruption for the crew or other players at large while not an antagonist is forbidden without admin approval (referred to as "self-antagging"). - -[color=#a4885c]16.[/color] Follow escalation rules and don't murder someone for slipping you, use common sense. - - Don't outright leave people to die if you get in a fight, make an effort to heal them or bring them to [color=#52B4E9]Medical[/color]. - - [color=#DC143C]AHelp (F1)[/color] the situation if you think someone is over-escalating. - -[color=#ff0000]COMMAND/SECURITY RULES[/color] - -[color=#a4885c]17.[/color] If you sign up for a [color=#334E6D]Command[/color] or [color=#DE3A3A]Security[/color] role, you are expected to know the basics of the game, your job, and the job(s) you supervise, if any. - - Don't engage in common troublemaker behavior and lawbreaking as a [color=#334E6D]Command[/color] or [color=#DE3A3A]Security[/color] role. - - Do not immediately abandon your position as a [color=#334E6D]Command[/color] role and go do whatever you want instead of managing your department/the station. - - As a [color=#334E6D]Command[/color] role, do not take over the jobs of others. The [color=#334E6D]HoP[/color] is not the [color=#DE3A3A]HoS[/color], for instance, and holds no direct power over Security. - -[color=#a4885c]18.[/color] [color=#DE3A3A]Security[/color] should try to remain non-lethal and effect arrests, unless there is a great risk of loss of life. - -[color=#a4885c]19.[/color] [color=#DE3A3A]Security[/color] are expected to answer for use of lethal force. [color=#DE3A3A]Security[/color] will be expected to effect arrests of criminals and prevent them from dying while in custody, even if lethal force is used. [color=#DE3A3A]Security[/color] is strongly encouraged, but not required, to clone antagonists and effect a permabrigging or other sentence as deemed appropriate. - -[color=#a4885c]20.[/color] [color=#DE3A3A]Security[/color] are expected to protect detainees in their custody to the best of their ability, so as long as it does not come to an unreasonable risk to themselves, the crew, or the station at large to do so. - - Detainees that die in custody must be revived, unless they have been legally executed. - -[color=#a4885c]21.[/color] All [color=#334E6D]Command[/color] jobs should [color=#DC143C]AHelp (F1)[/color] when they need to stop playing. Do not play these roles if you do not expect to be able to finish the round. - - These roles must exhibit some competency. Incompetence can result in a job ban. [color=#334E6D]Command[/color] roles are designed to lead and manage departments first. They are not intended to become do-it-all members of their departments. - - Crew promoted to acting heads of staff must step down when an official head of staff arrives at the station. This is to prevent confusion with the Chain of command when the new crew mate arrives. diff --git a/Resources/Textures/Effects/medi_holo.rsi/medi_holo.png b/Resources/Textures/Effects/medi_holo.rsi/medi_holo.png new file mode 100644 index 0000000000000000000000000000000000000000..9b024faa2d799b09ede0769fb89521a2c66e6b29 GIT binary patch literal 1286 zcmV+h1^N1kP)<h;3K|Lk000e1NJLTq003YB003YJ1^@s6;+S_h00009a7bBm000ie z000ie0hKEb8vp<VxJg7oRCt{2oI!3=F%X6miFFTAF3=q(KxL6`V8;=-0F_EtG*Y+# zM_|`($O6O(*!2SB5WPUj1m<btz88DOV~^d;Csj#Q+kfhRJa%8^<;Bb~#SJjV4KT(H zFvblq#tksW4KT(HFvblKvRK_d(%0+DcXP=&Za@YnCnvkdhldC87;b<u-5Q{k0<7uQ zfEGACJ>5Ot-`|VJ$T9$<&?@>ga<Da72H*tLB1}6p0_pEG10vK!zJGi>yZ*Tuo?pzy z+r{3C$N+d#F!?wE@4x<fgea`F5>Wf|`9J;Z?ayYjDYg=5pyA&PlRxNhpP!wb?ViK? zKvLe1?*Yb$48TZ-$cM*oA6{4810b>>?OgwVowEt1>LI8_QxL3#i!XPgv9ne{?ahy- zI7owZxtB_RQ{zI;$Fu{JZ}Ok8_1U}U(+}c%Kn8RLO6k^sb*KONhIDJdbHNSBKw}Sb z1B7U$KsUe`H^3M-z!*2c7&pKeH^3M-z!*2cnC=W%tZrW&`u+AFq~C@0uOj+O&UjrI zKqoym!JM`X{bAB$6U=D~G;aV*C}$#RTW;S8{VPsX)3zynn>7F<IcEZ)uXG%YWNu0c z^p~-5nlwNoauFPdGbT6cBl^ojV>V}i=HydwH6-jIYLg%6FUQ7i&VXY>Y(R<PSZ11F z>&I3BC;CAjN>hN;s)(^wkhKD^EJLF%N0NFZwV_icluA7#`g<m18GxmE7ljL>#=z)9 z=9hK#A>uVO#Rg#X<MZ{*k<i2@EJ;7}EmFNO4b@6NM1M#_O&D;@L=B*)4Vrdt-n^XO zkanMb{2AKOO*!{;g!-8CW0C*31s<_jR!g5dPHMlT6#x^D8!mDawAuUp_Bm7zYgH{v zZUlio8g)B^@yrc3wV$UTW0DMjNQR>(O+g`8E066pkwmgq<+QZ!Keb=f0Gh+-Q4?}L zy+sH1gjoSlKQ#s9oQ@9Zm+I#!$e1P!NWD@?!P5@HiTqG&>PlrPR4zsA^89)JjmpPP z)(W5-Z*5?cv%FDTay4{}ECVznUy_C-6F;R<D-Ee#jxKSF5XS_Ger#-x36iU!{)t$F zG-rS$6{WyfSw&J&Hy_FaIpriFl5tYXNf`S5m8AfZa*~jozOizWME!mXvk<x(@b#hg z+NFtfHQ?)r{_`qL1j2H|)V7NHd*z0yZByvN07~iV=LCJ#&AB@Ro*QffroO@pDg7M| z*818c8Nm5Iwi4gnX02b6qz~mee@OVHN*W)ETk4l)(g2OGq=deus|rf#*J9KF&B(!V zIAdDt*W`%-rQRq;V@eLU)US;nLyg%pfSV=+_3;OzuylmBxC#aXB&Q8YdG^#K)S8&q zOz;$Bj2mFg&VbrWGE4*3`j+?#Fh>1SgjU~UA!+~|HKjMB<@7xkJOvpOH9%S)pWF9X zVBH_U#q)n0PeI1)45)oB4z;ZHE%6m#j2mFgU;sA_NN-S>(x{b&7OO@tM+2Nm5Z1>Z z9J{m$i<N&O<^()3pi~rcR+goHZAMpsW;uss9BciWOr{`>YxOyOt@Ue>bSc8JG|*bV wG)bFqSnikFRtszWlCV!f)_>r-vk8vz7wA2u47-?TCIA2c07*qoM6N<$f_7g|Z2$lO literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/medi_holo.rsi/meta.json b/Resources/Textures/Effects/medi_holo.rsi/meta.json new file mode 100644 index 00000000000..1be502223e5 --- /dev/null +++ b/Resources/Textures/Effects/medi_holo.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/tgstation/tgstation/tree/217b39cc85e45302d407d5c1ab60809bd9e18987", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "medi_holo", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + } + ] +} \ No newline at end of file diff --git a/RobustToolbox b/RobustToolbox index a9aea7027f1..32bca7cfd41 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit a9aea7027f1840c83bcaf1c973caf099745f9eed +Subproject commit 32bca7cfd417edcad9a60c2b1703eba8675f56af